Commit 20710b3b authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso

netfilter: ctnetlink: synproxy support

This patch exposes synproxy information per-conntrack. Moreover, send
sequence adjustment events once server sends us the SYN,ACK packet, so
we can synchronize the sequence adjustment too for packets going as
reply from the server, as part of the synproxy logic.
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 5191d70f
...@@ -129,6 +129,7 @@ enum ip_conntrack_events { ...@@ -129,6 +129,7 @@ enum ip_conntrack_events {
IPCT_NATSEQADJ = IPCT_SEQADJ, IPCT_NATSEQADJ = IPCT_SEQADJ,
IPCT_SECMARK, /* new security mark has been set */ IPCT_SECMARK, /* new security mark has been set */
IPCT_LABEL, /* new connlabel has been set */ IPCT_LABEL, /* new connlabel has been set */
IPCT_SYNPROXY, /* synproxy has been set */
#ifdef __KERNEL__ #ifdef __KERNEL__
__IPCT_MAX __IPCT_MAX
#endif #endif
......
...@@ -54,6 +54,7 @@ enum ctattr_type { ...@@ -54,6 +54,7 @@ enum ctattr_type {
CTA_MARK_MASK, CTA_MARK_MASK,
CTA_LABELS, CTA_LABELS,
CTA_LABELS_MASK, CTA_LABELS_MASK,
CTA_SYNPROXY,
__CTA_MAX __CTA_MAX
}; };
#define CTA_MAX (__CTA_MAX - 1) #define CTA_MAX (__CTA_MAX - 1)
...@@ -190,6 +191,15 @@ enum ctattr_natseq { ...@@ -190,6 +191,15 @@ enum ctattr_natseq {
}; };
#define CTA_NAT_SEQ_MAX (__CTA_NAT_SEQ_MAX - 1) #define CTA_NAT_SEQ_MAX (__CTA_NAT_SEQ_MAX - 1)
enum ctattr_synproxy {
CTA_SYNPROXY_UNSPEC,
CTA_SYNPROXY_ISN,
CTA_SYNPROXY_ITS,
CTA_SYNPROXY_TSOFF,
__CTA_SYNPROXY_MAX,
};
#define CTA_SYNPROXY_MAX (__CTA_SYNPROXY_MAX - 1)
enum ctattr_expect { enum ctattr_expect {
CTA_EXPECT_UNSPEC, CTA_EXPECT_UNSPEC,
CTA_EXPECT_MASTER, CTA_EXPECT_MASTER,
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_seqadj.h> #include <net/netfilter/nf_conntrack_seqadj.h>
#include <net/netfilter/nf_conntrack_synproxy.h> #include <net/netfilter/nf_conntrack_synproxy.h>
#include <net/netfilter/nf_conntrack_ecache.h>
static struct iphdr * static struct iphdr *
synproxy_build_ip(struct net *net, struct sk_buff *skb, __be32 saddr, synproxy_build_ip(struct net *net, struct sk_buff *skb, __be32 saddr,
...@@ -384,6 +385,8 @@ static unsigned int ipv4_synproxy_hook(void *priv, ...@@ -384,6 +385,8 @@ static unsigned int ipv4_synproxy_hook(void *priv,
synproxy->isn = ntohl(th->ack_seq); synproxy->isn = ntohl(th->ack_seq);
if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP) if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
synproxy->its = opts.tsecr; synproxy->its = opts.tsecr;
nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
break; break;
case TCP_CONNTRACK_SYN_RECV: case TCP_CONNTRACK_SYN_RECV:
if (!th->syn || !th->ack) if (!th->syn || !th->ack)
...@@ -392,8 +395,10 @@ static unsigned int ipv4_synproxy_hook(void *priv, ...@@ -392,8 +395,10 @@ static unsigned int ipv4_synproxy_hook(void *priv,
if (!synproxy_parse_options(skb, thoff, th, &opts)) if (!synproxy_parse_options(skb, thoff, th, &opts))
return NF_DROP; return NF_DROP;
if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP) if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP) {
synproxy->tsoff = opts.tsval - synproxy->its; synproxy->tsoff = opts.tsval - synproxy->its;
nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
}
opts.options &= ~(XT_SYNPROXY_OPT_MSS | opts.options &= ~(XT_SYNPROXY_OPT_MSS |
XT_SYNPROXY_OPT_WSCALE | XT_SYNPROXY_OPT_WSCALE |
...@@ -403,6 +408,7 @@ static unsigned int ipv4_synproxy_hook(void *priv, ...@@ -403,6 +408,7 @@ static unsigned int ipv4_synproxy_hook(void *priv,
synproxy_send_server_ack(net, state, skb, th, &opts); synproxy_send_server_ack(net, state, skb, th, &opts);
nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq)); nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
nf_conntrack_event_cache(IPCT_SEQADJ, ct);
swap(opts.tsval, opts.tsecr); swap(opts.tsval, opts.tsecr);
synproxy_send_client_ack(net, skb, th, &opts); synproxy_send_client_ack(net, skb, th, &opts);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_seqadj.h> #include <net/netfilter/nf_conntrack_seqadj.h>
#include <net/netfilter/nf_conntrack_synproxy.h> #include <net/netfilter/nf_conntrack_synproxy.h>
#include <net/netfilter/nf_conntrack_ecache.h>
static struct ipv6hdr * static struct ipv6hdr *
synproxy_build_ip(struct net *net, struct sk_buff *skb, synproxy_build_ip(struct net *net, struct sk_buff *skb,
...@@ -405,6 +406,8 @@ static unsigned int ipv6_synproxy_hook(void *priv, ...@@ -405,6 +406,8 @@ static unsigned int ipv6_synproxy_hook(void *priv,
synproxy->isn = ntohl(th->ack_seq); synproxy->isn = ntohl(th->ack_seq);
if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP) if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP)
synproxy->its = opts.tsecr; synproxy->its = opts.tsecr;
nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
break; break;
case TCP_CONNTRACK_SYN_RECV: case TCP_CONNTRACK_SYN_RECV:
if (!th->syn || !th->ack) if (!th->syn || !th->ack)
...@@ -413,8 +416,10 @@ static unsigned int ipv6_synproxy_hook(void *priv, ...@@ -413,8 +416,10 @@ static unsigned int ipv6_synproxy_hook(void *priv,
if (!synproxy_parse_options(skb, thoff, th, &opts)) if (!synproxy_parse_options(skb, thoff, th, &opts))
return NF_DROP; return NF_DROP;
if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP) if (opts.options & XT_SYNPROXY_OPT_TIMESTAMP) {
synproxy->tsoff = opts.tsval - synproxy->its; synproxy->tsoff = opts.tsval - synproxy->its;
nf_conntrack_event_cache(IPCT_SYNPROXY, ct);
}
opts.options &= ~(XT_SYNPROXY_OPT_MSS | opts.options &= ~(XT_SYNPROXY_OPT_MSS |
XT_SYNPROXY_OPT_WSCALE | XT_SYNPROXY_OPT_WSCALE |
...@@ -424,6 +429,7 @@ static unsigned int ipv6_synproxy_hook(void *priv, ...@@ -424,6 +429,7 @@ static unsigned int ipv6_synproxy_hook(void *priv,
synproxy_send_server_ack(net, state, skb, th, &opts); synproxy_send_server_ack(net, state, skb, th, &opts);
nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq)); nf_ct_seqadj_init(ct, ctinfo, synproxy->isn - ntohl(th->seq));
nf_conntrack_event_cache(IPCT_SEQADJ, ct);
swap(opts.tsval, opts.tsecr); swap(opts.tsval, opts.tsecr);
synproxy_send_client_ack(net, skb, th, &opts); synproxy_send_client_ack(net, skb, th, &opts);
......
...@@ -440,6 +440,31 @@ static int ctnetlink_dump_ct_seq_adj(struct sk_buff *skb, struct nf_conn *ct) ...@@ -440,6 +440,31 @@ static int ctnetlink_dump_ct_seq_adj(struct sk_buff *skb, struct nf_conn *ct)
return -1; return -1;
} }
static int ctnetlink_dump_ct_synproxy(struct sk_buff *skb, struct nf_conn *ct)
{
struct nf_conn_synproxy *synproxy = nfct_synproxy(ct);
struct nlattr *nest_parms;
if (!synproxy)
return 0;
nest_parms = nla_nest_start(skb, CTA_SYNPROXY | NLA_F_NESTED);
if (!nest_parms)
goto nla_put_failure;
if (nla_put_be32(skb, CTA_SYNPROXY_ISN, htonl(synproxy->isn)) ||
nla_put_be32(skb, CTA_SYNPROXY_ITS, htonl(synproxy->its)) ||
nla_put_be32(skb, CTA_SYNPROXY_TSOFF, htonl(synproxy->tsoff)))
goto nla_put_failure;
nla_nest_end(skb, nest_parms);
return 0;
nla_put_failure:
return -1;
}
static int ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) static int ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct)
{ {
if (nla_put_be32(skb, CTA_ID, htonl((unsigned long)ct))) if (nla_put_be32(skb, CTA_ID, htonl((unsigned long)ct)))
...@@ -518,7 +543,8 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type, ...@@ -518,7 +543,8 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,
ctnetlink_dump_id(skb, ct) < 0 || ctnetlink_dump_id(skb, ct) < 0 ||
ctnetlink_dump_use(skb, ct) < 0 || ctnetlink_dump_use(skb, ct) < 0 ||
ctnetlink_dump_master(skb, ct) < 0 || ctnetlink_dump_master(skb, ct) < 0 ||
ctnetlink_dump_ct_seq_adj(skb, ct) < 0) ctnetlink_dump_ct_seq_adj(skb, ct) < 0 ||
ctnetlink_dump_ct_synproxy(skb, ct) < 0)
goto nla_put_failure; goto nla_put_failure;
nlmsg_end(skb, nlh); nlmsg_end(skb, nlh);
...@@ -730,6 +756,10 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item) ...@@ -730,6 +756,10 @@ ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
if (events & (1 << IPCT_SEQADJ) && if (events & (1 << IPCT_SEQADJ) &&
ctnetlink_dump_ct_seq_adj(skb, ct) < 0) ctnetlink_dump_ct_seq_adj(skb, ct) < 0)
goto nla_put_failure; goto nla_put_failure;
if (events & (1 << IPCT_SYNPROXY) &&
ctnetlink_dump_ct_synproxy(skb, ct) < 0)
goto nla_put_failure;
} }
#ifdef CONFIG_NF_CONNTRACK_MARK #ifdef CONFIG_NF_CONNTRACK_MARK
...@@ -1689,6 +1719,39 @@ ctnetlink_change_seq_adj(struct nf_conn *ct, ...@@ -1689,6 +1719,39 @@ ctnetlink_change_seq_adj(struct nf_conn *ct,
return ret; return ret;
} }
static const struct nla_policy synproxy_policy[CTA_SYNPROXY_MAX + 1] = {
[CTA_SYNPROXY_ISN] = { .type = NLA_U32 },
[CTA_SYNPROXY_ITS] = { .type = NLA_U32 },
[CTA_SYNPROXY_TSOFF] = { .type = NLA_U32 },
};
static int ctnetlink_change_synproxy(struct nf_conn *ct,
const struct nlattr * const cda[])
{
struct nf_conn_synproxy *synproxy = nfct_synproxy(ct);
struct nlattr *tb[CTA_SYNPROXY_MAX + 1];
int err;
if (!synproxy)
return 0;
err = nla_parse_nested(tb, CTA_SYNPROXY_MAX, cda[CTA_SYNPROXY],
synproxy_policy, NULL);
if (err < 0)
return err;
if (!tb[CTA_SYNPROXY_ISN] ||
!tb[CTA_SYNPROXY_ITS] ||
!tb[CTA_SYNPROXY_TSOFF])
return -EINVAL;
synproxy->isn = ntohl(nla_get_be32(tb[CTA_SYNPROXY_ISN]));
synproxy->its = ntohl(nla_get_be32(tb[CTA_SYNPROXY_ITS]));
synproxy->tsoff = ntohl(nla_get_be32(tb[CTA_SYNPROXY_TSOFF]));
return 0;
}
static int static int
ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[]) ctnetlink_attach_labels(struct nf_conn *ct, const struct nlattr * const cda[])
{ {
...@@ -1759,6 +1822,12 @@ ctnetlink_change_conntrack(struct nf_conn *ct, ...@@ -1759,6 +1822,12 @@ ctnetlink_change_conntrack(struct nf_conn *ct,
return err; return err;
} }
if (cda[CTA_SYNPROXY]) {
err = ctnetlink_change_synproxy(ct, cda);
if (err < 0)
return err;
}
if (cda[CTA_LABELS]) { if (cda[CTA_LABELS]) {
err = ctnetlink_attach_labels(ct, cda); err = ctnetlink_attach_labels(ct, cda);
if (err < 0) if (err < 0)
...@@ -1880,6 +1949,12 @@ ctnetlink_create_conntrack(struct net *net, ...@@ -1880,6 +1949,12 @@ ctnetlink_create_conntrack(struct net *net,
goto err2; goto err2;
} }
if (cda[CTA_SYNPROXY]) {
err = ctnetlink_change_synproxy(ct, cda);
if (err < 0)
goto err2;
}
#if defined(CONFIG_NF_CONNTRACK_MARK) #if defined(CONFIG_NF_CONNTRACK_MARK)
if (cda[CTA_MARK]) if (cda[CTA_MARK])
ct->mark = ntohl(nla_get_be32(cda[CTA_MARK])); ct->mark = ntohl(nla_get_be32(cda[CTA_MARK]));
...@@ -1991,7 +2066,9 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl, ...@@ -1991,7 +2066,9 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
(1 << IPCT_HELPER) | (1 << IPCT_HELPER) |
(1 << IPCT_PROTOINFO) | (1 << IPCT_PROTOINFO) |
(1 << IPCT_SEQADJ) | (1 << IPCT_SEQADJ) |
(1 << IPCT_MARK) | events, (1 << IPCT_MARK) |
(1 << IPCT_SYNPROXY) |
events,
ct, NETLINK_CB(skb).portid, ct, NETLINK_CB(skb).portid,
nlmsg_report(nlh)); nlmsg_report(nlh));
nf_ct_put(ct); nf_ct_put(ct);
...@@ -2012,7 +2089,8 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl, ...@@ -2012,7 +2089,8 @@ static int ctnetlink_new_conntrack(struct net *net, struct sock *ctnl,
(1 << IPCT_LABEL) | (1 << IPCT_LABEL) |
(1 << IPCT_PROTOINFO) | (1 << IPCT_PROTOINFO) |
(1 << IPCT_SEQADJ) | (1 << IPCT_SEQADJ) |
(1 << IPCT_MARK), (1 << IPCT_MARK) |
(1 << IPCT_SYNPROXY),
ct, NETLINK_CB(skb).portid, ct, NETLINK_CB(skb).portid,
nlmsg_report(nlh)); nlmsg_report(nlh));
} }
...@@ -2282,6 +2360,9 @@ static int __ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct) ...@@ -2282,6 +2360,9 @@ static int __ctnetlink_glue_build(struct sk_buff *skb, struct nf_conn *ct)
ctnetlink_dump_ct_seq_adj(skb, ct) < 0) ctnetlink_dump_ct_seq_adj(skb, ct) < 0)
goto nla_put_failure; goto nla_put_failure;
if (ctnetlink_dump_ct_synproxy(skb, ct) < 0)
goto nla_put_failure;
#ifdef CONFIG_NF_CONNTRACK_MARK #ifdef CONFIG_NF_CONNTRACK_MARK
if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0) if (ct->mark && ctnetlink_dump_mark(skb, ct) < 0)
goto nla_put_failure; goto nla_put_failure;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment