From 57f0f512b273f60d52568b8c6b77e17f5636edc0 Mon Sep 17 00:00:00 2001 From: André Fabian Silva Delgado Date: Wed, 5 Aug 2015 17:04:01 -0300 Subject: Initial import --- include/net/netfilter/br_netfilter.h | 6 + include/net/netfilter/ipv4/nf_conntrack_ipv4.h | 22 + include/net/netfilter/ipv4/nf_defrag_ipv4.h | 6 + include/net/netfilter/ipv4/nf_nat_masquerade.h | 14 + include/net/netfilter/ipv4/nf_reject.h | 19 + include/net/netfilter/ipv6/nf_conntrack_icmpv6.h | 20 + include/net/netfilter/ipv6/nf_conntrack_ipv6.h | 13 + include/net/netfilter/ipv6/nf_defrag_ipv6.h | 13 + include/net/netfilter/ipv6/nf_nat_masquerade.h | 10 + include/net/netfilter/ipv6/nf_reject.h | 21 + include/net/netfilter/nf_conntrack.h | 302 +++++++ include/net/netfilter/nf_conntrack_acct.h | 69 ++ include/net/netfilter/nf_conntrack_core.h | 89 ++ include/net/netfilter/nf_conntrack_ecache.h | 283 ++++++ include/net/netfilter/nf_conntrack_expect.h | 116 +++ include/net/netfilter/nf_conntrack_extend.h | 123 +++ include/net/netfilter/nf_conntrack_helper.h | 119 +++ include/net/netfilter/nf_conntrack_l3proto.h | 102 +++ include/net/netfilter/nf_conntrack_l4proto.h | 158 ++++ include/net/netfilter/nf_conntrack_labels.h | 60 ++ include/net/netfilter/nf_conntrack_seqadj.h | 47 + include/net/netfilter/nf_conntrack_synproxy.h | 75 ++ include/net/netfilter/nf_conntrack_timeout.h | 98 ++ include/net/netfilter/nf_conntrack_timestamp.h | 78 ++ include/net/netfilter/nf_conntrack_tuple.h | 186 ++++ include/net/netfilter/nf_conntrack_zones.h | 25 + include/net/netfilter/nf_log.h | 112 +++ include/net/netfilter/nf_nat.h | 79 ++ include/net/netfilter/nf_nat_core.h | 31 + include/net/netfilter/nf_nat_helper.h | 40 + include/net/netfilter/nf_nat_l3proto.h | 108 +++ include/net/netfilter/nf_nat_l4proto.h | 72 ++ include/net/netfilter/nf_nat_redirect.h | 12 + include/net/netfilter/nf_queue.h | 94 ++ include/net/netfilter/nf_tables.h | 1033 ++++++++++++++++++++++ include/net/netfilter/nf_tables_bridge.h | 7 + include/net/netfilter/nf_tables_core.h | 55 ++ include/net/netfilter/nf_tables_ipv4.h | 25 + include/net/netfilter/nf_tables_ipv6.h | 32 + include/net/netfilter/nfnetlink_log.h | 17 + include/net/netfilter/nfnetlink_queue.h | 51 ++ include/net/netfilter/nft_masq.h | 19 + include/net/netfilter/nft_meta.h | 36 + include/net/netfilter/nft_redir.h | 21 + include/net/netfilter/nft_reject.h | 20 + include/net/netfilter/xt_rateest.h | 22 + 46 files changed, 3960 insertions(+) create mode 100644 include/net/netfilter/br_netfilter.h create mode 100644 include/net/netfilter/ipv4/nf_conntrack_ipv4.h create mode 100644 include/net/netfilter/ipv4/nf_defrag_ipv4.h create mode 100644 include/net/netfilter/ipv4/nf_nat_masquerade.h create mode 100644 include/net/netfilter/ipv4/nf_reject.h create mode 100644 include/net/netfilter/ipv6/nf_conntrack_icmpv6.h create mode 100644 include/net/netfilter/ipv6/nf_conntrack_ipv6.h create mode 100644 include/net/netfilter/ipv6/nf_defrag_ipv6.h create mode 100644 include/net/netfilter/ipv6/nf_nat_masquerade.h create mode 100644 include/net/netfilter/ipv6/nf_reject.h create mode 100644 include/net/netfilter/nf_conntrack.h create mode 100644 include/net/netfilter/nf_conntrack_acct.h create mode 100644 include/net/netfilter/nf_conntrack_core.h create mode 100644 include/net/netfilter/nf_conntrack_ecache.h create mode 100644 include/net/netfilter/nf_conntrack_expect.h create mode 100644 include/net/netfilter/nf_conntrack_extend.h create mode 100644 include/net/netfilter/nf_conntrack_helper.h create mode 100644 include/net/netfilter/nf_conntrack_l3proto.h create mode 100644 include/net/netfilter/nf_conntrack_l4proto.h create mode 100644 include/net/netfilter/nf_conntrack_labels.h create mode 100644 include/net/netfilter/nf_conntrack_seqadj.h create mode 100644 include/net/netfilter/nf_conntrack_synproxy.h create mode 100644 include/net/netfilter/nf_conntrack_timeout.h create mode 100644 include/net/netfilter/nf_conntrack_timestamp.h create mode 100644 include/net/netfilter/nf_conntrack_tuple.h create mode 100644 include/net/netfilter/nf_conntrack_zones.h create mode 100644 include/net/netfilter/nf_log.h create mode 100644 include/net/netfilter/nf_nat.h create mode 100644 include/net/netfilter/nf_nat_core.h create mode 100644 include/net/netfilter/nf_nat_helper.h create mode 100644 include/net/netfilter/nf_nat_l3proto.h create mode 100644 include/net/netfilter/nf_nat_l4proto.h create mode 100644 include/net/netfilter/nf_nat_redirect.h create mode 100644 include/net/netfilter/nf_queue.h create mode 100644 include/net/netfilter/nf_tables.h create mode 100644 include/net/netfilter/nf_tables_bridge.h create mode 100644 include/net/netfilter/nf_tables_core.h create mode 100644 include/net/netfilter/nf_tables_ipv4.h create mode 100644 include/net/netfilter/nf_tables_ipv6.h create mode 100644 include/net/netfilter/nfnetlink_log.h create mode 100644 include/net/netfilter/nfnetlink_queue.h create mode 100644 include/net/netfilter/nft_masq.h create mode 100644 include/net/netfilter/nft_meta.h create mode 100644 include/net/netfilter/nft_redir.h create mode 100644 include/net/netfilter/nft_reject.h create mode 100644 include/net/netfilter/xt_rateest.h (limited to 'include/net/netfilter') diff --git a/include/net/netfilter/br_netfilter.h b/include/net/netfilter/br_netfilter.h new file mode 100644 index 000000000..2aa6048a5 --- /dev/null +++ b/include/net/netfilter/br_netfilter.h @@ -0,0 +1,6 @@ +#ifndef _BR_NETFILTER_H_ +#define _BR_NETFILTER_H_ + +void br_netfilter_enable(void); + +#endif /* _BR_NETFILTER_H_ */ diff --git a/include/net/netfilter/ipv4/nf_conntrack_ipv4.h b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h new file mode 100644 index 000000000..981c32737 --- /dev/null +++ b/include/net/netfilter/ipv4/nf_conntrack_ipv4.h @@ -0,0 +1,22 @@ +/* + * IPv4 support for nf_conntrack. + * + * 23 Mar 2004: Yasuyuki Kozakai @ USAGI + * - move L3 protocol dependent part from include/linux/netfilter_ipv4/ + * ip_conntarck.h + */ + +#ifndef _NF_CONNTRACK_IPV4_H +#define _NF_CONNTRACK_IPV4_H + + +extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4; + +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp4; +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4; +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp; + +int nf_conntrack_ipv4_compat_init(void); +void nf_conntrack_ipv4_compat_fini(void); + +#endif /*_NF_CONNTRACK_IPV4_H*/ diff --git a/include/net/netfilter/ipv4/nf_defrag_ipv4.h b/include/net/netfilter/ipv4/nf_defrag_ipv4.h new file mode 100644 index 000000000..f01ef208d --- /dev/null +++ b/include/net/netfilter/ipv4/nf_defrag_ipv4.h @@ -0,0 +1,6 @@ +#ifndef _NF_DEFRAG_IPV4_H +#define _NF_DEFRAG_IPV4_H + +void nf_defrag_ipv4_enable(void); + +#endif /* _NF_DEFRAG_IPV4_H */ diff --git a/include/net/netfilter/ipv4/nf_nat_masquerade.h b/include/net/netfilter/ipv4/nf_nat_masquerade.h new file mode 100644 index 000000000..a9c001c64 --- /dev/null +++ b/include/net/netfilter/ipv4/nf_nat_masquerade.h @@ -0,0 +1,14 @@ +#ifndef _NF_NAT_MASQUERADE_IPV4_H_ +#define _NF_NAT_MASQUERADE_IPV4_H_ + +#include + +unsigned int +nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum, + const struct nf_nat_range *range, + const struct net_device *out); + +void nf_nat_masquerade_ipv4_register_notifier(void); +void nf_nat_masquerade_ipv4_unregister_notifier(void); + +#endif /*_NF_NAT_MASQUERADE_IPV4_H_ */ diff --git a/include/net/netfilter/ipv4/nf_reject.h b/include/net/netfilter/ipv4/nf_reject.h new file mode 100644 index 000000000..77862c364 --- /dev/null +++ b/include/net/netfilter/ipv4/nf_reject.h @@ -0,0 +1,19 @@ +#ifndef _IPV4_NF_REJECT_H +#define _IPV4_NF_REJECT_H + +#include +#include +#include + +void nf_send_unreach(struct sk_buff *skb_in, int code, int hook); +void nf_send_reset(struct sk_buff *oldskb, int hook); + +const struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb, + struct tcphdr *_oth, int hook); +struct iphdr *nf_reject_iphdr_put(struct sk_buff *nskb, + const struct sk_buff *oldskb, + __u8 protocol, int ttl); +void nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb, + const struct tcphdr *oth); + +#endif /* _IPV4_NF_REJECT_H */ diff --git a/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h b/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h new file mode 100644 index 000000000..67edd50a3 --- /dev/null +++ b/include/net/netfilter/ipv6/nf_conntrack_icmpv6.h @@ -0,0 +1,20 @@ +/* + * ICMPv6 tracking. + * + * 21 Apl 2004: Yasuyuki Kozakai @USAGI + * - separated from nf_conntrack_icmp.h + * + * Derived from include/linux/netfiter_ipv4/ip_conntrack_icmp.h + */ + +#ifndef _NF_CONNTRACK_ICMPV6_H +#define _NF_CONNTRACK_ICMPV6_H + +#ifndef ICMPV6_NI_QUERY +#define ICMPV6_NI_QUERY 139 +#endif +#ifndef ICMPV6_NI_REPLY +#define ICMPV6_NI_REPLY 140 +#endif + +#endif /* _NF_CONNTRACK_ICMPV6_H */ diff --git a/include/net/netfilter/ipv6/nf_conntrack_ipv6.h b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h new file mode 100644 index 000000000..a4c993685 --- /dev/null +++ b/include/net/netfilter/ipv6/nf_conntrack_ipv6.h @@ -0,0 +1,13 @@ +#ifndef _NF_CONNTRACK_IPV6_H +#define _NF_CONNTRACK_IPV6_H + +extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6; + +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6; +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6; +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6; + +#include +extern struct ctl_table nf_ct_ipv6_sysctl_table[]; + +#endif /* _NF_CONNTRACK_IPV6_H*/ diff --git a/include/net/netfilter/ipv6/nf_defrag_ipv6.h b/include/net/netfilter/ipv6/nf_defrag_ipv6.h new file mode 100644 index 000000000..27666d8a0 --- /dev/null +++ b/include/net/netfilter/ipv6/nf_defrag_ipv6.h @@ -0,0 +1,13 @@ +#ifndef _NF_DEFRAG_IPV6_H +#define _NF_DEFRAG_IPV6_H + +void nf_defrag_ipv6_enable(void); + +int nf_ct_frag6_init(void); +void nf_ct_frag6_cleanup(void); +struct sk_buff *nf_ct_frag6_gather(struct sk_buff *skb, u32 user); +void nf_ct_frag6_consume_orig(struct sk_buff *skb); + +struct inet_frags_ctl; + +#endif /* _NF_DEFRAG_IPV6_H */ diff --git a/include/net/netfilter/ipv6/nf_nat_masquerade.h b/include/net/netfilter/ipv6/nf_nat_masquerade.h new file mode 100644 index 000000000..0a13396cd --- /dev/null +++ b/include/net/netfilter/ipv6/nf_nat_masquerade.h @@ -0,0 +1,10 @@ +#ifndef _NF_NAT_MASQUERADE_IPV6_H_ +#define _NF_NAT_MASQUERADE_IPV6_H_ + +unsigned int +nf_nat_masquerade_ipv6(struct sk_buff *skb, const struct nf_nat_range *range, + const struct net_device *out); +void nf_nat_masquerade_ipv6_register_notifier(void); +void nf_nat_masquerade_ipv6_unregister_notifier(void); + +#endif /* _NF_NAT_MASQUERADE_IPV6_H_ */ diff --git a/include/net/netfilter/ipv6/nf_reject.h b/include/net/netfilter/ipv6/nf_reject.h new file mode 100644 index 000000000..0ea4fa37d --- /dev/null +++ b/include/net/netfilter/ipv6/nf_reject.h @@ -0,0 +1,21 @@ +#ifndef _IPV6_NF_REJECT_H +#define _IPV6_NF_REJECT_H + +#include + +void nf_send_unreach6(struct net *net, struct sk_buff *skb_in, unsigned char code, + unsigned int hooknum); + +void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook); + +const struct tcphdr *nf_reject_ip6_tcphdr_get(struct sk_buff *oldskb, + struct tcphdr *otcph, + unsigned int *otcplen, int hook); +struct ipv6hdr *nf_reject_ip6hdr_put(struct sk_buff *nskb, + const struct sk_buff *oldskb, + __u8 protocol, int hoplimit); +void nf_reject_ip6_tcphdr_put(struct sk_buff *nskb, + const struct sk_buff *oldskb, + const struct tcphdr *oth, unsigned int otcplen); + +#endif /* _IPV6_NF_REJECT_H */ diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h new file mode 100644 index 000000000..095433b8a --- /dev/null +++ b/include/net/netfilter/nf_conntrack.h @@ -0,0 +1,302 @@ +/* + * Connection state tracking for netfilter. This is separated from, + * but required by, the (future) NAT layer; it can also be used by an iptables + * extension. + * + * 16 Dec 2003: Yasuyuki Kozakai @USAGI + * - generalize L3 protocol dependent part. + * + * Derived from include/linux/netfiter_ipv4/ip_conntrack.h + */ + +#ifndef _NF_CONNTRACK_H +#define _NF_CONNTRACK_H + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +/* per conntrack: protocol private data */ +union nf_conntrack_proto { + /* insert conntrack proto private data here */ + struct nf_ct_dccp dccp; + struct ip_ct_sctp sctp; + struct ip_ct_tcp tcp; + struct nf_ct_gre gre; +}; + +union nf_conntrack_expect_proto { + /* insert expect proto private data here */ +}; + +#include +#include +#include + +#ifdef CONFIG_NETFILTER_DEBUG +#define NF_CT_ASSERT(x) WARN_ON(!(x)) +#else +#define NF_CT_ASSERT(x) +#endif + +struct nf_conntrack_helper; + +/* Must be kept in sync with the classes defined by helpers */ +#define NF_CT_MAX_EXPECT_CLASSES 4 + +/* nf_conn feature for connections that have a helper */ +struct nf_conn_help { + /* Helper. if any */ + struct nf_conntrack_helper __rcu *helper; + + struct hlist_head expectations; + + /* Current number of expected connections */ + u8 expecting[NF_CT_MAX_EXPECT_CLASSES]; + + /* private helper information. */ + char data[]; +}; + +#include +#include + +struct nf_conn { + /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, + * plus 1 for any connection(s) we are `master' for + * + * Hint, SKB address this struct and refcnt via skb->nfct and + * helpers nf_conntrack_get() and nf_conntrack_put(). + * Helper nf_ct_put() equals nf_conntrack_put() by dec refcnt, + * beware nf_ct_get() is different and don't inc refcnt. + */ + struct nf_conntrack ct_general; + + spinlock_t lock; + u16 cpu; + + /* XXX should I move this to the tail ? - Y.K */ + /* These are my tuples; original and reply */ + struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; + + /* Have we seen traffic both ways yet? (bitset) */ + unsigned long status; + + /* Timer function; drops refcnt when it goes off. */ + struct timer_list timeout; + + possible_net_t ct_net; + + /* all members below initialized via memset */ + u8 __nfct_init_offset[0]; + + /* If we were expected by an expectation, this will be it */ + struct nf_conn *master; + +#if defined(CONFIG_NF_CONNTRACK_MARK) + u_int32_t mark; +#endif + +#ifdef CONFIG_NF_CONNTRACK_SECMARK + u_int32_t secmark; +#endif + + /* Extensions */ + struct nf_ct_ext *ext; + + /* Storage reserved for other modules, must be the last member */ + union nf_conntrack_proto proto; +}; + +static inline struct nf_conn * +nf_ct_tuplehash_to_ctrack(const struct nf_conntrack_tuple_hash *hash) +{ + return container_of(hash, struct nf_conn, + tuplehash[hash->tuple.dst.dir]); +} + +static inline u_int16_t nf_ct_l3num(const struct nf_conn *ct) +{ + return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num; +} + +static inline u_int8_t nf_ct_protonum(const struct nf_conn *ct) +{ + return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum; +} + +#define nf_ct_tuple(ct, dir) (&(ct)->tuplehash[dir].tuple) + +/* get master conntrack via master expectation */ +#define master_ct(conntr) (conntr->master) + +extern struct net init_net; + +static inline struct net *nf_ct_net(const struct nf_conn *ct) +{ + return read_pnet(&ct->ct_net); +} + +/* Alter reply tuple (maybe alter helper). */ +void nf_conntrack_alter_reply(struct nf_conn *ct, + const struct nf_conntrack_tuple *newreply); + +/* Is this tuple taken? (ignoring any belonging to the given + conntrack). */ +int nf_conntrack_tuple_taken(const struct nf_conntrack_tuple *tuple, + const struct nf_conn *ignored_conntrack); + +/* Return conntrack_info and tuple hash for given skb. */ +static inline struct nf_conn * +nf_ct_get(const struct sk_buff *skb, enum ip_conntrack_info *ctinfo) +{ + *ctinfo = skb->nfctinfo; + return (struct nf_conn *)skb->nfct; +} + +/* decrement reference count on a conntrack */ +static inline void nf_ct_put(struct nf_conn *ct) +{ + NF_CT_ASSERT(ct); + nf_conntrack_put(&ct->ct_general); +} + +/* Protocol module loading */ +int nf_ct_l3proto_try_module_get(unsigned short l3proto); +void nf_ct_l3proto_module_put(unsigned short l3proto); + +/* + * Allocate a hashtable of hlist_head (if nulls == 0), + * or hlist_nulls_head (if nulls == 1) + */ +void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls); + +void nf_ct_free_hashtable(void *hash, unsigned int size); + +struct nf_conntrack_tuple_hash * +__nf_conntrack_find(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); + +int nf_conntrack_hash_check_insert(struct nf_conn *ct); +bool nf_ct_delete(struct nf_conn *ct, u32 pid, int report); + +bool nf_ct_get_tuplepr(const struct sk_buff *skb, unsigned int nhoff, + u_int16_t l3num, struct nf_conntrack_tuple *tuple); +bool nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, + const struct nf_conntrack_tuple *orig); + +void __nf_ct_refresh_acct(struct nf_conn *ct, enum ip_conntrack_info ctinfo, + const struct sk_buff *skb, + unsigned long extra_jiffies, int do_acct); + +/* Refresh conntrack for this many jiffies and do accounting */ +static inline void nf_ct_refresh_acct(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + const struct sk_buff *skb, + unsigned long extra_jiffies) +{ + __nf_ct_refresh_acct(ct, ctinfo, skb, extra_jiffies, 1); +} + +/* Refresh conntrack for this many jiffies */ +static inline void nf_ct_refresh(struct nf_conn *ct, + const struct sk_buff *skb, + unsigned long extra_jiffies) +{ + __nf_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0); +} + +bool __nf_ct_kill_acct(struct nf_conn *ct, enum ip_conntrack_info ctinfo, + const struct sk_buff *skb, int do_acct); + +/* kill conntrack and do accounting */ +static inline bool nf_ct_kill_acct(struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + const struct sk_buff *skb) +{ + return __nf_ct_kill_acct(ct, ctinfo, skb, 1); +} + +/* kill conntrack without accounting */ +static inline bool nf_ct_kill(struct nf_conn *ct) +{ + return __nf_ct_kill_acct(ct, 0, NULL, 0); +} + +/* These are for NAT. Icky. */ +extern s32 (*nf_ct_nat_offset)(const struct nf_conn *ct, + enum ip_conntrack_dir dir, + u32 seq); + +/* Fake conntrack entry for untracked connections */ +DECLARE_PER_CPU(struct nf_conn, nf_conntrack_untracked); +static inline struct nf_conn *nf_ct_untracked_get(void) +{ + return raw_cpu_ptr(&nf_conntrack_untracked); +} +void nf_ct_untracked_status_or(unsigned long bits); + +/* Iterate over all conntracks: if iter returns true, it's deleted. */ +void nf_ct_iterate_cleanup(struct net *net, + int (*iter)(struct nf_conn *i, void *data), + void *data, u32 portid, int report); +void nf_conntrack_free(struct nf_conn *ct); +struct nf_conn *nf_conntrack_alloc(struct net *net, u16 zone, + const struct nf_conntrack_tuple *orig, + const struct nf_conntrack_tuple *repl, + gfp_t gfp); + +static inline int nf_ct_is_template(const struct nf_conn *ct) +{ + return test_bit(IPS_TEMPLATE_BIT, &ct->status); +} + +/* It's confirmed if it is, or has been in the hash table. */ +static inline int nf_ct_is_confirmed(struct nf_conn *ct) +{ + return test_bit(IPS_CONFIRMED_BIT, &ct->status); +} + +static inline int nf_ct_is_dying(struct nf_conn *ct) +{ + return test_bit(IPS_DYING_BIT, &ct->status); +} + +static inline int nf_ct_is_untracked(const struct nf_conn *ct) +{ + return test_bit(IPS_UNTRACKED_BIT, &ct->status); +} + +/* Packet is received from loopback */ +static inline bool nf_is_loopback_packet(const struct sk_buff *skb) +{ + return skb->dev && skb->skb_iif && skb->dev->flags & IFF_LOOPBACK; +} + +struct kernel_param; + +int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp); +extern unsigned int nf_conntrack_htable_size; +extern unsigned int nf_conntrack_max; +extern unsigned int nf_conntrack_hash_rnd; +void init_nf_conntrack_hash_rnd(void); + +void nf_conntrack_tmpl_insert(struct net *net, struct nf_conn *tmpl); + +#define NF_CT_STAT_INC(net, count) __this_cpu_inc((net)->ct.stat->count) +#define NF_CT_STAT_INC_ATOMIC(net, count) this_cpu_inc((net)->ct.stat->count) + +#define MODULE_ALIAS_NFCT_HELPER(helper) \ + MODULE_ALIAS("nfct-helper-" helper) + +#endif /* _NF_CONNTRACK_H */ diff --git a/include/net/netfilter/nf_conntrack_acct.h b/include/net/netfilter/nf_conntrack_acct.h new file mode 100644 index 000000000..79d8d1673 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_acct.h @@ -0,0 +1,69 @@ +/* + * (C) 2008 Krzysztof Piotr Oledzki + * + * 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. + */ + +#ifndef _NF_CONNTRACK_ACCT_H +#define _NF_CONNTRACK_ACCT_H +#include +#include +#include +#include +#include + +struct nf_conn_counter { + atomic64_t packets; + atomic64_t bytes; +}; + +struct nf_conn_acct { + struct nf_conn_counter counter[IP_CT_DIR_MAX]; +}; + +static inline +struct nf_conn_acct *nf_conn_acct_find(const struct nf_conn *ct) +{ + return nf_ct_ext_find(ct, NF_CT_EXT_ACCT); +} + +static inline +struct nf_conn_acct *nf_ct_acct_ext_add(struct nf_conn *ct, gfp_t gfp) +{ + struct net *net = nf_ct_net(ct); + struct nf_conn_acct *acct; + + if (!net->ct.sysctl_acct) + return NULL; + + acct = nf_ct_ext_add(ct, NF_CT_EXT_ACCT, gfp); + if (!acct) + pr_debug("failed to add accounting extension area"); + + + return acct; +}; + +unsigned int seq_print_acct(struct seq_file *s, const struct nf_conn *ct, + int dir); + +/* Check if connection tracking accounting is enabled */ +static inline bool nf_ct_acct_enabled(struct net *net) +{ + return net->ct.sysctl_acct != 0; +} + +/* Enable/disable connection tracking accounting */ +static inline void nf_ct_set_acct(struct net *net, bool enable) +{ + net->ct.sysctl_acct = enable; +} + +int nf_conntrack_acct_pernet_init(struct net *net); +void nf_conntrack_acct_pernet_fini(struct net *net); + +int nf_conntrack_acct_init(void); +void nf_conntrack_acct_fini(void); +#endif /* _NF_CONNTRACK_ACCT_H */ diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h new file mode 100644 index 000000000..f2f0fa3bb --- /dev/null +++ b/include/net/netfilter/nf_conntrack_core.h @@ -0,0 +1,89 @@ +/* + * This header is used to share core functionality between the + * standalone connection tracking module, and the compatibility layer's use + * of connection tracking. + * + * 16 Dec 2003: Yasuyuki Kozakai @USAGI + * - generalize L3 protocol dependent part. + * + * Derived from include/linux/netfiter_ipv4/ip_conntrack_core.h + */ + +#ifndef _NF_CONNTRACK_CORE_H +#define _NF_CONNTRACK_CORE_H + +#include +#include +#include +#include + +/* This header is used to share core functionality between the + standalone connection tracking module, and the compatibility layer's use + of connection tracking. */ +unsigned int nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, + struct sk_buff *skb); + +int nf_conntrack_init_net(struct net *net); +void nf_conntrack_cleanup_net(struct net *net); +void nf_conntrack_cleanup_net_list(struct list_head *net_exit_list); + +int nf_conntrack_proto_pernet_init(struct net *net); +void nf_conntrack_proto_pernet_fini(struct net *net); + +int nf_conntrack_proto_init(void); +void nf_conntrack_proto_fini(void); + +int nf_conntrack_init_start(void); +void nf_conntrack_cleanup_start(void); + +void nf_conntrack_init_end(void); +void nf_conntrack_cleanup_end(void); + +bool nf_ct_get_tuple(const struct sk_buff *skb, unsigned int nhoff, + unsigned int dataoff, u_int16_t l3num, u_int8_t protonum, + struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_l3proto *l3proto, + const struct nf_conntrack_l4proto *l4proto); + +bool nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, + const struct nf_conntrack_tuple *orig, + const struct nf_conntrack_l3proto *l3proto, + const struct nf_conntrack_l4proto *l4proto); + +/* Find a connection corresponding to a tuple. */ +struct nf_conntrack_tuple_hash * +nf_conntrack_find_get(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); + +int __nf_conntrack_confirm(struct sk_buff *skb); + +/* Confirm a connection: returns NF_DROP if packet must be dropped. */ +static inline int nf_conntrack_confirm(struct sk_buff *skb) +{ + struct nf_conn *ct = (struct nf_conn *)skb->nfct; + int ret = NF_ACCEPT; + + if (ct && !nf_ct_is_untracked(ct)) { + if (!nf_ct_is_confirmed(ct)) + ret = __nf_conntrack_confirm(skb); + if (likely(ret == NF_ACCEPT)) + nf_ct_deliver_cached_events(ct); + } + return ret; +} + +void +print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_l3proto *l3proto, + const struct nf_conntrack_l4proto *proto); + +#ifdef CONFIG_LOCKDEP +# define CONNTRACK_LOCKS 8 +#else +# define CONNTRACK_LOCKS 1024 +#endif +extern spinlock_t nf_conntrack_locks[CONNTRACK_LOCKS]; + +extern spinlock_t nf_conntrack_expect_lock; + +#endif /* _NF_CONNTRACK_CORE_H */ diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h new file mode 100644 index 000000000..57c880378 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -0,0 +1,283 @@ +/* + * connection tracking event cache. + */ + +#ifndef _NF_CONNTRACK_ECACHE_H +#define _NF_CONNTRACK_ECACHE_H +#include + +#include +#include +#include +#include +#include + +struct nf_conntrack_ecache { + unsigned long cache; /* bitops want long */ + unsigned long missed; /* missed events */ + u16 ctmask; /* bitmask of ct events to be delivered */ + u16 expmask; /* bitmask of expect events to be delivered */ + u32 portid; /* netlink portid of destroyer */ +}; + +static inline struct nf_conntrack_ecache * +nf_ct_ecache_find(const struct nf_conn *ct) +{ +#ifdef CONFIG_NF_CONNTRACK_EVENTS + return nf_ct_ext_find(ct, NF_CT_EXT_ECACHE); +#else + return NULL; +#endif +} + +static inline struct nf_conntrack_ecache * +nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp) +{ +#ifdef CONFIG_NF_CONNTRACK_EVENTS + struct net *net = nf_ct_net(ct); + struct nf_conntrack_ecache *e; + + if (!ctmask && !expmask && net->ct.sysctl_events) { + ctmask = ~0; + expmask = ~0; + } + if (!ctmask && !expmask) + return NULL; + + e = nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp); + if (e) { + e->ctmask = ctmask; + e->expmask = expmask; + } + return e; +#else + return NULL; +#endif +}; + +#ifdef CONFIG_NF_CONNTRACK_EVENTS +/* This structure is passed to event handler */ +struct nf_ct_event { + struct nf_conn *ct; + u32 portid; + int report; +}; + +struct nf_ct_event_notifier { + int (*fcn)(unsigned int events, struct nf_ct_event *item); +}; + +int nf_conntrack_register_notifier(struct net *net, + struct nf_ct_event_notifier *nb); +void nf_conntrack_unregister_notifier(struct net *net, + struct nf_ct_event_notifier *nb); + +void nf_ct_deliver_cached_events(struct nf_conn *ct); + +static inline void +nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) +{ + struct net *net = nf_ct_net(ct); + struct nf_conntrack_ecache *e; + + if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb)) + return; + + e = nf_ct_ecache_find(ct); + if (e == NULL) + return; + + set_bit(event, &e->cache); +} + +static inline int +nf_conntrack_eventmask_report(unsigned int eventmask, + struct nf_conn *ct, + u32 portid, + int report) +{ + int ret = 0; + struct net *net = nf_ct_net(ct); + struct nf_ct_event_notifier *notify; + struct nf_conntrack_ecache *e; + + rcu_read_lock(); + notify = rcu_dereference(net->ct.nf_conntrack_event_cb); + if (notify == NULL) + goto out_unlock; + + e = nf_ct_ecache_find(ct); + if (e == NULL) + goto out_unlock; + + if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) { + struct nf_ct_event item = { + .ct = ct, + .portid = e->portid ? e->portid : portid, + .report = report + }; + /* This is a resent of a destroy event? If so, skip missed */ + unsigned long missed = e->portid ? 0 : e->missed; + + if (!((eventmask | missed) & e->ctmask)) + goto out_unlock; + + ret = notify->fcn(eventmask | missed, &item); + if (unlikely(ret < 0 || missed)) { + spin_lock_bh(&ct->lock); + if (ret < 0) { + /* This is a destroy event that has been + * triggered by a process, we store the PORTID + * to include it in the retransmission. */ + if (eventmask & (1 << IPCT_DESTROY) && + e->portid == 0 && portid != 0) + e->portid = portid; + else + e->missed |= eventmask; + } else + e->missed &= ~missed; + spin_unlock_bh(&ct->lock); + } + } +out_unlock: + rcu_read_unlock(); + return ret; +} + +static inline int +nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct, + u32 portid, int report) +{ + return nf_conntrack_eventmask_report(1 << event, ct, portid, report); +} + +static inline int +nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) +{ + return nf_conntrack_eventmask_report(1 << event, ct, 0, 0); +} + +struct nf_exp_event { + struct nf_conntrack_expect *exp; + u32 portid; + int report; +}; + +struct nf_exp_event_notifier { + int (*fcn)(unsigned int events, struct nf_exp_event *item); +}; + +int nf_ct_expect_register_notifier(struct net *net, + struct nf_exp_event_notifier *nb); +void nf_ct_expect_unregister_notifier(struct net *net, + struct nf_exp_event_notifier *nb); + +static inline void +nf_ct_expect_event_report(enum ip_conntrack_expect_events event, + struct nf_conntrack_expect *exp, + u32 portid, + int report) +{ + struct net *net = nf_ct_exp_net(exp); + struct nf_exp_event_notifier *notify; + struct nf_conntrack_ecache *e; + + rcu_read_lock(); + notify = rcu_dereference(net->ct.nf_expect_event_cb); + if (notify == NULL) + goto out_unlock; + + e = nf_ct_ecache_find(exp->master); + if (e == NULL) + goto out_unlock; + + if (e->expmask & (1 << event)) { + struct nf_exp_event item = { + .exp = exp, + .portid = portid, + .report = report + }; + notify->fcn(1 << event, &item); + } +out_unlock: + rcu_read_unlock(); +} + +static inline void +nf_ct_expect_event(enum ip_conntrack_expect_events event, + struct nf_conntrack_expect *exp) +{ + nf_ct_expect_event_report(event, exp, 0, 0); +} + +int nf_conntrack_ecache_pernet_init(struct net *net); +void nf_conntrack_ecache_pernet_fini(struct net *net); + +int nf_conntrack_ecache_init(void); +void nf_conntrack_ecache_fini(void); + +static inline void nf_conntrack_ecache_delayed_work(struct net *net) +{ + if (!delayed_work_pending(&net->ct.ecache_dwork)) { + schedule_delayed_work(&net->ct.ecache_dwork, HZ); + net->ct.ecache_dwork_pending = true; + } +} + +static inline void nf_conntrack_ecache_work(struct net *net) +{ + if (net->ct.ecache_dwork_pending) { + net->ct.ecache_dwork_pending = false; + mod_delayed_work(system_wq, &net->ct.ecache_dwork, 0); + } +} +#else /* CONFIG_NF_CONNTRACK_EVENTS */ +static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, + struct nf_conn *ct) {} +static inline int nf_conntrack_eventmask_report(unsigned int eventmask, + struct nf_conn *ct, + u32 portid, + int report) { return 0; } +static inline int nf_conntrack_event(enum ip_conntrack_events event, + struct nf_conn *ct) { return 0; } +static inline int nf_conntrack_event_report(enum ip_conntrack_events event, + struct nf_conn *ct, + u32 portid, + int report) { return 0; } +static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {} +static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event, + struct nf_conntrack_expect *exp) {} +static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e, + struct nf_conntrack_expect *exp, + u32 portid, + int report) {} + +static inline int nf_conntrack_ecache_pernet_init(struct net *net) +{ + return 0; +} + +static inline void nf_conntrack_ecache_pernet_fini(struct net *net) +{ +} + +static inline int nf_conntrack_ecache_init(void) +{ + return 0; +} + +static inline void nf_conntrack_ecache_fini(void) +{ +} + +static inline void nf_conntrack_ecache_delayed_work(struct net *net) +{ +} + +static inline void nf_conntrack_ecache_work(struct net *net) +{ +} +#endif /* CONFIG_NF_CONNTRACK_EVENTS */ + +#endif /*_NF_CONNTRACK_ECACHE_H*/ + diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h new file mode 100644 index 000000000..3f3aecbc8 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -0,0 +1,116 @@ +/* + * connection tracking expectations. + */ + +#ifndef _NF_CONNTRACK_EXPECT_H +#define _NF_CONNTRACK_EXPECT_H +#include + +extern unsigned int nf_ct_expect_hsize; +extern unsigned int nf_ct_expect_max; + +struct nf_conntrack_expect { + /* Conntrack expectation list member */ + struct hlist_node lnode; + + /* Hash member */ + struct hlist_node hnode; + + /* We expect this tuple, with the following mask */ + struct nf_conntrack_tuple tuple; + struct nf_conntrack_tuple_mask mask; + + /* Function to call after setup and insertion */ + void (*expectfn)(struct nf_conn *new, + struct nf_conntrack_expect *this); + + /* Helper to assign to new connection */ + struct nf_conntrack_helper *helper; + + /* The conntrack of the master connection */ + struct nf_conn *master; + + /* Timer function; deletes the expectation. */ + struct timer_list timeout; + + /* Usage count. */ + atomic_t use; + + /* Flags */ + unsigned int flags; + + /* Expectation class */ + unsigned int class; + +#ifdef CONFIG_NF_NAT_NEEDED + union nf_inet_addr saved_addr; + /* This is the original per-proto part, used to map the + * expected connection the way the recipient expects. */ + union nf_conntrack_man_proto saved_proto; + /* Direction relative to the master connection. */ + enum ip_conntrack_dir dir; +#endif + + struct rcu_head rcu; +}; + +static inline struct net *nf_ct_exp_net(struct nf_conntrack_expect *exp) +{ + return nf_ct_net(exp->master); +} + +#define NF_CT_EXP_POLICY_NAME_LEN 16 + +struct nf_conntrack_expect_policy { + unsigned int max_expected; + unsigned int timeout; + char name[NF_CT_EXP_POLICY_NAME_LEN]; +}; + +#define NF_CT_EXPECT_CLASS_DEFAULT 0 + +int nf_conntrack_expect_pernet_init(struct net *net); +void nf_conntrack_expect_pernet_fini(struct net *net); + +int nf_conntrack_expect_init(void); +void nf_conntrack_expect_fini(void); + +struct nf_conntrack_expect * +__nf_ct_expect_find(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); + +struct nf_conntrack_expect * +nf_ct_expect_find_get(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); + +struct nf_conntrack_expect * +nf_ct_find_expectation(struct net *net, u16 zone, + const struct nf_conntrack_tuple *tuple); + +void nf_ct_unlink_expect_report(struct nf_conntrack_expect *exp, + u32 portid, int report); +static inline void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) +{ + nf_ct_unlink_expect_report(exp, 0, 0); +} + +void nf_ct_remove_expectations(struct nf_conn *ct); +void nf_ct_unexpect_related(struct nf_conntrack_expect *exp); + +/* Allocate space for an expectation: this is mandatory before calling + nf_ct_expect_related. You will have to call put afterwards. */ +struct nf_conntrack_expect *nf_ct_expect_alloc(struct nf_conn *me); +void nf_ct_expect_init(struct nf_conntrack_expect *, unsigned int, u_int8_t, + const union nf_inet_addr *, + const union nf_inet_addr *, + u_int8_t, const __be16 *, const __be16 *); +void nf_ct_expect_put(struct nf_conntrack_expect *exp); +int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, + u32 portid, int report); +static inline int nf_ct_expect_related(struct nf_conntrack_expect *expect) +{ + return nf_ct_expect_related_report(expect, 0, 0); +} + +#endif /*_NF_CONNTRACK_EXPECT_H*/ + diff --git a/include/net/netfilter/nf_conntrack_extend.h b/include/net/netfilter/nf_conntrack_extend.h new file mode 100644 index 000000000..55d15049a --- /dev/null +++ b/include/net/netfilter/nf_conntrack_extend.h @@ -0,0 +1,123 @@ +#ifndef _NF_CONNTRACK_EXTEND_H +#define _NF_CONNTRACK_EXTEND_H + +#include + +#include + +enum nf_ct_ext_id { + NF_CT_EXT_HELPER, +#if defined(CONFIG_NF_NAT) || defined(CONFIG_NF_NAT_MODULE) + NF_CT_EXT_NAT, +#endif + NF_CT_EXT_SEQADJ, + NF_CT_EXT_ACCT, +#ifdef CONFIG_NF_CONNTRACK_EVENTS + NF_CT_EXT_ECACHE, +#endif +#ifdef CONFIG_NF_CONNTRACK_ZONES + NF_CT_EXT_ZONE, +#endif +#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP + NF_CT_EXT_TSTAMP, +#endif +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT + NF_CT_EXT_TIMEOUT, +#endif +#ifdef CONFIG_NF_CONNTRACK_LABELS + NF_CT_EXT_LABELS, +#endif +#if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY) + NF_CT_EXT_SYNPROXY, +#endif + NF_CT_EXT_NUM, +}; + +#define NF_CT_EXT_HELPER_TYPE struct nf_conn_help +#define NF_CT_EXT_NAT_TYPE struct nf_conn_nat +#define NF_CT_EXT_SEQADJ_TYPE struct nf_conn_seqadj +#define NF_CT_EXT_ACCT_TYPE struct nf_conn_acct +#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache +#define NF_CT_EXT_ZONE_TYPE struct nf_conntrack_zone +#define NF_CT_EXT_TSTAMP_TYPE struct nf_conn_tstamp +#define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout +#define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels +#define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy + +/* Extensions: optional stuff which isn't permanently in struct. */ +struct nf_ct_ext { + struct rcu_head rcu; + u16 offset[NF_CT_EXT_NUM]; + u16 len; + char data[0]; +}; + +static inline bool __nf_ct_ext_exist(const struct nf_ct_ext *ext, u8 id) +{ + return !!ext->offset[id]; +} + +static inline bool nf_ct_ext_exist(const struct nf_conn *ct, u8 id) +{ + return (ct->ext && __nf_ct_ext_exist(ct->ext, id)); +} + +static inline void *__nf_ct_ext_find(const struct nf_conn *ct, u8 id) +{ + if (!nf_ct_ext_exist(ct, id)) + return NULL; + + return (void *)ct->ext + ct->ext->offset[id]; +} +#define nf_ct_ext_find(ext, id) \ + ((id##_TYPE *)__nf_ct_ext_find((ext), (id))) + +/* Destroy all relationships */ +void __nf_ct_ext_destroy(struct nf_conn *ct); +static inline void nf_ct_ext_destroy(struct nf_conn *ct) +{ + if (ct->ext) + __nf_ct_ext_destroy(ct); +} + +/* Free operation. If you want to free a object referred from private area, + * please implement __nf_ct_ext_free() and call it. + */ +static inline void nf_ct_ext_free(struct nf_conn *ct) +{ + if (ct->ext) + kfree_rcu(ct->ext, rcu); +} + +/* Add this type, returns pointer to data or NULL. */ +void *__nf_ct_ext_add_length(struct nf_conn *ct, enum nf_ct_ext_id id, + size_t var_alloc_len, gfp_t gfp); + +#define nf_ct_ext_add(ct, id, gfp) \ + ((id##_TYPE *)__nf_ct_ext_add_length((ct), (id), 0, (gfp))) +#define nf_ct_ext_add_length(ct, id, len, gfp) \ + ((id##_TYPE *)__nf_ct_ext_add_length((ct), (id), (len), (gfp))) + +#define NF_CT_EXT_F_PREALLOC 0x0001 + +struct nf_ct_ext_type { + /* Destroys relationships (can be NULL). */ + void (*destroy)(struct nf_conn *ct); + /* Called when realloacted (can be NULL). + Contents has already been moved. */ + void (*move)(void *new, void *old); + + enum nf_ct_ext_id id; + + unsigned int flags; + + /* Length and min alignment. */ + u8 len; + u8 align; + /* initial size of nf_ct_ext. */ + u8 alloc_size; +}; + +int nf_ct_extend_register(struct nf_ct_ext_type *type); +void nf_ct_extend_unregister(struct nf_ct_ext_type *type); +#endif /* _NF_CONNTRACK_EXTEND_H */ diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h new file mode 100644 index 000000000..6cf614bc0 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -0,0 +1,119 @@ +/* + * connection tracking helpers. + * + * 16 Dec 2003: Yasuyuki Kozakai @USAGI + * - generalize L3 protocol dependent part. + * + * Derived from include/linux/netfiter_ipv4/ip_conntrack_helper.h + */ + +#ifndef _NF_CONNTRACK_HELPER_H +#define _NF_CONNTRACK_HELPER_H +#include +#include +#include + +struct module; + +enum nf_ct_helper_flags { + NF_CT_HELPER_F_USERSPACE = (1 << 0), + NF_CT_HELPER_F_CONFIGURED = (1 << 1), +}; + +#define NF_CT_HELPER_NAME_LEN 16 + +struct nf_conntrack_helper { + struct hlist_node hnode; /* Internal use. */ + + char name[NF_CT_HELPER_NAME_LEN]; /* name of the module */ + struct module *me; /* pointer to self */ + const struct nf_conntrack_expect_policy *expect_policy; + + /* length of internal data, ie. sizeof(struct nf_ct_*_master) */ + size_t data_len; + + /* Tuple of things we will help (compared against server response) */ + struct nf_conntrack_tuple tuple; + + /* Function to call when data passes; return verdict, or -1 to + invalidate. */ + int (*help)(struct sk_buff *skb, + unsigned int protoff, + struct nf_conn *ct, + enum ip_conntrack_info conntrackinfo); + + void (*destroy)(struct nf_conn *ct); + + int (*from_nlattr)(struct nlattr *attr, struct nf_conn *ct); + int (*to_nlattr)(struct sk_buff *skb, const struct nf_conn *ct); + unsigned int expect_class_max; + + unsigned int flags; + unsigned int queue_num; /* For user-space helpers. */ +}; + +struct nf_conntrack_helper *__nf_conntrack_helper_find(const char *name, + u16 l3num, u8 protonum); + +struct nf_conntrack_helper *nf_conntrack_helper_try_module_get(const char *name, + u16 l3num, + u8 protonum); + +int nf_conntrack_helper_register(struct nf_conntrack_helper *); +void nf_conntrack_helper_unregister(struct nf_conntrack_helper *); + +struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, + struct nf_conntrack_helper *helper, + gfp_t gfp); + +int __nf_ct_try_assign_helper(struct nf_conn *ct, struct nf_conn *tmpl, + gfp_t flags); + +void nf_ct_helper_destroy(struct nf_conn *ct); + +static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) +{ + return nf_ct_ext_find(ct, NF_CT_EXT_HELPER); +} + +static inline void *nfct_help_data(const struct nf_conn *ct) +{ + struct nf_conn_help *help; + + help = nf_ct_ext_find(ct, NF_CT_EXT_HELPER); + + return (void *)help->data; +} + +int nf_conntrack_helper_pernet_init(struct net *net); +void nf_conntrack_helper_pernet_fini(struct net *net); + +int nf_conntrack_helper_init(void); +void nf_conntrack_helper_fini(void); + +int nf_conntrack_broadcast_help(struct sk_buff *skb, unsigned int protoff, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int timeout); + +struct nf_ct_helper_expectfn { + struct list_head head; + const char *name; + void (*expectfn)(struct nf_conn *ct, struct nf_conntrack_expect *exp); +}; + +__printf(3,4) +void nf_ct_helper_log(struct sk_buff *skb, const struct nf_conn *ct, + const char *fmt, ...); + +void nf_ct_helper_expectfn_register(struct nf_ct_helper_expectfn *n); +void nf_ct_helper_expectfn_unregister(struct nf_ct_helper_expectfn *n); +struct nf_ct_helper_expectfn * +nf_ct_helper_expectfn_find_by_name(const char *name); +struct nf_ct_helper_expectfn * +nf_ct_helper_expectfn_find_by_symbol(const void *symbol); + +extern struct hlist_head *nf_ct_helper_hash; +extern unsigned int nf_ct_helper_hsize; + +#endif /*_NF_CONNTRACK_HELPER_H*/ diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h new file mode 100644 index 000000000..cdc920b4c --- /dev/null +++ b/include/net/netfilter/nf_conntrack_l3proto.h @@ -0,0 +1,102 @@ +/* + * Copyright (C)2003,2004 USAGI/WIDE Project + * + * Header for use in defining a given L3 protocol for connection tracking. + * + * Author: + * Yasuyuki Kozakai @USAGI + * + * Derived from include/netfilter_ipv4/ip_conntrack_protocol.h + */ + +#ifndef _NF_CONNTRACK_L3PROTO_H +#define _NF_CONNTRACK_L3PROTO_H +#include +#include +#include +#include + +struct nf_conntrack_l3proto { + /* L3 Protocol Family number. ex) PF_INET */ + u_int16_t l3proto; + + /* Protocol name */ + const char *name; + + /* + * Try to fill in the third arg: nhoff is offset of l3 proto + * hdr. Return true if possible. + */ + bool (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int nhoff, + struct nf_conntrack_tuple *tuple); + + /* + * Invert the per-proto part of the tuple: ie. turn xmit into reply. + * Some packets can't be inverted: return 0 in that case. + */ + bool (*invert_tuple)(struct nf_conntrack_tuple *inverse, + const struct nf_conntrack_tuple *orig); + + /* Print out the per-protocol part of the tuple. */ + void (*print_tuple)(struct seq_file *s, + const struct nf_conntrack_tuple *); + + /* + * Called before tracking. + * *dataoff: offset of protocol header (TCP, UDP,...) in skb + * *protonum: protocol number + */ + int (*get_l4proto)(const struct sk_buff *skb, unsigned int nhoff, + unsigned int *dataoff, u_int8_t *protonum); + + int (*tuple_to_nlattr)(struct sk_buff *skb, + const struct nf_conntrack_tuple *t); + + /* + * Calculate size of tuple nlattr + */ + int (*nlattr_tuple_size)(void); + + int (*nlattr_to_tuple)(struct nlattr *tb[], + struct nf_conntrack_tuple *t); + const struct nla_policy *nla_policy; + + size_t nla_size; + +#ifdef CONFIG_SYSCTL + const char *ctl_table_path; +#endif /* CONFIG_SYSCTL */ + + /* Init l3proto pernet data */ + int (*init_net)(struct net *net); + + /* Module (if any) which this is connected to. */ + struct module *me; +}; + +extern struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[AF_MAX]; + +/* Protocol pernet registration. */ +int nf_ct_l3proto_pernet_register(struct net *net, + struct nf_conntrack_l3proto *proto); +void nf_ct_l3proto_pernet_unregister(struct net *net, + struct nf_conntrack_l3proto *proto); + +/* Protocol global registration. */ +int nf_ct_l3proto_register(struct nf_conntrack_l3proto *proto); +void nf_ct_l3proto_unregister(struct nf_conntrack_l3proto *proto); + +struct nf_conntrack_l3proto *nf_ct_l3proto_find_get(u_int16_t l3proto); + +/* Existing built-in protocols */ +extern struct nf_conntrack_l3proto nf_conntrack_l3proto_generic; + +static inline struct nf_conntrack_l3proto * +__nf_ct_l3proto_find(u_int16_t l3proto) +{ + if (unlikely(l3proto >= AF_MAX)) + return &nf_conntrack_l3proto_generic; + return rcu_dereference(nf_ct_l3protos[l3proto]); +} + +#endif /*_NF_CONNTRACK_L3PROTO_H*/ diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h new file mode 100644 index 000000000..1f7061313 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -0,0 +1,158 @@ +/* + * Header for use in defining a given L4 protocol for connection tracking. + * + * 16 Dec 2003: Yasuyuki Kozakai @USAGI + * - generalized L3 protocol dependent part. + * + * Derived from include/linux/netfiter_ipv4/ip_conntrack_protcol.h + */ + +#ifndef _NF_CONNTRACK_L4PROTO_H +#define _NF_CONNTRACK_L4PROTO_H +#include +#include +#include +#include + +struct seq_file; + +struct nf_conntrack_l4proto { + /* L3 Protocol number. */ + u_int16_t l3proto; + + /* L4 Protocol number. */ + u_int8_t l4proto; + + /* Try to fill in the third arg: dataoff is offset past network protocol + hdr. Return true if possible. */ + bool (*pkt_to_tuple)(const struct sk_buff *skb, unsigned int dataoff, + struct nf_conntrack_tuple *tuple); + + /* Invert the per-proto part of the tuple: ie. turn xmit into reply. + * Some packets can't be inverted: return 0 in that case. + */ + bool (*invert_tuple)(struct nf_conntrack_tuple *inverse, + const struct nf_conntrack_tuple *orig); + + /* Returns verdict for packet, or -1 for invalid. */ + int (*packet)(struct nf_conn *ct, + const struct sk_buff *skb, + unsigned int dataoff, + enum ip_conntrack_info ctinfo, + u_int8_t pf, + unsigned int hooknum, + unsigned int *timeouts); + + /* Called when a new connection for this protocol found; + * returns TRUE if it's OK. If so, packet() called next. */ + bool (*new)(struct nf_conn *ct, const struct sk_buff *skb, + unsigned int dataoff, unsigned int *timeouts); + + /* Called when a conntrack entry is destroyed */ + void (*destroy)(struct nf_conn *ct); + + int (*error)(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, + unsigned int dataoff, enum ip_conntrack_info *ctinfo, + u_int8_t pf, unsigned int hooknum); + + /* Print out the per-protocol part of the tuple. Return like seq_* */ + void (*print_tuple)(struct seq_file *s, + const struct nf_conntrack_tuple *); + + /* Print out the private part of the conntrack. */ + void (*print_conntrack)(struct seq_file *s, struct nf_conn *); + + /* Return the array of timeouts for this protocol. */ + unsigned int *(*get_timeouts)(struct net *net); + + /* convert protoinfo to nfnetink attributes */ + int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla, + struct nf_conn *ct); + /* Calculate protoinfo nlattr size */ + int (*nlattr_size)(void); + + /* convert nfnetlink attributes to protoinfo */ + int (*from_nlattr)(struct nlattr *tb[], struct nf_conn *ct); + + int (*tuple_to_nlattr)(struct sk_buff *skb, + const struct nf_conntrack_tuple *t); + /* Calculate tuple nlattr size */ + int (*nlattr_tuple_size)(void); + int (*nlattr_to_tuple)(struct nlattr *tb[], + struct nf_conntrack_tuple *t); + const struct nla_policy *nla_policy; + + size_t nla_size; + +#if IS_ENABLED(CONFIG_NF_CT_NETLINK_TIMEOUT) + struct { + size_t obj_size; + int (*nlattr_to_obj)(struct nlattr *tb[], + struct net *net, void *data); + int (*obj_to_nlattr)(struct sk_buff *skb, const void *data); + + unsigned int nlattr_max; + const struct nla_policy *nla_policy; + } ctnl_timeout; +#endif + int *net_id; + /* Init l4proto pernet data */ + int (*init_net)(struct net *net, u_int16_t proto); + + /* Return the per-net protocol part. */ + struct nf_proto_net *(*get_net_proto)(struct net *net); + + /* Protocol name */ + const char *name; + + /* Module (if any) which this is connected to. */ + struct module *me; +}; + +/* Existing built-in generic protocol */ +extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; + +#define MAX_NF_CT_PROTO 256 + +struct nf_conntrack_l4proto *__nf_ct_l4proto_find(u_int16_t l3proto, + u_int8_t l4proto); + +struct nf_conntrack_l4proto *nf_ct_l4proto_find_get(u_int16_t l3proto, + u_int8_t l4proto); +void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p); + +/* Protocol pernet registration. */ +int nf_ct_l4proto_pernet_register(struct net *net, + struct nf_conntrack_l4proto *proto); +void nf_ct_l4proto_pernet_unregister(struct net *net, + struct nf_conntrack_l4proto *proto); + +/* Protocol global registration. */ +int nf_ct_l4proto_register(struct nf_conntrack_l4proto *proto); +void nf_ct_l4proto_unregister(struct nf_conntrack_l4proto *proto); + +static inline void nf_ct_kfree_compat_sysctl_table(struct nf_proto_net *pn) +{ +#if defined(CONFIG_SYSCTL) && defined(CONFIG_NF_CONNTRACK_PROC_COMPAT) + kfree(pn->ctl_compat_table); + pn->ctl_compat_table = NULL; +#endif +} + +/* Generic netlink helpers */ +int nf_ct_port_tuple_to_nlattr(struct sk_buff *skb, + const struct nf_conntrack_tuple *tuple); +int nf_ct_port_nlattr_to_tuple(struct nlattr *tb[], + struct nf_conntrack_tuple *t); +int nf_ct_port_nlattr_tuple_size(void); +extern const struct nla_policy nf_ct_port_nla_policy[]; + +#ifdef CONFIG_SYSCTL +#define LOG_INVALID(net, proto) \ + ((net)->ct.sysctl_log_invalid == (proto) || \ + (net)->ct.sysctl_log_invalid == IPPROTO_RAW) +#else +static inline int LOG_INVALID(struct net *net, int proto) { return 0; } +#endif /* CONFIG_SYSCTL */ + +#endif /*_NF_CONNTRACK_PROTOCOL_H*/ diff --git a/include/net/netfilter/nf_conntrack_labels.h b/include/net/netfilter/nf_conntrack_labels.h new file mode 100644 index 000000000..dec6336bf --- /dev/null +++ b/include/net/netfilter/nf_conntrack_labels.h @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include + +#include + +#define NF_CT_LABELS_MAX_SIZE ((XT_CONNLABEL_MAXBIT + 1) / BITS_PER_BYTE) + +struct nf_conn_labels { + u8 words; + unsigned long bits[]; +}; + +static inline struct nf_conn_labels *nf_ct_labels_find(const struct nf_conn *ct) +{ +#ifdef CONFIG_NF_CONNTRACK_LABELS + return nf_ct_ext_find(ct, NF_CT_EXT_LABELS); +#else + return NULL; +#endif +} + +static inline struct nf_conn_labels *nf_ct_labels_ext_add(struct nf_conn *ct) +{ +#ifdef CONFIG_NF_CONNTRACK_LABELS + struct nf_conn_labels *cl_ext; + struct net *net = nf_ct_net(ct); + u8 words; + + words = ACCESS_ONCE(net->ct.label_words); + if (words == 0) + return NULL; + + cl_ext = nf_ct_ext_add_length(ct, NF_CT_EXT_LABELS, + words * sizeof(long), GFP_ATOMIC); + if (cl_ext != NULL) + cl_ext->words = words; + + return cl_ext; +#else + return NULL; +#endif +} + +bool nf_connlabel_match(const struct nf_conn *ct, u16 bit); +int nf_connlabel_set(struct nf_conn *ct, u16 bit); + +int nf_connlabels_replace(struct nf_conn *ct, + const u32 *data, const u32 *mask, unsigned int words); + +#ifdef CONFIG_NF_CONNTRACK_LABELS +int nf_conntrack_labels_init(void); +void nf_conntrack_labels_fini(void); +#else +static inline int nf_conntrack_labels_init(void) { return 0; } +static inline void nf_conntrack_labels_fini(void) {} +#endif diff --git a/include/net/netfilter/nf_conntrack_seqadj.h b/include/net/netfilter/nf_conntrack_seqadj.h new file mode 100644 index 000000000..4b3362991 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_seqadj.h @@ -0,0 +1,47 @@ +#ifndef _NF_CONNTRACK_SEQADJ_H +#define _NF_CONNTRACK_SEQADJ_H + +#include + +/** + * struct nf_ct_seqadj - sequence number adjustment information + * + * @correction_pos: position of the last TCP sequence number modification + * @offset_before: sequence number offset before last modification + * @offset_after: sequence number offset after last modification + */ +struct nf_ct_seqadj { + u32 correction_pos; + s32 offset_before; + s32 offset_after; +}; + +struct nf_conn_seqadj { + struct nf_ct_seqadj seq[IP_CT_DIR_MAX]; +}; + +static inline struct nf_conn_seqadj *nfct_seqadj(const struct nf_conn *ct) +{ + return nf_ct_ext_find(ct, NF_CT_EXT_SEQADJ); +} + +static inline struct nf_conn_seqadj *nfct_seqadj_ext_add(struct nf_conn *ct) +{ + return nf_ct_ext_add(ct, NF_CT_EXT_SEQADJ, GFP_ATOMIC); +} + +int nf_ct_seqadj_init(struct nf_conn *ct, enum ip_conntrack_info ctinfo, + s32 off); +int nf_ct_seqadj_set(struct nf_conn *ct, enum ip_conntrack_info ctinfo, + __be32 seq, s32 off); +void nf_ct_tcp_seqadj_set(struct sk_buff *skb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, s32 off); + +int nf_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, unsigned int protoff); +s32 nf_ct_seq_offset(const struct nf_conn *ct, enum ip_conntrack_dir, u32 seq); + +int nf_conntrack_seqadj_init(void); +void nf_conntrack_seqadj_fini(void); + +#endif /* _NF_CONNTRACK_SEQADJ_H */ diff --git a/include/net/netfilter/nf_conntrack_synproxy.h b/include/net/netfilter/nf_conntrack_synproxy.h new file mode 100644 index 000000000..6793614e6 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_synproxy.h @@ -0,0 +1,75 @@ +#ifndef _NF_CONNTRACK_SYNPROXY_H +#define _NF_CONNTRACK_SYNPROXY_H + +#include + +struct nf_conn_synproxy { + u32 isn; + u32 its; + u32 tsoff; +}; + +static inline struct nf_conn_synproxy *nfct_synproxy(const struct nf_conn *ct) +{ +#if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY) + return nf_ct_ext_find(ct, NF_CT_EXT_SYNPROXY); +#else + return NULL; +#endif +} + +static inline struct nf_conn_synproxy *nfct_synproxy_ext_add(struct nf_conn *ct) +{ +#if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY) + return nf_ct_ext_add(ct, NF_CT_EXT_SYNPROXY, GFP_ATOMIC); +#else + return NULL; +#endif +} + +struct synproxy_stats { + unsigned int syn_received; + unsigned int cookie_invalid; + unsigned int cookie_valid; + unsigned int cookie_retrans; + unsigned int conn_reopened; +}; + +struct synproxy_net { + struct nf_conn *tmpl; + struct synproxy_stats __percpu *stats; +}; + +extern int synproxy_net_id; +static inline struct synproxy_net *synproxy_pernet(struct net *net) +{ + return net_generic(net, synproxy_net_id); +} + +struct synproxy_options { + u8 options; + u8 wscale; + u16 mss; + u32 tsval; + u32 tsecr; +}; + +struct tcphdr; +struct xt_synproxy_info; +bool synproxy_parse_options(const struct sk_buff *skb, unsigned int doff, + const struct tcphdr *th, + struct synproxy_options *opts); +unsigned int synproxy_options_size(const struct synproxy_options *opts); +void synproxy_build_options(struct tcphdr *th, + const struct synproxy_options *opts); + +void synproxy_init_timestamp_cookie(const struct xt_synproxy_info *info, + struct synproxy_options *opts); +void synproxy_check_timestamp_cookie(struct synproxy_options *opts); + +unsigned int synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff, + struct tcphdr *th, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + const struct nf_conn_synproxy *synproxy); + +#endif /* _NF_CONNTRACK_SYNPROXY_H */ diff --git a/include/net/netfilter/nf_conntrack_timeout.h b/include/net/netfilter/nf_conntrack_timeout.h new file mode 100644 index 000000000..62308713d --- /dev/null +++ b/include/net/netfilter/nf_conntrack_timeout.h @@ -0,0 +1,98 @@ +#ifndef _NF_CONNTRACK_TIMEOUT_H +#define _NF_CONNTRACK_TIMEOUT_H + +#include +#include +#include +#include +#include + +#define CTNL_TIMEOUT_NAME_MAX 32 + +struct ctnl_timeout { + struct list_head head; + struct rcu_head rcu_head; + atomic_t refcnt; + char name[CTNL_TIMEOUT_NAME_MAX]; + __u16 l3num; + struct nf_conntrack_l4proto *l4proto; + char data[0]; +}; + +struct nf_conn_timeout { + struct ctnl_timeout *timeout; +}; + +#define NF_CT_TIMEOUT_EXT_DATA(__t) (unsigned int *) &((__t)->timeout->data) + +static inline +struct nf_conn_timeout *nf_ct_timeout_find(const struct nf_conn *ct) +{ +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT + return nf_ct_ext_find(ct, NF_CT_EXT_TIMEOUT); +#else + return NULL; +#endif +} + +static inline +struct nf_conn_timeout *nf_ct_timeout_ext_add(struct nf_conn *ct, + struct ctnl_timeout *timeout, + gfp_t gfp) +{ +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT + struct nf_conn_timeout *timeout_ext; + + timeout_ext = nf_ct_ext_add(ct, NF_CT_EXT_TIMEOUT, gfp); + if (timeout_ext == NULL) + return NULL; + + timeout_ext->timeout = timeout; + + return timeout_ext; +#else + return NULL; +#endif +}; + +static inline unsigned int * +nf_ct_timeout_lookup(struct net *net, struct nf_conn *ct, + struct nf_conntrack_l4proto *l4proto) +{ +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT + struct nf_conn_timeout *timeout_ext; + unsigned int *timeouts; + + timeout_ext = nf_ct_timeout_find(ct); + if (timeout_ext) + timeouts = NF_CT_TIMEOUT_EXT_DATA(timeout_ext); + else + timeouts = l4proto->get_timeouts(net); + + return timeouts; +#else + return l4proto->get_timeouts(net); +#endif +} + +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT +int nf_conntrack_timeout_init(void); +void nf_conntrack_timeout_fini(void); +#else +static inline int nf_conntrack_timeout_init(void) +{ + return 0; +} + +static inline void nf_conntrack_timeout_fini(void) +{ + return; +} +#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */ + +#ifdef CONFIG_NF_CONNTRACK_TIMEOUT +extern struct ctnl_timeout *(*nf_ct_timeout_find_get_hook)(const char *name); +extern void (*nf_ct_timeout_put_hook)(struct ctnl_timeout *timeout); +#endif + +#endif /* _NF_CONNTRACK_TIMEOUT_H */ diff --git a/include/net/netfilter/nf_conntrack_timestamp.h b/include/net/netfilter/nf_conntrack_timestamp.h new file mode 100644 index 000000000..300ae2209 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_timestamp.h @@ -0,0 +1,78 @@ +#ifndef _NF_CONNTRACK_TSTAMP_H +#define _NF_CONNTRACK_TSTAMP_H + +#include +#include +#include +#include +#include + +struct nf_conn_tstamp { + u_int64_t start; + u_int64_t stop; +}; + +static inline +struct nf_conn_tstamp *nf_conn_tstamp_find(const struct nf_conn *ct) +{ +#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP + return nf_ct_ext_find(ct, NF_CT_EXT_TSTAMP); +#else + return NULL; +#endif +} + +static inline +struct nf_conn_tstamp *nf_ct_tstamp_ext_add(struct nf_conn *ct, gfp_t gfp) +{ +#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP + struct net *net = nf_ct_net(ct); + + if (!net->ct.sysctl_tstamp) + return NULL; + + return nf_ct_ext_add(ct, NF_CT_EXT_TSTAMP, gfp); +#else + return NULL; +#endif +}; + +static inline bool nf_ct_tstamp_enabled(struct net *net) +{ + return net->ct.sysctl_tstamp != 0; +} + +static inline void nf_ct_set_tstamp(struct net *net, bool enable) +{ + net->ct.sysctl_tstamp = enable; +} + +#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP +int nf_conntrack_tstamp_pernet_init(struct net *net); +void nf_conntrack_tstamp_pernet_fini(struct net *net); + +int nf_conntrack_tstamp_init(void); +void nf_conntrack_tstamp_fini(void); +#else +static inline int nf_conntrack_tstamp_pernet_init(struct net *net) +{ + return 0; +} + +static inline void nf_conntrack_tstamp_pernet_fini(struct net *net) +{ + return; +} + +static inline int nf_conntrack_tstamp_init(void) +{ + return 0; +} + +static inline void nf_conntrack_tstamp_fini(void) +{ + return; +} +#endif /* CONFIG_NF_CONNTRACK_TIMESTAMP */ + +#endif /* _NF_CONNTRACK_TSTAMP_H */ diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h new file mode 100644 index 000000000..aea3f8221 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_tuple.h @@ -0,0 +1,186 @@ +/* + * Definitions and Declarations for tuple. + * + * 16 Dec 2003: Yasuyuki Kozakai @USAGI + * - generalize L3 protocol dependent part. + * + * Derived from include/linux/netfiter_ipv4/ip_conntrack_tuple.h + */ + +#ifndef _NF_CONNTRACK_TUPLE_H +#define _NF_CONNTRACK_TUPLE_H + +#include +#include +#include + +/* A `tuple' is a structure containing the information to uniquely + identify a connection. ie. if two packets have the same tuple, they + are in the same connection; if not, they are not. + + We divide the structure along "manipulatable" and + "non-manipulatable" lines, for the benefit of the NAT code. +*/ + +#define NF_CT_TUPLE_L3SIZE ARRAY_SIZE(((union nf_inet_addr *)NULL)->all) + +/* The manipulable part of the tuple. */ +struct nf_conntrack_man { + union nf_inet_addr u3; + union nf_conntrack_man_proto u; + /* Layer 3 protocol */ + u_int16_t l3num; +}; + +/* This contains the information to distinguish a connection. */ +struct nf_conntrack_tuple { + struct nf_conntrack_man src; + + /* These are the parts of the tuple which are fixed. */ + struct { + union nf_inet_addr u3; + union { + /* Add other protocols here. */ + __be16 all; + + struct { + __be16 port; + } tcp; + struct { + __be16 port; + } udp; + struct { + u_int8_t type, code; + } icmp; + struct { + __be16 port; + } dccp; + struct { + __be16 port; + } sctp; + struct { + __be16 key; + } gre; + } u; + + /* The protocol. */ + u_int8_t protonum; + + /* The direction (for tuplehash) */ + u_int8_t dir; + } dst; +}; + +struct nf_conntrack_tuple_mask { + struct { + union nf_inet_addr u3; + union nf_conntrack_man_proto u; + } src; +}; + +static inline void nf_ct_dump_tuple_ip(const struct nf_conntrack_tuple *t) +{ +#ifdef DEBUG + printk("tuple %p: %u %pI4:%hu -> %pI4:%hu\n", + t, t->dst.protonum, + &t->src.u3.ip, ntohs(t->src.u.all), + &t->dst.u3.ip, ntohs(t->dst.u.all)); +#endif +} + +static inline void nf_ct_dump_tuple_ipv6(const struct nf_conntrack_tuple *t) +{ +#ifdef DEBUG + printk("tuple %p: %u %pI6 %hu -> %pI6 %hu\n", + t, t->dst.protonum, + t->src.u3.all, ntohs(t->src.u.all), + t->dst.u3.all, ntohs(t->dst.u.all)); +#endif +} + +static inline void nf_ct_dump_tuple(const struct nf_conntrack_tuple *t) +{ + switch (t->src.l3num) { + case AF_INET: + nf_ct_dump_tuple_ip(t); + break; + case AF_INET6: + nf_ct_dump_tuple_ipv6(t); + break; + } +} + +/* If we're the first tuple, it's the original dir. */ +#define NF_CT_DIRECTION(h) \ + ((enum ip_conntrack_dir)(h)->tuple.dst.dir) + +/* Connections have two entries in the hash table: one for each way */ +struct nf_conntrack_tuple_hash { + struct hlist_nulls_node hnnode; + struct nf_conntrack_tuple tuple; +}; + +static inline bool __nf_ct_tuple_src_equal(const struct nf_conntrack_tuple *t1, + const struct nf_conntrack_tuple *t2) +{ + return (nf_inet_addr_cmp(&t1->src.u3, &t2->src.u3) && + t1->src.u.all == t2->src.u.all && + t1->src.l3num == t2->src.l3num); +} + +static inline bool __nf_ct_tuple_dst_equal(const struct nf_conntrack_tuple *t1, + const struct nf_conntrack_tuple *t2) +{ + return (nf_inet_addr_cmp(&t1->dst.u3, &t2->dst.u3) && + t1->dst.u.all == t2->dst.u.all && + t1->dst.protonum == t2->dst.protonum); +} + +static inline bool nf_ct_tuple_equal(const struct nf_conntrack_tuple *t1, + const struct nf_conntrack_tuple *t2) +{ + return __nf_ct_tuple_src_equal(t1, t2) && + __nf_ct_tuple_dst_equal(t1, t2); +} + +static inline bool +nf_ct_tuple_mask_equal(const struct nf_conntrack_tuple_mask *m1, + const struct nf_conntrack_tuple_mask *m2) +{ + return (nf_inet_addr_cmp(&m1->src.u3, &m2->src.u3) && + m1->src.u.all == m2->src.u.all); +} + +static inline bool +nf_ct_tuple_src_mask_cmp(const struct nf_conntrack_tuple *t1, + const struct nf_conntrack_tuple *t2, + const struct nf_conntrack_tuple_mask *mask) +{ + int count; + + for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++) { + if ((t1->src.u3.all[count] ^ t2->src.u3.all[count]) & + mask->src.u3.all[count]) + return false; + } + + if ((t1->src.u.all ^ t2->src.u.all) & mask->src.u.all) + return false; + + if (t1->src.l3num != t2->src.l3num || + t1->dst.protonum != t2->dst.protonum) + return false; + + return true; +} + +static inline bool +nf_ct_tuple_mask_cmp(const struct nf_conntrack_tuple *t, + const struct nf_conntrack_tuple *tuple, + const struct nf_conntrack_tuple_mask *mask) +{ + return nf_ct_tuple_src_mask_cmp(t, tuple, mask) && + __nf_ct_tuple_dst_equal(t, tuple); +} + +#endif /* _NF_CONNTRACK_TUPLE_H */ diff --git a/include/net/netfilter/nf_conntrack_zones.h b/include/net/netfilter/nf_conntrack_zones.h new file mode 100644 index 000000000..034efe8d4 --- /dev/null +++ b/include/net/netfilter/nf_conntrack_zones.h @@ -0,0 +1,25 @@ +#ifndef _NF_CONNTRACK_ZONES_H +#define _NF_CONNTRACK_ZONES_H + +#define NF_CT_DEFAULT_ZONE 0 + +#if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) +#include + +struct nf_conntrack_zone { + u16 id; +}; + +static inline u16 nf_ct_zone(const struct nf_conn *ct) +{ +#ifdef CONFIG_NF_CONNTRACK_ZONES + struct nf_conntrack_zone *nf_ct_zone; + nf_ct_zone = nf_ct_ext_find(ct, NF_CT_EXT_ZONE); + if (nf_ct_zone) + return nf_ct_zone->id; +#endif + return NF_CT_DEFAULT_ZONE; +} + +#endif /* CONFIG_NF_CONNTRACK || CONFIG_NF_CONNTRACK_MODULE */ +#endif /* _NF_CONNTRACK_ZONES_H */ diff --git a/include/net/netfilter/nf_log.h b/include/net/netfilter/nf_log.h new file mode 100644 index 000000000..57639fca2 --- /dev/null +++ b/include/net/netfilter/nf_log.h @@ -0,0 +1,112 @@ +#ifndef _NF_LOG_H +#define _NF_LOG_H + +#include + +/* those NF_LOG_* defines and struct nf_loginfo are legacy definitios that will + * disappear once iptables is replaced with pkttables. Please DO NOT use them + * for any new code! */ +#define NF_LOG_TCPSEQ 0x01 /* Log TCP sequence numbers */ +#define NF_LOG_TCPOPT 0x02 /* Log TCP options */ +#define NF_LOG_IPOPT 0x04 /* Log IP options */ +#define NF_LOG_UID 0x08 /* Log UID owning local socket */ +#define NF_LOG_MASK 0x0f + +enum nf_log_type { + NF_LOG_TYPE_LOG = 0, + NF_LOG_TYPE_ULOG, + NF_LOG_TYPE_MAX +}; + +struct nf_loginfo { + u_int8_t type; + union { + struct { + u_int32_t copy_len; + u_int16_t group; + u_int16_t qthreshold; + } ulog; + struct { + u_int8_t level; + u_int8_t logflags; + } log; + } u; +}; + +typedef void nf_logfn(struct net *net, + u_int8_t pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *li, + const char *prefix); + +struct nf_logger { + char *name; + enum nf_log_type type; + nf_logfn *logfn; + struct module *me; +}; + +/* Function to register/unregister log function. */ +int nf_log_register(u_int8_t pf, struct nf_logger *logger); +void nf_log_unregister(struct nf_logger *logger); + +void nf_log_set(struct net *net, u_int8_t pf, + const struct nf_logger *logger); +void nf_log_unset(struct net *net, const struct nf_logger *logger); + +int nf_log_bind_pf(struct net *net, u_int8_t pf, + const struct nf_logger *logger); +void nf_log_unbind_pf(struct net *net, u_int8_t pf); + +int nf_logger_find_get(int pf, enum nf_log_type type); +void nf_logger_put(int pf, enum nf_log_type type); +void nf_logger_request_module(int pf, enum nf_log_type type); + +#define MODULE_ALIAS_NF_LOGGER(family, type) \ + MODULE_ALIAS("nf-logger-" __stringify(family) "-" __stringify(type)) + +/* Calls the registered backend logging function */ +__printf(8, 9) +void nf_log_packet(struct net *net, + u_int8_t pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *li, + const char *fmt, ...); + +__printf(8, 9) +void nf_log_trace(struct net *net, + u_int8_t pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *li, + const char *fmt, ...); + +struct nf_log_buf; + +struct nf_log_buf *nf_log_buf_open(void); +__printf(2, 3) int nf_log_buf_add(struct nf_log_buf *m, const char *f, ...); +void nf_log_buf_close(struct nf_log_buf *m); + +/* common logging functions */ +int nf_log_dump_udp_header(struct nf_log_buf *m, const struct sk_buff *skb, + u8 proto, int fragment, unsigned int offset); +int nf_log_dump_tcp_header(struct nf_log_buf *m, const struct sk_buff *skb, + u8 proto, int fragment, unsigned int offset, + unsigned int logflags); +void nf_log_dump_sk_uid_gid(struct nf_log_buf *m, struct sock *sk); +void nf_log_dump_packet_common(struct nf_log_buf *m, u_int8_t pf, + unsigned int hooknum, const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *loginfo, + const char *prefix); + +#endif /* _NF_LOG_H */ diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h new file mode 100644 index 000000000..344b1ab19 --- /dev/null +++ b/include/net/netfilter/nf_nat.h @@ -0,0 +1,79 @@ +#ifndef _NF_NAT_H +#define _NF_NAT_H +#include +#include +#include + +enum nf_nat_manip_type { + NF_NAT_MANIP_SRC, + NF_NAT_MANIP_DST +}; + +/* SRC manip occurs POST_ROUTING or LOCAL_IN */ +#define HOOK2MANIP(hooknum) ((hooknum) != NF_INET_POST_ROUTING && \ + (hooknum) != NF_INET_LOCAL_IN) + +#include +#include +#include + +/* per conntrack: nat application helper private data */ +union nf_conntrack_nat_help { + /* insert nat helper private data here */ +#if defined(CONFIG_NF_NAT_PPTP) || defined(CONFIG_NF_NAT_PPTP_MODULE) + struct nf_nat_pptp nat_pptp_info; +#endif +}; + +struct nf_conn; + +/* The structure embedded in the conntrack structure. */ +struct nf_conn_nat { + struct hlist_node bysource; + struct nf_conn *ct; + union nf_conntrack_nat_help help; +#if IS_ENABLED(CONFIG_NF_NAT_MASQUERADE_IPV4) || \ + IS_ENABLED(CONFIG_NF_NAT_MASQUERADE_IPV6) + int masq_index; +#endif +}; + +/* Set up the info structure to map into this range. */ +unsigned int nf_nat_setup_info(struct nf_conn *ct, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype); + +extern unsigned int nf_nat_alloc_null_binding(struct nf_conn *ct, + unsigned int hooknum); + +struct nf_conn_nat *nf_ct_nat_ext_add(struct nf_conn *ct); + +/* Is this tuple already taken? (not by us)*/ +int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, + const struct nf_conn *ignored_conntrack); + +static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct) +{ +#if defined(CONFIG_NF_NAT) || defined(CONFIG_NF_NAT_MODULE) + return nf_ct_ext_find(ct, NF_CT_EXT_NAT); +#else + return NULL; +#endif +} + +static inline bool nf_nat_oif_changed(unsigned int hooknum, + enum ip_conntrack_info ctinfo, + struct nf_conn_nat *nat, + const struct net_device *out) +{ +#if IS_ENABLED(CONFIG_NF_NAT_MASQUERADE_IPV4) || \ + IS_ENABLED(CONFIG_NF_NAT_MASQUERADE_IPV6) + return nat->masq_index && hooknum == NF_INET_POST_ROUTING && + CTINFO2DIR(ctinfo) == IP_CT_DIR_ORIGINAL && + nat->masq_index != out->ifindex; +#else + return false; +#endif +} + +#endif diff --git a/include/net/netfilter/nf_nat_core.h b/include/net/netfilter/nf_nat_core.h new file mode 100644 index 000000000..fbfd1ba42 --- /dev/null +++ b/include/net/netfilter/nf_nat_core.h @@ -0,0 +1,31 @@ +#ifndef _NF_NAT_CORE_H +#define _NF_NAT_CORE_H +#include +#include +#include + +/* This header used to share core functionality between the standalone + NAT module, and the compatibility layer's use of NAT for masquerading. */ + +unsigned int nf_nat_packet(struct nf_conn *ct, enum ip_conntrack_info ctinfo, + unsigned int hooknum, struct sk_buff *skb); + +int nf_xfrm_me_harder(struct sk_buff *skb, unsigned int family); + +static inline int nf_nat_initialized(struct nf_conn *ct, + enum nf_nat_manip_type manip) +{ + if (manip == NF_NAT_MANIP_SRC) + return ct->status & IPS_SRC_NAT_DONE; + else + return ct->status & IPS_DST_NAT_DONE; +} + +struct nlattr; + +extern int +(*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct, + enum nf_nat_manip_type manip, + const struct nlattr *attr); + +#endif /* _NF_NAT_CORE_H */ diff --git a/include/net/netfilter/nf_nat_helper.h b/include/net/netfilter/nf_nat_helper.h new file mode 100644 index 000000000..01bcc6bfb --- /dev/null +++ b/include/net/netfilter/nf_nat_helper.h @@ -0,0 +1,40 @@ +#ifndef _NF_NAT_HELPER_H +#define _NF_NAT_HELPER_H +/* NAT protocol helper routines. */ + +#include + +struct sk_buff; + +/* These return true or false. */ +int __nf_nat_mangle_tcp_packet(struct sk_buff *skb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int protoff, unsigned int match_offset, + unsigned int match_len, const char *rep_buffer, + unsigned int rep_len, bool adjust); + +static inline int nf_nat_mangle_tcp_packet(struct sk_buff *skb, + struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int protoff, + unsigned int match_offset, + unsigned int match_len, + const char *rep_buffer, + unsigned int rep_len) +{ + return __nf_nat_mangle_tcp_packet(skb, ct, ctinfo, protoff, + match_offset, match_len, + rep_buffer, rep_len, true); +} + +int nf_nat_mangle_udp_packet(struct sk_buff *skb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int protoff, unsigned int match_offset, + unsigned int match_len, const char *rep_buffer, + unsigned int rep_len); + +/* Setup NAT on this expected conntrack so it follows master, but goes + * to port ct->master->saved_proto. */ +void nf_nat_follow_master(struct nf_conn *ct, struct nf_conntrack_expect *this); + +#endif diff --git a/include/net/netfilter/nf_nat_l3proto.h b/include/net/netfilter/nf_nat_l3proto.h new file mode 100644 index 000000000..a3127325f --- /dev/null +++ b/include/net/netfilter/nf_nat_l3proto.h @@ -0,0 +1,108 @@ +#ifndef _NF_NAT_L3PROTO_H +#define _NF_NAT_L3PROTO_H + +struct nf_nat_l4proto; +struct nf_nat_l3proto { + u8 l3proto; + + bool (*in_range)(const struct nf_conntrack_tuple *t, + const struct nf_nat_range *range); + + u32 (*secure_port)(const struct nf_conntrack_tuple *t, __be16); + + bool (*manip_pkt)(struct sk_buff *skb, + unsigned int iphdroff, + const struct nf_nat_l4proto *l4proto, + const struct nf_conntrack_tuple *target, + enum nf_nat_manip_type maniptype); + + void (*csum_update)(struct sk_buff *skb, unsigned int iphdroff, + __sum16 *check, + const struct nf_conntrack_tuple *t, + enum nf_nat_manip_type maniptype); + + void (*csum_recalc)(struct sk_buff *skb, u8 proto, + void *data, __sum16 *check, + int datalen, int oldlen); + + void (*decode_session)(struct sk_buff *skb, + const struct nf_conn *ct, + enum ip_conntrack_dir dir, + unsigned long statusbit, + struct flowi *fl); + + int (*nlattr_to_range)(struct nlattr *tb[], + struct nf_nat_range *range); +}; + +int nf_nat_l3proto_register(const struct nf_nat_l3proto *); +void nf_nat_l3proto_unregister(const struct nf_nat_l3proto *); +const struct nf_nat_l3proto *__nf_nat_l3proto_find(u8 l3proto); + +int nf_nat_icmp_reply_translation(struct sk_buff *skb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum); + +unsigned int nf_nat_ipv4_in(const struct nf_hook_ops *ops, struct sk_buff *skb, + const struct nf_hook_state *state, + unsigned int (*do_chain)(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state, + struct nf_conn *ct)); + +unsigned int nf_nat_ipv4_out(const struct nf_hook_ops *ops, struct sk_buff *skb, + const struct nf_hook_state *state, + unsigned int (*do_chain)(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state, + struct nf_conn *ct)); + +unsigned int nf_nat_ipv4_local_fn(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state, + unsigned int (*do_chain)(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state, + struct nf_conn *ct)); + +unsigned int nf_nat_ipv4_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, + const struct nf_hook_state *state, + unsigned int (*do_chain)(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state, + struct nf_conn *ct)); + +int nf_nat_icmpv6_reply_translation(struct sk_buff *skb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, + unsigned int hooknum, unsigned int hdrlen); + +unsigned int nf_nat_ipv6_in(const struct nf_hook_ops *ops, struct sk_buff *skb, + const struct nf_hook_state *state, + unsigned int (*do_chain)(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state, + struct nf_conn *ct)); + +unsigned int nf_nat_ipv6_out(const struct nf_hook_ops *ops, struct sk_buff *skb, + const struct nf_hook_state *state, + unsigned int (*do_chain)(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state, + struct nf_conn *ct)); + +unsigned int nf_nat_ipv6_local_fn(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state, + unsigned int (*do_chain)(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state, + struct nf_conn *ct)); + +unsigned int nf_nat_ipv6_fn(const struct nf_hook_ops *ops, struct sk_buff *skb, + const struct nf_hook_state *state, + unsigned int (*do_chain)(const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state, + struct nf_conn *ct)); + +#endif /* _NF_NAT_L3PROTO_H */ diff --git a/include/net/netfilter/nf_nat_l4proto.h b/include/net/netfilter/nf_nat_l4proto.h new file mode 100644 index 000000000..12f4cc841 --- /dev/null +++ b/include/net/netfilter/nf_nat_l4proto.h @@ -0,0 +1,72 @@ +/* Header for use in defining a given protocol. */ +#ifndef _NF_NAT_L4PROTO_H +#define _NF_NAT_L4PROTO_H +#include +#include + +struct nf_nat_range; +struct nf_nat_l3proto; + +struct nf_nat_l4proto { + /* Protocol number. */ + u8 l4proto; + + /* Translate a packet to the target according to manip type. + * Return true if succeeded. + */ + bool (*manip_pkt)(struct sk_buff *skb, + const struct nf_nat_l3proto *l3proto, + unsigned int iphdroff, unsigned int hdroff, + const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype); + + /* Is the manipable part of the tuple between min and max incl? */ + bool (*in_range)(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max); + + /* Alter the per-proto part of the tuple (depending on + * maniptype), to give a unique tuple in the given range if + * possible. Per-protocol part of tuple is initialized to the + * incoming packet. + */ + void (*unique_tuple)(const struct nf_nat_l3proto *l3proto, + struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct); + + int (*nlattr_to_range)(struct nlattr *tb[], + struct nf_nat_range *range); +}; + +/* Protocol registration. */ +int nf_nat_l4proto_register(u8 l3proto, const struct nf_nat_l4proto *l4proto); +void nf_nat_l4proto_unregister(u8 l3proto, + const struct nf_nat_l4proto *l4proto); + +const struct nf_nat_l4proto *__nf_nat_l4proto_find(u8 l3proto, u8 l4proto); + +/* Built-in protocols. */ +extern const struct nf_nat_l4proto nf_nat_l4proto_tcp; +extern const struct nf_nat_l4proto nf_nat_l4proto_udp; +extern const struct nf_nat_l4proto nf_nat_l4proto_icmp; +extern const struct nf_nat_l4proto nf_nat_l4proto_icmpv6; +extern const struct nf_nat_l4proto nf_nat_l4proto_unknown; + +bool nf_nat_l4proto_in_range(const struct nf_conntrack_tuple *tuple, + enum nf_nat_manip_type maniptype, + const union nf_conntrack_man_proto *min, + const union nf_conntrack_man_proto *max); + +void nf_nat_l4proto_unique_tuple(const struct nf_nat_l3proto *l3proto, + struct nf_conntrack_tuple *tuple, + const struct nf_nat_range *range, + enum nf_nat_manip_type maniptype, + const struct nf_conn *ct, u16 *rover); + +int nf_nat_l4proto_nlattr_to_range(struct nlattr *tb[], + struct nf_nat_range *range); + +#endif /*_NF_NAT_L4PROTO_H*/ diff --git a/include/net/netfilter/nf_nat_redirect.h b/include/net/netfilter/nf_nat_redirect.h new file mode 100644 index 000000000..73b729543 --- /dev/null +++ b/include/net/netfilter/nf_nat_redirect.h @@ -0,0 +1,12 @@ +#ifndef _NF_NAT_REDIRECT_H_ +#define _NF_NAT_REDIRECT_H_ + +unsigned int +nf_nat_redirect_ipv4(struct sk_buff *skb, + const struct nf_nat_ipv4_multi_range_compat *mr, + unsigned int hooknum); +unsigned int +nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range *range, + unsigned int hooknum); + +#endif /* _NF_NAT_REDIRECT_H_ */ diff --git a/include/net/netfilter/nf_queue.h b/include/net/netfilter/nf_queue.h new file mode 100644 index 000000000..d81d58415 --- /dev/null +++ b/include/net/netfilter/nf_queue.h @@ -0,0 +1,94 @@ +#ifndef _NF_QUEUE_H +#define _NF_QUEUE_H + +#include +#include +#include + +/* Each queued (to userspace) skbuff has one of these. */ +struct nf_queue_entry { + struct list_head list; + struct sk_buff *skb; + unsigned int id; + + struct nf_hook_ops *elem; + struct nf_hook_state state; + u16 size; /* sizeof(entry) + saved route keys */ + + /* extra space to store route keys */ +}; + +#define nf_queue_entry_reroute(x) ((void *)x + sizeof(struct nf_queue_entry)) + +/* Packet queuing */ +struct nf_queue_handler { + int (*outfn)(struct nf_queue_entry *entry, + unsigned int queuenum); +}; + +void nf_register_queue_handler(const struct nf_queue_handler *qh); +void nf_unregister_queue_handler(void); +void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict); + +bool nf_queue_entry_get_refs(struct nf_queue_entry *entry); +void nf_queue_entry_release_refs(struct nf_queue_entry *entry); + +static inline void init_hashrandom(u32 *jhash_initval) +{ + while (*jhash_initval == 0) + *jhash_initval = prandom_u32(); +} + +static inline u32 hash_v4(const struct sk_buff *skb, u32 jhash_initval) +{ + const struct iphdr *iph = ip_hdr(skb); + + /* packets in either direction go into same queue */ + if ((__force u32)iph->saddr < (__force u32)iph->daddr) + return jhash_3words((__force u32)iph->saddr, + (__force u32)iph->daddr, iph->protocol, jhash_initval); + + return jhash_3words((__force u32)iph->daddr, + (__force u32)iph->saddr, iph->protocol, jhash_initval); +} + +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) +static inline u32 hash_v6(const struct sk_buff *skb, u32 jhash_initval) +{ + const struct ipv6hdr *ip6h = ipv6_hdr(skb); + u32 a, b, c; + + if ((__force u32)ip6h->saddr.s6_addr32[3] < + (__force u32)ip6h->daddr.s6_addr32[3]) { + a = (__force u32) ip6h->saddr.s6_addr32[3]; + b = (__force u32) ip6h->daddr.s6_addr32[3]; + } else { + b = (__force u32) ip6h->saddr.s6_addr32[3]; + a = (__force u32) ip6h->daddr.s6_addr32[3]; + } + + if ((__force u32)ip6h->saddr.s6_addr32[1] < + (__force u32)ip6h->daddr.s6_addr32[1]) + c = (__force u32) ip6h->saddr.s6_addr32[1]; + else + c = (__force u32) ip6h->daddr.s6_addr32[1]; + + return jhash_3words(a, b, c, jhash_initval); +} +#endif + +static inline u32 +nfqueue_hash(const struct sk_buff *skb, u16 queue, u16 queues_total, u8 family, + u32 jhash_initval) +{ + if (family == NFPROTO_IPV4) + queue += ((u64) hash_v4(skb, jhash_initval) * queues_total) >> 32; +#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES) + else if (family == NFPROTO_IPV6) + queue += ((u64) hash_v6(skb, jhash_initval) * queues_total) >> 32; +#endif + + return queue; +} + +#endif /* _NF_QUEUE_H */ diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h new file mode 100644 index 000000000..e6bcf55dc --- /dev/null +++ b/include/net/netfilter/nf_tables.h @@ -0,0 +1,1033 @@ +#ifndef _NET_NF_TABLES_H +#define _NET_NF_TABLES_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NFT_JUMP_STACK_SIZE 16 + +struct nft_pktinfo { + struct sk_buff *skb; + const struct net_device *in; + const struct net_device *out; + const struct nf_hook_ops *ops; + u8 nhoff; + u8 thoff; + u8 tprot; + /* for x_tables compatibility */ + struct xt_action_param xt; +}; + +static inline void nft_set_pktinfo(struct nft_pktinfo *pkt, + const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + pkt->skb = skb; + pkt->in = pkt->xt.in = state->in; + pkt->out = pkt->xt.out = state->out; + pkt->ops = ops; + pkt->xt.hooknum = ops->hooknum; + pkt->xt.family = ops->pf; +} + +/** + * struct nft_verdict - nf_tables verdict + * + * @code: nf_tables/netfilter verdict code + * @chain: destination chain for NFT_JUMP/NFT_GOTO + */ +struct nft_verdict { + u32 code; + struct nft_chain *chain; +}; + +struct nft_data { + union { + u32 data[4]; + struct nft_verdict verdict; + }; +} __attribute__((aligned(__alignof__(u64)))); + +/** + * struct nft_regs - nf_tables register set + * + * @data: data registers + * @verdict: verdict register + * + * The first four data registers alias to the verdict register. + */ +struct nft_regs { + union { + u32 data[20]; + struct nft_verdict verdict; + }; +}; + +static inline void nft_data_copy(u32 *dst, const struct nft_data *src, + unsigned int len) +{ + memcpy(dst, src, len); +} + +static inline void nft_data_debug(const struct nft_data *data) +{ + pr_debug("data[0]=%x data[1]=%x data[2]=%x data[3]=%x\n", + data->data[0], data->data[1], + data->data[2], data->data[3]); +} + +/** + * struct nft_ctx - nf_tables rule/set context + * + * @net: net namespace + * @afi: address family info + * @table: the table the chain is contained in + * @chain: the chain the rule is contained in + * @nla: netlink attributes + * @portid: netlink portID of the original message + * @seq: netlink sequence number + * @report: notify via unicast netlink message + */ +struct nft_ctx { + struct net *net; + struct nft_af_info *afi; + struct nft_table *table; + struct nft_chain *chain; + const struct nlattr * const *nla; + u32 portid; + u32 seq; + bool report; +}; + +struct nft_data_desc { + enum nft_data_types type; + unsigned int len; +}; + +int nft_data_init(const struct nft_ctx *ctx, + struct nft_data *data, unsigned int size, + struct nft_data_desc *desc, const struct nlattr *nla); +void nft_data_uninit(const struct nft_data *data, enum nft_data_types type); +int nft_data_dump(struct sk_buff *skb, int attr, const struct nft_data *data, + enum nft_data_types type, unsigned int len); + +static inline enum nft_data_types nft_dreg_to_type(enum nft_registers reg) +{ + return reg == NFT_REG_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE; +} + +static inline enum nft_registers nft_type_to_reg(enum nft_data_types type) +{ + return type == NFT_DATA_VERDICT ? NFT_REG_VERDICT : NFT_REG_1; +} + +unsigned int nft_parse_register(const struct nlattr *attr); +int nft_dump_register(struct sk_buff *skb, unsigned int attr, unsigned int reg); + +int nft_validate_register_load(enum nft_registers reg, unsigned int len); +int nft_validate_register_store(const struct nft_ctx *ctx, + enum nft_registers reg, + const struct nft_data *data, + enum nft_data_types type, unsigned int len); + +/** + * struct nft_userdata - user defined data associated with an object + * + * @len: length of the data + * @data: content + * + * The presence of user data is indicated in an object specific fashion, + * so a length of zero can't occur and the value "len" indicates data + * of length len + 1. + */ +struct nft_userdata { + u8 len; + unsigned char data[0]; +}; + +/** + * struct nft_set_elem - generic representation of set elements + * + * @key: element key + * @priv: element private data and extensions + */ +struct nft_set_elem { + union { + u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)]; + struct nft_data val; + } key; + void *priv; +}; + +struct nft_set; +struct nft_set_iter { + unsigned int count; + unsigned int skip; + int err; + int (*fn)(const struct nft_ctx *ctx, + const struct nft_set *set, + const struct nft_set_iter *iter, + const struct nft_set_elem *elem); +}; + +/** + * struct nft_set_desc - description of set elements + * + * @klen: key length + * @dlen: data length + * @size: number of set elements + */ +struct nft_set_desc { + unsigned int klen; + unsigned int dlen; + unsigned int size; +}; + +/** + * enum nft_set_class - performance class + * + * @NFT_LOOKUP_O_1: constant, O(1) + * @NFT_LOOKUP_O_LOG_N: logarithmic, O(log N) + * @NFT_LOOKUP_O_N: linear, O(N) + */ +enum nft_set_class { + NFT_SET_CLASS_O_1, + NFT_SET_CLASS_O_LOG_N, + NFT_SET_CLASS_O_N, +}; + +/** + * struct nft_set_estimate - estimation of memory and performance + * characteristics + * + * @size: required memory + * @class: lookup performance class + */ +struct nft_set_estimate { + unsigned int size; + enum nft_set_class class; +}; + +struct nft_set_ext; +struct nft_expr; + +/** + * struct nft_set_ops - nf_tables set operations + * + * @lookup: look up an element within the set + * @insert: insert new element into set + * @activate: activate new element in the next generation + * @deactivate: deactivate element in the next generation + * @remove: remove element from set + * @walk: iterate over all set elemeennts + * @privsize: function to return size of set private data + * @init: initialize private data of new set instance + * @destroy: destroy private data of set instance + * @list: nf_tables_set_ops list node + * @owner: module reference + * @elemsize: element private size + * @features: features supported by the implementation + */ +struct nft_set_ops { + bool (*lookup)(const struct nft_set *set, + const u32 *key, + const struct nft_set_ext **ext); + bool (*update)(struct nft_set *set, + const u32 *key, + void *(*new)(struct nft_set *, + const struct nft_expr *, + struct nft_regs *), + const struct nft_expr *expr, + struct nft_regs *regs, + const struct nft_set_ext **ext); + + int (*insert)(const struct nft_set *set, + const struct nft_set_elem *elem); + void (*activate)(const struct nft_set *set, + const struct nft_set_elem *elem); + void * (*deactivate)(const struct nft_set *set, + const struct nft_set_elem *elem); + void (*remove)(const struct nft_set *set, + const struct nft_set_elem *elem); + void (*walk)(const struct nft_ctx *ctx, + const struct nft_set *set, + struct nft_set_iter *iter); + + unsigned int (*privsize)(const struct nlattr * const nla[]); + bool (*estimate)(const struct nft_set_desc *desc, + u32 features, + struct nft_set_estimate *est); + int (*init)(const struct nft_set *set, + const struct nft_set_desc *desc, + const struct nlattr * const nla[]); + void (*destroy)(const struct nft_set *set); + + struct list_head list; + struct module *owner; + unsigned int elemsize; + u32 features; +}; + +int nft_register_set(struct nft_set_ops *ops); +void nft_unregister_set(struct nft_set_ops *ops); + +/** + * struct nft_set - nf_tables set instance + * + * @list: table set list node + * @bindings: list of set bindings + * @name: name of the set + * @ktype: key type (numeric type defined by userspace, not used in the kernel) + * @dtype: data type (verdict or numeric type defined by userspace) + * @size: maximum set size + * @nelems: number of elements + * @ndeact: number of deactivated elements queued for removal + * @timeout: default timeout value in msecs + * @gc_int: garbage collection interval in msecs + * @policy: set parameterization (see enum nft_set_policies) + * @ops: set ops + * @pnet: network namespace + * @flags: set flags + * @klen: key length + * @dlen: data length + * @data: private set data + */ +struct nft_set { + struct list_head list; + struct list_head bindings; + char name[IFNAMSIZ]; + u32 ktype; + u32 dtype; + u32 size; + atomic_t nelems; + u32 ndeact; + u64 timeout; + u32 gc_int; + u16 policy; + /* runtime data below here */ + const struct nft_set_ops *ops ____cacheline_aligned; + possible_net_t pnet; + u16 flags; + u8 klen; + u8 dlen; + unsigned char data[] + __attribute__((aligned(__alignof__(u64)))); +}; + +static inline void *nft_set_priv(const struct nft_set *set) +{ + return (void *)set->data; +} + +static inline struct nft_set *nft_set_container_of(const void *priv) +{ + return (void *)priv - offsetof(struct nft_set, data); +} + +struct nft_set *nf_tables_set_lookup(const struct nft_table *table, + const struct nlattr *nla); +struct nft_set *nf_tables_set_lookup_byid(const struct net *net, + const struct nlattr *nla); + +static inline unsigned long nft_set_gc_interval(const struct nft_set *set) +{ + return set->gc_int ? msecs_to_jiffies(set->gc_int) : HZ; +} + +/** + * struct nft_set_binding - nf_tables set binding + * + * @list: set bindings list node + * @chain: chain containing the rule bound to the set + * @flags: set action flags + * + * A set binding contains all information necessary for validation + * of new elements added to a bound set. + */ +struct nft_set_binding { + struct list_head list; + const struct nft_chain *chain; + u32 flags; +}; + +int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, + struct nft_set_binding *binding); +void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set, + struct nft_set_binding *binding); + +/** + * enum nft_set_extensions - set extension type IDs + * + * @NFT_SET_EXT_KEY: element key + * @NFT_SET_EXT_DATA: mapping data + * @NFT_SET_EXT_FLAGS: element flags + * @NFT_SET_EXT_TIMEOUT: element timeout + * @NFT_SET_EXT_EXPIRATION: element expiration time + * @NFT_SET_EXT_USERDATA: user data associated with the element + * @NFT_SET_EXT_EXPR: expression assiociated with the element + * @NFT_SET_EXT_NUM: number of extension types + */ +enum nft_set_extensions { + NFT_SET_EXT_KEY, + NFT_SET_EXT_DATA, + NFT_SET_EXT_FLAGS, + NFT_SET_EXT_TIMEOUT, + NFT_SET_EXT_EXPIRATION, + NFT_SET_EXT_USERDATA, + NFT_SET_EXT_EXPR, + NFT_SET_EXT_NUM +}; + +/** + * struct nft_set_ext_type - set extension type + * + * @len: fixed part length of the extension + * @align: alignment requirements of the extension + */ +struct nft_set_ext_type { + u8 len; + u8 align; +}; + +extern const struct nft_set_ext_type nft_set_ext_types[]; + +/** + * struct nft_set_ext_tmpl - set extension template + * + * @len: length of extension area + * @offset: offsets of individual extension types + */ +struct nft_set_ext_tmpl { + u16 len; + u8 offset[NFT_SET_EXT_NUM]; +}; + +/** + * struct nft_set_ext - set extensions + * + * @genmask: generation mask + * @offset: offsets of individual extension types + * @data: beginning of extension data + */ +struct nft_set_ext { + u8 genmask; + u8 offset[NFT_SET_EXT_NUM]; + char data[0]; +}; + +static inline void nft_set_ext_prepare(struct nft_set_ext_tmpl *tmpl) +{ + memset(tmpl, 0, sizeof(*tmpl)); + tmpl->len = sizeof(struct nft_set_ext); +} + +static inline void nft_set_ext_add_length(struct nft_set_ext_tmpl *tmpl, u8 id, + unsigned int len) +{ + tmpl->len = ALIGN(tmpl->len, nft_set_ext_types[id].align); + BUG_ON(tmpl->len > U8_MAX); + tmpl->offset[id] = tmpl->len; + tmpl->len += nft_set_ext_types[id].len + len; +} + +static inline void nft_set_ext_add(struct nft_set_ext_tmpl *tmpl, u8 id) +{ + nft_set_ext_add_length(tmpl, id, 0); +} + +static inline void nft_set_ext_init(struct nft_set_ext *ext, + const struct nft_set_ext_tmpl *tmpl) +{ + memcpy(ext->offset, tmpl->offset, sizeof(ext->offset)); +} + +static inline bool __nft_set_ext_exists(const struct nft_set_ext *ext, u8 id) +{ + return !!ext->offset[id]; +} + +static inline bool nft_set_ext_exists(const struct nft_set_ext *ext, u8 id) +{ + return ext && __nft_set_ext_exists(ext, id); +} + +static inline void *nft_set_ext(const struct nft_set_ext *ext, u8 id) +{ + return (void *)ext + ext->offset[id]; +} + +static inline struct nft_data *nft_set_ext_key(const struct nft_set_ext *ext) +{ + return nft_set_ext(ext, NFT_SET_EXT_KEY); +} + +static inline struct nft_data *nft_set_ext_data(const struct nft_set_ext *ext) +{ + return nft_set_ext(ext, NFT_SET_EXT_DATA); +} + +static inline u8 *nft_set_ext_flags(const struct nft_set_ext *ext) +{ + return nft_set_ext(ext, NFT_SET_EXT_FLAGS); +} + +static inline u64 *nft_set_ext_timeout(const struct nft_set_ext *ext) +{ + return nft_set_ext(ext, NFT_SET_EXT_TIMEOUT); +} + +static inline unsigned long *nft_set_ext_expiration(const struct nft_set_ext *ext) +{ + return nft_set_ext(ext, NFT_SET_EXT_EXPIRATION); +} + +static inline struct nft_userdata *nft_set_ext_userdata(const struct nft_set_ext *ext) +{ + return nft_set_ext(ext, NFT_SET_EXT_USERDATA); +} + +static inline struct nft_expr *nft_set_ext_expr(const struct nft_set_ext *ext) +{ + return nft_set_ext(ext, NFT_SET_EXT_EXPR); +} + +static inline bool nft_set_elem_expired(const struct nft_set_ext *ext) +{ + return nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION) && + time_is_before_eq_jiffies(*nft_set_ext_expiration(ext)); +} + +static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set, + void *elem) +{ + return elem + set->ops->elemsize; +} + +void *nft_set_elem_init(const struct nft_set *set, + const struct nft_set_ext_tmpl *tmpl, + const u32 *key, const u32 *data, + u64 timeout, gfp_t gfp); +void nft_set_elem_destroy(const struct nft_set *set, void *elem); + +/** + * struct nft_set_gc_batch_head - nf_tables set garbage collection batch + * + * @rcu: rcu head + * @set: set the elements belong to + * @cnt: count of elements + */ +struct nft_set_gc_batch_head { + struct rcu_head rcu; + const struct nft_set *set; + unsigned int cnt; +}; + +#define NFT_SET_GC_BATCH_SIZE ((PAGE_SIZE - \ + sizeof(struct nft_set_gc_batch_head)) / \ + sizeof(void *)) + +/** + * struct nft_set_gc_batch - nf_tables set garbage collection batch + * + * @head: GC batch head + * @elems: garbage collection elements + */ +struct nft_set_gc_batch { + struct nft_set_gc_batch_head head; + void *elems[NFT_SET_GC_BATCH_SIZE]; +}; + +struct nft_set_gc_batch *nft_set_gc_batch_alloc(const struct nft_set *set, + gfp_t gfp); +void nft_set_gc_batch_release(struct rcu_head *rcu); + +static inline void nft_set_gc_batch_complete(struct nft_set_gc_batch *gcb) +{ + if (gcb != NULL) + call_rcu(&gcb->head.rcu, nft_set_gc_batch_release); +} + +static inline struct nft_set_gc_batch * +nft_set_gc_batch_check(const struct nft_set *set, struct nft_set_gc_batch *gcb, + gfp_t gfp) +{ + if (gcb != NULL) { + if (gcb->head.cnt + 1 < ARRAY_SIZE(gcb->elems)) + return gcb; + nft_set_gc_batch_complete(gcb); + } + return nft_set_gc_batch_alloc(set, gfp); +} + +static inline void nft_set_gc_batch_add(struct nft_set_gc_batch *gcb, + void *elem) +{ + gcb->elems[gcb->head.cnt++] = elem; +} + +/** + * struct nft_expr_type - nf_tables expression type + * + * @select_ops: function to select nft_expr_ops + * @ops: default ops, used when no select_ops functions is present + * @list: used internally + * @name: Identifier + * @owner: module reference + * @policy: netlink attribute policy + * @maxattr: highest netlink attribute number + * @family: address family for AF-specific types + * @flags: expression type flags + */ +struct nft_expr_type { + const struct nft_expr_ops *(*select_ops)(const struct nft_ctx *, + const struct nlattr * const tb[]); + const struct nft_expr_ops *ops; + struct list_head list; + const char *name; + struct module *owner; + const struct nla_policy *policy; + unsigned int maxattr; + u8 family; + u8 flags; +}; + +#define NFT_EXPR_STATEFUL 0x1 + +/** + * struct nft_expr_ops - nf_tables expression operations + * + * @eval: Expression evaluation function + * @size: full expression size, including private data size + * @init: initialization function + * @destroy: destruction function + * @dump: function to dump parameters + * @type: expression type + * @validate: validate expression, called during loop detection + * @data: extra data to attach to this expression operation + */ +struct nft_expr; +struct nft_expr_ops { + void (*eval)(const struct nft_expr *expr, + struct nft_regs *regs, + const struct nft_pktinfo *pkt); + unsigned int size; + + int (*init)(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nlattr * const tb[]); + void (*destroy)(const struct nft_ctx *ctx, + const struct nft_expr *expr); + int (*dump)(struct sk_buff *skb, + const struct nft_expr *expr); + int (*validate)(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nft_data **data); + const struct nft_expr_type *type; + void *data; +}; + +#define NFT_EXPR_MAXATTR 16 +#define NFT_EXPR_SIZE(size) (sizeof(struct nft_expr) + \ + ALIGN(size, __alignof__(struct nft_expr))) + +/** + * struct nft_expr - nf_tables expression + * + * @ops: expression ops + * @data: expression private data + */ +struct nft_expr { + const struct nft_expr_ops *ops; + unsigned char data[]; +}; + +static inline void *nft_expr_priv(const struct nft_expr *expr) +{ + return (void *)expr->data; +} + +struct nft_expr *nft_expr_init(const struct nft_ctx *ctx, + const struct nlattr *nla); +void nft_expr_destroy(const struct nft_ctx *ctx, struct nft_expr *expr); +int nft_expr_dump(struct sk_buff *skb, unsigned int attr, + const struct nft_expr *expr); + +static inline void nft_expr_clone(struct nft_expr *dst, struct nft_expr *src) +{ + __module_get(src->ops->type->owner); + memcpy(dst, src, src->ops->size); +} + +/** + * struct nft_rule - nf_tables rule + * + * @list: used internally + * @handle: rule handle + * @genmask: generation mask + * @dlen: length of expression data + * @udata: user data is appended to the rule + * @data: expression data + */ +struct nft_rule { + struct list_head list; + u64 handle:42, + genmask:2, + dlen:12, + udata:1; + unsigned char data[] + __attribute__((aligned(__alignof__(struct nft_expr)))); +}; + +static inline struct nft_expr *nft_expr_first(const struct nft_rule *rule) +{ + return (struct nft_expr *)&rule->data[0]; +} + +static inline struct nft_expr *nft_expr_next(const struct nft_expr *expr) +{ + return ((void *)expr) + expr->ops->size; +} + +static inline struct nft_expr *nft_expr_last(const struct nft_rule *rule) +{ + return (struct nft_expr *)&rule->data[rule->dlen]; +} + +static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule) +{ + return (void *)&rule->data[rule->dlen]; +} + +/* + * The last pointer isn't really necessary, but the compiler isn't able to + * determine that the result of nft_expr_last() is always the same since it + * can't assume that the dlen value wasn't changed within calls in the loop. + */ +#define nft_rule_for_each_expr(expr, last, rule) \ + for ((expr) = nft_expr_first(rule), (last) = nft_expr_last(rule); \ + (expr) != (last); \ + (expr) = nft_expr_next(expr)) + +enum nft_chain_flags { + NFT_BASE_CHAIN = 0x1, + NFT_CHAIN_INACTIVE = 0x2, +}; + +/** + * struct nft_chain - nf_tables chain + * + * @rules: list of rules in the chain + * @list: used internally + * @table: table that this chain belongs to + * @handle: chain handle + * @use: number of jump references to this chain + * @level: length of longest path to this chain + * @flags: bitmask of enum nft_chain_flags + * @name: name of the chain + */ +struct nft_chain { + struct list_head rules; + struct list_head list; + struct nft_table *table; + u64 handle; + u32 use; + u16 level; + u8 flags; + char name[NFT_CHAIN_MAXNAMELEN]; +}; + +enum nft_chain_type { + NFT_CHAIN_T_DEFAULT = 0, + NFT_CHAIN_T_ROUTE, + NFT_CHAIN_T_NAT, + NFT_CHAIN_T_MAX +}; + +/** + * struct nf_chain_type - nf_tables chain type info + * + * @name: name of the type + * @type: numeric identifier + * @family: address family + * @owner: module owner + * @hook_mask: mask of valid hooks + * @hooks: hookfn overrides + */ +struct nf_chain_type { + const char *name; + enum nft_chain_type type; + int family; + struct module *owner; + unsigned int hook_mask; + nf_hookfn *hooks[NF_MAX_HOOKS]; +}; + +int nft_chain_validate_dependency(const struct nft_chain *chain, + enum nft_chain_type type); +int nft_chain_validate_hooks(const struct nft_chain *chain, + unsigned int hook_flags); + +struct nft_stats { + u64 bytes; + u64 pkts; + struct u64_stats_sync syncp; +}; + +#define NFT_HOOK_OPS_MAX 2 + +/** + * struct nft_base_chain - nf_tables base chain + * + * @ops: netfilter hook ops + * @pnet: net namespace that this chain belongs to + * @type: chain type + * @policy: default policy + * @stats: per-cpu chain stats + * @chain: the chain + */ +struct nft_base_chain { + struct nf_hook_ops ops[NFT_HOOK_OPS_MAX]; + possible_net_t pnet; + const struct nf_chain_type *type; + u8 policy; + struct nft_stats __percpu *stats; + struct nft_chain chain; +}; + +static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chain) +{ + return container_of(chain, struct nft_base_chain, chain); +} + +unsigned int nft_do_chain(struct nft_pktinfo *pkt, + const struct nf_hook_ops *ops); + +/** + * struct nft_table - nf_tables table + * + * @list: used internally + * @chains: chains in the table + * @sets: sets in the table + * @hgenerator: handle generator state + * @use: number of chain references to this table + * @flags: table flag (see enum nft_table_flags) + * @name: name of the table + */ +struct nft_table { + struct list_head list; + struct list_head chains; + struct list_head sets; + u64 hgenerator; + u32 use; + u16 flags; + char name[NFT_TABLE_MAXNAMELEN]; +}; + +/** + * struct nft_af_info - nf_tables address family info + * + * @list: used internally + * @family: address family + * @nhooks: number of hooks in this family + * @owner: module owner + * @tables: used internally + * @nops: number of hook ops in this family + * @hook_ops_init: initialization function for chain hook ops + * @hooks: hookfn overrides for packet validation + */ +struct nft_af_info { + struct list_head list; + int family; + unsigned int nhooks; + struct module *owner; + struct list_head tables; + unsigned int nops; + void (*hook_ops_init)(struct nf_hook_ops *, + unsigned int); + nf_hookfn *hooks[NF_MAX_HOOKS]; +}; + +int nft_register_afinfo(struct net *, struct nft_af_info *); +void nft_unregister_afinfo(struct nft_af_info *); + +int nft_register_chain_type(const struct nf_chain_type *); +void nft_unregister_chain_type(const struct nf_chain_type *); + +int nft_register_expr(struct nft_expr_type *); +void nft_unregister_expr(struct nft_expr_type *); + +#define nft_dereference(p) \ + nfnl_dereference(p, NFNL_SUBSYS_NFTABLES) + +#define MODULE_ALIAS_NFT_FAMILY(family) \ + MODULE_ALIAS("nft-afinfo-" __stringify(family)) + +#define MODULE_ALIAS_NFT_CHAIN(family, name) \ + MODULE_ALIAS("nft-chain-" __stringify(family) "-" name) + +#define MODULE_ALIAS_NFT_AF_EXPR(family, name) \ + MODULE_ALIAS("nft-expr-" __stringify(family) "-" name) + +#define MODULE_ALIAS_NFT_EXPR(name) \ + MODULE_ALIAS("nft-expr-" name) + +#define MODULE_ALIAS_NFT_SET() \ + MODULE_ALIAS("nft-set") + +/* + * The gencursor defines two generations, the currently active and the + * next one. Objects contain a bitmask of 2 bits specifying the generations + * they're active in. A set bit means they're inactive in the generation + * represented by that bit. + * + * New objects start out as inactive in the current and active in the + * next generation. When committing the ruleset the bitmask is cleared, + * meaning they're active in all generations. When removing an object, + * it is set inactive in the next generation. After committing the ruleset, + * the objects are removed. + */ +static inline unsigned int nft_gencursor_next(const struct net *net) +{ + return net->nft.gencursor + 1 == 1 ? 1 : 0; +} + +static inline u8 nft_genmask_next(const struct net *net) +{ + return 1 << nft_gencursor_next(net); +} + +static inline u8 nft_genmask_cur(const struct net *net) +{ + /* Use ACCESS_ONCE() to prevent refetching the value for atomicity */ + return 1 << ACCESS_ONCE(net->nft.gencursor); +} + +#define NFT_GENMASK_ANY ((1 << 0) | (1 << 1)) + +/* + * Set element transaction helpers + */ + +static inline bool nft_set_elem_active(const struct nft_set_ext *ext, + u8 genmask) +{ + return !(ext->genmask & genmask); +} + +static inline void nft_set_elem_change_active(const struct nft_set *set, + struct nft_set_ext *ext) +{ + ext->genmask ^= nft_genmask_next(read_pnet(&set->pnet)); +} + +/* + * We use a free bit in the genmask field to indicate the element + * is busy, meaning it is currently being processed either by + * the netlink API or GC. + * + * Even though the genmask is only a single byte wide, this works + * because the extension structure if fully constant once initialized, + * so there are no non-atomic write accesses unless it is already + * marked busy. + */ +#define NFT_SET_ELEM_BUSY_MASK (1 << 2) + +#if defined(__LITTLE_ENDIAN_BITFIELD) +#define NFT_SET_ELEM_BUSY_BIT 2 +#elif defined(__BIG_ENDIAN_BITFIELD) +#define NFT_SET_ELEM_BUSY_BIT (BITS_PER_LONG - BITS_PER_BYTE + 2) +#else +#error +#endif + +static inline int nft_set_elem_mark_busy(struct nft_set_ext *ext) +{ + unsigned long *word = (unsigned long *)ext; + + BUILD_BUG_ON(offsetof(struct nft_set_ext, genmask) != 0); + return test_and_set_bit(NFT_SET_ELEM_BUSY_BIT, word); +} + +static inline void nft_set_elem_clear_busy(struct nft_set_ext *ext) +{ + unsigned long *word = (unsigned long *)ext; + + clear_bit(NFT_SET_ELEM_BUSY_BIT, word); +} + +/** + * struct nft_trans - nf_tables object update in transaction + * + * @list: used internally + * @msg_type: message type + * @ctx: transaction context + * @data: internal information related to the transaction + */ +struct nft_trans { + struct list_head list; + int msg_type; + struct nft_ctx ctx; + char data[0]; +}; + +struct nft_trans_rule { + struct nft_rule *rule; +}; + +#define nft_trans_rule(trans) \ + (((struct nft_trans_rule *)trans->data)->rule) + +struct nft_trans_set { + struct nft_set *set; + u32 set_id; +}; + +#define nft_trans_set(trans) \ + (((struct nft_trans_set *)trans->data)->set) +#define nft_trans_set_id(trans) \ + (((struct nft_trans_set *)trans->data)->set_id) + +struct nft_trans_chain { + bool update; + char name[NFT_CHAIN_MAXNAMELEN]; + struct nft_stats __percpu *stats; + u8 policy; +}; + +#define nft_trans_chain_update(trans) \ + (((struct nft_trans_chain *)trans->data)->update) +#define nft_trans_chain_name(trans) \ + (((struct nft_trans_chain *)trans->data)->name) +#define nft_trans_chain_stats(trans) \ + (((struct nft_trans_chain *)trans->data)->stats) +#define nft_trans_chain_policy(trans) \ + (((struct nft_trans_chain *)trans->data)->policy) + +struct nft_trans_table { + bool update; + bool enable; +}; + +#define nft_trans_table_update(trans) \ + (((struct nft_trans_table *)trans->data)->update) +#define nft_trans_table_enable(trans) \ + (((struct nft_trans_table *)trans->data)->enable) + +struct nft_trans_elem { + struct nft_set *set; + struct nft_set_elem elem; +}; + +#define nft_trans_elem_set(trans) \ + (((struct nft_trans_elem *)trans->data)->set) +#define nft_trans_elem(trans) \ + (((struct nft_trans_elem *)trans->data)->elem) + +#endif /* _NET_NF_TABLES_H */ diff --git a/include/net/netfilter/nf_tables_bridge.h b/include/net/netfilter/nf_tables_bridge.h new file mode 100644 index 000000000..511fb79f6 --- /dev/null +++ b/include/net/netfilter/nf_tables_bridge.h @@ -0,0 +1,7 @@ +#ifndef _NET_NF_TABLES_BRIDGE_H +#define _NET_NF_TABLES_BRIDGE_H + +int nft_bridge_iphdr_validate(struct sk_buff *skb); +int nft_bridge_ip6hdr_validate(struct sk_buff *skb); + +#endif /* _NET_NF_TABLES_BRIDGE_H */ diff --git a/include/net/netfilter/nf_tables_core.h b/include/net/netfilter/nf_tables_core.h new file mode 100644 index 000000000..c6f400cfa --- /dev/null +++ b/include/net/netfilter/nf_tables_core.h @@ -0,0 +1,55 @@ +#ifndef _NET_NF_TABLES_CORE_H +#define _NET_NF_TABLES_CORE_H + +int nf_tables_core_module_init(void); +void nf_tables_core_module_exit(void); + +int nft_immediate_module_init(void); +void nft_immediate_module_exit(void); + +struct nft_cmp_fast_expr { + u32 data; + enum nft_registers sreg:8; + u8 len; +}; + +/* Calculate the mask for the nft_cmp_fast expression. On big endian the + * mask needs to include the *upper* bytes when interpreting that data as + * something smaller than the full u32, therefore a cpu_to_le32 is done. + */ +static inline u32 nft_cmp_fast_mask(unsigned int len) +{ + return cpu_to_le32(~0U >> (FIELD_SIZEOF(struct nft_cmp_fast_expr, + data) * BITS_PER_BYTE - len)); +} + +extern const struct nft_expr_ops nft_cmp_fast_ops; + +int nft_cmp_module_init(void); +void nft_cmp_module_exit(void); + +int nft_lookup_module_init(void); +void nft_lookup_module_exit(void); + +int nft_dynset_module_init(void); +void nft_dynset_module_exit(void); + +int nft_bitwise_module_init(void); +void nft_bitwise_module_exit(void); + +int nft_byteorder_module_init(void); +void nft_byteorder_module_exit(void); + +struct nft_payload { + enum nft_payload_bases base:8; + u8 offset; + u8 len; + enum nft_registers dreg:8; +}; + +extern const struct nft_expr_ops nft_payload_fast_ops; + +int nft_payload_module_init(void); +void nft_payload_module_exit(void); + +#endif /* _NET_NF_TABLES_CORE_H */ diff --git a/include/net/netfilter/nf_tables_ipv4.h b/include/net/netfilter/nf_tables_ipv4.h new file mode 100644 index 000000000..2df7f9690 --- /dev/null +++ b/include/net/netfilter/nf_tables_ipv4.h @@ -0,0 +1,25 @@ +#ifndef _NF_TABLES_IPV4_H_ +#define _NF_TABLES_IPV4_H_ + +#include +#include + +static inline void +nft_set_pktinfo_ipv4(struct nft_pktinfo *pkt, + const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + struct iphdr *ip; + + nft_set_pktinfo(pkt, ops, skb, state); + + ip = ip_hdr(pkt->skb); + pkt->tprot = ip->protocol; + pkt->xt.thoff = ip_hdrlen(pkt->skb); + pkt->xt.fragoff = ntohs(ip->frag_off) & IP_OFFSET; +} + +extern struct nft_af_info nft_af_ipv4; + +#endif diff --git a/include/net/netfilter/nf_tables_ipv6.h b/include/net/netfilter/nf_tables_ipv6.h new file mode 100644 index 000000000..97db2e3a5 --- /dev/null +++ b/include/net/netfilter/nf_tables_ipv6.h @@ -0,0 +1,32 @@ +#ifndef _NF_TABLES_IPV6_H_ +#define _NF_TABLES_IPV6_H_ + +#include +#include + +static inline int +nft_set_pktinfo_ipv6(struct nft_pktinfo *pkt, + const struct nf_hook_ops *ops, + struct sk_buff *skb, + const struct nf_hook_state *state) +{ + int protohdr, thoff = 0; + unsigned short frag_off; + + nft_set_pktinfo(pkt, ops, skb, state); + + protohdr = ipv6_find_hdr(pkt->skb, &thoff, -1, &frag_off, NULL); + /* If malformed, drop it */ + if (protohdr < 0) + return -1; + + pkt->tprot = protohdr; + pkt->xt.thoff = thoff; + pkt->xt.fragoff = frag_off; + + return 0; +} + +extern struct nft_af_info nft_af_ipv6; + +#endif diff --git a/include/net/netfilter/nfnetlink_log.h b/include/net/netfilter/nfnetlink_log.h new file mode 100644 index 000000000..5ca3f14f0 --- /dev/null +++ b/include/net/netfilter/nfnetlink_log.h @@ -0,0 +1,17 @@ +#ifndef _KER_NFNETLINK_LOG_H +#define _KER_NFNETLINK_LOG_H + +void +nfulnl_log_packet(struct net *net, + u_int8_t pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *li_user, + const char *prefix); + +#define NFULNL_COPY_DISABLED 0xff + +#endif /* _KER_NFNETLINK_LOG_H */ + diff --git a/include/net/netfilter/nfnetlink_queue.h b/include/net/netfilter/nfnetlink_queue.h new file mode 100644 index 000000000..aff88ba91 --- /dev/null +++ b/include/net/netfilter/nfnetlink_queue.h @@ -0,0 +1,51 @@ +#ifndef _NET_NFNL_QUEUE_H_ +#define _NET_NFNL_QUEUE_H_ + +#include + +struct nf_conn; + +#ifdef CONFIG_NETFILTER_NETLINK_QUEUE_CT +struct nf_conn *nfqnl_ct_get(struct sk_buff *entskb, size_t *size, + enum ip_conntrack_info *ctinfo); +struct nf_conn *nfqnl_ct_parse(const struct sk_buff *skb, + const struct nlattr *attr, + enum ip_conntrack_info *ctinfo); +int nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo); +void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, int diff); +int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr, + u32 portid, u32 report); +#else +inline struct nf_conn * +nfqnl_ct_get(struct sk_buff *entskb, size_t *size, enum ip_conntrack_info *ctinfo) +{ + return NULL; +} + +inline struct nf_conn *nfqnl_ct_parse(const struct sk_buff *skb, + const struct nlattr *attr, + enum ip_conntrack_info *ctinfo) +{ + return NULL; +} + +inline int +nfqnl_ct_put(struct sk_buff *skb, struct nf_conn *ct, enum ip_conntrack_info ctinfo) +{ + return 0; +} + +inline void nfqnl_ct_seq_adjust(struct sk_buff *skb, struct nf_conn *ct, + enum ip_conntrack_info ctinfo, int diff) +{ +} + +inline int nfqnl_attach_expect(struct nf_conn *ct, const struct nlattr *attr, + u32 portid, u32 report) +{ + return 0; +} +#endif /* NF_CONNTRACK */ +#endif diff --git a/include/net/netfilter/nft_masq.h b/include/net/netfilter/nft_masq.h new file mode 100644 index 000000000..e2a518b60 --- /dev/null +++ b/include/net/netfilter/nft_masq.h @@ -0,0 +1,19 @@ +#ifndef _NFT_MASQ_H_ +#define _NFT_MASQ_H_ + +struct nft_masq { + u32 flags; +}; + +extern const struct nla_policy nft_masq_policy[]; + +int nft_masq_init(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nlattr * const tb[]); + +int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr); + +int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, + const struct nft_data **data); + +#endif /* _NFT_MASQ_H_ */ diff --git a/include/net/netfilter/nft_meta.h b/include/net/netfilter/nft_meta.h new file mode 100644 index 000000000..711887a09 --- /dev/null +++ b/include/net/netfilter/nft_meta.h @@ -0,0 +1,36 @@ +#ifndef _NFT_META_H_ +#define _NFT_META_H_ + +struct nft_meta { + enum nft_meta_keys key:8; + union { + enum nft_registers dreg:8; + enum nft_registers sreg:8; + }; +}; + +extern const struct nla_policy nft_meta_policy[]; + +int nft_meta_get_init(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nlattr * const tb[]); + +int nft_meta_set_init(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nlattr * const tb[]); + +int nft_meta_get_dump(struct sk_buff *skb, + const struct nft_expr *expr); + +int nft_meta_set_dump(struct sk_buff *skb, + const struct nft_expr *expr); + +void nft_meta_get_eval(const struct nft_expr *expr, + struct nft_regs *regs, + const struct nft_pktinfo *pkt); + +void nft_meta_set_eval(const struct nft_expr *expr, + struct nft_regs *regs, + const struct nft_pktinfo *pkt); + +#endif diff --git a/include/net/netfilter/nft_redir.h b/include/net/netfilter/nft_redir.h new file mode 100644 index 000000000..a2d67546a --- /dev/null +++ b/include/net/netfilter/nft_redir.h @@ -0,0 +1,21 @@ +#ifndef _NFT_REDIR_H_ +#define _NFT_REDIR_H_ + +struct nft_redir { + enum nft_registers sreg_proto_min:8; + enum nft_registers sreg_proto_max:8; + u16 flags; +}; + +extern const struct nla_policy nft_redir_policy[]; + +int nft_redir_init(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nlattr * const tb[]); + +int nft_redir_dump(struct sk_buff *skb, const struct nft_expr *expr); + +int nft_redir_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, + const struct nft_data **data); + +#endif /* _NFT_REDIR_H_ */ diff --git a/include/net/netfilter/nft_reject.h b/include/net/netfilter/nft_reject.h new file mode 100644 index 000000000..60fa15300 --- /dev/null +++ b/include/net/netfilter/nft_reject.h @@ -0,0 +1,20 @@ +#ifndef _NFT_REJECT_H_ +#define _NFT_REJECT_H_ + +struct nft_reject { + enum nft_reject_types type:8; + u8 icmp_code; +}; + +extern const struct nla_policy nft_reject_policy[]; + +int nft_reject_init(const struct nft_ctx *ctx, + const struct nft_expr *expr, + const struct nlattr * const tb[]); + +int nft_reject_dump(struct sk_buff *skb, const struct nft_expr *expr); + +int nft_reject_icmp_code(u8 code); +int nft_reject_icmpv6_code(u8 code); + +#endif diff --git a/include/net/netfilter/xt_rateest.h b/include/net/netfilter/xt_rateest.h new file mode 100644 index 000000000..79f45e19f --- /dev/null +++ b/include/net/netfilter/xt_rateest.h @@ -0,0 +1,22 @@ +#ifndef _XT_RATEEST_H +#define _XT_RATEEST_H + +struct xt_rateest { + /* keep lock and bstats on same cache line to speedup xt_rateest_tg() */ + struct gnet_stats_basic_packed bstats; + spinlock_t lock; + /* keep rstats and lock on same cache line to speedup xt_rateest_mt() */ + struct gnet_stats_rate_est64 rstats; + + /* following fields not accessed in hot path */ + struct hlist_node list; + char name[IFNAMSIZ]; + unsigned int refcnt; + struct gnet_estimator params; + struct rcu_head rcu; +}; + +struct xt_rateest *xt_rateest_lookup(const char *name); +void xt_rateest_put(struct xt_rateest *est); + +#endif /* _XT_RATEEST_H */ -- cgit v1.2.3-54-g00ecf