Linux Netfilter discussions
 help / color / mirror / Atom feed
* Failing to manipulate IP headers
@ 2002-09-20 20:29 Chen Ding
  0 siblings, 0 replies; only message in thread
From: Chen Ding @ 2002-09-20 20:29 UTC (permalink / raw)
  To: netfilter


[-- Attachment #1.1: Type: text/plain, Size: 1207 bytes --]

All,

I am trying to develop a customized NAT app based on netfilter framework. I have:
    a. Created a module
    b. Initialized and registered with netfilter
    c. Got sk_buff from the core

Currently, the program is very simple: just changes the receiver IP address (pre-routing)
and sender IP address (post-routing), and then forward the packets. 

Everything worked fine except that after the packets forwarded to the destination, the
reading program on the destination machine reported reading error (-1), and errno 11
(don't know the reason). 

After changed the IP address, I did recalculated the checksum, as follows (copied
from ip_nat_core.c):

            saddr = <the address to be changed to>;
            iph->check = ip_nat_cheat_check(~iph->saddr, saddr, iph->check);
            iph->saddr = saddr;

I did rechecked the checksum and it appeared to be good. 

Having searched answers from the Internet and digged the code without results, I hope
someone here can help me out. I guess I must have messed up the packets. 

For your information, I have attached the tiny source code at the end of this email.

Your help is most appreciated!!!


Chen Ding



[-- Attachment #1.2: Type: text/html, Size: 3120 bytes --]

[-- Attachment #2: hello.c --]
[-- Type: application/octet-stream, Size: 5860 bytes --]

/* hello.c 
 * Copyright (C) 1998 by Ori Pomerantz
 * 
 * "Hello, world" - the kernel module version. 
 */

/* The necessary header files */

/* Standard in kernel modules */
#include <linux/config.h>
#include <linux/skbuff.h>
#include <linux/kmod.h>
#include <linux/vmalloc.h>
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/tcp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <net/ip.h>
#include <asm/uaccess.h>
#include <asm/semaphore.h>
#include <asm/checksum.h>
#include <linux/proc_fs.h>


#include <linux/kernel.h>   /* We're doing kernel work */
#include <linux/module.h>   /* Specifically, a module */

#define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
#define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)

#include <linux/netfilter_ipv4/ip_nat.h>
#include <linux/netfilter_ipv4/ip_nat_rule.h>
#include <linux/netfilter_ipv4/ip_nat_protocol.h>
#include <linux/netfilter_ipv4/ip_nat_core.h>
#include <linux/netfilter_ipv4/ip_nat_helper.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
#include <linux/netfilter_ipv4/listhelp.h>

#include <linux/netfilter.h>

/* Deal with CONFIG_MODVERSIONS */
#if CONFIG_MODVERSIONS==1
#define MODVERSIONS
#include <linux/modversions.h>
#endif        


u_int16_t
ip_nat_cheat_check(u_int32_t oldvalinv, u_int32_t newval, u_int16_t oldcheck)
{
    u_int32_t diffs[] = { oldvalinv, newval };
    return csum_fold(csum_partial((char *)diffs, sizeof(diffs),
                      oldcheck^0xFFFF));
}

static unsigned int addr192_168_1_17 = 0x1101a8c0;
static unsigned int addr192_168_1_81 = 0x5101a8c0; 
static unsigned int addr10_10_10_1   = 0x010a0a0a;
static unsigned int addr10_10_10_3   = 0x030a0a0a;

static unsigned int
ip_nat_fn(unsigned int hooknum,
      struct sk_buff **pskb,
      const struct net_device *in,
      const struct net_device *out,
      int (*okfn)(struct sk_buff *))
{
	/* 
	 * The pre-routing function
	 */

	unsigned int saddr;
	unsigned int daddr;
	struct iphdr *iph;
	struct udphdr *udphdr;

	iph = (*pskb)->nh.iph;
	udphdr = (struct udphdr*)((u_int32_t *)iph + iph->ihl);
	
    if (iph->protocol == 17)
    {
        /*
         * It is UDP
         */

		saddr = iph->saddr;
		daddr = iph->daddr;
		if (saddr == addr192_168_1_17 && 
			daddr == addr192_168_1_81)
		{
			/* Found the match. Change daddr to 10.10.10.3 */
			daddr = addr10_10_10_3;		/* 10.10.10.3 */
			iph->check = ip_nat_cheat_check(~iph->daddr, daddr, iph->check);
        	iph->daddr = daddr;

			(*pskb)->nfcache |= NFC_UNKNOWN;	/* not sure whether should do this */
			(*pskb)->nfcache |= NFC_ALTERED;
			(*pskb)->nfcache |= NFC_IP_DST;
		}
    }

	return NF_ACCEPT;
}


static unsigned int
ip_nat_out(unsigned int hooknum,
       struct sk_buff **pskb,
       const struct net_device *in,
       const struct net_device *out,
       int (*okfn)(struct sk_buff *))
{
	/*
	 * The post-routing function
	 */
    unsigned int saddr;
    unsigned int daddr;

    struct iphdr *iph;
    struct udphdr *udphdr;

    iph = (*pskb)->nh.iph;
    udphdr = (struct udphdr*)((u_int32_t *)iph + iph->ihl);

    if (iph->protocol == 17)
    {
        /*
         * It is UDP
         */
        saddr = iph->saddr;
        daddr = iph->daddr;

        if (saddr == addr192_168_1_17 && daddr == addr10_10_10_3)
        {
			/* Change the source address to 10.10.10.1 */	
            saddr = addr10_10_10_1;      
            iph->check = ip_nat_cheat_check(~iph->saddr, saddr, iph->check);
            iph->saddr = saddr;

			(*pskb)->nfcache |= NFC_UNKNOWN;	/* again, not sure whether should do it */
			(*pskb)->nfcache |= NFC_ALTERED;
            (*pskb)->nfcache |= NFC_IP_SRC;
        }
    }

    return NF_ACCEPT;
}


static unsigned int
ip_nat_local_fn(unsigned int hooknum,
        struct sk_buff **pskb,
        const struct net_device *in,
        const struct net_device *out,
        int (*okfn)(struct sk_buff *))
{
	return NF_ACCEPT;
}

// = { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_NAT_DST };

/* Before packet filtering, change destination */
static struct nf_hook_ops ip_nat_in_ops
= { { NULL, NULL }, ip_nat_fn, PF_INET, NF_IP_PRE_ROUTING, NF_IP_PRI_NAT_DST-1};
/* After packet filtering, change source */
static struct nf_hook_ops ip_nat_out_ops
= { { NULL, NULL }, ip_nat_out, PF_INET, NF_IP_POST_ROUTING, NF_IP_PRI_NAT_SRC-1};
/* Before packet filtering, change destination */
static struct nf_hook_ops ip_nat_local_out_ops
= { { NULL, NULL }, ip_nat_local_fn, PF_INET, NF_IP_LOCAL_OUT, NF_IP_PRI_NAT_DST-1 };


/* Initialize the module */
int init_module()
{

  /* If we return a non zero value, it means that 
   * init_module failed and the kernel module 
   * can't be loaded */

    int ret = 0;

  	printk("Hello, world - this is the little netfilter module\n");

    ret = nf_register_hook(&ip_nat_in_ops);
    if (ret < 0) 
	{
        printk("ip_nat_init: can't register in hook.\n");

		// MUST_BE_READ_WRITE_UNLOCKED(&ip_nat_lock);
		return ret;
    }

    ret = nf_register_hook(&ip_nat_out_ops);
    if (ret < 0) 
	{
        printk("ip_nat_init: can't register out hook.\n");
		return ret;
    }

    ret = nf_register_hook(&ip_nat_local_out_ops);
    if (ret < 0) 
	{
        printk("ip_nat_init: can't register local out hook.\n");
		return ret;
    }

    return ret;


  return 0;
}


/* Cleanup - undid whatever init_module did */
void cleanup_module()
{
  	printk("Short is the life of a kernel module\n");

	nf_unregister_hook(&ip_nat_in_ops);
	nf_unregister_hook(&ip_nat_out_ops);
	nf_unregister_hook(&ip_nat_local_out_ops);
}


[-- Attachment #3: Makefile --]
[-- Type: application/octet-stream, Size: 373 bytes --]

# Makefile for a basic kernel module

CC=gcc
MODCFLAGS := -I/usr/src/linux/include -Wall -DMODULE -D__KERNEL__ -DLINUX

hello.o:	hello.c /usr/include/linux/version.h
		$(CC) $(MODCFLAGS) -c hello.c

#		echo insmod hello.o to turn it on
#		echo rmmod hello to turn if off
#		echo
#		echo X and kernel programming do not mix.
#		echo Do the insmod and rmmod from outside X.


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2002-09-20 20:29 UTC | newest]

Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2002-09-20 20:29 Failing to manipulate IP headers Chen Ding

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox