The IP Protocol injected, inspected, detected, infected - Part II

On the previous chapter of "IP injected, inspected, detected, infected" -

Today we will look at the other part - injecting new IP packets, and infecting existing IP packets.

IP Injection - This is raw stuff, human!

Creating Raw Sockets

Lets create a raw socket in mode I, for use with the ICMP protocol. First the include files:
#include <sys/types.h>
#include <sys/socket.h>
Then creating the socket:
int s = socket(PF_NET, SOCK_RAW, IPPROTO_ICMP);
if (s == -1) {
    perror("raw socket():");

Sending A Packet Via The Raw Socket

More include files:
#include <netinet/ip_icmp.h>
And code:
struct icmphdr icmphdr

/* clear out the packet, and fill with contents. */
memset(&icmphdr, 0, sizeof(struct icmphdr));
icmphdr.type = ICMP_ECHO;
icmphdr.un.echo.sequence = 50;  /* just some random number. */ = 48;        /* just some random number. */
icmphdr.checksum =
    in_cksum((unsigned short*)&icmphdr, sizeof(struct icmphdr));

Sending A Packet Via The Raw Socket (Cont.)

Even more include files (for 'inet_aton'):
#include <netinet/in.h>
#include <arpa/inet.h>
And code:
struct sockaddr_in addr;

// prepare the address we're sending the packet to.
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
inet_aton("", &addr.sin_addr);

// finally, send the packet.
rc = sendto(s,
            &icpmhdr, sizeof(struct icmphdr),
            0 /* flags */,
            (struct sockaddr*)&addr, sizeof(addr));
if (rc == -1) {

Receiving Packets Using A Raw Socket

Remember - we receive _every_ packet sent to the machine, not just "expected responses".
/* the received packet contains the IP header... */
char rbuf[sizeof(struct iphdr) + sizeof(struct icmp)];
struct sockaddr_in raddr;
socklen_t raddr_len;

// receive the packet that we sent (since we sent it to ourselves,
// and a raw socket sees everything...).
rc = recvfrom(s,
              rbuf, sizeof(rbuf),
              0 /* flags */,
              (struct sockaddr*)&raddr, &raddr_len);
if (rc == -1) {
    perror("recvfrom 1:");

Parse The Received Packet

struct iphdr* iphdr = NULL;
struct icmphdr* recv_icmphdr = NULL;

// we got an IP packet - verify that it contains an ICMP message.
iphdr = (struct iphdr*)rbuf;
if (iphdr->protocol != IPPROTO_ICMP) {
    fprintf(stderr, "Expected ICMP packet, got %u\n", iphdr->protocol);

Parse The Received Packet (Cont.)

// verify that it's an ICMP echo request, with the expected seq. num + id.
icmphdr = (struct icmphdr*)(rbuf + (iphdr->ihl * 4));
if (icmphdr->type != ICMP_ECHOREPLY) {
    fprintf(stderr, "Expected ICMP echo-reply, got %u\n", icmphdr->type);
if (icmphdr->un.echo.sequence != 50) {
            "Expected sequence 50, got %d\n", icmphdr->un.echo.sequence);
if (icmphdr-> != 48) {
            "Expected id 48, got %d\n", icmphdr->;
printf("Got the expected ICMP echo-request\n");

Creating The IP Header Too

In order to create the complete IP packet (including the header), we use a socket option:

char on = 1;
setsockopt(s, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on));
From now, the kernel expects us to supply a complete IP packet.

Netfilter, ip_queue And Netlink

Defining The Iptables Rule

The 'ipq' Library

Initializing libipq

#include <linux/netfilter.h>  /* \ for libipq methods */
#include <libipq.h>           /* / and types.         */

/* we want to get IP traffic. */
struct ipq_handle *h = ipq_create_handle(0, PF_INET);
if (!h) {

// set the queuing mode - we want to have the packets copied
// to user space, with up to BUFSIZE octets copied.
#define BUFSIZE 2048
rc = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE);
if (rc < 0) {

Reading Packets From The Queue

"Judging Them Little Buggers"

A Packet Reading Loop

// loop forever, reading packets.
while (1) {
    int msg_type;

    rc = ipq_read(h, buf, BUFSIZE, 0);
    if (rc < 0) {

    msg_type = ipq_message_type(buf);
    switch (msg_type) {
        case NLMSG_ERROR:
            fprintf(stderr, "ipq_read got error %d",
        case IPQM_PACKET:
                ipq_packet_msg_t* msg = ipq_get_packet(buf);
                rc = ipq_set_verdict(h, msg->packet_id, NF_ACCEPT, 0, NULL);
            fprintf(stderr, "unknown ipq msg type %d\n", msg_type);


  1. Raw IP Networking FAQ -
  2. The "libnet" Packet Construction Library -
  3. Iptables Download -
  4. man libipq
Originally written by Valid HTML 4.01!guy keren