mfontanini / libtins

High-level, multiplatform C++ network packet sniffing and crafting library.
http://libtins.github.io/
BSD 2-Clause "Simplified" License
1.91k stars 377 forks source link

TCP packet sending error #39

Closed mnt closed 9 years ago

mnt commented 9 years ago

I want to create a simple program which allows me to establish a TCP connection and sends packets of data. By following the tutorial I wrote this:

        PacketSender sender;
        try {
            IP pkt =  IP("127.0.0.1") / TCP(1111) / RawPDU("I'm a payload!");
            sender.send(pkt);

        }
        catch(socket_open_error){
            cout << "socket open error" << endl;
            return false;
        }

By testing the program I did 'nc -lk 1111'

However when running the program I enter the catch block.

mfontanini commented 9 years ago

That works for me. Are you running the application as the root user (sudo ./test in Debian based Linux distributions)? Keep in mind you have to do so, or otherwise give it _CAP_NETRAW capabilities.

bt commented 9 years ago

Actually, I'm having some trouble getting my application to connect to a netcat server too.

I ran Wireshark and did two tests; one with telnet -> nc, and that works perfectly. But when I wrote a similar application to send packets via libtins -> nc, then I just receive a RST packet back.

Would you happen to have a really simple piece of code that can connect to a netcat server and just send the text "Hello World" so that we know what way we should be heading?

Also, the packet seems to send without any exceptions if you set the TCP SYN flag on.

mfontanini commented 9 years ago

Well the first packet in each connection must have the SYN flag on. If you don't set it, you will get a RST packet as a response.

Establishing a connection from libtins should work, but you should use some firewall rules since otherwise, the kernel will always respond packets you receive with TCP RST packets.

If you do want to do this, then have a look at how the TCP 3-way handshake works and how to use sequence numbers.

mfontanini commented 9 years ago

@NeptuniumIO the last message, which you seem to have deleted, has actually shown me that there is a bug.

I'm only seeing this problem on OSX, could you confirm that you are using this OS? On Linux I can both send and receive against localhost and other external hosts, so there doesn't seem to be an issue. On OSX I can't send and receive neither to localhost nor external hosts.

mnt commented 9 years ago

@mfontanini Yes you are right about the deleted message, I am running on a OSX. I have tried running it on linux and it runs as expected.

mfontanini commented 9 years ago

Okay, so apparently both FreeBSD and OSX use a different strategy than Linux when using raw sockets. See this extract, taken from this site:

reeBSD takes another approach. It *never* passes TCP or UDP packets to raw
sockets. Such packets need to be read directly at the datalink layer by using
libraries like libpcap or the bpf API. It also *never* passes any fragmented 
datagram. Each datagram has to be completeley reassembled before it is passed
to a raw socket.
FreeBSD passes to a raw socket:
    a) every IP datagram with a protocol field that is not registered in
    the kernel
    b) all IGMP packets after kernel finishes processing them
    c) all ICMP packets (except echo request, timestamp request and address
    mask request) after kernel finishes processes them

This means that if you want to wait for a response, you either have to:

  1. Include a link layer PDU in the packet (e.g. EthernetII). In your example, the lowest layer is IP. If you added a link layer PDU below that, it should work.
  2. Use libpcap to match the responses. I actually prefer this one, since you'd make things much more efficient. Keep in mind on TCP you don't always send a packet and get 1 response. You might be receiving data from the server so you need to process that as well.

I'm going to push something so an exception is raised in case you do this on OSX/BSD.