Commit 545b2901 authored by David S. Miller's avatar David S. Miller

Merge branch 'master' of git://1984.lsi.us.es/nf-next

Conflicts:
	net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c

Minor conflict due to some IS_ENABLED conversions done
in net-next.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 130cd273 d3976a53
...@@ -240,6 +240,7 @@ struct in6_flowlabel_req { ...@@ -240,6 +240,7 @@ struct in6_flowlabel_req {
* *
* IP6T_SO_GET_REVISION_MATCH 68 * IP6T_SO_GET_REVISION_MATCH 68
* IP6T_SO_GET_REVISION_TARGET 69 * IP6T_SO_GET_REVISION_TARGET 69
* IP6T_SO_ORIGINAL_DST 80
*/ */
/* RFC5014: Source address selection */ /* RFC5014: Source address selection */
......
...@@ -178,6 +178,9 @@ struct ip6t_error { ...@@ -178,6 +178,9 @@ struct ip6t_error {
#define IP6T_SO_GET_REVISION_TARGET (IP6T_BASE_CTL + 5) #define IP6T_SO_GET_REVISION_TARGET (IP6T_BASE_CTL + 5)
#define IP6T_SO_GET_MAX IP6T_SO_GET_REVISION_TARGET #define IP6T_SO_GET_MAX IP6T_SO_GET_REVISION_TARGET
/* obtain original address if REDIRECT'd connection */
#define IP6T_SO_ORIGINAL_DST 80
/* ICMP matching stuff */ /* ICMP matching stuff */
struct ip6t_icmp { struct ip6t_icmp {
__u8 type; /* type to match */ __u8 type; /* type to match */
......
...@@ -276,9 +276,7 @@ static int __net_init iptable_nat_net_init(struct net *net) ...@@ -276,9 +276,7 @@ static int __net_init iptable_nat_net_init(struct net *net)
return -ENOMEM; return -ENOMEM;
net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl); net->ipv4.nat_table = ipt_register_table(net, &nf_nat_ipv4_table, repl);
kfree(repl); kfree(repl);
if (IS_ERR(net->ipv4.nat_table)) return PTR_RET(net->ipv4.nat_table);
return PTR_ERR(net->ipv4.nat_table);
return 0;
} }
static void __net_exit iptable_nat_net_exit(struct net *net) static void __net_exit iptable_nat_net_exit(struct net *net)
......
...@@ -277,9 +277,7 @@ static int __net_init ip6table_nat_net_init(struct net *net) ...@@ -277,9 +277,7 @@ static int __net_init ip6table_nat_net_init(struct net *net)
return -ENOMEM; return -ENOMEM;
net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl); net->ipv6.ip6table_nat = ip6t_register_table(net, &nf_nat_ipv6_table, repl);
kfree(repl); kfree(repl);
if (IS_ERR(net->ipv6.ip6table_nat)) return PTR_RET(net->ipv6.ip6table_nat);
return PTR_ERR(net->ipv6.ip6table_nat);
return 0;
} }
static void __net_exit ip6table_nat_net_exit(struct net *net) static void __net_exit ip6table_nat_net_exit(struct net *net)
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/netfilter_bridge.h> #include <linux/netfilter_bridge.h>
#include <linux/netfilter_ipv6.h> #include <linux/netfilter_ipv6.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack.h>
#include <net/netfilter/nf_conntrack_helper.h> #include <net/netfilter/nf_conntrack_helper.h>
#include <net/netfilter/nf_conntrack_l4proto.h> #include <net/netfilter/nf_conntrack_l4proto.h>
...@@ -295,6 +296,55 @@ static struct nf_hook_ops ipv6_conntrack_ops[] __read_mostly = { ...@@ -295,6 +296,55 @@ 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));
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;
}
#if IS_ENABLED(CONFIG_NF_CT_NETLINK) #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
#include <linux/netfilter/nfnetlink.h> #include <linux/netfilter/nfnetlink.h>
...@@ -359,6 +409,14 @@ MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6)); ...@@ -359,6 +409,14 @@ MODULE_ALIAS("nf_conntrack-" __stringify(AF_INET6));
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>"); MODULE_AUTHOR("Yasuyuki KOZAKAI @USAGI <yasuyuki.kozakai@toshiba.co.jp>");
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) static int ipv6_net_init(struct net *net)
{ {
int ret = 0; int ret = 0;
...@@ -425,6 +483,12 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) ...@@ -425,6 +483,12 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
need_conntrack(); need_conntrack();
nf_defrag_ipv6_enable(); 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); ret = register_pernet_subsys(&ipv6_net_ops);
if (ret < 0) if (ret < 0)
goto cleanup_pernet; goto cleanup_pernet;
...@@ -440,6 +504,7 @@ static int __init nf_conntrack_l3proto_ipv6_init(void) ...@@ -440,6 +504,7 @@ static int __init nf_conntrack_l3proto_ipv6_init(void)
cleanup_ipv6: cleanup_ipv6:
unregister_pernet_subsys(&ipv6_net_ops); unregister_pernet_subsys(&ipv6_net_ops);
cleanup_pernet: cleanup_pernet:
nf_unregister_sockopt(&so_getorigdst6);
return ret; return ret;
} }
...@@ -448,6 +513,7 @@ static void __exit nf_conntrack_l3proto_ipv6_fini(void) ...@@ -448,6 +513,7 @@ static void __exit nf_conntrack_l3proto_ipv6_fini(void)
synchronize_net(); synchronize_net();
nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops)); nf_unregister_hooks(ipv6_conntrack_ops, ARRAY_SIZE(ipv6_conntrack_ops));
unregister_pernet_subsys(&ipv6_net_ops); unregister_pernet_subsys(&ipv6_net_ops);
nf_unregister_sockopt(&so_getorigdst6);
} }
module_init(nf_conntrack_l3proto_ipv6_init); module_init(nf_conntrack_l3proto_ipv6_init);
......
...@@ -82,7 +82,7 @@ void ...@@ -82,7 +82,7 @@ void
ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp, int outin) ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp, int outin)
{ {
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
struct nf_conntrack_tuple new_tuple; struct nf_conntrack_tuple new_tuple;
if (ct == NULL || nf_ct_is_confirmed(ct) || nf_ct_is_untracked(ct) || if (ct == NULL || nf_ct_is_confirmed(ct) || nf_ct_is_untracked(ct) ||
......
...@@ -594,7 +594,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -594,7 +594,7 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
#if IS_ENABLED(CONFIG_NF_CONNTRACK) #if IS_ENABLED(CONFIG_NF_CONNTRACK)
if (cp->flags & IP_VS_CONN_F_SYNC && local) { if (cp->flags & IP_VS_CONN_F_SYNC && local) {
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
if (ct && !nf_ct_is_untracked(ct)) { if (ct && !nf_ct_is_untracked(ct)) {
IP_VS_DBG_RL_PKT(10, AF_INET, pp, skb, 0, IP_VS_DBG_RL_PKT(10, AF_INET, pp, skb, 0,
...@@ -710,7 +710,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -710,7 +710,7 @@ ip_vs_nat_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
#if IS_ENABLED(CONFIG_NF_CONNTRACK) #if IS_ENABLED(CONFIG_NF_CONNTRACK)
if (cp->flags & IP_VS_CONN_F_SYNC && local) { if (cp->flags & IP_VS_CONN_F_SYNC && local) {
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
if (ct && !nf_ct_is_untracked(ct)) { if (ct && !nf_ct_is_untracked(ct)) {
IP_VS_DBG_RL_PKT(10, AF_INET6, pp, skb, 0, IP_VS_DBG_RL_PKT(10, AF_INET6, pp, skb, 0,
...@@ -1235,7 +1235,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -1235,7 +1235,7 @@ ip_vs_icmp_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
#if IS_ENABLED(CONFIG_NF_CONNTRACK) #if IS_ENABLED(CONFIG_NF_CONNTRACK)
if (cp->flags & IP_VS_CONN_F_SYNC && local) { if (cp->flags & IP_VS_CONN_F_SYNC && local) {
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
if (ct && !nf_ct_is_untracked(ct)) { if (ct && !nf_ct_is_untracked(ct)) {
IP_VS_DBG(10, "%s(): " IP_VS_DBG(10, "%s(): "
...@@ -1356,7 +1356,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, ...@@ -1356,7 +1356,7 @@ ip_vs_icmp_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp,
#if IS_ENABLED(CONFIG_NF_CONNTRACK) #if IS_ENABLED(CONFIG_NF_CONNTRACK)
if (cp->flags & IP_VS_CONN_F_SYNC && local) { if (cp->flags & IP_VS_CONN_F_SYNC && local) {
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
struct nf_conn *ct = ct = nf_ct_get(skb, &ctinfo); struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
if (ct && !nf_ct_is_untracked(ct)) { if (ct && !nf_ct_is_untracked(ct)) {
IP_VS_DBG(10, "%s(): " IP_VS_DBG(10, "%s(): "
......
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