Merge git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next
Pablo Neira Ayuso says: ==================== Netfilter updates for net-next 1) Conntrack sets on CHECKSUM_UNNECESSARY for UDP packet with no checksum, from Kevin Mitchell. 2) skb->priority support for nfqueue, from Nicolas Dichtel. 3) Remove conntrack extension register API, from Florian Westphal. 4) Move nat destroy hook to nf_nat_hook instead, to remove nf_ct_ext_destroy(), also from Florian. 5) Wrap pptp conntrack NAT hooks into single structure, from Florian Westphal. 6) Support for tcp option set to noop for nf_tables, also from Florian. 7) Do not run x_tables comment match from packet path in nf_tables, from Florian Westphal. 8) Replace spinlock by cmpxchg() loop to update missed ct event, from Florian Westphal. 9) Wrap cttimeout hooks into single structure, from Florian. 10) Add fast nft_cmp expression for up to 16-bytes. 11) Use cb->ctx to store context in ctnetlink dump, instead of using cb->args[], from Florian Westphal. * git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf-next: netfilter: ctnetlink: use dump structure instead of raw args nfqueue: enable to set skb->priority netfilter: nft_cmp: optimize comparison for 16-bytes netfilter: cttimeout: use option structure netfilter: ecache: don't use nf_conn spinlock netfilter: nft_compat: suppress comment match netfilter: exthdr: add support for tcp option removal netfilter: conntrack: pptp: use single option structure netfilter: conntrack: remove extension register api netfilter: conntrack: handle ->destroy hook via nat_ops instead netfilter: conntrack: move extension sizes into core netfilter: conntrack: make all extensions 8-byte alignned netfilter: nfqueue: enable to get skb->priority netfilter: conntrack: mark UDP zero checksum as CHECKSUM_UNNECESSARY ==================== Link: https://lore.kernel.org/r/20220209133616.165104-1-pablo@netfilter.org Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
4523082982
|
@ -379,6 +379,7 @@ struct nf_nat_hook {
|
|||
unsigned int (*manip_pkt)(struct sk_buff *skb, struct nf_conn *ct,
|
||||
enum nf_nat_manip_type mtype,
|
||||
enum ip_conntrack_dir dir);
|
||||
void (*remove_nat_bysrc)(struct nf_conn *ct);
|
||||
};
|
||||
|
||||
extern const struct nf_nat_hook __rcu *nf_nat_hook;
|
||||
|
|
|
@ -300,26 +300,22 @@ union pptp_ctrl_union {
|
|||
struct PptpSetLinkInfo setlink;
|
||||
};
|
||||
|
||||
extern int
|
||||
(*nf_nat_pptp_hook_outbound)(struct sk_buff *skb,
|
||||
struct nf_conn *ct, enum ip_conntrack_info ctinfo,
|
||||
unsigned int protoff,
|
||||
struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq);
|
||||
|
||||
extern int
|
||||
(*nf_nat_pptp_hook_inbound)(struct sk_buff *skb,
|
||||
struct nf_conn *ct, enum ip_conntrack_info ctinfo,
|
||||
unsigned int protoff,
|
||||
struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq);
|
||||
|
||||
extern void
|
||||
(*nf_nat_pptp_hook_exp_gre)(struct nf_conntrack_expect *exp_orig,
|
||||
struct nf_conntrack_expect *exp_reply);
|
||||
|
||||
extern void
|
||||
(*nf_nat_pptp_hook_expectfn)(struct nf_conn *ct,
|
||||
struct nf_conntrack_expect *exp);
|
||||
struct nf_nat_pptp_hook {
|
||||
int (*outbound)(struct sk_buff *skb,
|
||||
struct nf_conn *ct, enum ip_conntrack_info ctinfo,
|
||||
unsigned int protoff,
|
||||
struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq);
|
||||
int (*inbound)(struct sk_buff *skb,
|
||||
struct nf_conn *ct, enum ip_conntrack_info ctinfo,
|
||||
unsigned int protoff,
|
||||
struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq);
|
||||
void (*exp_gre)(struct nf_conntrack_expect *exp_orig,
|
||||
struct nf_conntrack_expect *exp_reply);
|
||||
void (*expectfn)(struct nf_conn *ct,
|
||||
struct nf_conntrack_expect *exp);
|
||||
};
|
||||
|
||||
extern const struct nf_nat_pptp_hook __rcu *nf_nat_pptp_hook;
|
||||
#endif /* _NF_CONNTRACK_PPTP_H */
|
||||
|
|
|
@ -78,7 +78,6 @@ static inline void nf_ct_acct_update(struct nf_conn *ct, u32 dir,
|
|||
|
||||
void nf_conntrack_acct_pernet_init(struct net *net);
|
||||
|
||||
int nf_conntrack_acct_init(void);
|
||||
void nf_conntrack_acct_fini(void);
|
||||
|
||||
#endif /* _NF_CONNTRACK_ACCT_H */
|
||||
|
|
|
@ -21,10 +21,10 @@ enum nf_ct_ecache_state {
|
|||
|
||||
struct nf_conntrack_ecache {
|
||||
unsigned long cache; /* bitops want long */
|
||||
u16 missed; /* missed events */
|
||||
u16 ctmask; /* bitmask of ct events to be delivered */
|
||||
u16 expmask; /* bitmask of expect events to be delivered */
|
||||
enum nf_ct_ecache_state state:8;/* ecache state */
|
||||
u32 missed; /* missed events */
|
||||
u32 portid; /* netlink portid of destroyer */
|
||||
};
|
||||
|
||||
|
@ -166,9 +166,6 @@ void nf_conntrack_ecache_work(struct net *net, enum nf_ct_ecache_state state);
|
|||
void 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 bool nf_conntrack_ecache_dwork_pending(const struct net *net)
|
||||
{
|
||||
return net->ct.ecache_dwork_pending;
|
||||
|
@ -194,16 +191,6 @@ static inline void nf_conntrack_ecache_pernet_init(struct net *net)
|
|||
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 bool nf_conntrack_ecache_dwork_pending(const struct net *net) { return false; }
|
||||
#endif /* CONFIG_NF_CONNTRACK_EVENTS */
|
||||
#endif /*_NF_CONNTRACK_ECACHE_H*/
|
||||
|
|
|
@ -49,7 +49,7 @@ enum nf_ct_ext_id {
|
|||
struct nf_ct_ext {
|
||||
u8 offset[NF_CT_EXT_NUM];
|
||||
u8 len;
|
||||
char data[];
|
||||
char data[] __aligned(8);
|
||||
};
|
||||
|
||||
static inline bool __nf_ct_ext_exist(const struct nf_ct_ext *ext, u8 id)
|
||||
|
@ -72,23 +72,7 @@ static inline void *__nf_ct_ext_find(const struct nf_conn *ct, u8 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);
|
||||
|
||||
/* Add this type, returns pointer to data or NULL. */
|
||||
void *nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp);
|
||||
|
||||
struct nf_ct_ext_type {
|
||||
/* Destroys relationships (can be NULL). */
|
||||
void (*destroy)(struct nf_conn *ct);
|
||||
|
||||
enum nf_ct_ext_id id;
|
||||
|
||||
/* Length and min alignment. */
|
||||
u8 len;
|
||||
u8 align;
|
||||
};
|
||||
|
||||
int nf_ct_extend_register(const struct nf_ct_ext_type *type);
|
||||
void nf_ct_extend_unregister(const struct nf_ct_ext_type *type);
|
||||
#endif /* _NF_CONNTRACK_EXTEND_H */
|
||||
|
|
|
@ -45,12 +45,9 @@ int nf_connlabels_replace(struct nf_conn *ct,
|
|||
|
||||
#ifdef CONFIG_NF_CONNTRACK_LABELS
|
||||
int nf_conntrack_labels_init(void);
|
||||
void nf_conntrack_labels_fini(void);
|
||||
int nf_connlabels_get(struct net *net, unsigned int bit);
|
||||
void nf_connlabels_put(struct net *net);
|
||||
#else
|
||||
static inline int nf_conntrack_labels_init(void) { return 0; }
|
||||
static inline void nf_conntrack_labels_fini(void) {}
|
||||
static inline int nf_connlabels_get(struct net *net, unsigned int bit) { return 0; }
|
||||
static inline void nf_connlabels_put(struct net *net) {}
|
||||
#endif
|
||||
|
|
|
@ -42,7 +42,4 @@ 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 */
|
||||
|
|
|
@ -89,23 +89,11 @@ static inline unsigned int *nf_ct_timeout_lookup(const struct nf_conn *ct)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
|
||||
int nf_conntrack_timeout_init(void);
|
||||
void nf_conntrack_timeout_fini(void);
|
||||
void nf_ct_untimeout(struct net *net, struct nf_ct_timeout *timeout);
|
||||
int nf_ct_set_timeout(struct net *net, struct nf_conn *ct, u8 l3num, u8 l4num,
|
||||
const char *timeout_name);
|
||||
void nf_ct_destroy_timeout(struct nf_conn *ct);
|
||||
#else
|
||||
static inline int nf_conntrack_timeout_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void nf_conntrack_timeout_fini(void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
static inline int nf_ct_set_timeout(struct net *net, struct nf_conn *ct,
|
||||
u8 l3num, u8 l4num,
|
||||
const char *timeout_name)
|
||||
|
@ -120,8 +108,12 @@ static inline void nf_ct_destroy_timeout(struct nf_conn *ct)
|
|||
#endif /* CONFIG_NF_CONNTRACK_TIMEOUT */
|
||||
|
||||
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
|
||||
extern struct nf_ct_timeout *(*nf_ct_timeout_find_get_hook)(struct net *net, const char *name);
|
||||
extern void (*nf_ct_timeout_put_hook)(struct nf_ct_timeout *timeout);
|
||||
struct nf_ct_timeout_hooks {
|
||||
struct nf_ct_timeout *(*timeout_find_get)(struct net *net, const char *name);
|
||||
void (*timeout_put)(struct nf_ct_timeout *timeout);
|
||||
};
|
||||
|
||||
extern const struct nf_ct_timeout_hooks *nf_ct_timeout_hook;
|
||||
#endif
|
||||
|
||||
#endif /* _NF_CONNTRACK_TIMEOUT_H */
|
||||
|
|
|
@ -40,21 +40,8 @@ struct nf_conn_tstamp *nf_ct_tstamp_ext_add(struct nf_conn *ct, gfp_t gfp)
|
|||
|
||||
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
|
||||
void nf_conntrack_tstamp_pernet_init(struct net *net);
|
||||
|
||||
int nf_conntrack_tstamp_init(void);
|
||||
void nf_conntrack_tstamp_fini(void);
|
||||
#else
|
||||
static inline void nf_conntrack_tstamp_pernet_init(struct net *net) {}
|
||||
|
||||
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 */
|
||||
|
|
|
@ -42,6 +42,14 @@ struct nft_cmp_fast_expr {
|
|||
bool inv;
|
||||
};
|
||||
|
||||
struct nft_cmp16_fast_expr {
|
||||
struct nft_data data;
|
||||
struct nft_data mask;
|
||||
u8 sreg;
|
||||
u8 len;
|
||||
bool inv;
|
||||
};
|
||||
|
||||
struct nft_immediate_expr {
|
||||
struct nft_data data;
|
||||
u8 dreg;
|
||||
|
@ -59,6 +67,7 @@ static inline u32 nft_cmp_fast_mask(unsigned int len)
|
|||
}
|
||||
|
||||
extern const struct nft_expr_ops nft_cmp_fast_ops;
|
||||
extern const struct nft_expr_ops nft_cmp16_fast_ops;
|
||||
|
||||
struct nft_payload {
|
||||
enum nft_payload_bases base:8;
|
||||
|
|
|
@ -61,6 +61,7 @@ enum nfqnl_attr_type {
|
|||
NFQA_SECCTX, /* security context string */
|
||||
NFQA_VLAN, /* nested attribute: packet vlan info */
|
||||
NFQA_L2HDR, /* full L2 header */
|
||||
NFQA_PRIORITY, /* skb->priority */
|
||||
|
||||
__NFQA_MAX
|
||||
};
|
||||
|
|
|
@ -295,28 +295,24 @@ pptp_inbound_pkt(struct sk_buff *skb,
|
|||
return NF_ACCEPT;
|
||||
}
|
||||
|
||||
static const struct nf_nat_pptp_hook pptp_hooks = {
|
||||
.outbound = pptp_outbound_pkt,
|
||||
.inbound = pptp_inbound_pkt,
|
||||
.exp_gre = pptp_exp_gre,
|
||||
.expectfn = pptp_nat_expected,
|
||||
};
|
||||
|
||||
static int __init nf_nat_helper_pptp_init(void)
|
||||
{
|
||||
BUG_ON(nf_nat_pptp_hook_outbound != NULL);
|
||||
RCU_INIT_POINTER(nf_nat_pptp_hook_outbound, pptp_outbound_pkt);
|
||||
WARN_ON(nf_nat_pptp_hook != NULL);
|
||||
RCU_INIT_POINTER(nf_nat_pptp_hook, &pptp_hooks);
|
||||
|
||||
BUG_ON(nf_nat_pptp_hook_inbound != NULL);
|
||||
RCU_INIT_POINTER(nf_nat_pptp_hook_inbound, pptp_inbound_pkt);
|
||||
|
||||
BUG_ON(nf_nat_pptp_hook_exp_gre != NULL);
|
||||
RCU_INIT_POINTER(nf_nat_pptp_hook_exp_gre, pptp_exp_gre);
|
||||
|
||||
BUG_ON(nf_nat_pptp_hook_expectfn != NULL);
|
||||
RCU_INIT_POINTER(nf_nat_pptp_hook_expectfn, pptp_nat_expected);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit nf_nat_helper_pptp_fini(void)
|
||||
{
|
||||
RCU_INIT_POINTER(nf_nat_pptp_hook_expectfn, NULL);
|
||||
RCU_INIT_POINTER(nf_nat_pptp_hook_exp_gre, NULL);
|
||||
RCU_INIT_POINTER(nf_nat_pptp_hook_inbound, NULL);
|
||||
RCU_INIT_POINTER(nf_nat_pptp_hook_outbound, NULL);
|
||||
RCU_INIT_POINTER(nf_nat_pptp_hook, NULL);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
|
|
|
@ -22,26 +22,7 @@ static bool nf_ct_acct __read_mostly;
|
|||
module_param_named(acct, nf_ct_acct, bool, 0644);
|
||||
MODULE_PARM_DESC(acct, "Enable connection tracking flow accounting.");
|
||||
|
||||
static const struct nf_ct_ext_type acct_extend = {
|
||||
.len = sizeof(struct nf_conn_acct),
|
||||
.align = __alignof__(struct nf_conn_acct),
|
||||
.id = NF_CT_EXT_ACCT,
|
||||
};
|
||||
|
||||
void nf_conntrack_acct_pernet_init(struct net *net)
|
||||
{
|
||||
net->ct.sysctl_acct = nf_ct_acct;
|
||||
}
|
||||
|
||||
int nf_conntrack_acct_init(void)
|
||||
{
|
||||
int ret = nf_ct_extend_register(&acct_extend);
|
||||
if (ret < 0)
|
||||
pr_err("Unable to register extension\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void nf_conntrack_acct_fini(void)
|
||||
{
|
||||
nf_ct_extend_unregister(&acct_extend);
|
||||
}
|
||||
|
|
|
@ -38,7 +38,6 @@
|
|||
#include <net/netfilter/nf_conntrack_l4proto.h>
|
||||
#include <net/netfilter/nf_conntrack_expect.h>
|
||||
#include <net/netfilter/nf_conntrack_helper.h>
|
||||
#include <net/netfilter/nf_conntrack_seqadj.h>
|
||||
#include <net/netfilter/nf_conntrack_core.h>
|
||||
#include <net/netfilter/nf_conntrack_extend.h>
|
||||
#include <net/netfilter/nf_conntrack_acct.h>
|
||||
|
@ -48,7 +47,6 @@
|
|||
#include <net/netfilter/nf_conntrack_timeout.h>
|
||||
#include <net/netfilter/nf_conntrack_labels.h>
|
||||
#include <net/netfilter/nf_conntrack_synproxy.h>
|
||||
#include <net/netfilter/nf_conntrack_act_ct.h>
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
#include <net/netfilter/nf_nat_helper.h>
|
||||
#include <net/netns/hash.h>
|
||||
|
@ -595,7 +593,7 @@ EXPORT_SYMBOL_GPL(nf_ct_tmpl_alloc);
|
|||
|
||||
void nf_ct_tmpl_free(struct nf_conn *tmpl)
|
||||
{
|
||||
nf_ct_ext_destroy(tmpl);
|
||||
kfree(tmpl->ext);
|
||||
|
||||
if (ARCH_KMALLOC_MINALIGN <= NFCT_INFOMASK)
|
||||
kfree((char *)tmpl - tmpl->proto.tmpl_padto);
|
||||
|
@ -1598,7 +1596,17 @@ void nf_conntrack_free(struct nf_conn *ct)
|
|||
*/
|
||||
WARN_ON(refcount_read(&ct->ct_general.use) != 0);
|
||||
|
||||
nf_ct_ext_destroy(ct);
|
||||
if (ct->status & IPS_SRC_NAT_DONE) {
|
||||
const struct nf_nat_hook *nat_hook;
|
||||
|
||||
rcu_read_lock();
|
||||
nat_hook = rcu_dereference(nf_nat_hook);
|
||||
if (nat_hook)
|
||||
nat_hook->remove_nat_bysrc(ct);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
kfree(ct->ext);
|
||||
kmem_cache_free(nf_conntrack_cachep, ct);
|
||||
cnet = nf_ct_pernet(net);
|
||||
|
||||
|
@ -2468,13 +2476,7 @@ void nf_conntrack_cleanup_end(void)
|
|||
kvfree(nf_conntrack_hash);
|
||||
|
||||
nf_conntrack_proto_fini();
|
||||
nf_conntrack_seqadj_fini();
|
||||
nf_conntrack_labels_fini();
|
||||
nf_conntrack_helper_fini();
|
||||
nf_conntrack_timeout_fini();
|
||||
nf_conntrack_ecache_fini();
|
||||
nf_conntrack_tstamp_fini();
|
||||
nf_conntrack_acct_fini();
|
||||
nf_conntrack_expect_fini();
|
||||
|
||||
kmem_cache_destroy(nf_conntrack_cachep);
|
||||
|
@ -2629,39 +2631,6 @@ int nf_conntrack_set_hashsize(const char *val, const struct kernel_param *kp)
|
|||
return nf_conntrack_hash_resize(hashsize);
|
||||
}
|
||||
|
||||
static __always_inline unsigned int total_extension_size(void)
|
||||
{
|
||||
/* remember to add new extensions below */
|
||||
BUILD_BUG_ON(NF_CT_EXT_NUM > 10);
|
||||
|
||||
return sizeof(struct nf_ct_ext) +
|
||||
sizeof(struct nf_conn_help)
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
+ sizeof(struct nf_conn_nat)
|
||||
#endif
|
||||
+ sizeof(struct nf_conn_seqadj)
|
||||
+ sizeof(struct nf_conn_acct)
|
||||
#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
+ sizeof(struct nf_conntrack_ecache)
|
||||
#endif
|
||||
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
|
||||
+ sizeof(struct nf_conn_tstamp)
|
||||
#endif
|
||||
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
|
||||
+ sizeof(struct nf_conn_timeout)
|
||||
#endif
|
||||
#ifdef CONFIG_NF_CONNTRACK_LABELS
|
||||
+ sizeof(struct nf_conn_labels)
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
|
||||
+ sizeof(struct nf_conn_synproxy)
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_NET_ACT_CT)
|
||||
+ sizeof(struct nf_conn_act_ct_ext)
|
||||
#endif
|
||||
;
|
||||
};
|
||||
|
||||
int nf_conntrack_init_start(void)
|
||||
{
|
||||
unsigned long nr_pages = totalram_pages();
|
||||
|
@ -2669,9 +2638,6 @@ int nf_conntrack_init_start(void)
|
|||
int ret = -ENOMEM;
|
||||
int i;
|
||||
|
||||
/* struct nf_ct_ext uses u8 to store offsets/size */
|
||||
BUILD_BUG_ON(total_extension_size() > 255u);
|
||||
|
||||
seqcount_spinlock_init(&nf_conntrack_generation,
|
||||
&nf_conntrack_locks_all_lock);
|
||||
|
||||
|
@ -2716,34 +2682,10 @@ int nf_conntrack_init_start(void)
|
|||
if (ret < 0)
|
||||
goto err_expect;
|
||||
|
||||
ret = nf_conntrack_acct_init();
|
||||
if (ret < 0)
|
||||
goto err_acct;
|
||||
|
||||
ret = nf_conntrack_tstamp_init();
|
||||
if (ret < 0)
|
||||
goto err_tstamp;
|
||||
|
||||
ret = nf_conntrack_ecache_init();
|
||||
if (ret < 0)
|
||||
goto err_ecache;
|
||||
|
||||
ret = nf_conntrack_timeout_init();
|
||||
if (ret < 0)
|
||||
goto err_timeout;
|
||||
|
||||
ret = nf_conntrack_helper_init();
|
||||
if (ret < 0)
|
||||
goto err_helper;
|
||||
|
||||
ret = nf_conntrack_labels_init();
|
||||
if (ret < 0)
|
||||
goto err_labels;
|
||||
|
||||
ret = nf_conntrack_seqadj_init();
|
||||
if (ret < 0)
|
||||
goto err_seqadj;
|
||||
|
||||
ret = nf_conntrack_proto_init();
|
||||
if (ret < 0)
|
||||
goto err_proto;
|
||||
|
@ -2761,20 +2703,8 @@ err_kfunc:
|
|||
cancel_delayed_work_sync(&conntrack_gc_work.dwork);
|
||||
nf_conntrack_proto_fini();
|
||||
err_proto:
|
||||
nf_conntrack_seqadj_fini();
|
||||
err_seqadj:
|
||||
nf_conntrack_labels_fini();
|
||||
err_labels:
|
||||
nf_conntrack_helper_fini();
|
||||
err_helper:
|
||||
nf_conntrack_timeout_fini();
|
||||
err_timeout:
|
||||
nf_conntrack_ecache_fini();
|
||||
err_ecache:
|
||||
nf_conntrack_tstamp_fini();
|
||||
err_tstamp:
|
||||
nf_conntrack_acct_fini();
|
||||
err_acct:
|
||||
nf_conntrack_expect_fini();
|
||||
err_expect:
|
||||
kmem_cache_destroy(nf_conntrack_cachep);
|
||||
|
|
|
@ -131,13 +131,13 @@ static void ecache_work(struct work_struct *work)
|
|||
}
|
||||
|
||||
static int __nf_conntrack_eventmask_report(struct nf_conntrack_ecache *e,
|
||||
const unsigned int events,
|
||||
const unsigned long missed,
|
||||
const u32 events,
|
||||
const u32 missed,
|
||||
const struct nf_ct_event *item)
|
||||
{
|
||||
struct nf_conn *ct = item->ct;
|
||||
struct net *net = nf_ct_net(item->ct);
|
||||
struct nf_ct_event_notifier *notify;
|
||||
u32 old, want;
|
||||
int ret;
|
||||
|
||||
if (!((events | missed) & e->ctmask))
|
||||
|
@ -157,12 +157,13 @@ static int __nf_conntrack_eventmask_report(struct nf_conntrack_ecache *e,
|
|||
if (likely(ret >= 0 && missed == 0))
|
||||
return 0;
|
||||
|
||||
spin_lock_bh(&ct->lock);
|
||||
if (ret < 0)
|
||||
e->missed |= events;
|
||||
else
|
||||
e->missed &= ~missed;
|
||||
spin_unlock_bh(&ct->lock);
|
||||
do {
|
||||
old = READ_ONCE(e->missed);
|
||||
if (ret < 0)
|
||||
want = old | events;
|
||||
else
|
||||
want = old & ~missed;
|
||||
} while (cmpxchg(&e->missed, old, want) != old);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -172,7 +173,7 @@ int nf_conntrack_eventmask_report(unsigned int events, struct nf_conn *ct,
|
|||
{
|
||||
struct nf_conntrack_ecache *e;
|
||||
struct nf_ct_event item;
|
||||
unsigned long missed;
|
||||
unsigned int missed;
|
||||
int ret;
|
||||
|
||||
if (!nf_ct_is_confirmed(ct))
|
||||
|
@ -211,7 +212,7 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct)
|
|||
{
|
||||
struct nf_conntrack_ecache *e;
|
||||
struct nf_ct_event item;
|
||||
unsigned long events;
|
||||
unsigned int events;
|
||||
|
||||
if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct))
|
||||
return;
|
||||
|
@ -304,12 +305,6 @@ void nf_conntrack_ecache_work(struct net *net, enum nf_ct_ecache_state state)
|
|||
#define NF_CT_EVENTS_DEFAULT 1
|
||||
static int nf_ct_events __read_mostly = NF_CT_EVENTS_DEFAULT;
|
||||
|
||||
static const struct nf_ct_ext_type event_extend = {
|
||||
.len = sizeof(struct nf_conntrack_ecache),
|
||||
.align = __alignof__(struct nf_conntrack_ecache),
|
||||
.id = NF_CT_EXT_ECACHE,
|
||||
};
|
||||
|
||||
void nf_conntrack_ecache_pernet_init(struct net *net)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
|
@ -317,6 +312,8 @@ void nf_conntrack_ecache_pernet_init(struct net *net)
|
|||
net->ct.sysctl_events = nf_ct_events;
|
||||
cnet->ct_net = &net->ct;
|
||||
INIT_DELAYED_WORK(&cnet->ecache_dwork, ecache_work);
|
||||
|
||||
BUILD_BUG_ON(__IPCT_MAX >= 16); /* e->ctmask is u16 */
|
||||
}
|
||||
|
||||
void nf_conntrack_ecache_pernet_fini(struct net *net)
|
||||
|
@ -325,19 +322,3 @@ void nf_conntrack_ecache_pernet_fini(struct net *net)
|
|||
|
||||
cancel_delayed_work_sync(&cnet->ecache_dwork);
|
||||
}
|
||||
|
||||
int nf_conntrack_ecache_init(void)
|
||||
{
|
||||
int ret = nf_ct_extend_register(&event_extend);
|
||||
if (ret < 0)
|
||||
pr_err("Unable to register event extension\n");
|
||||
|
||||
BUILD_BUG_ON(__IPCT_MAX >= 16); /* ctmask, missed use u16 */
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void nf_conntrack_ecache_fini(void)
|
||||
{
|
||||
nf_ct_extend_unregister(&event_extend);
|
||||
}
|
||||
|
|
|
@ -13,40 +13,90 @@
|
|||
#include <linux/skbuff.h>
|
||||
#include <net/netfilter/nf_conntrack_extend.h>
|
||||
|
||||
static struct nf_ct_ext_type __rcu *nf_ct_ext_types[NF_CT_EXT_NUM];
|
||||
static DEFINE_MUTEX(nf_ct_ext_type_mutex);
|
||||
#include <net/netfilter/nf_conntrack_helper.h>
|
||||
#include <net/netfilter/nf_conntrack_acct.h>
|
||||
#include <net/netfilter/nf_conntrack_seqadj.h>
|
||||
#include <net/netfilter/nf_conntrack_ecache.h>
|
||||
#include <net/netfilter/nf_conntrack_zones.h>
|
||||
#include <net/netfilter/nf_conntrack_timestamp.h>
|
||||
#include <net/netfilter/nf_conntrack_timeout.h>
|
||||
#include <net/netfilter/nf_conntrack_labels.h>
|
||||
#include <net/netfilter/nf_conntrack_synproxy.h>
|
||||
#include <net/netfilter/nf_conntrack_act_ct.h>
|
||||
#include <net/netfilter/nf_nat.h>
|
||||
|
||||
#define NF_CT_EXT_PREALLOC 128u /* conntrack events are on by default */
|
||||
|
||||
void nf_ct_ext_destroy(struct nf_conn *ct)
|
||||
static const u8 nf_ct_ext_type_len[NF_CT_EXT_NUM] = {
|
||||
[NF_CT_EXT_HELPER] = sizeof(struct nf_conn_help),
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
[NF_CT_EXT_NAT] = sizeof(struct nf_conn_nat),
|
||||
#endif
|
||||
[NF_CT_EXT_SEQADJ] = sizeof(struct nf_conn_seqadj),
|
||||
[NF_CT_EXT_ACCT] = sizeof(struct nf_conn_acct),
|
||||
#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
[NF_CT_EXT_ECACHE] = sizeof(struct nf_conntrack_ecache),
|
||||
#endif
|
||||
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
|
||||
[NF_CT_EXT_TSTAMP] = sizeof(struct nf_conn_acct),
|
||||
#endif
|
||||
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
|
||||
[NF_CT_EXT_TIMEOUT] = sizeof(struct nf_conn_tstamp),
|
||||
#endif
|
||||
#ifdef CONFIG_NF_CONNTRACK_LABELS
|
||||
[NF_CT_EXT_LABELS] = sizeof(struct nf_conn_labels),
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
|
||||
[NF_CT_EXT_SYNPROXY] = sizeof(struct nf_conn_synproxy),
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_NET_ACT_CT)
|
||||
[NF_CT_EXT_ACT_CT] = sizeof(struct nf_conn_act_ct_ext),
|
||||
#endif
|
||||
};
|
||||
|
||||
static __always_inline unsigned int total_extension_size(void)
|
||||
{
|
||||
unsigned int i;
|
||||
struct nf_ct_ext_type *t;
|
||||
/* remember to add new extensions below */
|
||||
BUILD_BUG_ON(NF_CT_EXT_NUM > 10);
|
||||
|
||||
for (i = 0; i < NF_CT_EXT_NUM; i++) {
|
||||
rcu_read_lock();
|
||||
t = rcu_dereference(nf_ct_ext_types[i]);
|
||||
|
||||
/* Here the nf_ct_ext_type might have been unregisterd.
|
||||
* I.e., it has responsible to cleanup private
|
||||
* area in all conntracks when it is unregisterd.
|
||||
*/
|
||||
if (t && t->destroy)
|
||||
t->destroy(ct);
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
kfree(ct->ext);
|
||||
return sizeof(struct nf_ct_ext) +
|
||||
sizeof(struct nf_conn_help)
|
||||
#if IS_ENABLED(CONFIG_NF_NAT)
|
||||
+ sizeof(struct nf_conn_nat)
|
||||
#endif
|
||||
+ sizeof(struct nf_conn_seqadj)
|
||||
+ sizeof(struct nf_conn_acct)
|
||||
#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
+ sizeof(struct nf_conntrack_ecache)
|
||||
#endif
|
||||
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
|
||||
+ sizeof(struct nf_conn_tstamp)
|
||||
#endif
|
||||
#ifdef CONFIG_NF_CONNTRACK_TIMEOUT
|
||||
+ sizeof(struct nf_conn_timeout)
|
||||
#endif
|
||||
#ifdef CONFIG_NF_CONNTRACK_LABELS
|
||||
+ sizeof(struct nf_conn_labels)
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
|
||||
+ sizeof(struct nf_conn_synproxy)
|
||||
#endif
|
||||
#if IS_ENABLED(CONFIG_NET_ACT_CT)
|
||||
+ sizeof(struct nf_conn_act_ct_ext)
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
void *nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
|
||||
{
|
||||
unsigned int newlen, newoff, oldlen, alloc;
|
||||
struct nf_ct_ext_type *t;
|
||||
struct nf_ct_ext *new;
|
||||
|
||||
/* Conntrack must not be confirmed to avoid races on reallocation. */
|
||||
WARN_ON(nf_ct_is_confirmed(ct));
|
||||
|
||||
/* struct nf_ct_ext uses u8 to store offsets/size */
|
||||
BUILD_BUG_ON(total_extension_size() > 255u);
|
||||
|
||||
if (ct->ext) {
|
||||
const struct nf_ct_ext *old = ct->ext;
|
||||
|
@ -58,16 +108,8 @@ void *nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
|
|||
oldlen = sizeof(*new);
|
||||
}
|
||||
|
||||
rcu_read_lock();
|
||||
t = rcu_dereference(nf_ct_ext_types[id]);
|
||||
if (!t) {
|
||||
rcu_read_unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newoff = ALIGN(oldlen, t->align);
|
||||
newlen = newoff + t->len;
|
||||
rcu_read_unlock();
|
||||
newoff = ALIGN(oldlen, __alignof__(struct nf_ct_ext));
|
||||
newlen = newoff + nf_ct_ext_type_len[id];
|
||||
|
||||
alloc = max(newlen, NF_CT_EXT_PREALLOC);
|
||||
new = krealloc(ct->ext, alloc, gfp);
|
||||
|
@ -85,31 +127,3 @@ void *nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp)
|
|||
return (void *)new + newoff;
|
||||
}
|
||||
EXPORT_SYMBOL(nf_ct_ext_add);
|
||||
|
||||
/* This MUST be called in process context. */
|
||||
int nf_ct_extend_register(const struct nf_ct_ext_type *type)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&nf_ct_ext_type_mutex);
|
||||
if (nf_ct_ext_types[type->id]) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
||||
rcu_assign_pointer(nf_ct_ext_types[type->id], type);
|
||||
out:
|
||||
mutex_unlock(&nf_ct_ext_type_mutex);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_ct_extend_register);
|
||||
|
||||
/* This MUST be called in process context. */
|
||||
void nf_ct_extend_unregister(const struct nf_ct_ext_type *type)
|
||||
{
|
||||
mutex_lock(&nf_ct_ext_type_mutex);
|
||||
RCU_INIT_POINTER(nf_ct_ext_types[type->id], NULL);
|
||||
mutex_unlock(&nf_ct_ext_type_mutex);
|
||||
synchronize_rcu();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_ct_extend_unregister);
|
||||
|
|
|
@ -550,12 +550,6 @@ void nf_nat_helper_unregister(struct nf_conntrack_nat_helper *nat)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nf_nat_helper_unregister);
|
||||
|
||||
static const struct nf_ct_ext_type helper_extend = {
|
||||
.len = sizeof(struct nf_conn_help),
|
||||
.align = __alignof__(struct nf_conn_help),
|
||||
.id = NF_CT_EXT_HELPER,
|
||||
};
|
||||
|
||||
void nf_conntrack_helper_pernet_init(struct net *net)
|
||||
{
|
||||
struct nf_conntrack_net *cnet = nf_ct_pernet(net);
|
||||
|
@ -565,28 +559,17 @@ void nf_conntrack_helper_pernet_init(struct net *net)
|
|||
|
||||
int nf_conntrack_helper_init(void)
|
||||
{
|
||||
int ret;
|
||||
nf_ct_helper_hsize = 1; /* gets rounded up to use one page */
|
||||
nf_ct_helper_hash =
|
||||
nf_ct_alloc_hashtable(&nf_ct_helper_hsize, 0);
|
||||
if (!nf_ct_helper_hash)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = nf_ct_extend_register(&helper_extend);
|
||||
if (ret < 0) {
|
||||
pr_err("nf_ct_helper: Unable to register helper extension.\n");
|
||||
goto out_extend;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&nf_ct_nat_helpers);
|
||||
return 0;
|
||||
out_extend:
|
||||
kvfree(nf_ct_helper_hash);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void nf_conntrack_helper_fini(void)
|
||||
{
|
||||
nf_ct_extend_unregister(&helper_extend);
|
||||
kvfree(nf_ct_helper_hash);
|
||||
}
|
||||
|
|
|
@ -67,6 +67,8 @@ int nf_connlabels_get(struct net *net, unsigned int bits)
|
|||
net->ct.labels_used++;
|
||||
spin_unlock(&nf_connlabels_lock);
|
||||
|
||||
BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE / sizeof(long) >= U8_MAX);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_connlabels_get);
|
||||
|
@ -78,21 +80,3 @@ void nf_connlabels_put(struct net *net)
|
|||
spin_unlock(&nf_connlabels_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_connlabels_put);
|
||||
|
||||
static const struct nf_ct_ext_type labels_extend = {
|
||||
.len = sizeof(struct nf_conn_labels),
|
||||
.align = __alignof__(struct nf_conn_labels),
|
||||
.id = NF_CT_EXT_LABELS,
|
||||
};
|
||||
|
||||
int nf_conntrack_labels_init(void)
|
||||
{
|
||||
BUILD_BUG_ON(NF_CT_LABELS_MAX_SIZE / sizeof(long) >= U8_MAX);
|
||||
|
||||
return nf_ct_extend_register(&labels_extend);
|
||||
}
|
||||
|
||||
void nf_conntrack_labels_fini(void)
|
||||
{
|
||||
nf_ct_extend_unregister(&labels_extend);
|
||||
}
|
||||
|
|
|
@ -58,6 +58,12 @@
|
|||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
struct ctnetlink_list_dump_ctx {
|
||||
struct nf_conn *last;
|
||||
unsigned int cpu;
|
||||
bool done;
|
||||
};
|
||||
|
||||
static int ctnetlink_dump_tuples_proto(struct sk_buff *skb,
|
||||
const struct nf_conntrack_tuple *tuple,
|
||||
const struct nf_conntrack_l4proto *l4proto)
|
||||
|
@ -1694,14 +1700,18 @@ static int ctnetlink_get_conntrack(struct sk_buff *skb,
|
|||
|
||||
static int ctnetlink_done_list(struct netlink_callback *cb)
|
||||
{
|
||||
if (cb->args[1])
|
||||
nf_ct_put((struct nf_conn *)cb->args[1]);
|
||||
struct ctnetlink_list_dump_ctx *ctx = (void *)cb->ctx;
|
||||
|
||||
if (ctx->last)
|
||||
nf_ct_put(ctx->last);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying)
|
||||
{
|
||||
struct ctnetlink_list_dump_ctx *ctx = (void *)cb->ctx;
|
||||
struct nf_conn *ct, *last;
|
||||
struct nf_conntrack_tuple_hash *h;
|
||||
struct hlist_nulls_node *n;
|
||||
|
@ -1712,12 +1722,12 @@ ctnetlink_dump_list(struct sk_buff *skb, struct netlink_callback *cb, bool dying
|
|||
struct hlist_nulls_head *list;
|
||||
struct net *net = sock_net(skb->sk);
|
||||
|
||||
if (cb->args[2])
|
||||
if (ctx->done)
|
||||
return 0;
|
||||
|
||||
last = (struct nf_conn *)cb->args[1];
|
||||
last = ctx->last;
|
||||
|
||||
for (cpu = cb->args[0]; cpu < nr_cpu_ids; cpu++) {
|
||||
for (cpu = ctx->cpu; cpu < nr_cpu_ids; cpu++) {
|
||||
struct ct_pcpu *pcpu;
|
||||
|
||||
if (!cpu_possible(cpu))
|
||||
|
@ -1731,10 +1741,10 @@ restart:
|
|||
ct = nf_ct_tuplehash_to_ctrack(h);
|
||||
if (l3proto && nf_ct_l3num(ct) != l3proto)
|
||||
continue;
|
||||
if (cb->args[1]) {
|
||||
if (ctx->last) {
|
||||
if (ct != last)
|
||||
continue;
|
||||
cb->args[1] = 0;
|
||||
ctx->last = NULL;
|
||||
}
|
||||
|
||||
/* We can't dump extension info for the unconfirmed
|
||||
|
@ -1751,19 +1761,19 @@ restart:
|
|||
if (res < 0) {
|
||||
if (!refcount_inc_not_zero(&ct->ct_general.use))
|
||||
continue;
|
||||
cb->args[0] = cpu;
|
||||
cb->args[1] = (unsigned long)ct;
|
||||
ctx->cpu = cpu;
|
||||
ctx->last = ct;
|
||||
spin_unlock_bh(&pcpu->lock);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (cb->args[1]) {
|
||||
cb->args[1] = 0;
|
||||
if (ctx->last) {
|
||||
ctx->last = NULL;
|
||||
goto restart;
|
||||
}
|
||||
spin_unlock_bh(&pcpu->lock);
|
||||
}
|
||||
cb->args[2] = 1;
|
||||
ctx->done = true;
|
||||
out:
|
||||
if (last)
|
||||
nf_ct_put(last);
|
||||
|
@ -3877,6 +3887,8 @@ static int __init ctnetlink_init(void)
|
|||
{
|
||||
int ret;
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct ctnetlink_list_dump_ctx) > sizeof_field(struct netlink_callback, ctx));
|
||||
|
||||
ret = nfnetlink_subsys_register(&ctnl_subsys);
|
||||
if (ret < 0) {
|
||||
pr_err("ctnetlink_init: cannot register with nfnetlink.\n");
|
||||
|
|
|
@ -45,30 +45,8 @@ MODULE_ALIAS_NFCT_HELPER("pptp");
|
|||
|
||||
static DEFINE_SPINLOCK(nf_pptp_lock);
|
||||
|
||||
int
|
||||
(*nf_nat_pptp_hook_outbound)(struct sk_buff *skb,
|
||||
struct nf_conn *ct, enum ip_conntrack_info ctinfo,
|
||||
unsigned int protoff, struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq) __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_outbound);
|
||||
|
||||
int
|
||||
(*nf_nat_pptp_hook_inbound)(struct sk_buff *skb,
|
||||
struct nf_conn *ct, enum ip_conntrack_info ctinfo,
|
||||
unsigned int protoff, struct PptpControlHeader *ctlh,
|
||||
union pptp_ctrl_union *pptpReq) __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_inbound);
|
||||
|
||||
void
|
||||
(*nf_nat_pptp_hook_exp_gre)(struct nf_conntrack_expect *expect_orig,
|
||||
struct nf_conntrack_expect *expect_reply)
|
||||
__read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_exp_gre);
|
||||
|
||||
void
|
||||
(*nf_nat_pptp_hook_expectfn)(struct nf_conn *ct,
|
||||
struct nf_conntrack_expect *exp) __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_nat_pptp_hook_expectfn);
|
||||
const struct nf_nat_pptp_hook *nf_nat_pptp_hook;
|
||||
EXPORT_SYMBOL_GPL(nf_nat_pptp_hook);
|
||||
|
||||
#if defined(DEBUG) || defined(CONFIG_DYNAMIC_DEBUG)
|
||||
/* PptpControlMessageType names */
|
||||
|
@ -111,8 +89,8 @@ EXPORT_SYMBOL(pptp_msg_name);
|
|||
static void pptp_expectfn(struct nf_conn *ct,
|
||||
struct nf_conntrack_expect *exp)
|
||||
{
|
||||
const struct nf_nat_pptp_hook *hook;
|
||||
struct net *net = nf_ct_net(ct);
|
||||
typeof(nf_nat_pptp_hook_expectfn) nf_nat_pptp_expectfn;
|
||||
pr_debug("increasing timeouts\n");
|
||||
|
||||
/* increase timeout of GRE data channel conntrack entry */
|
||||
|
@ -122,9 +100,9 @@ static void pptp_expectfn(struct nf_conn *ct,
|
|||
/* Can you see how rusty this code is, compared with the pre-2.6.11
|
||||
* one? That's what happened to my shiny newnat of 2002 ;( -HW */
|
||||
|
||||
nf_nat_pptp_expectfn = rcu_dereference(nf_nat_pptp_hook_expectfn);
|
||||
if (nf_nat_pptp_expectfn && ct->master->status & IPS_NAT_MASK)
|
||||
nf_nat_pptp_expectfn(ct, exp);
|
||||
hook = rcu_dereference(nf_nat_pptp_hook);
|
||||
if (hook && ct->master->status & IPS_NAT_MASK)
|
||||
hook->expectfn(ct, exp);
|
||||
else {
|
||||
struct nf_conntrack_tuple inv_t;
|
||||
struct nf_conntrack_expect *exp_other;
|
||||
|
@ -209,9 +187,9 @@ static void pptp_destroy_siblings(struct nf_conn *ct)
|
|||
static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid)
|
||||
{
|
||||
struct nf_conntrack_expect *exp_orig, *exp_reply;
|
||||
const struct nf_nat_pptp_hook *hook;
|
||||
enum ip_conntrack_dir dir;
|
||||
int ret = 1;
|
||||
typeof(nf_nat_pptp_hook_exp_gre) nf_nat_pptp_exp_gre;
|
||||
|
||||
exp_orig = nf_ct_expect_alloc(ct);
|
||||
if (exp_orig == NULL)
|
||||
|
@ -239,9 +217,9 @@ static int exp_gre(struct nf_conn *ct, __be16 callid, __be16 peer_callid)
|
|||
IPPROTO_GRE, &callid, &peer_callid);
|
||||
exp_reply->expectfn = pptp_expectfn;
|
||||
|
||||
nf_nat_pptp_exp_gre = rcu_dereference(nf_nat_pptp_hook_exp_gre);
|
||||
if (nf_nat_pptp_exp_gre && ct->status & IPS_NAT_MASK)
|
||||
nf_nat_pptp_exp_gre(exp_orig, exp_reply);
|
||||
hook = rcu_dereference(nf_nat_pptp_hook);
|
||||
if (hook && ct->status & IPS_NAT_MASK)
|
||||
hook->exp_gre(exp_orig, exp_reply);
|
||||
if (nf_ct_expect_related(exp_orig, 0) != 0)
|
||||
goto out_put_both;
|
||||
if (nf_ct_expect_related(exp_reply, 0) != 0)
|
||||
|
@ -279,9 +257,9 @@ pptp_inbound_pkt(struct sk_buff *skb, unsigned int protoff,
|
|||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
struct nf_ct_pptp_master *info = nfct_help_data(ct);
|
||||
const struct nf_nat_pptp_hook *hook;
|
||||
u_int16_t msg;
|
||||
__be16 cid = 0, pcid = 0;
|
||||
typeof(nf_nat_pptp_hook_inbound) nf_nat_pptp_inbound;
|
||||
|
||||
msg = ntohs(ctlh->messageType);
|
||||
pr_debug("inbound control message %s\n", pptp_msg_name(msg));
|
||||
|
@ -383,10 +361,9 @@ pptp_inbound_pkt(struct sk_buff *skb, unsigned int protoff,
|
|||
goto invalid;
|
||||
}
|
||||
|
||||
nf_nat_pptp_inbound = rcu_dereference(nf_nat_pptp_hook_inbound);
|
||||
if (nf_nat_pptp_inbound && ct->status & IPS_NAT_MASK)
|
||||
return nf_nat_pptp_inbound(skb, ct, ctinfo,
|
||||
protoff, ctlh, pptpReq);
|
||||
hook = rcu_dereference(nf_nat_pptp_hook);
|
||||
if (hook && ct->status & IPS_NAT_MASK)
|
||||
return hook->inbound(skb, ct, ctinfo, protoff, ctlh, pptpReq);
|
||||
return NF_ACCEPT;
|
||||
|
||||
invalid:
|
||||
|
@ -407,9 +384,9 @@ pptp_outbound_pkt(struct sk_buff *skb, unsigned int protoff,
|
|||
enum ip_conntrack_info ctinfo)
|
||||
{
|
||||
struct nf_ct_pptp_master *info = nfct_help_data(ct);
|
||||
const struct nf_nat_pptp_hook *hook;
|
||||
u_int16_t msg;
|
||||
__be16 cid = 0, pcid = 0;
|
||||
typeof(nf_nat_pptp_hook_outbound) nf_nat_pptp_outbound;
|
||||
|
||||
msg = ntohs(ctlh->messageType);
|
||||
pr_debug("outbound control message %s\n", pptp_msg_name(msg));
|
||||
|
@ -479,10 +456,9 @@ pptp_outbound_pkt(struct sk_buff *skb, unsigned int protoff,
|
|||
goto invalid;
|
||||
}
|
||||
|
||||
nf_nat_pptp_outbound = rcu_dereference(nf_nat_pptp_hook_outbound);
|
||||
if (nf_nat_pptp_outbound && ct->status & IPS_NAT_MASK)
|
||||
return nf_nat_pptp_outbound(skb, ct, ctinfo,
|
||||
protoff, ctlh, pptpReq);
|
||||
hook = rcu_dereference(nf_nat_pptp_hook);
|
||||
if (hook && ct->status & IPS_NAT_MASK)
|
||||
return hook->outbound(skb, ct, ctinfo, protoff, ctlh, pptpReq);
|
||||
return NF_ACCEPT;
|
||||
|
||||
invalid:
|
||||
|
|
|
@ -63,8 +63,10 @@ static bool udp_error(struct sk_buff *skb,
|
|||
}
|
||||
|
||||
/* Packet with no checksum */
|
||||
if (!hdr->check)
|
||||
if (!hdr->check) {
|
||||
skb->ip_summed = CHECKSUM_UNNECESSARY;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Checksum invalid? Ignore.
|
||||
* We skip checking packets on the outgoing path
|
||||
|
|
|
@ -232,19 +232,3 @@ s32 nf_ct_seq_offset(const struct nf_conn *ct,
|
|||
this_way->offset_after : this_way->offset_before;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_ct_seq_offset);
|
||||
|
||||
static const struct nf_ct_ext_type nf_ct_seqadj_extend = {
|
||||
.len = sizeof(struct nf_conn_seqadj),
|
||||
.align = __alignof__(struct nf_conn_seqadj),
|
||||
.id = NF_CT_EXT_SEQADJ,
|
||||
};
|
||||
|
||||
int nf_conntrack_seqadj_init(void)
|
||||
{
|
||||
return nf_ct_extend_register(&nf_ct_seqadj_extend);
|
||||
}
|
||||
|
||||
void nf_conntrack_seqadj_fini(void)
|
||||
{
|
||||
nf_ct_extend_unregister(&nf_ct_seqadj_extend);
|
||||
}
|
||||
|
|
|
@ -22,12 +22,8 @@
|
|||
#include <net/netfilter/nf_conntrack_l4proto.h>
|
||||
#include <net/netfilter/nf_conntrack_timeout.h>
|
||||
|
||||
struct nf_ct_timeout *
|
||||
(*nf_ct_timeout_find_get_hook)(struct net *net, const char *name) __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_ct_timeout_find_get_hook);
|
||||
|
||||
void (*nf_ct_timeout_put_hook)(struct nf_ct_timeout *timeout) __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_ct_timeout_put_hook);
|
||||
const struct nf_ct_timeout_hooks *nf_ct_timeout_hook __read_mostly;
|
||||
EXPORT_SYMBOL_GPL(nf_ct_timeout_hook);
|
||||
|
||||
static int untimeout(struct nf_conn *ct, void *timeout)
|
||||
{
|
||||
|
@ -48,31 +44,30 @@ EXPORT_SYMBOL_GPL(nf_ct_untimeout);
|
|||
|
||||
static void __nf_ct_timeout_put(struct nf_ct_timeout *timeout)
|
||||
{
|
||||
typeof(nf_ct_timeout_put_hook) timeout_put;
|
||||
const struct nf_ct_timeout_hooks *h = rcu_dereference(nf_ct_timeout_hook);
|
||||
|
||||
timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
|
||||
if (timeout_put)
|
||||
timeout_put(timeout);
|
||||
if (h)
|
||||
h->timeout_put(timeout);
|
||||
}
|
||||
|
||||
int nf_ct_set_timeout(struct net *net, struct nf_conn *ct,
|
||||
u8 l3num, u8 l4num, const char *timeout_name)
|
||||
{
|
||||
typeof(nf_ct_timeout_find_get_hook) timeout_find_get;
|
||||
const struct nf_ct_timeout_hooks *h;
|
||||
struct nf_ct_timeout *timeout;
|
||||
struct nf_conn_timeout *timeout_ext;
|
||||
const char *errmsg = NULL;
|
||||
int ret = 0;
|
||||
|
||||
rcu_read_lock();
|
||||
timeout_find_get = rcu_dereference(nf_ct_timeout_find_get_hook);
|
||||
if (!timeout_find_get) {
|
||||
h = rcu_dereference(nf_ct_timeout_hook);
|
||||
if (!h) {
|
||||
ret = -ENOENT;
|
||||
errmsg = "Timeout policy base is empty";
|
||||
goto out;
|
||||
}
|
||||
|
||||
timeout = timeout_find_get(net, timeout_name);
|
||||
timeout = h->timeout_find_get(net, timeout_name);
|
||||
if (!timeout) {
|
||||
ret = -ENOENT;
|
||||
pr_info_ratelimited("No such timeout policy \"%s\"\n",
|
||||
|
@ -119,37 +114,18 @@ EXPORT_SYMBOL_GPL(nf_ct_set_timeout);
|
|||
void nf_ct_destroy_timeout(struct nf_conn *ct)
|
||||
{
|
||||
struct nf_conn_timeout *timeout_ext;
|
||||
typeof(nf_ct_timeout_put_hook) timeout_put;
|
||||
const struct nf_ct_timeout_hooks *h;
|
||||
|
||||
rcu_read_lock();
|
||||
timeout_put = rcu_dereference(nf_ct_timeout_put_hook);
|
||||
h = rcu_dereference(nf_ct_timeout_hook);
|
||||
|
||||
if (timeout_put) {
|
||||
if (h) {
|
||||
timeout_ext = nf_ct_timeout_find(ct);
|
||||
if (timeout_ext) {
|
||||
timeout_put(timeout_ext->timeout);
|
||||
h->timeout_put(timeout_ext->timeout);
|
||||
RCU_INIT_POINTER(timeout_ext->timeout, NULL);
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_ct_destroy_timeout);
|
||||
|
||||
static const struct nf_ct_ext_type timeout_extend = {
|
||||
.len = sizeof(struct nf_conn_timeout),
|
||||
.align = __alignof__(struct nf_conn_timeout),
|
||||
.id = NF_CT_EXT_TIMEOUT,
|
||||
};
|
||||
|
||||
int nf_conntrack_timeout_init(void)
|
||||
{
|
||||
int ret = nf_ct_extend_register(&timeout_extend);
|
||||
if (ret < 0)
|
||||
pr_err("nf_ct_timeout: Unable to register timeout extension.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void nf_conntrack_timeout_fini(void)
|
||||
{
|
||||
nf_ct_extend_unregister(&timeout_extend);
|
||||
}
|
||||
|
|
|
@ -19,27 +19,7 @@ static bool nf_ct_tstamp __read_mostly;
|
|||
module_param_named(tstamp, nf_ct_tstamp, bool, 0644);
|
||||
MODULE_PARM_DESC(tstamp, "Enable connection tracking flow timestamping.");
|
||||
|
||||
static const struct nf_ct_ext_type tstamp_extend = {
|
||||
.len = sizeof(struct nf_conn_tstamp),
|
||||
.align = __alignof__(struct nf_conn_tstamp),
|
||||
.id = NF_CT_EXT_TSTAMP,
|
||||
};
|
||||
|
||||
void nf_conntrack_tstamp_pernet_init(struct net *net)
|
||||
{
|
||||
net->ct.sysctl_tstamp = nf_ct_tstamp;
|
||||
}
|
||||
|
||||
int nf_conntrack_tstamp_init(void)
|
||||
{
|
||||
int ret;
|
||||
ret = nf_ct_extend_register(&tstamp_extend);
|
||||
if (ret < 0)
|
||||
pr_err("Unable to register extension\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void nf_conntrack_tstamp_fini(void)
|
||||
{
|
||||
nf_ct_extend_unregister(&tstamp_extend);
|
||||
}
|
||||
|
|
|
@ -838,7 +838,7 @@ static int nf_nat_proto_remove(struct nf_conn *i, void *data)
|
|||
return i->status & IPS_NAT_MASK ? 1 : 0;
|
||||
}
|
||||
|
||||
static void __nf_nat_cleanup_conntrack(struct nf_conn *ct)
|
||||
static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
|
||||
{
|
||||
unsigned int h;
|
||||
|
||||
|
@ -860,7 +860,7 @@ static int nf_nat_proto_clean(struct nf_conn *ct, void *data)
|
|||
* will delete entry from already-freed table.
|
||||
*/
|
||||
if (test_and_clear_bit(IPS_SRC_NAT_DONE_BIT, &ct->status))
|
||||
__nf_nat_cleanup_conntrack(ct);
|
||||
nf_nat_cleanup_conntrack(ct);
|
||||
|
||||
/* don't delete conntrack. Although that would make things a lot
|
||||
* simpler, we'd end up flushing all conntracks on nat rmmod.
|
||||
|
@ -868,20 +868,6 @@ static int nf_nat_proto_clean(struct nf_conn *ct, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* No one using conntrack by the time this called. */
|
||||
static void nf_nat_cleanup_conntrack(struct nf_conn *ct)
|
||||
{
|
||||
if (ct->status & IPS_SRC_NAT_DONE)
|
||||
__nf_nat_cleanup_conntrack(ct);
|
||||
}
|
||||
|
||||
static struct nf_ct_ext_type nat_extend __read_mostly = {
|
||||
.len = sizeof(struct nf_conn_nat),
|
||||
.align = __alignof__(struct nf_conn_nat),
|
||||
.destroy = nf_nat_cleanup_conntrack,
|
||||
.id = NF_CT_EXT_NAT,
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
|
||||
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
|
@ -1173,6 +1159,7 @@ static const struct nf_nat_hook nat_hook = {
|
|||
.decode_session = __nf_nat_decode_session,
|
||||
#endif
|
||||
.manip_pkt = nf_nat_manip_pkt,
|
||||
.remove_nat_bysrc = nf_nat_cleanup_conntrack,
|
||||
};
|
||||
|
||||
static int __init nf_nat_init(void)
|
||||
|
@ -1188,19 +1175,11 @@ static int __init nf_nat_init(void)
|
|||
if (!nf_nat_bysource)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = nf_ct_extend_register(&nat_extend);
|
||||
if (ret < 0) {
|
||||
kvfree(nf_nat_bysource);
|
||||
pr_err("Unable to register extension\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (i = 0; i < CONNTRACK_LOCKS; i++)
|
||||
spin_lock_init(&nf_nat_locks[i]);
|
||||
|
||||
ret = register_pernet_subsys(&nat_net_ops);
|
||||
if (ret < 0) {
|
||||
nf_ct_extend_unregister(&nat_extend);
|
||||
kvfree(nf_nat_bysource);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1219,7 +1198,6 @@ static void __exit nf_nat_cleanup(void)
|
|||
|
||||
nf_ct_iterate_destroy(nf_nat_proto_clean, &clean);
|
||||
|
||||
nf_ct_extend_unregister(&nat_extend);
|
||||
nf_ct_helper_expectfn_unregister(&follow_master_nat);
|
||||
RCU_INIT_POINTER(nf_nat_hook, NULL);
|
||||
|
||||
|
|
|
@ -236,12 +236,6 @@ synproxy_tstamp_adjust(struct sk_buff *skb, unsigned int protoff,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static struct nf_ct_ext_type nf_ct_synproxy_extend __read_mostly = {
|
||||
.len = sizeof(struct nf_conn_synproxy),
|
||||
.align = __alignof__(struct nf_conn_synproxy),
|
||||
.id = NF_CT_EXT_SYNPROXY,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static void *synproxy_cpu_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
|
@ -387,28 +381,12 @@ static struct pernet_operations synproxy_net_ops = {
|
|||
|
||||
static int __init synproxy_core_init(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = nf_ct_extend_register(&nf_ct_synproxy_extend);
|
||||
if (err < 0)
|
||||
goto err1;
|
||||
|
||||
err = register_pernet_subsys(&synproxy_net_ops);
|
||||
if (err < 0)
|
||||
goto err2;
|
||||
|
||||
return 0;
|
||||
|
||||
err2:
|
||||
nf_ct_extend_unregister(&nf_ct_synproxy_extend);
|
||||
err1:
|
||||
return err;
|
||||
return register_pernet_subsys(&synproxy_net_ops);
|
||||
}
|
||||
|
||||
static void __exit synproxy_core_exit(void)
|
||||
{
|
||||
unregister_pernet_subsys(&synproxy_net_ops);
|
||||
nf_ct_extend_unregister(&nf_ct_synproxy_extend);
|
||||
}
|
||||
|
||||
module_init(synproxy_core_init);
|
||||
|
|
|
@ -67,6 +67,20 @@ static void nft_cmp_fast_eval(const struct nft_expr *expr,
|
|||
regs->verdict.code = NFT_BREAK;
|
||||
}
|
||||
|
||||
static void nft_cmp16_fast_eval(const struct nft_expr *expr,
|
||||
struct nft_regs *regs)
|
||||
{
|
||||
const struct nft_cmp16_fast_expr *priv = nft_expr_priv(expr);
|
||||
const u64 *reg_data = (const u64 *)®s->data[priv->sreg];
|
||||
const u64 *mask = (const u64 *)&priv->mask;
|
||||
const u64 *data = (const u64 *)&priv->data;
|
||||
|
||||
if (((reg_data[0] & mask[0]) == data[0] &&
|
||||
((reg_data[1] & mask[1]) == data[1])) ^ priv->inv)
|
||||
return;
|
||||
regs->verdict.code = NFT_BREAK;
|
||||
}
|
||||
|
||||
static noinline void __nft_trace_verdict(struct nft_traceinfo *info,
|
||||
const struct nft_chain *chain,
|
||||
const struct nft_regs *regs)
|
||||
|
@ -225,6 +239,8 @@ next_rule:
|
|||
nft_rule_dp_for_each_expr(expr, last, rule) {
|
||||
if (expr->ops == &nft_cmp_fast_ops)
|
||||
nft_cmp_fast_eval(expr, ®s);
|
||||
else if (expr->ops == &nft_cmp16_fast_ops)
|
||||
nft_cmp16_fast_eval(expr, ®s);
|
||||
else if (expr->ops == &nft_bitwise_fast_ops)
|
||||
nft_bitwise_fast_eval(expr, ®s);
|
||||
else if (expr->ops != &nft_payload_fast_ops ||
|
||||
|
|
|
@ -605,6 +605,11 @@ static struct pernet_operations cttimeout_ops = {
|
|||
.size = sizeof(struct nfct_timeout_pernet),
|
||||
};
|
||||
|
||||
static const struct nf_ct_timeout_hooks hooks = {
|
||||
.timeout_find_get = ctnl_timeout_find_get,
|
||||
.timeout_put = ctnl_timeout_put,
|
||||
};
|
||||
|
||||
static int __init cttimeout_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -619,8 +624,7 @@ static int __init cttimeout_init(void)
|
|||
"nfnetlink.\n");
|
||||
goto err_out;
|
||||
}
|
||||
RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, ctnl_timeout_find_get);
|
||||
RCU_INIT_POINTER(nf_ct_timeout_put_hook, ctnl_timeout_put);
|
||||
RCU_INIT_POINTER(nf_ct_timeout_hook, &hooks);
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
|
@ -633,8 +637,7 @@ static void __exit cttimeout_exit(void)
|
|||
nfnetlink_subsys_unregister(&cttimeout_subsys);
|
||||
|
||||
unregister_pernet_subsys(&cttimeout_ops);
|
||||
RCU_INIT_POINTER(nf_ct_timeout_find_get_hook, NULL);
|
||||
RCU_INIT_POINTER(nf_ct_timeout_put_hook, NULL);
|
||||
RCU_INIT_POINTER(nf_ct_timeout_hook, NULL);
|
||||
synchronize_rcu();
|
||||
}
|
||||
|
||||
|
|
|
@ -402,6 +402,7 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
|
|||
+ nla_total_size(sizeof(u_int32_t)) /* ifindex */
|
||||
#endif
|
||||
+ nla_total_size(sizeof(u_int32_t)) /* mark */
|
||||
+ nla_total_size(sizeof(u_int32_t)) /* priority */
|
||||
+ nla_total_size(sizeof(struct nfqnl_msg_packet_hw))
|
||||
+ nla_total_size(sizeof(u_int32_t)) /* skbinfo */
|
||||
+ nla_total_size(sizeof(u_int32_t)); /* cap_len */
|
||||
|
@ -559,6 +560,10 @@ nfqnl_build_packet_message(struct net *net, struct nfqnl_instance *queue,
|
|||
nla_put_be32(skb, NFQA_MARK, htonl(entskb->mark)))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (entskb->priority &&
|
||||
nla_put_be32(skb, NFQA_PRIORITY, htonl(entskb->priority)))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (indev && entskb->dev &&
|
||||
skb_mac_header_was_set(entskb) &&
|
||||
skb_mac_header_len(entskb) != 0) {
|
||||
|
@ -1014,11 +1019,13 @@ static const struct nla_policy nfqa_verdict_policy[NFQA_MAX+1] = {
|
|||
[NFQA_CT] = { .type = NLA_UNSPEC },
|
||||
[NFQA_EXP] = { .type = NLA_UNSPEC },
|
||||
[NFQA_VLAN] = { .type = NLA_NESTED },
|
||||
[NFQA_PRIORITY] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static const struct nla_policy nfqa_verdict_batch_policy[NFQA_MAX+1] = {
|
||||
[NFQA_VERDICT_HDR] = { .len = sizeof(struct nfqnl_msg_verdict_hdr) },
|
||||
[NFQA_MARK] = { .type = NLA_U32 },
|
||||
[NFQA_PRIORITY] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static struct nfqnl_instance *
|
||||
|
@ -1099,6 +1106,9 @@ static int nfqnl_recv_verdict_batch(struct sk_buff *skb,
|
|||
if (nfqa[NFQA_MARK])
|
||||
entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK]));
|
||||
|
||||
if (nfqa[NFQA_PRIORITY])
|
||||
entry->skb->priority = ntohl(nla_get_be32(nfqa[NFQA_PRIORITY]));
|
||||
|
||||
nfqnl_reinject(entry, verdict);
|
||||
}
|
||||
return 0;
|
||||
|
@ -1225,6 +1235,9 @@ static int nfqnl_recv_verdict(struct sk_buff *skb, const struct nfnl_info *info,
|
|||
if (nfqa[NFQA_MARK])
|
||||
entry->skb->mark = ntohl(nla_get_be32(nfqa[NFQA_MARK]));
|
||||
|
||||
if (nfqa[NFQA_PRIORITY])
|
||||
entry->skb->priority = ntohl(nla_get_be32(nfqa[NFQA_PRIORITY]));
|
||||
|
||||
nfqnl_reinject(entry, verdict);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -272,12 +272,103 @@ const struct nft_expr_ops nft_cmp_fast_ops = {
|
|||
.offload = nft_cmp_fast_offload,
|
||||
};
|
||||
|
||||
static u32 nft_cmp_mask(u32 bitlen)
|
||||
{
|
||||
return (__force u32)cpu_to_le32(~0U >> (sizeof(u32) * BITS_PER_BYTE - bitlen));
|
||||
}
|
||||
|
||||
static void nft_cmp16_fast_mask(struct nft_data *data, unsigned int bitlen)
|
||||
{
|
||||
int len = bitlen / BITS_PER_BYTE;
|
||||
int i, words = len / sizeof(u32);
|
||||
|
||||
for (i = 0; i < words; i++) {
|
||||
data->data[i] = 0xffffffff;
|
||||
bitlen -= sizeof(u32) * BITS_PER_BYTE;
|
||||
}
|
||||
|
||||
if (len % sizeof(u32))
|
||||
data->data[i++] = nft_cmp_mask(bitlen);
|
||||
|
||||
for (; i < 4; i++)
|
||||
data->data[i] = 0;
|
||||
}
|
||||
|
||||
static int nft_cmp16_fast_init(const struct nft_ctx *ctx,
|
||||
const struct nft_expr *expr,
|
||||
const struct nlattr * const tb[])
|
||||
{
|
||||
struct nft_cmp16_fast_expr *priv = nft_expr_priv(expr);
|
||||
struct nft_data_desc desc;
|
||||
int err;
|
||||
|
||||
err = nft_data_init(NULL, &priv->data, sizeof(priv->data), &desc,
|
||||
tb[NFTA_CMP_DATA]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = nft_parse_register_load(tb[NFTA_CMP_SREG], &priv->sreg, desc.len);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
nft_cmp16_fast_mask(&priv->mask, desc.len * BITS_PER_BYTE);
|
||||
priv->inv = ntohl(nla_get_be32(tb[NFTA_CMP_OP])) != NFT_CMP_EQ;
|
||||
priv->len = desc.len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nft_cmp16_fast_offload(struct nft_offload_ctx *ctx,
|
||||
struct nft_flow_rule *flow,
|
||||
const struct nft_expr *expr)
|
||||
{
|
||||
const struct nft_cmp16_fast_expr *priv = nft_expr_priv(expr);
|
||||
struct nft_cmp_expr cmp = {
|
||||
.data = priv->data,
|
||||
.sreg = priv->sreg,
|
||||
.len = priv->len,
|
||||
.op = priv->inv ? NFT_CMP_NEQ : NFT_CMP_EQ,
|
||||
};
|
||||
|
||||
return __nft_cmp_offload(ctx, flow, &cmp);
|
||||
}
|
||||
|
||||
static int nft_cmp16_fast_dump(struct sk_buff *skb, const struct nft_expr *expr)
|
||||
{
|
||||
const struct nft_cmp16_fast_expr *priv = nft_expr_priv(expr);
|
||||
enum nft_cmp_ops op = priv->inv ? NFT_CMP_NEQ : NFT_CMP_EQ;
|
||||
|
||||
if (nft_dump_register(skb, NFTA_CMP_SREG, priv->sreg))
|
||||
goto nla_put_failure;
|
||||
if (nla_put_be32(skb, NFTA_CMP_OP, htonl(op)))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nft_data_dump(skb, NFTA_CMP_DATA, &priv->data,
|
||||
NFT_DATA_VALUE, priv->len) < 0)
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
const struct nft_expr_ops nft_cmp16_fast_ops = {
|
||||
.type = &nft_cmp_type,
|
||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_cmp16_fast_expr)),
|
||||
.eval = NULL, /* inlined */
|
||||
.init = nft_cmp16_fast_init,
|
||||
.dump = nft_cmp16_fast_dump,
|
||||
.offload = nft_cmp16_fast_offload,
|
||||
};
|
||||
|
||||
static const struct nft_expr_ops *
|
||||
nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
|
||||
{
|
||||
struct nft_data_desc desc;
|
||||
struct nft_data data;
|
||||
enum nft_cmp_ops op;
|
||||
u8 sreg;
|
||||
int err;
|
||||
|
||||
if (tb[NFTA_CMP_SREG] == NULL ||
|
||||
|
@ -306,9 +397,16 @@ nft_cmp_select_ops(const struct nft_ctx *ctx, const struct nlattr * const tb[])
|
|||
if (desc.type != NFT_DATA_VALUE)
|
||||
goto err1;
|
||||
|
||||
if (desc.len <= sizeof(u32) && (op == NFT_CMP_EQ || op == NFT_CMP_NEQ))
|
||||
return &nft_cmp_fast_ops;
|
||||
sreg = ntohl(nla_get_be32(tb[NFTA_CMP_SREG]));
|
||||
|
||||
if (op == NFT_CMP_EQ || op == NFT_CMP_NEQ) {
|
||||
if (desc.len <= sizeof(u32))
|
||||
return &nft_cmp_fast_ops;
|
||||
else if (desc.len <= sizeof(data) &&
|
||||
((sreg >= NFT_REG_1 && sreg <= NFT_REG_4) ||
|
||||
(sreg >= NFT_REG32_00 && sreg <= NFT_REG32_12 && sreg % 2 == 0)))
|
||||
return &nft_cmp16_fast_ops;
|
||||
}
|
||||
return &nft_cmp_ops;
|
||||
err1:
|
||||
nft_data_release(&data, desc.type);
|
||||
|
|
|
@ -731,6 +731,14 @@ static const struct nfnetlink_subsystem nfnl_compat_subsys = {
|
|||
|
||||
static struct nft_expr_type nft_match_type;
|
||||
|
||||
static bool nft_match_reduce(struct nft_regs_track *track,
|
||||
const struct nft_expr *expr)
|
||||
{
|
||||
const struct xt_match *match = expr->ops->data;
|
||||
|
||||
return strcmp(match->name, "comment") == 0;
|
||||
}
|
||||
|
||||
static const struct nft_expr_ops *
|
||||
nft_match_select_ops(const struct nft_ctx *ctx,
|
||||
const struct nlattr * const tb[])
|
||||
|
@ -773,6 +781,7 @@ nft_match_select_ops(const struct nft_ctx *ctx,
|
|||
ops->dump = nft_match_dump;
|
||||
ops->validate = nft_match_validate;
|
||||
ops->data = match;
|
||||
ops->reduce = nft_match_reduce;
|
||||
|
||||
matchsize = NFT_EXPR_SIZE(XT_ALIGN(match->matchsize));
|
||||
if (matchsize > NFT_MATCH_LARGE_THRESH) {
|
||||
|
|
|
@ -308,6 +308,63 @@ err:
|
|||
regs->verdict.code = NFT_BREAK;
|
||||
}
|
||||
|
||||
static void nft_exthdr_tcp_strip_eval(const struct nft_expr *expr,
|
||||
struct nft_regs *regs,
|
||||
const struct nft_pktinfo *pkt)
|
||||
{
|
||||
u8 buff[sizeof(struct tcphdr) + MAX_TCP_OPTION_SPACE];
|
||||
struct nft_exthdr *priv = nft_expr_priv(expr);
|
||||
unsigned int i, tcphdr_len, optl;
|
||||
struct tcphdr *tcph;
|
||||
u8 *opt;
|
||||
|
||||
tcph = nft_tcp_header_pointer(pkt, sizeof(buff), buff, &tcphdr_len);
|
||||
if (!tcph)
|
||||
goto err;
|
||||
|
||||
if (skb_ensure_writable(pkt->skb, nft_thoff(pkt) + tcphdr_len))
|
||||
goto drop;
|
||||
|
||||
opt = (u8 *)nft_tcp_header_pointer(pkt, sizeof(buff), buff, &tcphdr_len);
|
||||
if (!opt)
|
||||
goto err;
|
||||
for (i = sizeof(*tcph); i < tcphdr_len - 1; i += optl) {
|
||||
unsigned int j;
|
||||
|
||||
optl = optlen(opt, i);
|
||||
if (priv->type != opt[i])
|
||||
continue;
|
||||
|
||||
if (i + optl > tcphdr_len)
|
||||
goto drop;
|
||||
|
||||
for (j = 0; j < optl; ++j) {
|
||||
u16 n = TCPOPT_NOP;
|
||||
u16 o = opt[i+j];
|
||||
|
||||
if ((i + j) % 2 == 0) {
|
||||
o <<= 8;
|
||||
n <<= 8;
|
||||
}
|
||||
inet_proto_csum_replace2(&tcph->check, pkt->skb, htons(o),
|
||||
htons(n), false);
|
||||
}
|
||||
memset(opt + i, TCPOPT_NOP, optl);
|
||||
return;
|
||||
}
|
||||
|
||||
/* option not found, continue. This allows to do multiple
|
||||
* option removals per rule.
|
||||
*/
|
||||
return;
|
||||
err:
|
||||
regs->verdict.code = NFT_BREAK;
|
||||
return;
|
||||
drop:
|
||||
/* can't remove, no choice but to drop */
|
||||
regs->verdict.code = NF_DROP;
|
||||
}
|
||||
|
||||
static void nft_exthdr_sctp_eval(const struct nft_expr *expr,
|
||||
struct nft_regs *regs,
|
||||
const struct nft_pktinfo *pkt)
|
||||
|
@ -457,6 +514,28 @@ static int nft_exthdr_tcp_set_init(const struct nft_ctx *ctx,
|
|||
priv->len);
|
||||
}
|
||||
|
||||
static int nft_exthdr_tcp_strip_init(const struct nft_ctx *ctx,
|
||||
const struct nft_expr *expr,
|
||||
const struct nlattr * const tb[])
|
||||
{
|
||||
struct nft_exthdr *priv = nft_expr_priv(expr);
|
||||
|
||||
if (tb[NFTA_EXTHDR_SREG] ||
|
||||
tb[NFTA_EXTHDR_DREG] ||
|
||||
tb[NFTA_EXTHDR_FLAGS] ||
|
||||
tb[NFTA_EXTHDR_OFFSET] ||
|
||||
tb[NFTA_EXTHDR_LEN])
|
||||
return -EINVAL;
|
||||
|
||||
if (!tb[NFTA_EXTHDR_TYPE])
|
||||
return -EINVAL;
|
||||
|
||||
priv->type = nla_get_u8(tb[NFTA_EXTHDR_TYPE]);
|
||||
priv->op = NFT_EXTHDR_OP_TCPOPT;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nft_exthdr_ipv4_init(const struct nft_ctx *ctx,
|
||||
const struct nft_expr *expr,
|
||||
const struct nlattr * const tb[])
|
||||
|
@ -517,6 +596,13 @@ static int nft_exthdr_dump_set(struct sk_buff *skb, const struct nft_expr *expr)
|
|||
return nft_exthdr_dump_common(skb, priv);
|
||||
}
|
||||
|
||||
static int nft_exthdr_dump_strip(struct sk_buff *skb, const struct nft_expr *expr)
|
||||
{
|
||||
const struct nft_exthdr *priv = nft_expr_priv(expr);
|
||||
|
||||
return nft_exthdr_dump_common(skb, priv);
|
||||
}
|
||||
|
||||
static const struct nft_expr_ops nft_exthdr_ipv6_ops = {
|
||||
.type = &nft_exthdr_type,
|
||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_exthdr)),
|
||||
|
@ -549,6 +635,14 @@ static const struct nft_expr_ops nft_exthdr_tcp_set_ops = {
|
|||
.dump = nft_exthdr_dump_set,
|
||||
};
|
||||
|
||||
static const struct nft_expr_ops nft_exthdr_tcp_strip_ops = {
|
||||
.type = &nft_exthdr_type,
|
||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_exthdr)),
|
||||
.eval = nft_exthdr_tcp_strip_eval,
|
||||
.init = nft_exthdr_tcp_strip_init,
|
||||
.dump = nft_exthdr_dump_strip,
|
||||
};
|
||||
|
||||
static const struct nft_expr_ops nft_exthdr_sctp_ops = {
|
||||
.type = &nft_exthdr_type,
|
||||
.size = NFT_EXPR_SIZE(sizeof(struct nft_exthdr)),
|
||||
|
@ -576,7 +670,7 @@ nft_exthdr_select_ops(const struct nft_ctx *ctx,
|
|||
return &nft_exthdr_tcp_set_ops;
|
||||
if (tb[NFTA_EXTHDR_DREG])
|
||||
return &nft_exthdr_tcp_ops;
|
||||
break;
|
||||
return &nft_exthdr_tcp_strip_ops;
|
||||
case NFT_EXTHDR_OP_IPV6:
|
||||
if (tb[NFTA_EXTHDR_DREG])
|
||||
return &nft_exthdr_ipv6_ops;
|
||||
|
|
|
@ -57,12 +57,6 @@ static const struct rhashtable_params zones_params = {
|
|||
.automatic_shrinking = true,
|
||||
};
|
||||
|
||||
static struct nf_ct_ext_type act_ct_extend __read_mostly = {
|
||||
.len = sizeof(struct nf_conn_act_ct_ext),
|
||||
.align = __alignof__(struct nf_conn_act_ct_ext),
|
||||
.id = NF_CT_EXT_ACT_CT,
|
||||
};
|
||||
|
||||
static struct flow_action_entry *
|
||||
tcf_ct_flow_table_flow_action_get_next(struct flow_action *flow_action)
|
||||
{
|
||||
|
@ -1608,16 +1602,10 @@ static int __init ct_init_module(void)
|
|||
if (err)
|
||||
goto err_register;
|
||||
|
||||
err = nf_ct_extend_register(&act_ct_extend);
|
||||
if (err)
|
||||
goto err_register_extend;
|
||||
|
||||
static_branch_inc(&tcf_frag_xmit_count);
|
||||
|
||||
return 0;
|
||||
|
||||
err_register_extend:
|
||||
tcf_unregister_action(&act_ct_ops, &ct_net_ops);
|
||||
err_register:
|
||||
tcf_ct_flow_tables_uninit();
|
||||
err_tbl_init:
|
||||
|
@ -1628,7 +1616,6 @@ err_tbl_init:
|
|||
static void __exit ct_cleanup_module(void)
|
||||
{
|
||||
static_branch_dec(&tcf_frag_xmit_count);
|
||||
nf_ct_extend_unregister(&act_ct_extend);
|
||||
tcf_unregister_action(&act_ct_ops, &ct_net_ops);
|
||||
tcf_ct_flow_tables_uninit();
|
||||
destroy_workqueue(act_ct_wq);
|
||||
|
|
Loading…
Reference in New Issue