简体   繁体   中英

Using socket AF_PACKET / SOCK_RAW but tell kernel to not send RST

My question has roughly been discussed here .

And the tl;dr solution is to do:

iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP

And you could modify this to only block the port you're actively listening after.
But as mentioned in the above question, and here , these are not elegant solutions.

Now, I don't really care about the elegance of things.
But I do care about learning. So I've dug deep into the Linux source code (mostly interested in Linux based machines for now) and sorted through what I think is thesocket.bind method in order to find anything related to instructing the kernel that "we" are actively monitoring a TCP port.

I assumed that the socket library informed the kernel some how about a specific port being bound to a application, this so that the kernel don't automatically respond with a RST packet to the client connecting, prompting a "Connection refused" .

However, I find no such code in the source code.
Nor does the packet man page tell me anything about how to inform the kernel to ignore/accept packets coming in on a specific port.

I've got a pretty basic socket set up to listen with promiscuous mode (that is a tale of it's own) .

However, my problem is that as soon as a client connects, on any given port - the kernel sends the incoming Ethernet+IP+TCP data frame my way as expected - but it also instantly sends out a response with "reversed" source and destination ports and the RST flag set. Which it should, but not on a specific port I tell it to. Problem is, how do I tell the kernel I'm monitoring a specific port?

One option would be to (as discussed in some other forums and on other various SO threads) - create a dummy socket on that port.

s = socket()
s.bind(('', <port>))

However, that causes a bunch of other problems (one of which is that this will have a buffer that will quickly be filled) and most importantly, still doesn't teach me how all this magic happens. The two above solutions are last resort if there's no other ways, but I feel I'm closer than ever yet more stuck than ever too in finding a proper solution to this problem.

The solution or tips could be in C as well , and/ or a kernel module just for the sake of instructing the kernel of the needed information. I knew all this was going down in the kernel, and after the comments below and a much appreciate solution idea, I now get that there's no userspace function for this very thing. I could probably/easily port it to a cPython module or warp it around to Python code easily enough with a kernel module/extension. But I really have no idea where the kernel functions for setting these things are, or what they are called.

I've dug deep, far and shallow.. But it doesn't appear anyone else has had the need to do this. Mostly because a promiscuous socket is meant to pick up traffic and analyze it. But also the .bind((interface, protocol)) is out there and it faces the same issue, a way of not going into promiscuous mode but instead just receive TCP packets for instance by doing .bind((interface, 0x0800)) .

I might be out on a limb here, but maybe man 7 netdevice just gave me an idea. I'm trying to setup SystemTap to check what calls ioctl() does and how socket() object asks for a file descriptor. Might be a clue as to how this all goes down. Tricky getting SystemTap to work tho.

Anyone have any other clues how to go about this problem or have bumped into this before?

Ps. Sorry for a fuzzy question, I have no idea what the correct terminology is for these lower level things. As they are quite new to me.

Edit: I might have been looking in the wrong place for bind() , according to the ipv4.af_inet implementation it will try to call the sockets bind() function, but if not, it will try to setup a lot of magic in here. And here they clank down on af_inet and does a lot of table junk.. I still haven't found a solution, but a step on the way perhaps... Or worst case, another goose hunt.

Going further down the rabbit hole, selinux/hooks.c contains some bind functionality as well. Maybe more security related, but still worth my investigation. Still no where near solving this darn riddle.

The problem here is that you're asking for a way to tell the kernel in effect "do these 100 things for me, but leave this one particular detail out." Frankly, I think the iptables solution is the easiest and cleanest.

Another option, though, is to not ask the kernel to do all those other bits, and instead to take on more work yourself. Specifically, make up your own IP address, and start using it. The only downside is that you have to take over another important thing that the kernel has been doing for you: responding to ARPs (ARP is used to discover the MAC [Ethernet] address of the station that owns a given IP address). In brief, I'm suggesting you:

  1. Choose an unused IP address on your local subnet.
  2. Make up a MAC address for your use. (Not strictly necessary but will make it easier to distinguish "your" traffic.)
  3. Open a raw packet socket instead of raw IP socket ( https://linux.die.net/man/7/packet ).
  4. Compose and send an ARP request to discover the MAC address of the station you're sending to (if on local LAN, else the MAC of the next hop [router] IP address).
  5. Receive the ARP reply and record the other station's MAC.
  6. Construct and send your SYN packet from your own MAC address to the MAC of the destination station. (With your chosen source and dest IPs, ports, etc.)
  7. Listen for a return ARP for your IP and reply as needed.
  8. Receive the SYN+ACK response. Since the destination IP address (the one you made up) is not known to the kernel to belong to your system, the kernel will not respond to the SYN+ACK with RST (or anything else).
  9. Do whatever it is you want to do next...

You will of course have to be capturing promiscuously if you use a MAC address other than the one assigned to the interface. That is pretty typical with a raw packet socket. Also, you will be constructing Ethernet header, IP header, and TCP headers for all traffic (well, Ethernet + ARP for the ARP requests) so you will learn a lot.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM