All of lore.kernel.org
 help / color / mirror / Atom feed
* On IP_FREEBIND and IPv6...
@ 2011-11-02  0:57 Maciej Żenczykowski
  2011-11-08  0:57 ` [PATCH 1/2] net: make ipv6 bind honour freebind Maciej Żenczykowski
  2011-11-08  0:57 ` [PATCH 2/2] net: make ipv6 PKTINFO " Maciej Żenczykowski
  0 siblings, 2 replies; 5+ messages in thread
From: Maciej Żenczykowski @ 2011-11-02  0:57 UTC (permalink / raw)
  To: Linux NetDev

Short summary:
  IPV6 + IP_FREEBIND doesn't work the way IPV4 + IP_FREEBIND does.
  The native IPv6 bind path ignores 'freebind', but honours 'transparent'.
  The native and dual-stack IPv4 bind paths honour both.

Does anyone know if this was a (security?) feature?  Or is this just a bug?

I'll follow this up with a patch to support freebind for v6 bind (and
another one for v6 udp sendmsg).
Unless I hear some compelling story about why stuff is the way it is.

---

Please find test program source later on.

It basically does:
   for test_mode in {native_ipv4, ipv4_on_ipv6_socket, native_ipv6} do:
       create a udp socket
       set IP_FREEBIND=1
       set IP_TRANSPARENT=1 (will fail if not root, ignore failure)
       bind socket to an IP address we don't own (one of: 1.2.3.4,
::FFFF:1.2.3.4, 2001:4860:DEAD:CAFE::6006:13) [fails without root for
native ipv6]
       send a packet to another IP address (one of: 5.6.7.8,
::FFFF:5.6.7.8, 2001:4860:DEAD:BEEF::6006:13)

Running it generates:

$ ./test
setsockopt(TRANSPARENT=1): Operation not permitted [requires root]
setsockopt(TRANSPARENT=1): Operation not permitted [requires root]
setsockopt(TRANSPARENT=1): Operation not permitted [requires root]
bind(): Cannot assign requested address [native ipv6 bind does not
honour IP_FREEBIND, does honour IP{,V6}_TRANSPARENT]
$ sudo ./test
<no errors, everything succeeds, including bind native ipv6>

While running tcpdump shows:
# tcpdump -s 1555 -n -nn -i eth0 port 11111 or port 22222

>From ./a [ie. with IP_FREEBIND=1, IP_TRANSPARENT=0]:

IP 1.2.3.4.11111 > 5.6.7.8.22222: UDP, length 6 [native IPv4]
IP 1.2.3.4.11111 > 5.6.7.8.22222: UDP, length 6 [dual stack IPv4 on IPv6 socket]
IP6 [machines_true_ipv6_address].51912 >
2001:4860:dead:beef::6006:13.22222: UDP, length 6 [native IPv6, wrong
source since bind failed]

>From sudo ./a [ie. with IP_FREEBIND=1, IP_TRANSPARENT=1]:

IP 1.2.3.4.11111 > 5.6.7.8.22222: UDP, length 6 [native IPv4]
IP 1.2.3.4.11111 > 5.6.7.8.22222: UDP, length 6 [dual stack IPv4 on IPv6 socket]
IP6 2001:4860:dead:cafe::6006:13.vce >
2001:4860:dead:beef::6006:13.22222: UDP, length 6 [native IPv6]

This seems to prove that IP_TRANSPARENT requires root - this is as
expected, while IP_FREEBIND does not require root - again as expected.
However, as apparent above, we are successfully spoofing outgoing
source address on IPv4 UDP (whether native IPv4 or dual-stack IPv4
doesn't matter),
but there doesn't seem to be a way to do this with native IPv6.

ie. the native IPv6 bind path ignores the "freebind" setting, but does
honour the "transparent", while the IPv4 code paths honour both.

- Maciej

---
#include <string.h>
#include <stdio.h>

#include <sys/types.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#define NATIVE_IPv4 0
#define DUAL_STACK  1
#define NATIVE_IPv6 2

int main(int argc, char const * argv[], char const * envp[]) {
  struct sockaddr_in saddr4, daddr4;
  struct sockaddr_in6 saddr6, daddr6;
  int fd, rv, v, mode;

  for (mode = 0; mode <= 2; ++mode) {

    if (mode == NATIVE_IPv4) {
      fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
      if (fd < 0) perror("socket(IPv4 UDP)");
    } else {
      fd = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
      if (fd < 0) perror("socket(IPv6 UDP)");
    }

    v = 1;
    rv = setsockopt(fd, SOL_IP, IP_FREEBIND, &v, sizeof(v));
    if (rv < 0) perror("setsockopt(FREEBIND=1)");

    v = 1;
    rv = setsockopt(fd, SOL_IP, IP_TRANSPARENT, &v, sizeof(v));
    if (rv < 0) perror("setsockopt(TRANSPARENT=1)");

    if (mode == NATIVE_IPv4) {
      memset(&saddr4, 0, sizeof(saddr4));
      memset(&daddr4, 0, sizeof(daddr4));
      saddr4.sin_family = AF_INET;
      daddr4.sin_family = AF_INET;
      saddr4.sin_port = htons(11111);
      daddr4.sin_port = htons(22222);
      inet_pton(AF_INET, "1.2.3.4", &saddr4.sin_addr.s_addr);
      inet_pton(AF_INET, "5.6.7.8", &daddr4.sin_addr.s_addr);

      rv = bind(fd, (struct sockaddr const *)&saddr4, sizeof(saddr4));
      if (rv < 0) perror("bind()");

      rv = sendto(fd, "Hello!", 6, 0, (struct sockaddr const
*)&daddr4, sizeof(daddr4));
      if (rv < 0) perror("write");
    } else {
      memset(&saddr6, 0, sizeof(saddr6));
      memset(&daddr6, 0, sizeof(daddr6));
      saddr6.sin6_family = AF_INET6;
      daddr6.sin6_family = AF_INET6;
      saddr6.sin6_port = htons(11111);
      daddr6.sin6_port = htons(22222);
      //saddr6.sin6_flowinfo = 0;
      //daddr6.sin6_flowinfo = 0;
      if (mode == DUAL_STACK) {
        inet_pton(AF_INET6, "::FFFF:1.2.3.4", &saddr6.sin6_addr);
        inet_pton(AF_INET6, "::FFFF:5.6.7.8", &daddr6.sin6_addr);
      } else {
        inet_pton(AF_INET6, "2001:4860:DEAD:CAFE::6006:0013",
&saddr6.sin6_addr);
        inet_pton(AF_INET6, "2001:4860:DEAD:BEEF::6006:0013",
&daddr6.sin6_addr);
      }
      //saddr6.sin6_scope_id = 0;
      //daddr6.sin6_scope_id = 0;

      rv = bind(fd, (struct sockaddr const *)&saddr6, sizeof(saddr6));
      if (rv < 0) perror("bind()");

      rv = sendto(fd, "Hello!", 6, 0, (struct sockaddr const
*)&daddr6, sizeof(daddr6));
      if (rv < 0) perror("write");
    }

    rv = close(fd);
    if (rv < 0) perror("close");
  }

  return 0;
}

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH 1/2] net: make ipv6 bind honour freebind
  2011-11-02  0:57 On IP_FREEBIND and IPv6 Maciej Żenczykowski
@ 2011-11-08  0:57 ` Maciej Żenczykowski
  2011-11-08 20:17   ` David Miller
  2011-11-08  0:57 ` [PATCH 2/2] net: make ipv6 PKTINFO " Maciej Żenczykowski
  1 sibling, 1 reply; 5+ messages in thread
From: Maciej Żenczykowski @ 2011-11-08  0:57 UTC (permalink / raw)
  To: Maciej Żenczykowski; +Cc: netdev, Maciej Żenczykowski

From: Maciej Żenczykowski <maze@google.com>

This makes native ipv6 bind follow the precedent set by:
  - native ipv4 bind behaviour
  - dual stack ipv4-mapped ipv6 bind behaviour.

This does allow an unpriviledged process to spoof its source IPv6
address, just like it currently can spoof its source IPv4 address
(for example when using UDP).

Signed-off-by: Maciej Żenczykowski <maze@google.com>
---
 net/ipv6/af_inet6.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index d27c797..1040424 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -347,7 +347,7 @@ int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 			 */
 			v4addr = LOOPBACK4_IPV6;
 			if (!(addr_type & IPV6_ADDR_MULTICAST))	{
-				if (!inet->transparent &&
+				if (!(inet->freebind || inet->transparent) &&
 				    !ipv6_chk_addr(net, &addr->sin6_addr,
 						   dev, 0)) {
 					err = -EADDRNOTAVAIL;
-- 
1.7.3.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH 2/2] net: make ipv6 PKTINFO honour freebind
  2011-11-02  0:57 On IP_FREEBIND and IPv6 Maciej Żenczykowski
  2011-11-08  0:57 ` [PATCH 1/2] net: make ipv6 bind honour freebind Maciej Żenczykowski
@ 2011-11-08  0:57 ` Maciej Żenczykowski
  2011-11-08 20:17   ` David Miller
  1 sibling, 1 reply; 5+ messages in thread
From: Maciej Żenczykowski @ 2011-11-08  0:57 UTC (permalink / raw)
  To: Maciej Żenczykowski; +Cc: netdev, Maciej Żenczykowski

From: Maciej Żenczykowski <maze@google.com>

This just makes it possible to spoof source IPv6 address on a socket
without having to create and bind a new socket for every source IP
we wish to spoof.

Signed-off-by: Maciej Żenczykowski <maze@google.com>
---
 net/ipv6/datagram.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index e248069..83037af 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -654,7 +654,7 @@ int datagram_send_ctl(struct net *net, struct sock *sk,
 
 			if (addr_type != IPV6_ADDR_ANY) {
 				int strict = __ipv6_addr_src_scope(addr_type) <= IPV6_ADDR_SCOPE_LINKLOCAL;
-				if (!inet_sk(sk)->transparent &&
+				if (!(inet_sk(sk)->freebind || inet_sk(sk)->transparent) &&
 				    !ipv6_chk_addr(net, &src_info->ipi6_addr,
 						   strict ? dev : NULL, 0))
 					err = -EINVAL;
-- 
1.7.3.1

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 1/2] net: make ipv6 bind honour freebind
  2011-11-08  0:57 ` [PATCH 1/2] net: make ipv6 bind honour freebind Maciej Żenczykowski
@ 2011-11-08 20:17   ` David Miller
  0 siblings, 0 replies; 5+ messages in thread
From: David Miller @ 2011-11-08 20:17 UTC (permalink / raw)
  To: zenczykowski; +Cc: maze, netdev

From: Maciej Żenczykowski <zenczykowski@gmail.com>
Date: Mon,  7 Nov 2011 16:57:21 -0800

> From: Maciej Żenczykowski <maze@google.com>
> 
> This makes native ipv6 bind follow the precedent set by:
>   - native ipv4 bind behaviour
>   - dual stack ipv4-mapped ipv6 bind behaviour.
> 
> This does allow an unpriviledged process to spoof its source IPv6
> address, just like it currently can spoof its source IPv4 address
> (for example when using UDP).
> 
> Signed-off-by: Maciej Żenczykowski <maze@google.com>

Applied.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 2/2] net: make ipv6 PKTINFO honour freebind
  2011-11-08  0:57 ` [PATCH 2/2] net: make ipv6 PKTINFO " Maciej Żenczykowski
@ 2011-11-08 20:17   ` David Miller
  0 siblings, 0 replies; 5+ messages in thread
From: David Miller @ 2011-11-08 20:17 UTC (permalink / raw)
  To: zenczykowski; +Cc: maze, netdev

From: Maciej Żenczykowski <zenczykowski@gmail.com>
Date: Mon,  7 Nov 2011 16:57:22 -0800

> From: Maciej Żenczykowski <maze@google.com>
> 
> This just makes it possible to spoof source IPv6 address on a socket
> without having to create and bind a new socket for every source IP
> we wish to spoof.
> 
> Signed-off-by: Maciej Żenczykowski <maze@google.com>

Applied.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2011-11-08 20:17 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-11-02  0:57 On IP_FREEBIND and IPv6 Maciej Żenczykowski
2011-11-08  0:57 ` [PATCH 1/2] net: make ipv6 bind honour freebind Maciej Żenczykowski
2011-11-08 20:17   ` David Miller
2011-11-08  0:57 ` [PATCH 2/2] net: make ipv6 PKTINFO " Maciej Żenczykowski
2011-11-08 20:17   ` David Miller

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.