From 2198dfa3c6db25b9ba5f67d3080869b8d37fb60e Mon Sep 17 00:00:00 2001 From: Daniel Hokka Zakrisson Date: Fri, 6 Jul 2007 14:55:57 +0000 Subject: [PATCH] IPv6 support for VServer --- Documentation/vserver/debug.txt | 14 ++ include/linux/vs_network.h | 31 +++ include/linux/vserver/debug.h | 5 - include/linux/vserver/network.h | 28 ++- include/linux/vserver/network_cmd.h | 19 +- include/net/addrconf.h | 6 +- include/net/ipv6.h | 1 + kernel/vserver/network.c | 283 +++++++++++++++++++++++++--- kernel/vserver/proc.c | 7 + net/ipv4/af_inet.c | 8 +- net/ipv6/addrconf.c | 86 ++++++--- net/ipv6/af_inet6.c | 63 ++++++- net/ipv6/inet6_hashtables.c | 24 +++ net/ipv6/ip6_output.c | 4 +- net/ipv6/ndisc.c | 2 +- net/ipv6/raw.c | 23 ++- net/ipv6/route.c | 2 +- net/ipv6/tcp_ipv6.c | 15 +- net/ipv6/udp.c | 16 ++ net/ipv6/xfrm6_policy.c | 2 +- net/sctp/ipv6.c | 2 +- net/socket.c | 10 +- 22 files changed, 574 insertions(+), 77 deletions(-) diff --git a/Documentation/vserver/debug.txt b/Documentation/vserver/debug.txt index 4464a0f45..188b49f0d 100644 --- a/Documentation/vserver/debug.txt +++ b/Documentation/vserver/debug.txt @@ -51,9 +51,17 @@ debug_misc: debug_net: 2 4 "nx_addr_conflict(%p,%p) %d.%d,%d.%d" + "nx_addr6_conflict(%u,%u)" 3 8 "inet_bind(%p) %d.%d.%d.%d, %d.%d.%d.%d, %d.%d.%d.%d" "inet_bind(%p)* %p,%p;%lx %d.%d.%d.%d" + "inet6_bind(" NIP6_FMT ", %d): EADDRNOTAVAIL" + "inet6_bind(" NIP6_FMT ", %d): PASS" + "rawv6_bind(" NIP6_FMT ", %d): EADDRNOTAVAIL" + "rawv6_bind(" NIP6_FMT ", %d): PASS" 4 10 "ip_route_connect(%p) %p,%p;%lx" + "inet6_create(%p, %d): %d" + "tcp_v6_connect(dest ::1 redirected to: " NIP6_FMT ", %d)" + "__sock_create(%d, %d, %d, %p, %d): EAFNOSUPPORT" 5 20 "__addr_in_socket(%p,%d.%d.%d.%d) %p:%d.%d.%d.%d %p;%lx" 6 40 "sk,egf: %p [#%d] (from %d)" "sk,egn: %p [#%d] (from %d)" @@ -73,6 +81,12 @@ debug_nid: "dealloc_nx_info(%p)" 1 2 "alloc_nx_info(%d)*" "create_nx_info(%d)*" + "vc_net_add(%d, data[%d]): %d.%d.%d.%d" + "vc_net_add(%d, data[%d]): %d.%d.%d.%d EXISTS" + "vc_net_add(%d, data[%d]): %x:%x:%x:%x:%x:%x:%x:%x" + "vc_net_add(%d, data[%d]): %x:%x:%x:%x:%x:%x:%x:%x EXISTS" + "vc_net_remove(%d, data[%d]): %d.%d.%d.%d" + "vc_net_remove(%d, data[%d]): %x:%x:%x:%x:%x:%x:%x:%x" 2 4 "get_nx_info(%p[#%d.%d])" "put_nx_info(%p[#%d.%d])" 3 8 "claim_nx_info(%p[#%d.%d.%d]) %p" diff --git a/include/linux/vs_network.h b/include/linux/vs_network.h index a99d0e49d..0600425e8 100644 --- a/include/linux/vs_network.h +++ b/include/linux/vs_network.h @@ -162,6 +162,9 @@ static inline int addr_in_nx_info(struct nx_info *nxi, uint32_t addr) return 1; n = nxi->nbipv4; + /* Special case accept anything if addr[0] == :: + * FIXME either accept this on any position or adjust address + * addition in kernel/vserver/network.c */ if (n && (nxi->ipv4[0] == 0)) return 1; for (i=0; inx_info, p); } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +#include + +static inline int addr6_in_nx_info(struct nx_info *nxi, const struct in6_addr *addr) +{ + int n,i; + + if (!nxi) + return 1; + + n = nxi->nbipv6; + /* Special case accept anything if addr[0] == :: + * FIXME either accept this on any position or adjust address + * addition in kernel/vserver/network.c */ + if (n && nxi->ipv6[0].s6_addr32[0] == 0 && nxi->ipv6[0].s6_addr32[1] == 0 && + nxi->ipv6[0].s6_addr32[2] == 0 && nxi->ipv6[0].s6_addr32[3] == 0) + return 1; + for (i=0; iipv6[i]), addr)) + return 1; + } + return 0; +} + +extern int nx_addr6_conflict(struct nx_info *nxi, struct nx_info *nix2); + +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ #ifdef CONFIG_NETWORK_SECMARK #define skb_tag secmark diff --git a/include/linux/vserver/debug.h b/include/linux/vserver/debug.h index 1b1f34c92..44c970216 100644 --- a/include/linux/vserver/debug.h +++ b/include/linux/vserver/debug.h @@ -6,11 +6,6 @@ #define VXD_CMIN(n,m) (vx_debug_ ## n > (m)) #define VXD_MASK(n,m) (vx_debug_ ## n & (m)) -#define VXD_QPOS(v,p) (((uint32_t)(v) >> ((p)*8)) & 0xFF) -#define VXD_QUAD(v) VXD_QPOS(v,0), VXD_QPOS(v,1), \ - VXD_QPOS(v,2), VXD_QPOS(v,3) -#define VXF_QUAD "%u.%u.%u.%u" - #define VXD_DEV(d) (d), (d)->bd_inode->i_ino, \ imajor((d)->bd_inode), iminor((d)->bd_inode) #define VXF_DEV "%p[%lu,%d:%d]" diff --git a/include/linux/vserver/network.h b/include/linux/vserver/network.h index 0866bc80b..6195c32ec 100644 --- a/include/linux/vserver/network.h +++ b/include/linux/vserver/network.h @@ -9,7 +9,7 @@ #define NX_DYNAMIC_ID ((uint32_t)-1) /* id for dynamic context */ #define NB_IPV4ROOT 16 - +#define NB_IPV6ROOT 16 /* network flags */ @@ -49,7 +49,9 @@ #include #include #include - +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +#include +#endif struct nx_info { struct hlist_node nx_hlist; /* linked list of nxinfos */ @@ -70,10 +72,29 @@ struct nx_info { /* Used to select the proper source */ /* address for sockets */ __u32 v4_bcast; /* Broadcast address to receive UDP */ - +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + int nbipv6; + struct in6_addr ipv6[NB_IPV6ROOT]; /* equivalent to ipv4, but for IPv6 */ + int prefix6[NB_IPV6ROOT]; /* IPv6 prefix length (in bits) */ +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ char nx_name[65]; /* network context name */ }; +struct net_device; + +#ifdef CONFIG_IPV6_MODULE + +struct nx_ipv6_mod { + struct module *owner; + /* Function to check if dev in network context through IPv6 address */ + int (*dev_in_nx_info6)(struct net_device *dev, struct nx_info *nxi); +}; + +extern void vc_net_register_ipv6(struct nx_ipv6_mod *modv6); + +extern void vc_net_unregister_ipv6(void); + +#endif /* status flags */ @@ -111,7 +132,6 @@ extern int nx_migrate_task(struct task_struct *, struct nx_info *); extern long vs_net_change(struct nx_info *, unsigned int); struct in_ifaddr; -struct net_device; #ifdef CONFIG_INET int ifa_in_nx_info(struct in_ifaddr *, struct nx_info *); diff --git a/include/linux/vserver/network_cmd.h b/include/linux/vserver/network_cmd.h index fd6bddee8..37c30b9e8 100644 --- a/include/linux/vserver/network_cmd.h +++ b/include/linux/vserver/network_cmd.h @@ -35,11 +35,26 @@ struct vcmd_net_create { #define VCMD_net_add VC_CMD(NETALT, 1, 0) #define VCMD_net_remove VC_CMD(NETALT, 2, 0) +#ifdef __KERNEL__ +#include +#include +#else +#include +#endif /* __KERNEL__ */ + struct vcmd_net_addr_v0 { uint16_t type; uint16_t count; - uint32_t ip[4]; - uint32_t mask[4]; + union { + struct { + struct in_addr ip[4]; + struct in_addr mask[4]; + }; + struct { + struct in6_addr ip6; + uint32_t prefix; + }; + }; /* more to come */ }; diff --git a/include/net/addrconf.h b/include/net/addrconf.h index 88df8fc81..8fd5cc8cd 100644 --- a/include/net/addrconf.h +++ b/include/net/addrconf.h @@ -69,10 +69,12 @@ extern struct inet6_ifaddr * ipv6_get_ifaddr(struct in6_addr *addr, int strict); extern int ipv6_get_saddr(struct dst_entry *dst, struct in6_addr *daddr, - struct in6_addr *saddr); + struct in6_addr *saddr, + struct nx_info *nxi); extern int ipv6_dev_get_saddr(struct net_device *dev, struct in6_addr *daddr, - struct in6_addr *saddr); + struct in6_addr *saddr, + struct nx_info *nxi); extern int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *); extern int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2); diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 00328b71a..60b6613fa 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -260,6 +260,7 @@ struct ipv6_txoptions *ipv6_fixup_options(struct ipv6_txoptions *opt_space, struct ipv6_txoptions *opt); extern int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb); +extern int ipv6_dev_in_nx_info6(struct net_device *dev, struct nx_info *nxi); extern int ip6_frag_nqueues; extern atomic_t ip6_frag_mem; diff --git a/kernel/vserver/network.c b/kernel/vserver/network.c index 9dd163719..5388efc09 100644 --- a/kernel/vserver/network.c +++ b/kernel/vserver/network.c @@ -439,6 +439,27 @@ out: #include #include + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + +#include + +int nx_addr6_conflict(struct nx_info *nxi, struct nx_info *nxi2) +{ + vxdprintk(VXD_CBIT(net, 2), "nx_addr6_conflict(%u,%u)", + nxi ? nxi->nx_id : 0, nxi2 ? nxi2->nx_id : 0); + + if (nxi && nxi2 && nxi->nbipv6 > 0 && nxi2->nbipv6 > 0) { + int i = 0; + for (i = 0; i < nxi->nbipv6; i++) + if (addr6_in_nx_info(nxi2, &(nxi->ipv6[i]))) + return 1; + } + return 0; +} + +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + int ifa_in_nx_info(struct in_ifaddr *ifa, struct nx_info *nxi) { if (!nxi) @@ -448,11 +469,86 @@ int ifa_in_nx_info(struct in_ifaddr *ifa, struct nx_info *nxi) return addr_in_nx_info(nxi, ifa->ifa_local); } +#ifdef CONFIG_IPV6_MODULE + +struct nx_ipv6_mod vc_net_ipv6 = { + .dev_in_nx_info6 = NULL, + .owner = NULL +}; + +#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) +static atomic_t nx_ipv6mod_lockct = ATOMIC_INIT(0); +static DEFINE_SPINLOCK(nx_ipv6mod_lock); + +/* The strategy is: modifications of vc_net_ipv6 are short, do not + sleep and veeery rare, but read access should be free of any exclusive + locks. (copied from socket.c) + This should prevent any possible issues with module unloading! + */ + +static void nx_ipv6mod_write_lock(void) +{ + spin_lock(&nx_ipv6mod_lock); + while (atomic_read(&nx_ipv6mod_lockct) != 0) { + spin_unlock(&nx_ipv6mod_lock); + + yield(); + + spin_lock(&nx_ipv6mod_lock); + } +} + +static __inline__ void nx_ipv6mod_write_unlock(void) +{ + spin_unlock(&nx_ipv6mod_lock); +} + +static __inline__ void nx_ipv6mod_read_lock(void) +{ + atomic_inc(&nx_ipv6mod_lockct); + spin_unlock_wait(&nx_ipv6mod_lock); +} + +static __inline__ void nx_ipv6mod_read_unlock(void) +{ + atomic_dec(&nx_ipv6mod_lockct); +} + +#else +#define nx_ipv6mod_write_lock() do { } while(0) +#define nx_ipv6mod_write_unlock() do { } while(0) +#define nx_ipv6mod_read_lock() do { } while(0) +#define nx_ipv6mod_read_unlock() do { } while(0) +#endif + +void vc_net_register_ipv6(struct nx_ipv6_mod *modv6) { + nx_ipv6mod_write_lock(); + memcpy(&vc_net_ipv6, modv6, sizeof(struct nx_ipv6_mod)); + nx_ipv6mod_write_unlock(); +} + +void vc_net_unregister_ipv6() { + nx_ipv6mod_write_lock(); + memset(&vc_net_ipv6, 0, sizeof(struct nx_ipv6_mod)); + nx_ipv6mod_write_unlock(); +} + +inline int dev_in_nx_info6(struct net_device *dev, struct nx_info *nxi) { + nx_ipv6mod_read_lock(); + if (try_module_get(vc_net_ipv6.owner)) { + if (vc_net_ipv6.dev_in_nx_info6) + return vc_net_ipv6.dev_in_nx_info6(dev, nxi); + else + return 0; + module_put(vc_net_ipv6.owner); + } else + return 0; + nx_ipv6mod_read_unlock(); +} +#endif + int dev_in_nx_info(struct net_device *dev, struct nx_info *nxi) { - struct in_device *in_dev; - struct in_ifaddr **ifap; - struct in_ifaddr *ifa; int ret = 0; if (!nxi) @@ -460,18 +556,33 @@ int dev_in_nx_info(struct net_device *dev, struct nx_info *nxi) if (!dev) goto out; - in_dev = in_dev_get(dev); - if (!in_dev) - goto out; - for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; - ifap = &ifa->ifa_next) { - if (addr_in_nx_info(nxi, ifa->ifa_local)) { - ret = 1; - break; + if (nxi->nbipv4 > 0) { + struct in_device *in_dev; + struct in_ifaddr **ifap; + struct in_ifaddr *ifa; + + in_dev = in_dev_get(dev); + if (in_dev) { + for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; + ifap = &ifa->ifa_next) { + if (addr_in_nx_info(nxi, ifa->ifa_local)) { + ret = 1; + break; + } + } + in_dev_put(in_dev); } } - in_dev_put(in_dev); + +#if defined(CONFIG_IPV6_MODULE) + if (ret == 0) + ret = dev_in_nx_info6(dev, nxi); +#elif defined(CONFIG_IPV6) + if (ret == 0) + ret = ipv6_dev_in_nx_info6(dev, nxi); +#endif + out: return ret; } @@ -488,8 +599,8 @@ static inline int __addr_in_socket(const struct sock *sk, uint32_t addr) uint32_t saddr = inet_rcv_saddr(sk); vxdprintk(VXD_CBIT(net, 5), - "__addr_in_socket(%p,%d.%d.%d.%d) %p:%d.%d.%d.%d %p;%lx", - sk, VXD_QUAD(addr), nxi, VXD_QUAD(saddr), sk->sk_socket, + "__addr_in_socket(%p," NIPQUAD_FMT ") %p:" NIPQUAD_FMT " %p;%lx", + sk, NIPQUAD(addr), nxi, NIPQUAD(saddr), sk->sk_socket, (sk->sk_socket?sk->sk_socket->flags:0)); if (saddr) { @@ -508,8 +619,8 @@ static inline int __addr_in_socket(const struct sock *sk, uint32_t addr) int nx_addr_conflict(struct nx_info *nxi, uint32_t addr, const struct sock *sk) { vxdprintk(VXD_CBIT(net, 2), - "nx_addr_conflict(%p,%p) %d.%d,%d.%d", - nxi, sk, VXD_QUAD(addr)); + "nx_addr_conflict(%p,%p) " NIPQUAD_FMT, + nxi, sk, NIPQUAD(addr)); if (addr) { /* check real address */ @@ -645,6 +756,40 @@ int vc_net_migrate(struct nx_info *nxi, void __user *data) return nx_migrate_task(current, nxi); } +/* + * Lookup address/mask pair in list of v4 addresses + * Returns position if found, -1 if not found + */ +int vc_net_find_v4(const struct nx_info *nxi, uint32_t addr, uint32_t mask) +{ + int ret = nxi->nbipv4 - 1; + while (ret >= 0) { + if (nxi->ipv4[ret] == addr && nxi->mask[ret] == mask) + break; + else + ret--; + } + return ret; +} + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +/* + * Lookup address/prefix pair list of v6 addresses + * Returns position if found, -1 if not found + */ +int vc_net_find_v6(const struct nx_info *nxi, const struct in6_addr *addr, int prefix) +{ + int ret = nxi->nbipv6 - 1; + while (ret >= 0) { + if (memcmp(&(nxi->ipv6[ret]), addr, sizeof(struct in6_addr)) == 0 && nxi->prefix6[ret] == prefix) + break; + else + ret--; + } + return ret; +} +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + int vc_net_add(struct nx_info *nxi, void __user *data) { struct vcmd_net_addr_v0 vc_data; @@ -659,6 +804,14 @@ int vc_net_add(struct nx_info *nxi, void __user *data) return -EINVAL; break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case NXA_TYPE_IPV6: + /* Note: all 4 items of IP and MASK must be set, but its 1 IPv6 address */ + if ((vc_data.count != 1)) + return -EINVAL; + break; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + default: break; } @@ -666,21 +819,51 @@ int vc_net_add(struct nx_info *nxi, void __user *data) switch (vc_data.type) { case NXA_TYPE_IPV4: index = 0; + ret = 0; while ((index < vc_data.count) && ((pos = nxi->nbipv4) < NB_IPV4ROOT)) { - nxi->ipv4[pos] = vc_data.ip[index]; - nxi->mask[pos] = vc_data.mask[index]; + if (vc_net_find_v4(nxi, vc_data.ip[index].s_addr, vc_data.mask[index].s_addr) == -1) { + /* Only add if address is new */ + vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%d, data[%d]): " NIPQUAD_FMT, + nxi->nx_id, index, NIPQUAD(vc_data.ip[index].s_addr)); + nxi->ipv4[pos] = vc_data.ip[index].s_addr; + nxi->mask[pos] = vc_data.mask[index].s_addr; + nxi->nbipv4++; + ret++; + } else + vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%d, data[%d]): " NIPQUAD_FMT " EXISTS", + nxi->nx_id, index, NIPQUAD(vc_data.ip[index].s_addr)); index++; - nxi->nbipv4++; } ret = index; break; case NXA_TYPE_IPV4|NXA_MOD_BCAST: - nxi->v4_bcast = vc_data.ip[0]; + nxi->v4_bcast = vc_data.ip[0].s_addr; ret = 1; break; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case NXA_TYPE_IPV6: + index = 0; + ret = 0; + while (nxi->nbipv6 < NB_IPV6ROOT && index < vc_data.count) { + if (vc_net_find_v6(nxi, &vc_data.ip6, vc_data.prefix) == -1) { + /* Only add if address is new */ + vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%d, data[%d]): " NIP6_FMT, + nxi->nx_id, index, NIP6(vc_data.ip6)); + nxi->ipv6[nxi->nbipv6] = vc_data.ip6; + nxi->prefix6[nxi->nbipv6] = vc_data.prefix; + nxi->nbipv6++; + ret++; + } else + vxdprintk(VXD_CBIT(nid, 1), "vc_net_add(%d, data[%d]): " NIP6_FMT " EXISTS", + nxi->nx_id, index, NIP6(vc_data.ip6)); + index++; + } + break; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + default: ret = -EINVAL; break; @@ -691,19 +874,68 @@ int vc_net_add(struct nx_info *nxi, void __user *data) int vc_net_remove(struct nx_info * nxi, void __user *data) { struct vcmd_net_addr_v0 vc_data; + int index, pos, ret = 0; if (data && copy_from_user (&vc_data, data, sizeof(vc_data))) return -EFAULT; switch (vc_data.type) { case NXA_TYPE_ANY: +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + ret = nxi->nbipv6; + nxi->nbipv6 = 0; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + ret += nxi->nbipv4; nxi->nbipv4 = 0; break; + case NXA_TYPE_IPV4: + index = 0; + ret = 0; + while (index < vc_data.count) { + pos = vc_net_find_v4(nxi, vc_data.ip[index].s_addr, vc_data.mask[index].s_addr); + if (pos >= 0) { + nxi->nbipv4--; + ret++; + vxdprintk(VXD_CBIT(nid, 1), "vc_net_remove(%d, data[%d]): " NIPQUAD_FMT, + nxi->nx_id, index, NIPQUAD(vc_data.ip[index].s_addr)); + } + while (pos >= 0 && pos < nxi->nbipv4) { + nxi->ipv4[pos] = nxi->ipv4[pos+1]; + nxi->mask[pos] = nxi->mask[pos+1]; + pos++; + } + index++; + } + break; + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + case NXA_TYPE_IPV6: + index = 0; + ret = 0; + while (index < vc_data.count) { + pos = vc_net_find_v6(nxi, &(vc_data.ip6), vc_data.prefix); + if (pos >= 0) { + nxi->nbipv6--; + ret++; + vxdprintk(VXD_CBIT(nid, 1), "vc_net_remove(%d, data[%d]): " NIP6_FMT " EXISTS", + nxi->nx_id, index, NIP6(vc_data.ip6)); + } + while (pos >= 0 && pos < nxi->nbipv6) { + nxi->ipv6[pos] = nxi->ipv6[pos+1]; + nxi->prefix6[pos] = nxi->prefix6[pos+1]; + pos++; + } + index++; + } + break; +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ + default: - return -EINVAL; + ret = -EINVAL; + break; } - return 0; + return ret; } int vc_get_nflags(struct nx_info *nxi, void __user *data) @@ -770,3 +1002,10 @@ int vc_set_ncaps(struct nx_info *nxi, void __user *data) EXPORT_SYMBOL_GPL(free_nx_info); EXPORT_SYMBOL_GPL(unhash_nx_info); +#ifdef CONFIG_IPV6_MODULE +EXPORT_SYMBOL_GPL(nx_addr6_conflict); +EXPORT_SYMBOL_GPL(vc_net_register_ipv6); +EXPORT_SYMBOL_GPL(vc_net_unregister_ipv6); +#elif defined(CONFIG_IPV6) +EXPORT_SYMBOL_GPL(nx_addr6_conflict); +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ diff --git a/kernel/vserver/proc.c b/kernel/vserver/proc.c index f21e28346..4e6c15c86 100644 --- a/kernel/vserver/proc.c +++ b/kernel/vserver/proc.c @@ -187,6 +187,13 @@ int proc_nxi_info (struct nx_info *nxi, char *buffer) "%d:\t" NIPQUAD_FMT "/" NIPQUAD_FMT "\n", i, NIPQUAD(nxi->ipv4[i]), NIPQUAD(nxi->mask[i])); } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + for (i=0; inbipv6;i++) { + length += sprintf(buffer + length, + "%d:\t" NIP6_FMT "/%d\n", i, + NIP6(nxi->ipv6[i]), nxi->prefix6[i]); + } +#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */ return length; } diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 865c850b3..27653af28 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -426,10 +426,10 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) s_addr2 = 0xffffffffl; vxdprintk(VXD_CBIT(net, 3), - "inet_bind(%p)* %p,%p;%lx %d.%d.%d.%d", + "inet_bind(%p)* %p,%p;%lx " NIPQUAD_FMT, sk, sk->sk_nx_info, sk->sk_socket, (sk->sk_socket?sk->sk_socket->flags:0), - VXD_QUAD(s_addr)); + NIPQUAD(s_addr)); if (nxi) { __u32 v4_bcast = nxi->v4_bcast; __u32 ipv4root = nxi->ipv4[0]; @@ -453,8 +453,8 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) chk_addr_ret = inet_addr_type(s_addr); vxdprintk(VXD_CBIT(net, 3), - "inet_bind(%p) %d.%d.%d.%d, %d.%d.%d.%d, %d.%d.%d.%d", - sk, VXD_QUAD(s_addr), VXD_QUAD(s_addr1), VXD_QUAD(s_addr2)); + "inet_bind(%p) " NIPQUAD_FMT ", " NIPQUAD_FMT ", " NIPQUAD_FMT, + sk, NIPQUAD(s_addr), NIPQUAD(s_addr1), NIPQUAD(s_addr2)); /* Not specified by any standard per-se, however it breaks too * many applications when removed. It is unfortunate since diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 2c23f0848..529e39760 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -917,7 +917,7 @@ static int inline ipv6_saddr_label(const struct in6_addr *addr, int type) } int ipv6_dev_get_saddr(struct net_device *daddr_dev, - struct in6_addr *daddr, struct in6_addr *saddr) + struct in6_addr *daddr, struct in6_addr *saddr, struct nx_info *nxi) { struct ipv6_saddr_score hiscore; struct inet6_ifaddr *ifa_result = NULL; @@ -962,6 +962,11 @@ int ipv6_dev_get_saddr(struct net_device *daddr_dev, score.addr_type = __ipv6_addr_type(&ifa->addr); + /* Linux-VServer: only take into account addresses + available in guest context! */ + if (!addr6_in_nx_info(nxi, &ifa->addr)) + continue; + /* Rule 0: * - Tentative Address (RFC2462 section 5.4) * - A tentative address is not considered @@ -1172,9 +1177,9 @@ record_it: int ipv6_get_saddr(struct dst_entry *dst, - struct in6_addr *daddr, struct in6_addr *saddr) + struct in6_addr *daddr, struct in6_addr *saddr, struct nx_info *nxi) { - return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr); + return ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, daddr, saddr, nxi); } @@ -1277,26 +1282,48 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) int addr_type = ipv6_addr_type(sk_rcv_saddr6); int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; - if (!sk2_rcv_saddr && !sk_ipv6only) - return 1; + if (sk->sk_nid != sk2->sk_nid) { + // either socket is in host context and bound to everything + if (sk->sk_nx_info == NULL && addr_type == IPV6_ADDR_ANY && !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) + return 1; + if (sk2->sk_nx_info == NULL && addr_type2 == IPV6_ADDR_ANY && !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) + return 1; + // If both addresses are equal + if (sk2_rcv_saddr6 && ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) + return 1; + // If one socket bound to everything and the addr bound by other socket is in first context + if (addr_type2 == IPV6_ADDR_ANY && !(addr_type == IPV6_ADDR_ANY || addr_type == IPV6_ADDR_MAPPED) && + addr6_in_nx_info(sk2->sk_nx_info, sk_rcv_saddr6)) + return 1; + if (addr_type == IPV6_ADDR_ANY && !(addr_type2 == IPV6_ADDR_ANY || addr_type2 == IPV6_ADDR_MAPPED) && + sk2_rcv_saddr6 && addr6_in_nx_info(sk->sk_nx_info, sk2_rcv_saddr6)) + return 1; + // both sockets are in guests and bound to everything with addr-overlap between guests + if (sk->sk_nx_info && sk2->sk_nx_info && addr_type == IPV6_ADDR_ANY && addr_type2 == IPV6_ADDR_ANY && + nx_addr6_conflict(sk->sk_nx_info, sk2->sk_nx_info)) + return 1; + // TODO: handle the IPv4 addresses mapped in IPv6 completely... + } else { + if (!sk2_rcv_saddr && !sk_ipv6only) + return 1; - if (addr_type2 == IPV6_ADDR_ANY && - !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) - return 1; + if (addr_type2 == IPV6_ADDR_ANY && + !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) + return 1; - if (addr_type == IPV6_ADDR_ANY && - !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) - return 1; + if (addr_type == IPV6_ADDR_ANY && + !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) + return 1; - if (sk2_rcv_saddr6 && - ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) - return 1; - - if (addr_type == IPV6_ADDR_MAPPED && - !sk2_ipv6only && - (!sk2_rcv_saddr || !sk_rcv_saddr || sk_rcv_saddr == sk2_rcv_saddr)) - return 1; + if (sk2_rcv_saddr6 && + ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) + return 1; + if (addr_type == IPV6_ADDR_MAPPED && + !sk2_ipv6only && + (!sk2_rcv_saddr || !sk_rcv_saddr || sk_rcv_saddr == sk2_rcv_saddr)) + return 1; + } return 0; } @@ -2744,8 +2771,9 @@ static int if6_seq_show(struct seq_file *seq, void *v) { struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v; - /* no ipv6 inside a vserver for now */ - if (nx_check(0, VS_ADMIN|VS_WATCH)) + /* Only addresses visible to vserver context */ + if (nx_check(0, VS_ADMIN|VS_WATCH) || + addr6_in_nx_info(current_nx_info(), &ifp->addr)) seq_printf(seq, NIP6_SEQFMT " %02x %02x %02x %02x %8s\n", NIP6(ifp->addr), @@ -3218,8 +3246,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, struct ifmcaddr6 *ifmca; struct ifacaddr6 *ifaca; - /* no ipv6 inside a vserver for now */ - if (skb->sk && skb->sk->sk_vx_info) + /* no ipv6 inside a vserver if no addr set */ + if (skb->sk && skb->sk->sk_nx_info && skb->sk->sk_nx_info->nbipv6 == 0) return skb->len; s_idx = cb->args[0]; @@ -3242,6 +3270,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, ifa = ifa->if_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; + if (skb->sk && skb->sk->sk_nx_info && !addr6_in_nx_info(skb->sk->sk_nx_info, &ifa->addr)) + continue; /* Skip addresses not in nx */ if ((err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_NEWADDR, @@ -3255,6 +3285,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, ifmca = ifmca->next, ip_idx++) { if (ip_idx < s_ip_idx) continue; + if (skb->sk && skb->sk->sk_nx_info && !addr6_in_nx_info(skb->sk->sk_nx_info, &ifmca->mca_addr)) + continue; /* Skip addresses not in nx */ if ((err = inet6_fill_ifmcaddr(skb, ifmca, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_GETMULTICAST, @@ -3268,6 +3300,8 @@ static int inet6_dump_addr(struct sk_buff *skb, struct netlink_callback *cb, ifaca = ifaca->aca_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; + if (skb->sk && skb->sk->sk_nx_info && !addr6_in_nx_info(skb->sk->sk_nx_info, &ifaca->aca_addr)) + continue; /* Skip addresses not in nx */ if ((err = inet6_fill_ifacaddr(skb, ifaca, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, RTM_GETANYCAST, @@ -3494,14 +3528,16 @@ static int inet6_dump_ifinfo(struct sk_buff *skb, struct netlink_callback *cb) struct net_device *dev; struct inet6_dev *idev; - /* no ipv6 inside a vserver for now */ - if (skb->sk && skb->sk->sk_vx_info) + /* no ipv6 inside a vserver if no addr set */ + if (skb->sk && skb->sk->sk_nx_info && skb->sk->sk_nx_info->nbipv6 == 0) return skb->len; read_lock(&dev_base_lock); for (dev=dev_base, idx=0; dev; dev = dev->next, idx++) { if (idx < s_idx) continue; + if (skb->sk && skb->sk->sk_nx_info && !ipv6_dev_in_nx_info6(dev, skb->sk->sk_nx_info)) + continue; if ((idev = in6_dev_get(dev)) == NULL) continue; err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid, diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 0e0e4262f..f9a16d089 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include @@ -147,9 +148,11 @@ lookup_protocol: } err = -EPERM; + if ((protocol == IPPROTO_ICMPV6) && vx_ccaps(VXC_RAW_ICMP)) + goto override; if (answer->capability > 0 && !capable(answer->capability)) goto out_rcu_unlock; - +override: sock->ops = answer->ops; answer_prot = answer->prot; answer_no_check = answer->no_check; @@ -233,6 +236,8 @@ lookup_protocol: } } out: + vxdprintk(VXD_CBIT(net, 4), "inet6_create(%p, %d): %d", + sock, protocol, err); return err; out_rcu_unlock: rcu_read_unlock(); @@ -306,6 +311,18 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) } } + /* VServer: Only accept if we have the address available */ + if (sk->sk_nx_info && !addr6_in_nx_info(sk->sk_nx_info, &addr->sin6_addr)) { + vxdprintk(VXD_CBIT(net, 3), "inet6_bind(" NIP6_FMT ", %d): EADDRNOTAVAIL", + NIP6(addr->sin6_addr), sk->sk_nx_info->nx_id); + err = -EADDRNOTAVAIL; + if (dev) + dev_put(dev); + goto out; + } else + vxdprintk(VXD_CBIT(net, 3), "inet6_bind(" NIP6_FMT ", %d): PASS", + NIP6(addr->sin6_addr), sk->sk_nx_info ? sk->sk_nx_info->nx_id : 0); + /* ipv4 addr of the socket is invalid. Only the * unspecified and mapped address have a v4 equivalent. */ @@ -692,6 +709,31 @@ int ipv6_opt_accepted(struct sock *sk, struct sk_buff *skb) EXPORT_SYMBOL_GPL(ipv6_opt_accepted); +int ipv6_dev_in_nx_info6(struct net_device *dev, struct nx_info *nxi) { + int ret = 0; + + if (nxi->nbipv6 > 0) { + struct inet6_dev *in_dev; + struct inet6_ifaddr **ifap; + struct inet6_ifaddr *ifa; + + in_dev = in6_dev_get(dev); + if (in_dev) { + for (ifap = &in_dev->addr_list; (ifa = *ifap) != NULL; + ifap = &ifa->if_next) { + if (addr6_in_nx_info(nxi, &(ifa->addr))) { + ret = 1; + break; + } + } + in6_dev_put(in_dev); + } + } + return ret; +} + +EXPORT_SYMBOL_GPL(ipv6_dev_in_nx_info6); + int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign) { @@ -760,6 +802,17 @@ static void cleanup_ipv6_mibs(void) snmp6_mib_free((void **)udplite_stats_in6); } +#ifdef CONFIG_IPV6_MODULE +static void vc_net_register_init(void) +{ + struct nx_ipv6_mod mymod = { + .dev_in_nx_info6 = ipv6_dev_in_nx_info6, + .owner = THIS_MODULE + }; + vc_net_register_ipv6(&mymod); +} +#endif + static int __init inet6_init(void) { struct sk_buff *dummy_skb; @@ -877,6 +930,11 @@ static int __init inet6_init(void) tcpv6_init(); ipv6_packet_init(); + +#ifdef CONFIG_IPV6_MODULE + vc_net_register_init(); +#endif + err = 0; out: return err; @@ -930,6 +988,9 @@ static void __exit inet6_exit(void) { /* First of all disallow new sockets creation. */ sock_unregister(PF_INET6); +#ifdef CONFIG_IPV6_MODULE + vc_net_unregister_ipv6(); +#endif #ifdef CONFIG_PROC_FS if6_proc_exit(); ac6_proc_exit(); diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index ba13f7431..dd991f639 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -102,6 +102,26 @@ hit: } EXPORT_SYMBOL(__inet6_lookup_established); +/* + * Check if a given address matches for an inet socket + * + * nxi: the socket's nx_info if any + * addr: to be verified address + * saddr: socket addresses + */ +static inline int inet6_addr_match( + struct nx_info *nxi, + const struct in6_addr *addr, + const struct in6_addr *saddr) +{ + if ((addr->s6_addr32[0] || addr->s6_addr32[1] || addr->s6_addr32[2] || addr->s6_addr32[3]) && + memcmp(saddr,addr, sizeof(struct in6_addr)) == 0) + return 1; + if (!(saddr->s6_addr32[0] || saddr->s6_addr32[1] || saddr->s6_addr32[2] || saddr->s6_addr32[3])) + return addr6_in_nx_info(nxi, addr); + return 0; +} + struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, const struct in6_addr *daddr, const unsigned short hnum, const int dif) @@ -127,6 +147,10 @@ struct sock *inet6_lookup_listener(struct inet_hashinfo *hashinfo, continue; score++; } + if (!inet6_addr_match(sk->sk_nx_info, daddr, &(np->rcv_saddr))) { + /* No, this address is not available for guest */ + continue; + } if (score == 3) { result = sk; break; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index 7b7bd44fb..3acad4d53 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -38,7 +38,6 @@ #include #include #include -#include #include #include @@ -856,7 +855,8 @@ static int ip6_dst_lookup_tail(struct sock *sk, goto out_err_release; if (ipv6_addr_any(&fl->fl6_src)) { - err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src); + err = ipv6_get_saddr(*dst, &fl->fl6_dst, &fl->fl6_src, sk->sk_nx_info); + if (err) goto out_err_release; } diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 39bb658f3..b1907d986 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -449,7 +449,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, src_addr = solicited_addr; in6_ifa_put(ifp); } else { - if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr)) + if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr, NULL)) return; src_addr = &tmpaddr; } diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 9479fbd22..74ef1f0d1 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -103,7 +103,8 @@ struct sock *__raw_v6_lookup(struct sock *sk, unsigned short num, continue; if (!ipv6_addr_any(&np->rcv_saddr)) { - if (ipv6_addr_equal(&np->rcv_saddr, loc_addr)) + if (ipv6_addr_equal(&np->rcv_saddr, loc_addr) && + addr6_in_nx_info(sk->sk_nx_info, loc_addr)) goto found; if (is_multicast && inet6_mc_check(sk, loc_addr, rmt_addr)) @@ -261,7 +262,19 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) goto out; } } - + + /* VServer: Only accept if we have the address available */ + if (sk->sk_nx_info && !addr6_in_nx_info(sk->sk_nx_info, &addr->sin6_addr)) { + vxdprintk(VXD_CBIT(net, 3), "rawv6_bind(" NIP6_FMT ", %d): EADDRNOTAVAIL", + NIP6(addr->sin6_addr), sk->sk_nx_info->nx_id); + err = -EADDRNOTAVAIL; + if (dev) + dev_put(dev); + goto out; + } else + vxdprintk(VXD_CBIT(net, 3), "rawv6_bind(" NIP6_FMT ", %d): PASS", + NIP6(addr->sin6_addr), sk->sk_nx_info ? sk->sk_nx_info->nx_id : 0); + /* ipv4 addr of the socket is invalid. Only the * unspecified and mapped address have a v4 equivalent. */ @@ -585,6 +598,11 @@ static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, if (err) goto error_fault; + err = -EPERM; + if (!nx_check(0, VS_ADMIN) && !capable(CAP_NET_RAW) + && (!addr6_in_nx_info(sk->sk_nx_info, &iph->saddr))) + goto error_free; + IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTREQUESTS); err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); @@ -597,6 +615,7 @@ out: error_fault: err = -EFAULT; +error_free: kfree_skb(skb); error: IP6_INC_STATS(rt->rt6i_idev, IPSTATS_MIB_OUTDISCARDS); diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 01bcf4ab1..04ca7aac8 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -2109,7 +2109,7 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, NLA_PUT_U32(skb, RTA_IIF, iif); else if (dst) { struct in6_addr saddr_buf; - if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf) == 0) + if (ipv6_get_saddr(&rt->u.dst, dst, &saddr_buf, NULL) == 0) NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index a2d41ba13..bf1fc221c 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -160,8 +160,19 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, * connect() to INADDR_ANY means loopback (BSD'ism). */ - if(ipv6_addr_any(&usin->sin6_addr)) - usin->sin6_addr.s6_addr[15] = 0x1; + if(ipv6_addr_any(&usin->sin6_addr)) { + if (sk->sk_nx_info) { + if (sk->sk_nx_info->nbipv6) { + /* Linux-VServer: redirects to first IPv6 address set for guest + TODO: search for existing loopback address in guest context... */ + usin->sin6_addr = sk->sk_nx_info->ipv6[0]; + vxdprintk(VXD_CBIT(net, 4), "tcp_v6_connect(dest ::1 redirected to: " NIP6_FMT ", %d)", + NIP6(usin->sin6_addr), sk->sk_nx_info->nx_id); + } else + return -ENETUNREACH; + } else + usin->sin6_addr.s6_addr[15] = 0x1; + } addr_type = ipv6_addr_type(&usin->sin6_addr); diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index b5dc5dbf1..1f1eb94a2 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -58,6 +58,17 @@ static inline int udp_v6_get_port(struct sock *sk, unsigned short snum) return udp_get_port(sk, snum, ipv6_rcv_saddr_equal); } +static inline int udp_v6_in_list(struct nx_info *nx_info, struct in6_addr *addr) +{ + int n = nx_info->nbipv6; + int i; + + for (i=0; iipv6[i], addr)) + return 1; + return 0; +} + static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, struct in6_addr *daddr, __be16 dport, int dif, struct hlist_head udptable[]) @@ -83,6 +94,11 @@ static struct sock *__udp6_lib_lookup(struct in6_addr *saddr, __be16 sport, if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) continue; score++; + } else if (sk->sk_nx_info) { + if (udp_v6_in_list(sk->sk_nx_info, daddr)) + score++; + else + continue; } if (!ipv6_addr_any(&np->daddr)) { if (!ipv6_addr_equal(&np->daddr, saddr)) diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 8dffd4daa..a09fecef2 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -49,7 +49,7 @@ static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) if (!xfrm6_dst_lookup((struct xfrm_dst **)&rt, &fl_tunnel)) { ipv6_get_saddr(&rt->u.dst, (struct in6_addr *)&daddr->a6, - (struct in6_addr *)&saddr->a6); + (struct in6_addr *)&saddr->a6, NULL); dst_release(&rt->u.dst); return 0; } diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index ef36be073..8f91d07e9 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -306,7 +306,7 @@ static void sctp_v6_get_saddr(struct sctp_association *asoc, __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr)); if (!asoc) { - ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr); + ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr, NULL); SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n", NIP6(saddr->v6.sin6_addr)); return; diff --git a/net/socket.c b/net/socket.c index 2506f9d7a..d81381fec 100644 --- a/net/socket.c +++ b/net/socket.c @@ -94,6 +94,7 @@ #include #include #include +#include static int sock_no_open(struct inode *irrelevant, struct file *dontcare); static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, @@ -1096,9 +1097,14 @@ static int __sock_create(int family, int type, int protocol, if (type < 0 || type >= SOCK_MAX) return -EINVAL; - /* disable IPv6 inside vservers for now */ - if (family == PF_INET6 && !nx_check(0, VS_ADMIN)) +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + /* disable IPv6 inside vservers that have no IPv6 address configured */ + if (family == PF_INET6 && current_nx_info() && current_nx_info()->nbipv6 == 0) { + vxdprintk(VXD_CBIT(net, 4), "__sock_create(%d, %d, %d, %p, %d): EAFNOSUPPORT", + family, type, protocol, res, kern); return -EAFNOSUPPORT; + } +#endif /* Compatibility. -- 2.47.0