diff options
Diffstat (limited to 'net/netfilter/nf_conntrack_netlink.c')
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 264 |
1 files changed, 211 insertions, 53 deletions
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 7d23124..38141f1 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -59,7 +59,7 @@ ctnetlink_dump_tuples_proto(struct sk_buff *skb, nest_parms = nla_nest_start(skb, CTA_TUPLE_PROTO | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; - NLA_PUT(skb, CTA_PROTO_NUM, sizeof(u_int8_t), &tuple->dst.protonum); + NLA_PUT_U8(skb, CTA_PROTO_NUM, tuple->dst.protonum); if (likely(l4proto->tuple_to_nlattr)) ret = l4proto->tuple_to_nlattr(skb, tuple); @@ -95,7 +95,7 @@ nla_put_failure: return -1; } -static inline int +static int ctnetlink_dump_tuples(struct sk_buff *skb, const struct nf_conntrack_tuple *tuple) { @@ -120,8 +120,7 @@ ctnetlink_dump_tuples(struct sk_buff *skb, static inline int ctnetlink_dump_status(struct sk_buff *skb, const struct nf_conn *ct) { - __be32 status = htonl((u_int32_t) ct->status); - NLA_PUT(skb, CTA_STATUS, sizeof(status), &status); + NLA_PUT_BE32(skb, CTA_STATUS, htonl(ct->status)); return 0; nla_put_failure: @@ -131,15 +130,12 @@ nla_put_failure: static inline int ctnetlink_dump_timeout(struct sk_buff *skb, const struct nf_conn *ct) { - long timeout_l = ct->timeout.expires - jiffies; - __be32 timeout; + long timeout = (ct->timeout.expires - jiffies) / HZ; - if (timeout_l < 0) + if (timeout < 0) timeout = 0; - else - timeout = htonl(timeout_l / HZ); - NLA_PUT(skb, CTA_TIMEOUT, sizeof(timeout), &timeout); + NLA_PUT_BE32(skb, CTA_TIMEOUT, htonl(timeout)); return 0; nla_put_failure: @@ -193,7 +189,7 @@ ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) nest_helper = nla_nest_start(skb, CTA_HELP | NLA_F_NESTED); if (!nest_helper) goto nla_put_failure; - NLA_PUT(skb, CTA_HELP_NAME, strlen(helper->name), helper->name); + NLA_PUT_STRING(skb, CTA_HELP_NAME, helper->name); if (helper->to_nlattr) helper->to_nlattr(skb, ct); @@ -209,23 +205,21 @@ nla_put_failure: } #ifdef CONFIG_NF_CT_ACCT -static inline int +static int ctnetlink_dump_counters(struct sk_buff *skb, const struct nf_conn *ct, enum ip_conntrack_dir dir) { enum ctattr_type type = dir ? CTA_COUNTERS_REPLY: CTA_COUNTERS_ORIG; struct nlattr *nest_count; - __be32 tmp; nest_count = nla_nest_start(skb, type | NLA_F_NESTED); if (!nest_count) goto nla_put_failure; - tmp = htonl(ct->counters[dir].packets); - NLA_PUT(skb, CTA_COUNTERS32_PACKETS, sizeof(u_int32_t), &tmp); - - tmp = htonl(ct->counters[dir].bytes); - NLA_PUT(skb, CTA_COUNTERS32_BYTES, sizeof(u_int32_t), &tmp); + NLA_PUT_BE32(skb, CTA_COUNTERS32_PACKETS, + htonl(ct->counters[dir].packets)); + NLA_PUT_BE32(skb, CTA_COUNTERS32_BYTES, + htonl(ct->counters[dir].bytes)); nla_nest_end(skb, nest_count); @@ -242,9 +236,7 @@ nla_put_failure: static inline int ctnetlink_dump_mark(struct sk_buff *skb, const struct nf_conn *ct) { - __be32 mark = htonl(ct->mark); - - NLA_PUT(skb, CTA_MARK, sizeof(u_int32_t), &mark); + NLA_PUT_BE32(skb, CTA_MARK, htonl(ct->mark)); return 0; nla_put_failure: @@ -254,11 +246,95 @@ nla_put_failure: #define ctnetlink_dump_mark(a, b) (0) #endif +#ifdef CONFIG_NF_CONNTRACK_SECMARK +static inline int +ctnetlink_dump_secmark(struct sk_buff *skb, const struct nf_conn *ct) +{ + NLA_PUT_BE32(skb, CTA_SECMARK, htonl(ct->secmark)); + return 0; + +nla_put_failure: + return -1; +} +#else +#define ctnetlink_dump_secmark(a, b) (0) +#endif + +#define master_tuple(ct) &(ct->master->tuplehash[IP_CT_DIR_ORIGINAL].tuple) + +static inline int +ctnetlink_dump_master(struct sk_buff *skb, const struct nf_conn *ct) +{ + struct nlattr *nest_parms; + + if (!(ct->status & IPS_EXPECTED)) + return 0; + + nest_parms = nla_nest_start(skb, CTA_TUPLE_MASTER | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; + if (ctnetlink_dump_tuples(skb, master_tuple(ct)) < 0) + goto nla_put_failure; + nla_nest_end(skb, nest_parms); + + return 0; + +nla_put_failure: + return -1; +} + +#ifdef CONFIG_NF_NAT_NEEDED +static int +dump_nat_seq_adj(struct sk_buff *skb, const struct nf_nat_seq *natseq, int type) +{ + struct nlattr *nest_parms; + + nest_parms = nla_nest_start(skb, type | NLA_F_NESTED); + if (!nest_parms) + goto nla_put_failure; + + NLA_PUT_BE32(skb, CTA_NAT_SEQ_CORRECTION_POS, + htonl(natseq->correction_pos)); + NLA_PUT_BE32(skb, CTA_NAT_SEQ_OFFSET_BEFORE, + htonl(natseq->offset_before)); + NLA_PUT_BE32(skb, CTA_NAT_SEQ_OFFSET_AFTER, + htonl(natseq->offset_after)); + + nla_nest_end(skb, nest_parms); + + return 0; + +nla_put_failure: + return -1; +} + +static inline int +ctnetlink_dump_nat_seq_adj(struct sk_buff *skb, const struct nf_conn *ct) +{ + struct nf_nat_seq *natseq; + struct nf_conn_nat *nat = nfct_nat(ct); + + if (!(ct->status & IPS_SEQ_ADJUST) || !nat) + return 0; + + natseq = &nat->seq[IP_CT_DIR_ORIGINAL]; + if (dump_nat_seq_adj(skb, natseq, CTA_NAT_SEQ_ADJ_ORIG) == -1) + return -1; + + natseq = &nat->seq[IP_CT_DIR_REPLY]; + if (dump_nat_seq_adj(skb, natseq, CTA_NAT_SEQ_ADJ_REPLY) == -1) + return -1; + + return 0; +} +#else +#define ctnetlink_dump_nat_seq_adj(a, b) (0) +#endif + static inline int ctnetlink_dump_id(struct sk_buff *skb, const struct nf_conn *ct) { - __be32 id = htonl((unsigned long)ct); - NLA_PUT(skb, CTA_ID, sizeof(u_int32_t), &id); + NLA_PUT_BE32(skb, CTA_ID, htonl((unsigned long)ct)); return 0; nla_put_failure: @@ -268,9 +344,7 @@ nla_put_failure: static inline int ctnetlink_dump_use(struct sk_buff *skb, const struct nf_conn *ct) { - __be32 use = htonl(atomic_read(&ct->ct_general.use)); - - NLA_PUT(skb, CTA_USE, sizeof(u_int32_t), &use); + NLA_PUT_BE32(skb, CTA_USE, htonl(atomic_read(&ct->ct_general.use))); return 0; nla_put_failure: @@ -320,8 +394,11 @@ ctnetlink_fill_info(struct sk_buff *skb, u32 pid, u32 seq, ctnetlink_dump_protoinfo(skb, ct) < 0 || ctnetlink_dump_helpinfo(skb, ct) < 0 || ctnetlink_dump_mark(skb, ct) < 0 || + ctnetlink_dump_secmark(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_nat_seq_adj(skb, ct) < 0) goto nla_put_failure; nlh->nlmsg_len = skb_tail_pointer(skb) - b; @@ -419,11 +496,24 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, && ctnetlink_dump_mark(skb, ct) < 0) goto nla_put_failure; #endif +#ifdef CONFIG_NF_CONNTRACK_SECMARK + if ((events & IPCT_SECMARK || ct->secmark) + && ctnetlink_dump_secmark(skb, ct) < 0) + goto nla_put_failure; +#endif if (events & IPCT_COUNTER_FILLING && (ctnetlink_dump_counters(skb, ct, IP_CT_DIR_ORIGINAL) < 0 || ctnetlink_dump_counters(skb, ct, IP_CT_DIR_REPLY) < 0)) goto nla_put_failure; + + if (events & IPCT_RELATED && + ctnetlink_dump_master(skb, ct) < 0) + goto nla_put_failure; + + if (events & IPCT_NATSEQADJ && + ctnetlink_dump_nat_seq_adj(skb, ct) < 0) + goto nla_put_failure; } nlh->nlmsg_len = skb->tail - b; @@ -444,7 +534,7 @@ static int ctnetlink_done(struct netlink_callback *cb) return 0; } -#define L3PROTO(ct) ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num +#define L3PROTO(ct) (ct)->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.l3num static int ctnetlink_dump_table(struct sk_buff *skb, struct netlink_callback *cb) @@ -542,7 +632,7 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr, if (!tb[CTA_PROTO_NUM]) return -EINVAL; - tuple->dst.protonum = *(u_int8_t *)nla_data(tb[CTA_PROTO_NUM]); + tuple->dst.protonum = nla_get_u8(tb[CTA_PROTO_NUM]); l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum); @@ -558,7 +648,7 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr, return ret; } -static inline int +static int ctnetlink_parse_tuple(struct nlattr *cda[], struct nf_conntrack_tuple *tuple, enum ctattr_tuple type, u_int8_t l3num) { @@ -605,7 +695,7 @@ static int nfnetlink_parse_nat_proto(struct nlattr *attr, struct nf_nat_range *range) { struct nlattr *tb[CTA_PROTONAT_MAX+1]; - struct nf_nat_protocol *npt; + const struct nf_nat_protocol *npt; int err; err = nla_parse_nested(tb, CTA_PROTONAT_MAX, attr, protonat_nla_policy); @@ -647,12 +737,12 @@ nfnetlink_parse_nat(struct nlattr *nat, return err; if (tb[CTA_NAT_MINIP]) - range->min_ip = *(__be32 *)nla_data(tb[CTA_NAT_MINIP]); + range->min_ip = nla_get_be32(tb[CTA_NAT_MINIP]); if (!tb[CTA_NAT_MAXIP]) range->max_ip = range->min_ip; else - range->max_ip = *(__be32 *)nla_data(tb[CTA_NAT_MAXIP]); + range->max_ip = nla_get_be32(tb[CTA_NAT_MAXIP]); if (range->min_ip) range->flags |= IP_NAT_RANGE_MAP_IPS; @@ -722,7 +812,7 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, ct = nf_ct_tuplehash_to_ctrack(h); if (cda[CTA_ID]) { - u_int32_t id = ntohl(*(__be32 *)nla_data(cda[CTA_ID])); + u_int32_t id = ntohl(nla_get_be32(cda[CTA_ID])); if (id != (u32)(unsigned long)ct) { nf_ct_put(ct); return -ENOENT; @@ -798,11 +888,11 @@ out: return err; } -static inline int +static int ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[]) { unsigned long d; - unsigned int status = ntohl(*(__be32 *)nla_data(cda[CTA_STATUS])); + unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS])); d = ct->status ^ status; if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) @@ -828,19 +918,17 @@ ctnetlink_change_status(struct nf_conn *ct, struct nlattr *cda[]) if (nfnetlink_parse_nat(cda[CTA_NAT_DST], ct, &range) < 0) return -EINVAL; - if (nf_nat_initialized(ct, - HOOK2MANIP(NF_IP_PRE_ROUTING))) + if (nf_nat_initialized(ct, IP_NAT_MANIP_DST)) return -EEXIST; - nf_nat_setup_info(ct, &range, NF_IP_PRE_ROUTING); + nf_nat_setup_info(ct, &range, IP_NAT_MANIP_DST); } if (cda[CTA_NAT_SRC]) { if (nfnetlink_parse_nat(cda[CTA_NAT_SRC], ct, &range) < 0) return -EINVAL; - if (nf_nat_initialized(ct, - HOOK2MANIP(NF_IP_POST_ROUTING))) + if (nf_nat_initialized(ct, IP_NAT_MANIP_SRC)) return -EEXIST; - nf_nat_setup_info(ct, &range, NF_IP_POST_ROUTING); + nf_nat_setup_info(ct, &range, IP_NAT_MANIP_SRC); } #endif } @@ -904,7 +992,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[]) static inline int ctnetlink_change_timeout(struct nf_conn *ct, struct nlattr *cda[]) { - u_int32_t timeout = ntohl(*(__be32 *)nla_data(cda[CTA_TIMEOUT])); + u_int32_t timeout = ntohl(nla_get_be32(cda[CTA_TIMEOUT])); if (!del_timer(&ct->timeout)) return -ETIME; @@ -935,6 +1023,66 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[]) return err; } +#ifdef CONFIG_NF_NAT_NEEDED +static inline int +change_nat_seq_adj(struct nf_nat_seq *natseq, struct nlattr *attr) +{ + struct nlattr *cda[CTA_NAT_SEQ_MAX+1]; + + nla_parse_nested(cda, CTA_NAT_SEQ_MAX, attr, NULL); + + if (!cda[CTA_NAT_SEQ_CORRECTION_POS]) + return -EINVAL; + + natseq->correction_pos = + ntohl(nla_get_be32(cda[CTA_NAT_SEQ_CORRECTION_POS])); + + if (!cda[CTA_NAT_SEQ_OFFSET_BEFORE]) + return -EINVAL; + + natseq->offset_before = + ntohl(nla_get_be32(cda[CTA_NAT_SEQ_OFFSET_BEFORE])); + + if (!cda[CTA_NAT_SEQ_OFFSET_AFTER]) + return -EINVAL; + + natseq->offset_after = + ntohl(nla_get_be32(cda[CTA_NAT_SEQ_OFFSET_AFTER])); + + return 0; +} + +static int +ctnetlink_change_nat_seq_adj(struct nf_conn *ct, struct nlattr *cda[]) +{ + int ret = 0; + struct nf_conn_nat *nat = nfct_nat(ct); + + if (!nat) + return 0; + + if (cda[CTA_NAT_SEQ_ADJ_ORIG]) { + ret = change_nat_seq_adj(&nat->seq[IP_CT_DIR_ORIGINAL], + cda[CTA_NAT_SEQ_ADJ_ORIG]); + if (ret < 0) + return ret; + + ct->status |= IPS_SEQ_ADJUST; + } + + if (cda[CTA_NAT_SEQ_ADJ_REPLY]) { + ret = change_nat_seq_adj(&nat->seq[IP_CT_DIR_REPLY], + cda[CTA_NAT_SEQ_ADJ_REPLY]); + if (ret < 0) + return ret; + + ct->status |= IPS_SEQ_ADJUST; + } + + return 0; +} +#endif + static int ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[]) { @@ -966,7 +1114,15 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[]) #if defined(CONFIG_NF_CONNTRACK_MARK) if (cda[CTA_MARK]) - ct->mark = ntohl(*(__be32 *)nla_data(cda[CTA_MARK])); + ct->mark = ntohl(nla_get_be32(cda[CTA_MARK])); +#endif + +#ifdef CONFIG_NF_NAT_NEEDED + if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) { + err = ctnetlink_change_nat_seq_adj(ct, cda); + if (err < 0) + return err; + } #endif return 0; @@ -989,7 +1145,7 @@ ctnetlink_create_conntrack(struct nlattr *cda[], if (!cda[CTA_TIMEOUT]) goto err; - ct->timeout.expires = ntohl(*(__be32 *)nla_data(cda[CTA_TIMEOUT])); + ct->timeout.expires = ntohl(nla_get_be32(cda[CTA_TIMEOUT])); ct->timeout.expires = jiffies + ct->timeout.expires * HZ; ct->status |= IPS_CONFIRMED; @@ -1008,7 +1164,7 @@ ctnetlink_create_conntrack(struct nlattr *cda[], #if defined(CONFIG_NF_CONNTRACK_MARK) if (cda[CTA_MARK]) - ct->mark = ntohl(*(__be32 *)nla_data(cda[CTA_MARK])); + ct->mark = ntohl(nla_get_be32(cda[CTA_MARK])); #endif helper = nf_ct_helper_find_get(rtuple); @@ -1193,13 +1349,15 @@ nla_put_failure: return -1; } -static inline int +static int ctnetlink_exp_dump_expect(struct sk_buff *skb, const struct nf_conntrack_expect *exp) { struct nf_conn *master = exp->master; - __be32 timeout = htonl((exp->timeout.expires - jiffies) / HZ); - __be32 id = htonl((unsigned long)exp); + long timeout = (exp->timeout.expires - jiffies) / HZ; + + if (timeout < 0) + timeout = 0; if (ctnetlink_exp_dump_tuple(skb, &exp->tuple, CTA_EXPECT_TUPLE) < 0) goto nla_put_failure; @@ -1210,8 +1368,8 @@ ctnetlink_exp_dump_expect(struct sk_buff *skb, CTA_EXPECT_MASTER) < 0) goto nla_put_failure; - NLA_PUT(skb, CTA_EXPECT_TIMEOUT, sizeof(timeout), &timeout); - NLA_PUT(skb, CTA_EXPECT_ID, sizeof(u_int32_t), &id); + NLA_PUT_BE32(skb, CTA_EXPECT_TIMEOUT, htonl(timeout)); + NLA_PUT_BE32(skb, CTA_EXPECT_ID, htonl((unsigned long)exp)); return 0; @@ -1384,7 +1542,7 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, return -ENOENT; if (cda[CTA_EXPECT_ID]) { - __be32 id = *(__be32 *)nla_data(cda[CTA_EXPECT_ID]); + __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]); if (ntohl(id) != (u32)(unsigned long)exp) { nf_ct_expect_put(exp); return -ENOENT; @@ -1438,7 +1596,7 @@ ctnetlink_del_expect(struct sock *ctnl, struct sk_buff *skb, return -ENOENT; if (cda[CTA_EXPECT_ID]) { - __be32 id = *(__be32 *)nla_data(cda[CTA_EXPECT_ID]); + __be32 id = nla_get_be32(cda[CTA_EXPECT_ID]); if (ntohl(id) != (u32)(unsigned long)exp) { nf_ct_expect_put(exp); return -ENOENT; |