I use pcap to capture ICMP packets. In "main" function I set filter "char filter_exp[] = "icmp";", compile it and use "pcap_loop(handle, num_packets, got_packet, NULL);" to capture ICMP packets.
In function got_packet program detects ICMP, but I can't understand how to get and print size of ICMP packet.
I tried to use somthing like this:
case IPPROTO_ICMP:
printf(" Protocol: ICMP\n");
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
size_tcp = TH_OFF(tcp)*4;
printf("~~~~ %u ~~~~", size_tcp);
return;
but sometimes it prints "28", "36", or "0". I don't understand how ICMP packet size can be equal to zero. It seems like something wrong.
Can you help me write code, that print ICMP packet size?
Full code:
#include <pcap.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
/* 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 */
};
/* 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 */
};
void
got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet);
/*
* dissect/print packet
*/
void
got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
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 */
int size_ip;
int size_tcp;
int size_payload;
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");
return;
case IPPROTO_UDP:
printf(" Protocol: UDP\n");
return;
case IPPROTO_ICMP:
printf(" Protocol: ICMP\n");
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
size_tcp = TH_OFF(tcp)*4;
printf("~~~~ %u ~~~~", size_tcp);
return;
case IPPROTO_IP:
printf(" Protocol: IP\n");
return;
default:
printf(" Protocol: unknown\n");
return;
}
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[] = "icmp"; /* 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 = 3; /* number of packets to capture */
/* 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");
exit(EXIT_FAILURE);
}
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);
}
/* 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;
}
Now I try this code and it prints "~~~ 98 ~~~". Is this code valid, or not?
void
got_packet(u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
...
...
/* determine protocol */
switch(ip->ip_p) {
case IPPROTO_TCP:
printf(" Protocol: TCP\n");
return;
case IPPROTO_UDP:
printf(" Protocol: UDP\n");
return;
case IPPROTO_ICMP:
printf(" Protocol: ICMP\n");
//tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
//size_tcp = TH_OFF(tcp)*4;
printf("~~~~ %u ~~~~", header->len);
return;
...
No, it isn't correct. I launched tcpdump, and it prints "length 64".
Related
I am working on a sniffing and spoofing project using C and the pcap library. I have to admit, I am still learning this library and it is taking me forever. That being said, I am having some issues with my program. I cannot get it to properly send my ICMP reply. The idea of the program is that it sniffs for any ICMP requests on its network and sends a reply. Currently, the program executes but I cannot seem to get the reply to actually send correctly. I am fairly certain that the error is in the "SpoofReply()" function or the "Send_Raw_Packet()". Here is code:
*EDIT FOR CLARITY: The program should send an ICMP Reply to any ICMP request. Test using a ping command to any non functional IP desitination (1.1.1.1). Without program, there should be no response. If program is running on same network as ping request, (I just run from the same machine) then it should create an ICMP reply from "1.1.1.1". Spoofing. However, my reply never actually sends when I run the program. It detects the request and attemps to create a response, but the logic is wrong somewhere.
#include <pcap.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <unistd.h>
/* ethernet headers are always exactly 14 bytes [1] */
#define SIZE_ETHERNET 14
/* Ethernet addresses are 6 bytes */
#define ETHER_ADDR_LEN 6
#define PACKET_LEN 1500
#define BUFSIZE 1500
/* Ethernet header */
struct ethheader {
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 */
};
/* IP Header */
struct ipheader {
unsigned char iph_ihl:4, iph_ver:4; //IP Header length & Version.
unsigned char iph_tos; //Type of service
unsigned short int iph_len; //IP Packet length (Both data and header)
unsigned short int iph_ident; //Identification
unsigned short int iph_flag:3, iph_offset:13; //Flags and Fragmentation offset
unsigned char iph_ttl; //Time to Live
unsigned char iph_protocol; //Type of the upper-level protocol
unsigned short int iph_chksum; //IP datagram checksum
struct in_addr iph_sourceip; //IP Source address (In network byte order)
struct in_addr iph_destip;//IP Destination address (In network byte order)
};
/* ICMP Header */
struct icmpheader {
unsigned char icmp_type; //ICMP message type
unsigned char icmp_code; //Error code
unsigned short int icmp_chksum; //Checksum for ICMP Header and data
unsigned short int icmp_id; //Used in echo request/reply to identify request
unsigned short int icmp_seq;//Identifies the sequence of echo messages,
//if more than one is sent.
};
/* TCP Header */
struct tcpheader {
u_short tcp_sport; /* source port */
u_short tcp_dport; /* destination port */
u_int tcp_seq; /* sequence number */
u_int tcp_ack; /* acknowledgement number */
u_char tcp_offx2; /* data offset, rsvd */
#define TH_OFF(th) (((th)->tcp_offx2 & 0xf0) >> 4)
u_char tcp_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 tcp_win; /* window */
u_short tcp_sum; /* checksum */
u_short tcp_urp; /* urgent pointer */
};
/* UDP Header */
struct udpheader
{
u_int16_t udp_sport; /* source port */
u_int16_t udp_dport; /* destination port */
u_int16_t udp_ulen; /* udp length */
u_int16_t udp_sum; /* udp checksum */
};
struct pseudo_tcp
{
unsigned saddr, daddr;
unsigned char mbz;
unsigned char ptcl;
unsigned short tcpl;
struct tcpheader tcp;
char payload[PACKET_LEN];
};
// DNS layer header's structure
struct dnsheader {
unsigned short int query_id;
unsigned short int flags;
unsigned short int QDCOUNT;
unsigned short int ANCOUNT;
unsigned short int NSCOUNT;
unsigned short int ARCOUNT;
};
unsigned short in_cksum(unsigned short *buf,int length)
{
unsigned short *w = buf;
int nleft = length;
int sum = 0;
unsigned short temp=0;
/*
* The algorithm uses a 32 bit accumulator (sum), adds
* sequential 16 bit words to it, and at the end, folds back all the
* carry bits from the top 16 bits into the lower 16 bits.
*/
while (nleft > 1) {
sum += *w++;
nleft -= 2;
}
/* treat the odd byte at the end, if any */
if (nleft == 1) {
*(u_char *)(&temp) = *(u_char *)w ;
sum += temp;
}
/* 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
return (unsigned short)(~sum);
}
/****************************************************************************
TCP checksum is calculated on the pseudo header, which includes the
the TCP header and data, plus some part of the IP header. Therefore,
we need to construct the pseudo header first.
*****************************************************************************/
unsigned short calculate_tcp_checksum(struct ipheader *ip)
{
struct tcpheader *tcp = (struct tcpheader *)((u_char *)ip +
sizeof(struct ipheader));
int tcp_len = ntohs(ip->iph_len) - sizeof(struct ipheader);
/* pseudo tcp header for the checksum computation */
struct pseudo_tcp p_tcp;
memset(&p_tcp, 0x0, sizeof(struct pseudo_tcp));
p_tcp.saddr = ip->iph_sourceip.s_addr;
p_tcp.daddr = ip->iph_destip.s_addr;
p_tcp.mbz = 0;
p_tcp.ptcl = IPPROTO_TCP;
p_tcp.tcpl = htons(tcp_len);
memcpy(&p_tcp.tcp, tcp, tcp_len);
return (unsigned short)in_cksum((unsigned short *)&p_tcp, tcp_len + 12);
}
/****************************************************************************
Function to actually send the spoofed IP reply.
*****************************************************************************/
void send_raw_packet (struct ipheader* ip)
{
int n = 0;
struct sockaddr_in dest_info;
int enable = 1;
//create a raw network socket and set its options.
int sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &enable, sizeof(enable));
//provide needed information about destination
dest_info.sin_family = AF_INET;
dest_info.sin_addr = ip->iph_destip;
//dest_info.sin_addr.s_addr = ip->iph_sourceip.s_addr;
//send out the packet
printf("Attmpting to send a spoofed ICMP packet! \n");
printf("......................................\n");
/*print the source and destination IP Addresses*/
printf(" From: %s\n", inet_ntoa(ip->iph_sourceip));
printf(" To: %s\n", inet_ntoa(ip->iph_destip));
printf("......................................\n");
while (n<2){
sendto(sock, ip, ntohs(ip->iph_len), 0, (struct sockaddr *)&dest_info, sizeof(dest_info));
printf("Oooooo....a spoofed ICMP packet has successfully been sent! \n");
n++;
}
close(sock);
}
/****************************************************************************
Function designed to spoof the ICMP reply
*****************************************************************************/
void spoofReply(struct ipheader* ip)
{
int ip_header_len = ip->iph_ihl * 4;
const char buffer[BUFSIZE];
struct icmpheader* icmp = (struct icmpheader *) ((u_char *)ip + ip_header_len);
if (icmp->icmp_type != 8) //this is not a reply, this is a request
{
printf("Packet received was not an ICMP request. Nothing sent.\n");
return;
}
//copy the original packet to a buffer
memset((char*)buffer, 0, BUFSIZE);
memset((char*)buffer, (int) ip, ntohs(ip->iph_len));
struct ipheader * newip = (struct ipheader *) buffer; //check this line for an error!!!
struct icmpheader * newicmp = (struct icmpheader *) ((u_char *)buffer + ip_header_len);
//new IP construction
newip->iph_sourceip.s_addr = ip->iph_destip.s_addr;
newip->iph_destip.s_addr = ip->iph_sourceip.s_addr;
newip->iph_ttl = 20;
newip->iph_protocol = IPPROTO_ICMP;
//fill ICMP info
newicmp->icmp_type = 0;
//checksum
newicmp->icmp_chksum = 0;
newicmp->icmp_chksum = in_cksum((unsigned short *)newicmp, ntohs(ip->iph_len) - ip_header_len);
printf("Packet is for sure an ICMP Request. Lets send a raw packet!\n");
send_raw_packet(newip);
}
/****************************************************************************
Packet Handler- This function handles incoming packets and checks for ICMP
protocol. Calls spoofReply() if the packet is an ICMP Request.
spoofed ICMP reply if the incoming packet is an ICMP request.
*****************************************************************************/
void gotPacket (u_char *args, const struct pcap_pkthdr *header, const u_char *packet)
{
struct ethheader *eth = (struct ethheader *) packet;
if (eth->ether_type != ntohs(0x0800)) return; //this is not an IP packet
struct ipheader* ip = (struct ipheader*)(packet + SIZE_ETHERNET);
int ip_header_len = ip->iph_ihl * 4;
printf("......................................\n");
/*print the source and destination IP Addresses*/
printf(" From: %s\n", inet_ntoa(ip->iph_sourceip));
printf(" To: %s\n", inet_ntoa(ip->iph_destip));
if (ip->iph_protocol == IPPROTO_ICMP)
{
printf("Whoa! An ICMP packet has been found! Lets check it out.\n");
spoofReply(ip);
}
}
int main()
{
pcap_t *handle;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program fp;
char filter_exp[] = "";
bpf_u_int32 net;
//Print name of program and its filter:
printf("Sniff...Sniff...Sniff...\n");
printf("Cole Sniffer Started. Filtering %s \n", filter_exp);
//open the live session using the pcap_open function
handle = pcap_open_live("eth13", BUFSIZ, 1, 1000, errbuf);
//set the filter for whichever type of traffic you would like to receive
pcap_compile(handle, &fp, filter_exp, 0, net);
//set filter (continued)
pcap_setfilter(handle, &fp);
pcap_loop(handle, 100, gotPacket, NULL); // captures the packets
pcap_close(handle);
return 0;
};
I'm Trying to make this following code to access multiple .pcap files stored in a directory and capture the source IP address. After which i will have to anonymize it with the list of ip addresses from a txt file.
I'm at the first step, i'm unable to open multiple offline .pcap files stored in a directory and print its source and destination ip address. The following code works fine when i pass the .pcap file in commad line. I need help in solving this issue first. Thank You.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <pcap.h> //library for parsing pcap files
#define SIZE_ETHERNET 14
#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 */
};
/* 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;
struct in_addr ip_dst; /* source and dest address */
};
#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip) (((ip)->ip_vhl) >> 4)
/* TCP header */
struct sniff_tcp {
u_short th_sport; /* source port */
u_short th_dport; /* destination port */
u_int32_t th_seq; /* sequence number */
u_int32_t 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 */
};
void main(int argc, char *argv[])
{
//get filestring
string *filename = "/HiWi/pcap_files/*.pcap";
//error buffer
char errbuff[PCAP_ERRBUF_SIZE];
//open file and create pcap handler
pcap_t * handler = pcap_open_offline(filename.c_str(), errbuff);
//The header that pcap gives us
struct pcap_pkthdr *header;
//The actual packet
const u_char *packet;
int packetCount = 0;
int i;
//write to file
FILE *fp = fopen ( "result.txt", "w" ) ;
//tcp info
const struct sniff_ethernet *ethernet; /* The ethernet header */
const struct sniff_ip *ip; /* The IP header */
const struct sniff_tcp *tcp; /* The TCP header */
u_int size_ip;
u_int size_tcp;
while (pcap_next_ex(handler, &header, &packet) >= 0)
{
// Show the packet number
printf("Packet # %i\n", ++packetCount);
fprintf(fp,"Packet # %i\n", packetCount);
// Show the size in bytes of the packet
printf("Packet size: %d bytes\n", header->len);
fprintf(fp,"Packet size: %d bytes\n", header->len);
// Show a warning if the length captured is different
if (header->len != header->caplen)
printf("Warning! Capture size different than packet size: %ld bytes\n", header->len);
// Show Epoch Time
printf("Epoch Time: %d:%d seconds\n", header->ts.tv_sec, header->ts.tv_usec);
fprintf(fp,"Epoch Time: %d:%d seconds\n", header->ts.tv_sec, header->ts.tv_usec);
ethernet = (struct sniff_ethernet*)(packet);
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;
}
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + size_ip);
printf("src port: %d dest port: %d \n", tcp->th_sport, tcp->th_dport);
fprintf(fp,"src port: %d dest port: %d \n", tcp->th_sport, tcp->th_dport);
printf("src address: %s dest address: %s \n", inet_ntoa(ip->ip_src), inet_ntoa(ip->ip_dst));
fprintf(fp,"src address: %s dest address: %s \n", inet_ntoa(ip->ip_src), inet_ntoa(ip->ip_dst));
printf("seq number: %u ack number: %u \n", (unsigned int)tcp-> th_seq, (unsigned int)tcp->th_ack);
fprintf(fp,"seq number: %u ack number: %u \n", (unsigned int)tcp-> th_seq, (unsigned int)tcp->th_ack);
// Add two lines between packets
printf("\n");
fprintf(fp,"\n");
}
fclose (fp);
return;
}
string *filename = "/HiWi/pcap_files/*.pcap";
When you pass that string from the command line it is likely your shell does globbing for you and the program actually ends up with a few real paths. On the other hand pcap_open_offline expects real paths - does no globbing - so it just reports "No, I didn't find that file called *.pcap".
You will have to do globbing yourself, perhaps using glob(3). In essence it will give you a glob_t with a number of paths. You simply need to do pcap_open_offline each file in turn and so on. I suggest you make a function taking a filename that does all this so you can call it for each file.
Here is a code snippet im having with some help from the pcap tutorials. Im using a prebuilt pcap file (extension .pcap) for parsing and printing the addresses. Im trying to print mac addresses, ip addresses, tcp ports.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pcap.h> //library for parsing pcap files
/ethernet headers are always 14 bytes
//IP flags
#define IP_RSRV_FLG 0x8000 // IP's reserved fragment flag
#define IP_DNT_FRAG 0x4000 // flag for not fragmenting
#define IP_MRE_FRAG 0x2000 // Flag for more fragmenting
#define IP_MASK 0x1fff //mask for fragmenting.
//TCP flags
#define TH_ACK 0x10
#define TH_URG 0x20
#define TH_ECE 0x40
#define TH_CWR 0x80
#define TH_FIN 0x01
#define TH_SYN 0x02
#define TH_RST 0x04
#define TH_PUSH 0x08
#define TH_FLAGS (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
/***************************************
*
* Structs to represent headers
*
***************************************/
struct ethernet_h{
u_char ether_dest_host[ETHER_ADDR_LEN]; //the destination host address
u_char ether_src_host[ETHER_ADDR_LEN]; //the source host address
u_short ether_type; //to check if its ip etc
};
struct ip_h{
unsigned char ip_vhl; //assuming its ipv4 and header length more than 2
unsigned char service; //type of service
unsigned short total_len; //total length
unsigned short identification; // identification
u_short ip_off; //offset field
u_char ttl; // time to live value
u_char ip_protocol; // the protocol
u_short sum; //the checksum
unsigned long ip_src;
unsigned long ip_dst;
#define IP_HL(ip) (((ip)->ip_vhl) & 0x0f)
#define IP_V(ip) (((ip)->ip_vhl) >> 4)
};
struct tcp_h{
u_short src_port; /* source port */
u_short dst_port; /* destination port */
};
int main(int argc, char * argv[]){
pcap_t *pcap;
char errbuf [PCAP_ERRBUF_SIZE];
const unsigned char *packet;
struct pcap_pkthdr header;
int i;
/*Header Structs*/
const struct ethernet_h *ethernet;
const struct ip_h *ip;
const struct tcp_h *tcp;
/* check if the correct number of parameters are passed */
if ( argc != 2 )
{
printf("\n\t\t Incorrect number of arguments provided");
printf("\n\t\t Command format <<packet_headers.c>> <<capture1.pcap>>");
}
/*check if the correct file for trace is passed */
/*if ( ! (strcmp(argv[1],"capture1.pcap")) )
{
printf("\n\t\t Please provide the correct pcap trace file. ");
exit(2);
}*/
/*opening trace file*/
if ((pcap = pcap_open_offline(argv[1],errbuf)) == NULL){
fprintf(stderr, "cant read file %s : %s\n",
argv[0],errbuf);
exit(1);
}
/* reading packets */
for (i = 0; (packet = pcap_next(pcap,&header)) != NULL; i++){
printf("-------- Packet %d ------------\n",i);
printf(" Size: %d bytes",header.len);
/*ethernet map */
ethernet = (struct ethernet_h*) (packet);
printf("\n MAC src: %s", ethernet->ether_src_host);
printf("\n MAC dest: %s", ethernet->ether_dest_host);
ip = (struct ip_h*) (packet + sizeof(struct ethernet_h));
printf("\n IP src: %lu", ip->ip_src);
printf("\n IP dest: %lu",ip->ip_dst);
tcp = (struct tcp_h*) (packet + sizeof(struct ethernet_h) + sizeof(struct ip_h));
printf("\n Src port ; %d", ntohs(tcp->src_port));
printf("\n Dst port ; %d", ntohs(tcp->dst_port));
printf("\n");
}
}
BUt this isnt giving the correct output. I know there is some problem with typecasting/converting values but can't figure out the issue. i get garbage values for IP addresses, and incorrect nos for tcp ports. please let me know whats wrong.
printf("From: %s\n", inet_ntoa(ip->ip_src)); // network to ascii
printf(" To: %s\n", inet_ntoa(ip->ip_dst));
I think I figured it out. I was using your code to learn libpcap actually. You have to pass ip->ip_src, dst and mac src, dst to the inet_ntoa() function, which converts ip, mac addresses to readable strings. You have to change the types of the ip and mac addresses in your structs to struct in_addr.
struct in_addr ip_src,ip_dst;
and
struct in_addr ether_dest_host, ether_src_host;
to print them out just call printf with %s.
printf("\n IP SRC : %s", inet_ntoa(ip->ip_src));
I'm programming software which can send tcp packets to an host.
I'm able to create a packet with IP header, TCP Headers and data but I can't manage how to add TCP options like MSS, NOP, STACK, Window scaling or Timestamp.
I mean i'm not able to add options to the TCP header, calculate the correct checksum to send a good TCP packet to the host.
I can just send correct TCP packets without TCP options.
Do you think I'm on the correct patch? Could somebody please help me?
/* TCP Header structure */
struct tcphdr
{
u_int16_t th_sport; /* source port */
u_int16_t th_dport; /* destination port */
u_int32_t th_seq; /* sequence number */
u_int32_t th_ack; /* acknowledgement number */
#if __BYTE_ORDER == __LITTLE_ENDIAN
u_int8_t th_x2:4; /* (unused) */
u_int8_t th_off:4; /* data offset */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
u_int8_t th_off:4; /* data offset */
u_int8_t th_x2:4; /* (unused) */
#endif
u_int8_t 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
u_int16_t th_win; /* window */
u_int16_t th_sum; /* checksum */
u_int16_t th_urp; /* urgent pointer */
};
struct tcp_option_mss
{
uint8_t kind; /* 2 */
uint8_t len; /* 4 */
uint16_t mss;
} __attribute__((packed));
struct tcphdr_mss
{
struct tcphdr tcphdr;
struct tcp_option_mss mss;
};
/* IP Header structure */
struct ip
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
unsigned int ip_hl:4; /* header length */
unsigned int ip_v:4; /* version */
#endif
#if __BYTE_ORDER == __BIG_ENDIAN
unsigned int ip_v:4; /* version */
unsigned int ip_hl:4; /* header length */
#endif
u_int8_t 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_int8_t ip_ttl; /* time to live */
u_int8_t ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src, ip_dst; /* source and dest address */
};
int send_packet(int sock, long dest_ip , long source_ip, long port, u_int8_t th_flags, unsigned long seq, unsigned long ack, unsigned long port1, unsigned char * data, unsigned long data_i)
{
char * packet;
struct ip * pkt_ip;
struct tcphdr * pkt_tcp;
struct tcphdr_mss * tcp_header;
struct sockaddr_in sin;
packet = malloc(sizeof(struct ip) + sizeof(struct tcphdr_mss) + data_i);
if (packet == NULL)
{
if (ECHO)
fprintf(stderr, "Error in allocating memory\n");
exit(EXIT_FAILURE);
}
memset(packet, 0, sizeof(struct ip) + sizeof(struct tcphdr_mss));
pkt_ip = (struct ip *) packet;
pkt_tcp = (struct tcphdr *) (packet + sizeof(struct ip));
pkt_tcp->th_sport = htons(port1);
pkt_tcp->th_dport = htons(port);
pkt_tcp->th_seq = htonl(seq);
pkt_tcp->th_ack = htonl(ack);
pkt_tcp->th_off = sizeof(struct tcphdr) / 4 + 1;
pkt_tcp->th_flags = th_flags;
pkt_tcp->th_win = htons(32768);
pkt_tcp->th_sum = 0;
tcp_header = malloc(sizeof(struct tcphdr));
tcp_header->tcphdr = *pkt_tcp;
tcp_header->mss.kind = 2;
tcp_header->mss.len = 4;
tcp_header->mss.mss = htons(32000);
pkt_ip->ip_v = 4;
pkt_ip->ip_hl = sizeof(struct ip) >> 2;
pkt_ip->ip_tos = 0;
pkt_ip->ip_len = htons(sizeof(struct ip) + sizeof(struct tcphdr) + data_i);
if (ipid > 65000)
ipid = 0;
ipid++;
pkt_ip->ip_id = ipid;
pkt_ip->ip_off = 0;
pkt_ip->ip_ttl = 64;
pkt_ip->ip_p = IPPROTO_TCP ;
pkt_ip->ip_sum = 0;
pkt_ip->ip_src.s_addr = source_ip;
pkt_ip->ip_dst.s_addr = dest_ip;
pkt_ip->ip_sum = checksum((unsigned short*)pkt_ip, sizeof( struct ip) );
pkt_tcp->th_sum = in_cksum_tcp(pkt_ip->ip_src.s_addr, pkt_ip->ip_dst.s_addr, (unsigned short *) pkt_tcp, sizeof(struct tcphdr_mss), data, data_i);
memcpy(((char *)pkt_tcp + sizeof(struct tcphdr_mss)), data, data_i);
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = pkt_ip->ip_dst.s_addr;
if (sendto(sock, packet, sizeof(struct ip) + sizeof(struct tcphdr_mss) + data_i, 0, (struct sockaddr *) &sin, sizeof(sin)) < 0)
{
perror("sendto");
free(packet);
return -1;
}
free(packet);
return 0;
}
In the line:
pkt_tcp->th_sum = in_cksum_tcp(pkt_ip->ip_src.s_addr, pkt_ip->ip_dst.s_addr, (unsigned short *) pkt_tcp, sizeof(struct tcphdr_mss), data, data_i);
According to the in_cksum_tcp function that i've seen in the wild:
unsigned short in_cksum_tcp(int src, int dst, unsigned short *addr, int len, unsigned char * data, int data_i)
You are passing the size of the options header (sizeof(struct tcphdr_mss)), instead the size of the complete TCP header (sizeof (tcphdr) + sizeof(tcphdr_mss)). I think this could be the problem (you don't compute correctly the TCP checksum).
A good way to check wich is the problem creating raw packets is to save the packet with libpcap to a pcap file and open with the wireshark. You could check easily the integrity of the packet.
Below is a function which calculate correct checksum for a packet
unsigned short csum(unsigned short * ptr, int nbytes) {
register long sum;
unsigned short oddbyte;
register short answer;
sum = 0;
while (nbytes > 1) {
sum += * ptr++;
nbytes -= 2;
}
if (nbytes == 1) {
oddbyte = 0; * ((u_char * ) & oddbyte) = * (u_char * ) ptr;
sum += oddbyte;
}
sum = (sum >> 16) + (sum & 0xffff);
sum = sum + (sum >> 16);
answer = (short)~sum;
return (answer);
}
call the function to get checksum for ip and tcp.
other then this inorder to use option like options like MSS, NOP, STACK you need to declare all this in your TCP header. and when you are using all this in your program you have to set the value of th_off accordingly
This program should catch a packet from offline dump file and decode it. Here I have problems with ntohs() function (it's near the end, headers description in the start). Why it does not work?
OS win7 x86, VS 2010 express.
#include "pcap.h"
#define SIZE_ETHERNET 14
#define ETHER_ADDR_LEN 6
/* 4 bytes IP address */
typedef struct ip_address{
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}ip_address;
/* IPv4 header */
typedef struct ip_header{
u_char ver_ihl; // Version (4 bits) + Internet header length (4 bits)
u_char tos; // Type of service
u_short tlen; // Total length
u_short identification; // Identification
u_short flags_fo; // Flags (3 bits) + Fragment offset (13 bits)
u_char ttl; // Time to live
u_char proto; // Protocol
u_short crc; // Header checksum
ip_address saddr; // Source address
ip_address daddr; // Destination address
u_int op_pad; // Option + Padding
}ip_header;
/* UDP header*/
typedef struct udp_header{
u_short sport; // Source port
u_short dport; // Destination port
u_short len; // Datagram length
u_short crc; // Checksum
}udp_header;
typedef struct ethernet_address{
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
u_char byte5;
u_char byte6;
}ethernet_address;
/* Ethernet header */
typedef struct ethernet_header {
ethernet_address ether_dhost; /* Destination host address */
ethernet_address ether_shost; /* Source host address */
u_short ether_type; /* IP? ARP? RARP? etc */
};
/* TCP header */
typedef struct tcp_header {
u_short th_sport; /* source port */
u_short th_dport; /* destination port */
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 */
}tcp_header;
/* prototype of the packet handler */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data);
/* Packet count */
int num = 1;
int main(int argc, char **argv)
{
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
char source[PCAP_BUF_SIZE];
u_int netmask;
char packet_filter[] = "";
struct bpf_program fcode;
if(argc != 2){
printf("usage: %s filename", argv[0]);
return -1;
}
/* Create the source string according to the new WinPcap syntax */
if ( pcap_createsrcstr( source, // variable that will keep the source string
PCAP_SRC_FILE, // we want to open a file
NULL, // remote host
NULL, // port on the remote host
argv[1], // name of the file we want to open
errbuf // error buffer
) != 0)
{
fprintf(stderr,"\nError creating a source string\n");
return -1;
}
/* Open the adapter */
if ( (adhandle= pcap_open(source, // name of the device
65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
1000, // read timeout
NULL, // remote authentication
errbuf // error buffer
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n");
return -1;
}
/* Check the link layer. We support only Ethernet for simplicity. */
if(pcap_datalink(adhandle) != DLT_EN10MB)
{
fprintf(stderr,"\nThis program works only on Ethernet networks.\n");
return -1;
}
/* if(d->addresses != NULL)
Retrieve the mask of the first address of the interface
netmask=((struct sockaddr_in *)(d->addresses->netmask))->sin_addr.S_un.S_addr;
else */
/* If the interface is without addresses we suppose to be in a C class network */
netmask=0xffffff;
//compile the filter
if (pcap_compile(adhandle, &fcode, packet_filter, 1, netmask) <0 )
{
fprintf(stderr,"\nUnable to compile the packet filter. Check the syntax.\n");
return -1;
}
//set the filter
if (pcap_setfilter(adhandle, &fcode)<0)
{
fprintf(stderr,"\nError setting the filter.\n");
return -1;
}
/* start the capture */
pcap_loop(adhandle, 0, packet_handler, NULL);
return 0;
}
/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
struct tm ltime;
char timestr[16];
time_t local_tv_sec;
u_int ip_len;
u_short sport,dport;
ip_header *ih;
const struct ethernet_header *ethh; /* The ethernet header */
/*
* Unused variable
*/
(VOID)(param);
printf("Packet %d\n", num);
num++;
/* convert the timestamp to readable format */
local_tv_sec = header->ts.tv_sec;
localtime_s(<ime, &local_tv_sec);
strftime( timestr, sizeof timestr, "%H:%M:%S", <ime);
/* print timestamp and length of the packet */
// printf("%s.%.6d len:%d ", timestr, header->ts.tv_usec, header->len);
/* retireve the position of the ethernet header */
ethh = (struct ethernet_header*)(pkt_data);
/* retireve the position of the ip header */
ih = (ip_header *) (pkt_data + 14); //length of ethernet header
/* retireve the position of the udp header */
ip_len = (ih->ver_ihl & 0xf) * 4;
/* print ip addresses and ports */
printf("Eth Src: %x:%x:%x:%x:%x:%x >>> Dest: %x:%x:%x:%x:%x:%x\nIP Src: %d.%d.%d.%d >>> Dest: %d.%d.%d.%d\n",
ethh->ether_shost.byte1,
ethh->ether_shost.byte2,
ethh->ether_shost.byte3,
ethh->ether_shost.byte4,
ethh->ether_shost.byte5,
ethh->ether_shost.byte6,
ethh->ether_dhost.byte1,
ethh->ether_dhost.byte2,
ethh->ether_dhost.byte3,
ethh->ether_dhost.byte4,
ethh->ether_dhost.byte5,
ethh->ether_dhost.byte6,
ih->saddr.byte1,
ih->saddr.byte2,
ih->saddr.byte3,
ih->saddr.byte4,
ih->daddr.byte1,
ih->daddr.byte2,
ih->daddr.byte3,
ih->daddr.byte4
);
/* Panage protocols */
if(ih->proto == 0x11)
{
udp_header *uh;
uh = (udp_header *) ((u_char*)ih + ip_len);
printf("UDP Src: %d >>> Dest: %d\n", uh->sport,uh->dport);
}
else if(ih->proto == 0x06)
{
tcp_header *tcp = NULL;
/* convert from network byte order to host byte order */
tcp = (tcp_header *) ((u_char*)ih + ip_len);
/*HERE*/ sport = ntohs(tcp->th_sport);
/*HERE*/ dport = ntohs(tcp->th_dport);
printf("TCP Src: %d >>> Dest: %d\n", sport,dport);
}
}
error log:
1>------ Build started: Project: cw1, Configuration: Debug Win32 ------
1> cw1.c
1>cw1.obj : error LNK2019: unresolved external symbol __imp__ntohs#4 referenced in function _packet_handler
1>C:\Users\Medardas\Desktop\ComputerScience\C.SC251 - CW1\cw1\Debug\cw1.exe : fatal error LNK1120: 1 unresolved externals
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Try including <arpa/inet.h> or <netinet/in.h>. Failing that, check your linker settings.
That's a linker error. Consult the documentation of the function. At the bottom of that page (all such pages are laid out the same way) you will find the details of what header, lib and DLL are needed. In this case you need to link against Ws2_32.lib.