Can IPQ be used to reroute packets locally?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I'm trying to use libipq to take all outbound packets destined for a particular address (192.168.1.44) and reroute them to the local IP (10.10.0.70).  I have the program below, it works just fine in 2.4.x kernels but produces a ip_rt_bug message in the 2.6 series.  The specific error message is
    "ip_rt_bug: 192.168.1.44 -> 10.10.0.70, ?" 
To test this, run setup_iptables.sh, compile and run test_server.c(on port 80) and ipqtest.c.  Then "telnet 192.168.1.44 80".  The expected behavior (that on 2.4 kernel), is a successful connection to test_server.

Thanks in advance,
J

--------------------------------------------------------------
--------------------------- IPQTEST.C ------------------------
--------------------------------------------------------------
/* Compile with cc -lipq */
#include <linux/netfilter.h>
#include <libipq.h>
#include <stdio.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>

#define BUFSIZE 2048

struct in_addr dot_44;
struct in_addr dot_70;

inline u_int16_t checksum_update_32(
	u_int16_t old_check,
	u_int32_t old,
	u_int32_t new)
{
	u_int32_t l;

	old_check = ~old_check;
	old = ~old;

	l = (u_int32_t)old_check + (old >> 16) + (old & 0xffff)
+ (new >> 16) + (new & 0xffff);
	return ~((u_int16_t)(l >> 16) + (l & 0xffff));
}

static void filter(
	unsigned char *packet)
{
	struct iphdr *ip;
	struct tcphdr *tcp;

	ip = (struct iphdr *)packet;
	if (ip->protocol == IPPROTO_TCP)
	{
		tcp = (struct tcphdr *)(((u_int32_t *)ip) + ip->ihl);

		if (ip->saddr == dot_70.s_addr)
		{
			ip->check = checksum_update_32(
				ip->check,
				ip->saddr,
				dot_44.s_addr);
			tcp->check = checksum_update_32(
				tcp->check,
				ip->saddr,
				dot_44.s_addr);
			ip->saddr = dot_44.s_addr;
		}
		if (ip->daddr == dot_44.s_addr)
		{
			ip->check = checksum_update_32(
				ip->check,
				ip->daddr,
				dot_70.s_addr);
			tcp->check = checksum_update_32(
				tcp->check,
				ip->daddr,
				dot_70.s_addr);
			ip->daddr = dot_70.s_addr;
		}
	}
}

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

int main(int argc, char **argv)
{
	int status;
	unsigned char buf[BUFSIZE];
	struct ipq_handle *h;

	inet_aton("192.168.1.44", &(dot_44));
	inet_aton("10.10.0.70", &(dot_70));

	h = ipq_create_handle(0, PF_INET);
	if (!h)
		die(h);

	status = ipq_set_mode(h, IPQ_COPY_PACKET, BUFSIZE);
	if (status < 0)
		die(h);

	do{
		status = ipq_read(h, buf, BUFSIZE, 0);
		if (status < 0)
			die(h);

		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);

			fprintf(stderr, "----------------
Accepting packet ----------------\n");
			if (m->data_len < sizeof(struct iphdr)) 
			{
				fprintf(
					stderr,
					"XXX BUG: %d < %d\n",
					m->data_len,
					sizeof(struct iphdr));
			}
			filter(m->payload);
			status = ipq_set_verdict(
				h,
				m->packet_id,
				NF_ACCEPT,
				m->data_len,
				m->payload);
			if (status < 0)
				die(h);
			break;
		}

		default:
			fprintf(stderr, "Unknown message type!\n");
			break;
		}
	} while (1);

	ipq_destroy_handle(h);
	return 0;
}
--------------------------------------------------------------
------------------------- TEST_SERVER.C ----------------------
--------------------------------------------------------------
#include <string.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <sys/select.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>

int my_recv(
	int csock,
	char *bufptr,
	int read_len)
{
	fd_set fds;
	int rval;

	FD_ZERO(&fds);
	FD_SET(csock, &fds);
	do {
		select(csock + 1, &fds, NULL, NULL, NULL);

		rval = recv(csock, bufptr, read_len, 0); /* req1 */
		if (rval > 0)
		{
			bufptr += rval;
			read_len -= rval;
		}
		else if (rval < 0
				 && (errno == EAGAIN
					 || errno == EINTR
					 || errno == EWOULDBLOCK))
		{
			continue;
		}
		else
		{
			return -1;
		}
	} while (read_len);

	return 0;
}

int my_send(
	int csock,
	char *bufptr,
	int send_len)
{
	fd_set fds;
	int rval;

	FD_ZERO(&fds);
	FD_SET(csock, &fds);
	do {
		select(csock + 1, NULL, &fds, NULL, NULL);

		rval = send(csock, bufptr, send_len, 0); /* req1 */
		if (rval > 0)
		{
			bufptr += rval;
			send_len -= rval;
		}
		else if (rval < 0
				 && (errno == EAGAIN
					 || errno == EINTR
					 || errno == EWOULDBLOCK))
		{
			continue;
		}
		else
		{
			return -1;
		}
	} while (send_len);

	return 0;
}

static void usage() 
{
	fprintf(stderr, "\nusage : test_server -p port\n");
	exit(-1);
} 

int main(int argc, char **argv) {
	int ssock, csock[2000];
	struct sockaddr_in saddr;
	char res1[2048];
	char buf[204800];
	int sz, on, rval, i=0;
	int c, port;
	fd_set fds;
	
    /* get command line params */
    while ((c = getopt(argc, argv, "p:")) != -1) {
		switch(c) {
		  case 'p':
			  port = atoi(optarg); i++;
			  break;
	      default:
			  usage();
		}  /* switch end */
    }  /* while end */

	if (i < 1 )
	{
		usage();
	} 

	i=0;

	saddr.sin_family = AF_INET;
	saddr.sin_port = htons(port);
	saddr.sin_addr.s_addr = INADDR_ANY;

	ssock = socket(PF_INET, SOCK_STREAM, 0);
	on = 1;
	sz = 512 * 1024;
	setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
	setsockopt(ssock, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on));
	setsockopt(ssock, SOL_SOCKET, SO_SNDBUF, &sz, sizeof(sz));
	setsockopt(ssock, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on));
	fcntl(ssock, F_SETFL, O_NONBLOCK | O_ASYNC);
	bind(ssock, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in));
	listen(ssock, 100);

	FD_ZERO(&fds);
	FD_SET(ssock, &fds);
	
	while (1)
	{
		select(ssock + 1, &fds, NULL, NULL, NULL);
		csock[i] = accept(ssock, NULL, NULL);
		snprintf(res1,sizeof(res1),"[%d] Connected To
Test Server...",i);
		printf("%s\n",res1);
		my_send(csock[i], res1, strlen(res1)); 
		i++;
	}

	return 0;
}
--------------------------------------------------------------
------------------------- IPTABLES.SH ------------------------
--------------------------------------------------------------
#!/bin/sh
/sbin/iptables --flush
/sbin/iptables -A OUTPUT -j QUEUE
/sbin/iptables -A INPUT -j QUEUE
/sbin/iptables -A FORWARD -j QUEUE
/sbin/modprobe ip_queue
-- 
_______________________________________________
Find what you are looking for with the Lycos Yellow Pages
http://r.lycos.com/r/yp_emailfooter/http://yellowpages.lycos.com/default.asp?SRC=lycos10




[Index of Archives]     [Linux Netfilter Development]     [Linux Kernel Networking Development]     [Netem]     [Berkeley Packet Filter]     [Linux Kernel Development]     [Advanced Routing & Traffice Control]     [Bugtraq]

  Powered by Linux