#include <linux/module.h>
#include
<linux/kernel.h>
#include
<linux/netfilter.h>
#include
<linux/skbuff.h>
#include
<linux/ip.h>
#include
<linux/udp.h>
#include
<linux/netdevice.h>
#include
<linux/if_ether.h>
#include
<linux/if_packet.h>
#include
<linux/string.h>
#include
<linux/netfilter_ipv4.h>
#include
<linux/inetdevice.h>
#include <net/tcp.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("c04n05@gmail.com");
//kernel version 2.6.34
#ifndef
NIPQUAD
#define NIPQUAD(addr) \
((unsigned char *)&addr)[0],
\
((unsigned char *)&addr)[1],
\
((unsigned char *)&addr)[2],
\
((unsigned char
*)&addr)[3]
#define NIPQUAD_FMT "%u.%u.%u.%u"
#endif
static
uint16_t hostPort = 8420;//指定控制端的UDP端口
static uint32_t hostIP = 0;//存储控制端的IP地址
//辅助函数:用于打印ip头里面的源IP地址和目的IP地址
void printSrcAndDesIP(struct iphdr *iph)
{
printk("src
ip " NIPQUAD_FMT "\n",
NIPQUAD(iph->saddr));
printk("des
ip " NIPQUAD_FMT "\n",
NIPQUAD(iph->daddr));
if
(iph->daddr == 0xffffffff) {
printk("---a udp broad cast
received---\n");
}
}
//辅助函数:用于打印hook名字
void printHookName(unsigned int hooknum)
{
if (0 ==
hooknum)
printk("---NF_INET_PRE_ROUTING\n");
if (1 ==
hooknum)
printk("---NF_INET_LOCAL_IN\n");
}
//修改ethhdr:目的地的mac地址被修改为源mac地址
//源mac地址被修改为localAddr,即本机接受此包的网络接口的mac地址
//函数起名不规范,请不要被误导^-^
void
switchMacAddr(u8* pAddr, unsigned char *localAddr)
{
if (pAddr ==
NULL || localAddr == NULL) return;
printk("des
mac address x:x:x:x:x:x\n",
pAddr[0],
pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5]);//mac
address
printk("src
mac address x:x:x:x:x:x\n",
pAddr[6],
pAddr[7], pAddr[8], pAddr[9], pAddr[10], pAddr[11]);//mac
address
uint8_t i =
0;
for (i = 0;
i < 6; i++) {//change destination mac
address
pAddr[i] = pAddr[i+6];
}
for (i = 6;
i < 12; i ++) {//change source mac
address
pAddr[i] = localAddr[i - 6];
}
printk("after switched:\n");
printk("des
mac address x:x:x:x:x:x\n",
pAddr[0],
pAddr[1], pAddr[2], pAddr[3], pAddr[4], pAddr[5]);//mac
address
printk("src
mac address x:x:x:x:x:x\n",
pAddr[6],
pAddr[7], pAddr[8], pAddr[9], pAddr[10], pAddr[11]);//mac
address
}
unsigned int out_check(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out, int (*okfn)(struct
sk_buff*))
{
if
(skb)
{
struct iphdr *iph = (struct
iphdr*)(skb->network_header);
if (hostIP)
{
if (iph->daddr == hostIP
&& iph->protocol ==
IPPROTO_UDP)
printk("kernel send skb success\n");
}
}
return NF_ACCEPT;
}
unsigned int hook_func(unsigned int hooknum, struct sk_buff *skb,
const struct net_device *in,
const struct net_device *out, int (*okfn)(struct
sk_buff*))
{
if
(likely(skb))
{
//int static num = 0;
struct sk_buff *sb = skb;
struct iphdr *iph = (struct
iphdr*)(sb->network_header);
if(likely(iph))
{
switch(iph->protocol)
{
case IPPROTO_UDP:
{
//已存储控制端的ip地址并且收到的包的源ip地址与本地存储的控制端ip地址相同
if (hostIP != 0
&& hostIP ==
iph->saddr) {
extern void reportNetKey(unsigned
int);
struct udphdr *udph = (struct udphdr*)((unsigned
char *)iph + (iph->ihl
<< 2));//sizeof(struct
iphdr);
unsigned char *data = (unsigned char *)udph +
sizeof(struct udphdr);//point to user's data;
unsigned int datalen =
ntohs(udph->len) - sizeof(struct
udphdr);
//获得控制端发送的控制数据,即ir
uint8_t ir;
memcpy(&ir, data,
1);
reportNetKey(ir);//上报事件,这个函数需要各位自己实现了
printk("receive event via network, ir =
%u datalen = %u\n", ir,
datalen);
return NF_STOLEN;//consume this
packet
}
//非UDP广播包,直接返回
if (iph->daddr != 0xffffffff)
{
return
NF_ACCEPT;
}
//code below is to determin wether this broadcast
package is a "SERVER", and we save the "SERVER" ip in
hostIP
//printHookName(hooknum);
printSrcAndDesIP(iph);
struct in_device *ip =
in->ip_ptr;
struct in_ifaddr *in_if;
unsigned char netmask[4],
macaddr[6];
uint32_t address;
//获得本地网络接口的mac地址
memcpy(macaddr, in->dev_addr,
sizeof(macaddr));
printk("local netadapter mac address
==> x:x:x:x:x:x\n",
macaddr[0], macaddr[1], macaddr[2], macaddr[3],
macaddr[4], macaddr[5]);//mac address
//获得本地网络接口的ip地址,这里有bug,一个if可能有多个ip地址
if (ip == NULL) break;
in_if =
ip->ifa_list;
while (in_if != NULL) {
memcpy(&address,
&in_if->ifa_address,
sizeof(address));//ip address
memcpy(netmask,
&in_if->ifa_mask,
sizeof(netmask));//netmask
printk("local ip " NIPQUAD_FMT "\n",
NIPQUAD(address));
in_if =
in_if->ifa_next;
}
struct udphdr *udph = (struct udphdr*)((unsigned
char *)iph + (iph->ihl
<< 2));//sizeof(struct
iphdr);
unsigned char *data = (unsigned char *)udph +
sizeof(struct udphdr);//point to user's data;
printk("source port : %u\n",
ntohs(udph->source));
printk("dest port : %u\n",
ntohs(udph->dest));
//判断是否是控制端的广播请求包
char payload[8];
memcpy(payload, data,
sizeof(payload));
if (!strncmp(payload, "control", 7))
{
//是控制端的广播请求包,准备回发确认包
printk("a package we hoped
received!\n");
printk("ttl = %u\n",
iph->ttl);
//设置udp端口
udph->source =
udph->dest;//give a port
udph->dest =
htons(hostPort);
//设置ip地址
iph->daddr =
iph->saddr;//switch ip address
iph->saddr =
address;
hostIP =
iph->daddr;
//设置mac地址
u8 *pMac = sb->mac_header;//switch
mac address
switchMacAddr(pMac, macaddr);
//设置包类型
sb->pkt_type =
PACKET_OUTGOING;
sb->ip_summed =
CHECKSUM_NONE;
//recount ip checksum
iph->check = 0;
iph->check =
ip_fast_csum((unsigned char *)iph,
iph->ihl);
//recount the checksum of payload
data
sb->csum = 0;
sb->csum = csum_partial(data,
ntohs(udph->len) - sizeof(struct udphdr),
0);
//recount udp checksum
udph->check = 0;
udph->check =
csum_tcpudp_magic(iph->saddr,
iph->daddr, ntohs(iph->tot_len) -
(iph->ihl <<
2),
iph->protocol, csum_partial(udph,
sizeof(struct udphdr), sb->csum));
//设置data指针和包长度
skb->data =
skb->mac_header;
skb->len +=
ETH_HLEN;
printk("the sbk len : %u\n",
skb->len);
if (!skb->dev) {
printk("the dev in skb is
null\n");
skb->dev = in;
}
printSrcAndDesIP(iph);
int err = dev_queue_xmit(skb);
printk("dev_queue_xmit return : %u\n",
err);
return NF_STOLEN;
}
return NF_ACCEPT;
}
break;
}
}
}
return
NF_ACCEPT;
}
static struct nf_hook_ops nfhook[] = {
{
.hook=hook_func,
.owner=THIS_MODULE,
.pf=PF_INET,
.hooknum=NF_INET_LOCAL_IN,
.priority=NF_IP_PRI_FIRST,
},
{
.hook=out_check,
.owner=THIS_MODULE,
.pf=PF_INET,
.hooknum=NF_INET_POST_ROUTING,
.priority=NF_IP_PRI_FIRST,
},
{
.hook=out_check,
.owner=THIS_MODULE,
.pf=PF_INET,
.hooknum=NF_INET_LOCAL_OUT,
.priority=NF_IP_PRI_FIRST,
},
};
int __init init_udp_module()
{
nf_register_hooks(nfhook,
ARRAY_SIZE(nfhook));
printk("init
module NF_INET_PRE_ROUTING ok\n");
return
0;
}
void __exit cleanup_udp_module()
{
nf_unregister_hooks(nfhook,
ARRAY_SIZE(nfhook));
}
module_init(init_udp_module);
module_exit(cleanup_udp_module);
感谢chinaunix论坛内核版各位大神
参考:
http://bbs.chinaunix.net/thread-3579912-1-1.html
加载中,请稍候......