Linux Netfilter挂载钩子发送简单的UDP报文

匿名 (未验证) 提交于 2019-12-02 21:53:52

1、思路

分配空间--->填充udp、ip、ethernet报文头以及发送数据--->发送构造完成的报文

2、需要明白的接口

alloc_skb 分配skb空间

skb_reserve 在skb头部预留(将数据指针与skb尾指针后移)

skb_push 向前移动数据头指针(skb_reserve为这个操作预留空间)

skb_reset_transport_header 重置传输层报文头指针(存在偏移与不偏移两种方式)

skb_set_transport_header 重置并设置传输层报文头指针

skb_reset_network_header 重置ip层报文头指针

skb_reset_mac_header 重置链路层报文头指针

3、udp发送报文接口实现

#define ICMP 1 #define ETH "eth0" #define S_PORT 9988 #define D_PORT 8899 u_long S_IP = 0xC0A8034D; //"192.168.3.77" u_long D_IP = 0xC0A80305; //"192.168.3.5" unsigned char S_MAC[ETH_ALEN]={0x00,0x0c,0x29,0x41,0x3e,0x66};/*本地mac地址*/ unsigned char D_MAC[ETH_ALEN]={0x14,0xa5,0x1a,0xba,0xf1,0x04};/*网关mac地址*/  static int my_diyudp_and_send(char *eth, u_char *smac, u_char *dmac,             u_char *pkt, int pkt_len,u_long sip, u_long dip, u_short sport, u_short dport) {     int ret = -1;     unsigned int pktSize;     struct sk_buff *skb = NULL;     struct net_device *dev = NULL;     struct ethhdr *ethheader = NULL;     struct iphdr *ipheader = NULL;     struct udphdr *udpheader = NULL;     u_char *pdata = NULL;      /*参数合法性检查*/     if(NULL == smac || NULL == dmac)         goto out;      /*通过出口接口名称获取接口设备信息*/     dev = dev_get_by_name(&init_net, eth);     if(NULL == dev)     {         printk(KERN_ERR "unknow device name:%s\n", eth);         goto out;     }      /*计算报文长度*/     pktSize = pkt_len + sizeof(struct iphdr) + sizeof(struct udphdr) + LL_RESERVED_SPACE(dev);     skb = alloc_skb(pktSize, GFP_ATOMIC);     if(NULL == skb)     {         printk(KERN_ERR "malloc skb fail\n");         goto out;     }          /*在头部预留需要的空间*/      skb_reserve (skb, pktSize);      skb->dev = dev;     skb->pkt_type = PACKET_OTHERHOST;     skb->protocol = __constant_htons(ETH_P_IP);     skb->ip_summed = CHECKSUM_NONE;//udp校验和初始化     skb->priority = 0;      pdata = skb_push(skb, pkt_len);     if(NULL != pkt)         memcpy(pdata, pkt, pkt_len);      /*填充udp头部*/     udpheader = (struct udphdr*)skb_push(skb, sizeof(struct udphdr));     memset(udpheader, 0, sizeof(struct udphdr));     udpheader->source = htons(sport);     udpheader->dest = htons(dport);     skb->csum = 0;     udpheader->len = htons(sizeof(struct udphdr) + pkt_len);     udpheader->check = 0;     skb_reset_transport_header(skb);      /*填充IP头*/     ipheader = (struct iphdr*)skb_push(skb, sizeof(struct iphdr));     ipheader->version = 4;     ipheader->ihl = sizeof(struct iphdr) >> 2;//ip头部长度     ipheader->frag_off = 0;     ipheader->protocol = IPPROTO_UDP;     ipheader->tos = 0;     ipheader->saddr = htonl(sip);     ipheader->daddr = htonl(dip);     ipheader->ttl = 0x40;     ipheader->tot_len = htons(pkt_len + sizeof(struct iphdr) + sizeof(struct udphdr));     ipheader->check = 0;     ipheader->check = ip_fast_csum((unsigned char *)ipheader, ipheader->ihl);     skb_reset_network_header(skb);          skb->csum = skb_checksum(skb, ipheader->ihl*4, skb->len-ipheader->ihl*4, 0);     udpheader->check = csum_tcpudp_magic(sip, dip, skb->len-ipheader->ihl*4, IPPROTO_UDP, skb->csum);      /*填充MAC*/     ethheader = (struct ethhdr*)skb_push(skb, 14);     memcpy(ethheader->h_dest, dmac, ETH_ALEN);     memcpy(ethheader->h_source, smac, ETH_ALEN);     ethheader->h_proto = __constant_htons(ETH_P_IP);     skb_reset_mac_header(skb);          /*send pkt         dev_queue_xmit发送之后会释放相应的空间。         因此注意不能做重复释放     */     if(0 > dev_queue_xmit(skb))     {         printk(KERN_ERR "send pkt error");         goto out;     }     ret = 0;          printk(KERN_INFO "send success\n"); out:     if(ret != 0 && NULL != skb)     {         dev_put(dev);         kfree_skb(skb);     }     return NF_ACCEPT; }

4、需要注意

1)对报文头中的2字节、4字节等字段需要进行主机序转网络序的转换

2)调用构造报文函数的位置(在最开始实践的时候由于把所有包都丢弃,然后发送udp,导致ssh也不能登录)

5、函数调用

static unsigned int my_hook_test(unsigned int hooknum, struct sk_buff *skb,      const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) {     const struct iphdr *iph = ip_hdr(skb);     //filter icmp         if(iph->protocol == ICMP)     {         printk(KERN_INFO "recv pkt(%u):protocol:%u, Src:%u.%u.%u.%u, Dst:%u.%u.%u.%u\n",             pktcnt, iph->protocol, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));         my_diyudp_and_send(ETH, S_MAC, D_MAC, "Hello From Slackware", strlen("Hello From Slackware"), S_IP, D_IP, S_PORT, D_PORT);         return NF_DROP;     }      return NF_ACCEPT; }  //挂载钩子,挂在出口处理的位置 static struct nf_hook_ops nfhello = {         .hook = my_hook_test,         .owner = THIS_MODULE,         .pf = PF_INET,         .hooknum = NF_INET_LOCAL_OUT,//挂载在出口处理报文的节点         .priority = NF_IP_PRI_FIRST,//最高优先级 };  static int my_netfilter_init(void) {     printk(KERN_INFO "init my nodule\n");     /*注册钩子*/     nf_register_hook(&nfhello);      return 0; }  static void my_netfilter_exit(void) {     printk(KERN_INFO "Goodbye my module\n");     /*卸载钩子*/     nf_unregister_hook(&nfhello); }  module_init(my_netfilter_init); module_exit(my_netfilter_exit);  MODULE_LICENSE("GPL"); MODULE_AUTHOR("Zhaojie");  MODULE_DESCRIPTION("Hello netfilter");

6、运行结果

原文:https://www.cnblogs.com/linuxroute/p/9386480.html

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!