Skip to content

Commit

Permalink
netfilter: nf_conntrack: pass timeout array to l4->new and l4->packet
Browse files Browse the repository at this point in the history
This patch defines a new interface for l4 protocol trackers:

unsigned int *(*get_timeouts)(struct net *net);

that is used to return the array of unsigned int that contains
the timeouts that will be applied for this flow. This is passed
to the l4proto->new(...) and l4proto->packet(...) functions to
specify the timeout policy.

This interface allows per-net global timeout configuration
(although only DCCP supports this by now) and it will allow
custom custom timeout configuration by means of follow-up
patches.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
Pablo Neira Ayuso committed Mar 7, 2012
1 parent b888341 commit 2c8503f
Show file tree
Hide file tree
Showing 11 changed files with 128 additions and 52 deletions.
8 changes: 6 additions & 2 deletions include/net/netfilter/nf_conntrack_l4proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,13 @@ struct nf_conntrack_l4proto {
unsigned int dataoff,
enum ip_conntrack_info ctinfo,
u_int8_t pf,
unsigned int hooknum);
unsigned int hooknum,
unsigned int *timeouts);

/* Called when a new connection for this protocol found;
* returns TRUE if it's OK. If so, packet() called next. */
bool (*new)(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff);
unsigned int dataoff, unsigned int *timeouts);

/* Called when a conntrack entry is destroyed */
void (*destroy)(struct nf_conn *ct);
Expand All @@ -60,6 +61,9 @@ struct nf_conntrack_l4proto {
/* Print out the private part of the conntrack. */
int (*print_conntrack)(struct seq_file *s, struct nf_conn *);

/* Return the array of timeouts for this protocol. */
unsigned int *(*get_timeouts)(struct net *net);

/* convert protoinfo to nfnetink attributes */
int (*to_nlattr)(struct sk_buff *skb, struct nlattr *nla,
struct nf_conn *ct);
Expand Down
13 changes: 10 additions & 3 deletions net/ipv4/netfilter/nf_conntrack_proto_icmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,25 +75,31 @@ static int icmp_print_tuple(struct seq_file *s,
ntohs(tuple->src.u.icmp.id));
}

static unsigned int *icmp_get_timeouts(struct net *net)
{
return &nf_ct_icmp_timeout;
}

/* Returns verdict for packet, or -1 for invalid. */
static int icmp_packet(struct nf_conn *ct,
const struct sk_buff *skb,
unsigned int dataoff,
enum ip_conntrack_info ctinfo,
u_int8_t pf,
unsigned int hooknum)
unsigned int hooknum,
unsigned int *timeout)
{
/* Do not immediately delete the connection after the first
successful reply to avoid excessive conntrackd traffic
and also to handle correctly ICMP echo reply duplicates. */
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout);
nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);

return NF_ACCEPT;
}

/* Called when a new connection for this protocol found. */
static bool icmp_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff)
unsigned int dataoff, unsigned int *timeouts)
{
static const u_int8_t valid_new[] = {
[ICMP_ECHO] = 1,
Expand Down Expand Up @@ -298,6 +304,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmp __read_mostly =
.invert_tuple = icmp_invert_tuple,
.print_tuple = icmp_print_tuple,
.packet = icmp_packet,
.get_timeouts = icmp_get_timeouts,
.new = icmp_new,
.error = icmp_error,
.destroy = NULL,
Expand Down
13 changes: 10 additions & 3 deletions net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,25 +88,31 @@ static int icmpv6_print_tuple(struct seq_file *s,
ntohs(tuple->src.u.icmp.id));
}

static unsigned int *icmpv6_get_timeouts(struct net *net)
{
return &nf_ct_icmpv6_timeout;
}

/* Returns verdict for packet, or -1 for invalid. */
static int icmpv6_packet(struct nf_conn *ct,
const struct sk_buff *skb,
unsigned int dataoff,
enum ip_conntrack_info ctinfo,
u_int8_t pf,
unsigned int hooknum)
unsigned int hooknum,
unsigned int *timeout)
{
/* Do not immediately delete the connection after the first
successful reply to avoid excessive conntrackd traffic
and also to handle correctly ICMP echo reply duplicates. */
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout);
nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);

return NF_ACCEPT;
}

/* Called when a new connection for this protocol found. */
static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff)
unsigned int dataoff, unsigned int *timeouts)
{
static const u_int8_t valid_new[] = {
[ICMPV6_ECHO_REQUEST - 128] = 1,
Expand Down Expand Up @@ -293,6 +299,7 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_icmpv6 __read_mostly =
.invert_tuple = icmpv6_invert_tuple,
.print_tuple = icmpv6_print_tuple,
.packet = icmpv6_packet,
.get_timeouts = icmpv6_get_timeouts,
.new = icmpv6_new,
.error = icmpv6_error,
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
Expand Down
18 changes: 12 additions & 6 deletions net/netfilter/nf_conntrack_core.c
Original file line number Diff line number Diff line change
Expand Up @@ -763,7 +763,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
struct nf_conntrack_l3proto *l3proto,
struct nf_conntrack_l4proto *l4proto,
struct sk_buff *skb,
unsigned int dataoff, u32 hash)
unsigned int dataoff, u32 hash,
unsigned int *timeouts)
{
struct nf_conn *ct;
struct nf_conn_help *help;
Expand All @@ -782,7 +783,7 @@ init_conntrack(struct net *net, struct nf_conn *tmpl,
if (IS_ERR(ct))
return (struct nf_conntrack_tuple_hash *)ct;

if (!l4proto->new(ct, skb, dataoff)) {
if (!l4proto->new(ct, skb, dataoff, timeouts)) {
nf_conntrack_free(ct);
pr_debug("init conntrack: can't track with proto module\n");
return NULL;
Expand Down Expand Up @@ -848,7 +849,8 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
struct nf_conntrack_l3proto *l3proto,
struct nf_conntrack_l4proto *l4proto,
int *set_reply,
enum ip_conntrack_info *ctinfo)
enum ip_conntrack_info *ctinfo,
unsigned int *timeouts)
{
struct nf_conntrack_tuple tuple;
struct nf_conntrack_tuple_hash *h;
Expand All @@ -868,7 +870,7 @@ resolve_normal_ct(struct net *net, struct nf_conn *tmpl,
h = __nf_conntrack_find_get(net, zone, &tuple, hash);
if (!h) {
h = init_conntrack(net, tmpl, &tuple, l3proto, l4proto,
skb, dataoff, hash);
skb, dataoff, hash, timeouts);
if (!h)
return NULL;
if (IS_ERR(h))
Expand Down Expand Up @@ -909,6 +911,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
enum ip_conntrack_info ctinfo;
struct nf_conntrack_l3proto *l3proto;
struct nf_conntrack_l4proto *l4proto;
unsigned int *timeouts;
unsigned int dataoff;
u_int8_t protonum;
int set_reply = 0;
Expand Down Expand Up @@ -955,8 +958,11 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
goto out;
}

timeouts = l4proto->get_timeouts(net);

ct = resolve_normal_ct(net, tmpl, skb, dataoff, pf, protonum,
l3proto, l4proto, &set_reply, &ctinfo);
l3proto, l4proto, &set_reply, &ctinfo,
timeouts);
if (!ct) {
/* Not valid part of a connection */
NF_CT_STAT_INC_ATOMIC(net, invalid);
Expand All @@ -973,7 +979,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,

NF_CT_ASSERT(skb->nfct);

ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum);
ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum, timeouts);
if (ret <= 0) {
/* Invalid: inverse of the return code tells
* the netfilter core what to do */
Expand Down
16 changes: 11 additions & 5 deletions net/netfilter/nf_conntrack_proto_dccp.c
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,7 @@ static bool dccp_invert_tuple(struct nf_conntrack_tuple *inv,
}

static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff)
unsigned int dataoff, unsigned int *timeouts)
{
struct net *net = nf_ct_net(ct);
struct dccp_net *dn;
Expand Down Expand Up @@ -472,12 +472,17 @@ static u64 dccp_ack_seq(const struct dccp_hdr *dh)
ntohl(dhack->dccph_ack_nr_low);
}

static unsigned int *dccp_get_timeouts(struct net *net)
{
return dccp_pernet(net)->dccp_timeout;
}

static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff, enum ip_conntrack_info ctinfo,
u_int8_t pf, unsigned int hooknum)
u_int8_t pf, unsigned int hooknum,
unsigned int *timeouts)
{
struct net *net = nf_ct_net(ct);
struct dccp_net *dn;
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
struct dccp_hdr _dh, *dh;
u_int8_t type, old_state, new_state;
Expand Down Expand Up @@ -559,8 +564,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
if (new_state != old_state)
nf_conntrack_event_cache(IPCT_PROTOINFO, ct);

dn = dccp_pernet(net);
nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]);
nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]);

return NF_ACCEPT;
}
Expand Down Expand Up @@ -767,6 +771,7 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = {
.invert_tuple = dccp_invert_tuple,
.new = dccp_new,
.packet = dccp_packet,
.get_timeouts = dccp_get_timeouts,
.error = dccp_error,
.print_tuple = dccp_print_tuple,
.print_conntrack = dccp_print_conntrack,
Expand All @@ -789,6 +794,7 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
.invert_tuple = dccp_invert_tuple,
.new = dccp_new,
.packet = dccp_packet,
.get_timeouts = dccp_get_timeouts,
.error = dccp_error,
.print_tuple = dccp_print_tuple,
.print_conntrack = dccp_print_conntrack,
Expand Down
29 changes: 18 additions & 11 deletions net/netfilter/nf_conntrack_proto_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,27 @@ static int generic_print_tuple(struct seq_file *s,
return 0;
}

static unsigned int *generic_get_timeouts(struct net *net)
{
return &nf_ct_generic_timeout;
}

/* Returns verdict for packet, or -1 for invalid. */
static int packet(struct nf_conn *ct,
const struct sk_buff *skb,
unsigned int dataoff,
enum ip_conntrack_info ctinfo,
u_int8_t pf,
unsigned int hooknum)
static int generic_packet(struct nf_conn *ct,
const struct sk_buff *skb,
unsigned int dataoff,
enum ip_conntrack_info ctinfo,
u_int8_t pf,
unsigned int hooknum,
unsigned int *timeout)
{
nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_generic_timeout);
nf_ct_refresh_acct(ct, ctinfo, skb, *timeout);
return NF_ACCEPT;
}

/* Called when a new connection for this protocol found. */
static bool new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff)
static bool generic_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff, unsigned int *timeouts)
{
return true;
}
Expand Down Expand Up @@ -93,8 +99,9 @@ struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly =
.pkt_to_tuple = generic_pkt_to_tuple,
.invert_tuple = generic_invert_tuple,
.print_tuple = generic_print_tuple,
.packet = packet,
.new = new,
.packet = generic_packet,
.get_timeouts = generic_get_timeouts,
.new = generic_new,
#ifdef CONFIG_SYSCTL
.ctl_table_header = &generic_sysctl_header,
.ctl_table = generic_sysctl_table,
Expand Down
15 changes: 11 additions & 4 deletions net/netfilter/nf_conntrack_proto_gre.c
Original file line number Diff line number Diff line change
Expand Up @@ -235,13 +235,19 @@ static int gre_print_conntrack(struct seq_file *s, struct nf_conn *ct)
(ct->proto.gre.stream_timeout / HZ));
}

static unsigned int *gre_get_timeouts(struct net *net)
{
return gre_timeouts;
}

/* Returns verdict for packet, and may modify conntrack */
static int gre_packet(struct nf_conn *ct,
const struct sk_buff *skb,
unsigned int dataoff,
enum ip_conntrack_info ctinfo,
u_int8_t pf,
unsigned int hooknum)
unsigned int hooknum,
unsigned int *timeouts)
{
/* If we've seen traffic both ways, this is a GRE connection.
* Extend timeout. */
Expand All @@ -260,15 +266,15 @@ static int gre_packet(struct nf_conn *ct,

/* Called when a new connection for this protocol found. */
static bool gre_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff)
unsigned int dataoff, unsigned int *timeouts)
{
pr_debug(": ");
nf_ct_dump_tuple(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple);

/* initialize to sane value. Ideally a conntrack helper
* (e.g. in case of pptp) is increasing them */
ct->proto.gre.stream_timeout = gre_timeouts[GRE_CT_REPLIED];
ct->proto.gre.timeout = gre_timeouts[GRE_CT_UNREPLIED];
ct->proto.gre.stream_timeout = timeouts[GRE_CT_REPLIED];
ct->proto.gre.timeout = timeouts[GRE_CT_UNREPLIED];

return true;
}
Expand All @@ -295,6 +301,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_gre4 __read_mostly = {
.invert_tuple = gre_invert_tuple,
.print_tuple = gre_print_tuple,
.print_conntrack = gre_print_conntrack,
.get_timeouts = gre_get_timeouts,
.packet = gre_packet,
.new = gre_new,
.destroy = gre_destroy,
Expand Down
14 changes: 11 additions & 3 deletions net/netfilter/nf_conntrack_proto_sctp.c
Original file line number Diff line number Diff line change
Expand Up @@ -279,13 +279,19 @@ static int sctp_new_state(enum ip_conntrack_dir dir,
return sctp_conntracks[dir][i][cur_state];
}

static unsigned int *sctp_get_timeouts(struct net *net)
{
return sctp_timeouts;
}

/* Returns verdict for packet, or -NF_ACCEPT for invalid. */
static int sctp_packet(struct nf_conn *ct,
const struct sk_buff *skb,
unsigned int dataoff,
enum ip_conntrack_info ctinfo,
u_int8_t pf,
unsigned int hooknum)
unsigned int hooknum,
unsigned int *timeouts)
{
enum sctp_conntrack new_state, old_state;
enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
Expand Down Expand Up @@ -370,7 +376,7 @@ static int sctp_packet(struct nf_conn *ct,
}
spin_unlock_bh(&ct->lock);

nf_ct_refresh_acct(ct, ctinfo, skb, sctp_timeouts[new_state]);
nf_ct_refresh_acct(ct, ctinfo, skb, timeouts[new_state]);

if (old_state == SCTP_CONNTRACK_COOKIE_ECHOED &&
dir == IP_CT_DIR_REPLY &&
Expand All @@ -390,7 +396,7 @@ static int sctp_packet(struct nf_conn *ct,

/* Called when a new connection for this protocol found. */
static bool sctp_new(struct nf_conn *ct, const struct sk_buff *skb,
unsigned int dataoff)
unsigned int dataoff, unsigned int *timeouts)
{
enum sctp_conntrack new_state;
const struct sctphdr *sh;
Expand Down Expand Up @@ -664,6 +670,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp4 __read_mostly = {
.print_tuple = sctp_print_tuple,
.print_conntrack = sctp_print_conntrack,
.packet = sctp_packet,
.get_timeouts = sctp_get_timeouts,
.new = sctp_new,
.me = THIS_MODULE,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
Expand Down Expand Up @@ -694,6 +701,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_sctp6 __read_mostly = {
.print_tuple = sctp_print_tuple,
.print_conntrack = sctp_print_conntrack,
.packet = sctp_packet,
.get_timeouts = sctp_get_timeouts,
.new = sctp_new,
.me = THIS_MODULE,
#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
Expand Down
Loading

0 comments on commit 2c8503f

Please sign in to comment.