netfilter: conntrack: pass nf_hook_state to packet and error handlers

nf_hook_state contains all the hook meta-information: netns, protocol family,
hook location, and so on.

Instead of only passing selected information, pass a pointer to entire
structure.

This will allow to merge the error and the packet handlers and remove
the ->new() function in followup patches.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
Florian Westphal 2018-09-12 15:19:07 +02:00 committed by Pablo Neira Ayuso
parent c8204cab9c
commit 93e66024b0
13 changed files with 142 additions and 115 deletions

View File

@ -20,8 +20,7 @@
/* This header is used to share core functionality between the /* This header is used to share core functionality between the
standalone connection tracking module, and the compatibility layer's use standalone connection tracking module, and the compatibility layer's use
of connection tracking. */ of connection tracking. */
unsigned int nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, unsigned int nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state);
struct sk_buff *skb);
int nf_conntrack_init_net(struct net *net); int nf_conntrack_init_net(struct net *net);
void nf_conntrack_cleanup_net(struct net *net); void nf_conntrack_cleanup_net(struct net *net);

View File

@ -45,7 +45,8 @@ struct nf_conntrack_l4proto {
int (*packet)(struct nf_conn *ct, int (*packet)(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo); enum ip_conntrack_info ctinfo,
const struct nf_hook_state *state);
/* Called when a new connection for this protocol found; /* Called when a new connection for this protocol found;
* returns TRUE if it's OK. If so, packet() called next. */ * returns TRUE if it's OK. If so, packet() called next. */
@ -55,9 +56,9 @@ struct nf_conntrack_l4proto {
/* Called when a conntrack entry is destroyed */ /* Called when a conntrack entry is destroyed */
void (*destroy)(struct nf_conn *ct); void (*destroy)(struct nf_conn *ct);
int (*error)(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, int (*error)(struct nf_conn *tmpl, struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
u_int8_t pf, unsigned int hooknum); const struct nf_hook_state *state);
/* called by gc worker if table is full */ /* called by gc worker if table is full */
bool (*can_early_drop)(const struct nf_conn *ct); bool (*can_early_drop)(const struct nf_conn *ct);

View File

@ -1436,12 +1436,12 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
/* On success, returns 0, sets skb->_nfct | ctinfo */ /* On success, returns 0, sets skb->_nfct | ctinfo */
static int static int
resolve_normal_ct(struct net *net, struct nf_conn *tmpl, resolve_normal_ct(struct nf_conn *tmpl,
struct sk_buff *skb, struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
u_int16_t l3num,
u_int8_t protonum, u_int8_t protonum,
const struct nf_conntrack_l4proto *l4proto) const struct nf_conntrack_l4proto *l4proto,
const struct nf_hook_state *state)
{ {
const struct nf_conntrack_zone *zone; const struct nf_conntrack_zone *zone;
struct nf_conntrack_tuple tuple; struct nf_conntrack_tuple tuple;
@ -1452,17 +1452,18 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
u32 hash; u32 hash;
if (!nf_ct_get_tuple(skb, skb_network_offset(skb), if (!nf_ct_get_tuple(skb, skb_network_offset(skb),
dataoff, l3num, protonum, net, &tuple, l4proto)) { dataoff, state->pf, protonum, state->net,
&tuple, l4proto)) {
pr_debug("Can't get tuple\n"); pr_debug("Can't get tuple\n");
return 0; return 0;
} }
/* look for tuple match */ /* look for tuple match */
zone = nf_ct_zone_tmpl(tmpl, skb, &tmp); zone = nf_ct_zone_tmpl(tmpl, skb, &tmp);
hash = hash_conntrack_raw(&tuple, net); hash = hash_conntrack_raw(&tuple, state->net);
h = __nf_conntrack_find_get(net, zone, &tuple, hash); h = __nf_conntrack_find_get(state->net, zone, &tuple, hash);
if (!h) { if (!h) {
h = init_conntrack(net, tmpl, &tuple, l4proto, h = init_conntrack(state->net, tmpl, &tuple, l4proto,
skb, dataoff, hash); skb, dataoff, hash);
if (!h) if (!h)
return 0; return 0;
@ -1492,12 +1493,11 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
} }
unsigned int unsigned int
nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state)
struct sk_buff *skb)
{ {
const struct nf_conntrack_l4proto *l4proto; const struct nf_conntrack_l4proto *l4proto;
struct nf_conn *ct, *tmpl;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
struct nf_conn *ct, *tmpl;
u_int8_t protonum; u_int8_t protonum;
int dataoff, ret; int dataoff, ret;
@ -1506,32 +1506,32 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
/* Previously seen (loopback or untracked)? Ignore. */ /* Previously seen (loopback or untracked)? Ignore. */
if ((tmpl && !nf_ct_is_template(tmpl)) || if ((tmpl && !nf_ct_is_template(tmpl)) ||
ctinfo == IP_CT_UNTRACKED) { ctinfo == IP_CT_UNTRACKED) {
NF_CT_STAT_INC_ATOMIC(net, ignore); NF_CT_STAT_INC_ATOMIC(state->net, ignore);
return NF_ACCEPT; return NF_ACCEPT;
} }
skb->_nfct = 0; skb->_nfct = 0;
} }
/* rcu_read_lock()ed by nf_hook_thresh */ /* rcu_read_lock()ed by nf_hook_thresh */
dataoff = get_l4proto(skb, skb_network_offset(skb), pf, &protonum); dataoff = get_l4proto(skb, skb_network_offset(skb), state->pf, &protonum);
if (dataoff <= 0) { if (dataoff <= 0) {
pr_debug("not prepared to track yet or error occurred\n"); pr_debug("not prepared to track yet or error occurred\n");
NF_CT_STAT_INC_ATOMIC(net, error); NF_CT_STAT_INC_ATOMIC(state->net, error);
NF_CT_STAT_INC_ATOMIC(net, invalid); NF_CT_STAT_INC_ATOMIC(state->net, invalid);
ret = NF_ACCEPT; ret = NF_ACCEPT;
goto out; goto out;
} }
l4proto = __nf_ct_l4proto_find(pf, protonum); l4proto = __nf_ct_l4proto_find(state->pf, protonum);
/* It may be an special packet, error, unclean... /* It may be an special packet, error, unclean...
* inverse of the return code tells to the netfilter * inverse of the return code tells to the netfilter
* core what to do with the packet. */ * core what to do with the packet. */
if (l4proto->error != NULL) { if (l4proto->error != NULL) {
ret = l4proto->error(net, tmpl, skb, dataoff, pf, hooknum); ret = l4proto->error(tmpl, skb, dataoff, state);
if (ret <= 0) { if (ret <= 0) {
NF_CT_STAT_INC_ATOMIC(net, error); NF_CT_STAT_INC_ATOMIC(state->net, error);
NF_CT_STAT_INC_ATOMIC(net, invalid); NF_CT_STAT_INC_ATOMIC(state->net, invalid);
ret = -ret; ret = -ret;
goto out; goto out;
} }
@ -1540,10 +1540,11 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
goto out; goto out;
} }
repeat: repeat:
ret = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum, l4proto); ret = resolve_normal_ct(tmpl, skb, dataoff,
protonum, l4proto, state);
if (ret < 0) { if (ret < 0) {
/* Too stressed to deal. */ /* Too stressed to deal. */
NF_CT_STAT_INC_ATOMIC(net, drop); NF_CT_STAT_INC_ATOMIC(state->net, drop);
ret = NF_DROP; ret = NF_DROP;
goto out; goto out;
} }
@ -1551,21 +1552,21 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
ct = nf_ct_get(skb, &ctinfo); ct = nf_ct_get(skb, &ctinfo);
if (!ct) { if (!ct) {
/* Not valid part of a connection */ /* Not valid part of a connection */
NF_CT_STAT_INC_ATOMIC(net, invalid); NF_CT_STAT_INC_ATOMIC(state->net, invalid);
ret = NF_ACCEPT; ret = NF_ACCEPT;
goto out; goto out;
} }
ret = l4proto->packet(ct, skb, dataoff, ctinfo); ret = l4proto->packet(ct, skb, dataoff, ctinfo, state);
if (ret <= 0) { if (ret <= 0) {
/* Invalid: inverse of the return code tells /* Invalid: inverse of the return code tells
* the netfilter core what to do */ * the netfilter core what to do */
pr_debug("nf_conntrack_in: Can't track with proto module\n"); pr_debug("nf_conntrack_in: Can't track with proto module\n");
nf_conntrack_put(&ct->ct_general); nf_conntrack_put(&ct->ct_general);
skb->_nfct = 0; skb->_nfct = 0;
NF_CT_STAT_INC_ATOMIC(net, invalid); NF_CT_STAT_INC_ATOMIC(state->net, invalid);
if (ret == -NF_DROP) if (ret == -NF_DROP)
NF_CT_STAT_INC_ATOMIC(net, drop); NF_CT_STAT_INC_ATOMIC(state->net, drop);
/* Special case: TCP tracker reports an attempt to reopen a /* Special case: TCP tracker reports an attempt to reopen a
* closed/aborted connection. We have to go back and create a * closed/aborted connection. We have to go back and create a
* fresh conntrack. * fresh conntrack.

View File

@ -455,7 +455,7 @@ static unsigned int ipv4_conntrack_in(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return nf_conntrack_in(state->net, PF_INET, state->hook, skb); return nf_conntrack_in(skb, state);
} }
static unsigned int ipv4_conntrack_local(void *priv, static unsigned int ipv4_conntrack_local(void *priv,
@ -477,7 +477,7 @@ static unsigned int ipv4_conntrack_local(void *priv,
return NF_ACCEPT; return NF_ACCEPT;
} }
return nf_conntrack_in(state->net, PF_INET, state->hook, skb); return nf_conntrack_in(skb, state);
} }
/* Connection tracking may drop packets, but never alters them, so /* Connection tracking may drop packets, but never alters them, so
@ -690,14 +690,14 @@ static unsigned int ipv6_conntrack_in(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return nf_conntrack_in(state->net, PF_INET6, state->hook, skb); return nf_conntrack_in(skb, state);
} }
static unsigned int ipv6_conntrack_local(void *priv, static unsigned int ipv6_conntrack_local(void *priv,
struct sk_buff *skb, struct sk_buff *skb,
const struct nf_hook_state *state) const struct nf_hook_state *state)
{ {
return nf_conntrack_in(state->net, PF_INET6, state->hook, skb); return nf_conntrack_in(skb, state);
} }
static unsigned int ipv6_helper(void *priv, static unsigned int ipv6_helper(void *priv,

View File

@ -439,7 +439,8 @@ static u64 dccp_ack_seq(const struct dccp_hdr *dh)
} }
static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff, enum ip_conntrack_info ctinfo) unsigned int dataoff, enum ip_conntrack_info ctinfo,
const struct nf_hook_state *state)
{ {
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
struct dccp_hdr _dh, *dh; struct dccp_hdr _dh, *dh;
@ -527,9 +528,9 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
return NF_ACCEPT; return NF_ACCEPT;
} }
static int dccp_error(struct net *net, struct nf_conn *tmpl, static int dccp_error(struct nf_conn *tmpl,
struct sk_buff *skb, unsigned int dataoff, struct sk_buff *skb, unsigned int dataoff,
u_int8_t pf, unsigned int hooknum) const struct nf_hook_state *state)
{ {
struct dccp_hdr _dh, *dh; struct dccp_hdr _dh, *dh;
unsigned int dccp_len = skb->len - dataoff; unsigned int dccp_len = skb->len - dataoff;
@ -557,9 +558,10 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl,
} }
} }
if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && if (state->hook == NF_INET_PRE_ROUTING &&
nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_DCCP, state->net->ct.sysctl_checksum &&
pf)) { nf_checksum_partial(skb, state->hook, dataoff, cscov,
IPPROTO_DCCP, state->pf)) {
msg = "nf_ct_dccp: bad checksum "; msg = "nf_ct_dccp: bad checksum ";
goto out_invalid; goto out_invalid;
} }
@ -572,7 +574,8 @@ static int dccp_error(struct net *net, struct nf_conn *tmpl,
return NF_ACCEPT; return NF_ACCEPT;
out_invalid: out_invalid:
nf_l4proto_log_invalid(skb, net, pf, IPPROTO_DCCP, "%s", msg); nf_l4proto_log_invalid(skb, state->net, state->pf,
IPPROTO_DCCP, "%s", msg);
return -NF_ACCEPT; return -NF_ACCEPT;
} }

View File

@ -46,7 +46,8 @@ static bool generic_pkt_to_tuple(const struct sk_buff *skb,
static int generic_packet(struct nf_conn *ct, static int generic_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo) enum ip_conntrack_info ctinfo,
const struct nf_hook_state *state)
{ {
const unsigned int *timeout = nf_ct_timeout_lookup(ct); const unsigned int *timeout = nf_ct_timeout_lookup(ct);

View File

@ -235,7 +235,8 @@ static unsigned int *gre_get_timeouts(struct net *net)
static int gre_packet(struct nf_conn *ct, static int gre_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo) enum ip_conntrack_info ctinfo,
const struct nf_hook_state *state)
{ {
/* If we've seen traffic both ways, this is a GRE connection. /* If we've seen traffic both ways, this is a GRE connection.
* Extend timeout. */ * Extend timeout. */

View File

@ -81,7 +81,8 @@ static unsigned int *icmp_get_timeouts(struct net *net)
static int icmp_packet(struct nf_conn *ct, static int icmp_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo) enum ip_conntrack_info ctinfo,
const struct nf_hook_state *state)
{ {
/* Do not immediately delete the connection after the first /* Do not immediately delete the connection after the first
successful reply to avoid excessive conntrackd traffic successful reply to avoid excessive conntrackd traffic
@ -120,8 +121,8 @@ static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb,
/* Returns conntrack if it dealt with ICMP, and filled in skb fields */ /* Returns conntrack if it dealt with ICMP, and filled in skb fields */
static int static int
icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, icmp_error_message(struct nf_conn *tmpl, struct sk_buff *skb,
unsigned int hooknum) const struct nf_hook_state *state)
{ {
struct nf_conntrack_tuple innertuple, origtuple; struct nf_conntrack_tuple innertuple, origtuple;
const struct nf_conntrack_l4proto *innerproto; const struct nf_conntrack_l4proto *innerproto;
@ -137,7 +138,7 @@ icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
if (!nf_ct_get_tuplepr(skb, if (!nf_ct_get_tuplepr(skb,
skb_network_offset(skb) + ip_hdrlen(skb) skb_network_offset(skb) + ip_hdrlen(skb)
+ sizeof(struct icmphdr), + sizeof(struct icmphdr),
PF_INET, net, &origtuple)) { PF_INET, state->net, &origtuple)) {
pr_debug("icmp_error_message: failed to get tuple\n"); pr_debug("icmp_error_message: failed to get tuple\n");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
@ -154,7 +155,7 @@ icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
ctinfo = IP_CT_RELATED; ctinfo = IP_CT_RELATED;
h = nf_conntrack_find_get(net, zone, &innertuple); h = nf_conntrack_find_get(state->net, zone, &innertuple);
if (!h) { if (!h) {
pr_debug("icmp_error_message: no match\n"); pr_debug("icmp_error_message: no match\n");
return -NF_ACCEPT; return -NF_ACCEPT;
@ -168,17 +169,19 @@ icmp_error_message(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
return NF_ACCEPT; return NF_ACCEPT;
} }
static void icmp_error_log(const struct sk_buff *skb, struct net *net, static void icmp_error_log(const struct sk_buff *skb,
u8 pf, const char *msg) const struct nf_hook_state *state,
const char *msg)
{ {
nf_l4proto_log_invalid(skb, net, pf, IPPROTO_ICMP, "%s", msg); nf_l4proto_log_invalid(skb, state->net, state->pf,
IPPROTO_ICMP, "%s", msg);
} }
/* Small and modified version of icmp_rcv */ /* Small and modified version of icmp_rcv */
static int static int
icmp_error(struct net *net, struct nf_conn *tmpl, icmp_error(struct nf_conn *tmpl,
struct sk_buff *skb, unsigned int dataoff, struct sk_buff *skb, unsigned int dataoff,
u8 pf, unsigned int hooknum) const struct nf_hook_state *state)
{ {
const struct icmphdr *icmph; const struct icmphdr *icmph;
struct icmphdr _ih; struct icmphdr _ih;
@ -186,14 +189,15 @@ icmp_error(struct net *net, struct nf_conn *tmpl,
/* Not enough header? */ /* Not enough header? */
icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih); icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih);
if (icmph == NULL) { if (icmph == NULL) {
icmp_error_log(skb, net, pf, "short packet"); icmp_error_log(skb, state, "short packet");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
/* See ip_conntrack_proto_tcp.c */ /* See ip_conntrack_proto_tcp.c */
if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && if (state->net->ct.sysctl_checksum &&
nf_ip_checksum(skb, hooknum, dataoff, 0)) { state->hook == NF_INET_PRE_ROUTING &&
icmp_error_log(skb, net, pf, "bad hw icmp checksum"); nf_ip_checksum(skb, state->hook, dataoff, 0)) {
icmp_error_log(skb, state, "bad hw icmp checksum");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
@ -204,7 +208,7 @@ icmp_error(struct net *net, struct nf_conn *tmpl,
* discarded. * discarded.
*/ */
if (icmph->type > NR_ICMP_TYPES) { if (icmph->type > NR_ICMP_TYPES) {
icmp_error_log(skb, net, pf, "invalid icmp type"); icmp_error_log(skb, state, "invalid icmp type");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
@ -216,7 +220,7 @@ icmp_error(struct net *net, struct nf_conn *tmpl,
icmph->type != ICMP_REDIRECT) icmph->type != ICMP_REDIRECT)
return NF_ACCEPT; return NF_ACCEPT;
return icmp_error_message(net, tmpl, skb, hooknum); return icmp_error_message(tmpl, skb, state);
} }
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)

View File

@ -94,7 +94,8 @@ static unsigned int *icmpv6_get_timeouts(struct net *net)
static int icmpv6_packet(struct nf_conn *ct, static int icmpv6_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo) enum ip_conntrack_info ctinfo,
const struct nf_hook_state *state)
{ {
unsigned int *timeout = nf_ct_timeout_lookup(ct); unsigned int *timeout = nf_ct_timeout_lookup(ct);
@ -179,16 +180,19 @@ icmpv6_error_message(struct net *net, struct nf_conn *tmpl,
return NF_ACCEPT; return NF_ACCEPT;
} }
static void icmpv6_error_log(const struct sk_buff *skb, struct net *net, static void icmpv6_error_log(const struct sk_buff *skb,
u8 pf, const char *msg) const struct nf_hook_state *state,
const char *msg)
{ {
nf_l4proto_log_invalid(skb, net, pf, IPPROTO_ICMPV6, "%s", msg); nf_l4proto_log_invalid(skb, state->net, state->pf,
IPPROTO_ICMPV6, "%s", msg);
} }
static int static int
icmpv6_error(struct net *net, struct nf_conn *tmpl, icmpv6_error(struct nf_conn *tmpl,
struct sk_buff *skb, unsigned int dataoff, struct sk_buff *skb,
u8 pf, unsigned int hooknum) unsigned int dataoff,
const struct nf_hook_state *state)
{ {
const struct icmp6hdr *icmp6h; const struct icmp6hdr *icmp6h;
struct icmp6hdr _ih; struct icmp6hdr _ih;
@ -196,13 +200,14 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl,
icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih); icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih);
if (icmp6h == NULL) { if (icmp6h == NULL) {
icmpv6_error_log(skb, net, pf, "short packet"); icmpv6_error_log(skb, state, "short packet");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && if (state->hook == NF_INET_PRE_ROUTING &&
nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) { state->net->ct.sysctl_checksum &&
icmpv6_error_log(skb, net, pf, "ICMPv6 checksum failed"); nf_ip6_checksum(skb, state->hook, dataoff, IPPROTO_ICMPV6)) {
icmpv6_error_log(skb, state, "ICMPv6 checksum failed");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
@ -217,7 +222,7 @@ icmpv6_error(struct net *net, struct nf_conn *tmpl,
if (icmp6h->icmp6_type >= 128) if (icmp6h->icmp6_type >= 128)
return NF_ACCEPT; return NF_ACCEPT;
return icmpv6_error_message(net, tmpl, skb, dataoff); return icmpv6_error_message(state->net, tmpl, skb, dataoff);
} }
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)

View File

@ -277,7 +277,8 @@ static int sctp_new_state(enum ip_conntrack_dir dir,
static int sctp_packet(struct nf_conn *ct, static int sctp_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo) enum ip_conntrack_info ctinfo,
const struct nf_hook_state *state)
{ {
enum sctp_conntrack new_state, old_state; enum sctp_conntrack new_state, old_state;
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
@ -471,9 +472,9 @@ static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb,
return true; return true;
} }
static int sctp_error(struct net *net, struct nf_conn *tpl, struct sk_buff *skb, static int sctp_error(struct nf_conn *tpl, struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
u8 pf, unsigned int hooknum) const struct nf_hook_state *state)
{ {
const struct sctphdr *sh; const struct sctphdr *sh;
const char *logmsg; const char *logmsg;
@ -482,7 +483,8 @@ static int sctp_error(struct net *net, struct nf_conn *tpl, struct sk_buff *skb,
logmsg = "nf_ct_sctp: short packet "; logmsg = "nf_ct_sctp: short packet ";
goto out_invalid; goto out_invalid;
} }
if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && if (state->hook == NF_INET_PRE_ROUTING &&
state->net->ct.sysctl_checksum &&
skb->ip_summed == CHECKSUM_NONE) { skb->ip_summed == CHECKSUM_NONE) {
if (!skb_make_writable(skb, dataoff + sizeof(struct sctphdr))) { if (!skb_make_writable(skb, dataoff + sizeof(struct sctphdr))) {
logmsg = "nf_ct_sctp: failed to read header "; logmsg = "nf_ct_sctp: failed to read header ";
@ -497,7 +499,7 @@ static int sctp_error(struct net *net, struct nf_conn *tpl, struct sk_buff *skb,
} }
return NF_ACCEPT; return NF_ACCEPT;
out_invalid: out_invalid:
nf_l4proto_log_invalid(skb, net, pf, IPPROTO_SCTP, "%s", logmsg); nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_SCTP, "%s", logmsg);
return -NF_ACCEPT; return -NF_ACCEPT;
} }

View File

@ -717,18 +717,18 @@ static const u8 tcp_valid_flags[(TCPHDR_FIN|TCPHDR_SYN|TCPHDR_RST|TCPHDR_ACK|
[TCPHDR_ACK|TCPHDR_URG] = 1, [TCPHDR_ACK|TCPHDR_URG] = 1,
}; };
static void tcp_error_log(const struct sk_buff *skb, struct net *net, static void tcp_error_log(const struct sk_buff *skb,
u8 pf, const char *msg) const struct nf_hook_state *state,
const char *msg)
{ {
nf_l4proto_log_invalid(skb, net, pf, IPPROTO_TCP, "%s", msg); nf_l4proto_log_invalid(skb, state->net, state->pf, IPPROTO_TCP, "%s", msg);
} }
/* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */ /* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */
static int tcp_error(struct net *net, struct nf_conn *tmpl, static int tcp_error(struct nf_conn *tmpl,
struct sk_buff *skb, struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
u_int8_t pf, const struct nf_hook_state *state)
unsigned int hooknum)
{ {
const struct tcphdr *th; const struct tcphdr *th;
struct tcphdr _tcph; struct tcphdr _tcph;
@ -738,13 +738,13 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
/* Smaller that minimal TCP header? */ /* Smaller that minimal TCP header? */
th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph); th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
if (th == NULL) { if (th == NULL) {
tcp_error_log(skb, net, pf, "short packet"); tcp_error_log(skb, state, "short packet");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
/* Not whole TCP header or malformed packet */ /* Not whole TCP header or malformed packet */
if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) { if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) {
tcp_error_log(skb, net, pf, "truncated packet"); tcp_error_log(skb, state, "truncated packet");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
@ -753,16 +753,17 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
* because the checksum is assumed to be correct. * because the checksum is assumed to be correct.
*/ */
/* FIXME: Source route IP option packets --RR */ /* FIXME: Source route IP option packets --RR */
if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && if (state->net->ct.sysctl_checksum &&
nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) { state->hook == NF_INET_PRE_ROUTING &&
tcp_error_log(skb, net, pf, "bad checksum"); nf_checksum(skb, state->hook, dataoff, IPPROTO_TCP, state->pf)) {
tcp_error_log(skb, state, "bad checksum");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
/* Check TCP flags. */ /* Check TCP flags. */
tcpflags = (tcp_flag_byte(th) & ~(TCPHDR_ECE|TCPHDR_CWR|TCPHDR_PSH)); tcpflags = (tcp_flag_byte(th) & ~(TCPHDR_ECE|TCPHDR_CWR|TCPHDR_PSH));
if (!tcp_valid_flags[tcpflags]) { if (!tcp_valid_flags[tcpflags]) {
tcp_error_log(skb, net, pf, "invalid tcp flag combination"); tcp_error_log(skb, state, "invalid tcp flag combination");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
@ -773,7 +774,8 @@ static int tcp_error(struct net *net, struct nf_conn *tmpl,
static int tcp_packet(struct nf_conn *ct, static int tcp_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo) enum ip_conntrack_info ctinfo,
const struct nf_hook_state *state)
{ {
struct net *net = nf_ct_net(ct); struct net *net = nf_ct_net(ct);
struct nf_tcp_net *tn = tcp_pernet(net); struct nf_tcp_net *tn = tcp_pernet(net);

View File

@ -46,7 +46,8 @@ static unsigned int *udp_get_timeouts(struct net *net)
static int udp_packet(struct nf_conn *ct, static int udp_packet(struct nf_conn *ct,
const struct sk_buff *skb, const struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
enum ip_conntrack_info ctinfo) enum ip_conntrack_info ctinfo,
const struct nf_hook_state *state)
{ {
unsigned int *timeouts; unsigned int *timeouts;
@ -77,16 +78,17 @@ static bool udp_new(struct nf_conn *ct, const struct sk_buff *skb,
} }
#ifdef CONFIG_NF_CT_PROTO_UDPLITE #ifdef CONFIG_NF_CT_PROTO_UDPLITE
static void udplite_error_log(const struct sk_buff *skb, struct net *net, static void udplite_error_log(const struct sk_buff *skb,
u8 pf, const char *msg) const struct nf_hook_state *state,
const char *msg)
{ {
nf_l4proto_log_invalid(skb, net, pf, IPPROTO_UDPLITE, "%s", msg); nf_l4proto_log_invalid(skb, state->net, state->pf,
IPPROTO_UDPLITE, "%s", msg);
} }
static int udplite_error(struct net *net, struct nf_conn *tmpl, static int udplite_error(struct nf_conn *tmpl, struct sk_buff *skb,
struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
u8 pf, unsigned int hooknum) const struct nf_hook_state *state)
{ {
unsigned int udplen = skb->len - dataoff; unsigned int udplen = skb->len - dataoff;
const struct udphdr *hdr; const struct udphdr *hdr;
@ -96,7 +98,7 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl,
/* Header is too small? */ /* Header is too small? */
hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
if (!hdr) { if (!hdr) {
udplite_error_log(skb, net, pf, "short packet"); udplite_error_log(skb, state, "short packet");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
@ -104,21 +106,22 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl,
if (cscov == 0) { if (cscov == 0) {
cscov = udplen; cscov = udplen;
} else if (cscov < sizeof(*hdr) || cscov > udplen) { } else if (cscov < sizeof(*hdr) || cscov > udplen) {
udplite_error_log(skb, net, pf, "invalid checksum coverage"); udplite_error_log(skb, state, "invalid checksum coverage");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
/* UDPLITE mandates checksums */ /* UDPLITE mandates checksums */
if (!hdr->check) { if (!hdr->check) {
udplite_error_log(skb, net, pf, "checksum missing"); udplite_error_log(skb, state, "checksum missing");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
/* Checksum invalid? Ignore. */ /* Checksum invalid? Ignore. */
if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && if (state->hook == NF_INET_PRE_ROUTING &&
nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_UDP, state->net->ct.sysctl_checksum &&
pf)) { nf_checksum_partial(skb, state->hook, dataoff, cscov, IPPROTO_UDP,
udplite_error_log(skb, net, pf, "bad checksum"); state->pf)) {
udplite_error_log(skb, state, "bad checksum");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
@ -126,16 +129,17 @@ static int udplite_error(struct net *net, struct nf_conn *tmpl,
} }
#endif #endif
static void udp_error_log(const struct sk_buff *skb, struct net *net, static void udp_error_log(const struct sk_buff *skb,
u8 pf, const char *msg) const struct nf_hook_state *state,
const char *msg)
{ {
nf_l4proto_log_invalid(skb, net, pf, IPPROTO_UDP, "%s", msg); nf_l4proto_log_invalid(skb, state->net, state->pf,
IPPROTO_UDP, "%s", msg);
} }
static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb, static int udp_error(struct nf_conn *tmpl, struct sk_buff *skb,
unsigned int dataoff, unsigned int dataoff,
u_int8_t pf, const struct nf_hook_state *state)
unsigned int hooknum)
{ {
unsigned int udplen = skb->len - dataoff; unsigned int udplen = skb->len - dataoff;
const struct udphdr *hdr; const struct udphdr *hdr;
@ -144,13 +148,13 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
/* Header is too small? */ /* Header is too small? */
hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr); hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
if (hdr == NULL) { if (hdr == NULL) {
udp_error_log(skb, net, pf, "short packet"); udp_error_log(skb, state, "short packet");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
/* Truncated/malformed packets */ /* Truncated/malformed packets */
if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) { if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
udp_error_log(skb, net, pf, "truncated/malformed packet"); udp_error_log(skb, state, "truncated/malformed packet");
return -NF_ACCEPT; return -NF_ACCEPT;
} }
@ -162,9 +166,9 @@ static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
* We skip checking packets on the outgoing path * We skip checking packets on the outgoing path
* because the checksum is assumed to be correct. * because the checksum is assumed to be correct.
* FIXME: Source route IP option packets --RR */ * FIXME: Source route IP option packets --RR */
if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING && if (state->net->ct.sysctl_checksum && state->hook == NF_INET_PRE_ROUTING &&
nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) { nf_checksum(skb, state->hook, dataoff, IPPROTO_UDP, state->pf)) {
udp_error_log(skb, net, pf, "bad checksum"); udp_error_log(skb, state, "bad checksum");
return -NF_ACCEPT; return -NF_ACCEPT;
} }

View File

@ -933,6 +933,11 @@ static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
struct nf_conn *ct; struct nf_conn *ct;
if (!cached) { if (!cached) {
struct nf_hook_state state = {
.hook = NF_INET_PRE_ROUTING,
.pf = info->family,
.net = net,
};
struct nf_conn *tmpl = info->ct; struct nf_conn *tmpl = info->ct;
int err; int err;
@ -944,8 +949,7 @@ static int __ovs_ct_lookup(struct net *net, struct sw_flow_key *key,
nf_ct_set(skb, tmpl, IP_CT_NEW); nf_ct_set(skb, tmpl, IP_CT_NEW);
} }
err = nf_conntrack_in(net, info->family, err = nf_conntrack_in(skb, &state);
NF_INET_PRE_ROUTING, skb);
if (err != NF_ACCEPT) if (err != NF_ACCEPT)
return -ENOENT; return -ENOENT;