mirror of
https://github.com/torvalds/linux.git
synced 2024-11-27 14:41:39 +00:00
netfilter: ctnetlink: add timeout and protoinfo to destroy events
DESTROY events do not include the remaining timeout. Add the timeout if the entry was removed explicitly. This can happen when a conntrack gets deleted prematurely, e.g. due to a tcp reset, module removal, netdev notifier (nat/masquerade device went down), ctnetlink and so on. Add the protocol state too for the destroy message to check for abnormal state on connection termination. Joint work with Pablo. Signed-off-by: Florian Westphal <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
This commit is contained in:
parent
04295878be
commit
86d21fc747
@ -32,7 +32,7 @@ struct nf_conntrack_l4proto {
|
||||
|
||||
/* convert protoinfo to nfnetink attributes */
|
||||
int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla,
|
||||
struct nf_conn *ct);
|
||||
struct nf_conn *ct, bool destroy);
|
||||
|
||||
/* convert nfnetlink attributes to protoinfo */
|
||||
int (*from_nlattr)(struct nlattr *tb[], struct nf_conn *ct);
|
||||
|
@ -167,10 +167,14 @@ nla_put_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct)
|
||||
static int ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct,
|
||||
bool skip_zero)
|
||||
{
|
||||
long timeout = nf_ct_expires(ct) / HZ;
|
||||
|
||||
if (skip_zero && timeout == 0)
|
||||
return 0;
|
||||
|
||||
if (nla_put_be32(skb, CTA_TIMEOUT, htonl(timeout)))
|
||||
goto nla_put_failure;
|
||||
return 0;
|
||||
@ -179,7 +183,8 @@ nla_put_failure:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ctnetlink_dump_protoinfo(struct sk_buff *skb, struct nf_conn *ct)
|
||||
static int ctnetlink_dump_protoinfo(struct sk_buff *skb, struct nf_conn *ct,
|
||||
bool destroy)
|
||||
{
|
||||
const struct nf_conntrack_l4proto *l4proto;
|
||||
struct nlattr *nest_proto;
|
||||
@ -193,7 +198,7 @@ static int ctnetlink_dump_protoinfo(struct sk_buff *skb, struct nf_conn *ct)
|
||||
if (!nest_proto)
|
||||
goto nla_put_failure;
|
||||
|
||||
ret = l4proto->to_nlattr(skb, nest_proto, ct);
|
||||
ret = l4proto->to_nlattr(skb, nest_proto, ct, destroy);
|
||||
|
||||
nla_nest_end(skb, nest_proto);
|
||||
|
||||
@ -537,8 +542,8 @@ static int ctnetlink_dump_info(struct sk_buff *skb, struct nf_conn *ct)
|
||||
return -1;
|
||||
|
||||
if (!test_bit(IPS_OFFLOAD_BIT, &ct->status) &&
|
||||
(ctnetlink_dump_timeout(skb, ct) < 0 ||
|
||||
ctnetlink_dump_protoinfo(skb, ct) < 0))
|
||||
(ctnetlink_dump_timeout(skb, ct, false) < 0 ||
|
||||
ctnetlink_dump_protoinfo(skb, ct, false) < 0))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
@ -780,15 +785,19 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (events & (1 << IPCT_DESTROY)) {
|
||||
if (ctnetlink_dump_acct(skb, ct, type) < 0 ||
|
||||
ctnetlink_dump_timestamp(skb, ct) < 0)
|
||||
goto nla_put_failure;
|
||||
} else {
|
||||
if (ctnetlink_dump_timeout(skb, ct) < 0)
|
||||
if (ctnetlink_dump_timeout(skb, ct, true) < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (events & (1 << IPCT_PROTOINFO)
|
||||
&& ctnetlink_dump_protoinfo(skb, ct) < 0)
|
||||
if (ctnetlink_dump_acct(skb, ct, type) < 0 ||
|
||||
ctnetlink_dump_timestamp(skb, ct) < 0 ||
|
||||
ctnetlink_dump_protoinfo(skb, ct, true) < 0)
|
||||
goto nla_put_failure;
|
||||
} else {
|
||||
if (ctnetlink_dump_timeout(skb, ct, false) < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (events & (1 << IPCT_PROTOINFO) &&
|
||||
ctnetlink_dump_protoinfo(skb, ct, false) < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
if ((events & (1 << IPCT_HELPER) || nfct_help(ct))
|
||||
@ -2720,10 +2729,10 @@ static int __ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct)
|
||||
if (ctnetlink_dump_status(skb, ct) < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (ctnetlink_dump_timeout(skb, ct) < 0)
|
||||
if (ctnetlink_dump_timeout(skb, ct, false) < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (ctnetlink_dump_protoinfo(skb, ct) < 0)
|
||||
if (ctnetlink_dump_protoinfo(skb, ct, false) < 0)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (ctnetlink_dump_helpinfo(skb, ct) < 0)
|
||||
|
@ -589,7 +589,7 @@ static void dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
|
||||
|
||||
#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
|
||||
static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
|
||||
struct nf_conn *ct)
|
||||
struct nf_conn *ct, bool destroy)
|
||||
{
|
||||
struct nlattr *nest_parms;
|
||||
|
||||
@ -597,15 +597,22 @@ static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
|
||||
nest_parms = nla_nest_start(skb, CTA_PROTOINFO_DCCP);
|
||||
if (!nest_parms)
|
||||
goto nla_put_failure;
|
||||
if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state) ||
|
||||
nla_put_u8(skb, CTA_PROTOINFO_DCCP_ROLE,
|
||||
if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (destroy)
|
||||
goto skip_state;
|
||||
|
||||
if (nla_put_u8(skb, CTA_PROTOINFO_DCCP_ROLE,
|
||||
ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]) ||
|
||||
nla_put_be64(skb, CTA_PROTOINFO_DCCP_HANDSHAKE_SEQ,
|
||||
cpu_to_be64(ct->proto.dccp.handshake_seq),
|
||||
CTA_PROTOINFO_DCCP_PAD))
|
||||
goto nla_put_failure;
|
||||
skip_state:
|
||||
nla_nest_end(skb, nest_parms);
|
||||
spin_unlock_bh(&ct->lock);
|
||||
|
||||
return 0;
|
||||
|
||||
nla_put_failure:
|
||||
|
@ -543,7 +543,7 @@ static bool sctp_can_early_drop(const struct nf_conn *ct)
|
||||
#include <linux/netfilter/nfnetlink_conntrack.h>
|
||||
|
||||
static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
|
||||
struct nf_conn *ct)
|
||||
struct nf_conn *ct, bool destroy)
|
||||
{
|
||||
struct nlattr *nest_parms;
|
||||
|
||||
@ -552,15 +552,20 @@ static int sctp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
|
||||
if (!nest_parms)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nla_put_u8(skb, CTA_PROTOINFO_SCTP_STATE, ct->proto.sctp.state) ||
|
||||
nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
|
||||
if (nla_put_u8(skb, CTA_PROTOINFO_SCTP_STATE, ct->proto.sctp.state))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (destroy)
|
||||
goto skip_state;
|
||||
|
||||
if (nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_ORIGINAL,
|
||||
ct->proto.sctp.vtag[IP_CT_DIR_ORIGINAL]) ||
|
||||
nla_put_be32(skb, CTA_PROTOINFO_SCTP_VTAG_REPLY,
|
||||
ct->proto.sctp.vtag[IP_CT_DIR_REPLY]))
|
||||
goto nla_put_failure;
|
||||
|
||||
skip_state:
|
||||
spin_unlock_bh(&ct->lock);
|
||||
|
||||
nla_nest_end(skb, nest_parms);
|
||||
|
||||
return 0;
|
||||
|
@ -1186,7 +1186,7 @@ static bool tcp_can_early_drop(const struct nf_conn *ct)
|
||||
#include <linux/netfilter/nfnetlink_conntrack.h>
|
||||
|
||||
static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
|
||||
struct nf_conn *ct)
|
||||
struct nf_conn *ct, bool destroy)
|
||||
{
|
||||
struct nlattr *nest_parms;
|
||||
struct nf_ct_tcp_flags tmp = {};
|
||||
@ -1196,8 +1196,13 @@ static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
|
||||
if (!nest_parms)
|
||||
goto nla_put_failure;
|
||||
|
||||
if (nla_put_u8(skb, CTA_PROTOINFO_TCP_STATE, ct->proto.tcp.state) ||
|
||||
nla_put_u8(skb, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
|
||||
if (nla_put_u8(skb, CTA_PROTOINFO_TCP_STATE, ct->proto.tcp.state))
|
||||
goto nla_put_failure;
|
||||
|
||||
if (destroy)
|
||||
goto skip_state;
|
||||
|
||||
if (nla_put_u8(skb, CTA_PROTOINFO_TCP_WSCALE_ORIGINAL,
|
||||
ct->proto.tcp.seen[0].td_scale) ||
|
||||
nla_put_u8(skb, CTA_PROTOINFO_TCP_WSCALE_REPLY,
|
||||
ct->proto.tcp.seen[1].td_scale))
|
||||
@ -1212,8 +1217,8 @@ static int tcp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
|
||||
if (nla_put(skb, CTA_PROTOINFO_TCP_FLAGS_REPLY,
|
||||
sizeof(struct nf_ct_tcp_flags), &tmp))
|
||||
goto nla_put_failure;
|
||||
skip_state:
|
||||
spin_unlock_bh(&ct->lock);
|
||||
|
||||
nla_nest_end(skb, nest_parms);
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user