Raw socket for transport layer protocol - sockets

What I want to do is make my own transport layer protocol in C++. I can't figure out how to create a raw socket that that automatically resolves IP headers, and leaves it up to me to set the payload.
I managed to receive packets on the server using
socket(AF_PACKET, SOCK_RAW, htons(ETH_P_IP))
but didn't manage to create a client that can send data to the server. (I'm not even sure if the above socket is L2 or L3)
From what I understand from reading about raw sockets, a L3 socket would look like
socket(AF_INET, SOCK_RAW, protocol)
Thing is, I don't know what to fill in for the protocol, if my intention is to create my own and not to use existing ones. (I have tried many of the iana numbers, including the range 143-252)
So the question is: how to create a socket, server and client sided, on top of the Internet Protocol such that two computers can communicate in an arbitrary protocol (or send data to each other)? In other words, I want to specify the end IP address and a payload and have the socket take care of the IP header.
What I have now:
server.cpp: https://pastebin.com/yLMFLDmJ
client.cpp: https://pastebin.com/LWuNdqPT

For those who are searching, here is the solution I found: http://www.pdbuchan.com/rawsock/rawsock.html
In the file tcp4.c on the above mentioned page, there is a client implementation using a raw socket. The code adds both IP and TCP headers, but you can simply remove the lines where the TCP headers are added and replace them with your own protocol. You also need to change this line: iphdr.ip_p = IPPROTO_TCP to iphdr.ip_p = 200 (200 or any number in the range 143-252; see https://www.iana.org/assignments/protocol-numbers/protocol-numbers.xhtml) and set the name of the interface you are using, as well as change the addresses.
So here is a stripped down version with the mentioned changes that sends an IP packet only containing IP headers: https://pastebin.com/z2sGmtQd
And here is a very simple server that can receive these packets: https://pastebin.com/jJgZUv5p

Related

Confusion with AF_INET, with SOCK_RAW as the socket type, V/S AF_PACKET, with SOCK_DGRAM and SOCK_RAW as the socket type

I am quite new to network programming and have been trying to wrap my head around this for quite sometime now. After going through numerous resources over the internet, I have the below conclusion and following it the confusion.
Conclusion 1:
When we are talking about creating a socket as :
s = socket(AF_INET, SOCK_RAW, 0);
we are basically trying to create a raw socket. With a raw socket created this way one would be able to bypass TCP/UDP layer in the OSI stack. Meaning, when the packet is received by the application over this socket, the application would have the packet containing the network layer (layer 3) headers wrapping the layer 2 headers wrapping the actual data. So the application is free to process this packet, beyond layer 3, in anyway it wants to.
Similarly, when sending a packet through this socket also, the application is free to handle the packet creation till layer 4 and then pass it down to layer 3, from which point on the kernel would handle things.
Conclusion 2: When we are talking about creating a socket as :
s = socket(AF_PACKET, SOCK_RAW, 0);
we are again trying to create a raw socket. With a raw socket created this way one would be able to bypass all the layers of the OSI altogether.
A pure raw packet would be available to the user land application and it is free to do whatever it wants with that packet. A packets received over such a socket would have all the headers intact and the application would also have access to all of those headers.
Similarly, when sending data over such a socket as well, the user application is the one that would have to handle everything with regards to the creation of the packet and the wrapping of the actual data with the headers of each layer before it is actually placed on the physical medium to be transmitted across.
Conclusion 3: When we are talking about creating a socket as :
s = socket(AF_PACKET, SOCK_DGRAM, 0);
we are again trying to create a raw socket. With a raw socket created this way one would be able to bypass data link layer (layer 2) in the OSI stack. Meaning, when a packet over such a socket is received by the user land application, data link layer header is removed from the packet.
Similarly, while sending a packet through this socket, a suitable data link layer header is added to the packet, based on the information in the sockaddr_ll destination address.
Now below are my queries/points of confusion:
Are the conclusions that I have drawn above about raw sockets correct ?
I did not quite clearly understand the conclusion 3 above. Can someone please explain ? Like, does it mean that when the user land application receives a packet through this socket, it is only the data link layer headers that would have been handled by the kernel? And so the packet would be like the message wrapped with directly the layer 3 headers and wrapped subsequently by the layers above it?
If the conclusions drawn above are correct, conclusion 1 and conclusion 2 still make sense. But if conclusion 3 above (and the speculations around it in 2 above) are correct, when exactly would any application ever need to do that ?
Some resources that I have referred to trying to understand the above:
https://docs.freebsd.org/44doc/psd/21.ipc/paper.pdf
https://sock-raw.org/papers/sock_raw
https://www.quora.com/in/Whats-the-difference-between-the-AF_PACKET-and-AF_INET-in-python-socket
http://www.linuxcertif.com/man/7/PF_PACKET/
http://opensourceforu.com/2015/03/a-guide-to-using-raw-sockets/
'SOCK_RAW' option in 'socket' system call
http://stevendanna.github.io/blog/2013/06/23/a-short-sock-raw-adventure/
https://www.intervalzero.com/library/RTX/WebHelp/Content/PROJECTS/Application%20Development/Understanding_Network/Using_RAW_Sockets.htm
You got quite closer to their real explanation. Here I've got something to tell you what I think you're missing or wrong about.
First, for s = socket(AF_INET, SOCK_RAW, 0);, when packet is received over such socket, it will contain an IP header always. If IP_HDRINCL is not enabled, for sending, the packet must contain the IP header, the TCP/IP stack will not generate this for you. All other upper layers can be received by this socket.
Secondly, s = socket(AF_PACKET, SOCK_RAW, 0);:
This is a special type of Raw Socket and called Packet-socket in Linux system. This type of socket allows to send and receive packet at OSI layer 2 that's why APIs used for such socket are referred to as Link Layer API. Any protocol can be implemented on the top of physical layer by using this socket. Interestingly, we can also interact with the packet's trailer with this socket what though we don't frequently need.
Thirdly, In case of s = socket(AF_PACKET, SOCK_DGRAM, 0);, your conclusion is right. In this type of Packet Socket, you don't need to think about Ethernet header. It's a bit upper layer than previous type.
So, we can say that the main distinction amongst these types of sockets is their possibility of access. To summarize:
Raw-Socket access:
| Layer 3 header | Layer 4 header | Payload |
Packet-Socket access:
| Layer 2 header | Layer 3 header | Layer 4 header | Payload | Layer 2 trailer |

How do I get the sender IP address from a packet in a PCAP file?

I am most likely missing something here, but the PCAP specification does not show the sender IP address and PORT of the packet captured.
Is there a way that I can know who sent the packet in the PCAP file?
http://wiki.wireshark.org/Development/LibpcapFileFormat
As per what EJP said, you will have to parse the packet data yourself. See the tcpdump.org link-layer header type page for a list of the values for the network field in the file header and the corresponding format of the headers at the beginning of the packet data.
You need to look at those headers to determine whether the packet is an IP packet; if it is, then you need to parse the IPv4 or IPv6 header (depending on whether the headers indicate that it's an IPv4 or IPv6 packet, or, alternatively, on whether the "version" field in the header is 4 or 6 - the "version" field appears in the same location in the IPv4 and IPv6 header; for LINKTYPE_RAW, you would have to look at the "version" field, as there are no headers in front of the IPv4 or IPv6 header) to find the source IP address. See RFC 791 for the form of the IPv4 header; see RFC 2460 for the form of the IPv6 header.
If you want port numbers, you will have to check the "Protocol" field of the IPv4 header, or check the "Next header" field of the IPv6 header and handle extension headers, to determine what protocol is being carried on top of IP. See the IANA Protocol Numbers registry for the values of that field; TCP is 6 and UDP is 17. If the protocol is TCP, see RFC 793 for the format of the TCP header; if the protocol is UDP, see RFC 768 for the format of the UDP header.
Or you might want to use an existing packet parsing library, such as libtrace for C or C++ or other libraries for other languages (I think they may exist for Perl, Python, C#, and Java, for example), as that may let you avoid doing a lot of the above.
(For that matter, you shouldn't need to be looking at the pcap format specification; you should be using libpcap/WinPcap to read the pcap file, as that also means your program may be able to read some pcap-ng files as well, if it's using a sufficiently recent version of libpcap.)
The packet origin is in the IP packet itself. So it doesn't need to be in the PCap headers as well.
I was able to get the IP address and port numbers of both source and destination endpoints using the below Github example:
https://github.com/arisath/Pcap-dissection/blob/master/PcapDissector.java

How to detemine which network interface (ip address) will be used to send a packet to a specific ip address?

I'm writing a SIP stack, and I need to insert an ip address in the message. This address needs to be the one used for sending the message. I know the destination IP and need to determine the NIC (its address) that will be used to send the message....
To expand a bit on Remy Lebeau's comment, GetBestInterfaceEx() is your best bet, if you're on Windows XP or newer. That will work for both IPv4 and IPv6 addresses.
GetBestInterface/GetBestInterfaceEx return the index (call it IDX) of the most appropriate interface to use to contact some address.
Then you can map that index into a local IP address by getting your interface<->IP address mapping using GetIpAddrTable or GetAdaptersAddresses if you're dual-stacking (supporting both IPv6 and IPv4).
Iterate over that table and find the interface with the dwIndex (or IfIndex, in the case of GetAdaptersAddresses) matching IDX.
It's usually best to allow the IP address your SIP stack will operate on to be set as an adjustable configuration option. It means the user will need to set a configuration option but at least your stack will know the IP address it's operating on.
If that's not feasible then an approach you could use is to send out the SIP request on all IP addresses using a dummy value in the Via header such as 0.0.0.0 and set the interface you get a response back on as the default one. This approach alos as the advantage that the SIP response will tell you the public IP address the request was received from which can be useful if your SIP stack is behind a NAT.
Over TCP, I think you can get the address of the local side of the socket after connect(). I don't know if the same is true for UDP (I suspect not), but it might be worth a try.
The socket will allow you to Bind to a local endpoint before calling connect (both UDP and TCP).
That is all ok if you know the port. However, if you want the port to be ephemeral (e.g. some random port number) then you must come up with your own algorithm to do so and robust code to handle the cases where the port is exclusivly taken by another application.

How to bind to any available port?

I need an app that sends an UDP packet to some network server and receives the response. The server replies to the same port number where request came from, so I first need to bind() my socket to any UDP port number.
Hardcoding the UDP port number is a bad idea, as it might be used by any other application running on the same PC.
Is there a way to bind an UDP socket to any port available? IMO it should be an effective way to quickly obtain a free port #, which is used by e.g. accept() function.
If no, then what's the best strategy to try binding and check for WSAEADDRINUSE/EADDRINUSE status: try the ports sequentially starting from from 1025, or 1025+rand(), or some other?
Another option is to specify port 0 to bind(). That will allow you to bind to a specific IP address (in case you have multiple installed) while still binding to a random port. If you need to know which port was picked, you can use getsockname() after the binding has been performed.
Call sendto without calling bind first, the socket will be bound automatically (to a free port).
I must be missing something, why don't you use the udp socket to send back data?
Start with sendto and then use recvfrom function to read incoming data also you get as a bonus the address from which the data was sent, right there for you to send a response back.

BroadCasting

Ok in order to broadcast, I have created a socket:
notifySock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
And to send the hostname of my computer to all other computers connected to the same lan, I am using the send(Byte[] buffer) method:
notifySock.Send(hostBuffer);
hostBuffer contains the hostname of my computer.
However because I am using a 'datagram' socket-type do I need to format the data I need to send.
If possible please provide the code that I must put in between the two lines of code I have entered to create a socket and send the data.
For broadcast from a user application, UDP is typically used. You need to design a suitable protocol, i.e. a way to format the information you want to send into the UDP packet.
In your example you haven't specified who you are sending to. You need something like:
UdpClient notifySock = new UdpClient(endPoint);
notifySock.Send(buffer, buffer.Length, new IPEndPoint(IPAddress.Broadcast, 1234));
For the other hosts on your LAN to receive that they have to be listening on UDP port 1234.