From 6229b75d8da5a4eed7bb668de757e252986c2305 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Sun, 28 Oct 2012 14:40:44 +0000 Subject: netfilter: nf_nat: use PTR_RET Use PTR_RET rather than if(IS_ERR(...)) + PTR_ERR Generated by: coccinelle/api/ptr_ret.cocci Reported-by: Fengguang Wu Signed-off-by: Fengguang Wu Signed-off-by: Pablo Neira Ayuso --- net/ipv6/netfilter/ip6table_nat.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'net/ipv6/netfilter') diff --git a/net/ipv6/netfilter/ip6table_nat.c b/net/ipv6/netfilter/ip6table_nat.c index e418bd6..4c8219e 100644 --- a/net/ipv6/netfilter/ip6table_nat.c +++ b/net/ipv6/netfilter/ip6table_nat.c @@ -275,9 +275,7 @@ static int __net_init ip6table_nat_net_init(struct net *net) return -ENOMEM; net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl); kfree(repl); - if (IS_ERR(net->ipv6.ip6table_nat)) - return PTR_ERR(net->ipv6.ip6table_nat); - return 0; + return PTR_RET(net->ipv6.ip6table_nat); } static void __net_exit ip6table_nat_net_exit(struct net *net) -- cgit v1.1 From 121d1e0941e05c64ee4223064dd83eb24e871739 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 30 Oct 2012 01:08:49 +0000 Subject: netfilter: ipv6: add getsockopt to retrieve origdst userspace can query the original ipv4 destination address of a REDIRECTed connection via getsockopt(m_sock, SOL_IP, SO_ORIGINAL_DST, &m_server_addr, &addrsize) but for ipv6 no such option existed. This adds getsockopt(..., IPPROTO_IPV6, IP6T_SO_ORIGINAL_DST, ...). Without this, userspace needs to parse /proc or use ctnetlink, which appears to be overkill. This uses option number 80 for IP6T_SO_ORIGINAL_DST, which is spare, to use the same number we use in the IPv4 socket option SO_ORIGINAL_DST. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 61 ++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) (limited to 'net/ipv6/netfilter') diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 8860d23..02dcafd 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -295,6 +296,50 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { }, }; +static int +ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len) +{ + const struct inet_sock *inet = inet_sk(sk); + const struct ipv6_pinfo *inet6 = inet6_sk(sk); + const struct nf_conntrack_tuple_hash *h; + struct sockaddr_in6 sin6; + struct nf_conntrack_tuple tuple = { .src.l3num = NFPROTO_IPV6 }; + struct nf_conn *ct; + + tuple.src.u3.in6 = inet6->rcv_saddr; + tuple.src.u.tcp.port = inet->inet_sport; + tuple.dst.u3.in6 = inet6->daddr; + tuple.dst.u.tcp.port = inet->inet_dport; + tuple.dst.protonum = sk->sk_protocol; + + if (sk->sk_protocol != IPPROTO_TCP && sk->sk_protocol != IPPROTO_SCTP) + return -ENOPROTOOPT; + + if (*len < 0 || (unsigned int) *len < sizeof(sin6)) + return -EINVAL; + + h = nf_conntrack_find_get(sock_net(sk), NF_CT_DEFAULT_ZONE, &tuple); + if (!h) { + pr_debug("IP6T_SO_ORIGINAL_DST: Can't find %pI6c/%u-%pI6c/%u.\n", + &tuple.src.u3.ip6, ntohs(tuple.src.u.tcp.port), + &tuple.dst.u3.ip6, ntohs(tuple.dst.u.tcp.port)); + return -ENOENT; + } + + ct = nf_ct_tuplehash_to_ctrack(h); + + sin6.sin6_family = AF_INET6; + sin6.sin6_port = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u.tcp.port; + sin6.sin6_flowinfo = inet6->flow_label & IPV6_FLOWINFO_MASK; + memcpy(&sin6.sin6_addr, + &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6, + sizeof(sin6.sin6_addr)); + sin6.sin6_scope_id = sk->sk_bound_dev_if; + + nf_ct_put(ct); + return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0; +} + #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) #include @@ -359,6 +404,14 @@ MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI "); +static struct nf_sockopt_ops so_getorigdst6 = { + .pf = NFPROTO_IPV6, + .get_optmin = IP6T_SO_ORIGINAL_DST, + .get_optmax = IP6T_SO_ORIGINAL_DST + 1, + .get = ipv6_getorigdst, + .owner = THIS_MODULE, +}; + static int ipv6_net_init(struct net *net) { int ret = 0; @@ -425,6 +478,12 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) need_conntrack(); nf_defrag_ipv6_enable(); + ret = nf_register_sockopt(&so_getorigdst6); + if (ret < 0) { + pr_err("Unable to register netfilter socket option\n"); + return ret; + } + ret = register_pernet_subsys(&ipv6_net_ops); if (ret < 0) goto cleanup_pernet; @@ -440,6 +499,7 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) cleanup_ipv6: unregister_pernet_subsys(&ipv6_net_ops); cleanup_pernet: + nf_unregister_sockopt(&so_getorigdst6); return ret; } @@ -448,6 +508,7 @@ static void __exit nf_conntrack_l3proto_ipv6_fini(void) synchronize_net(); nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); unregister_pernet_subsys(&ipv6_net_ops); + nf_unregister_sockopt(&so_getorigdst6); } module_init(nf_conntrack_l3proto_ipv6_init); -- cgit v1.1 From d3976a53ce1f4763cb910d047e8763e4c696e5f7 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Tue, 13 Nov 2012 00:17:24 +0000 Subject: netfilter: ipv6: only provide sk_bound_dev_if for link-local addr yoshfuji points out that sk_bound_dev_if should only be provided for link-local addresses. IPv6 getpeer/sockname also has this test, i.e. we will now only set sin6_scope_id if the original(!) destination was a link-local address. Reported-by: YOSHIFUJI Hideaki Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso --- net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'net/ipv6/netfilter') diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index 02dcafd..e5f6cf7 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -334,9 +334,14 @@ ipv6_getorigdst(struct sock *sk, int optval, void __user *user, int *len) memcpy(&sin6.sin6_addr, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.in6, sizeof(sin6.sin6_addr)); - sin6.sin6_scope_id = sk->sk_bound_dev_if; nf_ct_put(ct); + + if (ipv6_addr_type(&sin6.sin6_addr) & IPV6_ADDR_LINKLOCAL) + sin6.sin6_scope_id = sk->sk_bound_dev_if; + else + sin6.sin6_scope_id = 0; + return copy_to_user(user, &sin6, sizeof(sin6)) ? -EFAULT : 0; } -- cgit v1.1