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
时间: 2024-10-13 21:58:19