Solved [Solved] Creating and transmitting raw IP packets

My goal is to create an IP packet with just headers and no payload. I am using http://www.enderunix.org/docs/en/rawipspoof/ as a guide. The current issue is that I cannot appease sendto() and I'm not sure how to get more verbose feedback on which parameter is invalid and how it is invalid. Running truss on my program.

Code:
sendto(3,"E\0\0<2\^^\0\0@\M^?\0\0\^?\0\0"...,20,0x0,{ AF_INET 127.0.0.1:1337 },0x10) ERR#22 'Invalid argument'

And the code;

Code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>

#include <netinet/in_systm.h>
#include <netinet/in.h>
#include <netinet/ip.h>

#include <arpa/inet.h>

int main(int argc, char *argv[])
{
  int    sockfd;
  const int on = 1;
  struct sockaddr_in tx; 
  struct ip pkt_hdr; 
  u_char *pkt; 

  //Init IP packet header fields
  pkt_hdr.ip_hl  = 0x5; // 5 x 32 bit length units
  pkt_hdr.ip_v   = 0x4; // IPv4 type packet
  pkt_hdr.ip_tos = 0x0; // ?? Type of Service, packet precedence ???
  pkt_hdr.ip_len = htons(20); // Total Length of Packet
  pkt_hdr.ip_id  = htons(12830); // Packet ID
  pkt_hdr.ip_off = 0x0; // Set fragment offset to 0, don't want fragmentation
  pkt_hdr.ip_ttl = 64; // TTL in number of hops
  pkt_hdr.ip_p   = IPPROTO_RAW; // Protocol
  pkt_hdr.ip_sum = 0x0; // No checksum
  
  pkt_hdr.ip_src.s_addr = inet_addr("127.0.0.1");
  pkt_hdr.ip_dst.s_addr = inet_addr("127.0.0.1");

  //Copy header packet 
  pkt = (u_char *)malloc(20);
  memcpy(pkt, &pkt_hdr, sizeof(pkt_hdr));    
  
  //Open raw socket as the intended output write 
  //destination for a IP packet 
  if ((sockfd = socket(PF_INET,SOCK_RAW, IPPROTO_RAW)) < 0 )
  {
    perror("socket");
    exit(1);
  }
  
  //Tell kernel to not prepare IP header
  if (setsockopt(sockfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on)))
  {
    perror("setsockop"); 
    exit(1);
  }

  //Init network IP information  
  //for routing and transmission
  //so kernel can prepare layer 1 data 
  memset(&tx, 0, sizeof(tx));
  tx.sin_family      = AF_INET;
  tx.sin_port        = htons(1337);
  tx.sin_addr.s_addr = inet_addr("127.0.0.1"); 
 
  //Write the packet out to the network pipe
  if (sendto(sockfd,pkt,20,0,(struct sockaddr *)&tx,sizeof(tx)) < 0 )
  {
    perror("sendto");
    exit(1);
  }
  
  return 0;
}
}

My end goal is to be able to tcpdump these packets on lo0 and gradually build a trivial protocol.
 
Re: Creating and transmitting raw IP packets

ip(4) mentions that the ip_len must be provided in host byte order.

Happy New Year! :beergrin
 
Re: Creating and transmitting raw IP packets

Thanks for pointing out that manpage, that's illuminating more aspects of raw IP packet creation in FreeBSD.

I modified the two packet fields to be set to host byte order as indicated.

Code:
ip_len = ntohs(20);
ip_off = ntohs(0);

Still getting the same error. My next step is to avoid crafting the layer 1 fields manually by omitting the setsockopt() call and have the kernel prepare that for me.
 
Re: Creating and transmitting raw IP packets

inetplumber said:
Code:
ip_len = ntohs(20);
ip_off = ntohs(0);

Still getting the same error.

Yes, that's because by using ntohs() you actually did the same wrong endian conversion again. :)

To use a number in host byte order just ..uhm.. use it:

Code:
ip_len = 20;
ip_off = 0;
 
Re: Creating and transmitting raw IP packets

That did it! Thanks for your help. Here's to more network programming in 2014!
 
Back
Top