Search code examples
csocketswindows-10raw-sockets

Raw UDP socket in windows 10 cause network issue


In my client socket code, I need to get IP layer header for the receiving packet for UDP data grams.

So I decided to change the socket to RAW using below system call:

int optval=1;
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2),&wsaData) == SOCKET_ERROR) {

  int err = WSAGetLastError();
  my_err("WSAStartup error %d\n",err);
  return 0;
}

if((sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) == INVALID_SOCKET) {

        perror("socket()");
        return 0;
}

if (setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, (char *)&optval, sizeof optval) != 0) {

    perror("setsockopt(IPPROTO_IP,IP_HDRINCL)");
    return 0;
}

An then I send first data using:

//content is a structure containing data and its length
uint16_t all_length = content->len;

size_t IP_HL = sizeof (IPHEADER);

//get_interface_ip returns interface ip address
uint32_t src_addr = get_interface_ip();

IPHEADER *iph = NULL;
size_t all_length =  IP_HL + sizeof (UDPHEADER) + total_len;
UDPHEADER *udph = NULL;
BUFFER buf;
make_buf(&buf, 0);

iph = (IPHEADER *) BPTR(&buf);

iph->ip_hl = 5;
iph->ip_v = 4;
iph->ip_tos = 0;
iph->ip_len = all_length;
//get_uniq_id creates ip id field
iph->ip_id = htonl (get_uniq_id()); //Id of this packet
iph->ip_off = 64; //DONT fragment
iph->ip_ttl = 255;
iph->ip_p = IPPROTO_UDP;
iph->ip_sum = 0;      //Set to 0 before calculating checksum
iph->ip_src = src_addr;
iph->ip_dst = remote.sin_addr.s_addr;

iph->ip_sum = csum((uint16_t *)iph, iph->ip_len);

udph = (UDPHEADER *) (iph + 1);
memcpy((udph + 1), (char *)content->data, total_len);

//get_src_port gets a fixed source port number randomly created in program start time
udph->uh_sport = get_src_port();
udph->uh_dport = get_server_port();

udph->uh_len = htons(sizeof (UDPHEADER) + total_len);
udph->uh_check = 0; //leave checksum 0 now, filled later by pseudo header

{
    PSESUDO_HEADER psh;
    int psize = 0;
    char *pseudogram = NULL;

    psh.source_address = src_addr;
    psh.dest_address = remote.sin_addr.s_addr;
    psh.placeholder = 0;
    psh.protocol = IPPROTO_UDP;
    psh.udp_length = udph->uh_len;

    psize = sizeof(PSESUDO_HEADER) + sizeof(UDPHEADER) + total_len;
    pseudogram = (char *)malloc(psize);

    memcpy(pseudogram , (char*) &psh , sizeof (PSESUDO_HEADER));
    memcpy(pseudogram + sizeof(PSESUDO_HEADER) , udph , sizeof(UDPHEADER) + total_len);

    udph->uh_check = csum((uint16_t *)pseudogram, psize);
}

es->wsabuf.len = all_length;
es->wsabuf.buf = buf.data;

if(WSASendTo(sock, &wsabuf, 1, NULL, 0, (SOCKADDR *)&remote, sizeof(remote), &io_ovl, NULL) == SOCKET_ERROR) {

    int err = WSAGetLastError();
    if (err != WSA_IO_PENDING)
        return 0;
}

Above code, creates an IP header then UDP header then calculates IP and UDP checksums. I use the same logic for linux code and works pretty well.

When I run the program and send the first data, something wired happens! This program causes my old ADSL modem crash!

The only thing I could think of, is the packet format it generates.

I thought it must generate a bad formed IP or UDP headers that makes the old modem crash.

I started Wireshark and captured packets two times, First time the same code without RAW socket (regular send) and second time with RAW socket.

Then compared the result. To my surprise, I could not find any differences!

Wireshark send capture without RAW socket:

Frame 1: 105 bytes on wire (840 bits), 105 bytes captured (840 bits) on interface 0
    Interface id: 0 (\Device\NPF_{UUID})
    Encapsulation type: Ethernet (1)
    Arrival Time: Jan 30, 2017 21:53:46.500050000 Iran Standard Time
    [Time shift for this packet: 0.000000000 seconds]
    Epoch Time: 1485800626.500050000 seconds
    [Time delta from previous captured frame: 0.000000000 seconds]
    [Time delta from previous displayed frame: 0.000000000 seconds]
    [Time since reference or first frame: 0.000000000 seconds]
    Frame Number: 1
    Frame Length: 105 bytes (840 bits)
    Capture Length: 105 bytes (840 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: eth:ethertype:ip:udp:data]
    [Coloring Rule Name: UDP]
    [Coloring Rule String: udp]
Ethernet II, Src: IntelCor_MAC:ADDR (SRC:MAC:ADDR), Dst: AlphaNet_MAC:ADDR (DST:MAC:ADDR)
    Destination: AlphaNet_MAC:ADDR (DST:MAC:ADDR)
    Source: IntelCor_MAC:ADDR (SRC:MAC:ADDR)
    Type: IPv4 (0x0800)
Internet Protocol Version 4, Src: 192.168.1.4, Dst: server_ip
    0100 .... = Version: 4
    .... 0101 = Header Length: 20 bytes (5)
    Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
    Total Length: 91
    Identification: 0x6a10 (27152)
    Flags: 0x02 (Don't Fragment)
    Fragment offset: 0
    Time to live: 128
    Protocol: UDP (17)
    Header checksum: 0x70a6 [correct]
    [Header checksum status: Good]
    [Calculated Checksum: 0x70a6]
    Source: 192.168.1.4
    Destination: server_ip
    [Source GeoIP: Unknown]
    [Destination GeoIP: Unknown]
User Datagram Protocol, Src Port: 60594, Dst Port: 7554
    Source Port: 60594
    Destination Port: 7554
    Length: 71
    Checksum: 0x755e [correct]
    [Checksum Status: Good]
    [Stream index: 0]
Data (63 bytes)
    Data: 002523a38308884051a46d6c5135778f0a32db3027df1576...
    [Length: 63]

And with RAW socket:

Frame 2: 105 bytes on wire (840 bits), 105 bytes captured (840 bits) on interface 0
    Interface id: 0 (\Device\NPF_{UUID})
    Encapsulation type: Ethernet (1)
    Arrival Time: Jan 30, 2017 21:39:38.086166000 Iran Standard Time
    [Time shift for this packet: 0.000000000 seconds]
    Epoch Time: 1485799778.086166000 seconds
    [Time delta from previous captured frame: 17.305889000 seconds]
    [Time delta from previous displayed frame: 17.305889000 seconds]
    [Time since reference or first frame: 17.305889000 seconds]
    Frame Number: 2
    Frame Length: 105 bytes (840 bits)
    Capture Length: 105 bytes (840 bits)
    [Frame is marked: False]
    [Frame is ignored: False]
    [Protocols in frame: eth:ethertype:ip:udp:data]
    [Coloring Rule Name: UDP]
    [Coloring Rule String: udp]
Ethernet II, Src: IntelCor_MAC:ADDR (SRC:MAC:ADDR), Dst: AlphaNet_MAC:ADDR (DST:MAC:ADDR)
    Destination: AlphaNet_MAC:ADDR (DST:MAC:ADDR)
    Source: IntelCor_MAC:ADDR (SRC:MAC:ADDR)
    Type: IPv4 (0x0800)
Internet Protocol Version 4, Src: 192.168.1.4, Dst: server_ip
    0100 .... = Version: 4
    .... 0101 = Header Length: 20 bytes (5)
    Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
    Total Length: 91
    Identification: 0x58ef (22767)
    Flags: 0x02 (Don't Fragment)
    Fragment offset: 0
    Time to live: 255
    Protocol: UDP (17)
    Header checksum: 0x02c7 [correct]
    [Header checksum status: Good]
    [Calculated Checksum: 0x02c7]
    Source: 192.168.1.4
    Destination: server_ip
    [Source GeoIP: Unknown]
    [Destination GeoIP: Unknown]
User Datagram Protocol, Src Port: 16383, Dst Port: 7554
    Source Port: 16383
    Destination Port: 7554
    Length: 71
    Checksum: 0x2faf [correct]
    [Checksum Status: Good]
    [Stream index: 0]
Data (63 bytes)
    Data: 00250d80dd1b561e4d81c22c2914f49f1bb492f78d6a3ee8...
    [Length: 63]

Any ideas?


Solution

  • Sorry, this was my mistake. This code was one my old codes containing lots of files. Recently I got some free times and decided to do some its TODO tasks.

    Since I changed the socket to RAW, number of writes increased (data_length + udp_header + ip_header) but there was another peace of code in some place else (another file) with the following contents:

    if(number_of_written != data_length) {
    
        repeat_socket_process();
    }
    

    With this code, I was actually DOS (denial of service attack) my own router!

    Too many packets were generated at a fraction of seconds. So it was nothing to do with the raw socket nor packet headers.

    All I needed to do is to check

    if (number_of_written != data_length + udp_header + ip_header)
    

    Anyway thank you guys for the follow up and hope this help others to trace other places of their codes in the case of similar situations