分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 前端开发

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

发布时间:2023-09-06 02:06责任编辑:彭小芳关键词:Linux

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 8899u_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、运行结果

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

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

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved