使用 netfilter 处理IPv6报文
生活随笔
收集整理的這篇文章主要介紹了
使用 netfilter 处理IPv6报文
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
? ????? netfilter對IPv6的處理和IPv4流程類似,只有鉤子函數注冊協議不同,優先級和注冊的鏈都是一樣的。
{.hook=nf_input_hook_v4,.pf=NFPROTO_IPV4, //IPv4協議.hooknum=NF_INET_POST_ROUTING,.priority=0,}, {.hook=nf_input_hook_v6,.pf=NFPROTO_IPV6, //IPv6協議.hooknum=NF_INET_PRE_ROUTING,.priority=NF_IP_PRI_FIRST,},下面是一個netfilter ipv6小栗子,對本機出去的IPv6 UDP報文做了端口變換處理,介紹一下IPv6地址操作、IPv6報文udp校驗值計算等等。
內核版本: 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輸入報文處理函數 */ 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輸出報文處理函數,這里對IPv6 UDP報文做了源端口變換 */ 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;/* 過濾源地址和目的地址相等的報文 */if (ipv6_addr_equal(&iph6->saddr, &iph6->daddr))return NF_ACCEPT;/* 過濾環回地址報文 ::1/128 */if (ipv6_addr_loopback(&iph6->saddr) || ipv6_addr_loopback(&iph6->daddr)) return NF_ACCEPT;/* 只處理UDP報文 */ if (iph6->nexthdr != NEXTHDR_UDP)return NF_ACCEPT;/* 設置傳輸層首部 */skb_set_transport_header(skb, sizeof(struct ipv6hdr));/* 獲取UDP首部 */udph = udp_hdr(skb);if (!udph )return NF_ACCEPT;/* 更改端口 */ udph->source = htons(6666); /* 重新計算校驗和 * IPv6校驗和計算使用 csum_ipv6_magic() 接口* IPv4校驗和計算使用 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首部校驗和為0,替換成CSUM_MANGLED_0 */if (0 == udph->check)udph->check = CSUM_MANGLED_0;/* 替換完成,把報文還給系統協議棧繼續處理 */return NF_ACCEPT; }struct nf_hook_ops nfdemo_hook_ops[] ={{.hook = nfdemo_input_hook_v6, /* 鉤子處理函數 */.pf = NFPROTO_IPV6, /* 協議類型IPv6 */.hooknum = NF_INET_PRE_ROUTING, /* Pre_Routing鏈 */.priority = NF_IP_PRI_FIRST + 20, /* 優先級 */},{.hook = nfdemo_output_hook_v6, /* 鉤子處理函數 */.pf = NFPROTO_IPV6, /* 協議類型IPv6 */.hooknum = NF_INET_PRE_ROUTING, /* Post_Routing鏈 */.priority = NF_IP_PRI_FIRST + 20, /* 優先級 */},{} };/* 模塊入口 */ static int __init nfdemov6_init(void) {printk("nfv6demo init \r\n");/* 注冊 Netfilter 鉤子函數 */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 鉤子函數 */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");代碼在本機編譯、運行通過。
調試遇到一個bug,地址替換直接使用128,IPv6地址 長度為40字節128位,導致直接覆蓋后面內容,悲催
當然啦,聰明的你應該不會出現這樣的錯誤
//正確的做法 memcpy(remote_ip.in6, &iph6->saddr, sizeof(struct in6_addr));//錯誤的做法 memcpy(remote_ip.in6, &iph6->saddr, 128);有問題歡迎提出來
またね
總結
以上是生活随笔為你收集整理的使用 netfilter 处理IPv6报文的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 推荐优秀团员个人简历(优秀团员个人简历)
- 下一篇: Linux 内核定时器使用 一 低精度定