I'm trying to get the TCP header of a TCP connection in C++11. Reading through already existing StackOverflow questions (here, here, here and here) it seems like I have to open a RAW_SOCKET or to write a Linux Kernel Module (LKM) to have access to it.
From what I've understood, opening a raw socket means handling the whole TCP protocol (handshake, window size, etc...). Is there a way to obtain the TCP header and let the kernel manage the TCP protocol (either "by hand" or with some framework)?
I know I could use libpcap for capturing the packets, but this would mean for my application making somehow a match from the incoming packet in the TCP socket and the captured packet from libpcap. While this is a possible solution, it'd be a cumbersome one (and I wouldn't like to do that).
Any help is appreciated, thank you!
A "quick and dirty" approach might be using two connections, an external connection to the remote host and a pure internal one. Sure, this won't be the most efficient approach, but is easy (and fast) to implement (the core feature of QAD "solutions"...):
socket ext_raw ------- socket remote, TCP (likely, at least)
socket int_raw ---
| (loop back connection)
socket int_tcp ---
Any incoming messages at ext_raw and int_raw are just forwarded from one to the other (while incoming messages on ext_raw can be inspected for TCP headers), whereas all the normal TCP handling is done by the internal TCP socket. So in a way, you'll be tunneling the TCP connection through your two raw sockets...
Related
TL;DR
I see that my sockets are in TIME_WAIT with the ss tool in Ubuntu 1804, but I can't find in the docs for boost sockets or on SO how to set the time delay to 0 such that the socket immediately closes (or better yet, set it to an arbitrarily small value for my application.
I am writing a socket application with Boost asio. Both the client and the server are using boost sockets. I see that, when the client sends a shutdown connection command: mysocket.shutdown( boost::asio::ip::tcp::socket::shutdown_both, error_code);, and my client C++ application closes down a 2 seconds later, I get TIME_WAIT on the output of ss -ap | grep application_port. I have been looking around SO and the internet looking for ways to set TIME_WAIT with Boost C++, but instead, I keep finding questions for why a TIME_WAIT happens.
Here are some:
https://stackoverflow.com/questions/14666740/receive-data-on-socket-in-time-wait-state
https://stackoverflow.com/questions/35006324/time-wait-with-boost-asio
https://stackoverflow.com/questions/47528798/closing-socket-cause-time-wait-pending-state
If I am interpreting the internet correctly (and the TCP protocol), the reason why TIME_WAIT happens is because the server connection is waiting for an ACK to allow for the socket conn to die, while the client-side socket has already died.
The question, again:
Is there a way to set the TIME_WAIT delay option locally for a C++ executable using Boost sockets? If so, how?
Changing the SO_LINGER option should help: here's the discussion about it:
TCP option SO_LINGER (zero) - when it's required
Boost has api for this reason so you can play around with changing linger to 0:
boost::asio::ip::tcp::socket socket(io_service);
boost::asio::socket_base::linger option(true, 30);
socket.set_option(option);
https://www.boost.org/doc/libs/1_50_0/doc/html/boost_asio/reference/socket_base/linger.html
Anyway, it's good to make sure if you really really have to do that. In case if you have a large number of sockets in TIME_WAIT it most probably means that the client site did not close connection gently. So if you can modify the client code, you can consider it as a first option. Here's nice explanation about how to gently finish the communication on TCP socket (it's not about boost but the logic is the same) Properly close a TCP socket
Most probably you are not closing the socket. The shutdown operation only informs that peer that there will be no more data to read. So most probably you have to:
- call shutdown
- make sure there's nothng more to read
- close the socket
I'm trying to set up a little test application on Linux (Ubuntu) based on some code I wrote (and that worked) for Winsock. As it stands now, it's just a little test that creates a socket (and seemingly successfully connects) only to hang eternally on recv() instead of receiving datagrams. It's a plain blocking socket.
Here's how I create it:
http://pastebin.com/kcCbgxbB
A few further things tested:
- Port is open.
- Other applications are able to receive data from the multicast address successfully.
So clearly I'm overlooking something. Help greatly appreciated :-)
In Unix systems, when using a socket for multicast you should bind to INADDR_ANY, not to a interface.
Multicast filtering by interface (i.e. not receive mcast from other interfaces than the specified one) is already in place because you are correctly filling imr_interface.
So, in the end a little system configuration and bugfixing went a long way:
a) As root, I'd had to do the following to disable the reverse packet filter:
echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
+ The same for ethX.
b) Add a bogus route for the ethX (route add -net 224.0.0.0. netmask 224.0.0.0 ethX)
c) Bind the socket to the to-be-joined group's IP (otherwise any subsequent socket would get all packets from all groups I joined on that particular port).
d) Set the interface member of the ip_mreq struct to the IP of the adapter we're receiving on.
And then all was fine and dandy, test runs fast & smooth (pulling 125 multicast transport streams # around 800-900 mbit - sure this can be smarter, but still). Thanks for all the pointers.
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.
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.
Recently I began working with the Boost::Asio library (C++). I'm looking for a way to send a TCP SYN message to a end destination. However I can't find any way of doing this, does somebody knows a way to accomplish it?
The TCP stack usually deals with this, not your code. If you just call boost::asio::ip::tcp::socket::connect() on an appropriately constructed instance, you will cause a TCP SYN packet to be sent, along with the rest of the TCP handshake and session handling.
Update:
If you want to implement TCP yourself you will need to deal with more than just a TCP SYN, otherwise you're just writing code to attack systems with half-open connections. You need a raw socket and you need to construct the contents of the packet yourself. If you are doing this you should be able to RTFM to find out more.
I going to create kernel mode driver level app that establish a TCP connection, here is my requirement:
I don’t want pass data to user-mode
I don’t want use winsocket and OS socket library
I need to just pass tcp packet to a library and
the library create simple TCP-client or TCP-Server connection for me. It should perform all TCP connection requirements such as tcp handshake, generate packet, calculate checksum, set TCP flags and acknowledgment then give the new packet to me so I can send the packet to my network adapter.
Do you know exiting TCP implementation that it does not use OS socket library?
I think the proper way to ask this question is this:
What is the proper way to do TCP sockets within kernel code?
And I'm not sure you want to do TCP just at the packet level, because you'll also likely want to handle TCP segmentation, IP fragmentaion, sending only when the remote window size permits it, and ACK generation. In other words, if you're doing a TCP server within kernel mode, you want the whole kernel TCP stack.
In any case, Bing or Google around for "kernel sockets" or "ksocket".
For Linux: http://ksocket.sourceforge.net/ Also, check out this example for UDP.
For Windows: Go to this page and downlaod both the HttpDisk and KHttpd samples. Both feature a windows device driver than makes use of a similar "ksocket" library. (Look for ksocket.c and ksocket.h in each)
For Linux, use the kernel_*() versions of the usual socket API, i.e. kernel_bind(), kernel_listen(), kernel_accept(), kernel_connect(). They're in #include <linux/net.h> and are used in ways very similar to "normal" sockets.
Solaris has very similar interfaces, there named ksocket_*(), see #include <sys/ksocket.h> for references.
For the *BSD UN*X flavours, Apple's Network Kernel Extensions Guide gives some details (also with references to the corresponding interfaces on Free/Net/OpenBSD).
Don't know about Windows.