#include <linux/netlink.h>
#include <linux/spinlock.h>
#include <linux/notifier.h>
-#include <linux/rtnetlink.h>
#include <linux/netfilter.h>
-#include <linux/netfilter_ipv4.h>
-#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
#include <linux/netfilter_ipv4/ip_conntrack_core.h>
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
const struct ip_conntrack_tuple *tuple)
{
struct ip_conntrack_protocol *proto;
+ int ret = 0;
NFA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum);
proto = ip_conntrack_proto_find_get(tuple->dst.protonum);
- if (proto && proto->tuple_to_nfattr)
- return proto->tuple_to_nfattr(skb, tuple);
+ if (likely(proto && proto->tuple_to_nfattr)) {
+ ret = proto->tuple_to_nfattr(skb, tuple);
+ ip_conntrack_proto_put(proto);
+ }
- return 0;
+ return ret;
nfattr_failure:
return -1;
{
enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG;
struct nfattr *nest_count = NFA_NEST(skb, type);
- u_int64_t tmp;
+ u_int32_t tmp;
- tmp = cpu_to_be64(ct->counters[dir].packets);
- NFA_PUT(skb, CTA_COUNTERS_PACKETS, sizeof(u_int64_t), &tmp);
+ tmp = htonl(ct->counters[dir].packets);
+ NFA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp);
- tmp = cpu_to_be64(ct->counters[dir].bytes);
- NFA_PUT(skb, CTA_COUNTERS_BYTES, sizeof(u_int64_t), &tmp);
+ tmp = htonl(ct->counters[dir].bytes);
+ NFA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp);
NFA_NEST_END(skb, nest_count);
DEBUGP("entered %s\n", __FUNCTION__);
-
- if (nfattr_parse_nested(tb, CTA_IP_MAX, attr) < 0)
- goto nfattr_failure;
+ nfattr_parse_nested(tb, CTA_IP_MAX, attr);
if (nfattr_bad_size(tb, CTA_IP_MAX, cta_min_ip))
return -EINVAL;
DEBUGP("leaving\n");
return 0;
-
-nfattr_failure:
- return -1;
}
static const int cta_min_proto[CTA_PROTO_MAX] = {
DEBUGP("entered %s\n", __FUNCTION__);
- if (nfattr_parse_nested(tb, CTA_PROTO_MAX, attr) < 0)
- goto nfattr_failure;
+ nfattr_parse_nested(tb, CTA_PROTO_MAX, attr);
if (nfattr_bad_size(tb, CTA_PROTO_MAX, cta_min_proto))
return -EINVAL;
}
return ret;
-
-nfattr_failure:
- return -1;
}
static inline int
memset(tuple, 0, sizeof(*tuple));
- if (nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]) < 0)
- goto nfattr_failure;
+ nfattr_parse_nested(tb, CTA_TUPLE_MAX, cda[type-1]);
if (!tb[CTA_TUPLE_IP-1])
return -EINVAL;
DEBUGP("leaving\n");
return 0;
-
-nfattr_failure:
- return -1;
}
#ifdef CONFIG_IP_NF_NAT_NEEDED
DEBUGP("entered %s\n", __FUNCTION__);
- if (nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr) < 0)
- goto nfattr_failure;
+ nfattr_parse_nested(tb, CTA_PROTONAT_MAX, attr);
if (nfattr_bad_size(tb, CTA_PROTONAT_MAX, cta_min_protonat))
- goto nfattr_failure;
+ return -EINVAL;
npt = ip_nat_proto_find_get(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum);
if (!npt)
DEBUGP("leaving\n");
return 0;
-
-nfattr_failure:
- return -1;
}
static inline int
memset(range, 0, sizeof(*range));
- if (nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]) < 0)
- goto nfattr_failure;
+ nfattr_parse_nested(tb, CTA_NAT_MAX, cda[CTA_NAT-1]);
if (tb[CTA_NAT_MINIP-1])
range->min_ip = *(u_int32_t *)NFA_DATA(tb[CTA_NAT_MINIP-1]);
DEBUGP("leaving\n");
return 0;
-
-nfattr_failure:
- return -1;
}
#endif
DEBUGP("entered %s\n", __FUNCTION__);
- if (nfattr_parse_nested(tb, CTA_HELP_MAX, attr) < 0)
- goto nfattr_failure;
+ nfattr_parse_nested(tb, CTA_HELP_MAX, attr);
if (!tb[CTA_HELP_NAME-1])
return -EINVAL;
*helper_name = NFA_DATA(tb[CTA_HELP_NAME-1]);
return 0;
-
-nfattr_failure:
- return -1;
}
static int
ct = tuplehash_to_ctrack(h);
err = -ENOMEM;
- skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
+ skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb2) {
ip_conntrack_put(ct);
return -ENOMEM;
IPCTNL_MSG_CT_NEW, 1, ct);
ip_conntrack_put(ct);
if (err <= 0)
- goto out;
+ goto free;
err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
if (err < 0)
DEBUGP("leaving\n");
return 0;
+free:
+ kfree_skb(skb2);
out:
- if (skb2)
- kfree_skb(skb2);
return -1;
}
static inline int
ctnetlink_change_status(struct ip_conntrack *ct, struct nfattr *cda[])
{
- unsigned long d, status = *(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]);
+ unsigned long d;
+ unsigned status = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_STATUS-1]));
d = ct->status ^ status;
if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING))
return 0;
}
+static inline int
+ctnetlink_change_protoinfo(struct ip_conntrack *ct, struct nfattr *cda[])
+{
+ struct nfattr *tb[CTA_PROTOINFO_MAX], *attr = cda[CTA_PROTOINFO-1];
+ struct ip_conntrack_protocol *proto;
+ u_int16_t npt = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum;
+ int err = 0;
+
+ nfattr_parse_nested(tb, CTA_PROTOINFO_MAX, attr);
+
+ proto = ip_conntrack_proto_find_get(npt);
+ if (!proto)
+ return -EINVAL;
+
+ if (proto->from_nfattr)
+ err = proto->from_nfattr(tb, ct);
+ ip_conntrack_proto_put(proto);
+
+ return err;
+}
+
static int
ctnetlink_change_conntrack(struct ip_conntrack *ct, struct nfattr *cda[])
{
return err;
}
+ if (cda[CTA_PROTOINFO-1]) {
+ err = ctnetlink_change_protoinfo(ct, cda);
+ if (err < 0)
+ return err;
+ }
+
+#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
+ if (cda[CTA_MARK-1])
+ ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
+#endif
+
DEBUGP("all done\n");
return 0;
}
if (err < 0)
goto err;
+ if (cda[CTA_PROTOINFO-1]) {
+ err = ctnetlink_change_protoinfo(ct, cda);
+ if (err < 0)
+ return err;
+ }
+
ct->helper = ip_conntrack_helper_find_get(rtuple);
add_timer(&ct->timeout);
if (ct->helper)
ip_conntrack_helper_put(ct->helper);
+#if defined(CONFIG_IP_NF_CONNTRACK_MARK)
+ if (cda[CTA_MARK-1])
+ ct->mark = ntohl(*(u_int32_t *)NFA_DATA(cda[CTA_MARK-1]));
+#endif
+
DEBUGP("conntrack with id %u inserted\n", ct->id);
return 0;
nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW,
1, exp);
if (err <= 0)
- goto out;
+ goto free;
ip_conntrack_expect_put(exp);
- err = netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
- if (err < 0)
- goto free;
-
- return err;
+ return netlink_unicast(ctnl, skb2, NETLINK_CB(skb).pid, MSG_DONTWAIT);
+free:
+ kfree_skb(skb2);
out:
ip_conntrack_expect_put(exp);
-free:
- if (skb2)
- kfree_skb(skb2);
return err;
}
.cb = ctnl_exp_cb,
};
+MODULE_ALIAS_NFNL_SUBSYS(NFNL_SUBSYS_CTNETLINK);
+
static int __init ctnetlink_init(void)
{
int ret;