0

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;
}
  • A naive question: Are you running your program as root (e.g. `sudo myprogram`) because you need `CAP_NET_RAW` (per `man 7 raw`)? I found: https://www.opensourceforu.com/2015/03/a-guide-to-using-raw-sockets/ and it seems to contradict the man page. Specifically, it uses `PF_PACKET` instead of `PF_INET` in the `socket` call. And, it implies you have to contruct your own ethernet header [that precedes the other headers] and the MAC address of the interfaces, etc. When I wrote some commercial S/W that had to sniff packets, I was using `PF_PACKET` – Craig Estey Nov 17 '20 at 21:13
  • Yes, I used sudo while executing the code. As I said only the UDP header was missing in wireshark packet capture. Do I have to build an ethernet header as well because most of the examples I saw only created IP and UDP header with IP_HDRINCL option. – Sunil Sharma Nov 18 '20 at 04:10
  • With wireshark, you should be able to see the ethernet header as the first part of the data. So, what do you see? It is unlikely that it will have a gap in the middle. You'd see `eth|ip|udp|data` or maybe just `ip|udp|data` but you won't see `eth|ip|data` [or `ip|data`]. So, I'd put a signature pattern in the data to be able to see in data offset in wireshark. Try sending [data]: `0x00, 0x01, 0x02, ...` (e.g.). Then, see at what offset this ends up at. Have the sender _program_ dump out the entire buffer in hex to stdout and compare against wireshark. – Craig Estey Nov 18 '20 at 05:59
  • Re. `PF_PACKET`, see my answer: https://stackoverflow.com/questions/54056426/af-packet-and-ethernet/54057044#54057044 – Craig Estey Nov 18 '20 at 06:04

0 Answers0