how can I get IP src addr from a raw socket - c

I want to sent TCP packets via raw socket and then I got stuck with the checksum field of tcp header. since I dont know how to figure out the actual IP address that raw socket had used, it seems impossible to construct TCP pseudo-header for checksum computation.

You know the ip address.
Because: Prior to sending any data over this socket you ought to bind() it, for doing so you need to specify the ip address you are looking for.
Update:
Binding to INADDR_ANY binds to any local interface. To get information on all local interfaces (including each's ip address) you might use getifaddrs().

Look at the following code if its any help. I used this code to make my own send_raw_tcp() function so i know it works.
//---cat rawtcp.c---
// Run as root or SUID 0, just datagram no data/payload
#include <unistd.h>mm
#include <netinet/tcp.h>
// Packet length
#define PCKT_LEN 8192
// May create separate header file (.h) for all
// headers' structures
// IP header's structure
struct ipheader {
unsigned char iph_ihl:5, /* Little-endian */
iph_ver:4;
unsigned char iph_tos;
unsigned short int iph_len;
unsigned short int iph_ident;
unsigned char iph_flags;
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;
};
// 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 = 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 = 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:::::Source IP: %s port: %u, Target 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 *)&sin, sizeof(sin)) < 0)
// Verify
{
perror("sendto() error");
exit(-1);
}
else
printf("Count #%u - sendto() is OK\n", count);
sleep(2);
}
close(sd);
return 0;
}

Related

sending custom tcp packet using sendto() in c?

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]

get ECHO REPLY with data from server to client behind nat

I have to write c program that send ICMP ECHO REQUEST from phone(it is connected by Mobile isp and it is behind NAT)to server with IP PUBLIC. i wrote a simple program that sends echo request and receives echo reply but now i want to send ECHO REQUEST from client to server and receive ECHO REPLY with some data(an IP PUBLIC and ICMP ID) from server to client. How can i make that?
Herre's my code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
typedef unsigned char u8;
typedef unsigned short int u16;
struct icmp_header{
unsigned char type;
unsigned char code;
unsigned short checksum;
unsigned short id;
unsigned short seq;
};
unsigned short in_cksum(unsigned short *ptr, int nbytes);
int main(int argc, char **argv){
int c=100;
int ls;//lunghezza struct sockaddr_in serveraddr
int rf;//receive from
unsigned long daddr;
unsigned long saddr;
int payload_size = 0, sent = 0, sent_size;
saddr = inet_addr("IP PRIVATE");
daddr = inet_addr("IP PUBLIC");
//Raw socket - if you use IPPROTO_ICMP, then kernel will fill in the correct ICMP header checksum, if IPPROTO_RAW, then it wont
int sockfd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sockfd < 0){
perror("could not create socket");
return (0);
}
int on = 1;
// We shall provide IP headers
if (setsockopt (sockfd, IPPROTO_IP, IP_HDRINCL, (const char*)&on, sizeof (on)) == -1){
perror("setsockopt");
return (0);
}
//allow socket to send datagrams to broadcast addresses
if (setsockopt (sockfd, SOL_SOCKET, SO_BROADCAST, (const char*)&on, sizeof (on)) == -1){
perror("setsockopt");
return (0);
}
//Calculate total packet size
int packet_size = sizeof (struct iphdr) + sizeof (struct icmp_header) + payload_size;
char *buffer = (char *) malloc (packet_size);
char *packet = (char *) malloc (packet_size);
if (!packet){
perror("out of memory");
close(sockfd);
return (0);
}
//ip header
struct iphdr *ip = (struct iphdr *) packet;
//struct icmphdr *icmp = (struct icmphdr *) (packet + sizeof (struct iphdr));
struct icmp_header *icmphdr = (struct icmp_header *) (packet + sizeof(struct iphdr));
//zero out the packet buffer
memset (packet, 0, packet_size);
memset (buffer, 0, packet_size);
ip->version = 4;
ip->ihl = 5;
ip->tos = 0;
ip->tot_len = htons (packet_size);
ip->id = rand ();
ip->frag_off = 0;
ip->ttl = 255;
ip->protocol = IPPROTO_ICMP;
ip->saddr = saddr;
ip->daddr = daddr;
//ip->check = in_cksum ((u16 *) ip, sizeof (struct iphdr));
//icmp->type = ICMP_ECHO significa ECHO REQUEST
//icmp->code = 0 รจ il codice dei ECHO REQUEST
icmphdr->type = ICMP_ECHO;
icmphdr->code = 0;
icmphdr->id = 5;
icmphdr->seq = 66;
//checksum
icmphdr->checksum = 0;
struct sockaddr_in servaddr;
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = daddr;
memset(&servaddr.sin_zero, 0, sizeof (servaddr.sin_zero));
puts("flooding...");
//while (1)
while(c>0){
memset(packet + sizeof(struct iphdr) + sizeof(struct icmp_header), rand() % 255, payload_size);
//memset(buffer + sizeof(struct iphdr) + sizeof(struct icmphdr), rand() % 255, payload_size);
//recalculate the icmp header checksum since we are filling the payload with random characters everytime
icmphdr->checksum = 0;
icmphdr->checksum = in_cksum((unsigned short *)icmphdr, sizeof(struct icmp_header) + payload_size);
if ( (sent_size = sendto(sockfd, packet, packet_size, 0, (struct sockaddr*) &servaddr, sizeof (servaddr))) < 1){
perror("send failed\n");
break;
}
++sent;
printf("%d packets sent\r", sent);
fflush(stdout);
ls = sizeof(servaddr);
//rf = recvfrom(sockfd, buffer, 42, 0, (struct sockaddr *)&servaddr, &ls);
rf = recvfrom(sockfd, buffer, packet_size, 0, (struct sockaddr *)&servaddr, &ls);
if(rf < 0){
perror("Errore recvfrom\n");
break;
}
else{
char *cp;
struct iphdr *ip_reply = (struct iphdr *)buffer;
cp = (char *)&ip_reply->saddr;
printf("Received %d byte reply from %u.%u.%u.%u:\n", ntohs(ip_reply->tot_len), cp[0]&0xff,cp[1]&0xff,cp[2]&0xff,cp[3]&0xff);
printf("ID: %d\n", ntohs(ip_reply->id));
printf("TTL: %d\n", ip_reply->ttl);
}
usleep(10000); //microseconds
c--;
}
free (buffer);
free(packet);
close(sockfd);
return (0);
}
/*
Function calculate checksum
*/
unsigned short in_cksum(unsigned short *ptr, int nbytes){
register long sum;
u_short oddbyte;
register u_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 >> 16);
answer = ~sum;
return (answer);
}
ANSWER.
Ok, i solve problem. I create custom icmp header with unsigned char array as payload (pay in this example). i use this array, in server side, to store data in this way
memcpy(pay, (unsigned char *)&icmp->id, 2); //here i store incoming icmp echo request id.
Then i prepare sending buffer
struct eth_frame *eths = (struct eth_frame *) buffer;
crea_eth(eths,0x0800,mactarget);//create eth frame
struct ip_datagram *ips = (struct ip_datagram*) eths->payload;
struct icmp_packet *icmps = (struct icmp_packet*) ips->payload;
Then i build custom icmp echo reply and custom ip packet that i have to send from server to client
memcpy(icmps->payload, &pay, 10);
icmps->type = 0;
icmps->code = 0;
icmps->checksum = 0;
icmps->id = (icmp->id);//i use same receiving icmp id
icmps->seq = htons(1);
icmps->checksum = //calculate checksum
ips->ver_ihl = 0x45;
ips->tos = 0x00;
ips->totlen = htons(20 + 8 + 8);
ips->id = 0xABCD;
ips->flags_offs = 0;
ips->ttl = 255;
ips->proto = IPPROTO_ICMP;
ips->checksum = 0;
ips->src = *(unsigned int *)serverip;
ips->dst = *(unsigned int *)clientip;//fill with IP PUBLIC ADDRESS OF CLIENT!!
ips->checksum = htons(calcola_checksum((unsigned char*)ips,20));
Then send icmp packet from server to client
unsigned char *p = (unsigned char *)&addr;
for(i = 0;i < sizeof(struct sockaddr_ll);i++)
p[i] = 0;
addr.sll_family = AF_PACKET;
addr.sll_ifindex = 3;
/*send to*/
n=sendto(s, buffer, 14 + 20 + 8 + 8 , 0 , (struct sockaddr*) &addr , sizeof(addr));

No output when using raw socket to send spoofed packets via multicast to different subnet

My application is a specialized user space UDP router that uses raw sockets to produce unicast and multicast output with actual or spoofed source addresses in the IP packet headers of the sent packets.
Briefly, there is one permutation of the outputs that fails to reach some of the destination hosts.
My question: is there some subtle logic in the Linux stack that prevents certain routing permutations, or is the output function I am using missing something?
I can't create a UDP packet writer that successfully sends packets that (1) contain a spoofed source address, (2) to a multicast address, (3) if sending host is on subnet A, (4) receiving host is on subnet B, if the (valid) spoofed source address is on subnet A.
Subnet A = 10.200.xx.nn
Subnet B = 10.200.yy.nn
Source address in packet = sending host
Subnet
Src addr = sender addr A A B B
Receiver A B A B
Result Yes Yes Yes Yes
Source address in packet != sending host
Subnet
Sender A A A A B B B B
Spoofed src addr A A B B A A B B
Receiver A B A B A B A B
Result Yes Yes Yes No No Yes Yes Yes
The spoof addresses are to existing network devices.
Wireshark run on the failing destinations shows no UDP data.
My raw socket class is derived very closely from the example program I found at Stack Overflow kindly donated by user Peter O. on March 11, 2012 - question 3737612 "Raw socket sendto failed using C on Linux". I have appended my version of it, with a
couple of enhancements/fixes. I compiled and ran it on RedHat 5, gcc 4.1.2.
I checked /etc/sysctl.conf entries that might be relevant, and set the following with no discernable effect:
sudo /sbin/sysctl -w net.ipv4.conf.default.rp_filter=0
sudo /sbin/sysctl -w net.ipv4.conf.eth2.rp_filter=0
sudo /sbin/sysctl -w net.ipv4.conf.lo.rp_filter=0
sudo /sbin/sysctl -w net.ipv4.conf.all.rp_filter=0
sudo /sbin/sysctl -w net.ipv4.ip_forward=1
sudo /sbin/sysctl -w net.ipv4.conf.default.accept_source_route=1
sudo /sbin/sysctl -w net.ipv4.conf.all.accept_source_route=1
My modified version of the example from 3737612 is appended.
#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>
#include <net/if.h>
#include <sys/ioctl.h>
#include <time.h>
//The packet length in byes
#define PCKT_LEN 50
//Date size in bytes
#define DATA_SIZE 15
//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_UDP;
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, ix;
char buffer[PCKT_LEN];
char data[DATA_SIZE];
int one = 1;
char interface[100];
struct ifreq ifr;
time_t the_time;
// Source and destination addresses: IP and port
struct sockaddr_in to_addr;
const int *val = &one;
printf("IP Header Size: %u \n", sizeof(struct ip));
printf("UDP Header Size: %u \n", sizeof(struct udphdr));
printf("Data Size: %d\n", DATA_SIZE);
printf("IP Total: %u \n", sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE);
memset(buffer, 0, PCKT_LEN);
if(argc != 5 && argc != 6)
{
printf("- Invalid parameters!!!\n");
printf("- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port> [interface]\n", argv[0]);
exit(-1);
}
if (argc == 6)
strcpy(interface, argv[5]);
else
strcpy(interface, "eth0");
printf("Interface: %s\n", interface);
// bind() fails in BindRawSocketToInterface() above if it is passed a source address that
// is not the actual host sending (i.e. spoofing): "Cannot assign requested address"
#if 0
// 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]));
#else
sd = socket(PF_INET, SOCK_RAW, IPPROTO_RAW);
if(sd < 0)
{
perror("socket() error");
exit(-1);
}
else
printf("socket() - Using SOCK_RAW socket and RAW protocol is OK.\n");
memset (&ifr, 0, sizeof (ifr));
snprintf (ifr.ifr_name, sizeof (ifr.ifr_name), "%s", interface);
if (ioctl(sd, SIOCGIFINDEX, &ifr))
{
perror("ioctl() error ");
exit(-1);
}
if (setsockopt (sd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof (ifr)) < 0)
{
perror("setsockopt() error (#2)");
exit(-1);
}
#endif
// 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]);
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]));
// include a timestamp
memset(data, ' ', sizeof(data));
the_time = htonl(time(NULL));
memcpy(data, &the_time, sizeof(the_time));
//Compute UDP checksum
CreatePseudoHeaderAndComputeUdpChecksum(udp_header, ip_header, (unsigned char*)data);
for (ix = 0; ix < 1000000; ++ix)
{
//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);
// length must include header sizes
#if 0
if(sendto(sd, buffer, 20/*ip_header->ip_len*/, 0, (struct sockaddr *)&to_addr, sizeof(to_addr)) < 0)
#else
if(sendto(sd, buffer, sizeof(struct ip) + sizeof(struct udphdr) + DATA_SIZE, 0,
(struct sockaddr *)&to_addr, sizeof(to_addr)) < 0)
#endif
{
perror("sendto() error");
break;
}
else
{
printf("sendto() is OK.\n");
}
sleep(1);
} // loop
free(ip_header);
free(udp_header);
close(sd);
return 0;
}

C - Program freezes; futex_wait_queue_me

I have, as requested, included the code in its entirety so that you can test it. Keep in mind that this is nowhere near completion, but should be able to send and recieve packets through a stable tcp connection.
When I run it I get:
./bunny -i 84.49.76.98 -p 80 -o 79.161.200.48 -t 80
Raw packet reader created
Waiting 1 second for packet reader thread to settle down...
socket() - Using SOCK_RAW and TCP protocol is OK.
Socketoptions OK.
and then it just hangs. I've also used strace and that gave me (only including the last bit where it stopped):
setsockopt(4, SOL_IP, IP_HDRINCL, [1], 4) = 0
write(1, "Socketoptions OK.\n", 18Socketoptions OK.
) = 18
sendto(4, "", 0, 0, {sa_family=AF_INET, sin_port=htons(63239), sin_addr=inet_addr("84.49.76.98")}, 16) = 0
close(4) = 0
futex(0x7f4c07bf89d0, FUTEX_WAIT, 3278, NULLsendto(4, "", 0, 0, {sa_family=AF_INET, sin_port=htons(63239), sin_addr=inet_addr("84.49.76.98")}, 16) = 0
close(4) = 0
and the system monitor says the program is sleeping, and gives futex_wait_queue_me.
Could this be down to a memory leak somewhere causing too many calls to futex?
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <pcap.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#define VERSION "1.0"
#define PCKT_LEN 8192
/* Prototypes */
int sock;
void run();
void capture();
void usage();
in_addr_t sip;
in_addr_t dip;
char *dstip = 0;
int s_seq;
int sport;
int dport;
struct pseudo {
struct in_addr sourceip;
struct in_addr destip;
unsigned char placeholder;
unsigned char protocol;
unsigned char tcp_len;
struct tcphdr tcp;
};
struct ipheader {
unsigned char iph_ihl:5,
iph_ver:4;
unsigned char iph_tos;
unsigned short int iph_len;
unsigned short int iph_id;
unsigned char iph_flags;
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;
};
struct tcpheader {
unsigned short int tcph_sourceport;
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 short int tcph_win;
unsigned short int tcph_chksum;
unsigned short int tcph_urgptr;
};
/* Checksum */
unsigned short checksum (unsigned short *pac, int len)
{
unsigned long sum;
for (sum = 0; len > 0; len--)
sum += *pac++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return(~sum);
}
/* Checksum TCP */
unsigned short checksum_tcp (unsigned short len, unsigned short sourceip[],
unsigned short destip[], unsigned short buf[])
{
unsigned char protocol = 6;
unsigned long sum;
int nleft;
unsigned short *w;
sum = 0;
nleft = len;
w=buf;
while(nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if(nleft > 0)
{
sum += *w&ntohs(0xFF00);
}
sum += sourceip[0];
sum += sourceip[1];
sum += destip[0];
sum += destip[1];
sum += htons(len);
sum += htons(protocol);
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
sum = ~sum;
return ((unsigned short) sum);
}
int main(int argc,char **argv)
{
int c;
/* Are we in root? */
if(geteuid() !=0)
{
printf("Root access is required to run this program.\n\n");
exit(0);
}
while (1)
{
static struct option long_options[] =
{
/* Options */
{"send", no_argument, 0, 's'}, /* args s, r and f have no function yet */
{"receive", no_argument, 0, 'r'},
{"file", required_argument, 0, 'f'},
{"destip", required_argument, 0, 'i'},
{"destport", required_argument, 0, 'p'},
{"sourceip", required_argument, 0, 'o'},
{"sourceport", required_argument, 0, 't'},
{0, 0, 0, 0}
};
int option_index = 0;
c = getopt_long (argc, argv, "srf:d:i:p:o:t:",
long_options, &option_index);
/* Detect the end of the options. */
if (c == -1)
break;
switch (c)
{
case 0: /* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0)
break;
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case 's': puts ("option -s\n");
break;
case 'r': puts ("option -r\n");
break;
case 'f': printf ("option -f with value `%s'\n", optarg);
break;
case 'i': dip = inet_addr(optarg);
dstip = optarg;
break;
case 'p': dport = htons(atoi(optarg));
/* Add handling of bad/non number input here */
break;
case 'o': sip = inet_addr(optarg);
break;
case 't': sport = htons(atoi(optarg));
break;
case '?': /* Error message printed */
break;
default: abort ();
}
}
/* Print any remaining command line arguments (not options). */
if (optind < argc)
{
printf ("\nNon-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
putchar ('\n');
}
/* check if all mandatory options are set and for unknown arguments */
/* This really needs changing... */
if (dip, sip, dport, sport == 0)
{
usage();
return (-1);
}
/* change */
pthread_t tid_pr;
if (pthread_create(&tid_pr, NULL, capture, NULL) != 0) {
fprintf(stderr, "can't create raw packet reader: %s\n", strerror(errno));
exit(1);
}
printf("\nRaw packet reader created\nWaiting 1 second for packet reader thread to settle down...\n\n");
sleep(1);
run();
pthread_join(tid_pr, NULL);
getchar ();
exit (0);
}
int send_syn(unsigned int sourceip, unsigned int destip, unsigned short sourceport,
unsigned short destport)
{
const int one = 1;
char buffer[PCKT_LEN];
struct sockaddr_in sin;
struct ipheader *ip;
struct tcpheader *tcp;
ip = (struct ipheader *) buffer;
tcp = (struct tcpheader *) buffer + ip->iph_ihl *4;
/* IP attributes */
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
ip->iph_len = sizeof(struct ipheader) + sizeof(struct tcpheader);
ip->iph_id = htons(54321);
ip->iph_offset = 0;
ip->iph_ttl = 64;
ip->iph_protocol = IPPROTO_TCP;
ip->iph_chksum = 0;
ip->iph_sourceip = sip;
ip->iph_destip = dip;
ip->iph_chksum = checksum ((unsigned short *) buffer, (sizeof (struct
ipheader )+ sizeof (struct tcpheader)));
/* TCP attributes */
tcp->tcph_sourceport = sport;
tcp->tcph_destport = dport;
tcp->tcph_seqnum = htonl(1); /* ADD SEQ NUM THINGY */
tcp->tcph_offset = 5;
tcp->tcph_flags = TH_SYN;
tcp->tcph_win = htons(32767);
tcp->tcph_chksum = 0;
tcp->tcph_urgptr = 0;
tcp->tcph_chksum = (unsigned short) checksum_tcp((unsigned short) (ip->iph_len - ip->iph_ihl *4), (unsigned short *) &ip->iph_sourceip,
(unsigned short *) &ip->iph_destip, (unsigned short *) &tcp);
/* Address family */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip->iph_destip;
/* Send */
if (sendto(sock, buffer, ip->iph_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
fprintf(stderr, "\nCan't send packet\n");
return (-1);
}
else
printf("Packet sent to %d", dip);
close(sock);
}
int send_syn_ack(unsigned int sourceip, unsigned int destip, unsigned short sourceport,
unsigned short destport, unsigned long s_seq)
{
const int one = 1;
char buffer[PCKT_LEN];
struct sockaddr_in sin;
struct ipheader *ip;
struct tcpheader *tcp;
ip = (struct ipheader *) buffer;
tcp = (struct tcpheader *) buffer + ip->iph_ihl *4;
/* IP attributes */
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
ip->iph_len = sizeof(struct ipheader) + sizeof(struct tcpheader);
ip->iph_id = htons(54321);
ip->iph_offset = 0;
ip->iph_ttl = 64;
ip->iph_protocol = IPPROTO_TCP;
ip->iph_chksum = 0;
ip->iph_sourceip = sip;
ip->iph_destip = dip;
ip->iph_chksum = checksum ((unsigned short *) buffer, (sizeof (struct
ipheader )+ sizeof (struct tcpheader)));
/* TCP attributes */
tcp->tcph_sourceport = sport;
tcp->tcph_destport = dport;
tcp->tcph_seqnum = htonl(1 + 1); /* ADD SEQ NUM THINGY */
tcp->tcph_acknum = htonl (s_seq + 1); /* ADD ACK NUM THINGY */
tcp->tcph_offset = 5;
tcp->tcph_flags = TH_ACK;
tcp->tcph_win = htons(32767);
tcp->tcph_chksum = 0;
tcp->tcph_urgptr = 0;
tcp->tcph_chksum = (unsigned short) checksum_tcp((unsigned short) (ip->iph_len - ip->iph_ihl *4), (unsigned short *) &ip->iph_sourceip,
(unsigned short *) &ip->iph_destip, (unsigned short *) &tcp);
/* Address family */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip->iph_destip;
/* Send */
if (sendto(sock, buffer, ip->iph_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
fprintf(stderr, "\nCan't send packet\n");
return (-1);
}
else
printf("Packet sent to %d\n", dip);
close(sock);
}
void run()
{
const int one = 1;
char buffer[PCKT_LEN];
struct sockaddr_in sin;
struct ipheader *ip;
struct tcpheader *tcp;
ip = (struct ipheader *) buffer;
tcp = (struct tcpheader *) buffer + ip->iph_ihl *4;
sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
if (sock < 0)
{
fprintf(stderr, "\nSocket()\n\n");
exit (-1);
}
else
printf ("socket() - Using SOCK_RAW and TCP protocol is OK.\n");
if ((setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof (one))) < 0)
{
fprintf(stderr, "Can't set socketoptions\n");
exit (-1);
}
else
printf("Socketoptions OK.\n");
send_syn(dip, sip, dport, sport);
}
void receive(u_char *args, const struct pcap_pkthdr *pkthdr, const u_char *buffer)
{
const int one = 1;
int LEN = strtol(args, NULL, 0); /* LEN = strtol(args, NULL, 0) ---- int LEN = *args;*/
struct ipheader *ip;
struct tcpheader *tcp;
ip = (struct ipheader *)(buffer + LEN);
tcp = (struct tcpheader *)(buffer + LEN + sizeof (struct ipheader));
printf("%d\n", LEN);
printf("Packet received. ACK number: %d\n", ntohl (tcp->tcph_seqnum));
printf("Packet received. SEQ number: %d\n", ntohl (tcp->tcph_acknum));
s_seq = ntohl (tcp->tcph_seqnum);
send_syn_ack(s_seq, dip, sip, dport, sport);
sleep(100);
}
void capture()
{
pcap_t *pd;
bpf_u_int32 netmask;
bpf_u_int32 localnet;
char filterbuf[64];
snprintf(filterbuf, sizeof(filterbuf), "ip dst host %s", dstip);
char *filter = filterbuf;
char *dev = NULL;
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program filterprog;
int dl = 0, dl_len = 0;
if ((pd = pcap_open_live(dev, 1514, 1, 500, errbuf)) == NULL) /* Look into snaplen size */
{
fprintf(stderr, "can't open device %s: %s\n", dev, errbuf);
exit(1);
}
pcap_lookupnet(dev, &localnet, &netmask, errbuf);
pcap_compile(pd, &filterprog, filter, 0, localnet);
if (pcap_setfilter(pd, &filterprog) == - 1)
{
fprintf(stderr, "can't set pcap filter: %s %s\n", filter, errbuf);
exit(1);
}
pcap_freecode(&filterprog);
dl = pcap_datalink(pd);
switch(dl) {
case 1:
dl_len = 14;
break;
default:
dl_len = 14;
break;
}
if (pcap_loop(pd, -1, receive, (u_char *) &dl_len) < 0)
{
fprintf(stderr, "can't get raw packet: %s\n", pcap_geterr(pd));
exit(1);
}
}
void usage()
{
/* This is the user manual (CHANGE) */
printf("\nChannelBunny %s, created 2012\n\n", VERSION);
printf("ChannelBunny Usage: -s -f <file> -i <destip> -p <destport> -o <sourceip> -t <sourceport>\n\n");
printf("-s, --send, Puts program in send mode\n");
printf("-r, --receive, Puts program in receive mode\n");
printf("-f, --file, Specify file\n");
printf("-i, --destip, Destination IP address\n");
printf("-p, --destport, Destination port\n");
printf("-o, --sourceip Source IP address\n");
printf("-t, --sourceport Source port\n");
}
The main problem of your code is that you're not handling correctly the LINK-LAYER TYPE, you are using:
pcap_open_live with the fisrt argument set to NULL, this mean that the kernel will choose "any" interface to sniff and inject RAW packets, in this case your are using "LINKTYPE_LINUX_SLL" instead of ETHERNET which is what you want (LINK_TYPE 1).
So you need to handle the link layer correctly (checkout the list here: http://www.tcpdump.org/linktypes.html). I modify your code and it works now(replace device eth0 with what you want):
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <getopt.h>
#include <errno.h>
#include <pcap.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define VERSION "1.0"
#define PCKT_LEN 8192
/* Prototypes */
int sock;
void run();
void* capture(void *);
void usage();
in_addr_t sip;
in_addr_t dip;
char *dstip = 0;
int s_seq;
unsigned short sport;
unsigned short dport;
struct pseudo {
struct in_addr sourceip;
struct in_addr destip;
unsigned char placeholder;
unsigned char protocol;
unsigned char tcp_len;
struct tcphdr tcp;
};
struct ipheader {
unsigned char iph_ihl:5,
iph_ver:4;
unsigned char iph_tos;
unsigned short int iph_len;
unsigned short int iph_id;
unsigned char iph_flags;
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;
};
struct tcpheader {
unsigned short int tcph_sourceport;
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 short int tcph_win;
unsigned short int tcph_chksum;
unsigned short int tcph_urgptr;
};
/* Checksum */
unsigned short checksum (unsigned short *pac, int len)
{
unsigned long sum;
for (sum = 0; len > 0; len--)
sum += *pac++;
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
return(~sum);
}
/* Checksum TCP */
unsigned short checksum_tcp (unsigned short len, unsigned short sourceip[],
unsigned short destip[], unsigned short buf[])
{
unsigned char protocol = 6;
unsigned long sum;
int nleft;
unsigned short *w;
sum = 0;
nleft = len;
w=buf;
while(nleft > 1)
{
sum += *w++;
nleft -= 2;
}
if(nleft > 0)
{
sum += *w&ntohs(0xFF00);
}
sum += sourceip[0];
sum += sourceip[1];
sum += destip[0];
sum += destip[1];
sum += htons(len);
sum += htons(protocol);
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
sum = ~sum;
return ((unsigned short) sum);
}
int main(int argc,char **argv)
{
int c;
/* Are we in root? */
if(geteuid() !=0)
{
printf("Root access is required to run this program.\n\n");
exit(0);
}
while (1)
{
static struct option long_options[] =
{
/* Options */
{"send", no_argument, 0, 's'}, /* args s, r and f have no function yet */
{"receive", no_argument, 0, 'r'},
{"file", required_argument, 0, 'f'},
{"destip", required_argument, 0, 'i'},
{"destport", required_argument, 0, 'p'},
{"sourceip", required_argument, 0, 'o'},
{"sourceport", required_argument, 0, 't'},
{0, 0, 0, 0}
};
int option_index = 0;
c = getopt_long (argc, argv, "srf:d:i:p:o:t:",
long_options, &option_index);
/* Detect the end of the options. */
if (c == -1)
break;
switch (c)
{
case 0: /* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0)
break;
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case 's': puts ("option -s\n");
break;
case 'r': puts ("option -r\n");
break;
case 'f': printf ("option -f with value `%s'\n", optarg);
break;
case 'i': dip = inet_addr(optarg);
dstip = optarg;
break;
case 'p': dport = htons(atoi(optarg));
/* Add handling of bad/non number input here */
break;
case 'o': sip = inet_addr(optarg);
break;
case 't': sport = htons(atoi(optarg));
break;
case '?': /* Error message printed */
break;
default: abort ();
}
}
/* Print any remaining command line arguments (not options). */
if (optind < argc)
{
printf ("\nNon-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
putchar ('\n');
}
/* check if all mandatory options are set and for unknown arguments */
/* This really needs changing... */
if ((dip && sip && dport && sport) == 0)
{
usage();
return (-1);
}
fprintf(stdout, "SPORT : %d, DPORT : %d\n", sport, dport);
/* change */
pthread_t tid_pr;
if (pthread_create(&tid_pr, NULL, capture, NULL) != 0) {
fprintf(stderr, "can't create raw packet reader: %s\n", strerror(errno));
exit(1);
}
printf("\nRaw packet reader created\nWaiting 1 second for packet reader thread to settle down...\n\n");
sleep(1);
run();
pthread_join(tid_pr, NULL);
getchar ();
exit (0);
}
int send_syn(unsigned int sourceip, unsigned int destip, unsigned short sourceport,
unsigned short destport)
{
//const int one = 1;
char buffer[PCKT_LEN];
struct sockaddr_in sin;
struct ipheader *ip;
struct tcpheader *tcp;
ip = (struct ipheader *) buffer;
tcp = (struct tcpheader *) buffer + ip->iph_ihl *4;
/* IP attributes */
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
ip->iph_len = sizeof(struct ipheader) + sizeof(struct tcpheader);
ip->iph_id = htons(54321);
ip->iph_offset = 0;
ip->iph_ttl = 64;
ip->iph_protocol = IPPROTO_TCP;
ip->iph_chksum = 0;
ip->iph_sourceip = sip;
ip->iph_destip = dip;
ip->iph_chksum = checksum ((unsigned short *) buffer, (sizeof (struct
ipheader )+ sizeof (struct tcpheader)));
/* TCP attributes */
tcp->tcph_sourceport = sport;
tcp->tcph_destport = dport;
tcp->tcph_seqnum = htonl(1); /* ADD SEQ NUM THINGY */
tcp->tcph_offset = 5;
tcp->tcph_flags = TH_SYN;
tcp->tcph_win = htons(32767);
tcp->tcph_chksum = 0;
tcp->tcph_urgptr = 0;
tcp->tcph_chksum = (unsigned short) checksum_tcp((unsigned short) (ip->iph_len - ip->iph_ihl *4), (unsigned short *) &ip->iph_sourceip,
(unsigned short *) &ip->iph_destip, (unsigned short *) &tcp);
/* Address family */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip->iph_destip;
/* Send */
if (sendto(sock, buffer, ip->iph_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
fprintf(stderr, "\nCan't send packet\n");
return (-1);
}
else
printf("Packet sent to %d", dip);
close(sock);
return 0;
}
int send_syn_ack(unsigned int sourceip, unsigned int destip, unsigned short sourceport,
unsigned short destport, unsigned long s_seq)
{
//const int one = 1;
char buffer[PCKT_LEN];
struct sockaddr_in sin;
struct ipheader *ip;
struct tcpheader *tcp;
ip = (struct ipheader *) buffer;
tcp = (struct tcpheader *) buffer + ip->iph_ihl *4;
/* IP attributes */
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
ip->iph_len = sizeof(struct ipheader) + sizeof(struct tcpheader);
ip->iph_id = htons(54321);
ip->iph_offset = 0;
ip->iph_ttl = 64;
ip->iph_protocol = IPPROTO_TCP;
ip->iph_chksum = 0;
ip->iph_sourceip = sip;
ip->iph_destip = dip;
ip->iph_chksum = checksum ((unsigned short *) buffer, (sizeof (struct
ipheader )+ sizeof (struct tcpheader)));
/* TCP attributes */
tcp->tcph_sourceport = sport;
tcp->tcph_destport = dport;
tcp->tcph_seqnum = htonl(1 + 1); /* ADD SEQ NUM THINGY */
tcp->tcph_acknum = htonl (s_seq + 1); /* ADD ACK NUM THINGY */
tcp->tcph_offset = 5;
tcp->tcph_flags = TH_ACK;
tcp->tcph_win = htons(32767);
tcp->tcph_chksum = 0;
tcp->tcph_urgptr = 0;
tcp->tcph_chksum = (unsigned short) checksum_tcp((unsigned short) (ip->iph_len - ip->iph_ihl *4), (unsigned short *) &ip->iph_sourceip,
(unsigned short *) &ip->iph_destip, (unsigned short *) &tcp);
/* Address family */
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip->iph_destip;
/* Send */
if (sendto(sock, buffer, ip->iph_len, 0, (struct sockaddr *)&sin, sizeof(sin)) < 0)
{
fprintf(stderr, "\nCan't send packet : %s\n", strerror(errno));
return (-1);
}
else
printf("Packet sent to %d\n", dip);
close(sock);
return 0;
}
void run()
{
const int one = 1;
//char buffer[PCKT_LEN];
//struct sockaddr_in sin;
//struct ipheader *ip;
//struct tcpheader *tcp;
//ip = (struct ipheader *) buffer;
//tcp = (struct tcpheader *) buffer + ip->iph_ihl *4;
sock = socket(PF_INET, SOCK_RAW, IPPROTO_TCP);
if (sock < 0)
{
fprintf(stderr, "\nSocket()\n\n");
exit (-1);
}
else
printf ("socket() - Using SOCK_RAW and TCP protocol is OK.\n");
if ((setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *)&one, sizeof (one))) < 0)
{
fprintf(stderr, "Can't set socketoptions\n");
exit (-1);
}
else
printf("Socketoptions OK.\n");
send_syn(dip, sip, dport, sport);
}
void receive(u_char *args, const struct pcap_pkthdr *pkthdr, const u_char *buffer)
{
//const int one = 1;
//int LEN = strtol(args, NULL, 0); /* LEN = strtol(args, NULL, 0) ---- int LEN = *args;*/
int LEN = atoi((char *)args);
//struct ipheader *ip;
struct tcpheader *tcp;
//ip = (struct ipheader *)(buffer + LEN);
tcp = (struct tcpheader *)(buffer + LEN + sizeof (struct ipheader));
printf("LEN = %d\n", LEN);
printf("Packet received. ACK number: %d\n", ntohl (tcp->tcph_seqnum));
printf("Packet received. SEQ number: %d\n", ntohl (tcp->tcph_acknum));
s_seq = ntohl (tcp->tcph_seqnum);
send_syn_ack(s_seq, dip, sip, dport, sport);
sleep(100);
}
void* capture(void *unused_arg)
{
pcap_t *pd;
bpf_u_int32 netmask;
bpf_u_int32 localnet;
char filterbuf[64];
snprintf(filterbuf, sizeof(filterbuf), "ip dst host %s", dstip);
char *filter = filterbuf;
//char *dev = NULL;
char dev[] = "eth0";
char errbuf[PCAP_ERRBUF_SIZE];
struct bpf_program filterprog;
int dl = 0, dl_len = 0;
/* TODO : SET THE INTERFACE CORRECTLY */
//if ((pd = pcap_open_live(dev, 1514, 1, 500, errbuf)) == NULL) /* Look into snaplen size */
if ((pd = pcap_open_live(dev, 1514, 1, 500, errbuf)) == NULL) /* Look into snaplen size */
{
fprintf(stderr, "can't open device %s: %s\n", dev, errbuf);
exit(1);
}
pcap_lookupnet(dev, &localnet, &netmask, errbuf);
pcap_compile(pd, &filterprog, filter, 0, localnet);
if (pcap_setfilter(pd, &filterprog) == - 1)
{
fprintf(stderr, "can't set pcap filter: %s %s\n", filter, errbuf);
exit(1);
}
pcap_freecode(&filterprog);
dl = pcap_datalink(pd);
switch(dl) {
/* TODO : HANDLE THIS PART CORRECTLY */
case 1:
dl_len = 14; /* Ethernet header */
fprintf(stdout, "\nDL = %d (ETHERNET)\n", dl);
break;
default:
dl_len = 14;
fprintf(stdout, "\nDL = %d (if you are here please handle correctly)\n", dl);
break;
}
if (pcap_loop(pd, -1, receive, (u_char *) &dl_len) < 0)
{
fprintf(stderr, "can't get raw packet: %s\n", pcap_geterr(pd));
exit(1);
}
return NULL;
}
void usage()
{
/* This is the user manual (CHANGE) */
printf("\nChannelBunny %s, created 2012\n\n", VERSION);
printf("ChannelBunny Usage: -s -f <file> -i <destip> -p <destport> -o <sourceip> -t <sourceport>\n\n");
printf("-s, --send, Puts program in send mode\n");
printf("-r, --receive, Puts program in receive mode\n");
printf("-f, --file, Specify file\n");
printf("-i, --destip, Destination IP address\n");
printf("-p, --destport, Destination port\n");
printf("-o, --sourceip Source IP address\n");
printf("-t, --sourceport Source port\n");
}
EDIT : Setting interface
To set the interface for pcap_open_live, use ifconfig command to check which interface you want to use, in the case of other interface than ETHERNET, you need to change your code, because the header will change.
To debug your code, you can use the old printf (it's always useful), add this in line in all parts that you suspect to be the cause of trouble:
fprintf(stdout, "Function : %s, Line : %d\n", __FUNCTION__, __LINE__);
EDIT2 : The value of the ETHERNET header passed to the receive function was wrong
Use :
int LEN = *(int *)args;
instead of:
int LEN = strtol(args, NULL, 0);
And then you can see clearly that the LEN is now 14 (Ethernet header length).
Another thing : i don't really understand how you think the global var sock will behave! your socket is created in the run function after the thread was launched! and you try to close it twice : inside send_syn_ack and send_syn.
You need to think the design of your code (take some time to do so).
I think that you should create the main socket inside the main function and close it when you want (inside the main function or when some errors occur).
Last thing please use : strerror(errno) with all your calls so you can trace the errors easily.
Hope this help.

Raw socket sendto failed using C on Linux

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.

Resources