I'm trying to make an ICMP packet with a custom IP header.
When I disable IP_HDRINCL to use the default IP header and cut out all the IP header related code, it works (I checked the checksums of the code below and the code that works with default headers, the ICMP packet is definitely valid in the code below).
The issue arrives when trying to use my own IP header, I don't receive any ICMP packets, indicating the packet didn't properly transmit or something went wrong.
I'm on Ubuntu 16.04 and compiling with GCC with the flags -std=c11 -Wall -Wextra -pedantic
#include <errno.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <netinet/ip_icmp.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <arpa/inet.h>
#define PACKETSIZE 256
// Packet struct
struct packet {
struct iphdr ip; // IP Header
struct icmphdr hdr; // ICMP Header
char msg[PACKETSIZE - sizeof(struct icmphdr) - sizeof(struct iphdr)]; // Message
};
// Checksum function
unsigned short checksum(void *b, int len) {
unsigned short *buf = b;
unsigned int sum = 0;
unsigned short result;
for (sum = 0; len > 1; len -= 2) {
sum += *buf++;
}
if (len == 1) sum += *(unsigned char*)buf;
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
int main(int argc, char* argv[])
{
// Enough arguments
if (argc < 2) {
printf("usage: ./tracert <server>\n");
return EXIT_FAILURE;
}
// Variables
struct hostent *hname;
struct sockaddr_in addr;
unsigned int i;
int sockfd, seq = 1;
struct packet pckt;
socklen_t len;
char buf[1024];
// Get host from domain
hname = gethostbyname(argv[1]);
memset(&addr, 0, sizeof(addr));
addr.sin_family = hname->h_addrtype;
addr.sin_port = htons(6969);
addr.sin_addr.s_addr = *(long *)hname->h_addr_list[0];
// Create ICMP RAW socket
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if (sockfd < 0) {
printf("error on socket creation\n");
return EXIT_FAILURE;;
}
if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &seq, sizeof(seq)) < 0) {
printf("error on default ip header settings\n");
return EXIT_FAILURE;
}
// Loop and receive/send packets
while (1) {
// Make packet
memset(&pckt, 0, sizeof(pckt));
// IP Header
pckt.ip.version = 4;
pckt.ip.ihl = 5;
pckt.ip.tot_len = htons(sizeof(pckt));
pckt.ip.ttl = 255;
pckt.ip.protocol = IPPROTO_ICMP;
pckt.ip.saddr = inet_addr("192.168.1.1");
pckt.ip.daddr = addr.sin_addr.s_addr;
pckt.ip.check = checksum(&pckt, sizeof(struct iphdr));
// ICMP Header
pckt.hdr.type = ICMP_ECHO;
pckt.hdr.un.echo.id = 0;
for (i = 0; i < sizeof(pckt.msg) - 1; i++) {
pckt.msg[i] = i+'0';
}
pckt.msg[i] = 0;
pckt.hdr.un.echo.sequence = seq;
pckt.hdr.checksum = checksum(&pckt.hdr, sizeof(struct icmphdr) + sizeof(pckt.msg));
// Send packet
if (sendto(sockfd, &pckt, sizeof(pckt), 0, (struct sockaddr*)&addr, sizeof(addr)) <= 0) {
printf("error on sending packet\n");
return EXIT_FAILURE;
}
// Receive packet
len = sizeof(addr);
memset(buf, 0, sizeof(buf));
if (recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr*)&addr, &len) > 0) {
printf("packet received\n");
// Do more stuff here later...
}
// The while is there for later, for now I just want to send one packet
return EXIT_SUCCESS;
}
close(sockfd);
return EXIT_SUCCESS;
}
Related
I am trying to write a server program that just displays any raw data it receives from anyone through udp. A client can send some data to it at any time. No errors appear except for "Socket error: Resource temporarily unavailable" which in other words mean that recvfrom has no data to receive (because it's presumably not getting any packets).
The client just sends "test!" to 127.0.0.0:12345, while the server listens with a non-blocking socket on port 12345. It may be worth noting that I am on linux.
Why is server not displaying the packets that it's obviously being sent from client? I don't see what I'm missing.
common.h
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
typedef struct sockaddr_in sockaddr_in;
typedef struct sockaddr sockaddr;
int createSocket(uint16_t port)
{
int handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (handle <= 0)
{
printf("failed to create socket\n");
return 0;
}
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons(port);
if (bind(handle, (const sockaddr*)&address, sizeof(sockaddr_in)) < 0)
{
printf("failed to bind socket\n");
return 0;
}
int nonBlocking = 1;
if (fcntl(handle, F_SETFL, O_NONBLOCK, nonBlocking) == -1)
{
printf("failed to set non-blocking\n");
return 0;
}
return handle;
}
int sendData(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint16_t port, int handle, char* packet_data, int packet_size)
{
uint32_t address = (a << 24) | (b << 16) | (c << 8) | d;
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(address);
addr.sin_port = htons(port);
int sent_bytes = sendto(handle, (const char*)packet_data, packet_size, 0, (sockaddr*)&address, sizeof(sockaddr_in));
if (sent_bytes != packet_size)
{
printf("failed to send packet (%d/%d)\n", sent_bytes, packet_size);
return 0;
}
}
server.c
#include "common.h"
#include <time.h>
void main(void){
int socket = createSocket(12345);
if (!socket){
perror("Socket error");
}
int true=1;
setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (const void*)&true, 1);
// so that we can immediately reuse the port if the server stops running
char buffer[100] = "No data";
if(!listen(socket, 0)){
perror("Socket error");
}
//struct timespec delay = {0,33333333}; // 30Hz
struct timespec delay = {0,100000000}; // 100Hz
int running = 1;
int ret = 0;
while(running){
ret = recvfrom(socket, &buffer, 100, 0, NULL, NULL);
if (ret < 0){
perror("Socket error");
} else if (ret > 0){
printf("%d: %s\n", ret, buffer);
}
nanosleep(&delay,NULL);
}
}
client.c
#include "common.h"
void main(void){
int socket = createSocket(0);
printf("Started client on port %d\n", socket);
if(!sendData(127,0,0,0,12345, socket, "test!", 5)){
perror("Socket error");
} else {
printf("Sent data.\n");
}
}
I passed a pointer to address where I was supposed to pass a pointer to addr in common.h -> sendTo().
On top of that, I was sending packets to 127.0.0.0 when that should have been 127.0.0.1 (thanks #yano).
Corrected code:
int sendData(uint32_t a, uint32_t b, uint32_t c, uint32_t d, uint16_t port, int handle, char* packet_data, int packet_size)
{
uint32_t address = (a << 24) | (b << 16) | (c << 8) | d;
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(address);
addr.sin_port = htons(port);
int sent_bytes = sendto(handle, (const char*)packet_data, packet_size, 0, (sockaddr*)&addr, sizeof(sockaddr_in));
if (sent_bytes != packet_size)
{
printf("failed to send packet (%d/%d)\n", sent_bytes, packet_size);
return 0;
}
}
I'm trying to write a ping function for an ICMP library. Everything seems to work up until sendto, when it returns Address family not supported by protocol family. I don't understand the error. What am I doing wrong?
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <errno.h>
#include <netdb.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
static u_int16_t
checksum(u_int16_t *arr, size_t bytes)
{
u_int32_t sum = 0;
u_int16_t *ptr = arr;
while (bytes > 1) {
sum += *ptr++;
bytes -= 2;
}
if (bytes == 1) {
*(u_int8_t *)&sum += *(u_int8_t *)ptr;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
return (u_int16_t)(~sum);
}
ssize_t
icmp_send(const char *host, const char *data, const size_t datalen)
{
int s, error;
struct addrinfo hints;
struct addrinfo *res = NULL;
bzero(&hints, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_RAW;
hints.ai_protocol = IPPROTO_ICMP;
if ((error = getaddrinfo(host, NULL, &hints, &res))) {
fprintf(stderr, "ping: getaddrinfo: %s\n", gai_strerror(error));
return -1;
}
struct protoent *proto = getprotobyname("icmp");
if ((s = socket(AF_INET, SOCK_RAW, proto->p_proto)) == -1) {
fprintf(stderr, "ping: socket: %s\n", strerror(errno));
return -1;
}
int on = 1;
if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) {
fprintf(stderr, "ping: setsockopt: %s\n", strerror(errno));
return -1;
}
struct sockaddr_in to;
bzero(&to, sizeof(to));
to.sin_family = AF_INET;
struct ip ip;
bzero(&ip, sizeof(ip));
ip.ip_v = IPVERSION;
ip.ip_hl = sizeof(struct ip) << 2;
ip.ip_id = 0;
ip.ip_ttl = 255;
ip.ip_p = IPPROTO_ICMP;
ip.ip_src.s_addr = INADDR_ANY;
ip.ip_dst = ((struct sockaddr_in *)res)->sin_addr;
ip.ip_sum = checksum((u_int16_t *)&ip, sizeof(ip));
struct icmp icp;
bzero(&icp, sizeof(icp));
icp.icmp_type = ICMP_ECHOREPLY;
icp.icmp_code = 0;
icp.icmp_cksum = checksum((u_int16_t *)&icp, sizeof(icp));
size_t packetlen = sizeof(ip) + sizeof(icp) + datalen;
char packet[packetlen];
memset(packet, 0, packetlen);
memcpy((char *)packet, &ip, sizeof(ip));
memcpy((char *)packet + sizeof(ip), &icp, sizeof(icp));
memcpy((char *)packet + sizeof(ip) + sizeof(icp), data, packetlen);
ssize_t snd_ret = sendto(s, packet, packetlen, 0, (const struct sockaddr *)&to, sizeof(to));
if (errno) {
fprintf(stderr, "ping: sendto: %s\n", strerror(errno));
return -1;
}
return snd_ret;
}
res is a pointer to an addrinfo structure, not a sockaddr. The sockaddr is in the ai_addr member, and its length is in the ai_addrlen member. These should be passed to sendto().
ssize_t snd_ret = sendto(s, packet, packetlen, 0, res->ai_addr, res->ai_addrlen);
I´m writing a small ping program in C. I hace succesfully built the ip header and icmp header. The data I´m sending is 64 bytes long. However, I´m having trouble with the checksum value of the ICMP header. The IP is sending the correct checkum, but the checksum in the ICMP is constantly changing and in wireshark I get a message telling me that it expects the same value.
Here´s my code:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/time.h>
#include <stdlib.h>
#include <memory.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <stdarg.h>
#include <math.h>
#include <sys/termios.h>
#define PCKT_LEN 8192
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;
};
struct icmpheader{
char type;
char code;
short int checksum;
char content[4];
char data[64];
};
unsigned short checksum(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 *argv[]){
int sd;
char buffer[92]; // ICMP +IP_HEADER + DATA(64 BYTES)
int i=0;
//Definiendo estructura de header IP
struct ipheader *ip = (struct ipheader *) buffer;
struct icmpheader *icmp = (struct icmpheader *) (buffer + sizeof(struct ipheader));
//Direcciones host y dest
struct sockaddr_in sin, din;
int one = 1;
const int *val = &one;
memset(buffer, 0, 92);
if(argc != 3)
{
printf("- Parametros invalidos\n");
printf("- Usage %s <source hostname/IP> <source port> <target hostname/IP> <target port>\n", argv[0]);
exit(-1);
}
sd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if(sd < 0){
perror("socket() error");
// If something wrong just exit
exit(-1);
}
printf("socket() Creado exitosamente.");
// The source is redundant, may be used later if needed
// The address family
sin.sin_family = AF_INET;
din.sin_family = AF_INET;
// IP addresses
sin.sin_addr.s_addr = inet_addr(argv[2]);
din.sin_addr.s_addr = inet_addr(argv[1]);
// Creando el header IP
ip->iph_ihl = 5;
ip->iph_ver = 4;
ip->iph_tos = 16;
ip->iph_len = sizeof(struct ipheader) + 8+64;
ip->iph_ident = htons(54321);
ip->iph_ttl = 64; // hops
ip->iph_protocol = 1; // ICMP
// Source IP
ip->iph_sourceip = inet_addr(argv[2]);
//DEST IP
ip->iph_destip = inet_addr(argv[1]);
//Creamos header icmp
icmp->type=8;
icmp->code=0;
for(i=0;i<4;i++){
icmp->content[i]=0;
}
for(i=0;i<64;i++){
icmp->data[i]=(char)i;
}
printf("ICMP HEADER: %d\n",sizeof(struct icmpheader));
printf("IP HEADER: %d\n",sizeof(struct ipheader));
// Calcular checksum IP
ip->iph_chksum = checksum((unsigned short *)buffer, sizeof(struct ipheader) +sizeof(struct icmpheader));
//ICMP checksum
icmp->checksum = 0;
icmp->checksum = checksum((unsigned short *)buffer+sizeof(struct ipheader) , sizeof(struct icmpheader));
//icmp->checksum = 0xfc13;
// 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() OK.\n");
}
// Send loop, enviar cada 2 segundos por 100
printf("Trying...\n");
printf("Using raw socket and ICMP protocol\n");
printf("Using Source IP: %s Destination IP: %s .\n", argv[2], argv[1]);
int count;
for(count = 1; 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;
}
Can anyone tell me the correct way to calculate the checksum for the ICMP header?
int ip_headerlen = ip->iph_ihl * 4;
ip->iph_chksum = in_cksum ((unsigned short *) ip,
ip_headerlen);//only need ipheaderlen
icmp->icmp_chksum = in_cksum((unsigned short *)icmp,
//sizeof(struct icmpheader));
ntohs(ip->iph_len)-ip_headerlen );
//need icmp header + icmp data
Why does recvfrom create additional IP header?
I am sending:
-------------
- IP header -
-------------
- Data -
-------------
But when I try to receive data, it looks like there is
-------------
- IP header -
-------------
- IP header -
-------------
- Data -
-------------
Client code:
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <netinet/ip.h>
#define DEBUG 1
int main(void) {
// Create File descrptor for socket
int socket_fd;
if ((socket_fd = socket(AF_INET, SOCK_RAW, IPPROTO_IPV6)) < 0) {
perror("ERROR Socket");
exit(2);
}
char *srcIP = "127.0.0.1";
char *dstIP = "127.0.0.1";
// Create address structure
struct sockaddr_in daddr;
daddr.sin_family = AF_INET;
daddr.sin_port = 0; // Raw sockets can't use ports
inet_pton(AF_INET, "127.0.0.1", &daddr.sin_addr);
memset(daddr.sin_zero, 0, sizeof(daddr.sin_zero));
// Create a Packet
char packet[50];
memset(packet, 0, sizeof(packet));
// Structure packet
struct iphdr *ip_header = (struct iphdr *) packet;
// Data to be appended at the end of the ip header
char *data = (char *) (packet + (sizeof(struct iphdr)));
ip_header->version = 4; // IPv4
ip_header->tos = 0; // Type of service
ip_header->ihl = 5; // 5 x 32-bit words
// ip_header->tot_len = htons(sizeof(struct iphdr) + strlen(data)); // Total IP packet length
ip_header->tot_len = sizeof(packet); // Total IP packet length
ip_header->protocol = IPPROTO_IPV6; // 6in4 protocol
ip_header->frag_off = 0x00; //16 bit field = [0:2] flags + [3:15] offset = 0x0
ip_header->ttl = 0xFF; // Max number of hops 16bit
// ip_header->id = htons(54321); // 0x00; //16 bit id
ip_header->check = 0; //16 bit checksum of IP header. Can't calculate at this point
ip_header->saddr = inet_addr(srcIP);
ip_header->daddr = inet_addr(dstIP);
data[0] = 'T';
data[1] = 'E';
data[2] = 'S';
data[3] = 'T';
data[4] = '7';
data[5] = '\0';
// ip_header->check = csum((unsigned short *) packet, ip_header->tot_len);
#if DEBUG
printf("\nIP header checksum: %d\n", ip_header->check);
#endif
while (1) {
sleep(1);
if (sendto(socket_fd, (char *) packet, sizeof(packet), 0,
(struct sockaddr *) &daddr, (socklen_t) sizeof(daddr)) < 0)
perror("Packet send error");
}
return 0;
}
Server code:
/*** IPPROTO_RAW receiver ***/
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int socket_fd;
struct sockaddr_in saddr;
char packet[50];
if ((socket_fd = socket(AF_INET, SOCK_RAW, IPPROTO_IPV6)) < 0) {
perror("socket_fd");
exit(EXIT_FAILURE);
}
memset(packet, 0, sizeof(packet));
socklen_t len = (socklen_t) sizeof(saddr);
while(1) {
if (recvfrom(socket_fd, packet, sizeof(packet), 0,
(struct sockaddr *)&saddr, &len) < 0)
perror("recvfrom");
int i = sizeof(struct iphdr); ////// WHY IS DATA PAYLOAD ON packet[sizeof(struct iphdr) * 2]
while (i < sizeof(packet)) {
fprintf(stderr, "%c", packet[i]);
i++;
}
printf("\n");
}
exit(EXIT_SUCCESS);
}
In your sender, you need to set the IP_HDRINCL socket option. That tells the API that you're manually supplying the IP header. Because you're not setting this option, you're effectively putting your own copy of the IP header after the one the system adds.
IP_HDRINCL socket option is normally implicitly set only in the case of usage of IPPROTO_RAW. If you are not using IPPROTO_RAW, then the header will be generated as IP_HDRINCL will not be set implicitly.
Refer to man7.org/linux/man-pages/man7/raw.7.html.
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