Daniele Bellavista's Blog

Security, IT, Projects

Raw Socket: TCP Segment — 2011-12-08

Raw Socket: TCP Segment

Now it’s time to get into the TCP header.
Obviously TCP over raw socket is very hard to use! Retrasmissions, control flow, congestion avoidance… All of that need to be implemented. However this may be interesting for learning and testing!
So let’s se the tcp header structure.

File: netinet/tcp.h


struct tcphdr
{…};
tcphdr->source //[16 bit] Source Port.
tcphdr->dest //[16 bit] Destination Port.
tcphdr->seq //[32 bit] Sequence Number: received payload byte count since the first SYN. It’s the segment ID.
tcphdr->ack_seq //[32 bit] Acknowledgement Number, if the segment is an ACK, this field contains the next Sequence Number that the receiver is waiting for.
tcphdr->res1 //[4 bit] Reserved.
tcphdr->fin //[Flag] After this segment, no more segment expected from sender.

tcphdr->syn //[Flag] TCP connection opening request.
tcphdr->rst //[Flag] Error or opening request denied.
tcphdr->psh //[Flag] If enabled, the data will be sent directly to the application instead of being bufferized.
tcphdr->ack //[Flag] Acknowledgement. Enables field Acknowledgement Number.
tcphdr->urg //[Flag] Notify an Urgent Data, enables field Urgen Pointer.
tcphdr->res2 //[2 bit] Reserved.
tcphdr->doff //[4 bit] Data offset, TCP Header size in 32 bit words.
tcphdr->th_flags //[8 bit] Flags.
tcphdr->window //[16 bit] Advertise Windows Size.
tcphdr->check //[16 bit] Pseudoheader + Data Checksum (see Wikipedia).
tcphdr->urg_ptr //[16 bit] If flag URG is enabled, Urgent Pointer represent the offset from the Seq. Numb.


Now we define also a structure for ip pseudoheader, in order to compute the checksum.



struct pseudoheader
{
u_int32_t sourceAddress;
u_int32_t destinationAddress;
u_int8_t zeros;
u_int8_t protocol;
u_int8_t tcpLength;
};


Ok, now let’s run our TCP test and here it is our capture!





Source codes:

testTCP.c
tcp.h
tcp.c
ip.h
ip.c

Advertisements
Raw Socket: IP datagrams —

Raw Socket: IP datagrams

IP datagrams represent data to be routed.
They store informations like IP source and destination address.
Inside an iphdr struct is defined, allowing us to create a custom ip header. (More detailed information about IP header here)

File:


struct iphdr
{…};

iphdr.ihl //[4 bit] Internet Header Length, contains the header length measured in 32 bit words.
iphdr.version //[4 bit] Datagram version. ipv4 version’s 4.
iphdr.tos //[8 bit] Type of service (we won’t use it).
iphdr.tot_len //[16 bit] Datagram total length in byte.
iphdr.id //[16 bit] Used on router fragmentation.
iphdr.frag_off//[3 bit] Fragmentation controls.
iphdr.ttl //[8 bit] Time to live, or max hops allowed before datagramm destruction.
iphdr.protocol //[8 bit] Payload protocol identifier  (6->TCP, 17->UDP, 1->ICMP …).
iphdr.check //[16 bit] Header checksum (16-bit checksum RFC1071).
iphdr.saddr //[32 bit] IP source address
iphdr.daddr //[32 bit] IP destination address

Now let’s define some usefull functions for future use:

int createIpv4Header(Iphdr* buffer, char * srcAddress, char * dstAddress, u_int8_t ttl);
void setPayloadInfo(Iphdr* ipheader, int payloadLength, u_int8_t protocolType);
Time for funny testing!
Editing the previous post code, we can create a function testIP(char* src, char* dest) able to send an empty datagram ip to a custom destination from a custom source.
So we initialize the buffer:

int length = createIpv4Header(ipheader, sourceAddress, destinationAddress, 100);
setPayloadInfo(ipheader, 0, 1);


Calling setPayloadInfo we are setting a ICMP protocol with 0 length (obviously that would be a malformed datagram, but now we want only to test the IP behaviour).
Now let’s call the testIP function inside a main(), with parameters (“127.0.0.1”, “127.0.0.1”).
Compile.

Now let’s open our favourite traffic analyzer (like wireshark) and enable capturing on lo (loopback interface, or 127.0.0.1). We’ll be able to see our little datagram :).


$ sudo ./test_ip


We will see on wireshark something like that:



We do it!


Here the code:


ip.h
ip.c
testIP.c

Raw Socket: Introduction — 2011-12-07

Raw Socket: Introduction

Sockets are APIs (application programming interface) for creating comunication flows between two endpoints. Sockets create an interface above the Transport Layer, so we can use them in order to send data on the TCP/IP Application Layer.


Raw Sockets are little different. They create a low-level comunication flow, enabling us to work directly on IP layer or better over the Data-Link Layer. Basically, we have to write the TCP/IP headers and (re)write “freehand” the comunication protocol, like 3-Ways handshake or sliding windows managment.

Only a fool would use such a thing! A fool or someone who wants to analyze/manipulate the traffic. So the creation of a Raw Socket requires root privileges.


Thankfully the OS give us structures for protocol’s header (like ip, tcp, udp, icmp, arp…).

The normal execution flow is:

  • Creation of a trasmission buffer, to be filled with IP header ip and payload.
  • IP packet checksum computation.
  • Raw Socket creation.
  • Tell the operating system to avoid adding automatically IP Header.
  • Sending the trasmission buffer using sendto().
  • Wait for a reply using recivefrom(), filling the receive buffer with the answer.
  • 😛