Changing MAC address for forwarding a pacjet with ebtables

"Mark Ryden" <[email protected]>
Newsgroups gmane.linux.network.bridge.ebtables.devel
Message-ID <[email protected]>
Hello,
I am writing a kernel module which changes the MAC address of a received UDP
packet so that it will be of a different machine on the same LAN and
so that the
packet will be forwarded to that machine.
Namely, I am trying to do fowarding in layer 2 using ebtables hook.

I am catching the packet with NF_BR_PRE_ROUTING ebtable hook.
In this hook, I am changing its MAC address to 00:11:2F:93:E0:52 ;
this is the MAC
address of another machine which is on the same LAN  (my ARP table
knows this MAC).

The code is below; it is short; (only 100 lines). If someone can
take a look at it and give some advice it will be more than welcomed.

I saw a posting in this mailing list a few days ago in which
somebody tried also to adjust a MAC address and it was suggested that
he should follow ebt_snat.c; so this is what I did.

see:
http://sourceforge.net/mailarchive/forum.php?thread_name=6.1.2.0.2.20050218133252.04555610%40luna.tlmat.unican.es&forum_name=ebtables-devel

More details:
When running the module and sending UDP packets on port 5555, I
see that I get the packets in the module;
Moreover, I see that the following if statement is valid:
if (skb_shared(*pskb) || skb_cloned(*pskb)) ..

However, when I put a sniffer on that machine or the second machine I
**don't** see that a packet is sent to the second machine,
namely to 00:11:2F:93:E0:52.

What is missing here ? should I add some ebtable forwarding hook?

BTW, on my machine, there is a bridge defined thus (as far as I know,this
should be ok):
ifconfig eth0 0.0.0.0
brctl addbr mybr
brctl addif mybr eth0
ifconfig mybr up
ifconfig mybr 192.168.0.45 netmask 255.255.255.0

Below is the code:

// ebtable.c

#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kmod.h>
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/kernel.h>
#include <linux/inet.h>
#include <linux/udp.h>
#include <linux/netdevice.h>
#include <linux/time.h>
#include <linux/netfilter_ipv4/ip_nat.h>
#include <net/ip.h>
#include <net/checksum.h>
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_nat.h>
#include <linux/netfilter_bridge.h>

static unsigned short ethpip;

static struct nf_hook_ops netfilter_ops_in;

unsigned int main_hook(unsigned int hooknum,
                      struct sk_buff** pskb,
                      const struct net_device* in,
                      const struct net_device* out,
                      int (*okfn)(struct sk_buff*))
{
	static int counter;
	struct sk_buff *nskb;
	unsigned char *data;
	int i;
	counter++;
	if(	(*pskb)->protocol == ethpip &&	(*pskb)->nh.iph->protocol == IPPROTO_UDP)
		{
		struct udphdr *udp_header = (struct udphdr *)((*pskb)->data +
((*pskb)->nh.iph->ihl *4));
		int port = ntohs(udp_header->dest);
		if (port == 5555)
			{
			char a[] = { 0x00, 0x11, 0x2F, 0x93, 0xE0, 0x52 };
			printk("changing IP dst address in %s\n", __FUNCTION__);
		  if (skb_shared(*pskb) || skb_cloned(*pskb)) {
		    struct sk_buff *nskb;
		    // printk("in if if (skb_shared(*pskb) || skb_cloned(*pskb)) \n");
		
		    nskb = skb_copy(*pskb, GFP_ATOMIC);
		    if (!nskb)
			    return NF_DROP;
		    if ((*pskb)->sk)
			    skb_set_owner_w(nskb, (*pskb)->sk);
		    kfree_skb(*pskb);
		    *pskb = nskb;
	    }
	   memcpy(eth_hdr(*pskb)->h_dest, a, ETH_ALEN);
		 }// of if port = 5555
	 }
	return NF_ACCEPT;

}

static int __init ebtable_init(void)
 {
	 int ret;
	 ethpip = htons(ETH_P_IP);
	
	 netfilter_ops_in.hook     = main_hook;
	 netfilter_ops_in.owner		 = THIS_MODULE,
	 netfilter_ops_in.pf       = PF_BRIDGE;
	 netfilter_ops_in.hooknum  = NF_BR_PRE_ROUTING;
	 netfilter_ops_in.priority = NF_BR_PRI_FILTER_BRIDGED;
	 ret = nf_register_hook(&netfilter_ops_in);
	 if (ret < 0)
	 	{
 	  nf_unregister_hook(&netfilter_ops_in);
		return -1;
		}
	 return 0;
 }

 static void __exit ebtable_exit(void)
 {
	 nf_unregister_hook(&netfilter_ops_in);
 }

 module_init(ebtable_init)
 module_exit(ebtable_exit)

 MODULE_AUTHOR("MarkRyde");
 MODULE_DESCRIPTION("ebtables changing mac address");
 MODULE_LICENSE("GPL");

Regards,
Mark

-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.