]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
* rebased openvpn-2.1_rc1b.jjo.20061206.d.patch
authorJuanJo Ciarlante <jjo@google.com>
Sun, 13 Sep 2009 11:43:04 +0000 (13:43 +0200)
committerJuanJo Ciarlante <juanjosec@gmail.com>
Fri, 25 Mar 2011 12:30:28 +0000 (13:30 +0100)
* passes {udp,tcp}x{v4,v6} loopback tests
* passes {udp,tcp}x{v6} remote tests

13 files changed:
buffer.c
configure.ac
init.c
manage.c
mroute.c
mtcp.c
multi.c
occ.c
options.c
ps.c
socket.c
socket.h
socks.c

index e2f8caab0a5b2a870092c6cd508a1a50c21c3ba3..c43cb47004a6bef1f0ef49d1c9b24e9173e51b1a 100644 (file)
--- a/buffer.c
+++ b/buffer.c
@@ -214,6 +214,19 @@ buf_printf (struct buffer *buf, const char *format, ...)
   return ret;
 }
 
+void buf_puts(struct buffer *buf, const char *str)
+{
+  uint8_t *ptr = BEND (buf);
+  int cap = buf_forward_capacity (buf);
+  if (cap > 0)
+    {
+      strncpynt ((char *)ptr,str, cap);
+      *(buf->data + buf->capacity - 1) = 0; /* windows vsnprintf needs this */
+      buf->len += (int) strlen ((char *)ptr);
+    }
+}
+
 /*
  * This is necessary due to certain buggy implementations of snprintf,
  * that don't guarantee null termination for size > 0.
index e0847bccd20f95b772bf9e6a0fae8c30525c8f54..c3bd8e812a53dc1efba67c5f3da4d5ce0e04b733 100644 (file)
@@ -146,6 +146,12 @@ AC_ARG_ENABLE(multihome,
    [MULTIHOME="yes"]
 )
 
+AC_ARG_ENABLE(ipv6,
+   [  --disable-ipv6          Disable UDP/IPv6 support],
+   [PF_INET6="$enableval"],
+   [PF_INET6="yes"]
+)
+
 AC_ARG_ENABLE(port-share,
    [  --disable-port-share    Disable TCP server port-share support (--port-share)],
    [PORT_SHARE="$enableval"],
@@ -566,6 +572,16 @@ LDFLAGS="$LDFLAGS -Wl,--fatal-warnings"
 AC_CHECK_FUNC(epoll_create, AC_DEFINE(HAVE_EPOLL_CREATE, 1, [epoll_create function is defined]))
 LDFLAGS="$OLDLDFLAGS"
 
+dnl ipv6 support
+if test "$PF_INET6" = "yes"; then
+  AC_CHECKING([for struct sockaddr_in6 for IPv6 support])
+  AC_CHECK_TYPE(
+      [struct sockaddr_in6],
+      [AC_DEFINE(USE_PF_INET6, 1, [struct sockaddr_in6 is needed for IPv6 peer support])],
+      [],
+      [#include "syshead.h"])
+fi
+
 dnl
 dnl check for valgrind tool
 dnl
diff --git a/init.c b/init.c
index a51b7d435b06dbe0be26ea826f6325f1aedd6636..e9cb0899324624e17f1bf99659ed3f576432ef56 100644 (file)
--- a/init.c
+++ b/init.c
@@ -96,7 +96,7 @@ update_options_ce_post (struct options *options)
    */
   if (options->pull
       && options->ping_rec_timeout_action == PING_UNDEF
-      && options->ce.proto == PROTO_UDPv4)
+      && proto_is_dgram(options->ce.proto))
     {
       options->ping_rec_timeout = PRE_PULL_INITIAL_PING_RESTART;
       options->ping_rec_timeout_action = PING_RESTART;
@@ -1150,7 +1150,7 @@ initialization_sequence_completed (struct context *c, const unsigned int flags)
       const char *detail = "SUCCESS";
       if (c->c1.tuntap)
        tun_local = c->c1.tuntap->local;
-      tun_remote = htonl (c->c1.link_socket_addr.actual.dest.sa.sin_addr.s_addr);
+      tun_remote = htonl (c->c1.link_socket_addr.actual.dest.addr.in4.sin_addr.s_addr);
       if (flags & ISC_ERRORS)
        detail = "ERROR";
       management_set_state (management,
@@ -1569,7 +1569,7 @@ do_deferred_options (struct context *c, const unsigned int found)
 #ifdef ENABLE_OCC
   if (found & OPT_P_EXPLICIT_NOTIFY)
     {
-      if (c->options.ce.proto != PROTO_UDPv4 && c->options.explicit_exit_notification)
+      if (!proto_is_udp(c->options.ce.proto) && c->options.explicit_exit_notification)
        {
          msg (D_PUSH, "OPTIONS IMPORT: --explicit-exit-notify can only be used with --proto udp");
          c->options.explicit_exit_notification = 0;
@@ -1664,13 +1664,22 @@ socket_restart_pause (struct context *c)
   switch (c->options.ce.proto)
     {
     case PROTO_UDPv4:
+#ifdef USE_PF_INET6
+    case PROTO_UDPv6:
+#endif
       if (proxy)
        sec = c->options.ce.connect_retry_seconds;
       break;
     case PROTO_TCPv4_SERVER:
+#ifdef USE_PF_INET6
+    case PROTO_TCPv6_SERVER:
+#endif
       sec = 1;
       break;
     case PROTO_TCPv4_CLIENT:
+#ifdef USE_PF_INET6
+    case PROTO_TCPv6_CLIENT:
+#endif
       sec = c->options.ce.connect_retry_seconds;
       break;
     }
@@ -2810,7 +2819,7 @@ do_setup_fast_io (struct context *c)
 #ifdef WIN32
       msg (M_INFO, "NOTE: --fast-io is disabled since we are running on Windows");
 #else
-      if (c->options.ce.proto != PROTO_UDPv4)
+      if (!proto_is_udp(c->options.ce.proto))
        msg (M_INFO, "NOTE: --fast-io is disabled since we are not using UDP");
       else
        {
@@ -3086,7 +3095,11 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
   /* link_socket_mode allows CM_CHILD_TCP
      instances to inherit acceptable fds
      from a top-level parent */
+#ifdef USE_PF_INET6
+  if (c->options.ce.proto == PROTO_TCPv4_SERVER || c->options.ce.proto == PROTO_TCPv6_SERVER)
+#else
   if (c->options.ce.proto == PROTO_TCPv4_SERVER)
+#endif
     {
       if (c->mode == CM_TOP)
        link_socket_mode = LS_MODE_TCP_LISTEN;
@@ -3361,17 +3374,8 @@ inherit_context_child (struct context *dest,
 {
   CLEAR (*dest);
 
-  switch (src->options.ce.proto)
-    {
-    case PROTO_UDPv4:
-      dest->mode = CM_CHILD_UDP;
-      break;
-    case PROTO_TCPv4_SERVER:
-      dest->mode = CM_CHILD_TCP;
-      break;
-    default:
-      ASSERT (0);
-    }
+  /* proto_is_dgram will ASSERT(0) if proto is invalid */
+  dest->mode = proto_is_dgram(src->options.ce.proto)? CM_CHILD_UDP : CM_CHILD_TCP;
 
   dest->gc = gc_new ();
 
@@ -3477,7 +3481,7 @@ inherit_context_top (struct context *dest,
   dest->c2.es_owned = false;
 
   dest->c2.event_set = NULL;
-  if (src->options.ce.proto == PROTO_UDPv4)
+  if (proto_is_dgram(src->options.ce.proto))
     do_event_set_init (dest, false);
 }
 
index 310a70ebbe82a297b910beed0a42e0dff2fdb566..a4fd258c9881c4b455dccf517b1714415c39dad7 100644 (file)
--- a/manage.c
+++ b/manage.c
@@ -1999,9 +1999,9 @@ man_settings_init (struct man_settings *ms,
          /*
           * Initialize socket address
           */
-         ms->local.sa.sin_family = AF_INET;
-         ms->local.sa.sin_addr.s_addr = 0;
-         ms->local.sa.sin_port = htons (port);
+         ms->local.addr.in4.sin_family = AF_INET;
+         ms->local.addr.in4.sin_addr.s_addr = 0;
+         ms->local.addr.in4.sin_port = htons (port);
 
          /*
           * Run management over tunnel, or
@@ -2013,7 +2013,7 @@ man_settings_init (struct man_settings *ms,
            }
          else
            {
-             ms->local.sa.sin_addr.s_addr = getaddr
+             ms->local.addr.in4.sin_addr.s_addr = getaddr
                (GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL, addr, 0, NULL, NULL);
            }
        }
@@ -2472,7 +2472,7 @@ management_post_tunnel_open (struct management *man, const in_addr_t tun_local_i
       && man->connection.state == MS_INITIAL)
     {
       /* listen on our local TUN/TAP IP address */
-      man->settings.local.sa.sin_addr.s_addr = htonl (tun_local_ip);
+      man->settings.local.addr.in4.sin_addr.s_addr = htonl (tun_local_ip);
       man_connection_init (man);
     }
 
index 3debd80f2c02b6f3f23886cee217382cc2afe895..7477a51050fba5a2a0c72fa1ba31aa1a25e9bc9a 100644 (file)
--- a/mroute.c
+++ b/mroute.c
@@ -226,25 +226,47 @@ bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr,
                                      const struct openvpn_sockaddr *osaddr,
                                      bool use_port)
 {
-  if (osaddr->sa.sin_family == AF_INET)
+  switch (osaddr->addr.sa.sa_family) 
+  {
+    case AF_INET:
     {
       if (use_port)
        {
          addr->type = MR_ADDR_IPV4 | MR_WITH_PORT;
          addr->netbits = 0;
          addr->len = 6;
-         memcpy (addr->addr, &osaddr->sa.sin_addr.s_addr, 4);
-         memcpy (addr->addr + 4, &osaddr->sa.sin_port, 2);
+         memcpy (addr->addr, &osaddr->addr.in4.sin_addr.s_addr, 4);
+         memcpy (addr->addr + 4, &osaddr->addr.in4.sin_port, 2);
        }
       else
        {
          addr->type = MR_ADDR_IPV4;
          addr->netbits = 0;
          addr->len = 4;
-         memcpy (addr->addr, &osaddr->sa.sin_addr.s_addr, 4);
+         memcpy (addr->addr, &osaddr->addr.in4.sin_addr.s_addr, 4);
        }
       return true;
     }
+#ifdef USE_PF_INET6
+    case AF_INET6:
+      if (use_port)
+       {
+         addr->type = MR_ADDR_IPV6 | MR_WITH_PORT;
+         addr->netbits = 0;
+         addr->len = 18;
+         memcpy (addr->addr, &osaddr->addr.in6.sin6_addr, 16);
+         memcpy (addr->addr + 16, &osaddr->addr.in6.sin6_port, 2);
+       }
+      else
+       {
+         addr->type = MR_ADDR_IPV6;
+         addr->netbits = 0;
+         addr->len = 16;
+         memcpy (addr->addr, &osaddr->addr.in6.sin6_addr, 16);
+       }
+      return true;
+#endif
+  }
   return false;
 }
 
@@ -337,7 +359,37 @@ mroute_addr_print_ex (const struct mroute_addr *ma,
          }
          break;
        case MR_ADDR_IPV6:
+#ifdef USE_PF_INET6
+          {
+           struct buffer buf;
+           struct sockaddr_in6 sin6;
+           int port;
+           char buf6[INET6_ADDRSTRLEN] = "";
+           memset(&sin6, 0, sizeof sin6);
+           sin6.sin6_family = AF_INET6;
+           buf_set_read (&buf, maddr.addr, maddr.len);
+            if (buf_read(&buf, &sin6.sin6_addr, sizeof (sin6.sin6_addr)))
+            {
+              if (getnameinfo((struct sockaddr *)&sin6, sizeof (struct sockaddr_in6),
+                                      buf6, sizeof (buf6), NULL, 0, NI_NUMERICHOST) != 0)
+                {
+                  buf_printf (&out, "MR_ADDR_IPV6 getnameinfo() err");
+                  break;
+               }
+              buf_puts (&out, buf6);
+             if (maddr.type & MR_WITH_NETBITS)
+               buf_printf (&out, "/%d", maddr.netbits);
+              if (maddr.type & MR_WITH_PORT)
+                {
+                  port = buf_read_u16 (&buf);
+                  if (port >= 0)
+                    buf_printf (&out, ":%d", port);
+                }
+           }
+          }
+#else /* old pre IPV6 1-line code: */
          buf_printf (&out, "IPV6"); 
+#endif
          break;
        default:
          buf_printf (&out, "UNKNOWN"); 
diff --git a/mtcp.c b/mtcp.c
index 314aa4477b1ca3689a165344f59cd8f8055fc565..f8cc50ffde3ea15b1ff7d87f85d979091f406eae 100644 (file)
--- a/mtcp.c
+++ b/mtcp.c
@@ -150,6 +150,7 @@ multi_tcp_instance_specific_init (struct multi_context *m, struct multi_instance
   ASSERT (mi->context.c2.link_socket);
   ASSERT (mi->context.c2.link_socket->info.lsa);
   ASSERT (mi->context.c2.link_socket->mode == LS_MODE_TCP_ACCEPT_FROM);
+  ASSERT (mi->context.c2.link_socket->info.lsa->actual.dest.addr.sa.sa_family == AF_INET);
   if (!mroute_extract_openvpn_sockaddr (&mi->real, &mi->context.c2.link_socket->info.lsa->actual.dest, true))
     {
       msg (D_MULTI_ERRORS, "MULTI TCP: TCP client address is undefined");
diff --git a/multi.c b/multi.c
index cc3c4cb3b54cf28b59085c28779a74693a00c018..0196be9e050d9ef1cc4aea863b9df1c19ad4e1e9 100644 (file)
--- a/multi.c
+++ b/multi.c
@@ -1058,8 +1058,8 @@ multi_learn_in_addr_t (struct multi_context *m,
   struct mroute_addr addr;
 
   CLEAR (remote_si);
-  remote_si.sa.sin_family = AF_INET;
-  remote_si.sa.sin_addr.s_addr = htonl (a);
+  remote_si.addr.in4.sin_family = AF_INET;
+  remote_si.addr.in4.sin_addr.s_addr = htonl (a);
   ASSERT (mroute_extract_openvpn_sockaddr (&addr, &remote_si, false));
 
   if (netbits >= 0)
@@ -2496,9 +2496,9 @@ management_callback_kill_by_addr (void *arg, const in_addr_t addr, const int por
   int count = 0;
 
   CLEAR (saddr);
-  saddr.sa.sin_family = AF_INET;
-  saddr.sa.sin_addr.s_addr = htonl (addr);
-  saddr.sa.sin_port = htons (port);
+  saddr.addr.in4.sin_family = AF_INET;
+  saddr.addr.in4.sin_addr.s_addr = htonl (addr);
+  saddr.addr.in4.sin_port = htons (port);
   if (mroute_extract_openvpn_sockaddr (&maddr, &saddr, true))
     {
       hash_iterator_init (m->iter, &hi);
@@ -2675,6 +2675,12 @@ tunnel_server (struct context *top)
 {
   ASSERT (top->options.mode == MODE_SERVER);
 
+#ifdef USE_PF_INET6
+  if (proto_is_dgram(top->options.ce.proto))
+    tunnel_server_udp(top);
+  else
+    tunnel_server_tcp(top);
+#else
   switch (top->options.ce.proto) {
   case PROTO_UDPv4:
     tunnel_server_udp (top);
@@ -2685,6 +2691,7 @@ tunnel_server (struct context *top)
   default:
     ASSERT (0);
   }
+#endif
 }
 
 #else
diff --git a/occ.c b/occ.c
index b84b18d9e9ca41e7a5d6194ba15a3b565f02bbc4..bcf91cc2643acfb6b02b1dd11dac5ff93f9668e5 100644 (file)
--- a/occ.c
+++ b/occ.c
@@ -369,7 +369,7 @@ process_received_occ_msg (struct context *c)
               c->c2.max_send_size_remote,
               c->c2.max_recv_size_local);
          if (!c->options.fragment
-             && c->options.ce.proto == PROTO_UDPv4
+             && (proto_is_dgram(c->options.ce.proto))
              && c->c2.max_send_size_local > TUN_MTU_MIN
              && (c->c2.max_recv_size_remote < c->c2.max_send_size_local
                  || c->c2.max_recv_size_local < c->c2.max_send_size_remote))
index fca4a8e3de78fb7ec3a040c56251262b52dbf415..ec219298e3881d226f94f059bfb2a8bb348e50c4 100644 (file)
--- a/options.c
+++ b/options.c
@@ -79,6 +79,11 @@ const char title_string[] =
 #endif
 #ifdef ENABLE_EUREPHIA
   " [eurephia]"
+#ifdef ENABLE_IP_PKTINFO
+  " [MH]"
+#endif
+#ifdef USE_PF_INET6
+  " [PF_INET6]"
 #endif
   " built on " __DATE__
 ;
@@ -102,6 +107,9 @@ static const char usage_message[] =
   "--proto p       : Use protocol p for communicating with peer.\n"
   "                  p = udp (default), tcp-server, or tcp-client\n"
   "--proto-force p : only consider protocol p in list of connection profiles.\n"
+#ifdef USE_PF_INET6
+  "                  p = udp6, tcp6-server, or tcp6-client (IPv6)\n"
+#endif
   "--connect-retry n : For --proto tcp-client, number of seconds to wait\n"
   "                    between connection retries (default=%d).\n"
   "--connect-timeout n : For --proto tcp-client, connection timeout (in seconds).\n"
@@ -1695,10 +1703,10 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
    * Sanity check on TCP mode options
    */
 
-  if (ce->connect_retry_defined && ce->proto != PROTO_TCPv4_CLIENT)
+  if (ce->connect_retry_defined && ce->proto != PROTO_TCPv4_CLIENT && ce->proto != PROTO_TCPv6_CLIENT)
     msg (M_USAGE, "--connect-retry doesn't make sense unless also used with --proto tcp-client");
 
-  if (ce->connect_timeout_defined && ce->proto != PROTO_TCPv4_CLIENT)
+  if (ce->connect_timeout_defined && ce->proto != PROTO_TCPv4_CLIENT && ce->proto != PROTO_TCPv6_CLIENT)
     msg (M_USAGE, "--connect-timeout doesn't make sense unless also used with --proto tcp-client");
 
   /*
@@ -1708,7 +1716,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
     msg (M_USAGE, "only one of --tun-mtu or --link-mtu may be defined (note that --ifconfig implies --link-mtu %d)", LINK_MTU_DEFAULT);
 
 #ifdef ENABLE_OCC
-  if (ce->proto != PROTO_UDPv4 && options->mtu_test)
+  if (!proto_is_udp(ce->proto) && options->mtu_test)
     msg (M_USAGE, "--mtu-test only makes sense with --proto udp");
 #endif
 
@@ -1721,7 +1729,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
    * Sanity check on --local, --remote, and --ifconfig
    */
 
-  if (string_defined_equal (ce->local, ce->remote)
+  if (proto_is_net(ce->proto)
+      && string_defined_equal (ce->local, ce->remote)
       && ce->local_port == ce->remote_port)
     msg (M_USAGE, "--remote and --local addresses are the same");
   
@@ -1786,16 +1795,16 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
    */
 
 #ifdef ENABLE_FRAGMENT
-  if (ce->proto != PROTO_UDPv4 && options->fragment)
+  if (!proto_is_udp(ce->proto) && options->fragment)
     msg (M_USAGE, "--fragment can only be used with --proto udp");
 #endif
 
 #ifdef ENABLE_OCC
-  if (ce->proto != PROTO_UDPv4 && options->explicit_exit_notification)
+  if (!proto_is_udp(ce->proto) && options->explicit_exit_notification)
     msg (M_USAGE, "--explicit-exit-notify can only be used with --proto udp");
 #endif
 
-  if (!ce->remote && ce->proto == PROTO_TCPv4_CLIENT)
+  if (!ce->remote && (ce->proto == PROTO_TCPv4_CLIENT || ce->proto == PROTO_TCPv6_CLIENT))
     msg (M_USAGE, "--remote MUST be used in TCP Client mode");
 
 #ifdef ENABLE_HTTP_PROXY
@@ -1813,7 +1822,8 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
     msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode");
 #endif
 
-  if (ce->proto == PROTO_TCPv4_SERVER && connection_list_defined (options))
+  if ((ce->proto == PROTO_TCPv4_SERVER || ce->proto == PROTO_TCPv6_SERVER)
+       && connection_list_defined (options))
     msg (M_USAGE, "TCP server mode allows at most one --remote address");
 
 #if P2MP_SERVER
@@ -1827,10 +1837,11 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
        msg (M_USAGE, "--mode server only works with --dev tun or --dev tap");
       if (options->pull)
        msg (M_USAGE, "--pull cannot be used with --mode server");
-      if (!(ce->proto == PROTO_UDPv4 || ce->proto == PROTO_TCPv4_SERVER))
+      if (!(proto_is_udp(ce->proto) || ce->proto == PROTO_TCPv4_SERVER || ce->proto == PROTO_TCPv6_SERVER))
        msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server");
 #if PORT_SHARE
-      if ((options->port_share_host || options->port_share_port) && ce->proto != PROTO_TCPv4_SERVER)
+      if ((options->port_share_host || options->port_share_port) && 
+            (ce->proto != PROTO_TCPv4_SERVER && ce->proto != PROTO_TCPv6_SERVER))
        msg (M_USAGE, "--port-share only works in TCP server mode (--proto tcp-server)");
 #endif
       if (!options->tls_server)
@@ -1859,9 +1870,9 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
        msg (M_USAGE, "--inetd cannot be used with --mode server");
       if (options->ipchange)
        msg (M_USAGE, "--ipchange cannot be used with --mode server (use --client-connect instead)");
-      if (!(ce->proto == PROTO_UDPv4 || ce->proto == PROTO_TCPv4_SERVER))
+      if (!(proto_is_dgram(ce->proto) || ce->proto == PROTO_TCPv4_SERVER || ce->proto == PROTO_TCPv6_SERVER ))
        msg (M_USAGE, "--mode server currently only supports --proto udp or --proto tcp-server");
-      if (ce->proto != PROTO_UDPv4 && (options->cf_max || options->cf_per))
+      if (!proto_is_udp(ce->proto) && (options->cf_max || options->cf_per))
        msg (M_USAGE, "--connect-freq only works with --mode server --proto udp.  Try --max-clients instead.");
       if (!(dev == DEV_TYPE_TAP || (dev == DEV_TYPE_TUN && options->topology == TOP_SUBNET)) && options->ifconfig_pool_netmask)
        msg (M_USAGE, "The third parameter to --ifconfig-pool (netmask) is only valid in --dev tap mode");
@@ -1954,7 +1965,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
   /*
    * Check consistency of replay options
    */
-  if ((ce->proto != PROTO_UDPv4)
+  if ((!proto_is_udp(ce->proto))
       && (options->replay_window != defaults.replay_window
          || options->replay_time != defaults.replay_time))
     msg (M_USAGE, "--replay-window only makes sense with --proto udp");
@@ -2127,6 +2138,10 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce)
     {
       if (ce->proto == PROTO_TCPv4)
        ce->proto = PROTO_TCPv4_CLIENT;
+#ifdef USE_PF_INET6
+      else if (ce->proto == PROTO_TCPv6)
+       ce->proto = PROTO_TCPv6_CLIENT;
+#endif
     }
 #endif
 
diff --git a/ps.c b/ps.c
index 9b9723cbc6108bbbbac33eb452298258443a4516..049b39fb060013238d8166e15feb3fa1deafd4b7 100644 (file)
--- a/ps.c
+++ b/ps.c
@@ -320,9 +320,9 @@ sock_addr_set (struct openvpn_sockaddr *osaddr,
               const int port)
 {
   CLEAR (*osaddr);
-  osaddr->sa.sin_family = AF_INET;
-  osaddr->sa.sin_addr.s_addr = htonl (addr);
-  osaddr->sa.sin_port = htons (port);
+  osaddr->addr.in4.sin_family = AF_INET;
+  osaddr->addr.in4.sin_addr.s_addr = htonl (addr);
+  osaddr->addr.in4.sin_port = htons (port);
 }
 
 static inline void
index a49940d09cc8556babe9f9c98896dabf1c7e0981..67bd2eb6b30e8151cb34dd603e12a27480b1dfdd 100644 (file)
--- a/socket.c
+++ b/socket.c
 #include "memdbg.h"
 
 const int proto_overhead[] = { /* indexed by PROTO_x */
-  IPv4_UDP_HEADER_SIZE,
+  0,
+  IPv4_UDP_HEADER_SIZE, /* IPv4 */
   IPv4_TCP_HEADER_SIZE,
   IPv4_TCP_HEADER_SIZE,
-  IPv4_TCP_HEADER_SIZE
+#ifdef USE_PF_INET6
+  IPv6_UDP_HEADER_SIZE, /* IPv6 */
+  IPv6_TCP_HEADER_SIZE,
+  IPv6_TCP_HEADER_SIZE,
+  IPv6_TCP_HEADER_SIZE,
+#endif
 };
 
 /*
@@ -410,6 +416,8 @@ update_remote (const char* host,
               bool *changed,
               const unsigned int sockflags)
 {
+  switch(addr->addr.sa.sa_family) {
+  case AF_INET:
   if (host && addr)
     {
       const in_addr_t new_addr = getaddr (
@@ -418,12 +426,39 @@ update_remote (const char* host,
                                          1,
                                          NULL,
                                          NULL);
-      if (new_addr && addr->sa.sin_addr.s_addr != new_addr)
+      if (new_addr && addr->addr.in4.sin_addr.s_addr != new_addr)
        {
-         addr->sa.sin_addr.s_addr = new_addr;
+         addr->addr.in4.sin_addr.s_addr = new_addr;
          *changed = true;
        }
     }
+  break;
+#ifdef USE_PF_INET6
+    case AF_INET6: /* TODO(jjo): should adapt getaddr() + sf2gaf() for AF_INET6 */
+      if (host && addr)
+      {
+       struct addrinfo hints , *ai;
+       int err;
+       memset(&hints, 0, sizeof hints);
+       hints.ai_flags = AI_PASSIVE;
+       hints.ai_family = AF_INET6;
+       if ((err=getaddrinfo(host, NULL, &hints, &ai))==0)
+       {
+         struct sockaddr_in6 *sin6 = (struct sockaddr_in6*)ai->ai_addr;
+         if (IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &addr->addr.in6.sin6_addr))
+         {
+           int port = addr->addr.in6.sin6_port; /* backup current port for easier copy, restore later */
+           addr->addr.in6 = *sin6; /* ipv6 requires also eg. sin6_scope_id => easy to full copy*/
+           addr->addr.in6.sin6_port = port;
+         }
+         freeaddrinfo(ai);
+       }
+      }
+      break;
+#endif
+    default:
+       ASSERT(0);
+  }
 }
 
 static int
@@ -616,6 +651,44 @@ create_socket_udp (const unsigned int flags)
   return sd;
 }
 
+#ifdef USE_PF_INET6
+static socket_descriptor_t
+create_socket_udp6 (const unsigned int flags)
+{
+  socket_descriptor_t sd;
+
+  if ((sd = socket (PF_INET6, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+    msg (M_SOCKERR, "UDP: Cannot create UDP6 socket");
+#if ENABLE_IP_PKTINFO
+  else if (flags & SF_USE_IP_PKTINFO)
+    {
+      int pad = 1;
+      setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO, (void*)&pad, sizeof(pad));
+    }
+#endif
+  return sd;
+}
+
+static socket_descriptor_t
+create_socket_tcp6 (void)
+{
+  socket_descriptor_t sd;
+
+  if ((sd = socket (PF_INET6, SOCK_STREAM, IPPROTO_TCP)) < 0)
+    msg (M_SOCKERR, "Cannot create TCP6 socket");
+
+  /* set SO_REUSEADDR on socket */
+  {
+    int on = 1;
+    if (setsockopt (sd, SOL_SOCKET, SO_REUSEADDR,
+                   (void *) &on, sizeof (on)) < 0)
+      msg (M_SOCKERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP6 socket");
+  }
+
+  return sd;
+}
+
+#endif
 static void
 create_socket (struct link_socket *sock)
 {
@@ -634,6 +707,17 @@ create_socket (struct link_socket *sock)
     {
       sock->sd = create_socket_tcp ();
     }
+#ifdef USE_PF_INET6
+  else if (sock->info.proto == PROTO_TCPv6_SERVER
+          || sock->info.proto == PROTO_TCPv6_CLIENT)
+    {
+      sock->sd = create_socket_tcp6 ();
+    }
+  else if (sock->info.proto == PROTO_UDPv6)
+    {
+      sock->sd = create_socket_udp6 (sock->sockflags);
+    }
+#endif
   else
     {
       ASSERT (0);
@@ -671,7 +755,12 @@ socket_do_accept (socket_descriptor_t sd,
                  struct link_socket_actual *act,
                  const bool nowait)
 {
-  socklen_t remote_len = sizeof (act->dest.sa);
+  /* af_addr_size WILL return 0 in this case if AFs other than AF_INET
+   * are compiled because act is empty here.
+   * could use getsockname() to support later remote_len check
+   */
+  socklen_t remote_len_af = af_addr_size(act->dest.addr.sa.sa_family);
+  socklen_t remote_len = sizeof(act->dest.addr);
   socket_descriptor_t new_sd = SOCKET_UNDEFINED;
 
   CLEAR (*act);
@@ -679,7 +768,7 @@ socket_do_accept (socket_descriptor_t sd,
 #ifdef HAVE_GETPEERNAME
   if (nowait)
     {
-      new_sd = getpeername (sd, (struct sockaddr *) &act->dest.sa, &remote_len);
+      new_sd = getpeername (sd, &act->dest.addr.sa, &remote_len);
 
       if (!socket_defined (new_sd))
        msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: getpeername() failed");
@@ -692,7 +781,7 @@ socket_do_accept (socket_descriptor_t sd,
 #endif
   else
     {
-      new_sd = accept (sd, (struct sockaddr *) &act->dest.sa, &remote_len);
+      new_sd = accept (sd, &act->dest.addr.sa, &remote_len);
     }
 
 #if 0 /* For debugging only, test the effect of accept() failures */
@@ -708,7 +797,8 @@ socket_do_accept (socket_descriptor_t sd,
     {
       msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: accept(%d) failed", sd);
     }
-  else if (remote_len != sizeof (act->dest.sa))
+  /* only valid if we have remote_len_af!=0 */
+  else if (remote_len_af && remote_len != remote_len_af)
     {
       msg (D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len);
       openvpn_close_socket (new_sd);
@@ -809,7 +899,7 @@ socket_bind (socket_descriptor_t sd,
 {
   struct gc_arena gc = gc_new ();
 
-  if (bind (sd, (struct sockaddr *) &local->sa, sizeof (local->sa)))
+  if (bind (sd, &local->addr.sa, af_addr_size(local->addr.sa.sa_family)))
     {
       const int errnum = openvpn_errno_socket ();
       msg (M_FATAL, "%s: Socket bind failed on local address %s: %s",
@@ -830,7 +920,7 @@ openvpn_connect (socket_descriptor_t sd,
 
 #ifdef CONNECT_NONBLOCK
   set_nonblock (sd);
-  status = connect (sd, (struct sockaddr *) &remote->sa, sizeof (remote->sa));
+  status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family));
   if (status)
     status = openvpn_errno_socket ();
   if (status == EINPROGRESS)
@@ -1030,17 +1120,44 @@ resolve_bind_local (struct link_socket *sock)
 
   /* resolve local address if undefined */
   if (!addr_defined (&sock->info.lsa->local))
-    {
-      sock->info.lsa->local.sa.sin_family = AF_INET;
-      sock->info.lsa->local.sa.sin_addr.s_addr =
-       (sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL,
-                                    sock->local_host,
-                                    0,
-                                    NULL,
-                                    NULL)
-        : htonl (INADDR_ANY));
-      sock->info.lsa->local.sa.sin_port = htons (sock->local_port);
+  {
+    /* may return AF_{INET|INET6} guessed from local_host */
+    switch(addr_guess_family(sock->info.proto, sock->local_host)) {
+      case AF_INET:
+       sock->info.lsa->local.addr.in4.sin_family = AF_INET;
+       sock->info.lsa->local.addr.in4.sin_addr.s_addr =
+         (sock->local_host ? getaddr (GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL | GETADDR_FATAL,
+                                      sock->local_host,
+                                      0,
+                                      NULL,
+                                      NULL)
+          : htonl (INADDR_ANY));
+       sock->info.lsa->local.addr.in4.sin_port = htons (sock->local_port);
+       break;
+#ifdef USE_PF_INET6
+      case AF_INET6:
+       {
+         struct addrinfo hints , *ai;
+         int err;
+         memset(&hints, 0, sizeof hints);
+         hints.ai_flags=AI_PASSIVE;
+         hints.ai_family=AF_INET6;
+         /* if no local_host provided, ask for IN6ADDR_ANY ... */
+         if ((err=getaddrinfo(sock->local_host? sock->local_host : "::", 
+                 NULL, &hints, &ai))==0) {
+           sock->info.lsa->local.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr));
+           freeaddrinfo(ai);
+         } else {
+           msg (M_FATAL, "getaddrinfo() failed for local \"%s\": %s",
+               sock->local_host,
+               gai_strerror(err));
+         }
+         sock->info.lsa->local.addr.in6.sin6_port = htons (sock->local_port);
+       }
+       break;
+#endif
     }
+  }
   
   /* bind to local address/port */
   if (sock->bind_local)
@@ -1068,8 +1185,11 @@ resolve_remote (struct link_socket *sock,
       /* resolve remote address if undefined */
       if (!addr_defined (&sock->info.lsa->remote))
        {
-         sock->info.lsa->remote.sa.sin_family = AF_INET;
-         sock->info.lsa->remote.sa.sin_addr.s_addr = 0;
+          switch(addr_guess_family(sock->info.proto, sock->remote_host)) 
+          {
+          case AF_INET:
+         sock->info.lsa->remote.addr.in4.sin_family = AF_INET;
+         sock->info.lsa->remote.addr.in4.sin_addr.s_addr = 0;
 
          if (sock->remote_host)
            {
@@ -1112,7 +1232,7 @@ resolve_remote (struct link_socket *sock,
                  ASSERT (0);
                }
 
-             sock->info.lsa->remote.sa.sin_addr.s_addr = getaddr (
+             sock->info.lsa->remote.addr.in4.sin_addr.s_addr = getaddr (
                    flags,
                    sock->remote_host,
                    retry,
@@ -1139,7 +1259,29 @@ resolve_remote (struct link_socket *sock,
                }
            }
 
-         sock->info.lsa->remote.sa.sin_port = htons (sock->remote_port);
+         sock->info.lsa->remote.addr.in4.sin_port = htons (sock->remote_port);
+          break;
+#ifdef USE_PF_INET6
+       case AF_INET6: /* TODO(jjo): ipv6 signal logic */
+         {
+           struct addrinfo hints , *ai;
+           int err;
+           memset(&hints, 0, sizeof hints);
+           hints.ai_flags=0;
+           hints.ai_family=AF_INET6;
+           if ((err=getaddrinfo(sock->remote_host? sock->remote_host : "::" , NULL, &hints, &ai))==0) {
+             sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr));
+             freeaddrinfo(ai);
+           } else {
+             msg (M_FATAL, "getaddrinfo() failed for remote \"%s\": %s",
+                 sock->remote_host,
+                 gai_strerror(err));
+           }
+           sock->info.lsa->remote.addr.in6.sin6_port = htons (sock->remote_port);
+         }
+         break;
+#endif
+          }
        }
   
       /* should we re-use previous active remote address? */
@@ -1384,7 +1526,11 @@ link_socket_init_phase2 (struct link_socket *sock,
        goto done;
 
       /* TCP client/server */
-      if (sock->info.proto == PROTO_TCPv4_SERVER)
+      if (sock->info.proto == PROTO_TCPv4_SERVER
+#ifdef USE_PF_INET6
+       ||sock->info.proto == PROTO_TCPv6_SERVER
+#endif
+       )
        {
          switch (sock->mode)
            {
@@ -1419,7 +1565,11 @@ link_socket_init_phase2 (struct link_socket *sock,
              ASSERT (0);
            }
        }
-      else if (sock->info.proto == PROTO_TCPv4_CLIENT)
+      else if (sock->info.proto == PROTO_TCPv4_CLIENT
+#ifdef USE_PF_INET6
+       ||sock->info.proto == PROTO_TCPv6_CLIENT
+#endif
+       )
        {
 
 #ifdef GENERAL_PROXY_SUPPORT
@@ -1506,8 +1656,8 @@ link_socket_init_phase2 (struct link_socket *sock,
          sock->remote_port = sock->proxy_dest_port;
          sock->did_resolve_remote = false;
 
-         sock->info.lsa->actual.dest.sa.sin_addr.s_addr = 0;
-         sock->info.lsa->remote.sa.sin_addr.s_addr = 0;
+         addr_zero_host(&sock->info.lsa->actual.dest);
+         addr_zero_host(&sock->info.lsa->remote);
 
          resolve_remote (sock, 1, NULL, signal_received);
 
@@ -1522,7 +1672,7 @@ link_socket_init_phase2 (struct link_socket *sock,
       if (remote_changed)
        {
          msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment");
-         sock->info.lsa->remote.sa.sin_addr.s_addr = sock->info.lsa->actual.dest.sa.sin_addr.s_addr;
+         addr_copy_host(&sock->info.lsa->remote, &sock->info.lsa->actual.dest);
        }
     }
 
@@ -1708,13 +1858,20 @@ link_socket_bad_incoming_addr (struct buffer *buf,
 {
   struct gc_arena gc = gc_new ();
 
-  msg (D_LINK_ERRORS,
-       "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)",
-       print_link_socket_actual (from_addr, &gc),
-       (int)from_addr->dest.sa.sin_family,
-       print_sockaddr (&info->lsa->remote, &gc));
+  switch(from_addr->dest.addr.sa.sa_family)
+  {
+    case AF_INET:
+#ifdef USE_PF_INET6
+    case AF_INET6:
+#endif
+      msg (D_LINK_ERRORS,
+         "TCP/UDP: Incoming packet rejected from %s[%d], expected peer address: %s (allow this incoming source address/port by removing --remote or adding --float)",
+         print_link_socket_actual (from_addr, &gc),
+         (int)from_addr->dest.addr.sa.sa_family,
+         print_sockaddr (&info->lsa->remote, &gc));
+      break;
+  }
   buf->len = 0;
-
   gc_free (&gc);
 }
 
@@ -1729,10 +1886,25 @@ link_socket_current_remote (const struct link_socket_info *info)
 {
   const struct link_socket_addr *lsa = info->lsa;
 
+/* 
+ * This logic supports "redirect-gateway" semantic, which 
+ * makes sense only for PF_INET routes over PF_INET endpoints
+ *
+ * Maybe in the future consider PF_INET6 endpoints also ...
+ * by now just ignore it
+ *
+ */
+#if defined ( USE_PF_INET6 )
+  if(lsa->actual.dest.addr.sa.sa_family != AF_INET)
+         return 0;
+#else
+  ASSERT(lsa->actual.dest.addr.sa.sa_family == AF_INET);
+#endif
+
   if (link_socket_actual_defined (&lsa->actual))
-    return ntohl (lsa->actual.dest.sa.sin_addr.s_addr);
+    return ntohl (lsa->actual.dest.addr.in4.sin_addr.s_addr);
   else if (addr_defined (&lsa->remote))
-    return ntohl (lsa->remote.sa.sin_addr.s_addr);
+    return ntohl (lsa->remote.addr.in4.sin_addr.s_addr);
   else
     return 0;
 }
@@ -1959,26 +2131,58 @@ print_sockaddr_ex (const struct openvpn_sockaddr *addr,
                   const unsigned int flags,
                   struct gc_arena *gc)
 {
-  if (addr)
-    {
-      struct buffer out = alloc_buf_gc (64, gc);
-      const int port = ntohs (addr->sa.sin_port);
-
-      if (!(flags & PS_DONT_SHOW_ADDR))
-       buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sa.sin_addr) : "[undef]"));
-
-      if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED)))
-         && port)
+  struct buffer out;
+  bool addr_is_defined;
+  if (!addr) {
+    return "[NULL]";
+  }
+  addr_is_defined =  addr_defined (addr);
+  switch(addr->addr.sa.sa_family) {
+    case AF_INET:
+      {
+       const int port= ntohs (addr->addr.in4.sin_port);
+       out = alloc_buf_gc (128, gc);
+       buf_puts (&out, "[AF_INET]");
+       mutex_lock_static (L_INET_NTOA);
+       buf_puts (&out, (addr_is_defined ? inet_ntoa (addr->addr.in4.sin_addr) : "[undef]"));
+       mutex_unlock_static (L_INET_NTOA);
+
+       if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED)))
+           && port)
        {
          if (separator)
            buf_printf (&out, "%s", separator);
 
          buf_printf (&out, "%d", port);
        }
-      return BSTR (&out);
-    }
-  else
-    return "[NULL]";
+        }
+        break;
+#ifdef USE_PF_INET6
+    case AF_INET6:
+      {
+       const int port= ntohs (addr->addr.in6.sin6_port);
+       char buf[INET6_ADDRSTRLEN] = "[undef]";
+       out = alloc_buf_gc (128, gc);
+       buf_puts (&out, "[AF_INET6]");
+       if (addr_is_defined)
+       {
+         getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6),
+             buf, sizeof (buf), NULL, 0, NI_NUMERICHOST);
+         buf_puts (&out, buf);
+       }
+       if (((flags & PS_SHOW_PORT) || (addr_is_defined && (flags & PS_SHOW_PORT_IF_DEFINED)))
+           && port)
+       {
+         if (separator)
+           buf_puts (&out, separator);
+
+         buf_printf (&out, "%d", port);
+       }
+      }
+      break;
+#endif
+  }
+  return BSTR (&out);
 }
 
 const char *
@@ -1998,12 +2202,38 @@ print_link_socket_actual_ex (const struct link_socket_actual *act,
       struct buffer out = alloc_buf_gc (128, gc);
       buf_printf (&out, "%s", print_sockaddr_ex (&act->dest, separator, flags, gc));
 #if ENABLE_IP_PKTINFO
-      if ((flags & PS_SHOW_PKTINFO) && act->pi.ipi_spec_dst.s_addr)
+      if ((flags & PS_SHOW_PKTINFO) && addr_defined_ipi(act))
        {
+         switch(act->dest.addr.sa.sa_family)
+         {
+       case AF_INET:
+         {
          struct openvpn_sockaddr sa;
          CLEAR (sa);
-         sa.sa.sin_addr = act->pi.ipi_spec_dst;
+         sa.addr.in4.sin_addr = act->pi.in4.ipi_spec_dst;
          buf_printf (&out, " (via %s)", print_sockaddr_ex (&sa, separator, 0, gc));
+         }
+         break;
+#ifdef USE_PF_INET6
+       case AF_INET6:
+         {
+           struct sockaddr_in6 sin6;
+           char buf[INET6_ADDRSTRLEN] = "[undef]";
+           memset(&sin6, 0, sizeof sin6);
+           sin6.sin6_family = AF_INET6;
+           sin6.sin6_addr = act->pi.in6.ipi6_addr;
+           {
+             if (getnameinfo((struct sockaddr *)&sin6, sizeof (struct sockaddr_in6),
+                   buf, sizeof (buf), NULL, 0, NI_NUMERICHOST) == 0)
+               buf_printf (&out, " (via %s)", buf);
+             else
+               buf_printf (&out, " (via [getnameinfo() err])");
+           }
+         }
+         break;
+#endif
+         }
+
        }
 #endif
       return BSTR (&out);
@@ -2037,19 +2267,37 @@ void
 setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const bool flags)
 {
   char name_buf[256];
+  char buf[128];
 
-  if (flags & SA_IP_PORT)
-    openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix);
-  else
-    openvpn_snprintf (name_buf, sizeof (name_buf), "%s", name_prefix);
+  switch(addr->addr.sa.sa_family) {
+    case AF_INET:
+      if (flags & SA_IP_PORT)
+       openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip", name_prefix);
+      else
+       openvpn_snprintf (name_buf, sizeof (name_buf), "%s", name_prefix);
 
-  setenv_str (es, name_buf, inet_ntoa (addr->sa.sin_addr));
+      mutex_lock_static (L_INET_NTOA);
+      setenv_str (es, name_buf, inet_ntoa (addr->addr.in4.sin_addr));
+      mutex_unlock_static (L_INET_NTOA);
+
+      if ((flags & SA_IP_PORT) && addr->addr.in4.sin_port)
+      {
+       openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix);
+       setenv_int (es, name_buf, ntohs (addr->addr.in4.sin_port));
+      }
+      break;
+#ifdef USE_PF_INET6
+    case AF_INET6:
+      openvpn_snprintf (name_buf, sizeof (name_buf), "%s_ip6", name_prefix);
+      getnameinfo(&addr->addr.sa, sizeof (struct sockaddr_in6),
+         buf, sizeof(buf), NULL, 0, NI_NUMERICHOST);
+      setenv_str (es, name_buf, buf);
 
-  if ((flags & SA_IP_PORT) && addr->sa.sin_port)
-    {
       openvpn_snprintf (name_buf, sizeof (name_buf), "%s_port", name_prefix);
-      setenv_int (es, name_buf, ntohs (addr->sa.sin_port));
-    }
+      setenv_int (es, name_buf, ntohs (addr->addr.in6.sin6_port));
+      break;
+#endif
+  }
 }
 
 void
@@ -2059,7 +2307,8 @@ setenv_in_addr_t (struct env_set *es, const char *name_prefix, in_addr_t addr, c
     {
       struct openvpn_sockaddr si;
       CLEAR (si);
-      si.sa.sin_addr.s_addr = htonl (addr);
+      si.addr.in4.sin_family = AF_INET;
+      si.addr.in4.sin_addr.s_addr = htonl (addr);
       setenv_sockaddr (es, name_prefix, &si, flags);
     }
 }
@@ -2080,16 +2329,63 @@ setenv_link_socket_actual (struct env_set *es,
 struct proto_names {
   const char *short_form;
   const char *display_form;
+  bool is_dgram;
+  bool is_net;
+  sa_family_t proto_af;
 };
 
 /* Indexed by PROTO_x */
-static const struct proto_names proto_names[] = {
-  {"udp",        "UDPv4"},
-  {"tcp-server", "TCPv4_SERVER"},
-  {"tcp-client", "TCPv4_CLIENT"},
-  {"tcp",        "TCPv4"}
+static const struct proto_names proto_names[PROTO_N] = {
+  {"proto-uninitialized",        "proto-NONE",0,0, AF_UNSPEC},
+  {"udp",        "UDPv4",1,1, AF_INET},
+  {"tcp-server", "TCPv4_SERVER",0,1, AF_INET},
+  {"tcp-client", "TCPv4_CLIENT",0,1, AF_INET},
+  {"tcp",        "TCPv4",0,1, AF_INET},
+#ifdef USE_PF_INET6
+  {"udp6"       ,"UDPv6",1,1, AF_INET6},
+  {"tcp6-server","TCPv6_SERVER",0,1, AF_INET6},
+  {"tcp6-client","TCPv6_CLIENT",0,1, AF_INET6},
+  {"tcp6"       ,"TCPv6",0,1, AF_INET6},
+#endif
 };
 
+bool
+proto_is_net(int proto)
+{
+  if (proto < 0 || proto >= PROTO_N)
+    ASSERT(0);
+  return proto_names[proto].is_net;
+}
+bool
+proto_is_dgram(int proto)
+{
+  if (proto < 0 || proto >= PROTO_N)
+    ASSERT(0);
+  return proto_names[proto].is_dgram;
+}
+bool
+proto_is_udp(int proto)
+{
+  if (proto < 0 || proto >= PROTO_N)
+    ASSERT(0);
+  return proto_names[proto].is_dgram&&proto_names[proto].is_net;
+}
+bool
+proto_is_tcp(int proto)
+{
+  if (proto < 0 || proto >= PROTO_N)
+    ASSERT(0);
+  return (!proto_names[proto].is_dgram)&&proto_names[proto].is_net;
+}
+
+sa_family_t 
+proto_sa_family(int proto)
+{
+  if (proto < 0 || proto >= PROTO_N)
+    ASSERT(0);
+  return proto_names[proto].proto_af;
+}
+
 int
 ascii2proto (const char* proto_name)
 {
@@ -2129,6 +2425,38 @@ proto2ascii_all (struct gc_arena *gc)
   return BSTR (&out);
 }
 
+int
+addr_guess_family(int proto, const char *name) 
+{
+  sa_family_t ret;
+  if (proto) {
+    return proto_sa_family(proto);     /* already stamped */
+  } 
+#ifdef USE_PF_INET6
+  else {
+    struct addrinfo hints , *ai;
+    int err;
+    memset(&hints, 0, sizeof hints);
+    hints.ai_flags=AI_NUMERICHOST;
+    if ((err=getaddrinfo(name, NULL, &hints, &ai))==0) {
+      ret=ai->ai_family;
+      freeaddrinfo(ai);
+      return ret;
+    }
+  }
+#endif
+  return AF_INET;      /* default */
+}
+const char *
+addr_family_name (int af) 
+{
+  switch (af) {
+    case AF_INET: return "AF_INET";
+    case AF_INET6: return "AF_INET6";
+  }
+  return "AF_UNSPEC";
+}
+
 /*
  * Given a local proto, return local proto
  * if !remote, or compatible remote proto
@@ -2143,10 +2471,15 @@ proto_remote (int proto, bool remote)
   ASSERT (proto >= 0 && proto < PROTO_N);
   if (remote)
     {
-      if (proto == PROTO_TCPv4_SERVER)
-       return PROTO_TCPv4_CLIENT;
-      if (proto == PROTO_TCPv4_CLIENT)
-       return PROTO_TCPv4_SERVER;
+      switch (proto)
+      {
+       case PROTO_TCPv4_SERVER: return PROTO_TCPv4_CLIENT;
+       case PROTO_TCPv4_CLIENT: return PROTO_TCPv4_SERVER;
+#ifdef USE_PF_INET6
+       case PROTO_TCPv6_SERVER: return PROTO_TCPv6_CLIENT;
+       case PROTO_TCPv6_CLIENT: return PROTO_TCPv6_SERVER;
+#endif
+      }
     }
   return proto;
 }
@@ -2205,10 +2538,24 @@ link_socket_read_tcp (struct link_socket *sock,
 #if ENABLE_IP_PKTINFO
 
 #pragma pack(1) /* needed to keep structure size consistent for 32 vs. 64-bit architectures */
-struct openvpn_pktinfo
+struct openvpn_in4_pktinfo
 {
   struct cmsghdr cmsghdr;
-  struct in_pktinfo in_pktinfo;
+  struct in_pktinfo pi;
+};
+#ifdef USE_PF_INET6
+struct openvpn_in6_pktinfo
+{
+  struct cmsghdr cmsghdr;
+  struct in6_pktinfo pi6;
+};
+#endif
+
+union openvpn_pktinfo {
+       struct openvpn_in4_pktinfo cmsgpi;
+#ifdef USE_PF_INET6
+       struct openvpn_in6_pktinfo cmsgpi6;
+#endif
 };
 #pragma pack()
 
@@ -2219,15 +2566,15 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
                                    struct link_socket_actual *from)
 {
   struct iovec iov;
-  struct openvpn_pktinfo opi;
+  union openvpn_pktinfo opi;
   struct msghdr mesg;
-  socklen_t fromlen = sizeof (from->dest.sa);
+  socklen_t fromlen = sizeof (from->dest.addr);
 
   iov.iov_base = BPTR (buf);
   iov.iov_len = maxsize;
   mesg.msg_iov = &iov;
   mesg.msg_iovlen = 1;
-  mesg.msg_name = &from->dest.sa;
+  mesg.msg_name = &from->dest.addr;
   mesg.msg_namelen = fromlen;
   mesg.msg_control = &opi;
   mesg.msg_controllen = sizeof (opi);
@@ -2244,9 +2591,21 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
          && cmsg->cmsg_len >= sizeof (opi))
        {
          struct in_pktinfo *pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
-         from->pi.ipi_ifindex = pkti->ipi_ifindex;
-         from->pi.ipi_spec_dst = pkti->ipi_spec_dst;
+         from->pi.in4.ipi_ifindex = pkti->ipi_ifindex;
+         from->pi.in4.ipi_spec_dst = pkti->ipi_spec_dst;
        }
+#ifdef USE_PF_INET6
+      else if (cmsg != NULL
+         && CMSG_NXTHDR (&mesg, cmsg) == NULL
+         && cmsg->cmsg_level == IPPROTO_IPV6 
+         && cmsg->cmsg_type == IPV6_PKTINFO
+         && cmsg->cmsg_len >= sizeof (struct openvpn_in6_pktinfo))
+       {
+         struct in6_pktinfo *pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg);
+         from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex;
+         from->pi.in6.ipi6_addr = pkti6->ipi6_addr;
+       }
+#endif
     }
   return fromlen;
 }
@@ -2258,18 +2617,20 @@ link_socket_read_udp_posix (struct link_socket *sock,
                            int maxsize,
                            struct link_socket_actual *from)
 {
-  socklen_t fromlen = sizeof (from->dest.sa);
-  from->dest.sa.sin_addr.s_addr = 0;
+  socklen_t fromlen = sizeof (from->dest.addr);
+  socklen_t expectedlen = af_addr_size(proto_sa_family(sock->info.proto));
+  addr_zero_host(&from->dest);
   ASSERT (buf_safe (buf, maxsize));
 #if ENABLE_IP_PKTINFO
-  if (sock->sockflags & SF_USE_IP_PKTINFO)
+  /* Both PROTO_UDPv4 and PROTO_UDPv6 */
+  if (proto_is_udp(sock->info.proto) && sock->sockflags & SF_USE_IP_PKTINFO)
     fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from);
   else
 #endif
     buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0,
-                        (struct sockaddr *) &from->dest.sa, &fromlen);
-  if (fromlen != sizeof (from->dest.sa))
-    bad_address_length (fromlen, sizeof (from->dest.sa));
+                        &from->dest.addr.sa, &fromlen);
+  if (buf->len >= 0 && expectedlen && fromlen != expectedlen)
+    bad_address_length (fromlen, expectedlen);
   return buf->len;
 }
 
@@ -2306,26 +2667,52 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
   struct iovec iov;
   struct msghdr mesg;
   struct cmsghdr *cmsg;
-  struct in_pktinfo *pkti;
-  struct openvpn_pktinfo opi;
 
   iov.iov_base = BPTR (buf);
   iov.iov_len = BLEN (buf);
   mesg.msg_iov = &iov;
   mesg.msg_iovlen = 1;
-  mesg.msg_name = &to->dest.sa;
-  mesg.msg_namelen = sizeof (to->dest.sa);
-  mesg.msg_control = &opi;
-  mesg.msg_controllen = sizeof (opi);
-  mesg.msg_flags = 0;
-  cmsg = CMSG_FIRSTHDR (&mesg);
-  cmsg->cmsg_len = sizeof (opi);
-  cmsg->cmsg_level = SOL_IP;
-  cmsg->cmsg_type = IP_PKTINFO;
-  pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
-  pkti->ipi_ifindex = to->pi.ipi_ifindex;
-  pkti->ipi_spec_dst = to->pi.ipi_spec_dst;
-  pkti->ipi_addr.s_addr = 0;
+  switch (sock->info.lsa->remote.addr.sa.sa_family)
+  {
+    case AF_INET: {
+         struct openvpn_in4_pktinfo opi;
+         struct in_pktinfo *pkti;
+         mesg.msg_name = &to->dest.addr.sa;
+         mesg.msg_namelen = sizeof (struct sockaddr_in);
+         mesg.msg_control = &opi;
+         mesg.msg_controllen = sizeof (opi);
+         mesg.msg_flags = 0;
+         cmsg = CMSG_FIRSTHDR (&mesg);
+         cmsg->cmsg_len = sizeof (opi);
+         cmsg->cmsg_level = SOL_IP;
+         cmsg->cmsg_type = IP_PKTINFO;
+         pkti = (struct in_pktinfo *) CMSG_DATA (cmsg);
+         pkti->ipi_ifindex = to->pi.in4.ipi_ifindex;
+         pkti->ipi_spec_dst = to->pi.in4.ipi_spec_dst;
+         pkti->ipi_addr.s_addr = 0;
+         break;
+    }
+#ifdef USE_PF_INET6
+    case AF_INET6: {
+         struct openvpn_in6_pktinfo opi6;
+         struct in6_pktinfo *pkti6;
+         mesg.msg_name = &to->dest.addr.sa;
+         mesg.msg_namelen = sizeof (struct sockaddr_in6);
+         mesg.msg_control = &opi6;
+         mesg.msg_controllen = sizeof (opi6);
+         mesg.msg_flags = 0;
+         cmsg = CMSG_FIRSTHDR (&mesg);
+         cmsg->cmsg_len = sizeof (opi6);
+         cmsg->cmsg_level = IPPROTO_IPV6;
+         cmsg->cmsg_type = IPV6_PKTINFO;
+         pkti6 = (struct in6_pktinfo *) CMSG_DATA (cmsg);
+         pkti6->ipi6_ifindex = to->pi.in6.ipi6_ifindex;
+         pkti6->ipi6_addr = to->pi.in6.ipi6_addr;
+         break;
+    }
+#endif
+    default: ASSERT(0);
+  }
   return sendmsg (sock->sd, &mesg, 0);
 }
 
@@ -2469,7 +2856,7 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct li
        {
          /* set destination address for UDP writes */
          sock->writes.addr_defined = true;
-         sock->writes.addr = to->dest.sa;
+         sock->writes.addr = to->dest.addr.in4;
          sock->writes.addrlen = sizeof (sock->writes.addr);
 
          status = WSASendTo(
@@ -2625,10 +3012,10 @@ socket_finalize (SOCKET s,
        {
          if (io->addrlen != sizeof (io->addr))
            bad_address_length (io->addrlen, sizeof (io->addr));
-         from->dest.sa = io->addr;
+         from->dest.addr.sa = io->addr;
        }
       else
-       CLEAR (from->dest.sa);
+       CLEAR (from->dest.addr.sa);
     }
   
   if (buf)
index eef98d1bd216ebb172d31341d2bb5bc5da74de20..ba8cd6e694c1faa2d47414b7418fecd6b075bd15 100644 (file)
--- a/socket.h
+++ b/socket.h
@@ -70,7 +70,13 @@ typedef uint16_t packet_size_type;
 struct openvpn_sockaddr
 {
   /*int dummy;*/ /* add offset to force a bug if sa not explicitly dereferenced */
-  struct sockaddr_in sa;
+  union {
+    struct sockaddr sa;
+    struct sockaddr_in in4;
+#ifdef USE_PF_INET6
+    struct sockaddr_in6 in6;
+#endif
+  } addr;
 };
 
 /* actual address of remote, based on source address of received packets */
@@ -79,7 +85,12 @@ struct link_socket_actual
   /*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */
   struct openvpn_sockaddr dest;
 #if ENABLE_IP_PKTINFO
-  struct in_pktinfo pi;
+  union {
+    struct in_pktinfo in4;
+#ifdef USE_PF_INET6
+    struct in6_pktinfo in6;
+#endif
+  } pi;
 #endif
 };
 
@@ -410,6 +421,14 @@ socket_descriptor_t create_socket_tcp (void);
 socket_descriptor_t socket_do_accept (socket_descriptor_t sd,
                                      struct link_socket_actual *act,
                                      const bool nowait);
+/*
+ * proto related
+ */
+bool proto_is_net(int proto);
+bool proto_is_dgram(int proto);
+bool proto_is_udp(int proto);
+bool proto_is_tcp(int proto);
+
 
 #if UNIX_SOCK_SUPPORT
 
@@ -472,23 +491,49 @@ in_addr_t getaddr_multi (unsigned int flags,
  * Transport protocol naming and other details.
  */
 
-#define PROTO_UDPv4        0
-#define PROTO_TCPv4_SERVER 1
-#define PROTO_TCPv4_CLIENT 2
-#define PROTO_TCPv4        3
-#define PROTO_N            4
+#if 0 /* PRE UDPv6/TCPv6 code */
+#define PROTO_NONE         0 /* catch for uninitialized */
+#define PROTO_UDPv4        1
+#define PROTO_TCPv4_SERVER 2
+#define PROTO_TCPv4_CLIENT 3
+#define PROTO_TCPv4        4
+#define PROTO_UDPv6        5
+#define PROTO_TCPv6_SERVER 6
+#define PROTO_TCPv6_CLIENT 7
+#define PROTO_TCPv6        8
+#define PROTO_N            9
+#endif /* if 0 */
+
+/* 
+ * Use enum's instead of #define to allow for easier
+ * optional proto support
+ */
+enum proto_num {
+       PROTO_NONE, /* catch for uninitialized */
+       PROTO_UDPv4,
+       PROTO_TCPv4_SERVER,
+       PROTO_TCPv4_CLIENT,
+       PROTO_TCPv4,
+       PROTO_UDPv6,
+       PROTO_TCPv6_SERVER,
+       PROTO_TCPv6_CLIENT,
+       PROTO_TCPv6,
+       PROTO_N
+};
 
 int ascii2proto (const char* proto_name);
 const char *proto2ascii (int proto, bool display_form);
 const char *proto2ascii_all (struct gc_arena *gc);
 int proto_remote (int proto, bool remote);
+const char *addr_family_name(int af);
 
 /*
  * Overhead added to packets by various protocols.
  */
 #define IPv4_UDP_HEADER_SIZE              28
 #define IPv4_TCP_HEADER_SIZE              40
-#define IPv6_UDP_HEADER_SIZE              40
+#define IPv6_UDP_HEADER_SIZE              48
+#define IPv6_TCP_HEADER_SIZE              60
 
 extern const int proto_overhead[];
 
@@ -518,7 +563,7 @@ is_proto_tcp(const int p)
 static inline bool
 link_socket_proto_connection_oriented (int proto)
 {
-  return proto == PROTO_TCPv4_SERVER || proto == PROTO_TCPv4_CLIENT;
+  return !proto_is_dgram(proto);
 }
 
 static inline bool
@@ -533,7 +578,30 @@ link_socket_connection_oriented (const struct link_socket *sock)
 static inline bool
 addr_defined (const struct openvpn_sockaddr *addr)
 {
-  return addr->sa.sin_addr.s_addr != 0;
+  if (!addr) return 0;
+  switch (addr->addr.sa.sa_family) {
+    case AF_INET: return addr->addr.in4.sin_addr.s_addr != 0;
+#ifdef USE_PF_INET6
+    case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&addr->addr.in6.sin6_addr);
+#endif
+    default: return 0;
+  }
+}
+static inline bool
+addr_defined_ipi (const struct link_socket_actual *lsa)
+{
+#if ENABLE_IP_PKTINFO
+  if (!lsa) return 0;
+  switch (lsa->dest.addr.sa.sa_family) {
+    case AF_INET: return lsa->pi.in4.ipi_spec_dst.s_addr != 0;
+#ifdef USE_PF_INET6
+    case AF_INET6: return !IN6_IS_ADDR_UNSPECIFIED(&lsa->pi.in6.ipi6_addr);
+#endif
+    default: return 0;
+  }
+#else
+  ASSERT(0);
+#endif
 }
 
 static inline bool
@@ -545,20 +613,50 @@ link_socket_actual_defined (const struct link_socket_actual *act)
 static inline bool
 addr_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
 {
-  return a1->sa.sin_addr.s_addr == a2->sa.sin_addr.s_addr;
+  switch(a1->addr.sa.sa_family) {
+    case AF_INET:
+      return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr;
+#ifdef USE_PF_INET6
+    case AF_INET6:
+      return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr);
+#endif
+  }
+  ASSERT(0);
+  return false;
 }
 
 static inline in_addr_t
-addr_host (const struct openvpn_sockaddr *s)
+addr_host (const struct openvpn_sockaddr *addr)
 {
-  return ntohl (s->sa.sin_addr.s_addr);
+  /* 
+   * "public" addr returned is checked against ifconfig for
+   * possible clash: non sense for now given
+   * that we do ifconfig only IPv4
+   */
+#if defined(USE_PF_INET6) 
+  if(addr->addr.sa.sa_family != AF_INET)
+    return 0;
+#else 
+  ASSERT(addr->addr.sa.sa_family == AF_INET);
+#endif
+  return ntohl (addr->addr.in4.sin_addr.s_addr);
 }
 
 static inline bool
 addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
 {
-  return a1->sa.sin_addr.s_addr == a2->sa.sin_addr.s_addr
-    && a1->sa.sin_port == a2->sa.sin_port;
+  switch(a1->addr.sa.sa_family) {
+    case AF_INET:
+      return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr
+       && a1->addr.in4.sin_port == a2->addr.in4.sin_port;
+#ifdef USE_PF_INET6
+    case AF_INET6:
+      return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr) 
+       && a1->addr.in6.sin6_port == a2->addr.in6.sin6_port;
+#endif
+  }
+  ASSERT(0);
+  return false;
 }
 
 static inline bool
@@ -571,6 +669,74 @@ addr_match_proto (const struct openvpn_sockaddr *a1,
     : addr_port_match (a1, a2);
 }
 
+static inline void
+addr_zero_host(struct openvpn_sockaddr *addr)
+{
+   switch(addr->addr.sa.sa_family) {
+     case AF_INET:
+       addr->addr.in4.sin_addr.s_addr = 0;
+       break;
+#ifdef USE_PF_INET6
+     case AF_INET6: 
+       memset(&addr->addr.in6.sin6_addr, 0, sizeof (struct in6_addr));
+       break;
+#endif
+   }
+}
+
+static inline void
+addr_copy_sa(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src)
+{
+  dst->addr = src->addr;
+}
+
+static inline void
+addr_copy_host(struct openvpn_sockaddr *dst, const struct openvpn_sockaddr *src)
+{
+   switch(src->addr.sa.sa_family) {
+     case AF_INET:
+       dst->addr.in4.sin_addr.s_addr = src->addr.in4.sin_addr.s_addr;
+       break;
+#ifdef USE_PF_INET6
+     case AF_INET6: 
+       dst->addr.in6.sin6_addr = src->addr.in6.sin6_addr;
+       break;
+#endif
+   }
+}
+
+static inline bool
+addr_inet4or6(struct sockaddr *addr)
+{
+       return addr->sa_family == AF_INET || addr->sa_family == AF_INET6;
+}
+
+int addr_guess_family(int proto, const char *name);
+static inline int
+af_addr_size(sa_family_t af)
+{
+#if defined(USE_PF_INET6) || defined (USE_PF_UNIX)
+   switch(af) {
+     case AF_INET: return sizeof (struct sockaddr_in);
+#ifdef USE_PF_UNIX
+     case AF_UNIX: return sizeof (struct sockaddr_un);
+#endif
+#ifdef USE_PF_INET6
+     case AF_INET6: return sizeof (struct sockaddr_in6);
+#endif
+     default: 
+#if 0
+      /* could be called from socket_do_accept() with empty addr */
+      msg (M_ERR, "Bad address family: %d\n", addr->sa_family);
+      ASSERT(0);
+#endif
+       return 0;
+   }
+#else /* only AF_INET */
+   return sizeof(struct sockaddr_in);
+#endif
+}
+
 static inline bool
 link_socket_actual_match (const struct link_socket_actual *a1, const struct link_socket_actual *a2)
 {
@@ -627,14 +793,18 @@ link_socket_verify_incoming_addr (struct buffer *buf,
 {
   if (buf->len > 0)
     {
-      if (from_addr->dest.sa.sin_family != AF_INET)
-       return false;
-      if (!link_socket_actual_defined (from_addr))
-       return false;
-      if (info->remote_float || !addr_defined (&info->lsa->remote))
-       return true;
-      if (addr_match_proto (&from_addr->dest, &info->lsa->remote, info->proto))
-       return true;
+      switch (from_addr->dest.addr.sa.sa_family) {
+#ifdef USE_PF_INET6
+       case AF_INET6:
+#endif
+       case AF_INET:
+         if (!link_socket_actual_defined (from_addr))
+           return false;
+         if (info->remote_float || !addr_defined (&info->lsa->remote))
+           return true;
+         if (addr_match_proto (&from_addr->dest, &info->lsa->remote, info->proto))
+           return true;
+      }
     }
   return false;
 }
@@ -740,7 +910,7 @@ link_socket_read (struct link_socket *sock,
                  int maxsize,
                  struct link_socket_actual *from)
 {
-  if (sock->info.proto == PROTO_UDPv4)
+  if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */
     {
       int res;
 
@@ -751,10 +921,10 @@ link_socket_read (struct link_socket *sock,
 #endif
       return res;
     }
-  else if (sock->info.proto == PROTO_TCPv4_SERVER || sock->info.proto == PROTO_TCPv4_CLIENT)
+  else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */
     {
       /* from address was returned by accept */
-      from->dest.sa = sock->info.lsa->actual.dest.sa;
+      addr_copy_sa(&from->dest, &sock->info.lsa->actual.dest);
       return link_socket_read_tcp (sock, buf);
     }
   else
@@ -809,13 +979,14 @@ link_socket_write_udp_posix (struct link_socket *sock,
                                           struct buffer *buf,
                                           struct link_socket_actual *to);
 
-  if (sock->sockflags & SF_USE_IP_PKTINFO)
+  if (proto_is_udp(sock->info.proto) && (sock->sockflags & SF_USE_IP_PKTINFO)
+         && addr_defined_ipi(to))
     return link_socket_write_udp_posix_sendmsg (sock, buf, to);
   else
 #endif
     return sendto (sock->sd, BPTR (buf), BLEN (buf), 0,
-                  (struct sockaddr *) &to->dest.sa,
-                  (socklen_t) sizeof (to->dest.sa));
+                  (struct sockaddr *) &to->dest.addr.sa,
+                  (socklen_t) af_addr_size(to->dest.addr.sa.sa_family));
 }
 
 static inline int
@@ -846,11 +1017,11 @@ link_socket_write (struct link_socket *sock,
                   struct buffer *buf,
                   struct link_socket_actual *to)
 {
-  if (sock->info.proto == PROTO_UDPv4)
+  if (proto_is_udp(sock->info.proto)) /* unified UDPv4 and UDPv6 */
     {
       return link_socket_write_udp (sock, buf, to);
     }
-  else if (sock->info.proto == PROTO_TCPv4_SERVER || sock->info.proto == PROTO_TCPv4_CLIENT)
+  else if (proto_is_tcp(sock->info.proto)) /* unified TCPv4 and TCPv6 */
     {
       return link_socket_write_tcp (sock, buf, to);
     }
diff --git a/socks.c b/socks.c
index 82872743221c9d44a7be562cdf4d80cb1245ffca..949d25600cc78d6ee9307f49e188c2a879cad027 100644 (file)
--- a/socks.c
+++ b/socks.c
@@ -299,9 +299,9 @@ recv_socks_reply (socket_descriptor_t sd,
 
   if (addr != NULL)
     {
-      addr->sa.sin_family = AF_INET;
-      addr->sa.sin_addr.s_addr = htonl (INADDR_ANY);
-      addr->sa.sin_port = htons (0);
+      addr->addr.in4.sin_family = AF_INET;
+      addr->addr.in4.sin_addr.s_addr = htonl (INADDR_ANY);
+      addr->addr.in4.sin_port = htons (0);
     }
 
   while (len < 4 + alen + 2)
@@ -388,8 +388,8 @@ recv_socks_reply (socket_descriptor_t sd,
   /* ATYP == 1 (IP V4 address) */
   if (atyp == '\x01' && addr != NULL)
     {
-      memcpy (&addr->sa.sin_addr, buf + 4, sizeof (addr->sa.sin_addr));
-      memcpy (&addr->sa.sin_port, buf + 8, sizeof (addr->sa.sin_port));
+      memcpy (&addr->addr.in4.sin_addr, buf + 4, sizeof (addr->addr.in4.sin_addr));
+      memcpy (&addr->addr.in4.sin_port, buf + 8, sizeof (addr->addr.in4.sin_port));
     }
 
 
@@ -507,8 +507,8 @@ socks_process_incoming_udp (struct buffer *buf,
   if (atyp != 1)               /* ATYP == 1 (IP V4) */
     goto error;
 
-  buf_read (buf, &from->dest.sa.sin_addr, sizeof (from->dest.sa.sin_addr));
-  buf_read (buf, &from->dest.sa.sin_port, sizeof (from->dest.sa.sin_port));
+  buf_read (buf, &from->dest.addr.in4.sin_addr, sizeof (from->dest.addr.in4.sin_addr));
+  buf_read (buf, &from->dest.addr.in4.sin_port, sizeof (from->dest.addr.in4.sin_port));
 
   return;
 
@@ -540,8 +540,8 @@ socks_process_outgoing_udp (struct buffer *buf,
   buf_write_u16 (&head, 0);    /* RSV = 0 */
   buf_write_u8 (&head, 0);     /* FRAG = 0 */
   buf_write_u8 (&head, '\x01'); /* ATYP = 1 (IP V4) */
-  buf_write (&head, &to->dest.sa.sin_addr, sizeof (to->dest.sa.sin_addr));
-  buf_write (&head, &to->dest.sa.sin_port, sizeof (to->dest.sa.sin_port));
+  buf_write (&head, &to->dest.addr.in4.sin_addr, sizeof (to->dest.addr.in4.sin_addr));
+  buf_write (&head, &to->dest.addr.in4.sin_port, sizeof (to->dest.addr.in4.sin_port));
 
   return 10;
 }