Hello I would like to make a programm which would work similarly to "SendIP a command-line tool to send arbitrary IP packets"
I have a programm to send "IPv4 + UDP". I try to validate my program by Wireshark but nothing is received and I don't know why.
I send it by command ./Project 192.168.1.15 21 192.168.1.15 8080 5
Here is my code: (In ipv4.h and udp.h I have ip and udp headers)
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include "ipv4.h"
#include "udp.h"
// Source IP, source port, target IP, target port from the command line arguments
int main(int argc, char *argv[])
{
if (argc != 6)
{
printf("- Invalid parameters!!!\n");
printf(
"- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n",
argv[0]);
exit(-1);
}
else {
int sd;
char buffer[PCKT_LEN];
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);
// 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 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]);
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
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));
if (setsockopt(sd, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("setsockopt() error");
exit(-1);
}
else
printf("setsockopt() is OK.\n");
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]));
//printf("Interfejs=%d\n", *val);
int count;
int number = (atoi(argv[5]));
printf("Number=%d\n", number);
for (count = 1; count <= number; count++)
{
if (sendto(sd, buffer, ip->iph_len, 0, (struct sockaddr *) &sin,
sizeof(sin)) < 0)
{
perror("sendto() error");
exit(-1);
}
else
{
printf("Count #%u - sendto() is OK.\n", count);
sleep(2);
}
}
close(sd);
return 0;
}
}
Ok I fix it. The problem was with int one = 1; which specife number of interface. I changed to 0 and it works. What a stupid mistake :D
Related
I have been learning raw sockets for the past few days and I am unable to send UDP packets over RAW sockets. I tried writing code for this but UDP packets were not sent. (I was capturing packets via wireshark, only IPv4 packets were sent, containing headers upto IP layer). I searched a lot on the internet and tried various codes as well which I found on the internet but still couldn't send UDP packets (not seen on wireshark). Can someone suggest changes in code or point to some resource regarding this.
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <linux/ip.h>
#include <linux/udp.h>
#define PCKT_LEN 8192
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);
}
int main(int argc, char const *argv[])
{
if (argc != 5) {
printf("Error: Invalid parameters!\n");
printf("Usage: %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(1);
}
u_int16_t src_port, dst_port;
u_int32_t src_addr, dst_addr;
src_addr = inet_addr(argv[1]);
dst_addr = inet_addr(argv[3]);
src_port = atoi(argv[2]);
dst_port = atoi(argv[4]);
int sd;
char buffer[PCKT_LEN];
struct iphdr *ip = (struct iphdr *) buffer;
struct udphdr *udp = (struct udphdr *) (buffer + sizeof(struct iphdr));
struct sockaddr_in sin;
int one = 1;
const int *val = &one;
memset(buffer, 0, PCKT_LEN);
// create a raw socket with UDP protocol
sd = socket(PF_INET, SOCK_RAW, IPPROTO_UDP);
if (sd < 0) {
perror("socket() error");
exit(2);
}
printf("OK: a raw socket is created.\n");
// 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(2);
}
printf("OK: socket option IP_HDRINCL is set.\n");
sin.sin_family = AF_INET;
sin.sin_port = htons(dst_port);
sin.sin_addr.s_addr = dst_addr;
// fabricate the IP header
ip->ihl = 5;
ip->version = 4;
ip->tos = 16; // low delay
ip->tot_len = sizeof(struct iphdr) + sizeof(struct udphdr);
ip->id = htons(54321);
ip->ttl = 64; // hops
ip->protocol = 17; // UDP
// source IP address, can use spoofed address here
ip->saddr = src_addr;
ip->daddr = dst_addr;
// fabricate the UDP header
udp->source = htons(src_port);
// destination port number
udp->dest = htons(dst_port);
udp->len = htons(sizeof(struct udphdr));
// calculate the checksum for integrity
ip->check = csum((unsigned short *)buffer,
sizeof(struct iphdr) + sizeof(struct udphdr));
if (sendto(sd, buffer, ip->tot_len, 0,
(struct sockaddr *)&sin, sizeof(sin)) < 0)
{
perror("sendto()");
exit(3);
}
printf("OK: one packet is sent.\n");
close(sd);
return 0;
}
I keep getting this error getaddrinfo failed: Undefined error: 0. I am trying to compile my code on MacOS using the command gcc mac-client-2.c -o client. The program is compiling successfully, but when I run the executable, the error above shows up. I searched google and SO, the closest thing I could find to the problem was this link Undefined reference to getaddrinfo But, this link talks about the issue for windows, not for MacOS.
I am pasting my code as it is below. Could anyone please help.
EDIT: Got a more descriptive error saying getaddrinfo: Address family for nodename not supported
// Client side implementation of UDP client-server model
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/udp.h> //Provides declarations for udp header
#include <netinet/ip.h> //Provides declarations for ip header
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <netdb.h>
#include <errno.h>
#define PORT 12345
#define MAXLINE 1024
//standard checksum function
unsigned short csum(unsigned short *ptr, int nbytes)
{
register long sum;
unsigned short oddbyte;
register short answer;
sum = 0;
while (nbytes > 1)
{
sum += *ptr++;
nbytes -= 2;
}
if (nbytes == 1)
{
oddbyte = 0;
*((u_char *)&oddbyte) = *(u_char *)ptr;
sum += oddbyte;
}
sum = (sum >> 16) + (sum & 0xffff);
sum = sum + (sum >> 16);
answer = (short)~sum;
return (answer);
}
// struct ip
// {
// unsigned char ihl;
// unsigned char version;
// unsigned char tos;
// unsigned short int tot_len;
// unsigned short int id;
// unsigned short int frag_off;
// unsigned char ttl;
// unsigned char protocol;
// unsigned short int check;
// unsigned int saddr;
// unsigned int daddr;
// };
//required for udp
struct pseudo_header
{
u_int32_t source_address;
u_int32_t dest_address;
u_int8_t placeholder;
u_int8_t protocol;
u_int16_t udp_length;
};
// Driver code
int main()
{
int errno;
int sockfd, raw_sock;
char buffer[MAXLINE];
int port;
char *hello = "Client Hello";
char *done = "Client Done";
char source_ip[32];
struct sockaddr_in servaddr;
struct sockaddr_in local_address;
int addr_size = sizeof(local_address);
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket creation failed");
exit(EXIT_FAILURE);
}
if ((raw_sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) < 0) //PF_PACKET -- 0 can be replaced with IPPROTO_UDP (gives same outcome)
{
perror("Raw Socket creation failed");
exit(EXIT_FAILURE);
}
setuid(getuid());
//********** Part with getaddrinfo//*********
int stat;
struct addrinfo hints;
struct addrinfo *info, *ptr;
struct sockaddr_in *client_address;
char clientIPstr[16];
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; //put NULL in getaddrinfo
//AI_PASSIVE allows to assign address of local host
//No hardcoding needed
if ((stat = getaddrinfo(NULL, "0", &hints, &info) != 0))
{
perror("getaddrinfo failed");
exit(EXIT_FAILURE);
}
for (ptr = info; ptr != NULL; ptr = ptr->ai_next)
{
if (ptr->ai_family == AF_INET)
{
client_address = (struct sockaddr_in *)ptr->ai_addr;
inet_ntop(AF_INET, &(client_address->sin_addr), clientIPstr, sizeof(clientIPstr));
printf("%s\n", clientIPstr);
int x = bind(sockfd, ptr->ai_addr, ptr->ai_addrlen);
//int y = bind(raw_sock, ptr->ai_addr, ptr->ai_addrlen);
//printf("Bind Status: %d, %d\n", x, y);
break;
}
}
///************///************////*****************
memset(&servaddr, 0, sizeof(servaddr));
// Filling server information
servaddr.sin_family = AF_INET; //IPv4
servaddr.sin_port = htons(PORT); //8080
inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);
int len, n;
//send hello
sendto(sockfd, (const char *)hello, strlen(hello),
0, (const struct sockaddr *)&servaddr,
sizeof(servaddr));
//fetch the port number and store in local address -- dont forget to convert using ntohs
getsockname(sockfd, (struct sockaddr *)&local_address, &addr_size);
port = ntohs(local_address.sin_port);
printf("My Port: %u\n", port);
//receive hello
bzero(buffer, MAXLINE);
recvfrom(sockfd, buffer, sizeof(buffer),
0, (struct sockaddr *)&servaddr,
&len);
printf("%s\n", buffer);
/* ---------------------Packet spoofing code starts here----------------------- */
printf("Creating spoofed packet\n");
char spoof_packet[4096];
char *data, *pseudogram;
int one = 1;
const int *val = &one;
memset(spoof_packet, 0, 4096);
//strcpy(clientIPstr, "127.0.0.1");
struct ip *iph = (struct ip *)spoof_packet;
struct udphdr *udph = (struct udphdr *)(spoof_packet + sizeof(struct ip));
struct pseudo_header psh;
struct sockaddr_in my_sockaddress;
my_sockaddress.sin_addr.s_addr = inet_addr(clientIPstr); //just set this to htonl(INADDR_ANY); instead of 127.0.0.1
//struct sockaddr_in sin;
data = spoof_packet + sizeof(struct ip) + sizeof(struct udphdr);
strcpy(data, "SPOOFED CLIENT DONE");
strcpy(source_ip, clientIPstr);
//IP Header
iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = sizeof(struct ip) + sizeof(struct udphdr) + strlen(data);
iph->ip_id = htonl(54321); //Id of this packet
iph->ip_off = 0;
iph->ip_ttl = 255;
iph->ip_p = IPPROTO_UDP;
iph->ip_sum = 0; //Set to 0 before calculating checksum
iph->ip_src = my_sockaddress.sin_addr; //Spoof the source ip address
iph->ip_dst = servaddr.sin_addr; //value should be of type in_addr
iph->ip_sum = csum((unsigned short *)spoof_packet, iph->ip_len); //ip checksum
//UDP header
udph->uh_sport = local_address.sin_port;
udph->uh_dport = htons(PORT);
udph->uh_ulen = htons(8 + strlen(data)); //header size
udph->uh_sum = 0; //leave checksum 0 now, filled later by pseudo header
/* Stackoverflow - The IPv4 layer generates an IP header when sending a packet unless the IP_HDRINCL socket
option is enabled on the socket. When it is enabled, the packet must contain an IP header.
For receiving the IP header is always included in the packet.*/
if (setsockopt(raw_sock, IPPROTO_IP, IP_HDRINCL, val, sizeof(one)) < 0)
{
perror("setsockopt() error");
exit(-1);
}
//UDP checksum using the pseudo header
psh.source_address = inet_addr(source_ip);
psh.dest_address = servaddr.sin_addr.s_addr;
psh.placeholder = 0;
psh.protocol = IPPROTO_UDP;
psh.udp_length = htons(sizeof(struct udphdr) + strlen(data));
int psize = sizeof(struct pseudo_header) + sizeof(struct udphdr) + strlen(data);
pseudogram = malloc(psize);
memcpy(pseudogram, (char *)&psh, sizeof(struct pseudo_header));
memcpy(pseudogram + sizeof(struct pseudo_header), udph, sizeof(struct udphdr) + strlen(data));
udph->uh_sum = csum((unsigned short *)pseudogram, psize);
printf("%s\n", spoof_packet);
printf("Sending spoofed packet.......");
int k;
//send spoofed Done
k = sendto(raw_sock, spoof_packet, iph->ip_len,
0, (const struct sockaddr *)&servaddr,
sizeof(servaddr));
if (k == -1)
{
printf("Error sending: %i\n", errno);
}
printf("%d\n", k);
fflush(stdout);
/*---------------------------------END------------------------------------------*/
//send Done
// sendto(sockfd, (const char *)done, strlen(done),
// 0, (const struct sockaddr *)&servaddr,
// sizeof(servaddr));
//receive done
bzero(buffer, MAXLINE);
recvfrom(sockfd, buffer, sizeof(buffer),
0, (struct sockaddr *)&servaddr,
&len);
printf("%s\n", buffer);
//close(sockfd);
return 0;
}
/* get ip and port number:
char myIP[16];
struct sockaddr_in local_address;
getsockname(sockfd, (struct sockaddr *)&local_address, &addr_size); //get socket info
inet_ntop(AF_INET, &local_address.sin_addr, myIP, sizeof(myIP)); // get IP info
int myPort = ntohs(local_address.sin_port); //get port info
printf("Local ip address: %s\n", myIP);
printf("Local port : %u\n", myPort);
*/
Your struct addrinfo hints; is uninitialized, and has junk in the members you did not explicitly write to. Change it to struct addrinfo hints = { 0 }; or put all the hints in designated initializers rather than assignments after creation of an uninitialized object.
So, I forgot to post back here. I had figured out the solution. Its basically the same as the above post. Just added the line memset(&hints,0,sizeof(hints)) and everything worked perfectly.
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;
}
Have some problems in receiving packets.
I can receive and read incoming packets, but I think i do not get a handshake with any host.
I only want to send a packet to a remote computer with an open port on receiving an answer to see the TTL(time to live) and the window size.
Does anyone have an idea where the errors are? (I don't have very deep knowledge in C programming)
CODE:
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <errno.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <net/ethernet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
struct pseudohdr {
u_int32_t src_addr;
u_int32_t dst_addr;
u_int8_t padding;
u_int8_t proto;
u_int16_t length;
};
struct data_4_checksum {
struct pseudohdr pshd;
struct tcphdr tcphdr;
char payload[1024];
};
unsigned short comp_chksum(unsigned short *addr, int len) {
long sum = 0;
while (len > 1) {
sum += *(addr++);
len -= 2;
}
if (len > 0)
sum += *addr;
while (sum >> 16)
sum = ((sum & 0xffff) + (sum >> 16));
sum = ~sum;
return ((u_short) sum);
}
int main(int argc, char *argv[]) {
int sock, bytes, on = 1;
char buffer[1024];
struct iphdr *ip;
struct tcphdr *tcp;
struct sockaddr_in to;
struct pseudohdr pseudoheader;
struct data_4_checksum tcp_chk_construct;
if (argc != 2) {
fprintf(stderr, "Usage: %s ", argv[0]);
fprintf(stderr, "<dest-addr>\n");
return 1;
}
sock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);
if (sock == -1) {
perror("socket() failed");
return 1;
}else{
printf("socket() ok\n");
}
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) == -1) {
perror("setsockopt() failed");
return 2;
}else{
printf("setsockopt() ok\n");
}
ip = (struct iphdr*) buffer;
tcp = (struct tcphdr*) (buffer + sizeof(struct tcphdr));
int iphdrlen = sizeof(struct iphdr);
int tcphdrlen = sizeof(struct tcphdr);
int datalen = 0;
printf("Typecasting ok\n");
ip->frag_off = 0;
ip->version = 4;
ip->ihl = 5;
ip->tot_len = htons(iphdrlen + tcphdrlen);
ip->id = 0;
ip->ttl = 40;
ip->protocol = IPPROTO_TCP;
ip->saddr = inet_addr("192.168.165.135");
ip->daddr = inet_addr(argv[1]);
ip->check = 0;
tcp->source = htons(12345);
tcp->dest = htons(80);
tcp->seq = random();
tcp->doff = 5;
tcp->ack = 0;
tcp->psh = 0;
tcp->rst = 0;
tcp->urg = 0;
tcp->syn = 1;
tcp->fin = 0;
tcp->window = htons(65535);
pseudoheader.src_addr = ip->saddr;
pseudoheader.dst_addr = ip->daddr;
pseudoheader.padding = 0;
pseudoheader.proto = ip->protocol;
pseudoheader.length = htons(tcphdrlen + datalen);
tcp_chk_construct.pshd = pseudoheader;
tcp_chk_construct.tcphdr = *tcp;
int checksum = comp_chksum((unsigned short*) &tcp_chk_construct,
sizeof(struct pseudohdr) + tcphdrlen + datalen);
tcp->check = checksum;
printf("TCP Checksum: %i\n", checksum);
printf("Destination : %i\n", ntohs(tcp->dest));
printf("Source: %i\n", ntohs(tcp->source));
to.sin_addr.s_addr = ip->daddr;
to.sin_family = AF_INET;
to.sin_port = tcp->dest;
bytes = sendto(sock, buffer, ntohs(ip->tot_len), 0, (struct sockaddr*) &to,
sizeof(to));
if (bytes == -1) {
perror("sendto() failed");
return 1;
}
recv(sock, buffer, sizeof(buffer), 0);
printf("TTL= %d\n", ip->ttl);
printf("Window= %d\n", tcp->window);
printf("ACK= %d\n", tcp->ack);
printf("%s:%d\t --> \t%s:%d \tSeq: %d \tAck: %d\n",
inet_ntoa(*(struct in_addr*) &ip->saddr), ntohs(tcp->source),
inet_ntoa(*(struct in_addr *) &ip->daddr), ntohs(tcp->dest),
ntohl(tcp->seq), ntohl(tcp->ack_seq));
return 0;
}
You're receiving and storing packets in buffer, but you're printing data from ip and tcp without parsing that buffer. You should parse the packet from buffer after receiving it, and before printing.
Your code assumes all packets are TCP, which is not the case. RAW sockets only support Layer 3 protocols (IP, ICMP, etc). In other words, using IPPROTO_TCP is misleading when creating a RAW socket. Stick to IPPROTO_IP, and add the necessary conditions to your code for each protocol you care about (TCP, UDP, etc). This happens to be working because the Linux Kernel validates the protocol number, and fallbacks to IPPROTO_IP. However, this might not work in other systems.
Review if your network communication is using the correct byte-order. The network-byte-order is Big-Endian, while the host-byte-order depends on your architecture, so you may need to convert multi-byte fields back and forth.
Your tcp->seq might have an invalid value, because TCP only accepts values up to 65535, while random() returns values from 0 to RAND_MAX (0x7fffffff). Try tcp->seq = htonl(random() % 65535);
Your offset calculation for the TCP header is incorrect. It should be sizeof(struct iphdr) rather than sizeof(struct tcphdr).
ip = (struct iphdr*) buffer;
tcp = (struct tcphdr*) (buffer + sizeof(struct tcphdr)); //This is wrong
Here to get array index of tcp header in buffer, you need to add sizeof(struct iphdr) to buffer like mentioned below.
ip = (struct iphdr*) buffer;
tcp = (struct tcphdr*) (buffer + sizeof(struct iphdr)); //This is correct
So, I have the raw sockets set up with some copypasta, it sends data, that part is working fine. But how would I set the data send over the socket? I'm looking to make a DNS request, if that helps. Code below.
int main(int argc, char *argv[])
{
if (!argv[1])
{
printf("Target not specified!\nUsage: ");
printf(argv[0]);
printf(" <target>\n");
exit(1);
}
struct ip ip;
struct udphdr udp;
int sd;
const int on = 1;
struct sockaddr_in sin;
//char msg[] = "\x03\xF0\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01";
u_char *packet;
packet = (u_char *)malloc(120);
ip.ip_hl = 0x5;
ip.ip_v = 0x4;
ip.ip_tos = 0x0;
ip.ip_len = 60;
ip.ip_id = htons(12830);
ip.ip_off = 0x0;
ip.ip_ttl = 64;
ip.ip_p = IPPROTO_UDP;
ip.ip_sum = 0x0;
ip.ip_src.s_addr = inet_addr(argv[1]);
ip.ip_dst.s_addr = inet_addr("67.228.44.4");
ip.ip_sum = in_cksum((unsigned short *)&ip, sizeof(ip));
memcpy(packet, &ip, sizeof(ip));
udp.source = htons(80);
udp.dest = htons(53);
udp.len = htons(22);
udp.check = 0;
udp.check = in_cksum_udp(ip.ip_src.s_addr, ip.ip_dst.s_addr, (unsigned short *)&udp, sizeof(udp));
memcpy(packet + 20, &udp, sizeof(udp));
if ((sd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("raw socket");
exit(1);
}
if (setsockopt(sd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) {
perror("setsockopt");
exit(1);
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip.ip_dst.s_addr;
if (sendto(sd, packet, 120, 0, (struct sockaddr *)&sin, sizeof(struct sockaddr)) < 0)
{
perror("sendto");
exit(1);
}
}
Hmmm...I think you're wondering how to set the payload in your message? Basically, you want to offset from the IP and UDP headers and start writing your payload data at that point.
A hastily thrown together example of this:
int offset = packet + sizeof(struct ip) + sizeof(struct udphdr);
Then you can write your payload as follows:
strcpy(offset, "1234");
Here's some working ICMP code that is effectively writing out the data over a RAW IP socket:
struct icmphdr *icmp_hdr;
char *datapart;
icmp_hdr = (struct icmphdr *) icmp_data;
icmp_hdr->i_type = ICMP_ECHO;
icmp_hdr->i_code = 0;
icmp_hdr->i_id = (unsigned short) getpid();
icmp_hdr->i_cksum = 0;
icmp_hdr->i_seq = 0;
datapart = icmp_data + sizeof(struct icmphdr);
memset(datapart, 'E', datasize - sizeof(struct icmphdr));