📄 nf_conntrack_l3proto_ipv6.c
字号:
/* * Copyright (C)2004 USAGI/WIDE Project * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Author: * Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> * * 16 Dec 2003: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> * - support Layer 3 protocol independent connection tracking. * Based on the original ip_conntrack code which had the following * copyright information: * (C) 1999-2001 Paul `Rusty' Russell * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> * * 23 Mar 2004: Yasuyuki Kozakai @USAGI <yasuyuki.kozakai@toshiba.co.jp> * - add get_features() to support various size of conntrack * structures. */#include <linux/config.h>#include <linux/types.h>#include <linux/ipv6.h>#include <linux/in6.h>#include <linux/netfilter.h>#include <linux/module.h>#include <linux/skbuff.h>#include <linux/icmp.h>#include <linux/sysctl.h>#include <net/ipv6.h>#include <linux/netfilter_ipv6.h>#include <net/netfilter/nf_conntrack.h>#include <net/netfilter/nf_conntrack_helper.h>#include <net/netfilter/nf_conntrack_protocol.h>#include <net/netfilter/nf_conntrack_l3proto.h>#include <net/netfilter/nf_conntrack_core.h>#if 0#define DEBUGP printk#else#define DEBUGP(format, args...)#endifDECLARE_PER_CPU(struct ip_conntrack_stat, nf_conntrack_stat);static int ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, struct nf_conntrack_tuple *tuple){ u_int32_t _addrs[8], *ap; ap = skb_header_pointer(skb, nhoff + offsetof(struct ipv6hdr, saddr), sizeof(_addrs), _addrs); if (ap == NULL) return 0; memcpy(tuple->src.u3.ip6, ap, sizeof(tuple->src.u3.ip6)); memcpy(tuple->dst.u3.ip6, ap + 4, sizeof(tuple->dst.u3.ip6)); return 1;}static int ipv6_invert_tuple(struct nf_conntrack_tuple *tuple, const struct nf_conntrack_tuple *orig){ memcpy(tuple->src.u3.ip6, orig->dst.u3.ip6, sizeof(tuple->src.u3.ip6)); memcpy(tuple->dst.u3.ip6, orig->src.u3.ip6, sizeof(tuple->dst.u3.ip6)); return 1;}static int ipv6_print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple){ return seq_printf(s, "src=%x:%x:%x:%x:%x:%x:%x:%x dst=%x:%x:%x:%x:%x:%x:%x:%x ", NIP6(*((struct in6_addr *)tuple->src.u3.ip6)), NIP6(*((struct in6_addr *)tuple->dst.u3.ip6)));}static int ipv6_print_conntrack(struct seq_file *s, const struct nf_conn *conntrack){ return 0;}/* * Based on ipv6_skip_exthdr() in net/ipv6/exthdr.c * * This function parses (probably truncated) exthdr set "hdr" * of length "len". "nexthdrp" initially points to some place, * where type of the first header can be found. * * It skips all well-known exthdrs, and returns pointer to the start * of unparsable area i.e. the first header with unknown type. * if success, *nexthdr is updated by type/protocol of this header. * * NOTES: - it may return pointer pointing beyond end of packet, * if the last recognized header is truncated in the middle. * - if packet is truncated, so that all parsed headers are skipped, * it returns -1. * - if packet is fragmented, return pointer of the fragment header. * - ESP is unparsable for now and considered like * normal payload protocol. * - Note also special handling of AUTH header. Thanks to IPsec wizards. */int nf_ct_ipv6_skip_exthdr(struct sk_buff *skb, int start, u8 *nexthdrp, int len){ u8 nexthdr = *nexthdrp; while (ipv6_ext_hdr(nexthdr)) { struct ipv6_opt_hdr hdr; int hdrlen; if (len < (int)sizeof(struct ipv6_opt_hdr)) return -1; if (nexthdr == NEXTHDR_NONE) break; if (nexthdr == NEXTHDR_FRAGMENT) break; if (skb_copy_bits(skb, start, &hdr, sizeof(hdr))) BUG(); if (nexthdr == NEXTHDR_AUTH) hdrlen = (hdr.hdrlen+2)<<2; else hdrlen = ipv6_optlen(&hdr); nexthdr = hdr.nexthdr; len -= hdrlen; start += hdrlen; } *nexthdrp = nexthdr; return start;}static intipv6_prepare(struct sk_buff **pskb, unsigned int hooknum, unsigned int *dataoff, u_int8_t *protonum){ unsigned int extoff; unsigned char pnum; int protoff; extoff = (u8*)((*pskb)->nh.ipv6h + 1) - (*pskb)->data; pnum = (*pskb)->nh.ipv6h->nexthdr; protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, (*pskb)->len - extoff); /* * (protoff == (*pskb)->len) mean that the packet doesn't have no data * except of IPv6 & ext headers. but it's tracked anyway. - YK */ if ((protoff < 0) || (protoff > (*pskb)->len)) { DEBUGP("ip6_conntrack_core: can't find proto in pkt\n"); NF_CT_STAT_INC(error); NF_CT_STAT_INC(invalid); return -NF_ACCEPT; } *dataoff = protoff; *protonum = pnum; return NF_ACCEPT;}static u_int32_t ipv6_get_features(const struct nf_conntrack_tuple *tuple){ return NF_CT_F_BASIC;}static unsigned int ipv6_confirm(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)){ struct nf_conn *ct; enum ip_conntrack_info ctinfo; /* This is where we call the helper: as the packet goes out. */ ct = nf_ct_get(*pskb, &ctinfo); if (ct && ct->helper) { unsigned int ret, protoff; unsigned int extoff = (u8*)((*pskb)->nh.ipv6h + 1) - (*pskb)->data; unsigned char pnum = (*pskb)->nh.ipv6h->nexthdr; protoff = nf_ct_ipv6_skip_exthdr(*pskb, extoff, &pnum, (*pskb)->len - extoff); if (protoff < 0 || protoff > (*pskb)->len || pnum == NEXTHDR_FRAGMENT) { DEBUGP("proto header not found\n"); return NF_ACCEPT; } ret = ct->helper->help(pskb, protoff, ct, ctinfo); if (ret != NF_ACCEPT) return ret; } /* We've seen it coming out the other side: confirm it */ return nf_conntrack_confirm(pskb);}extern struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb);extern void nf_ct_frag6_output(unsigned int hooknum, struct sk_buff *skb, struct net_device *in, struct net_device *out, int (*okfn)(struct sk_buff *));static unsigned int ipv6_defrag(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)){ struct sk_buff *reasm; /* Previously seen (loopback)? */ if ((*pskb)->nfct) return NF_ACCEPT; reasm = nf_ct_frag6_gather(*pskb); /* queued */ if (reasm == NULL) return NF_STOLEN; /* error occured or not fragmented */ if (reasm == *pskb) return NF_ACCEPT; nf_ct_frag6_output(hooknum, reasm, (struct net_device *)in, (struct net_device *)out, okfn); return NF_STOLEN;}static unsigned int ipv6_conntrack_in(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)){ struct sk_buff *reasm = (*pskb)->nfct_reasm; /* This packet is fragmented and has reassembled packet. */ if (reasm) { /* Reassembled packet isn't parsed yet ? */ if (!reasm->nfct) { unsigned int ret; ret = nf_conntrack_in(PF_INET6, hooknum, &reasm); if (ret != NF_ACCEPT) return ret; } nf_conntrack_get(reasm->nfct); (*pskb)->nfct = reasm->nfct; return NF_ACCEPT; } return nf_conntrack_in(PF_INET6, hooknum, pskb);}static unsigned int ipv6_conntrack_local(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)){ /* root is playing with raw sockets. */ if ((*pskb)->len < sizeof(struct ipv6hdr)) { if (net_ratelimit()) printk("ipv6_conntrack_local: packet too short\n"); return NF_ACCEPT; } return ipv6_conntrack_in(hooknum, pskb, in, out, okfn);}/* Connection tracking may drop packets, but never alters them, so make it the first hook. */static struct nf_hook_ops ipv6_conntrack_defrag_ops = { .hook = ipv6_defrag, .owner = THIS_MODULE, .pf = PF_INET6, .hooknum = NF_IP6_PRE_ROUTING, .priority = NF_IP6_PRI_CONNTRACK_DEFRAG,};static struct nf_hook_ops ipv6_conntrack_in_ops = { .hook = ipv6_conntrack_in, .owner = THIS_MODULE, .pf = PF_INET6, .hooknum = NF_IP6_PRE_ROUTING, .priority = NF_IP6_PRI_CONNTRACK,};static struct nf_hook_ops ipv6_conntrack_local_out_ops = { .hook = ipv6_conntrack_local, .owner = THIS_MODULE, .pf = PF_INET6, .hooknum = NF_IP6_LOCAL_OUT, .priority = NF_IP6_PRI_CONNTRACK,};static struct nf_hook_ops ipv6_conntrack_defrag_local_out_ops = { .hook = ipv6_defrag, .owner = THIS_MODULE, .pf = PF_INET6, .hooknum = NF_IP6_LOCAL_OUT, .priority = NF_IP6_PRI_CONNTRACK_DEFRAG,};/* Refragmenter; last chance. */static struct nf_hook_ops ipv6_conntrack_out_ops = { .hook = ipv6_confirm, .owner = THIS_MODULE, .pf = PF_INET6, .hooknum = NF_IP6_POST_ROUTING, .priority = NF_IP6_PRI_LAST,};static struct nf_hook_ops ipv6_conntrack_local_in_ops = { .hook = ipv6_confirm, .owner = THIS_MODULE, .pf = PF_INET6, .hooknum = NF_IP6_LOCAL_IN, .priority = NF_IP6_PRI_LAST-1,};#ifdef CONFIG_SYSCTL/* From nf_conntrack_proto_icmpv6.c */extern unsigned long nf_ct_icmpv6_timeout;/* From nf_conntrack_frag6.c */extern unsigned long nf_ct_frag6_timeout;extern unsigned int nf_ct_frag6_low_thresh;extern unsigned int nf_ct_frag6_high_thresh;static struct ctl_table_header *nf_ct_ipv6_sysctl_header;static ctl_table nf_ct_sysctl_table[] = { { .ctl_name = NET_NF_CONNTRACK_ICMPV6_TIMEOUT, .procname = "nf_conntrack_icmpv6_timeout", .data = &nf_ct_icmpv6_timeout, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = &proc_dointvec_jiffies, }, { .ctl_name = NET_NF_CONNTRACK_FRAG6_TIMEOUT, .procname = "nf_conntrack_frag6_timeout", .data = &nf_ct_frag6_timeout, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = &proc_dointvec_jiffies, }, { .ctl_name = NET_NF_CONNTRACK_FRAG6_LOW_THRESH, .procname = "nf_conntrack_frag6_low_thresh", .data = &nf_ct_frag6_low_thresh, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = NET_NF_CONNTRACK_FRAG6_HIGH_THRESH, .procname = "nf_conntrack_frag6_high_thresh", .data = &nf_ct_frag6_high_thresh, .maxlen = sizeof(unsigned int), .mode = 0644, .proc_handler = &proc_dointvec, }, { .ctl_name = 0 }};static ctl_table nf_ct_netfilter_table[] = { { .ctl_name = NET_NETFILTER, .procname = "netfilter", .mode = 0555, .child = nf_ct_sysctl_table, }, { .ctl_name = 0 }};static ctl_table nf_ct_net_table[] = { { .ctl_name = CTL_NET, .procname = "net", .mode = 0555, .child = nf_ct_netfilter_table, }, { .ctl_name = 0 }};#endifstruct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = { .l3proto = PF_INET6, .name = "ipv6", .pkt_to_tuple = ipv6_pkt_to_tuple, .invert_tuple = ipv6_invert_tuple, .print_tuple = ipv6_print_tuple, .print_conntrack = ipv6_print_conntrack, .prepare = ipv6_prepare, .get_features = ipv6_get_features, .me = THIS_MODULE,};extern struct nf_conntrack_protocol nf_conntrack_protocol_tcp6;extern struct nf_conntrack_protocol nf_conntrack_protocol_udp6;extern struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6;extern int nf_ct_frag6_init(void);extern void nf_ct_frag6_cleanup(void);static int init_or_cleanup(int init){ int ret = 0; if (!init) goto cleanup; ret = nf_ct_frag6_init(); if (ret < 0) { printk("nf_conntrack_ipv6: can't initialize frag6.\n"); goto cleanup_nothing; } ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_tcp6); if (ret < 0) { printk("nf_conntrack_ipv6: can't register tcp.\n"); goto cleanup_frag6; } ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_udp6); if (ret < 0) { printk("nf_conntrack_ipv6: can't register udp.\n"); goto cleanup_tcp; } ret = nf_conntrack_protocol_register(&nf_conntrack_protocol_icmpv6); if (ret < 0) { printk("nf_conntrack_ipv6: can't register icmpv6.\n"); goto cleanup_udp; } ret = nf_conntrack_l3proto_register(&nf_conntrack_l3proto_ipv6); if (ret < 0) { printk("nf_conntrack_ipv6: can't register ipv6\n"); goto cleanup_icmpv6; } ret = nf_register_hook(&ipv6_conntrack_defrag_ops); if (ret < 0) { printk("nf_conntrack_ipv6: can't register pre-routing defrag " "hook.\n"); goto cleanup_ipv6; } ret = nf_register_hook(&ipv6_conntrack_defrag_local_out_ops); if (ret < 0) { printk("nf_conntrack_ipv6: can't register local_out defrag " "hook.\n"); goto cleanup_defragops; } ret = nf_register_hook(&ipv6_conntrack_in_ops); if (ret < 0) { printk("nf_conntrack_ipv6: can't register pre-routing hook.\n"); goto cleanup_defraglocalops; } ret = nf_register_hook(&ipv6_conntrack_local_out_ops); if (ret < 0) { printk("nf_conntrack_ipv6: can't register local out hook.\n"); goto cleanup_inops; } ret = nf_register_hook(&ipv6_conntrack_out_ops); if (ret < 0) { printk("nf_conntrack_ipv6: can't register post-routing hook.\n"); goto cleanup_inandlocalops; } ret = nf_register_hook(&ipv6_conntrack_local_in_ops); if (ret < 0) { printk("nf_conntrack_ipv6: can't register local in hook.\n"); goto cleanup_inoutandlocalops; }#ifdef CONFIG_SYSCTL nf_ct_ipv6_sysctl_header = register_sysctl_table(nf_ct_net_table, 0); if (nf_ct_ipv6_sysctl_header == NULL) { printk("nf_conntrack: can't register to sysctl.\n"); ret = -ENOMEM; goto cleanup_localinops; }#endif return ret; cleanup: synchronize_net();#ifdef CONFIG_SYSCTL unregister_sysctl_table(nf_ct_ipv6_sysctl_header); cleanup_localinops:#endif nf_unregister_hook(&ipv6_conntrack_local_in_ops); cleanup_inoutandlocalops: nf_unregister_hook(&ipv6_conntrack_out_ops); cleanup_inandlocalops: nf_unregister_hook(&ipv6_conntrack_local_out_ops); cleanup_inops: nf_unregister_hook(&ipv6_conntrack_in_ops); cleanup_defraglocalops: nf_unregister_hook(&ipv6_conntrack_defrag_local_out_ops); cleanup_defragops: nf_unregister_hook(&ipv6_conntrack_defrag_ops); cleanup_ipv6: nf_conntrack_l3proto_unregister(&nf_conntrack_l3proto_ipv6); cleanup_icmpv6: nf_conntrack_protocol_unregister(&nf_conntrack_protocol_icmpv6); cleanup_udp: nf_conntrack_protocol_unregister(&nf_conntrack_protocol_udp6); cleanup_tcp: nf_conntrack_protocol_unregister(&nf_conntrack_protocol_tcp6); cleanup_frag6: nf_ct_frag6_cleanup(); cleanup_nothing: return ret;}MODULE_LICENSE("GPL");MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");static int __init init(void){ need_nf_conntrack(); return init_or_cleanup(1);}static void __exit fini(void){ init_or_cleanup(0);}module_init(init);module_exit(fini);void need_ip6_conntrack(void){}EXPORT_SYMBOL(need_ip6_conntrack);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -