how to count the ipv4 tcp and udp using npcap in c++? - c++

I tried to code to give the statistics of a saved .pcap file in C++ using the npcap library.
My IPv4 count is correct and matches Wireshark's IPv4 count, but my TCP and UDP don't match with Wireshark's statistics.
Output of my code:
Output of the same .pcap file in Wireshark:
Here is my code:
void PcapSolutionFast::generateStats() {
ipv4_header* ip4;
ethernet_header* ethernet; /* The ethernet header */
u_short eth_type;
while (pcap_next_ex(pcap, &header, &data) >= 0) {
//count every packets
ethernet = (ethernet_header*)(data);
eth_type = ntohs(ethernet->ether_type);
if (eth_type == 0x0800) {
ip4 = (ipv4_header*)(data + 14); // 14 is header length of ethernet
if (ip4->proto == 6 /* tcp protocol number */) {
tcpCount++;
}
else if (ip4->proto == 17) {//udp protocol number
udpCount++;
}
ipv4Count++; //count total ipv4 packets
}
++packetCount; //count all the packets
}
These are the data structure used:
#define ETHER_ADDR_LEN 6 //mac address length is 6
#define ETHER_HEADER_LEN 14 //header length of ethernet is fixed i.e 14
/* Ethernet or MAC addresses are 6 bytes */
/* Ethernet header */
struct ethernet_header {
u_char ether_dhost[ETHER_ADDR_LEN]; /* Destination Mac address */
u_char ether_shost[ETHER_ADDR_LEN]; /* Source Mac address */
u_short ether_type; /* IP/ ARP/ RARP/ etc */
};
//divided each ip_address octet into 4 u_char
typedef struct ip_address {
u_char byte1;
u_char byte2;
u_char byte3;
u_char byte4;
}ip_address;
//ipv4 ip header
typedef struct ipv4_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
}ipv4_header;
/* IPv6 header */
typedef struct ipv6_header
{
unsigned int
version : 4,
traffic_class : 8,
flow_label : 20;
uint16_t length;
uint8_t next_header;
uint8_t hop_limit;
struct in6_addr saddr;
struct in6_addr daddr;
} ipv6_header;
Why is it that my TCP and UDP counts are not the same as Wireshark's statistics?

Related

TCP manual checksum calculation in C++

I'm using pcap to capture packets and now want to calculate IP checksum manually.
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 */
};
struct sniff_ip_16bit {
u_short a;
u_short b;
u_short c;
u_short d;
u_short e;
u_short f;
u_short g;
u_short h;
u_short i;
u_short j;
};
I have to divide the IP header into 16 bits, ones complement sum them, and ones complement the result.
I did following to cast them into 16bit fragments, and finally just sum all those elements.
ip->ip_sum = 0;
sniff_ip_16bit* ip_crc = reinterpret_cast<sniff_ip_16bit*>(&ip);
u_short ip_crc_calculated = ip_crc->a+ip_crc->b+ip_crc->c+ip_crc->d+ip_crc->e+ip_crc->f+ip_crc->g+ip_crc->h+ip_crc->i+ip_crc->j;
std::cout << "MNL CRC:" << std::bitset<16>(~ip_crc_calculated) << std::endl;
But yet I get wrong CRC results, the last two lines.
Packet number 4:
IP Header length : 20
From: 127.0.0.1
To: 127.0.0.1
Protocol: TCP
Len : 66 CLen: 66
Seq: 3415166211
Ack: 458071927
Src port: 45878
Dst port: 8080
Payload empty
CRC TCP: 0010100011111110
IP ID: 55139
CRC IP: 1110101011011000 //original
MNL CRC:0100011001111000

getting ip address of a packet in pcap file

I am programming with 'winpcap', I read a ".pcap" file in my program and after that I want to get the Ip addresses of packets, I've wrote these code for getting ip addresses,here is the piece of my code:
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 */
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 */};
and after that I read the file:
while (pcap_next_ex(handler, &header, &packet) >= 0)
{
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
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);
but the source and Ip addresses are the same!!!and it print the source and destination port incorrect!!what is the problem?what should I do for it?plz help me.
Source and destination ports are in network byte order (big-endian). Use ntohs to get them in the correct byte order for your machine. Same goes for SEQ and ACK, use ntohl for those.
The size of the IP header might not always be 20, multiply the value of ip_hdr_len with 4 to get the actual size.
If your compiler supports bitfields you can use them for your IP header declaration to make things easier:
struct sniff_ip {
u_char ip_hdr_len:4;
u_char ip_ver:4;
Fixed code:
while (pcap_next_ex(handler, &header, &packet) >= 0) {
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
if (ip->ip_p == 6 /* tcp protocol number */) {
tcp = (struct sniff_tcp*)(packet + SIZE_ETHERNET + ip->ip_hdr_len * 4);
u_short srcport = ntohs(tcp->th_sport);
u_short dstport = ntohs(tcp->th_dport);
printf("src port: %d dest port: %d \n", srcport, dstport);
char srcname[100];
strcpy(srcname, inet_ntoa(ip->ip_src));
char dstname[100];
strcpy(dstname, inet_ntoa(ip->ip_dst));
printf("src address: %s dest address: %s \n", srcname, dstname);
u_long seq = ntohl(tcp->th_seq);
u_long ack = ntohl(tcp->th_ack);
printf("seq number: %u ack number: %u \n", seq, ack);
}
}
Note that not every packet will contain TCP data, unless you applied a filter using pcap_compile and pcap_setfilter or can assure that the file you're reading contains only TCP packets. Therefore you might want to check the value of the IP headers protocol field to be 6 (TCP) as seen in the above code.
Also note that Wireshark by default displays relative SEQ and ACK numbers so they will not match with what you see there.
Structure packing should be fine.
First, make sure that the packets do, in fact, have an Ethernet header (do not assume they do!), by doing
if (pcap_datalink(handler) != DLT_EN10MB) {
fprintf(stderr, "%s is not an Ethernet capture\n",
{whatever the pathname of the file is});
exit(2);
}
after you've opened the capture file.
Then, you must make sure the packet really is an IPv4 packet, either by compiling the string "ip" as a filter, with pcap_compile(), and applying that to the file by calling pcap_setfilter() with handler and the compiled filter before you start reading, or by checking it in your read loop:
while (pcap_next_ex(handler, &header, &packet) >= 0) {
u_short ethertype;
/*
* For an Ethernet packet, the destination Ethernet
* address is in bytes 0 through 5, the source Ethernet
* address is in bytes 6 through 11, and the type/length
* field is in bytes 12 and 13.
*
* It's a big-endian value, so fetch the first byte, at
* an offset of 12, and put it in the upper 8 bits of
* the value, and then fetch the second byte, at an offset
* of 13, and put it in the lower 8 bits of the value.
*/
ethertype = (packet[12] << 8) | packet[13];
/*
* Now make sure it's the Ethernet type value for
* IPv4, which is 0x0800.
*/
if (ethertype != 0x0800) {
/*
* Skip this packet.
*/
continue;
}
/*
* Now we know it's an IPv4 packet, so process it as such.
*/
ip = (struct sniff_ip*)(packet + SIZE_ETHERNET);
Note: do NOT use bitfields for the version and header length fields, as there is no guarantee that they will be in the correct order. Instead, calculate the header length using ip_vhl, e.g.
size_ip = (ip->ip_vhl & 0x0F) * 4;
How to pack structures depends on your compiler; for example, gcc uses #pragma pack(). Google for pack pragma gcc or pack pragma visual c or whichever compiler you're using.
You need to save the results of inet_ntoa if you're calling it twice to printf, like in
char *srcname=strdup(inet_ntoa(ip->ip_src));
char *dstname=strdup(inet_ntoa(ip->ip_dst));
printf("src address: %s dest address: %s \n", srcname, dstname);
free(srcname);
free(dstname);
(Note that you should add error checking, the function result pointers might be NULL).
inet_ntoa() returns the dots-and-numbers string in a static buffer that is overwritten with each call to the function.
http://www.retran.com/beej/inet_ntoaman.html
// We can print the ip address for source and destination like this.
while (currpos < InLen){
pcktcnt++;
currpos = ftello64(InRaw);
if (fread((char *) &pckthdr, sizeof(pckthdr), 1, InRaw) != 1) {
break;
}
if (fread((char *) &pcktbuf, pckthdr.caplen, 1, InRaw) != 1) {
break;
}
/* Find stream in file, count packets and get size (in bytes) */
if( isgetTCPIP(pcktbuf, &size_ip, &size_tcp,fp)){
/* Simple example code */
char srcIp[INET_ADDRSTRLEN]; /*or malloc it later*/
char dstIp[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(ip->ip_src), srcIp, INET_ADDRSTRLEN);
inet_ntop(AF_INET, &(ip->ip_dst), dstIp, INET_ADDRSTRLEN);
fprintf("packet: %d, Src addr.: %s, Src port #: %d, Dest. addr: %s, Dest. port #: %d, \n",pcktcnt, srcIp, tcp->th_sport, dstIp, tcp->th_dport);
} // isgetTCPIP

Why does not the server respond with syn-ack packets when I send syn-packets with raw sockets?

I am experimenting with raw sockets and I have just written a small program that sends TCP packets with the syn flag set. I can see the packets coming with Wireshark on the server side and they look good, but the server never responds with any syn-ack packets.
I have compared the syn packets that my program constructs (see code below) with the ones that hping3 sends (because the packets of hping3 always get a syn-ack). The only that differs between my syn packets and hping3's syn packets are the ip identification number, tcp source port (which is randomized in hping3), tcp sequence number (which is also randomized in hping3) and the ip checksum field. All these four fields are based on some random numbers, that is why they differ. All other fields are equal! But my program does not get any syn-acks but hping3 does!
I am using Kali Linux for sending the packets (of course as root) and CentOS for the server.
Have I missed something essential or just missunderstood anything?
Removed code
EDIT
Here is the entire packet captured by Wireshark on the client side (divided into 4 images below). Note that the packets sent by hping3 are totally equal except the values for ip identification, source port, sequence number and checksum:
Images removed
Here is the hex dump of the packet.
Hexdump removed
EDIT 2 Ok, now I have created the pseudo header according to RFC793. The pseudo header is just used for the tcp checksum calculation. Now the IP header seems to be correct, but Wireshark complains about that the packet does not contain a full TCP header and it really seems corrupted because some of the fields contains strange values that I have not set.
First I allocate a buffer (called tcp_header) with space for the tcp header and the pseudo header. Second, I create a buffer for the ip header containing space for ip, tcp and pseudo headers.
First I fill the tcp_header with its data and then I copy it to the ip_header before sending it with the sendto function.
Does something go wrong when I copy the contents of tcp_packet to ip_packet or am I doing something else wrong?
#include <cstdlib>
#include <stdio.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#define __FAVOR_BSD 1
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <sys/ioctl.h>
#include <string.h>
#include <iostream>
#include <net/ethernet.h>
#include <time.h>
#define PCKT_LEN 1024
struct pseudohdr
{
__u32 saddr;
__u32 daddr;
__u8 zero;
__u8 protocol;
__u16 lenght;
};
#define PSEUDOHDR_SIZE sizeof(struct pseudohdr)
unsigned short csum(unsigned short *buf, int len) {
unsigned long sum;
for(sum=0; len>0; len-=2)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
int main(int argc, char** argv) {
srand(time(NULL));
char *ip_packet = new char[sizeof(struct iphdr) +
sizeof(struct tcphdr)]();
char *tcp_packet = new char[sizeof(struct pseudohdr) +
sizeof(struct tcphdr)]();
struct pseudohdr *pseudoheader = (struct pseudohdr*) tcp_packet;
class tcphdr *tcp = (struct tcphdr *) (tcp_packet + sizeof(struct pseudohdr));
class iphdr *ip = (struct iphdr *) ip_packet;
class sockaddr_in sin, din;
int sd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if(sd < 0) {
perror("socket() error");
exit(-1);
} else {
printf("socket()-SOCK_RAW and tcp protocol is OK.\n");
}
// Randomize src port
int srcport = rand()%100+25000;
sin.sin_family = AF_INET; // Address family
sin.sin_addr.s_addr = inet_addr("192.168.2.80");
sin.sin_port = htons(srcport); // Source port
din.sin_family = AF_INET;
din.sin_addr.s_addr = inet_addr("192.168.2.6");
din.sin_port = htons(80); // Destination port
/* tcp pseudo header */
memcpy(&pseudoheader->saddr, &sin.sin_addr.s_addr, 4);
memcpy(&pseudoheader->daddr, &din.sin_addr.s_addr, 4);
pseudoheader->protocol = 6; /* tcp */
pseudoheader->lenght = htons(sizeof(struct pseudohdr) + sizeof(struct tcphdr));
ip->ihl = 5;
ip->version = 4;
ip->tos = 0;
ip->tot_len = sizeof(class iphdr) + sizeof(class tcphdr);
ip->id = htons((getpid() & 255) + rand()%100+30000);
ip->frag_off = 0;
ip->ttl = 32;
ip->protocol = 6; // TCP
ip->check = 0; // Done by kernel
memcpy(&ip->saddr, (char*)&sin.sin_addr, sizeof(ip->saddr));
memcpy(&ip->daddr, (char*)&din.sin_addr, sizeof(ip->daddr));
// The TCP structure
tcp->th_sport = htons(srcport);
tcp->th_dport = htons(80); // Destination port
tcp->th_seq = htonl(rand()%100+1000);
tcp->th_ack = htonl(rand()%30);
tcp->th_off = 5;
tcp->th_flags = TH_SYN;
tcp->th_win = htons(1024);
tcp->th_urp = 0;
// Now calculate tcp checksum
tcp->th_sum = csum((unsigned short *) tcp_packet, sizeof(struct pseudohdr) + sizeof(struct tcphdr));
// Copy tcp_packet to ip_packet
memcpy(ip_packet + sizeof(struct iphdr), tcp_packet+sizeof(struct pseudohdr), sizeof(struct tcphdr));
// Bind socket to interface
int one = 1;
const int *val = &one;
const char opt[] = "eth0";
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof(one)) < 0) {
perror("setsockopt() error");
exit(-1);
}
else
printf("setsockopt() is OK\n");
if(sendto(sd, ip_packet, ip->tot_len, 0, (sockaddr*)&din, sizeof(din)) < 0) {
perror("sendto() error");
exit(-1);
}
else
printf("Send OK!");
close(sd);
return 0;
}
The tcp contents of the packet:
Images removed
Edit 3
Now I have found something interesting. Study the cheksums on this picture:
The checksum is in network order and shall thus be read in reversed order, as 0x06c0 (and not is as it is stated above as 0xc006). That is equal to the decimal value of 1728. Wireshark says the correct cheksum should be 0x12c0 which gives a decimal value of 4800.
4800-1728=3072. That is the difference between the actual checksum and the correct checksum calculated by Wireshark in all packets that is sent by my program.
So, if I simply add that value to the cheksum result:
tcp->th_sum = csum((unsigned short *) tcp_packet, sizeof(struct pseudohdr) + sizeof(struct tcphdr)) + 3072;
...then all packets get the correct checksum and receives a corresponding SYN-ACK.
Why the magic number 3072???
I am not content with the check sum algorithm you are using. The one suggested by Stevens:
uint16_t
in_cksum(uint16_t *addr, int len)
{
int nleft = len;
uint32_t sum = 0;
uint16_t *w = addr;
uint16_t answer = 0;
/*
* 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;
}
/* 4mop up an odd byte, if necessary */
if (nleft == 1) {
*(unsigned char *)(&answer) = *(unsigned char *)w ;
sum += answer;
}
/* 4add 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);
}

Wireshark doesn't detect any packet sent. sendto return 0

I have been trying to send packets using raw socket in following code.This code I found somewhere in the internet. I created my own ipheader and udp header. The whole data packet is sent using sendto() function on raw socket. sendto() returns 0. Which means a packet of 0 length is sent out of it and hence even wireshark doesnt detect any packet. Where is my mistake?
// Must be run by root lol! Just datagram, no payload/data
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <cstdlib>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
// The packet length
#define PCKT_LEN 35
// Can create separate header file (.h) for all headers' structure
// The IP header's structure
struct ipheader {
unsigned char iph_ihl:4, iph_ver:4;
unsigned char iph_tos;
unsigned short int iph_len;
unsigned short int iph_ident;
unsigned char iph_flag;
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;
};
// UDP header's structure
struct udpheader {
unsigned short int udph_srcport;
unsigned short int udph_destport;
unsigned short int udph_len;
unsigned short int udph_chksum;
};
// total udp header length: 8 bytes (=64 bits)
// Function for checksum calculation. From the RFC,
// the checksum algorithm is:
// "The checksum field is the 16 bit one's complement of the one's
// complement sum of all 16 bit words in the header. For purposes of
// computing the checksum, the value of the checksum field is zero."
unsigned short csum(unsigned short *buf, int nwords)
{ //
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
// Source IP, source port, target IP, target port from the command line arguments
int main(int argc, char *argv[])
{
int sd;
// No data/payload just datagram
char buffer[PCKT_LEN];
// Our own headers' structures
struct ipheader *ip = (struct ipheader *) buffer;
struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct ipheader));
// Source and destination addresses: IP and port
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);
}
// Create a raw socket with UDP protocol
sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if(sd < 0)
{
perror("socket() error");
// If something wrong just exit
exit(-1);
}
else
printf("socket() - Using SOCK_RAW socket and UDP protocol is OK.\n");
// The source is redundant, may be used later if needed
// The address family
sin.sin_family = AF_INET;
din.sin_family = AF_INET;
// Port numbers
sin.sin_port = htons(atoi(argv[2]));
din.sin_port = htons(atoi(argv[4]));
// IP addresses
sin.sin_addr.s_addr = inet_addr(argv[1]);
din.sin_addr.s_addr = inet_addr(argv[3]);
// Fabricate the IP header or we can use the
// standard header structures but assign our own values.
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16; // Low delay
ip->iph_len = sizeof(struct ipheader) + sizeof(struct udpheader);
ip->iph_ident = htons(54321);
ip->iph_ttl = 64; // hops
ip->iph_protocol = 17; // UDP
// Source IP address, can use spoofed address here!!!
ip->iph_sourceip = inet_addr(argv[1]);
// The destination IP address
ip->iph_destip = inet_addr(argv[3]);
// Fabricate the UDP header. Source port number, redundant
udp->udph_srcport = htons(atoi(argv[2]));
// Destination port number
udp->udph_destport = htons(atoi(argv[4]));
udp->udph_len = htons(sizeof(struct udpheader));
// Calculate the checksum for integrity
ip->iph_chksum = csum((unsigned short *)buffer, sizeof(struct ipheader) + sizeof(struct udpheader));
// Inform the kernel do not fill up the packet structure. we will build our own...
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("setsockopt() error");
exit(-1);
}
else
printf("setsockopt() is OK.\n");
// Send loop, send for every 2 second for 100 count
printf("Trying...\n");
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]));
int count;
int i;
for(count = 1; count <=20; count++)
{
if(i = sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
// Verify
{
perror("sendto() error");
exit(-1);
}
else
{
printf("Count #%u - sendto() is OK. Data Length#%d\n", count,i);
sleep(2);
}
}
close(sd);
return 0;
}
Aha! I've got at least part of it.
i = sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0
is the same as
i = (sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
you probably want:
(i = sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin))) < 0
You may want to:
Turn on warnings in your compiler - at least if you use gcc, that should give you a warning for comparing and assigning in the same if-statement.
Retry with the fixed code.
I'm sure there may be other problems in your code too - I'm no network expert.
It is really hard to read this piece of code and to understand what and why you're doing. So I can recoomend you look at my piece of code: dhcp client implementation
Look at function getSock() to see how socket is created, and on function talker() on how to form and send completed packet.
Local IP header structure is wrong... my suggestion is to include the IP header provided with your distro (are you using linux? don't you?).
What i did is just include linux/ip.h, rename ipheader structure reference to iphdr, and rename the ip header fields according to the structure described in the latter file.
I tried to sniff packets with tcpdump and it works now (i didn't try with wireshark but it must work too)
Try this fixed code:
// Must be run by root lol! Just datagram, no payload/data
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/udp.h>
#include <linux/ip.h>
// The packet length
#define PCKT_LEN 35
// UDP header's structure
struct udpheader {
unsigned short int udph_srcport;
unsigned short int udph_destport;
unsigned short int udph_len;
unsigned short int udph_chksum;
};
// total udp header length: 8 bytes (=64 bits)
// Function for checksum calculation. From the RFC,
// the checksum algorithm is:
// "The checksum field is the 16 bit one's complement of the one's
// complement sum of all 16 bit words in the header. For purposes of
// computing the checksum, the value of the checksum field is zero."
unsigned short csum(unsigned short *buf, int nwords)
{ //
unsigned long sum;
for(sum=0; nwords>0; nwords--)
sum += *buf++;
sum = (sum >> 16) + (sum &0xffff);
sum += (sum >> 16);
return (unsigned short)(~sum);
}
// Source IP, source port, target IP, target port from the command line arguments
int main(int argc, char *argv[])
{
int sd;
// No data/payload just datagram
char buffer[PCKT_LEN];
// Our own headers' structures
struct iphdr *ip = (struct iphdr *) buffer;
struct udpheader *udp = (struct udpheader *) (buffer + sizeof(struct iphdr));
// Source and destination addresses: IP and port
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);
}
// Create a raw socket with UDP protocol
sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if(sd < 0)
{
perror("socket() error");
// If something wrong just exit
exit(-1);
}
else
printf("socket() - Using SOCK_RAW socket and UDP protocol is OK.\n");
// The source is redundant, may be used later if needed
// The address family
sin.sin_family = AF_INET;
din.sin_family = AF_INET;
// Port numbers
sin.sin_port = htons(atoi(argv[2]));
din.sin_port = htons(atoi(argv[4]));
// IP addresses
sin.sin_addr.s_addr = inet_addr(argv[1]);
din.sin_addr.s_addr = inet_addr(argv[3]);
// Fabricate the IP header or we can use the
// standard header structures but assign our own values.
ip->ihl = 5;
ip->version = 4;
ip->tos = 16; // Low delay
ip->tot_len = sizeof(struct iphdr) + sizeof(struct udpheader);
ip->id = htons(54321);
ip->ttl = 64; // hops
ip->protocol = 17; // UDP
// Source IP address, can use spoofed address here!!!
ip->saddr = inet_addr(argv[1]);
// The destination IP address
ip->daddr = inet_addr(argv[3]);
// Fabricate the UDP header. Source port number, redundant
udp->udph_srcport = htons(atoi(argv[2]));
// Destination port number
udp->udph_destport = htons(atoi(argv[4]));
udp->udph_len = htons(sizeof(struct udpheader));
// Calculate the checksum for integrity
ip->check = csum((unsigned short *)buffer, sizeof(struct iphdr) + sizeof(struct udpheader));
// Inform the kernel do not fill up the packet structure. we will build our own...
if(setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("setsockopt() error");
exit(-1);
}
else
printf("setsockopt() is OK.\n");
// Send loop, send for every 2 second for 100 count
printf("Trying...\n");
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]));
int count;
int i;
for(count = 1; count <=20; count++)
{
if((i = sendto(sd, buffer, PCKT_LEN, 0, (struct sockaddr *)&sin, sizeof(sin))) < 0)
// Verify
{
perror("sendto() error");
exit(-1);
}
else
{
printf("Count #%u - sendto() is OK. Data Length# %d\n", count,i);
sleep(2);
}
}
close(sd);
return 0;
}
I'm guessing you based that on this example code, which has multiple fatal bugs. It has wasted many hours of my life.
But to answer this specific question (and to help anyone else who is unfortunate enough to try to use that code), the bug that prevents you from seeing the packets in wireshark is here:
sin.sin_addr.s_addr = inet_addr(argv[1]);
This sets the address used for sending the packet in sentdo() to the source address. Therefore, the packet is sent over the loopback interface, and it goes nowhere. (Wireshark or other capture tools will be able to see the packet if you capture the lo/loopback interface, fwiw.)
So the corrected line for this particular program is:
sin.sin_addr.s_addr = inet_addr(argv[3]);

Problem with IP_HDRINCL?

I already asked this question on raw IP packet implementation. But I didn't get any solutions.
My code:
if((s = WSASocket(AF_INET, SOCK_RAW, IPPROTO_TCP, 0, 0, 0))==SOCKET_ERROR) // Socket
{
printf("Creation of raw socket failed.");
return 0;
}
if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval))==SOCKET_ERROR)
{
printf("failed to set socket in raw mode.");
return 0;
}
if((sendto(s ,(char *) buf , sizeof(IPV4_HDR)+sizeof(TCP_HDR) + payload, 0,(SOCKADDR *)&dest, sizeof(dest)))==SOCKET_ERROR)
{
printf("Error sending Packet : %d",WSAGetLastError());
break;
}
Error:
WSAGetLastError() returns 10022:
Description:
An invalid argument (for example, an argument that specified an invalid level) was supplied to the setsockopt (Wsapiref_94aa.asp) function. Sometimes, it also refers to the current state of the sockets, for example, calling accept (Wsapiref_13aq.asp) on a socket that is not listening.
Commentary:
But I have set the correct option value and size.
What am I doing wrong? I am using Windows XP (SP3). In setsocketopt I tried IP_OPTIONS for that program it works fine and it sends IP Packets too. But in ethereal for every IP packet it generates ICMP packets from the destination.
How can I fix this?
Source code:
//raw tcp packet crafter
#include "stdio.h"
#include "winsock2.h"
#include "ws2tcpip.h" //IP_HDRINCL is here
#include "conio.h"
typedef struct ip_hdr
{
unsigned char ip_header_len:4; // 4-bit header length (in 32-bit words) normally=5 (Means 20 Bytes may be 24 also)
unsigned char ip_version :4; // 4-bit IPv4 version
unsigned char ip_tos; // IP type of service
unsigned short ip_total_length; // Total length
unsigned short ip_id; // Unique identifier
unsigned char ip_frag_offset :5; // Fragment offset field
unsigned char ip_more_fragment :1;
unsigned char ip_dont_fragment :1;
unsigned char ip_reserved_zero :1;
unsigned char ip_frag_offset1; //fragment offset
unsigned char ip_ttl; // Time to live
unsigned char ip_protocol; // Protocol(TCP,UDP etc)
unsigned short ip_checksum; // IP checksum
unsigned int ip_srcaddr; // Source address
unsigned int ip_destaddr; // Source address
} IPV4_HDR, *PIPV4_HDR, FAR * LPIPV4_HDR;
// TCP header
typedef struct tcp_header
{
unsigned short source_port; // source port
unsigned short dest_port; // destination port
unsigned int sequence; // sequence number - 32 bits
unsigned int acknowledge; // acknowledgement number - 32 bits
unsigned char ns :1; //Nonce Sum Flag Added in RFC 3540.
unsigned char reserved_part1:3; //according to rfc
unsigned char data_offset:4; /*The number of 32-bit words in the TCP header.
This indicates where the data begins.
The length of the TCP header is always a multiple
of 32 bits.*/
unsigned char fin :1; //Finish Flag
unsigned char syn :1; //Synchronise Flag
unsigned char rst :1; //Reset Flag
unsigned char psh :1; //Push Flag
unsigned char ack :1; //Acknowledgement Flag
unsigned char urg :1; //Urgent Flag
unsigned char ecn :1; //ECN-Echo Flag
unsigned char cwr :1; //Congestion Window Reduced Flag
////////////////////////////////
unsigned short window; // window
unsigned short checksum; // checksum
unsigned short urgent_pointer; // urgent pointer
} TCP_HDR , *PTCP_HDR , FAR * LPTCP_HDR , TCPHeader , TCP_HEADER;
int main()
{
char host[100],buf[1000],*data=NULL,source_ip[20]; //buf is the complete packet
SOCKET s;
int k=1;
IPV4_HDR *v4hdr=NULL;
TCP_HDR *tcphdr=NULL;
int payload=512 ;
int optval= 1;
SOCKADDR_IN dest;
hostent *server;
//Initialise Winsock
WSADATA wsock;
printf("\nInitialising Winsock...");
if (WSAStartup(MAKEWORD(2,2),&wsock) != 0)
{
fprintf(stderr,"WSAStartup() failed");
exit(EXIT_FAILURE);
}
printf("Initialised successfully.");
////////////////////////////////////////////////
//Create Raw TCP Packet
printf("\nCreating Raw TCP Socket...");
if((s = WSASocket(AF_INET, SOCK_RAW, IPPROTO_TCP, 0, 0, 0))==SOCKET_ERROR)
{
printf("Creation of raw socket failed.");
return 0;
}
printf("Raw TCP Socket Created successfully.");
////////////////////////////////////////////////
//Put Socket in RAW Mode.
printf("\nSetting the socket in RAW mode...");
if(setsockopt(s, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof(optval))==SOCKET_ERROR)
{
printf("failed to set socket in raw mode.");
return 0;
}
printf("Successful.");
////////////////////////////////////////////////
//Target Hostname
printf("\nEnter hostname : ");
gets(host);
printf("\nResolving Hostname...");
if((server=gethostbyname(host))==0)
{
printf("Unable to resolve.");
return 0;
}
dest.sin_family = AF_INET;
dest.sin_port = htons(8888); //your destination port
memcpy(&dest.sin_addr.s_addr,server->h_addr,server->h_length);
printf("Resolved.");
/////////////////////////////////////////////////
printf("\nEnter Source IP : ");
gets(source_ip);
v4hdr = (IPV4_HDR *)buf; //lets point to the ip header portion
v4hdr->ip_version=4;
v4hdr->ip_header_len=5;
v4hdr->ip_tos = 0;
v4hdr->ip_total_length = htons ( sizeof(IPV4_HDR) + sizeof(TCP_HDR) + payload );
v4hdr->ip_id = htons(2);
v4hdr->ip_frag_offset = 0;
v4hdr->ip_frag_offset1 = 0;
v4hdr->ip_reserved_zero = 0;
v4hdr->ip_dont_fragment = 1;
v4hdr->ip_more_fragment = 0;
v4hdr->ip_ttl = 8;
v4hdr->ip_protocol = IPPROTO_TCP;
v4hdr->ip_srcaddr = inet_addr(source_ip);
v4hdr->ip_destaddr = inet_addr(inet_ntoa(dest.sin_addr));
v4hdr->ip_checksum = 0;
tcphdr = (TCP_HDR *)&buf[sizeof(IPV4_HDR)]; //get the pointer to the tcp header in the packet
tcphdr->source_port = htons(1234);
tcphdr->dest_port = htons(8888);
tcphdr->cwr=0;
tcphdr->ecn=1;
tcphdr->urg=0;
tcphdr->ack=0;
tcphdr->psh=0;
tcphdr->rst=1;
tcphdr->syn=0;
tcphdr->fin=0;
tcphdr->ns=1;
tcphdr->checksum = 0;
// Initialize the TCP payload to some rubbish
data = &buf[sizeof(IPV4_HDR) + sizeof(TCP_HDR)];
memset(data, '^', payload);
printf("\nSending packet...\n");
while(!_kbhit())
{
printf(" %d packets send\r",k++);
if((sendto(s ,(char *) buf , sizeof(IPV4_HDR)+sizeof(TCP_HDR) + payload, 0,(SOCKADDR *)&dest, sizeof(dest)))==SOCKET_ERROR)
{
printf("Error sending Packet : %d",WSAGetLastError());
break;
}
}
return 0;
}
You can't send data on a raw tcp socket in windows.
From here:
"Limitations on Raw Sockets
On Windows 7, Windows Vista, Windows XP with Service Pack 2 (SP2), and Windows XP with Service Pack 3 (SP3), the ability to send traffic over raw sockets has been restricted in several ways:
TCP data cannot be sent over raw sockets.
UDP datagrams with an invalid source address cannot be sent over raw sockets. The IP source address for any outgoing UDP datagram must exist on a network interface or the datagram is dropped. This change was made to limit the ability of malicious code to create distributed denial-of-service attacks and limits the ability to send spoofed packets (TCP/IP packets with a forged source IP address).
A call to the bind function with a raw socket for the IPPROTO_TCP protocol is not allowed.
"
Well, seems you don't have a counterparty to send to.
You have created the socket and set its option, but then you need either listen for incoming connection (bind() + accept()) or connect() to other party.
Error description: Sometimes, it also refers to the current state of the sockets - I guess it's your case. Your socket is not in connected state so sendto() is invalid.
Btw, for reference, there is a discussion regarding 'optval', whether it is bool or int. Apparently 'int' is the better choice, but I've seen lots of examples with bool.
Set IP_HDRINCL to setsockopt function in win32
I had used 'bool' and my program worked fine on Windows XP. Now it doesn't work on Win 7, with the 10022 error code.