Lets set IP_FREEBIND on IPv6 sockets as well, this works since Linux 3.3
and doesn't require CAP_NET_ADMIN privileges (IPV6_TRANSPARENT does).

This allows unprivileged users to bind to non-local IPv6 addresses, which
can be useful when setting up the listening sockets or when connecting
to backend servers with a specific, non-local source IPv6 address (at that
point we usually dropped root privileges already).

---

Before this patch an unprivileged bind fails:
setsockopt(5, SOL_IPV6, 0x4b /* IPV6_TRANSPARENT */, [1], 4) = -1 EPERM 
(Operation not permitted)
bind(5, {sa_family=AF_INET6, sin6_port=htons(1080), inet_pton(AF_INET6, 
"2005::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 
EADDRNOTAVAIL (Cannot assign requested address)

After the patch:
setsockopt(5, SOL_IPV6, 0x4b /* IPV6_TRANSPARENT */, [1], 4) = -1 EPERM 
(Operation not permitted)
setsockopt(5, SOL_IP, IP_FREEBIND, [1], 4) = 0
bind(5, {sa_family=AF_INET6, sin6_port=htons(1080), inet_pton(AF_INET6, 
"2005::1", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = 0

---
 src/proto_tcp.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/src/proto_tcp.c b/src/proto_tcp.c
index 11f6331..2b12ef8 100644
--- a/src/proto_tcp.c
+++ b/src/proto_tcp.c
@@ -160,6 +160,9 @@ int tcp_bind_socket(int fd, int flags, struct 
sockaddr_storage *local, struct so
 #if defined(IPV6_TRANSPARENT)
                            || (setsockopt(fd, SOL_IPV6, IPV6_TRANSPARENT, 
&one, sizeof(one)) == 0)
 #endif
+#if defined(IP_FREEBIND)
+                           || (setsockopt(fd, SOL_IP, IP_FREEBIND, &one, 
sizeof(one)) == 0)
+#endif
 #if defined(IPV6_BINDANY)
                            || (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDANY, 
&one, sizeof(one)) == 0)
 #endif
@@ -787,6 +790,9 @@ int tcp_bind_listener(struct listener *listener, char 
*errmsg, int errlen)
 #if defined(IPV6_TRANSPARENT)
                            && (setsockopt(fd, SOL_IPV6, IPV6_TRANSPARENT, 
&one, sizeof(one)) == -1)
 #endif
+#if defined(IP_FREEBIND)
+                           && (setsockopt(fd, SOL_IP, IP_FREEBIND, &one, 
sizeof(one)) == -1)
+#endif
 #if defined(IPV6_BINDANY)
                            && (setsockopt(fd, IPPROTO_IPV6, IPV6_BINDANY, 
&one, sizeof(one)) == -1)
 #endif
-- 
1.7.9.5


Reply via email to