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;
};
Related
To be precise I have created this simple TCP program to send a simple TCP packet over network to a destination machine, but somehow Don't really know, what am I doing wrong but it don't appear to be sending any packets to the destination host. also I can't find it in my wireshark.
rawtcp.c:
//---cat rawtcp.c---
// Run as root or SUID 0, just datagram no data/payload
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
// Packet length
#define PCKT_LEN 8192
#pragma pack(push, 1)
// May create separate header file (.h) for all
// headers' structures
// IP header's structure
struct ipheader {
unsigned char iph_ihl:4, /* Little-endian */
iph_ver:4;
unsigned char iph_tos;
unsigned short int iph_len;
unsigned short int iph_ident;
unsigned short int iph_offset;
unsigned char iph_ttl;
unsigned char iph_protocol;
unsigned short int iph_chksum;
unsigned int iph_sourceip;
unsigned int iph_destip;
};
/* Structure of a TCP header */
struct tcpheader {
unsigned short int tcph_srcport;
unsigned short int tcph_destport;
unsigned int tcph_seqnum;
unsigned int tcph_acknum;
unsigned char tcph_reserved:4, tcph_offset:4;
// unsigned char tcph_flags;
unsigned int
tcp_res1:4, /*little-endian*/
tcph_hlen:4, /*length of tcp header in 32-bit words*/
tcph_fin:1, /*Finish flag "fin"*/
tcph_syn:1, /*Synchronize sequence numbers to start a connection*/
tcph_rst:1, /*Reset flag */
tcph_psh:1, /*Push, sends data to the application*/
tcph_ack:1, /*acknowledge*/
tcph_urg:1, /*urgent pointer*/
tcph_res2:2;
unsigned short int tcph_win;
unsigned short int tcph_chksum;
unsigned short int tcph_urgptr;
};
#pragma pack(pop)
// Simple checksum function, may use others such as Cyclic Redundancy Check, CRC
unsigned short csum(unsigned short *buf, int len)
{
unsigned long sum;
for(sum=0; len>0; len--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
int main(int argc, char *argv[])
{
int sd;
// No data, just datagram
char buffer[PCKT_LEN];
// The size of the headers
struct ipheader *ip = (struct ipheader *) buffer;
struct tcpheader *tcp = (struct tcpheader *) (buffer + sizeof(struct ipheader));
struct sockaddr_in sin, din;
int one = 1;
const int *val = &one;
memset(buffer, 0, PCKT_LEN);
if(argc != 5)
{
printf("- Invalid parameters!!!\n");
printf("- Usage: %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(-1);
}
sd = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
if(sd < 0)
{
perror("socket() error");
exit(-1);
} else
printf("socket()-SOCK_RAW and tcp protocol is OK.\n");
// The source is redundant, may be used later if needed
// Address family
sin.sin_family = AF_INET;
din.sin_family = AF_INET;
// Source port, can be any, modify as needed
sin.sin_port = htons(atoi(argv[2]));
din.sin_port = htons(atoi(argv[4]));
// Source IP, can be any, modify as needed
sin.sin_addr.s_addr = inet_addr(argv[1]);
din.sin_addr.s_addr = inet_addr(argv[3]);
// IP structure
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
ip->iph_len = htons(sizeof(struct ipheader) + sizeof(struct tcpheader));
ip->iph_ident = htons(54321);
ip->iph_offset = 0;
ip->iph_ttl = 64;
ip->iph_protocol = 6; // TCP
ip->iph_chksum = 0; // Done by kernel
// Source IP, modify as needed, spoofed, we accept through command line argument
ip->iph_sourceip = inet_addr(argv[1]);
// Destination IP, modify as needed, but here we accept through command line argument
ip->iph_destip = inet_addr(argv[3]);
// The TCP structure. The source port, spoofed, we accept through the command line
tcp->tcph_srcport = htons(atoi(argv[2]));
// The destination port, we accept through command line
tcp->tcph_destport = htons(atoi(argv[4]));
tcp->tcph_seqnum = htonl(1);
tcp->tcph_acknum = 0;
tcp->tcph_offset = 5;
tcp->tcph_syn = 1;
tcp->tcph_ack = 0;
tcp->tcph_win = htons(32767);
tcp->tcph_chksum = 0; // Done by kernel
tcp->tcph_urgptr = 0;
// IP checksum calculation
ip->iph_chksum = htons(csum((unsigned short *) buffer, (sizeof(struct ipheader) + sizeof(struct tcpheader))));
// Inform the kernel do not fill up the headers' structure, we fabricated our own
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("setsockopt() error");
exit(-1);
} else
printf("setsockopt() is OK\n");
printf("Using:::::Destination IP: %s port: %u, Source IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));
// sendto() loop, send every 2 second for 50 counts
unsigned int count;
for(count = 0; count < 20; count++)
{
if(sendto(sd, buffer, ip->iph_len, 0, (struct sockaddr *)&din, sizeof(din)) < 0)
// Verify
{
perror("sendto() error");
exit(-1);
} else
printf("Count #%u - sendto() is OK\n", count);
sleep(2);
}
close(sd);
return 0;
}
while compiling it, it compiles just fine. also when I run the program as it suppose to be as ./rawtcp 192.168.1.152 1000 192.168.1.151 1000 it says:
socket()-SOCK_RAW and tcp protocol is OK.
setsockopt() is OK
Using:::::Destination IP: 192.168.1.151 port: 1000, Source IP: 192.168.1.152 port: 1000.
Count #0 - sendto() is OK
Count #1 - sendto() is OK
but while filtering wireshark as tcp.port == 1000 it never show up (Note: source ip is 192.168.1.152 and destination ip is 192.168.1.151). but If I do a simple hping3 -p 1000 192.168.1.151 it works just fine and I can see it in wireshark too.
I would really appreciate if you could tell me what am I doing wrong in my code :)
First of all, you are missing the <arpa/inet.h> header, which provides the inet_addr function you are using. Your program should still compile under C89 without this due to implicit function declaration but it is bad practice to rely on that and it could lead to subtle bugs.
One issue is your misuse of #pragma pack.
Before you declare your structs, you should do #pragma pack(push, 1), which both sets struct packing alignment to 1, and pushes the previous state of packing alignment to a stack. After you are finished declaring your structs, you can then do #pragma pack(pop) to reset struct packing back to normal in any following declarations. In the case of your program, omitting #pragma pack(pop) after your declarations should still work, but it is good practice to reset this, in case you ever do declare any other structs which you don't want to be tightly-packed, or you include any other header files afterwards.
#pragma pack(push, 1)
struct a {
/* ... */
};
struct b {
/* ... */
};
#pragma pack(pop)
The other problem with your struct ipheader is that you have both an 8-bit iph_flags and a 16-bit iph_offset, while the flags field in an IP header should be 3 bits and the offset field should be 13 bits (both of these together adding up to 16 bits). This means you have an extra 8 bits in your header which shouldn't be there. Since you are filling both of these fields with zero anyway, you can fix this by removing iph_flags from your struct completely, and just keeping the one 16-bit iph_offset field, filled with zero, which actually spans the space of the 3-bit and the 13-bit field in the IP header.
With these fixes, your program works for me and a packet can be seen in Wireshark.
I think your port is already used.
You should change port for 30000 or higher, the 1000 ports are often take by other applications
You should also debug using telnet [ip] [port]
I am sending TCP SYN packets (with no payload) to a webserver in the same network. I am using sniffex.c
for capturing the packets .
The problem is that after I send a SYN packet, I do not receive the SYN/ACK packet from server.
In sniffex.c:
I have used my LAN IP as the source ip.
I have set the filter as "tcp" .
I am sending to port 80
When i print the fields of the sent packet ,after i capture it using sniffex , all fields are printed correctly, hence i assume that the structure of the sent packet is such that the server can understand it.
When I connect to the webserver using browser, the SYN/ACK is received successfully.
Another related query: how do I set the filter such that I get packets relating to this conversation (b/w my pc and webserver) only
I am using UBUNTU 14.04
EDIT: The c file with which I am trying to send the packet
#define __USE_BSD /* use bsd'ish ip header */
#include <sys/socket.h> /* these headers are for a Linux system, but */
#include <netinet/in.h> /* the names on other systems are easy to guess.. */
#include <netinet/ip.h>
#define __FAVOR_BSD /* use bsd'ish tcp header */
#include <netinet/tcp.h>
#include <unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<memory.h>
#include<errno.h>
#include<sys/socket.h>
#include<sys/types.h>
#define P 80 /* 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 (AF_INET, SOCK_RAW, IPPROTO_TCP);
printf("s=%d\n",s); /* 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 ("xxx.xxx.xxx.xxx");
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 ("xxx.xxx.xxx.xxx");/* SYN's can be blindly spoofed */
iph->ip_dst.s_addr = sin.sin_addr.s_addr;
tcph->th_sport = htons (2000); /* arbitrary port */
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 = 5;
tcph->th_off = 5; /* 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 */
/* lets do it the ugly way.. */
int one = 1;
// const int *val = &one;
if (setsockopt (s, IPPROTO_IP, IP_HDRINCL, &one, sizeof (one)) < 0)
printf ("Warning: Cannot set HDRINCL!\terrno = %d\n",errno);
// 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 ("SUCCESS\n\n\n\n");
//}
char buffer[8192];
memset (buffer, 0, 8192);
int n;
//while(n=read (s, buffer, 8192) > 0)
//{
//printf("n=%d\n",n);
//printf ("Caught tcp packet: %s\n", buffer);
//memset (buffer, 0, 8192);
//}
return 0;
}
[Summary of chat session]
In addition to the iph->ip_off issue, you may need to compute the TCP checksum yourself (your O/S may not do it for you). Useful info is here: http://www.tcpipguide.com/free/t_TCPChecksumCalculationandtheTCPPseudoHeader-2.htm and http://www.netfor2.com/tcpsum.htm
Also tcph->th_seq = htonl(23456); may be useful.
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
I'm trying to send a raw packet using UDP, with the IP and UDP headers that I have constructed in my code. Raw packet successfully initialized with socket(PF_INET, SOCK_RAW, IPPROTO_UDP) and socket option set using setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(int)).
The problem is when I send the packet using sendto(), I get the error 'Message too long'.
My IP header is 20 bytes and UDP header 8 bytes and my data is 12 bytes. So the total is only 40 bytes. This can't possibly be too long for a single UDP packet. Can someone help?
The type of val is a pointer to an int
Here is my code:
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
//The packet length in byes
#define PCKT_LEN 50
//Date size in bytes
#define DATA_SIZE 12
//PseudoHeader struct used to calculate UDP checksum.
typedef struct PseudoHeader{
unsigned long int source_ip;
unsigned long int dest_ip;
unsigned char reserved;
unsigned char protocol;
unsigned short int udp_length;
}PseudoHeader;
// Ripped from Richard Stevans Book
unsigned short ComputeChecksum(unsigned char *data, int len)
{
long sum = 0; /* assume 32 bit long, 16 bit short */
unsigned short *temp = (unsigned short *)data;
while(len > 1){
sum += *temp++;
if(sum & 0x80000000) /* if high order bit set, fold */
sum = (sum & 0xFFFF) + (sum >> 16);
len -= 2;
}
if(len) /* take care of left over byte */
sum += (unsigned short) *((unsigned char *)temp);
while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);
return ~sum;
}
int BindRawSocketToInterface(int rawsock, char *addr, short int port)
{
struct sockaddr_in s_addr;
s_addr.sin_family = AF_INET;
s_addr.sin_addr.s_addr = inet_addr(addr);
s_addr.sin_port = htons(port);
if((bind(rawsock, (struct sockaddr *)&s_addr, sizeof(s_addr)))== -1)
{
perror("Error binding raw socket to interface\n");
exit(-1);
}
return 1;
}
// Fabricate the IP header or we can use the
// standard header structures but assign our own values.
struct ip *CreateIPHeader(char *srcip, char *destip)
{
struct ip *ip_header;
ip_header = (struct ip *)malloc(sizeof(struct ip));
ip_header->ip_v = 4;
ip_header->ip_hl = 5;
ip_header->ip_tos = 0;
ip_header->ip_len = htons(sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE);
ip_header->ip_id = htons(111);
ip_header->ip_off = 0;
ip_header->ip_ttl = 111;
ip_header->ip_p = IPPROTO_TCP;
ip_header->ip_sum = 0; /* We will calculate the checksum later */
inet_pton(AF_INET, srcip, &ip_header->ip_src);
inet_pton(AF_INET, destip, &ip_header->ip_dst);
/* Calculate the IP checksum now :
The IP Checksum is only over the IP header */
ip_header->ip_sum = ComputeChecksum((unsigned char *)ip_header, ip_header->ip_hl*4);
return (ip_header);
}
// Creates a the UDP header.
struct udphdr *CreateUdpHeader(char *srcport, char *destport )
{
struct udphdr *udp_header;
/* Check netinet/udp.h for header definiation */
udp_header = (struct udphdr *)malloc(sizeof(struct udphdr));
udp_header->source = htons(atoi(srcport));
udp_header->dest = htons(atoi(destport));
udp_header->len = htons(sizeof(struct udphdr) + DATA_SIZE); //TODO: need to specify this
udp_header->check = htons(0);
return (udp_header);
}
void CreatePseudoHeaderAndComputeUdpChecksum(struct udphdr *udp_header, struct ip *ip_header, unsigned char *data)
{
/*The TCP Checksum is calculated over the PseudoHeader + TCP header +Data*/
/* Find the size of the TCP Header + Data */
int segment_len = ntohs(ip_header->ip_len) - ip_header->ip_hl*4;
/* Total length over which TCP checksum will be computed */
int header_len = sizeof(PseudoHeader) + segment_len;
/* Allocate the memory */
unsigned char *hdr = (unsigned char *)malloc(header_len);
/* Fill in the pseudo header first */
PseudoHeader *pseudo_header = (PseudoHeader *)hdr;
pseudo_header->source_ip = ip_header->ip_src.s_addr;
pseudo_header->dest_ip = ip_header->ip_dst.s_addr;
pseudo_header->reserved = 0;
pseudo_header->protocol = ip_header->ip_p;
pseudo_header->udp_length = htons(segment_len);
/* Now copy TCP */
memcpy((hdr + sizeof(PseudoHeader)), (void *)udp_header, 8);
/* Now copy the Data */
memcpy((hdr + sizeof(PseudoHeader) + 8), data, DATA_SIZE);
/* Calculate the Checksum */
udp_header->check = ComputeChecksum(hdr, header_len);
/* Free the PseudoHeader */
free(hdr);
}
// Source IP, source port, target IP, target port from the command line arguments
int main(int argc, char *argv[])
{
int sd;
char buffer[PCKT_LEN];
char *data = "Hello World!";
// Source and destination addresses: IP and port
struct sockaddr_in to_addr;
int one = 1;
const int *val = &one;
printf("IP Header Size: %lu \n", sizeof(struct ip));
printf("UDP Header Size: %lu \n", sizeof(struct udphdr));
printf("Data Size: %d\n", DATA_SIZE);
printf("IP Total: %lu \n", sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE);
memset(buffer, 0, PCKT_LEN);
if(argc != 5)
{
printf("- Invalid parameters!!!\n");
printf("- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(-1);
}
// Create a raw socket with UDP protocol
sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if(sd < 0)
{
perror("socket() error");
exit(-1);
}
else
printf("socket() - Using SOCK_RAW socket and UDP protocol is OK.\n");
//Bind the socket to the source address and port.
BindRawSocketToInterface(sd, argv[1], atoi(argv[2]));
// Inform the kernel do not fill up the packet structure. we will build our own...
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(int)) < 0)
{
perror("setsockopt() error");
close(sd);
exit(-1);
}
else
printf("setsockopt() is OK.\n");
// The source is redundant, may be used later if needed
// The address family
to_addr.sin_family = AF_INET;
to_addr.sin_addr.s_addr = inet_addr(argv[3]);
to_addr.sin_port = htons(atoi(argv[4]));
//Create the IP header.
struct ip *ip_header = CreateIPHeader(argv[1], argv[3]);
//Create the UDP header.
struct udphdr *udp_header = CreateUdpHeader(argv[2], argv[4]);
//Compute UDP checksum
CreatePseudoHeaderAndComputeUdpChecksum(udp_header, ip_header, (unsigned char*)data);
//Copy IP header, UDP header, and data to the packet buffer.
memcpy(buffer, ip_header, sizeof(struct ip));
memcpy(buffer + sizeof(struct ip), udp_header, 8 /*sizeof(struct udphdr)*/);
memcpy(buffer + sizeof(struct ip) + 8, data, DATA_SIZE);
printf("Using raw socket and UDP protocol\n");
printf("Using Source IP: %s port: %u, Target IP: %s port: %u.\n", argv[1], atoi(argv[2]), argv[3], atoi(argv[4]));
if(sendto(sd, buffer, htons(20)/*ip_header->ip_len*/, 0, (struct sockaddr *)&to_addr, sizeof(to_addr)) < 0)
{
perror("sendto() error");
}
else
{
printf("sendto() is OK.\n");
}
free(ip_header);
free(udp_header);
close(sd);
return 0;
}
if(sendto(sd, buffer, htons(20)/*ip_header->ip_len*/, 0, (struct sockaddr *)&to_addr, sizeof(to_addr)) < 0)
The length here is wrong, you should not specify that in network byte order.
A simple 20 is enough. htons(20) will be a very large number on a little endian machine.
( if you want to send other things that just the IP header, you should include that too in the length,, sounds like your buffer is 40 bytes, not 20)
You can use my own function that i don't have your problem:
#define NDEBUG
#define COUNTMAX 3000
#define MAX_FAKE 100
#define ERROR -1
#define TYPE_A 1
#define TYPE_PTR 12
#define CLASS_INET 1
#define ERROR -1
#ifndef IPVERSION
#define IPVERSION 4
#endif /* IPVERISON */
#ifndef IP_MAXPACKET
#define IP_MAXPACKET 65535
#endif /* IP_MAXPACKET */
#define DNSHDRSIZE 12
#ifndef IP_MAXPACKET
#define IP_MAXPACKET 65535
#endif /* IP_MAXPACKET */
#define IPHDRSIZE sizeof(struct iphdr)
#define UDPHDRSIZE sizeof(struct udphdr)
int udp_send(int s, unsigned long saddr, unsigned long daddr,unsigned short sport,unsigned short dport,char *datagram, unsigned datasize)
{
struct sockaddr_in sin;
struct iphdr *ip;
struct udphdr *udp;
unsigned char *data;
unsigned char packet[4024];
ip = (struct iphdr *)packet;
udp = (struct udphdr *)(packet+IPHDRSIZE);
data = (unsigned char *)(packet+IPHDRSIZE+UDPHDRSIZE);
memset(packet,0,sizeof(packet));
udp->source = htons(sport);
udp->dest = htons(dport);
udp->len = htons(UDPHDRSIZE+datasize);
udp->check = 0;
memcpy(data,datagram,datasize);
ip->saddr.s_addr = saddr;
ip->daddr.s_addr = daddr;
ip->version = 4; /*ip version*/
ip->ihl = 5;
ip->ttl = 245;
ip->id = random()%5985;
ip->protocol = IPPROTO_UDP; /*protocol type*/
ip->tot_len = htons((IPHDRSIZE + UDPHDRSIZE + datasize));
ip->check = 0;
ip->check = in_cksum((char *)packet,IPHDRSIZE);
sin.sin_family=AF_INET;
sin.sin_addr.s_addr=daddr;
sin.sin_port=udp->dest;
printf ("socket: %d, packet: %s,size: %d, struct addr: %p, size: %i", s, packet, IPHDRSIZE+UDPHDRSIZE+datasize, (struct sockaddr*)&sin, sizeof(struct sockaddr));
return sendto(s, packet, IPHDRSIZE+UDPHDRSIZE+datasize, 0, (struct sockaddr*)&sin, sizeof(struct sockaddr));
}// end of udp_send function
The call to sendto() doesn't appear to be right as shown, even corrected per the comments:
Original: sendto(sd, buffer, htons(20)/ip_header->ip_len/,...);
Orr as corrected: sendto(sd, buffer, 20/ip_header->ip_len/,...);
The data length parameter should be the sum of header and data lengths: 20+8+12 = 40. A general solution could be:
sendto(sd, buffer, sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE,...);
With this change it started working for me.
I am trying to write a sample Raw socket program to clear my understanding of raw sockets. I create a Raw UDP socket and then call sendto. My sendto succeeds but I never see the packet received by the other side. I don't have any receive side running so I am relying on Wireshark running on both the sender and receiver.
I am pasting the code snippet here. Please point out any errors.
#include<stdio.h>
#include<stdlib.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<string.h>
#include "protHeaders.x"
#include "gen.h"
U16 csum(U16* buf, S32 nwords)
{
U32 sum;
for (sum = 0; nwords > 0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return ~sum;
}/*csum*/
int main(int argc,char** argv)
{
U8 datagram[MAX_IPPACKET];
U8 udpPayLoad[MAX_UDPPAYLOAD];
CustIpHeader* ipH;
CustUdpHeader* udpH;
struct sockaddr_in sin;
S32 sockFd;
S32 one = 1;
const S32* val = &one;
ipH = (CustIpHeader *)datagram;
udpH = (CustUdpHeader *)(datagram + sizeof(CustIpHeader));
memset(datagram,0,sizeof(datagram));
memset(udpPayLoad,0,sizeof(udpPayLoad));
memset(&sin,0,sizeof(struct sockaddr_in));
strcpy(udpPayLoad,"<<<<Aditya>>>>");
sin.sin_family = AF_INET;
sin.sin_port = htons(atoi(argv[4]));
/* fill the Ip header */
ipH->ip_hl = 5;
ipH->ip_v = 4;
ipH->ip_tos = 0;
ipH->ip_len = sizeof(CustIpHeader) + sizeof(CustUdpHeader) + strlen(udpPayLoad);
ipH->ip_id = htonl(54321);
ipH->ip_off = 0;
ipH->ip_p = 17;
ipH->ip_ttl = 65;
ipH->ip_sum = 0;
ipH->ip_src.s_addr = inet_addr(argv[1]);
ipH->ip_dst.s_addr = inet_addr(argv[3]);
/* fill the Udp header */
udpH->uh_sport = htons(atoi(argv[2]));
udpH->uh_dport = htons(atoi(argv[4]));
udpH->uh_len = sizeof(CustUdpHeader) + strlen(udpPayLoad);
udpH->uh_check = 0;
printf("Checksum = %u\n",udpH->uh_check);
/* copy udpPayLoad */
strcpy(datagram+sizeof(CustIpHeader)+sizeof(CustUdpHeader),udpPayLoad);
#if 1
printf("Datagram %p,UdpPayload %p\n",(void *)datagram,(void *)datagram+sizeof(CustIpHeader)+sizeof(CustUdpHeader));
printf("IpHeader %p, UdpHeader %p\n",(void *)ipH,udpH);
#endif
/* fill in the checksum */
ipH->ip_sum = csum((U16 *)datagram,ipH->ip_len >> 1);
printf("Checksum = %u\n",ipH->ip_sum);
if ((sockFd = socket(PF_INET,SOCK_RAW,IPPROTO_UDP)) < 0)
{
perror("socket:create");
RETURN(RFAILED);
}
/* doing the IP_HDRINCL call */
if (setsockopt(sockFd,IPPROTO_IP,IP_HDRINCL,val,sizeof(one)) < 0)
{
perror("Client:setsockopt");
}
while(1)
{
if ( sendto(sockFd,
datagram,
ipH->ip_len,
0,
(struct sockaddr *)&sin,
sizeof (sin)) < 0)
{ perror("Client:sendto"); }
else
printf(".");
}
RETURN(ROK);
}
The IP and UDP headers are:
typedef struct _ipheader
{
U8 ip_hl:4,ip_v:4; /* ip_hl: the ip header length in 32bit octets.
* ip_v : ip version (always 4 for our case).
*/
U8 ip_tos; /* reliability of the service. 0x00 is Normal */
U16 ip_len; /* totoal length including ip header,icmp/tcp/udp header
* and payload size in bytes
*/
U16 ip_id; /* sequence no. used for reassembly of fragmented IP packets */
U16 ip_off; /* the fragment offset used for reassembly of fragmented packets */
U16 ip_p; /* the transport layer protocol. can be tcp (6), udp(17) */
U8 ip_ttl; /* time to live */
U16 ip_sum; /* the datagram checksum for the whole IP packet */
struct in_addr ip_src; /* the source IP address, converted to a long format */
struct in_addr ip_dst; /* the desitnation IP address, converted to a long format */
}CustIpHeader; /* total ip header length: 20 bytes */
typedef struct _udpheader
{
U16 uh_sport; /* The source port that a client bind()s to */
U16 uh_dport; /* The desination port that a server bind()s to*/
U16 uh_len; /* The length of udp header and payload data in bytes */
U16 uh_check; /* The checksum of header and data */
}CustUdpHeader; /* total udp header length: 8 bytes (=64 bits) */
I am running as root user, so privileges is not a problem.
Language: C
Os: Linux
I had the wireshark running on a slow system. The packets were indeed being send but the Wireshark could only show them after a gap of 6 minutes or so. Moving to a faster system helped. I am therefore closing this myself.
This may help you to get started http://www.securitytube.net/Raw-Sockets-Basics-Presentation-video.aspx.
if you are using libcap/wincap i would have helped. but above video help you get started.