当前位置: 技术问答>linux和unix
关于网卡转发问题的程序
来源: 互联网 发布时间:2016-05-08
本文导语: 我要利用linux内核里的Netfilter框架实现网卡转发,就是数据从一个网口eth1进,从另一网口eth2发出去,是自己写,不用网桥实现。 首先,我将两个网卡设为混沌模式(使用指令 ifconfig eth1/eth2 prom...
我要利用linux内核里的Netfilter框架实现网卡转发,就是数据从一个网口eth1进,从另一网口eth2发出去,是自己写,不用网桥实现。
首先,我将两个网卡设为混沌模式(使用指令 ifconfig eth1/eth2 promics后, 运行ifconfig这条指令,eth1/eth2 有promisc这个属性,不知道这算不算设置起,如何测试),然后运行了两个自己写的转发模块。连接eth2网口的主机ping 另一台间接与eth1连接的主机,arp请求转发出去eth2->eth1,但arp应答包到达eth1口(不知道eth1是否接收),没有转发到eth2。我的转发程序如下:
//转发arp包
#ifndef MODULE
#define MODULE
#endif
#ifndef __KERNEL__
#define __KERNEL__
#endif
#include
#include
#include
#include
#include
#include
#include
#include
static unsigned int watch_arp(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct sk_buff *sb = *skb;
struct sk_buff *sb_new = NULL;
unsigned int result=NF_STOLEN;
unsigned long long t1, t2;
int n=1;
__asm__ volatile ("rdtsc":"=A"(t1));
switch (sb->dev->type)
{
case ARPHRD_PPP:
return result;
case ARPHRD_LOOPBACK:
case ARPHRD_ETHER:
{
int i;
printk("phisical address isn");
for (i=0; imac.raw[i]);
printk("protocol is %xn",ntohs (sb->protocol));
sb_new = skb_clone(sb, GFP_ATOMIC);
printk("this packet comes from %sn ", sb->dev->name);
printk("this new packet comes from %sn", sb_new->dev->name);
if (!strncmp(sb_new->dev->name, "eth0", 4))
return NF_ACCEPT;
else if(!strncmp(sb_new->dev->name, "eth1", 4))
{
sb_new->dev = dev_get_by_name("eth2");
printk("Now, go by %sn",sb_new->dev->name);
}
else
{
sb_new->dev = dev_get_by_name("eth1");
printk("Now, go by %sn",sb_new->dev->name);
}
break;
}
}
sb_new->pkt_type = PACKET_OUTGOING;
printk("the priority of this packet is %dn", ntohs(sb_new->priority));
skb_push(sb_new,ETH_HLEN);
n = dev_queue_xmit(sb_new);
if (n dev);
__asm__ volatile ("rdtsc":"=A"(t2));
printk("elapsed: %llun", t2 - t1);
return result;
}
int init_module()
{
printk("ok, starting...n");
arp_hook.hook = watch_arp;
arp_hook.pf = NF_ARP;
arp_hook.priority = NF_IP_PRI_FIRST;
arp_hook.hooknum = NF_ARP_IN;
nf_register_hook(&arp_hook);
printk("ok, starting...n");
return 0;
}
void cleanup_module()
{
nf_unregister_hook(&arp_hook);
}
//转发ip包
#ifndef MODULE
#define MODULE
#endif
#ifndef __KERNEL__
#define __KERNEL__
#endif
#include
#include
#include
#include
#include
#include
#include
#include
struct nf_hook_ops ip_hook;
// struct nf_hook_ops arp_hook;
static unsigned int watch_ip(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct sk_buff *sb = *skb;
struct sk_buff *sb_new = NULL;
unsigned int result=NF_STOLEN;
unsigned long long t1, t2;
int n=1;
__asm__ volatile ("rdtsc":"=A"(t1));
switch (sb->dev->type)
{
case ARPHRD_PPP:
return result;
case ARPHRD_LOOPBACK:
case ARPHRD_ETHER:
{
int i;
printk("phisical address isn");
for (i=0; imac.raw[i]);
printk("protocol is %xn", ntohs(sb->protocol));
printk("this packet comes from %sn", sb->dev->name);
// printk("this new packet comes from %sn", sb_new->dev->name);
if (!strncmp(sb->dev->name, "eth0", 4))
return NF_ACCEPT;
else if (!strncmp(sb->dev->name, "eth1", 4))
{
sb_new = skb_clone(sb,GFP_ATOMIC);
sb_new->dev = dev_get_by_name("eth2");
printk("Now, go by %sn ",sb_new->dev->name);
}
else
{
sb_new = skb_clone(sb,GFP_ATOMIC);
sb_new->dev = dev_get_by_name("eth1");
printk("Now, go by %sn",sb_new->dev->name);
}
break;
}
}
sb_new->pkt_type = PACKET_OUTGOING;
printk("priority of this packet is %dn ", ntohs(sb_new->priority));
skb_push(sb_new,ETH_HLEN);
n = dev_queue_xmit(sb_new);
if (n dev);
__asm__ volatile ("rdtsc":"=A"(t2));
printk("elapsed: %llun", t2 - t1);
return result;
}
int init_module()
{
printk("ok, starting...n");
ip_hook.hook = watch_ip;
ip_hook.pf = PF_INET;
ip_hook.priority = NF_IP_PRI_FIRST;
ip_hook.hooknum = NF_IP_PRE_ROUTING;
/* arp_hook.hook = watch_arp;
arp_hook.pf = NF_ARP;
arp_hook.priority = NF_IP_PRI_FIRST;
arp_hook.hooknum = NF_ARP_IN;*/
nf_register_hook(&ip_hook);
/* nf_register_hook(&arp_hook);*/
printk("ok, starting...n");
return 0;
}
void cleanup_module()
{
nf_unregister_hook(&ip_hook);
/* nf_unregister_hook(&arp_hook);*/
}
我不知道dev_put是否需要用,请个位大侠帮我看看问题出在哪?
首先,我将两个网卡设为混沌模式(使用指令 ifconfig eth1/eth2 promics后, 运行ifconfig这条指令,eth1/eth2 有promisc这个属性,不知道这算不算设置起,如何测试),然后运行了两个自己写的转发模块。连接eth2网口的主机ping 另一台间接与eth1连接的主机,arp请求转发出去eth2->eth1,但arp应答包到达eth1口(不知道eth1是否接收),没有转发到eth2。我的转发程序如下:
//转发arp包
#ifndef MODULE
#define MODULE
#endif
#ifndef __KERNEL__
#define __KERNEL__
#endif
#include
#include
#include
#include
#include
#include
#include
#include
static unsigned int watch_arp(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct sk_buff *sb = *skb;
struct sk_buff *sb_new = NULL;
unsigned int result=NF_STOLEN;
unsigned long long t1, t2;
int n=1;
__asm__ volatile ("rdtsc":"=A"(t1));
switch (sb->dev->type)
{
case ARPHRD_PPP:
return result;
case ARPHRD_LOOPBACK:
case ARPHRD_ETHER:
{
int i;
printk("phisical address isn");
for (i=0; imac.raw[i]);
printk("protocol is %xn",ntohs (sb->protocol));
sb_new = skb_clone(sb, GFP_ATOMIC);
printk("this packet comes from %sn ", sb->dev->name);
printk("this new packet comes from %sn", sb_new->dev->name);
if (!strncmp(sb_new->dev->name, "eth0", 4))
return NF_ACCEPT;
else if(!strncmp(sb_new->dev->name, "eth1", 4))
{
sb_new->dev = dev_get_by_name("eth2");
printk("Now, go by %sn",sb_new->dev->name);
}
else
{
sb_new->dev = dev_get_by_name("eth1");
printk("Now, go by %sn",sb_new->dev->name);
}
break;
}
}
sb_new->pkt_type = PACKET_OUTGOING;
printk("the priority of this packet is %dn", ntohs(sb_new->priority));
skb_push(sb_new,ETH_HLEN);
n = dev_queue_xmit(sb_new);
if (n dev);
__asm__ volatile ("rdtsc":"=A"(t2));
printk("elapsed: %llun", t2 - t1);
return result;
}
int init_module()
{
printk("ok, starting...n");
arp_hook.hook = watch_arp;
arp_hook.pf = NF_ARP;
arp_hook.priority = NF_IP_PRI_FIRST;
arp_hook.hooknum = NF_ARP_IN;
nf_register_hook(&arp_hook);
printk("ok, starting...n");
return 0;
}
void cleanup_module()
{
nf_unregister_hook(&arp_hook);
}
//转发ip包
#ifndef MODULE
#define MODULE
#endif
#ifndef __KERNEL__
#define __KERNEL__
#endif
#include
#include
#include
#include
#include
#include
#include
#include
struct nf_hook_ops ip_hook;
// struct nf_hook_ops arp_hook;
static unsigned int watch_ip(unsigned int hooknum,
struct sk_buff **skb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
struct sk_buff *sb = *skb;
struct sk_buff *sb_new = NULL;
unsigned int result=NF_STOLEN;
unsigned long long t1, t2;
int n=1;
__asm__ volatile ("rdtsc":"=A"(t1));
switch (sb->dev->type)
{
case ARPHRD_PPP:
return result;
case ARPHRD_LOOPBACK:
case ARPHRD_ETHER:
{
int i;
printk("phisical address isn");
for (i=0; imac.raw[i]);
printk("protocol is %xn", ntohs(sb->protocol));
printk("this packet comes from %sn", sb->dev->name);
// printk("this new packet comes from %sn", sb_new->dev->name);
if (!strncmp(sb->dev->name, "eth0", 4))
return NF_ACCEPT;
else if (!strncmp(sb->dev->name, "eth1", 4))
{
sb_new = skb_clone(sb,GFP_ATOMIC);
sb_new->dev = dev_get_by_name("eth2");
printk("Now, go by %sn ",sb_new->dev->name);
}
else
{
sb_new = skb_clone(sb,GFP_ATOMIC);
sb_new->dev = dev_get_by_name("eth1");
printk("Now, go by %sn",sb_new->dev->name);
}
break;
}
}
sb_new->pkt_type = PACKET_OUTGOING;
printk("priority of this packet is %dn ", ntohs(sb_new->priority));
skb_push(sb_new,ETH_HLEN);
n = dev_queue_xmit(sb_new);
if (n dev);
__asm__ volatile ("rdtsc":"=A"(t2));
printk("elapsed: %llun", t2 - t1);
return result;
}
int init_module()
{
printk("ok, starting...n");
ip_hook.hook = watch_ip;
ip_hook.pf = PF_INET;
ip_hook.priority = NF_IP_PRI_FIRST;
ip_hook.hooknum = NF_IP_PRE_ROUTING;
/* arp_hook.hook = watch_arp;
arp_hook.pf = NF_ARP;
arp_hook.priority = NF_IP_PRI_FIRST;
arp_hook.hooknum = NF_ARP_IN;*/
nf_register_hook(&ip_hook);
/* nf_register_hook(&arp_hook);*/
printk("ok, starting...n");
return 0;
}
void cleanup_module()
{
nf_unregister_hook(&ip_hook);
/* nf_unregister_hook(&arp_hook);*/
}
我不知道dev_put是否需要用,请个位大侠帮我看看问题出在哪?
|
我看了一下你的源程序,想问一下,你返回NF_STOLEN却没看到对原来的skb做什么处理,这样内存没问题吗
|
dev_put 用的是对的, 在每一次dev_get_by_name 引用net_device 完毕后, 都需要调用 dev_put
|
看了一下, 基本思路是对的, 不过在处理ARP方面我觉得应该是有问题的, 就算ARP能成功回复, 但再以后的IP数据层可能会遇到一些问题。
建议你在转发的时候从那个口出去的,源MAC应该为这个口的MAC地址。
不知道你要实现这个功能的目的, 是透明桥?eth1 and eth2是否有IP地址?
建议你在转发的时候从那个口出去的,源MAC应该为这个口的MAC地址。
不知道你要实现这个功能的目的, 是透明桥?eth1 and eth2是否有IP地址?