加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

【转】Linux netfilter udp skb修改实例(1)

(2012-06-19 18:18:07)
标签:

ip

mac

it

 

#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

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有