4

Given a local IP and port for an established TCP session, can I find out which side sent the initial SYN? That is, was this connection actively or passively opened? I need something that works in C/C++ on Linux. A hacky way might be to socket()/listen() and catch EADDRINUSE but I was hoping for something cleaner. I'm not even sure if the kernel tracks this once the session is established.

EDIT: I'd also prefer not to call out to netstat (or even ss) as both are too slow with many sockets open. This code will be called often.

markdrayton
  • 485
  • 6
  • 11

1 Answers1

2

Always the client makes an active connection, by sending a SYN(to the server). So, given a local IP and port number, check if its a listening socket using the following command:

netstat --listening | grep given_ip:given_port

If it is not listed here, then it is a client-side socket, thus initiates a SYN. If its there, then its a listening socket and hence it has received a SYN.

The corresponding code looks as follows:

system("netstat --listening | grep given_ip:given_port > tmp.txt");
int fd = open("tmp.txt", O_RDONLY);
char buf[100] ;
if(read(fd,buf,100)>0)
    printf("The socket has received a SYN!");
else
    printf("The socket has sent a SYN!");

EDIT:

If you feel netstat has poor speed to scan the entire ports, then the only way to achieve the fastness is to open a raw socket and set it to receive all the TCP packets.

Process only those packets which contain a SYN in them. Now, store both source address:port and destination address:port into two tables. One that is a sender of SYN and one that is a receiver.

Now, when you are given a port and ip-address, make a scan over the data stored so far. You can also use STL map of C++ to achieve faster results.

Since there can be many requests, the map may get filled up swiftly, making the look-ups slow. I advice you to process the FIN packets also and based on that remove the corresponding entries from the table.

nitish712
  • 19,504
  • 5
  • 26
  • 34
  • 2
    Thanks for this. I was hoping for something other than netstat because it's so slow when you have thousands of sockets open. I'll update the question with this. – markdrayton Jan 24 '14 at 03:00
  • 1
    When a TCP server listening on a socket accepts a client connection the accept call returns a separate socket/port that's not itself in a listening state - it's a peer-to-peer connection: isn't the question about finding out whether sockets in that state were created by server accepts or outgoing client connections? `netstat --listening` won't help with that. – Tony Delroy Jan 24 '14 at 03:29
  • @TonyD `accept()` does return a new socket, but not on a new `port`. See [this](http://stackoverflow.com/questions/489036/how-does-the-socket-api-accept-function-work) – nitish712 Jan 24 '14 at 03:36
  • Tony: yes, the question is about established connections so looking for a listening socket isn't exactly right. I don't need an exact answer, though -- if a socket was listening on the port I'm looking at it'd be close enough most of the time. Shame finding a listening socket is so expensive :( – markdrayton Jan 24 '14 at 03:37
  • @nitish712: unfortunately there's too much traffic to track in this way. I'm looking for a very cheap solution. – markdrayton Jan 24 '14 at 03:39
  • @markdrayton "if a socket was listening on the port I'm looking at" - I'm still not sure you understand how this works... if the socket is listening it's a local server's socket, but that doesn't give you the foggiest clue whether there's been any client connection thereto because each client connection is accepted on *another socket and port*. So given a "socket [...] listening on the port I'm looking at it'd be close enough" - only if you're trying to find the local server listening sockets/ports - it won't help you determine *anything* about the established peer-to-peer connections. – Tony Delroy Jan 24 '14 at 03:59
  • @TonyD Assume a listening socket on `80`. Client `A` sent a request. You will see `A:prt ->SYN-> :80`. For the next `ACK` its `A:prt<-SYN,ACK<-:80`. and then `A:prt->ACK->:80`. Now the connection is established. If A sends `msg`, its still `A:prt->msg->:80`, but not `A:prt->msg->:some_other_port`. I recommend you to check this in `wireshark`. All I want to say that the port number from the server doesn't change at all, even after the connection is established. The data is still sent to `80`, but re-directed to the corresponding client socket. – nitish712 Jan 24 '14 at 04:12
  • @nitish712: "if A send `msg`" - there's the rub - you're talking about waiting for and reading the real-time trace of the *next* message that may or may not turn up, when you happen to have a connected but idling peer-to-peer connection you could be waiting a very long time. Using netstat or wireshark to monitor future activity is very different to getting a client-vs-server determination when desired. Anyway, it's quite likely that some /proc or kernel socket state will indicate this - just nothing accessible through the normal application-level socket/thread API. – Tony Delroy Jan 24 '14 at 04:24
  • @TonyD I sniff all the packets from the beginning of the session. So, I will come to know who sent the first `SYN`. If you want to figure out this for an already existing TCP connection, then the only way is to check if the local port is a listening port, which is what I have stated. If not this, and you don't want to sniff the packets from the beginning, then its impossible to figure out because both ends become symmetric after the connection establishment. – nitish712 Jan 24 '14 at 04:33
  • @nitish712: it's the "figure out this for an already existing TCP connection, then the only way is to check if the local port is a listening port" that stumped me; I found http://stackoverflow.com/questions/489036/how-does-the-socket-api-accept-function-work which explains how it's possible for an established connection to retain the listening socket's port number - not clear to me yet if this only happens on specific TCP implementations, as I'd have sworn going back 10-20 years when I was doing heavy socket programming that the client connections were given another port.... – Tony Delroy Jan 24 '14 at 05:23
  • @TonyD: I do understand how this stuff works but I probably didn't give enough context to cover this avenue in my question: I'll obtain the given IP and port by sampling traffic. That is, if I see a packet arriving at port 1234 on my local IP I want a way to see who set up the flow it is part of (without having seen the original SYNs). If I am listening on port 1234 there is a very high likelihood that the client set it up; if I am not listening on that port then I probably made the outbound connection. I hoped for something cleaner than this, though. – markdrayton Jan 24 '14 at 05:29
  • @nitish712: digging around, seems system/implementation defined - lots of reports of different ports - e.g. http://answers.yahoo.com/question/index?qid=20080624151304AAU5IcG http://www.coderanch.com/t/207309/sockets/java/ServerSocket-port-number-Socket-port ... if recent Linux implementations are using the same port, all's good and sorry for the heckling. ;-) – Tony Delroy Jan 24 '14 at 05:31
  • @markdrayton: "probably didn't give enough context" - no worries. Looks like you're covered then.... Cheers. – Tony Delroy Jan 24 '14 at 05:34