In this example I am going to change destination ip address of packet. Of course I should change source ip address in return path.
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
/*
* 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