Commit c1d10adb authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso Committed by David S. Miller

[NETFILTER]: Add ctnetlink port for nf_conntrack

Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: default avatarPatrick McHardy <kaber@trash.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 205d67c7
...@@ -64,6 +64,9 @@ enum ctattr_l4proto { ...@@ -64,6 +64,9 @@ enum ctattr_l4proto {
CTA_PROTO_ICMP_ID, CTA_PROTO_ICMP_ID,
CTA_PROTO_ICMP_TYPE, CTA_PROTO_ICMP_TYPE,
CTA_PROTO_ICMP_CODE, CTA_PROTO_ICMP_CODE,
CTA_PROTO_ICMPV6_ID,
CTA_PROTO_ICMPV6_TYPE,
CTA_PROTO_ICMPV6_CODE,
__CTA_PROTO_MAX __CTA_PROTO_MAX
}; };
#define CTA_PROTO_MAX (__CTA_PROTO_MAX - 1) #define CTA_PROTO_MAX (__CTA_PROTO_MAX - 1)
......
...@@ -94,6 +94,9 @@ struct nf_conn ...@@ -94,6 +94,9 @@ struct nf_conn
/* Current number of expected connections */ /* Current number of expected connections */
unsigned int expecting; unsigned int expecting;
/* Unique ID that identifies this conntrack*/
unsigned int id;
/* Helper. if any */ /* Helper. if any */
struct nf_conntrack_helper *helper; struct nf_conntrack_helper *helper;
...@@ -140,6 +143,9 @@ struct nf_conntrack_expect ...@@ -140,6 +143,9 @@ struct nf_conntrack_expect
/* Usage count. */ /* Usage count. */
atomic_t use; atomic_t use;
/* Unique ID */
unsigned int id;
/* Flags */ /* Flags */
unsigned int flags; unsigned int flags;
...@@ -190,6 +196,31 @@ static inline void nf_ct_put(struct nf_conn *ct) ...@@ -190,6 +196,31 @@ static inline void nf_ct_put(struct nf_conn *ct)
nf_conntrack_put(&ct->ct_general); nf_conntrack_put(&ct->ct_general);
} }
extern struct nf_conntrack_tuple_hash *
__nf_conntrack_find(const struct nf_conntrack_tuple *tuple,
const struct nf_conn *ignored_conntrack);
extern void nf_conntrack_hash_insert(struct nf_conn *ct);
extern struct nf_conntrack_expect *
__nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple);
extern struct nf_conntrack_expect *
nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple);
extern void nf_ct_unlink_expect(struct nf_conntrack_expect *exp);
extern void nf_ct_remove_expectations(struct nf_conn *ct);
extern void nf_conntrack_flush(void);
extern struct nf_conntrack_helper *
nf_ct_helper_find_get( const struct nf_conntrack_tuple *tuple);
extern void nf_ct_helper_put(struct nf_conntrack_helper *helper);
extern struct nf_conntrack_helper *
__nf_conntrack_helper_find_byname(const char *name);
/* call to create an explicit dependency on nf_conntrack. */ /* call to create an explicit dependency on nf_conntrack. */
extern void need_nf_conntrack(void); extern void need_nf_conntrack(void);
......
...@@ -33,6 +33,8 @@ struct nf_conntrack_helper ...@@ -33,6 +33,8 @@ struct nf_conntrack_helper
unsigned int protoff, unsigned int protoff,
struct nf_conn *ct, struct nf_conn *ct,
enum ip_conntrack_info conntrackinfo); enum ip_conntrack_info conntrackinfo);
int (*to_nfattr)(struct sk_buff *skb, const struct nf_conn *ct);
}; };
extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack.h>
struct nfattr;
struct nf_conntrack_l3proto struct nf_conntrack_l3proto
{ {
/* Next pointer. */ /* Next pointer. */
...@@ -70,6 +72,12 @@ struct nf_conntrack_l3proto ...@@ -70,6 +72,12 @@ struct nf_conntrack_l3proto
u_int32_t (*get_features)(const struct nf_conntrack_tuple *tuple); u_int32_t (*get_features)(const struct nf_conntrack_tuple *tuple);
int (*tuple_to_nfattr)(struct sk_buff *skb,
const struct nf_conntrack_tuple *t);
int (*nfattr_to_tuple)(struct nfattr *tb[],
struct nf_conntrack_tuple *t);
/* Module (if any) which this is connected to. */ /* Module (if any) which this is connected to. */
struct module *me; struct module *me;
}; };
...@@ -81,11 +89,16 @@ extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto); ...@@ -81,11 +89,16 @@ extern int nf_conntrack_l3proto_register(struct nf_conntrack_l3proto *proto);
extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto); extern void nf_conntrack_l3proto_unregister(struct nf_conntrack_l3proto *proto);
static inline struct nf_conntrack_l3proto * static inline struct nf_conntrack_l3proto *
nf_ct_find_l3proto(u_int16_t l3proto) __nf_ct_l3proto_find(u_int16_t l3proto)
{ {
return nf_ct_l3protos[l3proto]; return nf_ct_l3protos[l3proto];
} }
extern struct nf_conntrack_l3proto *
nf_ct_l3proto_find_get(u_int16_t l3proto);
extern void nf_ct_l3proto_put(struct nf_conntrack_l3proto *p);
/* Existing built-in protocols */ /* Existing built-in protocols */
extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4; extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4;
extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6; extern struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack.h>
struct seq_file; struct seq_file;
struct nfattr;
struct nf_conntrack_protocol struct nf_conntrack_protocol
{ {
...@@ -66,6 +67,18 @@ struct nf_conntrack_protocol ...@@ -66,6 +67,18 @@ struct nf_conntrack_protocol
enum ip_conntrack_info *ctinfo, enum ip_conntrack_info *ctinfo,
int pf, unsigned int hooknum); int pf, unsigned int hooknum);
/* convert protoinfo to nfnetink attributes */
int (*to_nfattr)(struct sk_buff *skb, struct nfattr *nfa,
const struct nf_conn *ct);
/* convert nfnetlink attributes to protoinfo */
int (*from_nfattr)(struct nfattr *tb[], struct nf_conn *ct);
int (*tuple_to_nfattr)(struct sk_buff *skb,
const struct nf_conntrack_tuple *t);
int (*nfattr_to_tuple)(struct nfattr *tb[],
struct nf_conntrack_tuple *t);
/* Module (if any) which this is connected to. */ /* Module (if any) which this is connected to. */
struct module *me; struct module *me;
}; };
...@@ -80,12 +93,23 @@ extern struct nf_conntrack_protocol nf_conntrack_generic_protocol; ...@@ -80,12 +93,23 @@ extern struct nf_conntrack_protocol nf_conntrack_generic_protocol;
extern struct nf_conntrack_protocol **nf_ct_protos[PF_MAX]; extern struct nf_conntrack_protocol **nf_ct_protos[PF_MAX];
extern struct nf_conntrack_protocol * extern struct nf_conntrack_protocol *
nf_ct_find_proto(u_int16_t l3proto, u_int8_t protocol); __nf_ct_proto_find(u_int16_t l3proto, u_int8_t protocol);
extern struct nf_conntrack_protocol *
nf_ct_proto_find_get(u_int16_t l3proto, u_int8_t protocol);
extern void nf_ct_proto_put(struct nf_conntrack_protocol *p);
/* Protocol registration. */ /* Protocol registration. */
extern int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto); extern int nf_conntrack_protocol_register(struct nf_conntrack_protocol *proto);
extern void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto); extern void nf_conntrack_protocol_unregister(struct nf_conntrack_protocol *proto);
/* Generic netlink helpers */
extern int nf_ct_port_tuple_to_nfattr(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple);
extern int nf_ct_port_nfattr_to_tuple(struct nfattr *tb[],
struct nf_conntrack_tuple *t);
/* Log invalid packets */ /* Log invalid packets */
extern unsigned int nf_ct_log_invalid; extern unsigned int nf_ct_log_invalid;
......
...@@ -392,6 +392,48 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) ...@@ -392,6 +392,48 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len)
return -ENOENT; return -ENOENT;
} }
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_conntrack.h>
static int ipv4_tuple_to_nfattr(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple)
{
NFA_PUT(skb, CTA_IP_V4_SRC, sizeof(u_int32_t),
&tuple->src.u3.ip);
NFA_PUT(skb, CTA_IP_V4_DST, sizeof(u_int32_t),
&tuple->dst.u3.ip);
return 0;
nfattr_failure:
return -1;
}
static const size_t cta_min_ip[CTA_IP_MAX] = {
[CTA_IP_V4_SRC-1] = sizeof(u_int32_t),
[CTA_IP_V4_DST-1] = sizeof(u_int32_t),
};
static int ipv4_nfattr_to_tuple(struct nfattr *tb[],
struct nf_conntrack_tuple *t)
{
if (!tb[CTA_IP_V4_SRC-1] || !tb[CTA_IP_V4_DST-1])
return -EINVAL;
if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
return -EINVAL;
t->src.u3.ip =
*(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_SRC-1]);
t->dst.u3.ip =
*(u_int32_t *)NFA_DATA(tb[CTA_IP_V4_DST-1]);
return 0;
}
#endif
static struct nf_sockopt_ops so_getorigdst = { static struct nf_sockopt_ops so_getorigdst = {
.pf = PF_INET, .pf = PF_INET,
.get_optmin = SO_ORIGINAL_DST, .get_optmin = SO_ORIGINAL_DST,
...@@ -408,6 +450,11 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = { ...@@ -408,6 +450,11 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv4 = {
.print_conntrack = ipv4_print_conntrack, .print_conntrack = ipv4_print_conntrack,
.prepare = ipv4_prepare, .prepare = ipv4_prepare,
.get_features = ipv4_get_features, .get_features = ipv4_get_features,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = ipv4_tuple_to_nfattr,
.nfattr_to_tuple = ipv4_nfattr_to_tuple,
#endif
.me = THIS_MODULE, .me = THIS_MODULE,
}; };
......
...@@ -50,20 +50,21 @@ static int icmp_pkt_to_tuple(const struct sk_buff *skb, ...@@ -50,20 +50,21 @@ static int icmp_pkt_to_tuple(const struct sk_buff *skb,
return 1; return 1;
} }
static int icmp_invert_tuple(struct nf_conntrack_tuple *tuple, /* Add 1; spaces filled with 0. */
const struct nf_conntrack_tuple *orig) static const u_int8_t invmap[] = {
{ [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
/* Add 1; spaces filled with 0. */
static u_int8_t invmap[]
= { [ICMP_ECHO] = ICMP_ECHOREPLY + 1,
[ICMP_ECHOREPLY] = ICMP_ECHO + 1, [ICMP_ECHOREPLY] = ICMP_ECHO + 1,
[ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1,
[ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1,
[ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1,
[ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1,
[ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1,
[ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1}; [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1
};
static int icmp_invert_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_tuple *orig)
{
if (orig->dst.u.icmp.type >= sizeof(invmap) if (orig->dst.u.icmp.type >= sizeof(invmap)
|| !invmap[orig->dst.u.icmp.type]) || !invmap[orig->dst.u.icmp.type])
return 0; return 0;
...@@ -120,11 +121,12 @@ static int icmp_packet(struct nf_conn *ct, ...@@ -120,11 +121,12 @@ static int icmp_packet(struct nf_conn *ct,
static int icmp_new(struct nf_conn *conntrack, static int icmp_new(struct nf_conn *conntrack,
const struct sk_buff *skb, unsigned int dataoff) const struct sk_buff *skb, unsigned int dataoff)
{ {
static u_int8_t valid_new[] static const u_int8_t valid_new[] = {
= { [ICMP_ECHO] = 1, [ICMP_ECHO] = 1,
[ICMP_TIMESTAMP] = 1, [ICMP_TIMESTAMP] = 1,
[ICMP_INFO_REQUEST] = 1, [ICMP_INFO_REQUEST] = 1,
[ICMP_ADDRESS] = 1 }; [ICMP_ADDRESS] = 1
};
if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new) if (conntrack->tuplehash[0].tuple.dst.u.icmp.type >= sizeof(valid_new)
|| !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) { || !valid_new[conntrack->tuplehash[0].tuple.dst.u.icmp.type]) {
...@@ -168,7 +170,7 @@ icmp_error_message(struct sk_buff *skb, ...@@ -168,7 +170,7 @@ icmp_error_message(struct sk_buff *skb,
return -NF_ACCEPT; return -NF_ACCEPT;
} }
innerproto = nf_ct_find_proto(PF_INET, inside->ip.protocol); innerproto = __nf_ct_proto_find(PF_INET, inside->ip.protocol);
dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp); dataoff = skb->nh.iph->ihl*4 + sizeof(inside->icmp);
/* Are they talking about one of our connections? */ /* Are they talking about one of our connections? */
if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET, if (!nf_ct_get_tuple(skb, dataoff, dataoff + inside->ip.ihl*4, PF_INET,
...@@ -281,6 +283,60 @@ icmp_error(struct sk_buff *skb, unsigned int dataoff, ...@@ -281,6 +283,60 @@ icmp_error(struct sk_buff *skb, unsigned int dataoff,
return icmp_error_message(skb, ctinfo, hooknum); return icmp_error_message(skb, ctinfo, hooknum);
} }
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_conntrack.h>
static int icmp_tuple_to_nfattr(struct sk_buff *skb,
const struct nf_conntrack_tuple *t)
{
NFA_PUT(skb, CTA_PROTO_ICMP_ID, sizeof(u_int16_t),
&t->src.u.icmp.id);
NFA_PUT(skb, CTA_PROTO_ICMP_TYPE, sizeof(u_int8_t),
&t->dst.u.icmp.type);
NFA_PUT(skb, CTA_PROTO_ICMP_CODE, sizeof(u_int8_t),
&t->dst.u.icmp.code);
return 0;
nfattr_failure:
return -1;
}
static const size_t cta_min_proto[CTA_PROTO_MAX] = {
[CTA_PROTO_ICMP_TYPE-1] = sizeof(u_int8_t),
[CTA_PROTO_ICMP_CODE-1] = sizeof(u_int8_t),
[CTA_PROTO_ICMP_ID-1] = sizeof(u_int16_t)
};
static int icmp_nfattr_to_tuple(struct nfattr *tb[],
struct nf_conntrack_tuple *tuple)
{
if (!tb[CTA_PROTO_ICMP_TYPE-1]
|| !tb[CTA_PROTO_ICMP_CODE-1]
|| !tb[CTA_PROTO_ICMP_ID-1])
return -EINVAL;
if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
return -EINVAL;
tuple->dst.u.icmp.type =
*(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_TYPE-1]);
tuple->dst.u.icmp.code =
*(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMP_CODE-1]);
tuple->src.u.icmp.id =
*(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMP_ID-1]);
if (tuple->dst.u.icmp.type >= sizeof(invmap)
|| !invmap[tuple->dst.u.icmp.type])
return -EINVAL;
return 0;
}
#endif
struct nf_conntrack_protocol nf_conntrack_protocol_icmp = struct nf_conntrack_protocol nf_conntrack_protocol_icmp =
{ {
.list = { NULL, NULL }, .list = { NULL, NULL },
...@@ -295,7 +351,12 @@ struct nf_conntrack_protocol nf_conntrack_protocol_icmp = ...@@ -295,7 +351,12 @@ struct nf_conntrack_protocol nf_conntrack_protocol_icmp =
.new = icmp_new, .new = icmp_new,
.error = icmp_error, .error = icmp_error,
.destroy = NULL, .destroy = NULL,
.me = NULL .me = NULL,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = icmp_tuple_to_nfattr,
.nfattr_to_tuple = icmp_nfattr_to_tuple,
#endif
}; };
EXPORT_SYMBOL(nf_conntrack_protocol_icmp); EXPORT_SYMBOL(nf_conntrack_protocol_icmp);
...@@ -401,6 +401,48 @@ static ctl_table nf_ct_net_table[] = { ...@@ -401,6 +401,48 @@ static ctl_table nf_ct_net_table[] = {
}; };
#endif #endif
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_conntrack.h>
static int ipv6_tuple_to_nfattr(struct sk_buff *skb,
const struct nf_conntrack_tuple *tuple)
{
NFA_PUT(skb, CTA_IP_V6_SRC, sizeof(u_int32_t) * 4,
&tuple->src.u3.ip6);
NFA_PUT(skb, CTA_IP_V6_DST, sizeof(u_int32_t) * 4,
&tuple->dst.u3.ip6);
return 0;
nfattr_failure:
return -1;
}
static const size_t cta_min_ip[CTA_IP_MAX] = {
[CTA_IP_V6_SRC-1] = sizeof(u_int32_t)*4,
[CTA_IP_V6_DST-1] = sizeof(u_int32_t)*4,
};
static int ipv6_nfattr_to_tuple(struct nfattr *tb[],
struct nf_conntrack_tuple *t)
{
if (!tb[CTA_IP_V6_SRC-1] || !tb[CTA_IP_V6_DST-1])
return -EINVAL;
if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
return -EINVAL;
memcpy(&t->src.u3.ip6, NFA_DATA(tb[CTA_IP_V6_SRC-1]),
sizeof(u_int32_t) * 4);
memcpy(&t->dst.u3.ip6, NFA_DATA(tb[CTA_IP_V6_DST-1]),
sizeof(u_int32_t) * 4);
return 0;
}
#endif
struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = { struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = {
.l3proto = PF_INET6, .l3proto = PF_INET6,
.name = "ipv6", .name = "ipv6",
...@@ -409,6 +451,11 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = { ...@@ -409,6 +451,11 @@ struct nf_conntrack_l3proto nf_conntrack_l3proto_ipv6 = {
.print_tuple = ipv6_print_tuple, .print_tuple = ipv6_print_tuple,
.print_conntrack = ipv6_print_conntrack, .print_conntrack = ipv6_print_conntrack,
.prepare = ipv6_prepare, .prepare = ipv6_prepare,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = ipv6_tuple_to_nfattr,
.nfattr_to_tuple = ipv6_nfattr_to_tuple,
#endif
.get_features = ipv6_get_features, .get_features = ipv6_get_features,
.me = THIS_MODULE, .me = THIS_MODULE,
}; };
......
...@@ -57,17 +57,17 @@ static int icmpv6_pkt_to_tuple(const struct sk_buff *skb, ...@@ -57,17 +57,17 @@ static int icmpv6_pkt_to_tuple(const struct sk_buff *skb,
return 1; return 1;
} }
static int icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple, /* Add 1; spaces filled with 0. */
const struct nf_conntrack_tuple *orig) static u_int8_t invmap[] = {
{
/* Add 1; spaces filled with 0. */
static u_int8_t invmap[] = {
[ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1, [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1,
[ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1, [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1,
[ICMPV6_NI_QUERY - 128] = ICMPV6_NI_QUERY + 1, [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_QUERY + 1,
[ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1 [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY +1
}; };
static int icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_tuple *orig)
{
int type = orig->dst.u.icmp.type - 128; int type = orig->dst.u.icmp.type - 128;
if (type < 0 || type >= sizeof(invmap) || !invmap[type]) if (type < 0 || type >= sizeof(invmap) || !invmap[type])
return 0; return 0;
...@@ -185,7 +185,7 @@ icmpv6_error_message(struct sk_buff *skb, ...@@ -185,7 +185,7 @@ icmpv6_error_message(struct sk_buff *skb,
return -NF_ACCEPT; return -NF_ACCEPT;
} }
inproto = nf_ct_find_proto(PF_INET6, inprotonum); inproto = __nf_ct_proto_find(PF_INET6, inprotonum);
/* Are they talking about one of our connections? */ /* Are they talking about one of our connections? */
if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum, if (!nf_ct_get_tuple(skb, inip6off, inprotoff, PF_INET6, inprotonum,
...@@ -255,6 +255,60 @@ icmpv6_error(struct sk_buff *skb, unsigned int dataoff, ...@@ -255,6 +255,60 @@ icmpv6_error(struct sk_buff *skb, unsigned int dataoff,
return icmpv6_error_message(skb, dataoff, ctinfo, hooknum); return icmpv6_error_message(skb, dataoff, ctinfo, hooknum);
} }
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_conntrack.h>
static int icmpv6_tuple_to_nfattr(struct sk_buff *skb,
const struct nf_conntrack_tuple *t)
{
NFA_PUT(skb, CTA_PROTO_ICMPV6_ID, sizeof(u_int16_t),
&t->src.u.icmp.id);
NFA_PUT(skb, CTA_PROTO_ICMPV6_TYPE, sizeof(u_int8_t),
&t->dst.u.icmp.type);
NFA_PUT(skb, CTA_PROTO_ICMPV6_CODE, sizeof(u_int8_t),
&t->dst.u.icmp.code);
return 0;
nfattr_failure:
return -1;
}
static const size_t cta_min_proto[CTA_PROTO_MAX] = {
[CTA_PROTO_ICMPV6_TYPE-1] = sizeof(u_int8_t),
[CTA_PROTO_ICMPV6_CODE-1] = sizeof(u_int8_t),
[CTA_PROTO_ICMPV6_ID-1] = sizeof(u_int16_t)
};
static int icmpv6_nfattr_to_tuple(struct nfattr *tb[],
struct nf_conntrack_tuple *tuple)
{
if (!tb[CTA_PROTO_ICMPV6_TYPE-1]
|| !tb[CTA_PROTO_ICMPV6_CODE-1]
|| !tb[CTA_PROTO_ICMPV6_ID-1])
return -EINVAL;
if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
return -EINVAL;
tuple->dst.u.icmp.type =
*(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_TYPE-1]);
tuple->dst.u.icmp.code =
*(u_int8_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_CODE-1]);
tuple->src.u.icmp.id =
*(u_int16_t *)NFA_DATA(tb[CTA_PROTO_ICMPV6_ID-1]);
if (tuple->dst.u.icmp.type < 128
|| tuple->dst.u.icmp.type - 128 >= sizeof(invmap)
|| !invmap[tuple->dst.u.icmp.type - 128])
return -EINVAL;
return 0;
}
#endif
struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 = struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 =
{ {
.l3proto = PF_INET6, .l3proto = PF_INET6,
...@@ -267,6 +321,11 @@ struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 = ...@@ -267,6 +321,11 @@ struct nf_conntrack_protocol nf_conntrack_protocol_icmpv6 =
.packet = icmpv6_packet, .packet = icmpv6_packet,
.new = icmpv6_new, .new = icmpv6_new,
.error = icmpv6_error, .error = icmpv6_error,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = icmpv6_tuple_to_nfattr,
.nfattr_to_tuple = icmpv6_nfattr_to_tuple,
#endif
}; };
EXPORT_SYMBOL(nf_conntrack_protocol_icmpv6); EXPORT_SYMBOL(nf_conntrack_protocol_icmpv6);
...@@ -95,4 +95,11 @@ config NF_CONNTRACK_FTP ...@@ -95,4 +95,11 @@ config NF_CONNTRACK_FTP
To compile it as a module, choose M here. If unsure, say N. To compile it as a module, choose M here. If unsure, say N.
config NF_CT_NETLINK
tristate 'Connection tracking netlink interface (EXPERIMENTAL)'
depends on EXPERIMENTAL && NF_CONNTRACK && NETFILTER_NETLINK
depends on NF_CONNTRACK!=y || NETFILTER_NETLINK!=m
help
This option enables support for a netlink-based userspace interface
endmenu endmenu
...@@ -13,3 +13,6 @@ obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o ...@@ -13,3 +13,6 @@ obj-$(CONFIG_NF_CONNTRACK_FTP) += nf_conntrack_ftp.o
# SCTP protocol connection tracking # SCTP protocol connection tracking
obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o obj-$(CONFIG_NF_CT_PROTO_SCTP) += nf_conntrack_proto_sctp.o
# netlink interface for nf_conntrack
obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o
This diff is collapsed.
This diff is collapsed.
...@@ -1148,6 +1148,63 @@ static int tcp_new(struct nf_conn *conntrack, ...@@ -1148,6 +1148,63 @@ static int tcp_new(struct nf_conn *conntrack,
return 1; return 1;
} }
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
#include <linux/netfilter/nfnetlink.h>
#include <linux/netfilter/nfnetlink_conntrack.h>
static int tcp_to_nfattr(struct sk_buff *skb, struct nfattr *nfa,
const struct nf_conn *ct)
{
struct nfattr *nest_parms;
read_lock_bh(&tcp_lock);
nest_parms = NFA_NEST(skb, CTA_PROTOINFO_TCP);
NFA_PUT(skb, CTA_PROTOINFO_TCP_STATE, sizeof(u_int8_t),
&ct->proto.tcp.state);
read_unlock_bh(&tcp_lock);
NFA_NEST_END(skb, nest_parms);
return 0;
nfattr_failure:
read_unlock_bh(&tcp_lock);
return -1;
}
static const size_t cta_min_tcp[CTA_PROTOINFO_TCP_MAX] = {
[CTA_PROTOINFO_TCP_STATE-1] = sizeof(u_int8_t),
};
static int nfattr_to_tcp(struct nfattr *cda[], struct nf_conn *ct)
{
struct nfattr *attr = cda[CTA_PROTOINFO_TCP-1];
struct nfattr *tb[CTA_PROTOINFO_TCP_MAX];
/* updates could not contain anything about the private
* protocol info, in that case skip the parsing */
if (!attr)
return 0;
nfattr_parse_nested(tb, CTA_PROTOINFO_TCP_MAX, attr);
if (nfattr_bad_size(tb, CTA_PROTOINFO_TCP_MAX, cta_min_tcp))
return -EINVAL;
if (!tb[CTA_PROTOINFO_TCP_STATE-1])
return -EINVAL;
write_lock_bh(&tcp_lock);
ct->proto.tcp.state =
*(u_int8_t *)NFA_DATA(tb[CTA_PROTOINFO_TCP_STATE-1]);
write_unlock_bh(&tcp_lock);
return 0;
}
#endif
struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 = struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 =
{ {
.l3proto = PF_INET, .l3proto = PF_INET,
...@@ -1160,6 +1217,13 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 = ...@@ -1160,6 +1217,13 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp4 =
.packet = tcp_packet, .packet = tcp_packet,
.new = tcp_new, .new = tcp_new,
.error = tcp_error4, .error = tcp_error4,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.to_nfattr = tcp_to_nfattr,
.from_nfattr = nfattr_to_tcp,
.tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
.nfattr_to_tuple = nf_ct_port_nfattr_to_tuple,
#endif
}; };
struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 = struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 =
...@@ -1174,6 +1238,13 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 = ...@@ -1174,6 +1238,13 @@ struct nf_conntrack_protocol nf_conntrack_protocol_tcp6 =
.packet = tcp_packet, .packet = tcp_packet,
.new = tcp_new, .new = tcp_new,
.error = tcp_error6, .error = tcp_error6,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.to_nfattr = tcp_to_nfattr,
.from_nfattr = nfattr_to_tcp,
.tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
.nfattr_to_tuple = nf_ct_port_nfattr_to_tuple,
#endif
}; };
EXPORT_SYMBOL(nf_conntrack_protocol_tcp4); EXPORT_SYMBOL(nf_conntrack_protocol_tcp4);
......
...@@ -196,6 +196,11 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp4 = ...@@ -196,6 +196,11 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp4 =
.packet = udp_packet, .packet = udp_packet,
.new = udp_new, .new = udp_new,
.error = udp_error4, .error = udp_error4,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
.nfattr_to_tuple = nf_ct_port_nfattr_to_tuple,
#endif
}; };
struct nf_conntrack_protocol nf_conntrack_protocol_udp6 = struct nf_conntrack_protocol nf_conntrack_protocol_udp6 =
...@@ -210,6 +215,11 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp6 = ...@@ -210,6 +215,11 @@ struct nf_conntrack_protocol nf_conntrack_protocol_udp6 =
.packet = udp_packet, .packet = udp_packet,
.new = udp_new, .new = udp_new,
.error = udp_error6, .error = udp_error6,
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
.tuple_to_nfattr = nf_ct_port_tuple_to_nfattr,
.nfattr_to_tuple = nf_ct_port_nfattr_to_tuple,
#endif
}; };
EXPORT_SYMBOL(nf_conntrack_protocol_udp4); EXPORT_SYMBOL(nf_conntrack_protocol_udp4);
......
...@@ -161,11 +161,11 @@ static int ct_seq_show(struct seq_file *s, void *v) ...@@ -161,11 +161,11 @@ static int ct_seq_show(struct seq_file *s, void *v)
if (NF_CT_DIRECTION(hash)) if (NF_CT_DIRECTION(hash))
return 0; return 0;
l3proto = nf_ct_find_l3proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL] l3proto = __nf_ct_l3proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
.tuple.src.l3num); .tuple.src.l3num);
NF_CT_ASSERT(l3proto); NF_CT_ASSERT(l3proto);
proto = nf_ct_find_proto(conntrack->tuplehash[IP_CT_DIR_ORIGINAL] proto = __nf_ct_proto_find(conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
.tuple.src.l3num, .tuple.src.l3num,
conntrack->tuplehash[IP_CT_DIR_ORIGINAL] conntrack->tuplehash[IP_CT_DIR_ORIGINAL]
.tuple.dst.protonum); .tuple.dst.protonum);
...@@ -307,8 +307,8 @@ static int exp_seq_show(struct seq_file *s, void *v) ...@@ -307,8 +307,8 @@ static int exp_seq_show(struct seq_file *s, void *v)
expect->tuple.src.l3num, expect->tuple.src.l3num,
expect->tuple.dst.protonum); expect->tuple.dst.protonum);
print_tuple(s, &expect->tuple, print_tuple(s, &expect->tuple,
nf_ct_find_l3proto(expect->tuple.src.l3num), __nf_ct_l3proto_find(expect->tuple.src.l3num),
nf_ct_find_proto(expect->tuple.src.l3num, __nf_ct_proto_find(expect->tuple.src.l3num,
expect->tuple.dst.protonum)); expect->tuple.dst.protonum));
return seq_putc(s, '\n'); return seq_putc(s, '\n');
} }
...@@ -847,7 +847,11 @@ EXPORT_SYMBOL(nf_conntrack_helper_unregister); ...@@ -847,7 +847,11 @@ EXPORT_SYMBOL(nf_conntrack_helper_unregister);
EXPORT_SYMBOL(nf_ct_iterate_cleanup); EXPORT_SYMBOL(nf_ct_iterate_cleanup);
EXPORT_SYMBOL(__nf_ct_refresh_acct); EXPORT_SYMBOL(__nf_ct_refresh_acct);
EXPORT_SYMBOL(nf_ct_protos); EXPORT_SYMBOL(nf_ct_protos);
EXPORT_SYMBOL(nf_ct_find_proto); EXPORT_SYMBOL(__nf_ct_proto_find);
EXPORT_SYMBOL(nf_ct_proto_find_get);
EXPORT_SYMBOL(nf_ct_proto_put);
EXPORT_SYMBOL(nf_ct_l3proto_find_get);
EXPORT_SYMBOL(nf_ct_l3proto_put);
EXPORT_SYMBOL(nf_ct_l3protos); EXPORT_SYMBOL(nf_ct_l3protos);
EXPORT_SYMBOL(nf_conntrack_expect_alloc); EXPORT_SYMBOL(nf_conntrack_expect_alloc);
EXPORT_SYMBOL(nf_conntrack_expect_put); EXPORT_SYMBOL(nf_conntrack_expect_put);
...@@ -867,3 +871,21 @@ EXPORT_SYMBOL(nf_ct_get_tuple); ...@@ -867,3 +871,21 @@ EXPORT_SYMBOL(nf_ct_get_tuple);
EXPORT_SYMBOL(nf_ct_invert_tuple); EXPORT_SYMBOL(nf_ct_invert_tuple);
EXPORT_SYMBOL(nf_conntrack_in); EXPORT_SYMBOL(nf_conntrack_in);
EXPORT_SYMBOL(__nf_conntrack_attach); EXPORT_SYMBOL(__nf_conntrack_attach);
EXPORT_SYMBOL(nf_conntrack_alloc);
EXPORT_SYMBOL(nf_conntrack_free);
EXPORT_SYMBOL(nf_conntrack_flush);
EXPORT_SYMBOL(nf_ct_remove_expectations);
EXPORT_SYMBOL(nf_ct_helper_find_get);
EXPORT_SYMBOL(nf_ct_helper_put);
EXPORT_SYMBOL(__nf_conntrack_helper_find_byname);
EXPORT_SYMBOL(__nf_conntrack_find);
EXPORT_SYMBOL(nf_ct_unlink_expect);
EXPORT_SYMBOL(nf_conntrack_hash_insert);
EXPORT_SYMBOL(__nf_conntrack_expect_find);
EXPORT_SYMBOL(nf_conntrack_expect_find);
EXPORT_SYMBOL(nf_conntrack_expect_list);
#if defined(CONFIG_NF_CT_NETLINK) || \
defined(CONFIG_NF_CT_NETLINK_MODULE)
EXPORT_SYMBOL(nf_ct_port_tuple_to_nfattr);
EXPORT_SYMBOL(nf_ct_port_nfattr_to_tuple);
#endif
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