Commit ae3e4562 authored by David S. Miller's avatar David S. Miller

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next

Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

The following patchset contains Netfilter updates for net-next,
they are:

1) Don't use userspace datatypes in bridge netfilter code, from
   Tobin Harding.

2) Iterate only once over the expectation table when removing the
   helper module, instead of once per-netns, from Florian Westphal.

3) Extra sanitization in xt_hook_ops_alloc() to return error in case
   we ever pass zero hooks, xt_hook_ops_alloc():

4) Handle NFPROTO_INET from the logging core infrastructure, from
   Liping Zhang.

5) Autoload loggers when TRACE target is used from rules, this doesn't
   change the behaviour in case the user already selected nfnetlink_log
   as preferred way to print tracing logs, also from Liping Zhang.

6) Conntrack slabs with SLAB_HWCACHE_ALIGN to allow rearranging fields
   by cache lines, increases the size of entries in 11% per entry.
   From Florian Westphal.

7) Skip zone comparison if CONFIG_NF_CONNTRACK_ZONES=n, from Florian.

8) Remove useless defensive check in nf_logger_find_get() from Shivani
   Bhardwaj.

9) Remove zone extension as place it in the conntrack object, this is
   always include in the hashing and we expect more intensive use of
   zones since containers are in place. Also from Florian Westphal.

10) Owner match now works from any namespace, from Eric Bierdeman.

11) Make sure we only reply with TCP reset to TCP traffic from
    nf_reject_ipv4, patch from Liping Zhang.

12) Introduce --nflog-size to indicate amount of network packet bytes
    that are copied to userspace via log message, from Vishwanath Pai.
    This obsoletes --nflog-range that has never worked, it was designed
    to achieve this but it has never worked.

13) Introduce generic macros for nf_tables object generation masks.

14) Use generation mask in table, chain and set objects in nf_tables.
    This allows fixes interferences with ongoing preparation phase of
    the commit protocol and object listings going on at the same time.
    This update is introduced in three patches, one per object.

15) Check if the object is active in the next generation for element
    deactivation in the rbtree implementation, given that deactivation
    happens from the commit phase path we have to observe the future
    status of the object.

16) Support for deletion of just added elements in the hash set type.

17) Allow to resize hashtable from /proc entry, not only from the
    obscure /sys entry that maps to the module parameter, from Florian
    Westphal.

18) Get rid of NFT_BASECHAIN_DISABLED, this code is not exercised
    anymore since we tear down the ruleset whenever the netdevice
    goes away.

19) Support for matching inverted set lookups, from Arturo Borrero.

20) Simplify the iptables_mangle_hook() by removing a superfluous
    extra branch.

21) Introduce ether_addr_equal_masked() and use it from the netfilter
    codebase, from Joe Perches.

22) Remove references to "Use netfilter MARK value as routing key"
    from the Netfilter Kconfig description given that this toggle
    doesn't exists already for 10 years, from Moritz Sichert.

23) Introduce generic NF_INVF() and use it from the xtables codebase,
    from Joe Perches.

24) Setting logger to NONE via /proc was not working unless explicit
    nul-termination was included in the string. This fixes seems to
    leave the former behaviour there, so we don't break backward.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 73e20b76 c6ac37d8
...@@ -7,12 +7,13 @@ nf_conntrack_acct - BOOLEAN ...@@ -7,12 +7,13 @@ nf_conntrack_acct - BOOLEAN
Enable connection tracking flow accounting. 64-bit byte and packet Enable connection tracking flow accounting. 64-bit byte and packet
counters per flow are added. counters per flow are added.
nf_conntrack_buckets - INTEGER (read-only) nf_conntrack_buckets - INTEGER
Size of hash table. If not specified as parameter during module Size of hash table. If not specified as parameter during module
loading, the default size is calculated by dividing total memory loading, the default size is calculated by dividing total memory
by 16384 to determine the number of buckets but the hash table will by 16384 to determine the number of buckets but the hash table will
never have fewer than 32 and limited to 16384 buckets. For systems never have fewer than 32 and limited to 16384 buckets. For systems
with more than 4GB of memory it will be 65536 buckets. with more than 4GB of memory it will be 65536 buckets.
This sysctl is only writeable in the initial net namespace.
nf_conntrack_checksum - BOOLEAN nf_conntrack_checksum - BOOLEAN
0 - disabled 0 - disabled
......
...@@ -373,6 +373,29 @@ static inline bool ether_addr_equal_unaligned(const u8 *addr1, const u8 *addr2) ...@@ -373,6 +373,29 @@ static inline bool ether_addr_equal_unaligned(const u8 *addr1, const u8 *addr2)
#endif #endif
} }
/**
* ether_addr_equal_masked - Compare two Ethernet addresses with a mask
* @addr1: Pointer to a six-byte array containing the 1st Ethernet address
* @addr2: Pointer to a six-byte array containing the 2nd Ethernet address
* @mask: Pointer to a six-byte array containing the Ethernet address bitmask
*
* Compare two Ethernet addresses with a mask, returns true if for every bit
* set in the bitmask the equivalent bits in the ethernet addresses are equal.
* Using a mask with all bits set is a slower ether_addr_equal.
*/
static inline bool ether_addr_equal_masked(const u8 *addr1, const u8 *addr2,
const u8 *mask)
{
int i;
for (i = 0; i < ETH_ALEN; i++) {
if ((addr1[i] ^ addr2[i]) & mask[i])
return false;
}
return true;
}
/** /**
* is_etherdev_addr - Tell if given Ethernet address belongs to the device. * is_etherdev_addr - Tell if given Ethernet address belongs to the device.
* @dev: Pointer to a device structure * @dev: Pointer to a device structure
......
...@@ -6,6 +6,10 @@ ...@@ -6,6 +6,10 @@
#include <linux/static_key.h> #include <linux/static_key.h>
#include <uapi/linux/netfilter/x_tables.h> #include <uapi/linux/netfilter/x_tables.h>
/* Test a struct->invflags and a boolean for inequality */
#define NF_INVF(ptr, flag, boolean) \
((boolean) ^ !!((ptr)->invflags & (flag)))
/** /**
* struct xt_action_param - parameters for matches/targets * struct xt_action_param - parameters for matches/targets
* *
......
...@@ -115,8 +115,6 @@ extern unsigned int ebt_do_table(struct sk_buff *skb, ...@@ -115,8 +115,6 @@ extern unsigned int ebt_do_table(struct sk_buff *skb,
const struct nf_hook_state *state, const struct nf_hook_state *state,
struct ebt_table *table); struct ebt_table *table);
/* Used in the kernel match() functions */
#define FWINV(bool,invflg) ((bool) ^ !!(info->invflags & invflg))
/* True if the hook mask denotes that the rule is in a base chain, /* True if the hook mask denotes that the rule is in a base chain,
* used in the check() functions */ * used in the check() functions */
#define BASE_CHAIN (par->hook_mask & (1 << NF_BR_NUMHOOKS)) #define BASE_CHAIN (par->hook_mask & (1 << NF_BR_NUMHOOKS))
......
...@@ -85,6 +85,9 @@ struct nf_conn { ...@@ -85,6 +85,9 @@ struct nf_conn {
spinlock_t lock; spinlock_t lock;
u16 cpu; u16 cpu;
#ifdef CONFIG_NF_CONNTRACK_ZONES
struct nf_conntrack_zone zone;
#endif
/* XXX should I move this to the tail ? - Y.K */ /* XXX should I move this to the tail ? - Y.K */
/* These are my tuples; original and reply */ /* These are my tuples; original and reply */
struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; struct nf_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX];
...@@ -287,6 +290,7 @@ static inline bool nf_is_loopback_packet(const struct sk_buff *skb) ...@@ -287,6 +290,7 @@ static inline bool nf_is_loopback_packet(const struct sk_buff *skb)
struct kernel_param; struct kernel_param;
int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp); int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp);
int nf_conntrack_hash_resize(unsigned int hashsize);
extern unsigned int nf_conntrack_htable_size; extern unsigned int nf_conntrack_htable_size;
extern unsigned int nf_conntrack_max; extern unsigned int nf_conntrack_max;
......
...@@ -15,9 +15,6 @@ enum nf_ct_ext_id { ...@@ -15,9 +15,6 @@ enum nf_ct_ext_id {
#ifdef CONFIG_NF_CONNTRACK_EVENTS #ifdef CONFIG_NF_CONNTRACK_EVENTS
NF_CT_EXT_ECACHE, NF_CT_EXT_ECACHE,
#endif #endif
#ifdef CONFIG_NF_CONNTRACK_ZONES
NF_CT_EXT_ZONE,
#endif
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP #ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
NF_CT_EXT_TSTAMP, NF_CT_EXT_TSTAMP,
#endif #endif
...@@ -38,7 +35,6 @@ enum nf_ct_ext_id { ...@@ -38,7 +35,6 @@ enum nf_ct_ext_id {
#define NF_CT_EXT_SEQADJ_TYPE struct nf_conn_seqadj #define NF_CT_EXT_SEQADJ_TYPE struct nf_conn_seqadj
#define NF_CT_EXT_ACCT_TYPE struct nf_conn_acct #define NF_CT_EXT_ACCT_TYPE struct nf_conn_acct
#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache #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_TSTAMP_TYPE struct nf_conn_tstamp
#define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout #define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
#define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels #define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
......
...@@ -9,12 +9,11 @@ ...@@ -9,12 +9,11 @@
static inline const struct nf_conntrack_zone * static inline const struct nf_conntrack_zone *
nf_ct_zone(const struct nf_conn *ct) nf_ct_zone(const struct nf_conn *ct)
{ {
const struct nf_conntrack_zone *nf_ct_zone = NULL;
#ifdef CONFIG_NF_CONNTRACK_ZONES #ifdef CONFIG_NF_CONNTRACK_ZONES
nf_ct_zone = nf_ct_ext_find(ct, NF_CT_EXT_ZONE); return &ct->zone;
#else
return &nf_ct_zone_dflt;
#endif #endif
return nf_ct_zone ? nf_ct_zone : &nf_ct_zone_dflt;
} }
static inline const struct nf_conntrack_zone * static inline const struct nf_conntrack_zone *
...@@ -31,32 +30,22 @@ static inline const struct nf_conntrack_zone * ...@@ -31,32 +30,22 @@ static inline const struct nf_conntrack_zone *
nf_ct_zone_tmpl(const struct nf_conn *tmpl, const struct sk_buff *skb, nf_ct_zone_tmpl(const struct nf_conn *tmpl, const struct sk_buff *skb,
struct nf_conntrack_zone *tmp) struct nf_conntrack_zone *tmp)
{ {
const struct nf_conntrack_zone *zone; #ifdef CONFIG_NF_CONNTRACK_ZONES
if (!tmpl) if (!tmpl)
return &nf_ct_zone_dflt; return &nf_ct_zone_dflt;
zone = nf_ct_zone(tmpl); if (tmpl->zone.flags & NF_CT_FLAG_MARK)
if (zone->flags & NF_CT_FLAG_MARK) return nf_ct_zone_init(tmp, skb->mark, tmpl->zone.dir, 0);
zone = nf_ct_zone_init(tmp, skb->mark, zone->dir, 0); #endif
return nf_ct_zone(tmpl);
return zone;
} }
static inline int nf_ct_zone_add(struct nf_conn *ct, gfp_t flags, static inline void nf_ct_zone_add(struct nf_conn *ct,
const struct nf_conntrack_zone *info) const struct nf_conntrack_zone *zone)
{ {
#ifdef CONFIG_NF_CONNTRACK_ZONES #ifdef CONFIG_NF_CONNTRACK_ZONES
struct nf_conntrack_zone *nf_ct_zone; ct->zone = *zone;
nf_ct_zone = nf_ct_ext_add(ct, NF_CT_EXT_ZONE, flags);
if (!nf_ct_zone)
return -ENOMEM;
nf_ct_zone_init(nf_ct_zone, info->id, info->dir,
info->flags);
#endif #endif
return 0;
} }
static inline bool nf_ct_zone_matches_dir(const struct nf_conntrack_zone *zone, static inline bool nf_ct_zone_matches_dir(const struct nf_conntrack_zone *zone,
...@@ -68,22 +57,34 @@ static inline bool nf_ct_zone_matches_dir(const struct nf_conntrack_zone *zone, ...@@ -68,22 +57,34 @@ static inline bool nf_ct_zone_matches_dir(const struct nf_conntrack_zone *zone,
static inline u16 nf_ct_zone_id(const struct nf_conntrack_zone *zone, static inline u16 nf_ct_zone_id(const struct nf_conntrack_zone *zone,
enum ip_conntrack_dir dir) enum ip_conntrack_dir dir)
{ {
#ifdef CONFIG_NF_CONNTRACK_ZONES
return nf_ct_zone_matches_dir(zone, dir) ? return nf_ct_zone_matches_dir(zone, dir) ?
zone->id : NF_CT_DEFAULT_ZONE_ID; zone->id : NF_CT_DEFAULT_ZONE_ID;
#else
return NF_CT_DEFAULT_ZONE_ID;
#endif
} }
static inline bool nf_ct_zone_equal(const struct nf_conn *a, static inline bool nf_ct_zone_equal(const struct nf_conn *a,
const struct nf_conntrack_zone *b, const struct nf_conntrack_zone *b,
enum ip_conntrack_dir dir) enum ip_conntrack_dir dir)
{ {
#ifdef CONFIG_NF_CONNTRACK_ZONES
return nf_ct_zone_id(nf_ct_zone(a), dir) == return nf_ct_zone_id(nf_ct_zone(a), dir) ==
nf_ct_zone_id(b, dir); nf_ct_zone_id(b, dir);
#else
return true;
#endif
} }
static inline bool nf_ct_zone_equal_any(const struct nf_conn *a, static inline bool nf_ct_zone_equal_any(const struct nf_conn *a,
const struct nf_conntrack_zone *b) const struct nf_conntrack_zone *b)
{ {
#ifdef CONFIG_NF_CONNTRACK_ZONES
return nf_ct_zone(a)->id == b->id; return nf_ct_zone(a)->id == b->id;
#else
return true;
#endif
} }
#endif /* IS_ENABLED(CONFIG_NF_CONNTRACK) */ #endif /* IS_ENABLED(CONFIG_NF_CONNTRACK) */
#endif /* _NF_CONNTRACK_ZONES_H */ #endif /* _NF_CONNTRACK_ZONES_H */
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
#define NF_LOG_UID 0x08 /* Log UID owning local socket */ #define NF_LOG_UID 0x08 /* Log UID owning local socket */
#define NF_LOG_MASK 0x0f #define NF_LOG_MASK 0x0f
/* This flag indicates that copy_len field in nf_loginfo is set */
#define NF_LOG_F_COPY_LEN 0x1
enum nf_log_type { enum nf_log_type {
NF_LOG_TYPE_LOG = 0, NF_LOG_TYPE_LOG = 0,
NF_LOG_TYPE_ULOG, NF_LOG_TYPE_ULOG,
...@@ -22,9 +25,13 @@ struct nf_loginfo { ...@@ -22,9 +25,13 @@ struct nf_loginfo {
u_int8_t type; u_int8_t type;
union { union {
struct { struct {
/* copy_len will be used iff you set
* NF_LOG_F_COPY_LEN in flags
*/
u_int32_t copy_len; u_int32_t copy_len;
u_int16_t group; u_int16_t group;
u_int16_t qthreshold; u_int16_t qthreshold;
u_int16_t flags;
} ulog; } ulog;
struct { struct {
u_int8_t level; u_int8_t level;
......
...@@ -297,6 +297,7 @@ void nft_unregister_set(struct nft_set_ops *ops); ...@@ -297,6 +297,7 @@ void nft_unregister_set(struct nft_set_ops *ops);
* @ops: set ops * @ops: set ops
* @pnet: network namespace * @pnet: network namespace
* @flags: set flags * @flags: set flags
* @genmask: generation mask
* @klen: key length * @klen: key length
* @dlen: data length * @dlen: data length
* @data: private set data * @data: private set data
...@@ -318,7 +319,8 @@ struct nft_set { ...@@ -318,7 +319,8 @@ struct nft_set {
/* runtime data below here */ /* runtime data below here */
const struct nft_set_ops *ops ____cacheline_aligned; const struct nft_set_ops *ops ____cacheline_aligned;
possible_net_t pnet; possible_net_t pnet;
u16 flags; u16 flags:14,
genmask:2;
u8 klen; u8 klen;
u8 dlen; u8 dlen;
unsigned char data[] unsigned char data[]
...@@ -336,9 +338,9 @@ static inline struct nft_set *nft_set_container_of(const void *priv) ...@@ -336,9 +338,9 @@ static inline struct nft_set *nft_set_container_of(const void *priv)
} }
struct nft_set *nf_tables_set_lookup(const struct nft_table *table, struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
const struct nlattr *nla); const struct nlattr *nla, u8 genmask);
struct nft_set *nf_tables_set_lookup_byid(const struct net *net, struct nft_set *nf_tables_set_lookup_byid(const struct net *net,
const struct nlattr *nla); const struct nlattr *nla, u8 genmask);
static inline unsigned long nft_set_gc_interval(const struct nft_set *set) static inline unsigned long nft_set_gc_interval(const struct nft_set *set)
{ {
...@@ -733,7 +735,6 @@ static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule) ...@@ -733,7 +735,6 @@ static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule)
enum nft_chain_flags { enum nft_chain_flags {
NFT_BASE_CHAIN = 0x1, NFT_BASE_CHAIN = 0x1,
NFT_CHAIN_INACTIVE = 0x2,
}; };
/** /**
...@@ -755,7 +756,8 @@ struct nft_chain { ...@@ -755,7 +756,8 @@ struct nft_chain {
u64 handle; u64 handle;
u32 use; u32 use;
u16 level; u16 level;
u8 flags; u8 flags:6,
genmask:2;
char name[NFT_CHAIN_MAXNAMELEN]; char name[NFT_CHAIN_MAXNAMELEN];
}; };
...@@ -797,7 +799,6 @@ struct nft_stats { ...@@ -797,7 +799,6 @@ struct nft_stats {
}; };
#define NFT_HOOK_OPS_MAX 2 #define NFT_HOOK_OPS_MAX 2
#define NFT_BASECHAIN_DISABLED (1 << 0)
/** /**
* struct nft_base_chain - nf_tables base chain * struct nft_base_chain - nf_tables base chain
...@@ -839,6 +840,7 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv); ...@@ -839,6 +840,7 @@ unsigned int nft_do_chain(struct nft_pktinfo *pkt, void *priv);
* @hgenerator: handle generator state * @hgenerator: handle generator state
* @use: number of chain references to this table * @use: number of chain references to this table
* @flags: table flag (see enum nft_table_flags) * @flags: table flag (see enum nft_table_flags)
* @genmask: generation mask
* @name: name of the table * @name: name of the table
*/ */
struct nft_table { struct nft_table {
...@@ -847,7 +849,8 @@ struct nft_table { ...@@ -847,7 +849,8 @@ struct nft_table {
struct list_head sets; struct list_head sets;
u64 hgenerator; u64 hgenerator;
u32 use; u32 use;
u16 flags; u16 flags:14,
genmask:2;
char name[NFT_TABLE_MAXNAMELEN]; char name[NFT_TABLE_MAXNAMELEN];
}; };
...@@ -970,6 +973,32 @@ static inline u8 nft_genmask_cur(const struct net *net) ...@@ -970,6 +973,32 @@ static inline u8 nft_genmask_cur(const struct net *net)
#define NFT_GENMASK_ANY ((1 << 0) | (1 << 1)) #define NFT_GENMASK_ANY ((1 << 0) | (1 << 1))
/*
* Generic transaction helpers
*/
/* Check if this object is currently active. */
#define nft_is_active(__net, __obj) \
(((__obj)->genmask & nft_genmask_cur(__net)) == 0)
/* Check if this object is active in the next generation. */
#define nft_is_active_next(__net, __obj) \
(((__obj)->genmask & nft_genmask_next(__net)) == 0)
/* This object becomes active in the next generation. */
#define nft_activate_next(__net, __obj) \
(__obj)->genmask = nft_genmask_cur(__net)
/* This object becomes inactive in the next generation. */
#define nft_deactivate_next(__net, __obj) \
(__obj)->genmask = nft_genmask_next(__net)
/* After committing the ruleset, clear the stale generation bit. */
#define nft_clear(__net, __obj) \
(__obj)->genmask &= ~nft_genmask_next(__net)
#define nft_active_genmask(__obj, __genmask) \
!((__obj)->genmask & __genmask)
/* /*
* Set element transaction helpers * Set element transaction helpers
*/ */
......
...@@ -546,6 +546,10 @@ enum nft_cmp_attributes { ...@@ -546,6 +546,10 @@ enum nft_cmp_attributes {
}; };
#define NFTA_CMP_MAX (__NFTA_CMP_MAX - 1) #define NFTA_CMP_MAX (__NFTA_CMP_MAX - 1)
enum nft_lookup_flags {
NFT_LOOKUP_F_INV = (1 << 0),
};
/** /**
* enum nft_lookup_attributes - nf_tables set lookup expression netlink attributes * enum nft_lookup_attributes - nf_tables set lookup expression netlink attributes
* *
...@@ -553,6 +557,7 @@ enum nft_cmp_attributes { ...@@ -553,6 +557,7 @@ enum nft_cmp_attributes {
* @NFTA_LOOKUP_SREG: source register of the data to look for (NLA_U32: nft_registers) * @NFTA_LOOKUP_SREG: source register of the data to look for (NLA_U32: nft_registers)
* @NFTA_LOOKUP_DREG: destination register (NLA_U32: nft_registers) * @NFTA_LOOKUP_DREG: destination register (NLA_U32: nft_registers)
* @NFTA_LOOKUP_SET_ID: uniquely identifies a set in a transaction (NLA_U32) * @NFTA_LOOKUP_SET_ID: uniquely identifies a set in a transaction (NLA_U32)
* @NFTA_LOOKUP_FLAGS: flags (NLA_U32: enum nft_lookup_flags)
*/ */
enum nft_lookup_attributes { enum nft_lookup_attributes {
NFTA_LOOKUP_UNSPEC, NFTA_LOOKUP_UNSPEC,
...@@ -560,6 +565,7 @@ enum nft_lookup_attributes { ...@@ -560,6 +565,7 @@ enum nft_lookup_attributes {
NFTA_LOOKUP_SREG, NFTA_LOOKUP_SREG,
NFTA_LOOKUP_DREG, NFTA_LOOKUP_DREG,
NFTA_LOOKUP_SET_ID, NFTA_LOOKUP_SET_ID,
NFTA_LOOKUP_FLAGS,
__NFTA_LOOKUP_MAX __NFTA_LOOKUP_MAX
}; };
#define NFTA_LOOKUP_MAX (__NFTA_LOOKUP_MAX - 1) #define NFTA_LOOKUP_MAX (__NFTA_LOOKUP_MAX - 1)
......
...@@ -6,9 +6,13 @@ ...@@ -6,9 +6,13 @@
#define XT_NFLOG_DEFAULT_GROUP 0x1 #define XT_NFLOG_DEFAULT_GROUP 0x1
#define XT_NFLOG_DEFAULT_THRESHOLD 0 #define XT_NFLOG_DEFAULT_THRESHOLD 0
#define XT_NFLOG_MASK 0x0 #define XT_NFLOG_MASK 0x1
/* This flag indicates that 'len' field in xt_nflog_info is set*/
#define XT_NFLOG_F_COPY_LEN 0x1
struct xt_nflog_info { struct xt_nflog_info {
/* 'len' will be used iff you set XT_NFLOG_F_COPY_LEN in flags */
__u32 len; __u32 len;
__u16 group; __u16 group;
__u16 threshold; __u16 threshold;
......
...@@ -20,16 +20,16 @@ ebt_802_3_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -20,16 +20,16 @@ ebt_802_3_mt(const struct sk_buff *skb, struct xt_action_param *par)
__be16 type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type; __be16 type = hdr->llc.ui.ctrl & IS_UI ? hdr->llc.ui.type : hdr->llc.ni.type;
if (info->bitmask & EBT_802_3_SAP) { if (info->bitmask & EBT_802_3_SAP) {
if (FWINV(info->sap != hdr->llc.ui.ssap, EBT_802_3_SAP)) if (NF_INVF(info, EBT_802_3_SAP, info->sap != hdr->llc.ui.ssap))
return false; return false;
if (FWINV(info->sap != hdr->llc.ui.dsap, EBT_802_3_SAP)) if (NF_INVF(info, EBT_802_3_SAP, info->sap != hdr->llc.ui.dsap))
return false; return false;
} }
if (info->bitmask & EBT_802_3_TYPE) { if (info->bitmask & EBT_802_3_TYPE) {
if (!(hdr->llc.ui.dsap == CHECK_TYPE && hdr->llc.ui.ssap == CHECK_TYPE)) if (!(hdr->llc.ui.dsap == CHECK_TYPE && hdr->llc.ui.ssap == CHECK_TYPE))
return false; return false;
if (FWINV(info->type != type, EBT_802_3_TYPE)) if (NF_INVF(info, EBT_802_3_TYPE, info->type != type))
return false; return false;
} }
......
...@@ -25,14 +25,14 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -25,14 +25,14 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par)
ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph); ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
if (ah == NULL) if (ah == NULL)
return false; return false;
if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode != if ((info->bitmask & EBT_ARP_OPCODE) &&
ah->ar_op, EBT_ARP_OPCODE)) NF_INVF(info, EBT_ARP_OPCODE, info->opcode != ah->ar_op))
return false; return false;
if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype != if ((info->bitmask & EBT_ARP_HTYPE) &&
ah->ar_hrd, EBT_ARP_HTYPE)) NF_INVF(info, EBT_ARP_HTYPE, info->htype != ah->ar_hrd))
return false; return false;
if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype != if ((info->bitmask & EBT_ARP_PTYPE) &&
ah->ar_pro, EBT_ARP_PTYPE)) NF_INVF(info, EBT_ARP_PTYPE, info->ptype != ah->ar_pro))
return false; return false;
if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_GRAT)) { if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP | EBT_ARP_GRAT)) {
...@@ -51,21 +51,22 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -51,21 +51,22 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par)
sizeof(daddr), &daddr); sizeof(daddr), &daddr);
if (dap == NULL) if (dap == NULL)
return false; return false;
if (info->bitmask & EBT_ARP_SRC_IP && if ((info->bitmask & EBT_ARP_SRC_IP) &&
FWINV(info->saddr != (*sap & info->smsk), EBT_ARP_SRC_IP)) NF_INVF(info, EBT_ARP_SRC_IP,
info->saddr != (*sap & info->smsk)))
return false; return false;
if (info->bitmask & EBT_ARP_DST_IP && if ((info->bitmask & EBT_ARP_DST_IP) &&
FWINV(info->daddr != (*dap & info->dmsk), EBT_ARP_DST_IP)) NF_INVF(info, EBT_ARP_DST_IP,
info->daddr != (*dap & info->dmsk)))
return false; return false;
if (info->bitmask & EBT_ARP_GRAT && if ((info->bitmask & EBT_ARP_GRAT) &&
FWINV(*dap != *sap, EBT_ARP_GRAT)) NF_INVF(info, EBT_ARP_GRAT, *dap != *sap))
return false; return false;
} }
if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) { if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
const unsigned char *mp; const unsigned char *mp;
unsigned char _mac[ETH_ALEN]; unsigned char _mac[ETH_ALEN];
uint8_t verdict, i;
if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER)) if (ah->ar_hln != ETH_ALEN || ah->ar_hrd != htons(ARPHRD_ETHER))
return false; return false;
...@@ -74,11 +75,9 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -74,11 +75,9 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par)
sizeof(_mac), &_mac); sizeof(_mac), &_mac);
if (mp == NULL) if (mp == NULL)
return false; return false;
verdict = 0; if (NF_INVF(info, EBT_ARP_SRC_MAC,
for (i = 0; i < 6; i++) !ether_addr_equal_masked(mp, info->smaddr,
verdict |= (mp[i] ^ info->smaddr[i]) & info->smmsk)))
info->smmsk[i];
if (FWINV(verdict != 0, EBT_ARP_SRC_MAC))
return false; return false;
} }
...@@ -88,11 +87,9 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -88,11 +87,9 @@ ebt_arp_mt(const struct sk_buff *skb, struct xt_action_param *par)
sizeof(_mac), &_mac); sizeof(_mac), &_mac);
if (mp == NULL) if (mp == NULL)
return false; return false;
verdict = 0; if (NF_INVF(info, EBT_ARP_DST_MAC,
for (i = 0; i < 6; i++) !ether_addr_equal_masked(mp, info->dmaddr,
verdict |= (mp[i] ^ info->dmaddr[i]) & info->dmmsk)))
info->dmmsk[i];
if (FWINV(verdict != 0, EBT_ARP_DST_MAC))
return false; return false;
} }
} }
......
...@@ -36,19 +36,19 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -36,19 +36,19 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par)
ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph); ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
if (ih == NULL) if (ih == NULL)
return false; return false;
if (info->bitmask & EBT_IP_TOS && if ((info->bitmask & EBT_IP_TOS) &&
FWINV(info->tos != ih->tos, EBT_IP_TOS)) NF_INVF(info, EBT_IP_TOS, info->tos != ih->tos))
return false; return false;
if (info->bitmask & EBT_IP_SOURCE && if ((info->bitmask & EBT_IP_SOURCE) &&
FWINV((ih->saddr & info->smsk) != NF_INVF(info, EBT_IP_SOURCE,
info->saddr, EBT_IP_SOURCE)) (ih->saddr & info->smsk) != info->saddr))
return false; return false;
if ((info->bitmask & EBT_IP_DEST) && if ((info->bitmask & EBT_IP_DEST) &&
FWINV((ih->daddr & info->dmsk) != NF_INVF(info, EBT_IP_DEST,
info->daddr, EBT_IP_DEST)) (ih->daddr & info->dmsk) != info->daddr))
return false; return false;
if (info->bitmask & EBT_IP_PROTO) { if (info->bitmask & EBT_IP_PROTO) {
if (FWINV(info->protocol != ih->protocol, EBT_IP_PROTO)) if (NF_INVF(info, EBT_IP_PROTO, info->protocol != ih->protocol))
return false; return false;
if (!(info->bitmask & EBT_IP_DPORT) && if (!(info->bitmask & EBT_IP_DPORT) &&
!(info->bitmask & EBT_IP_SPORT)) !(info->bitmask & EBT_IP_SPORT))
...@@ -61,16 +61,16 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -61,16 +61,16 @@ ebt_ip_mt(const struct sk_buff *skb, struct xt_action_param *par)
return false; return false;
if (info->bitmask & EBT_IP_DPORT) { if (info->bitmask & EBT_IP_DPORT) {
u32 dst = ntohs(pptr->dst); u32 dst = ntohs(pptr->dst);
if (FWINV(dst < info->dport[0] || if (NF_INVF(info, EBT_IP_DPORT,
dst > info->dport[1], dst < info->dport[0] ||
EBT_IP_DPORT)) dst > info->dport[1]))
return false; return false;
} }
if (info->bitmask & EBT_IP_SPORT) { if (info->bitmask & EBT_IP_SPORT) {
u32 src = ntohs(pptr->src); u32 src = ntohs(pptr->src);
if (FWINV(src < info->sport[0] || if (NF_INVF(info, EBT_IP_SPORT,
src > info->sport[1], src < info->sport[0] ||
EBT_IP_SPORT)) src > info->sport[1]))
return false; return false;
} }
} }
......
...@@ -45,15 +45,18 @@ ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -45,15 +45,18 @@ ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par)
ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h); ih6 = skb_header_pointer(skb, 0, sizeof(_ip6h), &_ip6h);
if (ih6 == NULL) if (ih6 == NULL)
return false; return false;
if (info->bitmask & EBT_IP6_TCLASS && if ((info->bitmask & EBT_IP6_TCLASS) &&
FWINV(info->tclass != ipv6_get_dsfield(ih6), EBT_IP6_TCLASS)) NF_INVF(info, EBT_IP6_TCLASS,
info->tclass != ipv6_get_dsfield(ih6)))
return false; return false;
if ((info->bitmask & EBT_IP6_SOURCE && if (((info->bitmask & EBT_IP6_SOURCE) &&
FWINV(ipv6_masked_addr_cmp(&ih6->saddr, &info->smsk, NF_INVF(info, EBT_IP6_SOURCE,
&info->saddr), EBT_IP6_SOURCE)) || ipv6_masked_addr_cmp(&ih6->saddr, &info->smsk,
(info->bitmask & EBT_IP6_DEST && &info->saddr))) ||
FWINV(ipv6_masked_addr_cmp(&ih6->daddr, &info->dmsk, ((info->bitmask & EBT_IP6_DEST) &&
&info->daddr), EBT_IP6_DEST))) NF_INVF(info, EBT_IP6_DEST,
ipv6_masked_addr_cmp(&ih6->daddr, &info->dmsk,
&info->daddr))))
return false; return false;
if (info->bitmask & EBT_IP6_PROTO) { if (info->bitmask & EBT_IP6_PROTO) {
uint8_t nexthdr = ih6->nexthdr; uint8_t nexthdr = ih6->nexthdr;
...@@ -63,7 +66,7 @@ ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -63,7 +66,7 @@ ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par)
offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr, &frag_off); offset_ph = ipv6_skip_exthdr(skb, sizeof(_ip6h), &nexthdr, &frag_off);
if (offset_ph == -1) if (offset_ph == -1)
return false; return false;
if (FWINV(info->protocol != nexthdr, EBT_IP6_PROTO)) if (NF_INVF(info, EBT_IP6_PROTO, info->protocol != nexthdr))
return false; return false;
if (!(info->bitmask & (EBT_IP6_DPORT | if (!(info->bitmask & (EBT_IP6_DPORT |
EBT_IP6_SPORT | EBT_IP6_ICMP6))) EBT_IP6_SPORT | EBT_IP6_ICMP6)))
...@@ -76,22 +79,24 @@ ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -76,22 +79,24 @@ ebt_ip6_mt(const struct sk_buff *skb, struct xt_action_param *par)
return false; return false;
if (info->bitmask & EBT_IP6_DPORT) { if (info->bitmask & EBT_IP6_DPORT) {
u16 dst = ntohs(pptr->tcpudphdr.dst); u16 dst = ntohs(pptr->tcpudphdr.dst);
if (FWINV(dst < info->dport[0] || if (NF_INVF(info, EBT_IP6_DPORT,
dst > info->dport[1], EBT_IP6_DPORT)) dst < info->dport[0] ||
dst > info->dport[1]))
return false; return false;
} }
if (info->bitmask & EBT_IP6_SPORT) { if (info->bitmask & EBT_IP6_SPORT) {
u16 src = ntohs(pptr->tcpudphdr.src); u16 src = ntohs(pptr->tcpudphdr.src);
if (FWINV(src < info->sport[0] || if (NF_INVF(info, EBT_IP6_SPORT,
src > info->sport[1], EBT_IP6_SPORT)) src < info->sport[0] ||
src > info->sport[1]))
return false; return false;
} }
if ((info->bitmask & EBT_IP6_ICMP6) && if ((info->bitmask & EBT_IP6_ICMP6) &&
FWINV(pptr->icmphdr.type < info->icmpv6_type[0] || NF_INVF(info, EBT_IP6_ICMP6,
pptr->icmphdr.type > info->icmpv6_type[1] || pptr->icmphdr.type < info->icmpv6_type[0] ||
pptr->icmphdr.code < info->icmpv6_code[0] || pptr->icmphdr.type > info->icmpv6_type[1] ||
pptr->icmphdr.code > info->icmpv6_code[1], pptr->icmphdr.code < info->icmpv6_code[0] ||
EBT_IP6_ICMP6)) pptr->icmphdr.code > info->icmpv6_code[1]))
return false; return false;
} }
return true; return true;
......
...@@ -17,24 +17,24 @@ ...@@ -17,24 +17,24 @@
#define BPDU_TYPE_TCN 0x80 #define BPDU_TYPE_TCN 0x80
struct stp_header { struct stp_header {
uint8_t dsap; u8 dsap;
uint8_t ssap; u8 ssap;
uint8_t ctrl; u8 ctrl;
uint8_t pid; u8 pid;
uint8_t vers; u8 vers;
uint8_t type; u8 type;
}; };
struct stp_config_pdu { struct stp_config_pdu {
uint8_t flags; u8 flags;
uint8_t root[8]; u8 root[8];
uint8_t root_cost[4]; u8 root_cost[4];
uint8_t sender[8]; u8 sender[8];
uint8_t port[2]; u8 port[2];
uint8_t msg_age[2]; u8 msg_age[2];
uint8_t max_age[2]; u8 max_age[2];
uint8_t hello_time[2]; u8 hello_time[2];
uint8_t forward_delay[2]; u8 forward_delay[2];
}; };
#define NR16(p) (p[0] << 8 | p[1]) #define NR16(p) (p[0] << 8 | p[1])
...@@ -44,76 +44,73 @@ static bool ebt_filter_config(const struct ebt_stp_info *info, ...@@ -44,76 +44,73 @@ static bool ebt_filter_config(const struct ebt_stp_info *info,
const struct stp_config_pdu *stpc) const struct stp_config_pdu *stpc)
{ {
const struct ebt_stp_config_info *c; const struct ebt_stp_config_info *c;
uint16_t v16; u16 v16;
uint32_t v32; u32 v32;
int verdict, i;
c = &info->config; c = &info->config;
if ((info->bitmask & EBT_STP_FLAGS) && if ((info->bitmask & EBT_STP_FLAGS) &&
FWINV(c->flags != stpc->flags, EBT_STP_FLAGS)) NF_INVF(info, EBT_STP_FLAGS, c->flags != stpc->flags))
return false; return false;
if (info->bitmask & EBT_STP_ROOTPRIO) { if (info->bitmask & EBT_STP_ROOTPRIO) {
v16 = NR16(stpc->root); v16 = NR16(stpc->root);
if (FWINV(v16 < c->root_priol || if (NF_INVF(info, EBT_STP_ROOTPRIO,
v16 > c->root_priou, EBT_STP_ROOTPRIO)) v16 < c->root_priol || v16 > c->root_priou))
return false; return false;
} }
if (info->bitmask & EBT_STP_ROOTADDR) { if (info->bitmask & EBT_STP_ROOTADDR) {
verdict = 0; if (NF_INVF(info, EBT_STP_ROOTADDR,
for (i = 0; i < 6; i++) !ether_addr_equal_masked(&stpc->root[2],
verdict |= (stpc->root[2+i] ^ c->root_addr[i]) & c->root_addr,
c->root_addrmsk[i]; c->root_addrmsk)))
if (FWINV(verdict != 0, EBT_STP_ROOTADDR))
return false; return false;
} }
if (info->bitmask & EBT_STP_ROOTCOST) { if (info->bitmask & EBT_STP_ROOTCOST) {
v32 = NR32(stpc->root_cost); v32 = NR32(stpc->root_cost);
if (FWINV(v32 < c->root_costl || if (NF_INVF(info, EBT_STP_ROOTCOST,
v32 > c->root_costu, EBT_STP_ROOTCOST)) v32 < c->root_costl || v32 > c->root_costu))
return false; return false;
} }
if (info->bitmask & EBT_STP_SENDERPRIO) { if (info->bitmask & EBT_STP_SENDERPRIO) {
v16 = NR16(stpc->sender); v16 = NR16(stpc->sender);
if (FWINV(v16 < c->sender_priol || if (NF_INVF(info, EBT_STP_SENDERPRIO,
v16 > c->sender_priou, EBT_STP_SENDERPRIO)) v16 < c->sender_priol || v16 > c->sender_priou))
return false; return false;
} }
if (info->bitmask & EBT_STP_SENDERADDR) { if (info->bitmask & EBT_STP_SENDERADDR) {
verdict = 0; if (NF_INVF(info, EBT_STP_SENDERADDR,
for (i = 0; i < 6; i++) !ether_addr_equal_masked(&stpc->sender[2],
verdict |= (stpc->sender[2+i] ^ c->sender_addr[i]) & c->sender_addr,
c->sender_addrmsk[i]; c->sender_addrmsk)))
if (FWINV(verdict != 0, EBT_STP_SENDERADDR))
return false; return false;
} }
if (info->bitmask & EBT_STP_PORT) { if (info->bitmask & EBT_STP_PORT) {
v16 = NR16(stpc->port); v16 = NR16(stpc->port);
if (FWINV(v16 < c->portl || if (NF_INVF(info, EBT_STP_PORT,
v16 > c->portu, EBT_STP_PORT)) v16 < c->portl || v16 > c->portu))
return false; return false;
} }
if (info->bitmask & EBT_STP_MSGAGE) { if (info->bitmask & EBT_STP_MSGAGE) {
v16 = NR16(stpc->msg_age); v16 = NR16(stpc->msg_age);
if (FWINV(v16 < c->msg_agel || if (NF_INVF(info, EBT_STP_MSGAGE,
v16 > c->msg_ageu, EBT_STP_MSGAGE)) v16 < c->msg_agel || v16 > c->msg_ageu))
return false; return false;
} }
if (info->bitmask & EBT_STP_MAXAGE) { if (info->bitmask & EBT_STP_MAXAGE) {
v16 = NR16(stpc->max_age); v16 = NR16(stpc->max_age);
if (FWINV(v16 < c->max_agel || if (NF_INVF(info, EBT_STP_MAXAGE,
v16 > c->max_ageu, EBT_STP_MAXAGE)) v16 < c->max_agel || v16 > c->max_ageu))
return false; return false;
} }
if (info->bitmask & EBT_STP_HELLOTIME) { if (info->bitmask & EBT_STP_HELLOTIME) {
v16 = NR16(stpc->hello_time); v16 = NR16(stpc->hello_time);
if (FWINV(v16 < c->hello_timel || if (NF_INVF(info, EBT_STP_HELLOTIME,
v16 > c->hello_timeu, EBT_STP_HELLOTIME)) v16 < c->hello_timel || v16 > c->hello_timeu))
return false; return false;
} }
if (info->bitmask & EBT_STP_FWDD) { if (info->bitmask & EBT_STP_FWDD) {
v16 = NR16(stpc->forward_delay); v16 = NR16(stpc->forward_delay);
if (FWINV(v16 < c->forward_delayl || if (NF_INVF(info, EBT_STP_FWDD,
v16 > c->forward_delayu, EBT_STP_FWDD)) v16 < c->forward_delayl || v16 > c->forward_delayu))
return false; return false;
} }
return true; return true;
...@@ -125,7 +122,7 @@ ebt_stp_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -125,7 +122,7 @@ ebt_stp_mt(const struct sk_buff *skb, struct xt_action_param *par)
const struct ebt_stp_info *info = par->matchinfo; const struct ebt_stp_info *info = par->matchinfo;
const struct stp_header *sp; const struct stp_header *sp;
struct stp_header _stph; struct stp_header _stph;
const uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00}; const u8 header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
sp = skb_header_pointer(skb, 0, sizeof(_stph), &_stph); sp = skb_header_pointer(skb, 0, sizeof(_stph), &_stph);
if (sp == NULL) if (sp == NULL)
...@@ -135,8 +132,8 @@ ebt_stp_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -135,8 +132,8 @@ ebt_stp_mt(const struct sk_buff *skb, struct xt_action_param *par)
if (memcmp(sp, header, sizeof(header))) if (memcmp(sp, header, sizeof(header)))
return false; return false;
if (info->bitmask & EBT_STP_TYPE && if ((info->bitmask & EBT_STP_TYPE) &&
FWINV(info->type != sp->type, EBT_STP_TYPE)) NF_INVF(info, EBT_STP_TYPE, info->type != sp->type))
return false; return false;
if (sp->type == BPDU_TYPE_CONFIG && if (sp->type == BPDU_TYPE_CONFIG &&
...@@ -156,8 +153,8 @@ ebt_stp_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -156,8 +153,8 @@ ebt_stp_mt(const struct sk_buff *skb, struct xt_action_param *par)
static int ebt_stp_mt_check(const struct xt_mtchk_param *par) static int ebt_stp_mt_check(const struct xt_mtchk_param *par)
{ {
const struct ebt_stp_info *info = par->matchinfo; const struct ebt_stp_info *info = par->matchinfo;
const uint8_t bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00}; const u8 bridge_ula[6] = {0x01, 0x80, 0xc2, 0x00, 0x00, 0x00};
const uint8_t msk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; const u8 msk[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
const struct ebt_entry *e = par->entryinfo; const struct ebt_entry *e = par->entryinfo;
if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK || if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK ||
......
...@@ -121,7 +121,6 @@ ebt_dev_check(const char *entry, const struct net_device *device) ...@@ -121,7 +121,6 @@ ebt_dev_check(const char *entry, const struct net_device *device)
return devname[i] != entry[i] && entry[i] != 1; return devname[i] != entry[i] && entry[i] != 1;
} }
#define FWINV2(bool, invflg) ((bool) ^ !!(e->invflags & invflg))
/* process standard matches */ /* process standard matches */
static inline int static inline int
ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb,
...@@ -130,7 +129,6 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, ...@@ -130,7 +129,6 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb,
const struct ethhdr *h = eth_hdr(skb); const struct ethhdr *h = eth_hdr(skb);
const struct net_bridge_port *p; const struct net_bridge_port *p;
__be16 ethproto; __be16 ethproto;
int verdict, i;
if (skb_vlan_tag_present(skb)) if (skb_vlan_tag_present(skb))
ethproto = htons(ETH_P_8021Q); ethproto = htons(ETH_P_8021Q);
...@@ -138,38 +136,36 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb, ...@@ -138,38 +136,36 @@ ebt_basic_match(const struct ebt_entry *e, const struct sk_buff *skb,
ethproto = h->h_proto; ethproto = h->h_proto;
if (e->bitmask & EBT_802_3) { if (e->bitmask & EBT_802_3) {
if (FWINV2(eth_proto_is_802_3(ethproto), EBT_IPROTO)) if (NF_INVF(e, EBT_IPROTO, eth_proto_is_802_3(ethproto)))
return 1; return 1;
} else if (!(e->bitmask & EBT_NOPROTO) && } else if (!(e->bitmask & EBT_NOPROTO) &&
FWINV2(e->ethproto != ethproto, EBT_IPROTO)) NF_INVF(e, EBT_IPROTO, e->ethproto != ethproto))
return 1; return 1;
if (FWINV2(ebt_dev_check(e->in, in), EBT_IIN)) if (NF_INVF(e, EBT_IIN, ebt_dev_check(e->in, in)))
return 1; return 1;
if (FWINV2(ebt_dev_check(e->out, out), EBT_IOUT)) if (NF_INVF(e, EBT_IOUT, ebt_dev_check(e->out, out)))
return 1; return 1;
/* rcu_read_lock()ed by nf_hook_slow */ /* rcu_read_lock()ed by nf_hook_slow */
if (in && (p = br_port_get_rcu(in)) != NULL && if (in && (p = br_port_get_rcu(in)) != NULL &&
FWINV2(ebt_dev_check(e->logical_in, p->br->dev), EBT_ILOGICALIN)) NF_INVF(e, EBT_ILOGICALIN,
ebt_dev_check(e->logical_in, p->br->dev)))
return 1; return 1;
if (out && (p = br_port_get_rcu(out)) != NULL && if (out && (p = br_port_get_rcu(out)) != NULL &&
FWINV2(ebt_dev_check(e->logical_out, p->br->dev), EBT_ILOGICALOUT)) NF_INVF(e, EBT_ILOGICALOUT,
ebt_dev_check(e->logical_out, p->br->dev)))
return 1; return 1;
if (e->bitmask & EBT_SOURCEMAC) { if (e->bitmask & EBT_SOURCEMAC) {
verdict = 0; if (NF_INVF(e, EBT_ISOURCE,
for (i = 0; i < 6; i++) !ether_addr_equal_masked(h->h_source, e->sourcemac,
verdict |= (h->h_source[i] ^ e->sourcemac[i]) & e->sourcemsk)))
e->sourcemsk[i];
if (FWINV2(verdict != 0, EBT_ISOURCE))
return 1; return 1;
} }
if (e->bitmask & EBT_DESTMAC) { if (e->bitmask & EBT_DESTMAC) {
verdict = 0; if (NF_INVF(e, EBT_IDEST,
for (i = 0; i < 6; i++) !ether_addr_equal_masked(h->h_dest, e->destmac,
verdict |= (h->h_dest[i] ^ e->destmac[i]) & e->destmsk)))
e->destmsk[i];
if (FWINV2(verdict != 0, EBT_IDEST))
return 1; return 1;
} }
return 0; return 0;
......
...@@ -89,22 +89,20 @@ static inline int arp_packet_match(const struct arphdr *arphdr, ...@@ -89,22 +89,20 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
__be32 src_ipaddr, tgt_ipaddr; __be32 src_ipaddr, tgt_ipaddr;
long ret; long ret;
#define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg))) if (NF_INVF(arpinfo, ARPT_INV_ARPOP,
(arphdr->ar_op & arpinfo->arpop_mask) != arpinfo->arpop))
if (FWINV((arphdr->ar_op & arpinfo->arpop_mask) != arpinfo->arpop,
ARPT_INV_ARPOP))
return 0; return 0;
if (FWINV((arphdr->ar_hrd & arpinfo->arhrd_mask) != arpinfo->arhrd, if (NF_INVF(arpinfo, ARPT_INV_ARPHRD,
ARPT_INV_ARPHRD)) (arphdr->ar_hrd & arpinfo->arhrd_mask) != arpinfo->arhrd))
return 0; return 0;
if (FWINV((arphdr->ar_pro & arpinfo->arpro_mask) != arpinfo->arpro, if (NF_INVF(arpinfo, ARPT_INV_ARPPRO,
ARPT_INV_ARPPRO)) (arphdr->ar_pro & arpinfo->arpro_mask) != arpinfo->arpro))
return 0; return 0;
if (FWINV((arphdr->ar_hln & arpinfo->arhln_mask) != arpinfo->arhln, if (NF_INVF(arpinfo, ARPT_INV_ARPHLN,
ARPT_INV_ARPHLN)) (arphdr->ar_hln & arpinfo->arhln_mask) != arpinfo->arhln))
return 0; return 0;
src_devaddr = arpptr; src_devaddr = arpptr;
...@@ -115,31 +113,32 @@ static inline int arp_packet_match(const struct arphdr *arphdr, ...@@ -115,31 +113,32 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
arpptr += dev->addr_len; arpptr += dev->addr_len;
memcpy(&tgt_ipaddr, arpptr, sizeof(u32)); memcpy(&tgt_ipaddr, arpptr, sizeof(u32));
if (FWINV(arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr, dev->addr_len), if (NF_INVF(arpinfo, ARPT_INV_SRCDEVADDR,
ARPT_INV_SRCDEVADDR) || arp_devaddr_compare(&arpinfo->src_devaddr, src_devaddr,
FWINV(arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr, dev->addr_len), dev->addr_len)) ||
ARPT_INV_TGTDEVADDR)) NF_INVF(arpinfo, ARPT_INV_TGTDEVADDR,
arp_devaddr_compare(&arpinfo->tgt_devaddr, tgt_devaddr,
dev->addr_len)))
return 0; return 0;
if (FWINV((src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr, if (NF_INVF(arpinfo, ARPT_INV_SRCIP,
ARPT_INV_SRCIP) || (src_ipaddr & arpinfo->smsk.s_addr) != arpinfo->src.s_addr) ||
FWINV(((tgt_ipaddr & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr), NF_INVF(arpinfo, ARPT_INV_TGTIP,
ARPT_INV_TGTIP)) (tgt_ipaddr & arpinfo->tmsk.s_addr) != arpinfo->tgt.s_addr))
return 0; return 0;
/* Look for ifname matches. */ /* Look for ifname matches. */
ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask); ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask);
if (FWINV(ret != 0, ARPT_INV_VIA_IN)) if (NF_INVF(arpinfo, ARPT_INV_VIA_IN, ret != 0))
return 0; return 0;
ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask); ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask);
if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) if (NF_INVF(arpinfo, ARPT_INV_VIA_OUT, ret != 0))
return 0; return 0;
return 1; return 1;
#undef FWINV
} }
static inline int arp_checkentry(const struct arpt_arp *arp) static inline int arp_checkentry(const struct arpt_arp *arp)
......
...@@ -58,32 +58,31 @@ ip_packet_match(const struct iphdr *ip, ...@@ -58,32 +58,31 @@ ip_packet_match(const struct iphdr *ip,
{ {
unsigned long ret; unsigned long ret;
#define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg))) if (NF_INVF(ipinfo, IPT_INV_SRCIP,
(ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) ||
if (FWINV((ip->saddr&ipinfo->smsk.s_addr) != ipinfo->src.s_addr, NF_INVF(ipinfo, IPT_INV_DSTIP,
IPT_INV_SRCIP) || (ip->daddr & ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr))
FWINV((ip->daddr&ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr,
IPT_INV_DSTIP))
return false; return false;
ret = ifname_compare_aligned(indev, ipinfo->iniface, ipinfo->iniface_mask); ret = ifname_compare_aligned(indev, ipinfo->iniface, ipinfo->iniface_mask);
if (FWINV(ret != 0, IPT_INV_VIA_IN)) if (NF_INVF(ipinfo, IPT_INV_VIA_IN, ret != 0))
return false; return false;
ret = ifname_compare_aligned(outdev, ipinfo->outiface, ipinfo->outiface_mask); ret = ifname_compare_aligned(outdev, ipinfo->outiface, ipinfo->outiface_mask);
if (FWINV(ret != 0, IPT_INV_VIA_OUT)) if (NF_INVF(ipinfo, IPT_INV_VIA_OUT, ret != 0))
return false; return false;
/* Check specific protocol */ /* Check specific protocol */
if (ipinfo->proto && if (ipinfo->proto &&
FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO)) NF_INVF(ipinfo, IPT_INV_PROTO, ip->protocol != ipinfo->proto))
return false; return false;
/* If we have a fragment rule but the packet is not a fragment /* If we have a fragment rule but the packet is not a fragment
* then we return zero */ * then we return zero */
if (FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG)) if (NF_INVF(ipinfo, IPT_INV_FRAG,
(ipinfo->flags & IPT_F_FRAG) && !isfrag))
return false; return false;
return true; return true;
...@@ -122,7 +121,6 @@ static inline bool unconditional(const struct ipt_entry *e) ...@@ -122,7 +121,6 @@ static inline bool unconditional(const struct ipt_entry *e)
return e->target_offset == sizeof(struct ipt_entry) && return e->target_offset == sizeof(struct ipt_entry) &&
memcmp(&e->ip, &uncond, sizeof(uncond)) == 0; memcmp(&e->ip, &uncond, sizeof(uncond)) == 0;
#undef FWINV
} }
/* for const-correctness */ /* for const-correctness */
......
...@@ -87,10 +87,6 @@ iptable_mangle_hook(void *priv, ...@@ -87,10 +87,6 @@ iptable_mangle_hook(void *priv,
{ {
if (state->hook == NF_INET_LOCAL_OUT) if (state->hook == NF_INET_LOCAL_OUT)
return ipt_mangle_out(skb, state); return ipt_mangle_out(skb, state);
if (state->hook == NF_INET_POST_ROUTING)
return ipt_do_table(skb, state,
state->net->ipv4.iptable_mangle);
/* PREROUTING/INPUT/FORWARD: */
return ipt_do_table(skb, state, state->net->ipv4.iptable_mangle); return ipt_do_table(skb, state, state->net->ipv4.iptable_mangle);
} }
......
...@@ -24,6 +24,9 @@ const struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb, ...@@ -24,6 +24,9 @@ const struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb,
if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET)) if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
return NULL; return NULL;
if (ip_hdr(oldskb)->protocol != IPPROTO_TCP)
return NULL;
oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb), oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
sizeof(struct tcphdr), _oth); sizeof(struct tcphdr), _oth);
if (oth == NULL) if (oth == NULL)
......
...@@ -73,22 +73,22 @@ ip6_packet_match(const struct sk_buff *skb, ...@@ -73,22 +73,22 @@ ip6_packet_match(const struct sk_buff *skb,
unsigned long ret; unsigned long ret;
const struct ipv6hdr *ipv6 = ipv6_hdr(skb); const struct ipv6hdr *ipv6 = ipv6_hdr(skb);
#define FWINV(bool, invflg) ((bool) ^ !!(ip6info->invflags & (invflg))) if (NF_INVF(ip6info, IP6T_INV_SRCIP,
ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk,
if (FWINV(ipv6_masked_addr_cmp(&ipv6->saddr, &ip6info->smsk, &ip6info->src)) ||
&ip6info->src), IP6T_INV_SRCIP) || NF_INVF(ip6info, IP6T_INV_DSTIP,
FWINV(ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk, ipv6_masked_addr_cmp(&ipv6->daddr, &ip6info->dmsk,
&ip6info->dst), IP6T_INV_DSTIP)) &ip6info->dst)))
return false; return false;
ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask); ret = ifname_compare_aligned(indev, ip6info->iniface, ip6info->iniface_mask);
if (FWINV(ret != 0, IP6T_INV_VIA_IN)) if (NF_INVF(ip6info, IP6T_INV_VIA_IN, ret != 0))
return false; return false;
ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask); ret = ifname_compare_aligned(outdev, ip6info->outiface, ip6info->outiface_mask);
if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) if (NF_INVF(ip6info, IP6T_INV_VIA_OUT, ret != 0))
return false; return false;
/* ... might want to do something with class and flowlabel here ... */ /* ... might want to do something with class and flowlabel here ... */
......
...@@ -83,10 +83,6 @@ ip6table_mangle_hook(void *priv, struct sk_buff *skb, ...@@ -83,10 +83,6 @@ ip6table_mangle_hook(void *priv, struct sk_buff *skb,
{ {
if (state->hook == NF_INET_LOCAL_OUT) if (state->hook == NF_INET_LOCAL_OUT)
return ip6t_mangle_out(skb, state); return ip6t_mangle_out(skb, state);
if (state->hook == NF_INET_POST_ROUTING)
return ip6t_do_table(skb, state,
state->net->ipv6.ip6table_mangle);
/* INPUT/FORWARD */
return ip6t_do_table(skb, state, state->net->ipv6.ip6table_mangle); return ip6t_do_table(skb, state, state->net->ipv6.ip6table_mangle);
} }
......
...@@ -609,9 +609,8 @@ config NETFILTER_XT_MARK ...@@ -609,9 +609,8 @@ config NETFILTER_XT_MARK
The target allows you to create rules in the "mangle" table which alter The target allows you to create rules in the "mangle" table which alter
the netfilter mark (nfmark) field associated with the packet. the netfilter mark (nfmark) field associated with the packet.
Prior to routing, the nfmark can influence the routing method (see Prior to routing, the nfmark can influence the routing method and can
"Use netfilter MARK value as routing key") and can also be used by also be used by other subsystems to change their behavior.
other subsystems to change their behavior.
config NETFILTER_XT_CONNMARK config NETFILTER_XT_CONNMARK
tristate 'ctmark target and match support' tristate 'ctmark target and match support'
...@@ -753,9 +752,8 @@ config NETFILTER_XT_TARGET_HMARK ...@@ -753,9 +752,8 @@ config NETFILTER_XT_TARGET_HMARK
The target allows you to create rules in the "raw" and "mangle" tables The target allows you to create rules in the "raw" and "mangle" tables
which set the skbuff mark by means of hash calculation within a given which set the skbuff mark by means of hash calculation within a given
range. The nfmark can influence the routing method (see "Use netfilter range. The nfmark can influence the routing method and can also be used
MARK value as routing key") and can also be used by other subsystems to by other subsystems to change their behaviour.
change their behaviour.
To compile it as a module, choose M here. If unsure, say N. To compile it as a module, choose M here. If unsure, say N.
......
...@@ -327,16 +327,10 @@ struct nf_conn *nf_ct_tmpl_alloc(struct net *net, ...@@ -327,16 +327,10 @@ struct nf_conn *nf_ct_tmpl_alloc(struct net *net,
tmpl->status = IPS_TEMPLATE; tmpl->status = IPS_TEMPLATE;
write_pnet(&tmpl->ct_net, net); write_pnet(&tmpl->ct_net, net);
nf_ct_zone_add(tmpl, zone);
if (nf_ct_zone_add(tmpl, flags, zone) < 0)
goto out_free;
atomic_set(&tmpl->ct_general.use, 0); atomic_set(&tmpl->ct_general.use, 0);
return tmpl; return tmpl;
out_free:
kfree(tmpl);
return NULL;
} }
EXPORT_SYMBOL_GPL(nf_ct_tmpl_alloc); EXPORT_SYMBOL_GPL(nf_ct_tmpl_alloc);
...@@ -929,16 +923,13 @@ __nf_conntrack_alloc(struct net *net, ...@@ -929,16 +923,13 @@ __nf_conntrack_alloc(struct net *net,
offsetof(struct nf_conn, proto) - offsetof(struct nf_conn, proto) -
offsetof(struct nf_conn, __nfct_init_offset[0])); offsetof(struct nf_conn, __nfct_init_offset[0]));
if (zone && nf_ct_zone_add(ct, GFP_ATOMIC, zone) < 0) nf_ct_zone_add(ct, zone);
goto out_free;
/* Because we use RCU lookups, we set ct_general.use to zero before /* Because we use RCU lookups, we set ct_general.use to zero before
* this is inserted in any list. * this is inserted in any list.
*/ */
atomic_set(&ct->ct_general.use, 0); atomic_set(&ct->ct_general.use, 0);
return ct; return ct;
out_free:
kmem_cache_free(nf_conntrack_cachep, ct);
out: out:
atomic_dec(&net->ct.count); atomic_dec(&net->ct.count);
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
...@@ -1342,14 +1333,6 @@ bool __nf_ct_kill_acct(struct nf_conn *ct, ...@@ -1342,14 +1333,6 @@ bool __nf_ct_kill_acct(struct nf_conn *ct,
} }
EXPORT_SYMBOL_GPL(__nf_ct_kill_acct); EXPORT_SYMBOL_GPL(__nf_ct_kill_acct);
#ifdef CONFIG_NF_CONNTRACK_ZONES
static struct nf_ct_ext_type nf_ct_zone_extend __read_mostly = {
.len = sizeof(struct nf_conntrack_zone),
.align = __alignof__(struct nf_conntrack_zone),
.id = NF_CT_EXT_ZONE,
};
#endif
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink.h>
...@@ -1532,9 +1515,6 @@ void nf_conntrack_cleanup_end(void) ...@@ -1532,9 +1515,6 @@ void nf_conntrack_cleanup_end(void)
nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_htable_size); nf_ct_free_hashtable(nf_conntrack_hash, nf_conntrack_htable_size);
#ifdef CONFIG_NF_CONNTRACK_ZONES
nf_ct_extend_unregister(&nf_ct_zone_extend);
#endif
nf_conntrack_proto_fini(); nf_conntrack_proto_fini();
nf_conntrack_seqadj_fini(); nf_conntrack_seqadj_fini();
nf_conntrack_labels_fini(); nf_conntrack_labels_fini();
...@@ -1617,24 +1597,14 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls) ...@@ -1617,24 +1597,14 @@ void *nf_ct_alloc_hashtable(unsigned int *sizep, int nulls)
} }
EXPORT_SYMBOL_GPL(nf_ct_alloc_hashtable); EXPORT_SYMBOL_GPL(nf_ct_alloc_hashtable);
int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) int nf_conntrack_hash_resize(unsigned int hashsize)
{ {
int i, bucket, rc; int i, bucket;
unsigned int hashsize, old_size; unsigned int old_size;
struct hlist_nulls_head *hash, *old_hash; struct hlist_nulls_head *hash, *old_hash;
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
struct nf_conn *ct; struct nf_conn *ct;
if (current->nsproxy->net_ns != &init_net)
return -EOPNOTSUPP;
/* On boot, we can set this without any fancy locking. */
if (!nf_conntrack_htable_size)
return param_set_uint(val, kp);
rc = kstrtouint(val, 0, &hashsize);
if (rc)
return rc;
if (!hashsize) if (!hashsize)
return -EINVAL; return -EINVAL;
...@@ -1642,6 +1612,12 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) ...@@ -1642,6 +1612,12 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
if (!hash) if (!hash)
return -ENOMEM; return -ENOMEM;
old_size = nf_conntrack_htable_size;
if (old_size == hashsize) {
nf_ct_free_hashtable(hash, hashsize);
return 0;
}
local_bh_disable(); local_bh_disable();
nf_conntrack_all_lock(); nf_conntrack_all_lock();
write_seqcount_begin(&nf_conntrack_generation); write_seqcount_begin(&nf_conntrack_generation);
...@@ -1677,6 +1653,25 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) ...@@ -1677,6 +1653,25 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
nf_ct_free_hashtable(old_hash, old_size); nf_ct_free_hashtable(old_hash, old_size);
return 0; return 0;
} }
int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
{
unsigned int hashsize;
int rc;
if (current->nsproxy->net_ns != &init_net)
return -EOPNOTSUPP;
/* On boot, we can set this without any fancy locking. */
if (!nf_conntrack_htable_size)
return param_set_uint(val, kp);
rc = kstrtouint(val, 0, &hashsize);
if (rc)
return rc;
return nf_conntrack_hash_resize(hashsize);
}
EXPORT_SYMBOL_GPL(nf_conntrack_set_hashsize); EXPORT_SYMBOL_GPL(nf_conntrack_set_hashsize);
module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint, module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
...@@ -1733,7 +1728,7 @@ int nf_conntrack_init_start(void) ...@@ -1733,7 +1728,7 @@ int nf_conntrack_init_start(void)
nf_conntrack_cachep = kmem_cache_create("nf_conntrack", nf_conntrack_cachep = kmem_cache_create("nf_conntrack",
sizeof(struct nf_conn), 0, sizeof(struct nf_conn), 0,
SLAB_DESTROY_BY_RCU, NULL); SLAB_DESTROY_BY_RCU | SLAB_HWCACHE_ALIGN, NULL);
if (!nf_conntrack_cachep) if (!nf_conntrack_cachep)
goto err_cachep; goto err_cachep;
...@@ -1773,11 +1768,6 @@ int nf_conntrack_init_start(void) ...@@ -1773,11 +1768,6 @@ int nf_conntrack_init_start(void)
if (ret < 0) if (ret < 0)
goto err_seqadj; goto err_seqadj;
#ifdef CONFIG_NF_CONNTRACK_ZONES
ret = nf_ct_extend_register(&nf_ct_zone_extend);
if (ret < 0)
goto err_extend;
#endif
ret = nf_conntrack_proto_init(); ret = nf_conntrack_proto_init();
if (ret < 0) if (ret < 0)
goto err_proto; goto err_proto;
...@@ -1793,10 +1783,6 @@ int nf_conntrack_init_start(void) ...@@ -1793,10 +1783,6 @@ int nf_conntrack_init_start(void)
return 0; return 0;
err_proto: err_proto:
#ifdef CONFIG_NF_CONNTRACK_ZONES
nf_ct_extend_unregister(&nf_ct_zone_extend);
err_extend:
#endif
nf_conntrack_seqadj_fini(); nf_conntrack_seqadj_fini();
err_seqadj: err_seqadj:
nf_conntrack_labels_fini(); nf_conntrack_labels_fini();
......
...@@ -387,13 +387,40 @@ EXPORT_SYMBOL_GPL(nf_conntrack_helper_register); ...@@ -387,13 +387,40 @@ EXPORT_SYMBOL_GPL(nf_conntrack_helper_register);
static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me, static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me,
struct net *net) struct net *net)
{
struct nf_conntrack_tuple_hash *h;
const struct hlist_nulls_node *nn;
int cpu;
/* Get rid of expecteds, set helpers to NULL. */
for_each_possible_cpu(cpu) {
struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
spin_lock_bh(&pcpu->lock);
hlist_nulls_for_each_entry(h, nn, &pcpu->unconfirmed, hnnode)
unhelp(h, me);
spin_unlock_bh(&pcpu->lock);
}
}
void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
{ {
struct nf_conntrack_tuple_hash *h; struct nf_conntrack_tuple_hash *h;
struct nf_conntrack_expect *exp; struct nf_conntrack_expect *exp;
const struct hlist_node *next; const struct hlist_node *next;
const struct hlist_nulls_node *nn; const struct hlist_nulls_node *nn;
struct net *net;
unsigned int i; unsigned int i;
int cpu;
mutex_lock(&nf_ct_helper_mutex);
hlist_del_rcu(&me->hnode);
nf_ct_helper_count--;
mutex_unlock(&nf_ct_helper_mutex);
/* Make sure every nothing is still using the helper unless its a
* connection in the hash.
*/
synchronize_rcu();
/* Get rid of expectations */ /* Get rid of expectations */
spin_lock_bh(&nf_conntrack_expect_lock); spin_lock_bh(&nf_conntrack_expect_lock);
...@@ -413,15 +440,11 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me, ...@@ -413,15 +440,11 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me,
} }
spin_unlock_bh(&nf_conntrack_expect_lock); spin_unlock_bh(&nf_conntrack_expect_lock);
/* Get rid of expecteds, set helpers to NULL. */ rtnl_lock();
for_each_possible_cpu(cpu) { for_each_net(net)
struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu); __nf_conntrack_helper_unregister(me, net);
rtnl_unlock();
spin_lock_bh(&pcpu->lock);
hlist_nulls_for_each_entry(h, nn, &pcpu->unconfirmed, hnnode)
unhelp(h, me);
spin_unlock_bh(&pcpu->lock);
}
local_bh_disable(); local_bh_disable();
for (i = 0; i < nf_conntrack_htable_size; i++) { for (i = 0; i < nf_conntrack_htable_size; i++) {
nf_conntrack_lock(&nf_conntrack_locks[i % CONNTRACK_LOCKS]); nf_conntrack_lock(&nf_conntrack_locks[i % CONNTRACK_LOCKS]);
...@@ -433,26 +456,6 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me, ...@@ -433,26 +456,6 @@ static void __nf_conntrack_helper_unregister(struct nf_conntrack_helper *me,
} }
local_bh_enable(); local_bh_enable();
} }
void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
{
struct net *net;
mutex_lock(&nf_ct_helper_mutex);
hlist_del_rcu(&me->hnode);
nf_ct_helper_count--;
mutex_unlock(&nf_ct_helper_mutex);
/* Make sure every nothing is still using the helper unless its a
* connection in the hash.
*/
synchronize_rcu();
rtnl_lock();
for_each_net(net)
__nf_conntrack_helper_unregister(me, net);
rtnl_unlock();
}
EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister); EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister);
static struct nf_ct_ext_type helper_extend __read_mostly = { static struct nf_ct_ext_type helper_extend __read_mostly = {
......
...@@ -434,8 +434,29 @@ static void nf_conntrack_standalone_fini_proc(struct net *net) ...@@ -434,8 +434,29 @@ static void nf_conntrack_standalone_fini_proc(struct net *net)
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
/* Log invalid packets of a given protocol */ /* Log invalid packets of a given protocol */
static int log_invalid_proto_min = 0; static int log_invalid_proto_min __read_mostly;
static int log_invalid_proto_max = 255; static int log_invalid_proto_max __read_mostly = 255;
/* size the user *wants to set */
static unsigned int nf_conntrack_htable_size_user __read_mostly;
static int
nf_conntrack_hash_sysctl(struct ctl_table *table, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int ret;
ret = proc_dointvec(table, write, buffer, lenp, ppos);
if (ret < 0 || !write)
return ret;
/* update ret, we might not be able to satisfy request */
ret = nf_conntrack_hash_resize(nf_conntrack_htable_size_user);
/* update it to the actual value used by conntrack */
nf_conntrack_htable_size_user = nf_conntrack_htable_size;
return ret;
}
static struct ctl_table_header *nf_ct_netfilter_header; static struct ctl_table_header *nf_ct_netfilter_header;
...@@ -456,10 +477,10 @@ static struct ctl_table nf_ct_sysctl_table[] = { ...@@ -456,10 +477,10 @@ static struct ctl_table nf_ct_sysctl_table[] = {
}, },
{ {
.procname = "nf_conntrack_buckets", .procname = "nf_conntrack_buckets",
.data = &nf_conntrack_htable_size, .data = &nf_conntrack_htable_size_user,
.maxlen = sizeof(unsigned int), .maxlen = sizeof(unsigned int),
.mode = 0444, .mode = 0644,
.proc_handler = proc_dointvec, .proc_handler = nf_conntrack_hash_sysctl,
}, },
{ {
.procname = "nf_conntrack_checksum", .procname = "nf_conntrack_checksum",
...@@ -515,6 +536,9 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net) ...@@ -515,6 +536,9 @@ static int nf_conntrack_standalone_init_sysctl(struct net *net)
if (net->user_ns != &init_user_ns) if (net->user_ns != &init_user_ns)
table[0].procname = NULL; table[0].procname = NULL;
if (!net_eq(&init_net, net))
table[2].mode = 0444;
net->ct.sysctl_header = register_net_sysctl(net, "net/netfilter", table); net->ct.sysctl_header = register_net_sysctl(net, "net/netfilter", table);
if (!net->ct.sysctl_header) if (!net->ct.sysctl_header)
goto out_unregister_netfilter; goto out_unregister_netfilter;
...@@ -604,6 +628,8 @@ static int __init nf_conntrack_standalone_init(void) ...@@ -604,6 +628,8 @@ static int __init nf_conntrack_standalone_init(void)
ret = -ENOMEM; ret = -ENOMEM;
goto out_sysctl; goto out_sysctl;
} }
nf_conntrack_htable_size_user = nf_conntrack_htable_size;
#endif #endif
ret = register_pernet_subsys(&nf_conntrack_net_ops); ret = register_pernet_subsys(&nf_conntrack_net_ops);
......
...@@ -159,6 +159,20 @@ int nf_logger_find_get(int pf, enum nf_log_type type) ...@@ -159,6 +159,20 @@ int nf_logger_find_get(int pf, enum nf_log_type type)
struct nf_logger *logger; struct nf_logger *logger;
int ret = -ENOENT; int ret = -ENOENT;
if (pf == NFPROTO_INET) {
ret = nf_logger_find_get(NFPROTO_IPV4, type);
if (ret < 0)
return ret;
ret = nf_logger_find_get(NFPROTO_IPV6, type);
if (ret < 0) {
nf_logger_put(NFPROTO_IPV4, type);
return ret;
}
return 0;
}
if (rcu_access_pointer(loggers[pf][type]) == NULL) if (rcu_access_pointer(loggers[pf][type]) == NULL)
request_module("nf-logger-%u-%u", pf, type); request_module("nf-logger-%u-%u", pf, type);
...@@ -167,7 +181,7 @@ int nf_logger_find_get(int pf, enum nf_log_type type) ...@@ -167,7 +181,7 @@ int nf_logger_find_get(int pf, enum nf_log_type type)
if (logger == NULL) if (logger == NULL)
goto out; goto out;
if (logger && try_module_get(logger->me)) if (try_module_get(logger->me))
ret = 0; ret = 0;
out: out:
rcu_read_unlock(); rcu_read_unlock();
...@@ -179,6 +193,12 @@ void nf_logger_put(int pf, enum nf_log_type type) ...@@ -179,6 +193,12 @@ void nf_logger_put(int pf, enum nf_log_type type)
{ {
struct nf_logger *logger; struct nf_logger *logger;
if (pf == NFPROTO_INET) {
nf_logger_put(NFPROTO_IPV4, type);
nf_logger_put(NFPROTO_IPV6, type);
return;
}
BUG_ON(loggers[pf][type] == NULL); BUG_ON(loggers[pf][type] == NULL);
rcu_read_lock(); rcu_read_lock();
...@@ -398,16 +418,17 @@ static int nf_log_proc_dostring(struct ctl_table *table, int write, ...@@ -398,16 +418,17 @@ static int nf_log_proc_dostring(struct ctl_table *table, int write,
{ {
const struct nf_logger *logger; const struct nf_logger *logger;
char buf[NFLOGGER_NAME_LEN]; char buf[NFLOGGER_NAME_LEN];
size_t size = *lenp;
int r = 0; int r = 0;
int tindex = (unsigned long)table->extra1; int tindex = (unsigned long)table->extra1;
struct net *net = current->nsproxy->net_ns; struct net *net = current->nsproxy->net_ns;
if (write) { if (write) {
if (size > sizeof(buf)) struct ctl_table tmp = *table;
size = sizeof(buf);
if (copy_from_user(buf, buffer, size)) tmp.data = buf;
return -EFAULT; r = proc_dostring(&tmp, write, buffer, lenp, ppos);
if (r)
return r;
if (!strcmp(buf, "NONE")) { if (!strcmp(buf, "NONE")) {
nf_log_unbind_pf(net, tindex); nf_log_unbind_pf(net, tindex);
......
This diff is collapsed.
...@@ -700,10 +700,13 @@ nfulnl_log_packet(struct net *net, ...@@ -700,10 +700,13 @@ nfulnl_log_packet(struct net *net,
break; break;
case NFULNL_COPY_PACKET: case NFULNL_COPY_PACKET:
if (inst->copy_range > skb->len) data_len = inst->copy_range;
if ((li->u.ulog.flags & NF_LOG_F_COPY_LEN) &&
(li->u.ulog.copy_len < data_len))
data_len = li->u.ulog.copy_len;
if (data_len > skb->len)
data_len = skb->len; data_len = skb->len;
else
data_len = inst->copy_range;
size += nla_total_size(data_len); size += nla_total_size(data_len);
break; break;
......
...@@ -103,6 +103,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx, ...@@ -103,6 +103,7 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_dynset *priv = nft_expr_priv(expr); struct nft_dynset *priv = nft_expr_priv(expr);
u8 genmask = nft_genmask_next(ctx->net);
struct nft_set *set; struct nft_set *set;
u64 timeout; u64 timeout;
int err; int err;
...@@ -112,11 +113,13 @@ static int nft_dynset_init(const struct nft_ctx *ctx, ...@@ -112,11 +113,13 @@ static int nft_dynset_init(const struct nft_ctx *ctx,
tb[NFTA_DYNSET_SREG_KEY] == NULL) tb[NFTA_DYNSET_SREG_KEY] == NULL)
return -EINVAL; return -EINVAL;
set = nf_tables_set_lookup(ctx->table, tb[NFTA_DYNSET_SET_NAME]); set = nf_tables_set_lookup(ctx->table, tb[NFTA_DYNSET_SET_NAME],
genmask);
if (IS_ERR(set)) { if (IS_ERR(set)) {
if (tb[NFTA_DYNSET_SET_ID]) if (tb[NFTA_DYNSET_SET_ID])
set = nf_tables_set_lookup_byid(ctx->net, set = nf_tables_set_lookup_byid(ctx->net,
tb[NFTA_DYNSET_SET_ID]); tb[NFTA_DYNSET_SET_ID],
genmask);
if (IS_ERR(set)) if (IS_ERR(set))
return PTR_ERR(set); return PTR_ERR(set);
} }
......
...@@ -153,9 +153,10 @@ static void *nft_hash_deactivate(const struct nft_set *set, ...@@ -153,9 +153,10 @@ static void *nft_hash_deactivate(const struct nft_set *set,
const struct nft_set_elem *elem) const struct nft_set_elem *elem)
{ {
struct nft_hash *priv = nft_set_priv(set); struct nft_hash *priv = nft_set_priv(set);
struct net *net = read_pnet(&set->pnet);
struct nft_hash_elem *he; struct nft_hash_elem *he;
struct nft_hash_cmp_arg arg = { struct nft_hash_cmp_arg arg = {
.genmask = nft_genmask_next(read_pnet(&set->pnet)), .genmask = nft_genmask_next(net),
.set = set, .set = set,
.key = elem->key.val.data, .key = elem->key.val.data,
}; };
...@@ -163,7 +164,8 @@ static void *nft_hash_deactivate(const struct nft_set *set, ...@@ -163,7 +164,8 @@ static void *nft_hash_deactivate(const struct nft_set *set,
rcu_read_lock(); rcu_read_lock();
he = rhashtable_lookup_fast(&priv->ht, &arg, nft_hash_params); he = rhashtable_lookup_fast(&priv->ht, &arg, nft_hash_params);
if (he != NULL) { if (he != NULL) {
if (!nft_set_elem_mark_busy(&he->ext)) if (!nft_set_elem_mark_busy(&he->ext) ||
!nft_is_active(net, &he->ext))
nft_set_elem_change_active(set, &he->ext); nft_set_elem_change_active(set, &he->ext);
else else
he = NULL; he = NULL;
......
...@@ -52,7 +52,6 @@ static int nft_log_init(const struct nft_ctx *ctx, ...@@ -52,7 +52,6 @@ static int nft_log_init(const struct nft_ctx *ctx,
struct nft_log *priv = nft_expr_priv(expr); struct nft_log *priv = nft_expr_priv(expr);
struct nf_loginfo *li = &priv->loginfo; struct nf_loginfo *li = &priv->loginfo;
const struct nlattr *nla; const struct nlattr *nla;
int ret;
nla = tb[NFTA_LOG_PREFIX]; nla = tb[NFTA_LOG_PREFIX];
if (nla != NULL) { if (nla != NULL) {
...@@ -97,19 +96,6 @@ static int nft_log_init(const struct nft_ctx *ctx, ...@@ -97,19 +96,6 @@ static int nft_log_init(const struct nft_ctx *ctx,
break; break;
} }
if (ctx->afi->family == NFPROTO_INET) {
ret = nf_logger_find_get(NFPROTO_IPV4, li->type);
if (ret < 0)
return ret;
ret = nf_logger_find_get(NFPROTO_IPV6, li->type);
if (ret < 0) {
nf_logger_put(NFPROTO_IPV4, li->type);
return ret;
}
return 0;
}
return nf_logger_find_get(ctx->afi->family, li->type); return nf_logger_find_get(ctx->afi->family, li->type);
} }
...@@ -122,12 +108,7 @@ static void nft_log_destroy(const struct nft_ctx *ctx, ...@@ -122,12 +108,7 @@ static void nft_log_destroy(const struct nft_ctx *ctx,
if (priv->prefix != nft_log_null_prefix) if (priv->prefix != nft_log_null_prefix)
kfree(priv->prefix); kfree(priv->prefix);
if (ctx->afi->family == NFPROTO_INET) { nf_logger_put(ctx->afi->family, li->type);
nf_logger_put(NFPROTO_IPV4, li->type);
nf_logger_put(NFPROTO_IPV6, li->type);
} else {
nf_logger_put(ctx->afi->family, li->type);
}
} }
static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr) static int nft_log_dump(struct sk_buff *skb, const struct nft_expr *expr)
......
...@@ -22,6 +22,7 @@ struct nft_lookup { ...@@ -22,6 +22,7 @@ struct nft_lookup {
struct nft_set *set; struct nft_set *set;
enum nft_registers sreg:8; enum nft_registers sreg:8;
enum nft_registers dreg:8; enum nft_registers dreg:8;
bool invert;
struct nft_set_binding binding; struct nft_set_binding binding;
}; };
...@@ -32,14 +33,20 @@ static void nft_lookup_eval(const struct nft_expr *expr, ...@@ -32,14 +33,20 @@ static void nft_lookup_eval(const struct nft_expr *expr,
const struct nft_lookup *priv = nft_expr_priv(expr); const struct nft_lookup *priv = nft_expr_priv(expr);
const struct nft_set *set = priv->set; const struct nft_set *set = priv->set;
const struct nft_set_ext *ext; const struct nft_set_ext *ext;
bool found;
if (set->ops->lookup(set, &regs->data[priv->sreg], &ext)) { found = set->ops->lookup(set, &regs->data[priv->sreg], &ext) ^
if (set->flags & NFT_SET_MAP) priv->invert;
nft_data_copy(&regs->data[priv->dreg],
nft_set_ext_data(ext), set->dlen); if (!found) {
regs->verdict.code = NFT_BREAK;
return; return;
} }
regs->verdict.code = NFT_BREAK;
if (found && set->flags & NFT_SET_MAP)
nft_data_copy(&regs->data[priv->dreg],
nft_set_ext_data(ext), set->dlen);
} }
static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = { static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = {
...@@ -47,6 +54,7 @@ static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = { ...@@ -47,6 +54,7 @@ static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = {
[NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 }, [NFTA_LOOKUP_SET_ID] = { .type = NLA_U32 },
[NFTA_LOOKUP_SREG] = { .type = NLA_U32 }, [NFTA_LOOKUP_SREG] = { .type = NLA_U32 },
[NFTA_LOOKUP_DREG] = { .type = NLA_U32 }, [NFTA_LOOKUP_DREG] = { .type = NLA_U32 },
[NFTA_LOOKUP_FLAGS] = { .type = NLA_U32 },
}; };
static int nft_lookup_init(const struct nft_ctx *ctx, static int nft_lookup_init(const struct nft_ctx *ctx,
...@@ -54,18 +62,21 @@ static int nft_lookup_init(const struct nft_ctx *ctx, ...@@ -54,18 +62,21 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct nft_lookup *priv = nft_expr_priv(expr); struct nft_lookup *priv = nft_expr_priv(expr);
u8 genmask = nft_genmask_next(ctx->net);
struct nft_set *set; struct nft_set *set;
u32 flags;
int err; int err;
if (tb[NFTA_LOOKUP_SET] == NULL || if (tb[NFTA_LOOKUP_SET] == NULL ||
tb[NFTA_LOOKUP_SREG] == NULL) tb[NFTA_LOOKUP_SREG] == NULL)
return -EINVAL; return -EINVAL;
set = nf_tables_set_lookup(ctx->table, tb[NFTA_LOOKUP_SET]); set = nf_tables_set_lookup(ctx->table, tb[NFTA_LOOKUP_SET], genmask);
if (IS_ERR(set)) { if (IS_ERR(set)) {
if (tb[NFTA_LOOKUP_SET_ID]) { if (tb[NFTA_LOOKUP_SET_ID]) {
set = nf_tables_set_lookup_byid(ctx->net, set = nf_tables_set_lookup_byid(ctx->net,
tb[NFTA_LOOKUP_SET_ID]); tb[NFTA_LOOKUP_SET_ID],
genmask);
} }
if (IS_ERR(set)) if (IS_ERR(set))
return PTR_ERR(set); return PTR_ERR(set);
...@@ -79,7 +90,22 @@ static int nft_lookup_init(const struct nft_ctx *ctx, ...@@ -79,7 +90,22 @@ static int nft_lookup_init(const struct nft_ctx *ctx,
if (err < 0) if (err < 0)
return err; return err;
if (tb[NFTA_LOOKUP_FLAGS]) {
flags = ntohl(nla_get_be32(tb[NFTA_LOOKUP_FLAGS]));
if (flags & ~NFT_LOOKUP_F_INV)
return -EINVAL;
if (flags & NFT_LOOKUP_F_INV) {
if (set->flags & NFT_SET_MAP)
return -EINVAL;
priv->invert = true;
}
}
if (tb[NFTA_LOOKUP_DREG] != NULL) { if (tb[NFTA_LOOKUP_DREG] != NULL) {
if (priv->invert)
return -EINVAL;
if (!(set->flags & NFT_SET_MAP)) if (!(set->flags & NFT_SET_MAP))
return -EINVAL; return -EINVAL;
...@@ -112,6 +138,7 @@ static void nft_lookup_destroy(const struct nft_ctx *ctx, ...@@ -112,6 +138,7 @@ static void nft_lookup_destroy(const struct nft_ctx *ctx,
static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr) static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
{ {
const struct nft_lookup *priv = nft_expr_priv(expr); const struct nft_lookup *priv = nft_expr_priv(expr);
u32 flags = priv->invert ? NFT_LOOKUP_F_INV : 0;
if (nla_put_string(skb, NFTA_LOOKUP_SET, priv->set->name)) if (nla_put_string(skb, NFTA_LOOKUP_SET, priv->set->name))
goto nla_put_failure; goto nla_put_failure;
...@@ -120,6 +147,8 @@ static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr) ...@@ -120,6 +147,8 @@ static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
if (priv->set->flags & NFT_SET_MAP) if (priv->set->flags & NFT_SET_MAP)
if (nft_dump_register(skb, NFTA_LOOKUP_DREG, priv->dreg)) if (nft_dump_register(skb, NFTA_LOOKUP_DREG, priv->dreg))
goto nla_put_failure; goto nla_put_failure;
if (nla_put_be32(skb, NFTA_LOOKUP_FLAGS, htonl(flags)))
goto nla_put_failure;
return 0; return 0;
nla_put_failure: nla_put_failure:
......
...@@ -170,7 +170,7 @@ static void *nft_rbtree_deactivate(const struct nft_set *set, ...@@ -170,7 +170,7 @@ static void *nft_rbtree_deactivate(const struct nft_set *set,
const struct nft_rbtree *priv = nft_set_priv(set); const struct nft_rbtree *priv = nft_set_priv(set);
const struct rb_node *parent = priv->root.rb_node; const struct rb_node *parent = priv->root.rb_node;
struct nft_rbtree_elem *rbe, *this = elem->priv; struct nft_rbtree_elem *rbe, *this = elem->priv;
u8 genmask = nft_genmask_cur(read_pnet(&set->pnet)); u8 genmask = nft_genmask_next(read_pnet(&set->pnet));
int d; int d;
while (parent != NULL) { while (parent != NULL) {
......
...@@ -1460,6 +1460,9 @@ xt_hook_ops_alloc(const struct xt_table *table, nf_hookfn *fn) ...@@ -1460,6 +1460,9 @@ xt_hook_ops_alloc(const struct xt_table *table, nf_hookfn *fn)
uint8_t hooknum; uint8_t hooknum;
struct nf_hook_ops *ops; struct nf_hook_ops *ops;
if (!num_hooks)
return ERR_PTR(-EINVAL);
ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL); ops = kmalloc(sizeof(*ops) * num_hooks, GFP_KERNEL);
if (ops == NULL) if (ops == NULL)
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
......
...@@ -33,6 +33,9 @@ nflog_tg(struct sk_buff *skb, const struct xt_action_param *par) ...@@ -33,6 +33,9 @@ nflog_tg(struct sk_buff *skb, const struct xt_action_param *par)
li.u.ulog.group = info->group; li.u.ulog.group = info->group;
li.u.ulog.qthreshold = info->threshold; li.u.ulog.qthreshold = info->threshold;
if (info->flags & XT_NFLOG_F_COPY_LEN)
li.u.ulog.flags |= NF_LOG_F_COPY_LEN;
nfulnl_log_packet(net, par->family, par->hooknum, skb, par->in, nfulnl_log_packet(net, par->family, par->hooknum, skb, par->in,
par->out, &li, info->prefix); par->out, &li, info->prefix);
return XT_CONTINUE; return XT_CONTINUE;
......
...@@ -4,12 +4,23 @@ ...@@ -4,12 +4,23 @@
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netfilter/x_tables.h> #include <linux/netfilter/x_tables.h>
#include <net/netfilter/nf_log.h>
MODULE_DESCRIPTION("Xtables: packet flow tracing"); MODULE_DESCRIPTION("Xtables: packet flow tracing");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_TRACE"); MODULE_ALIAS("ipt_TRACE");
MODULE_ALIAS("ip6t_TRACE"); MODULE_ALIAS("ip6t_TRACE");
static int trace_tg_check(const struct xt_tgchk_param *par)
{
return nf_logger_find_get(par->family, NF_LOG_TYPE_LOG);
}
static void trace_tg_destroy(const struct xt_tgdtor_param *par)
{
nf_logger_put(par->family, NF_LOG_TYPE_LOG);
}
static unsigned int static unsigned int
trace_tg(struct sk_buff *skb, const struct xt_action_param *par) trace_tg(struct sk_buff *skb, const struct xt_action_param *par)
{ {
...@@ -18,12 +29,14 @@ trace_tg(struct sk_buff *skb, const struct xt_action_param *par) ...@@ -18,12 +29,14 @@ trace_tg(struct sk_buff *skb, const struct xt_action_param *par)
} }
static struct xt_target trace_tg_reg __read_mostly = { static struct xt_target trace_tg_reg __read_mostly = {
.name = "TRACE", .name = "TRACE",
.revision = 0, .revision = 0,
.family = NFPROTO_UNSPEC, .family = NFPROTO_UNSPEC,
.table = "raw", .table = "raw",
.target = trace_tg, .target = trace_tg,
.me = THIS_MODULE, .checkentry = trace_tg_check,
.destroy = trace_tg_destroy,
.me = THIS_MODULE,
}; };
static int __init trace_tg_init(void) static int __init trace_tg_init(void)
......
...@@ -21,11 +21,39 @@ ...@@ -21,11 +21,39 @@
static int owner_check(const struct xt_mtchk_param *par) static int owner_check(const struct xt_mtchk_param *par)
{ {
struct xt_owner_match_info *info = par->matchinfo; struct xt_owner_match_info *info = par->matchinfo;
struct net *net = par->net;
/* For now only allow adding matches from the initial user namespace */ /* Only allow the common case where the userns of the writer
* matches the userns of the network namespace.
*/
if ((info->match & (XT_OWNER_UID|XT_OWNER_GID)) && if ((info->match & (XT_OWNER_UID|XT_OWNER_GID)) &&
(current_user_ns() != &init_user_ns)) (current_user_ns() != net->user_ns))
return -EINVAL; return -EINVAL;
/* Ensure the uids are valid */
if (info->match & XT_OWNER_UID) {
kuid_t uid_min = make_kuid(net->user_ns, info->uid_min);
kuid_t uid_max = make_kuid(net->user_ns, info->uid_max);
if (!uid_valid(uid_min) || !uid_valid(uid_max) ||
(info->uid_max < info->uid_min) ||
uid_lt(uid_max, uid_min)) {
return -EINVAL;
}
}
/* Ensure the gids are valid */
if (info->match & XT_OWNER_GID) {
kgid_t gid_min = make_kgid(net->user_ns, info->gid_min);
kgid_t gid_max = make_kgid(net->user_ns, info->gid_max);
if (!gid_valid(gid_min) || !gid_valid(gid_max) ||
(info->gid_max < info->gid_min) ||
gid_lt(gid_max, gid_min)) {
return -EINVAL;
}
}
return 0; return 0;
} }
...@@ -35,6 +63,7 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -35,6 +63,7 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
const struct xt_owner_match_info *info = par->matchinfo; const struct xt_owner_match_info *info = par->matchinfo;
const struct file *filp; const struct file *filp;
struct sock *sk = skb_to_full_sk(skb); struct sock *sk = skb_to_full_sk(skb);
struct net *net = par->net;
if (sk == NULL || sk->sk_socket == NULL) if (sk == NULL || sk->sk_socket == NULL)
return (info->match ^ info->invert) == 0; return (info->match ^ info->invert) == 0;
...@@ -51,8 +80,8 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -51,8 +80,8 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
(XT_OWNER_UID | XT_OWNER_GID)) == 0; (XT_OWNER_UID | XT_OWNER_GID)) == 0;
if (info->match & XT_OWNER_UID) { if (info->match & XT_OWNER_UID) {
kuid_t uid_min = make_kuid(&init_user_ns, info->uid_min); kuid_t uid_min = make_kuid(net->user_ns, info->uid_min);
kuid_t uid_max = make_kuid(&init_user_ns, info->uid_max); kuid_t uid_max = make_kuid(net->user_ns, info->uid_max);
if ((uid_gte(filp->f_cred->fsuid, uid_min) && if ((uid_gte(filp->f_cred->fsuid, uid_min) &&
uid_lte(filp->f_cred->fsuid, uid_max)) ^ uid_lte(filp->f_cred->fsuid, uid_max)) ^
!(info->invert & XT_OWNER_UID)) !(info->invert & XT_OWNER_UID))
...@@ -60,8 +89,8 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -60,8 +89,8 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par)
} }
if (info->match & XT_OWNER_GID) { if (info->match & XT_OWNER_GID) {
kgid_t gid_min = make_kgid(&init_user_ns, info->gid_min); kgid_t gid_min = make_kgid(net->user_ns, info->gid_min);
kgid_t gid_max = make_kgid(&init_user_ns, info->gid_max); kgid_t gid_max = make_kgid(net->user_ns, info->gid_max);
if ((gid_gte(filp->f_cred->fsgid, gid_min) && if ((gid_gte(filp->f_cred->fsgid, gid_min) &&
gid_lte(filp->f_cred->fsgid, gid_max)) ^ gid_lte(filp->f_cred->fsgid, gid_max)) ^
!(info->invert & XT_OWNER_GID)) !(info->invert & XT_OWNER_GID))
......
...@@ -83,8 +83,6 @@ static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -83,8 +83,6 @@ static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par)
return false; return false;
} }
#define FWINVTCP(bool, invflg) ((bool) ^ !!(tcpinfo->invflags & (invflg)))
th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph); th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
if (th == NULL) { if (th == NULL) {
/* We've been asked to examine this packet, and we /* We've been asked to examine this packet, and we
...@@ -102,9 +100,8 @@ static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par) ...@@ -102,9 +100,8 @@ static bool tcp_mt(const struct sk_buff *skb, struct xt_action_param *par)
ntohs(th->dest), ntohs(th->dest),
!!(tcpinfo->invflags & XT_TCP_INV_DSTPT))) !!(tcpinfo->invflags & XT_TCP_INV_DSTPT)))
return false; return false;
if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask) if (!NF_INVF(tcpinfo, XT_TCP_INV_FLAGS,
== tcpinfo->flg_cmp, (((unsigned char *)th)[13] & tcpinfo->flg_mask) == tcpinfo->flg_cmp))
XT_TCP_INV_FLAGS))
return false; return false;
if (tcpinfo->option) { if (tcpinfo->option) {
if (th->doff * 4 < sizeof(_tcph)) { if (th->doff * 4 < sizeof(_tcph)) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment