Sendto function doesn't send packets

200 views Asked by At

I'm trying to send raw packets using the Sendto function in c with ipv4 and tcp headers that I provide on my own, but for some reason my code doesn't send the packets.

I think my problem might be on the following lines (but I am not really sure):

    int on = 1;
    int error =  setsockopt(s,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));
    if (error == SOCKET_ERROR)
    {
        printf("Error setsockopt(): %d", WSAGetLastError());
        return -1;
    }

Because when I comment it out, my code sends pakcets with an extra ipv4 header (1 that I supplied and 1 that windows added on it's own).

Another weird thing that happens is that on both the version where this segment is commented out and the segment where it's not, the sendto function returns 40, as if it sent 40 bytes, even though on one version it sent more that 40 bytes and on the other version it didn't send anything.

I tried everything I can think about, I tried to bind the socket, configure the socket with different ip protocols and change the configurations of the ipv4 and tcp headers, but nothing works.

I use cygwin to compile my code and I run it on windows 11.

Here is my full code (which is greatly inspired from a post I saw on the internet but can't find now):


#include "stdio.h"
#include "winsock2.h"
#include "ws2tcpip.h" //IP_HDRINCL is here
#include <stdint.h>
#include <netioapi.h>


#define host_port 3389
#define dst_port 3389

typedef struct ip_hdr
{
    unsigned char ip_header_len:4; // 4-bit header length (in 32-bit words) normally=5 (Means 20 Bytes may be 24 also)
    unsigned char ip_version :4; // 4-bit IPv4 version
    unsigned char ip_tos; // IP type of service
    unsigned short ip_total_length; // Total length
    unsigned short ip_id; // Unique identifier

    unsigned char ip_frag_offset :5; // Fragment offset field

    unsigned char ip_more_fragment :1;
    unsigned char ip_dont_fragment :1;
    unsigned char ip_reserved_zero :1;

    unsigned char ip_frag_offset1; //fragment offset

    unsigned char ip_ttl; // Time to live
    unsigned char ip_protocol; // Protocol(TCP,UDP etc)
    unsigned short ip_checksum; // IP checksum
    unsigned int ip_srcaddr; // Source address
    unsigned int ip_destaddr; // Source address
} IPV4_HDR, *PIPV4_HDR, FAR * LPIPV4_HDR;

// TCP header
typedef struct tcp_header
{
    unsigned short source_port; // source port
    unsigned short dest_port; // destination port
    unsigned int sequence; // sequence number - 32 bits
    unsigned int acknowledge; // acknowledgement number - 32 bits

    unsigned char ns :1; //Nonce Sum Flag Added in RFC 3540.
    unsigned char reserved_part1:3; //according to rfc
    unsigned char data_offset:4; /*The number of 32-bit words in the TCP header.
This indicates where the data begins.
The length of the TCP header is always a multiple
of 32 bits.*/

    unsigned char fin :1; //Finish Flag
    unsigned char syn :1; //Synchronise Flag
    unsigned char rst :1; //Reset Flag
    unsigned char psh :1; //Push Flag
    unsigned char ack :1; //Acknowledgement Flag
    unsigned char urg :1; //Urgent Flag

    unsigned char ecn :1; //ECN-Echo Flag
    unsigned char cwr :1; //Congestion Window Reduced Flag

////////////////////////////////

    unsigned short window; // window
    unsigned short checksum; // checksum
    unsigned short urgent_pointer; // urgent pointer
} TCP_HDR , *PTCP_HDR , FAR * LPTCP_HDR , TCPHeader , TCP_HEADER;

struct pseudo_header    //needed for checksum calculation
{
    unsigned int source_address;
    unsigned int dest_address;
    unsigned char placeholder;
    unsigned char protocol;
    unsigned short tcp_length;

    struct tcp_header tcp;
};

struct pseudoTcpHeader
{
    unsigned int ip_src;
    unsigned int ip_dst;
    unsigned char zero;//always zero
    unsigned char protocol;// = 6;//for tcp
    unsigned short tcp_len;
    struct tcp_header tcph;
};

unsigned short TcpCheckSum(unsigned short *buffer, int size)
{
    unsigned long cksum=0;
    while(size >1)
    {
        cksum+=*buffer++;
        size -=sizeof(unsigned short);
    }
    if(size)
        cksum += *(unsigned char*)buffer;

    cksum = (cksum >> 16) + (cksum & 0xffff);
    cksum += (cksum >>16);
    return (unsigned short)(~cksum);
}

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);
}

int main()
{
    setbuf(stdout, 0);

    char buf[1000],*data=NULL; //buf is the complete packet
    SOCKET s;

    IPV4_HDR *v4hdr=NULL;
    TCP_HDR *tcphdr=NULL;

    int payload=0;
    SOCKADDR_IN dest;
    struct hostent *server;

//Initialise Winsock
    WSADATA wsock;
    printf("\r\nInitialising Winsock...");
    if (WSAStartup(MAKEWORD(2,2),&wsock) != 0)
    {
        fprintf(stderr,"WSAStartup() failed");
        exit(EXIT_FAILURE);
    }
    printf("Initialised successfully.");
////////////////////////////////////////////////

//Create Raw TCP Packet
    printf("\r\nCreating Raw TCP Socket...");
    if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW))==SOCKET_ERROR)
    {
        printf("Creation of raw socket failed.");
        return 0;
    }

    printf("Raw TCP Socket Created successfully.");
//////////////////////////////////////////////

//Put Socket in RAW Mode.
    printf("\nSetting the socket in RAW mode...");
    int on = 1;
    int error =  setsockopt(s,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));
    if (error == SOCKET_ERROR)
    {
        printf("Error setsockopt(): %d", WSAGetLastError());
        return -1;
    }


////////////////////////////////////////////////


//Target Hostname
    char* host = "192.168.0.1";
    printf("\nResolving Hostname...");
    if((server=gethostbyname(host))==0)
    {
        printf("Unable to resolve.");
        return 0;
    }



    dest.sin_family = AF_INET;
    dest.sin_port = htons(dst_port); //your destination port
    memcpy(&dest.sin_addr.s_addr,server->h_addr,server->h_length);
    printf("Resolved.");
/////////////////////////////////////////////////


    char* source_ip = "192.168.0.9";
    printf("\nInitialized source ip");

    struct sockaddr_in bind_addr;
    bind_addr.sin_family = AF_INET;
    bind_addr.sin_port = htons(host_port);
    inet_aton(source_ip, &bind_addr.sin_addr.s_addr);
    bind(s, (struct sockaddr*) &bind_addr, sizeof(bind_addr));

    v4hdr = (IPV4_HDR *)buf; //let's point to the ip header portion
    v4hdr->ip_version=4;
    v4hdr->ip_header_len=5;
    v4hdr->ip_tos = 0;
    v4hdr->ip_total_length = htons ( sizeof(IPV4_HDR) + sizeof(TCP_HDR) + payload );
    v4hdr->ip_id = htons(2);
    v4hdr->ip_frag_offset = 0;
    v4hdr->ip_frag_offset1 = 0;
    v4hdr->ip_reserved_zero = 0;
    v4hdr->ip_dont_fragment = 1;
    v4hdr->ip_more_fragment = 0;
    v4hdr->ip_ttl = 100;
    v4hdr->ip_protocol = IPPROTO_TCP;
    v4hdr->ip_srcaddr = inet_addr(source_ip);
    v4hdr->ip_destaddr = inet_addr(inet_ntoa(dest.sin_addr));
    v4hdr->ip_checksum = csum( (unsigned short*) &v4hdr , sizeof (struct pseudo_header));


    tcphdr = (TCP_HDR *)&buf[sizeof(IPV4_HDR)]; //get the pointer to the tcp header in the packet

    tcphdr->source_port = htons(host_port);
    tcphdr->dest_port = htons(dst_port);

    tcphdr->sequence = 0xABCDEFAB;

    tcphdr->data_offset = 5;

    tcphdr->cwr=0;
    tcphdr->ecn=0;
    tcphdr->urg=0;
    tcphdr->ack=0;
    tcphdr->psh=0;
    tcphdr->rst=0;
    tcphdr->syn=1;
    tcphdr->fin=0;
    tcphdr->ns=0;

    tcphdr->checksum = TcpCheckSum((short unsigned int*)tcphdr, sizeof(TCP_HDR));


// Initialize the TCP payload to some rubbish
    data = &buf[sizeof(IPV4_HDR) + sizeof(TCP_HDR)];
    memset(data, '\0', payload);


    printf("\nSending packet...\n");


    int i=0;
    while(1)
    {
        int result = sendto(s, buf, sizeof(IPV4_HDR)+sizeof(TCP_HDR) + payload, 0, (SOCKADDR *)&dest, sizeof(dest));
        if (result <= 0){
            printf("Couldn't sent packet.");
            break;
        }
        i++;
    }
}
0

There are 0 answers