使用 netfilter 处理IPv6报文
生活随笔
收集整理的這篇文章主要介紹了
使用 netfilter 处理IPv6报文
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
? ????? netfilter對IPv6的處理和IPv4流程類似,只有鉤子函數(shù)注冊協(xié)議不同,優(yōu)先級和注冊的鏈都是一樣的。
{.hook=nf_input_hook_v4,.pf=NFPROTO_IPV4, //IPv4協(xié)議.hooknum=NF_INET_POST_ROUTING,.priority=0,}, {.hook=nf_input_hook_v6,.pf=NFPROTO_IPV6, //IPv6協(xié)議.hooknum=NF_INET_PRE_ROUTING,.priority=NF_IP_PRI_FIRST,},下面是一個(gè)netfilter ipv6小栗子,對本機(jī)出去的IPv6 UDP報(bào)文做了端口變換處理,介紹一下IPv6地址操作、IPv6報(bào)文udp校驗(yàn)值計(jì)算等等。
內(nèi)核版本: 3.4.39
/** Netfilter IPv6 Demo, NAT* Autor : Mason* Date : 20180731*/#include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/socket.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> #include <linux/in.h> #include <linux/if_ether.h> #include <linux/ip.h> #include <net/ip.h> #include <net/dsfield.h> #include <linux/skbuff.h> #include <linux/inet.h> #include <linux/netdevice.h> #include <net/route.h> #include "nfdemov6.h"/* IPv6輸入報(bào)文處理函數(shù) */ static unsigned int nfdemo_input_hook_v6(unsigned int hooknum,struct sk_buff *skb,const struct net_device *in,const struct net_device *out,int (*okfn)(struct sk_buff *)) { /* do something */return NF_ACCEPT; }/* IPv6輸出報(bào)文處理函數(shù),這里對IPv6 UDP報(bào)文做了源端口變換 */ static unsigned int nfdemo_output_hook_v6(unsigned int hooknum,struct sk_buff *skb,const struct net_device *in,const struct net_device *out,int (*okfn)(struct sk_buff *)) { struct ipv6hdr *iph6;struct udphdr *udph; unsigned int udp_len;/* 獲取IPv6首部指針 */iph6 = ipv6_hdr(skb);if (!iph6)return NF_ACCEPT;/* 過濾 ::/128 空類型地址 */if (ipv6_addr_any(&iph6->saddr) || ipv6_addr_any(&iph6->daddr))return NF_ACCEPT;/* 過濾源地址和目的地址相等的報(bào)文 */if (ipv6_addr_equal(&iph6->saddr, &iph6->daddr))return NF_ACCEPT;/* 過濾環(huán)回地址報(bào)文 ::1/128 */if (ipv6_addr_loopback(&iph6->saddr) || ipv6_addr_loopback(&iph6->daddr)) return NF_ACCEPT;/* 只處理UDP報(bào)文 */ if (iph6->nexthdr != NEXTHDR_UDP)return NF_ACCEPT;/* 設(shè)置傳輸層首部 */skb_set_transport_header(skb, sizeof(struct ipv6hdr));/* 獲取UDP首部 */udph = udp_hdr(skb);if (!udph )return NF_ACCEPT;/* 更改端口 */ udph->source = htons(6666); /* 重新計(jì)算校驗(yàn)和 * IPv6校驗(yàn)和計(jì)算使用 csum_ipv6_magic() 接口* IPv4校驗(yàn)和計(jì)算使用 csum_tcpudp_magic() 接口*/ udph->check = 0; udp_len = ntohs(udph->len); skb->csum = csum_partial(skb_transport_header(skb), udp_len, 0);udph->check = csum_ipv6_magic(&iph6->saddr, &iph6->daddr, udp_len, IPPROTO_UDP, skb->csum); skb->ip_summed = CHECKSUM_NONE;/* 如果udp首部校驗(yàn)和為0,替換成CSUM_MANGLED_0 */if (0 == udph->check)udph->check = CSUM_MANGLED_0;/* 替換完成,把報(bào)文還給系統(tǒng)協(xié)議棧繼續(xù)處理 */return NF_ACCEPT; }struct nf_hook_ops nfdemo_hook_ops[] ={{.hook = nfdemo_input_hook_v6, /* 鉤子處理函數(shù) */.pf = NFPROTO_IPV6, /* 協(xié)議類型IPv6 */.hooknum = NF_INET_PRE_ROUTING, /* Pre_Routing鏈 */.priority = NF_IP_PRI_FIRST + 20, /* 優(yōu)先級 */},{.hook = nfdemo_output_hook_v6, /* 鉤子處理函數(shù) */.pf = NFPROTO_IPV6, /* 協(xié)議類型IPv6 */.hooknum = NF_INET_PRE_ROUTING, /* Post_Routing鏈 */.priority = NF_IP_PRI_FIRST + 20, /* 優(yōu)先級 */},{} };/* 模塊入口 */ static int __init nfdemov6_init(void) {printk("nfv6demo init \r\n");/* 注冊 Netfilter 鉤子函數(shù) */nf_register_hooks(nfdemo_hook_ops,ARRAY_SIZE(nfdemo_hook_ops)); return 0; }/* 模塊出口 */ static void __exit nfdemov6_exit(void) {printk("nfv6demo exit \r\n");/* 注銷 Netfilter 鉤子函數(shù) */nf_unregister_hooks(nfdemo_hook_ops,ARRAY_SIZE(nfdemo_hook_ops)); return ; }module_init(nfdemov6_init) module_exit(nfdemov6_exit) MODULE_LICENSE("GPL"); MODULE_AUTHOR("Mason");代碼在本機(jī)編譯、運(yùn)行通過。
調(diào)試遇到一個(gè)bug,地址替換直接使用128,IPv6地址 長度為40字節(jié)128位,導(dǎo)致直接覆蓋后面內(nèi)容,悲催
當(dāng)然啦,聰明的你應(yīng)該不會出現(xiàn)這樣的錯誤
//正確的做法 memcpy(remote_ip.in6, &iph6->saddr, sizeof(struct in6_addr));//錯誤的做法 memcpy(remote_ip.in6, &iph6->saddr, 128);有問題歡迎提出來
またね
總結(jié)
以上是生活随笔為你收集整理的使用 netfilter 处理IPv6报文的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 推荐优秀团员个人简历(优秀团员个人简历)
- 下一篇: SNMP功能开发简介 一 net-snm