Pejman Moghadam / C-programming

C - libipq example

In this example I am going to change destination ip address of packet. Of course I should change source ip address in return path.


Commands

modprobe iptable_filter
modprobe ip_queue
iptables -I OUTPUT -d 192.168.20.22 -p tcp --dport 80 -j QUEUE
iptables -I INPUT -s 172.16.27.9 -p tcp --sport 80 -j QUEUE

Changing source ip 192.168.20.22 to 172.16.27.9

/*
 * This code is GPL.
 *
 * Compile : gcc libipq.c -o libipq -lipq
 *
 */

#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <linux/netfilter.h>
#include <libipq.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define BUFSIZE 2048


struct pseudo_tcphdr
{
    unsigned int ip_src;
    unsigned int ip_dst;
    unsigned char zero;
    unsigned char protocol;
    unsigned short tcp_len;
};                                                                                                                                          

static void die(struct ipq_handle *h)
{
    ipq_perror("passer");
    ipq_destroy_handle(h);
    exit(1);
}

unsigned short in_checksum(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 tcp_checksum(struct iphdr* iph, struct tcphdr* tcph, 
                                            char* data, int size)
{
    char buffer[65536];
    struct pseudo_tcphdr psd_header;

    psd_header.ip_dst   = iph->daddr;
    psd_header.ip_src   = iph->saddr;
    psd_header.zero     = 0;
    psd_header.protocol = iph->protocol;
    psd_header.tcp_len  = htons(sizeof(struct tcphdr)+size);

    tcph->check = 0;
    memcpy(buffer, &psd_header, sizeof(struct pseudo_tcphdr));
    memcpy(buffer+sizeof(struct pseudo_tcphdr), tcph, 
                                    sizeof(struct tcphdr));
    memcpy(buffer+sizeof(struct pseudo_tcphdr)+sizeof(struct tcphdr), 
                                                            data, size);
    return tcph->check = in_checksum((unsigned short *)buffer,
            sizeof(struct pseudo_tcphdr)+sizeof(struct tcphdr)+size);
}

void show_buffer(unsigned char *buf, int len)
{
    int i, j;
    char str[17];

    str[16] = 0;
    printf("\n");
    for (i = 0; i < len; i += 16) { 
            fprintf(stdout,  "   ");
            for (j = 0; j < 16 && i+j < len; j++) {
                    fprintf(stdout,  "%02x ", buf[i+j]);

                    if (buf[i+j] > 32 && buf[i+j] < 127)
                            str[j] = buf[i+j];
                    else
                            str[j] = '.';

            }
            for (; j < 16; j++) {
                    fprintf(stdout,  "   ", buf[i+j]);
                    str[j] = ' ';
            }
            printf("   |   %s   |\n", str);
    }
}

int main(int argc, char **argv)
{
    int status;
    unsigned char buf[BUFSIZE];
    struct ipq_handle *h;
    size_t pack_len;
    int i;
    struct iphdr *iph;
    struct tcphdr *tcph;
    unsigned char *pack;
    char *src_addr, *dst_addr;
    long long count;

    /* 
     * Initialisation
     * IPV4 protocol only
     */
    h = ipq_create_handle(0, NFPROTO_IPV4);
    if (!h)
            die(h);

    /*
     * Setting the Queue Mode 
     * Get packet metadata and packet payloads 
     */
    status = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE);
    if (status < 0)
            die(h);

    /* Receiving Packets from the Queue */
    count = 1;
    do {
            status = ipq_read(h, buf, BUFSIZE, 0);
            if (status < 0)
                    die(h);

            fprintf(stdout, "\nCount: %lld\n", count++);

            switch (ipq_message_type(buf)) {
            case NLMSG_ERROR:
                    fprintf(stderr, "Received error message %d\n",
                                            ipq_get_msgerr(buf));
                    break;
            case IPQM_PACKET: {
                    ipq_packet_msg_t *m = ipq_get_packet(buf);


                    /* get and show packet length */
                    pack_len = m->data_len;
                    fprintf(stdout, "Length: %d\n", pack_len);

                    /* Show original packet */
                    fprintf(stdout, "Payload: ");
                    show_buffer(m->payload, pack_len);

                    /* Create new changed packet */
                    pack = (unsigned char *) malloc(pack_len);
                    memset((char *)pack, '\0', pack_len);
                    memcpy(pack, m->payload, pack_len);
                    iph = (struct iphdr *) pack;

                    /* Getting Source */
                    src_addr = (char *)inet_ntoa((struct in_addr *)
                                                            iph->saddr);
                    fprintf(stdout, "Original Source Address: %s\n", 
                                                            src_addr);

                    /* Change source if necessary */
                    if (strcmp(src_addr, "172.16.27.9") == 0)
                            iph->saddr = inet_addr("192.168.20.22");

                    /* Getting Destination */
                    dst_addr = (char *)inet_ntoa((struct in_addr *)
                                                            iph->daddr);
                    fprintf(stdout, "Original Destination Address: %s\n", 
                                                            dst_addr);

                    /* Change destinatin if necessary */
                    if (strcmp(dst_addr, "192.168.20.22") == 0)
                            iph->daddr = inet_addr("172.16.27.9");

                    /* Getting Source */
                    src_addr = (char *)inet_ntoa((struct in_addr *)
                                                            iph->saddr);
                    fprintf(stdout, "New Source Address: %s\n", 
                                                            src_addr);

                    /* Getting Destination */
                    dst_addr = (char *)inet_ntoa((struct in_addr *)
                                                            iph->daddr);
                    fprintf(stdout, "New Destination Address: %s\n", 
                                                            dst_addr);

                    /* Change IP checksum */
                    iph->check = 0;
                    iph->check = (unsigned short) in_checksum(
                            (unsigned short *) iph, sizeof(struct iphdr));

                    /* Change TCP checksum */
                    tcph = (struct tcphdr *) &pack[ iph->ihl * 4 ];
                    tcph->check = 0;
                    tcph->check = (unsigned short) tcp_checksum(
                                    iph, tcph, (char *)tcph + 20, 
                                    pack_len - sizeof(struct iphdr) 
                                    - sizeof(struct tcphdr));

                    /* Show new packet */
                    fprintf(stdout, "Changed: ");
                    show_buffer(pack, pack_len);

                    /* Accept packet and send it to kernel */
                    status = ipq_set_verdict(h, m->packet_id, NF_ACCEPT, 
                                    pack_len, (unsigned char *) pack);
                    if (status < 0)
                            die(h);
                    break;
                    }
            default:
                    fprintf(stderr, "Unknown message type!\n");
                    break;
            }
    } while (1);

    ipq_destroy_handle(h);
    return 0;
}

BY: Pejman Moghadam
TAG: libipq, iptables
DATE: 2012-11-07 19:10:11


Pejman Moghadam / C-programming [ TXT ]