]> git.pld-linux.org Git - packages/openvpn.git/commitdiff
- http://openvpn.net/patch/openvpn-2.0_rc16MH.patch
authorareq <areq@pld-linux.org>
Mon, 29 Aug 2005 20:48:16 +0000 (20:48 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
- Enable multi-homed UDP server support

Changed files:
    openvpn-2.0_rc16MH.patch -> 1.1

openvpn-2.0_rc16MH.patch [new file with mode: 0644]

diff --git a/openvpn-2.0_rc16MH.patch b/openvpn-2.0_rc16MH.patch
new file mode 100644 (file)
index 0000000..212011b
--- /dev/null
@@ -0,0 +1,2139 @@
+diff -ur openvpn-2.0_rc16/configure.ac openvpn-2.0_rc16MH/configure.ac
+--- openvpn-2.0_rc16/configure.ac      2005-02-20 11:46:15.000000000 -0700
++++ openvpn-2.0_rc16MH/configure.ac    2005-02-26 00:21:45.000000000 -0700
+@@ -89,6 +89,12 @@
+    [FRAGMENT="yes"]
+ )
++AC_ARG_ENABLE(multihome,
++   [  --disable-multihome     Disable multi-homed UDP server support (--multihome)],
++   [MULTIHOME="$enableval"],
++   [MULTIHOME="yes"]
++)
++
+ AC_ARG_ENABLE(debug,
+    [  --disable-debug         Disable debugging support (disable gremlin and verb 7+ messages)],
+    [DEBUG="$enableval"],
+@@ -326,6 +332,11 @@
+       [AC_DEFINE(HAVE_CMSGHDR, 1, [struct cmsghdr needed for extended socket error support])],
+       [],
+       [#include "syshead.h"])
++AC_CHECK_TYPE(
++      [struct in_pktinfo],
++      [AC_DEFINE(HAVE_IN_PKTINFO, 1, [struct in_pktinfo needed for IP_PKTINFO support])],
++      [],
++      [#include "syshead.h"])
+ AC_CHECK_SIZEOF(unsigned int)
+ AC_CHECK_SIZEOF(unsigned long)
+@@ -351,7 +362,7 @@
+              getpass strerror syslog openlog mlockall getgrnam setgid dnl
+              setgroups stat flock readv writev setsockopt getsockopt dnl
+              setsid chdir gettimeofday putenv getpeername unlink dnl
+-               poll chsize ftruncate)
++               poll chsize ftruncate sendmsg recvmsg)
+ AC_CACHE_SAVE
+ dnl Required library functions
+@@ -568,6 +579,11 @@
+    AC_DEFINE(ENABLE_HTTP_PROXY, 1, [Enable HTTP proxy support])
+ fi
++dnl compile --multihome option
++if test "$MULTIHOME" = "yes"; then
++   AC_DEFINE(ENABLE_MULTIHOME, 1, [Enable multi-homed UDP server capability])
++fi
++
+ dnl enable debugging
+ if test "$DEBUG" = "yes"; then
+    AC_DEFINE(ENABLE_DEBUG, 1, [Enable debugging support])
+diff -ur openvpn-2.0_rc16/forward.c openvpn-2.0_rc16MH/forward.c
+--- openvpn-2.0_rc16/forward.c 2005-02-05 01:55:10.000000000 -0700
++++ openvpn-2.0_rc16MH/forward.c       2005-02-25 20:52:18.000000000 -0700
+@@ -563,12 +563,12 @@
+ static inline void
+ socks_preprocess_outgoing_link (struct context *c,
+-                              struct sockaddr_in **to_addr,
++                              struct link_socket_actual **to_addr,
+                               int *size_delta)
+ {
+   if (c->c2.link_socket->socks_proxy && c->c2.link_socket->info.proto == PROTO_UDPv4)
+     {
+-      *size_delta += socks_process_outgoing_udp (&c->c2.to_link, &c->c2.to_link_addr);
++      *size_delta += socks_process_outgoing_udp (&c->c2.to_link, c->c2.to_link_addr);
+       *to_addr = &c->c2.link_socket->socks_relay;
+     }
+ }
+@@ -607,7 +607,11 @@
+   c->c2.buf = c->c2.buffers->read_link_buf;
+   ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM_ADJ (&c->c2.frame, FRAME_HEADROOM_MARKER_READ_LINK)));
+-  status = link_socket_read (c->c2.link_socket, &c->c2.buf, MAX_RW_SIZE_LINK (&c->c2.frame), &c->c2.from);
++
++  status = link_socket_read (c->c2.link_socket,
++                           &c->c2.buf,
++                           MAX_RW_SIZE_LINK (&c->c2.frame),
++                           &c->c2.from);
+   if (socket_connection_reset (c->c2.link_socket, status))
+     {
+@@ -677,7 +681,7 @@
+   msg (D_LINK_RW, "%s READ [%d] from %s: %s",
+        proto2ascii (lsi->proto, true),
+        BLEN (&c->c2.buf),
+-       print_sockaddr (&c->c2.from, &gc),
++       print_link_socket_actual (&c->c2.from, &gc),
+        PROTO_DUMP (&c->c2.buf, &gc));
+   /*
+@@ -947,7 +951,7 @@
+        * packet to remote over the TCP/UDP port.
+        */
+       int size = 0;
+-      ASSERT (addr_defined (&c->c2.to_link_addr));
++      ASSERT (link_socket_actual_defined (c->c2.to_link_addr));
+ #ifdef ENABLE_DEBUG
+       /* In gremlin-test mode, we may choose to drop this packet */
+@@ -982,12 +986,12 @@
+         msg (D_LINK_RW, "%s WRITE [%d] to %s: %s",
+              proto2ascii (c->c2.link_socket->info.proto, true),
+              BLEN (&c->c2.to_link),
+-             print_sockaddr (&c->c2.to_link_addr, &gc),
++             print_link_socket_actual (c->c2.to_link_addr, &gc),
+              PROTO_DUMP (&c->c2.to_link, &gc));
+         /* Packet send complexified by possible Socks5 usage */
+         {
+-          struct sockaddr_in *to_addr = &c->c2.to_link_addr;
++          struct link_socket_actual *to_addr = c->c2.to_link_addr;
+ #ifdef ENABLE_SOCKS
+           int size_delta = 0;
+ #endif
+@@ -997,7 +1001,9 @@
+           socks_preprocess_outgoing_link (c, &to_addr, &size_delta);
+ #endif
+           /* Send packet */
+-          size = link_socket_write (c->c2.link_socket, &c->c2.to_link, to_addr);
++          size = link_socket_write (c->c2.link_socket,
++                                    &c->c2.to_link,
++                                    to_addr);
+ #ifdef ENABLE_SOCKS
+           /* Undo effect of prepend */
+@@ -1021,7 +1027,7 @@
+         if (size != BLEN (&c->c2.to_link))
+           msg (D_LINK_ERRORS,
+                "TCP/UDP packet was truncated/expanded on write to %s (tried=%d,actual=%d)",
+-               print_sockaddr (&c->c2.to_link_addr, &gc),
++               print_link_socket_actual (c->c2.to_link_addr, &gc),
+                BLEN (&c->c2.to_link),
+                size);
+       }
+@@ -1030,7 +1036,7 @@
+     {
+       if (c->c2.to_link.len > 0)
+       msg (D_LINK_ERRORS, "TCP/UDP packet too large on write to %s (tried=%d,max=%d)",
+-           print_sockaddr (&c->c2.to_link_addr, &gc),
++           print_link_socket_actual (c->c2.to_link_addr, &gc),
+            c->c2.to_link.len,
+            EXPANDED_SIZE (&c->c2.frame));
+     }
+diff -ur openvpn-2.0_rc16/init.c openvpn-2.0_rc16MH/init.c
+--- openvpn-2.0_rc16/init.c    2005-02-17 13:36:08.000000000 -0700
++++ openvpn-2.0_rc16MH/init.c  2005-02-25 21:12:42.000000000 -0700
+@@ -1651,6 +1651,13 @@
+ static void
+ do_init_socket_1 (struct context *c, int mode)
+ {
++  unsigned int flags = 0;
++
++#if ENABLE_IP_PKTINFO
++  if (c->options.multihome)
++    flags |= SF_USE_IP_PKTINFO;
++#endif
++  
+   link_socket_init_phase1 (c->c2.link_socket,
+                          c->options.local,
+                          c->c1.remote_list,
+@@ -1677,7 +1684,8 @@
+                          c->options.connect_retry_seconds,
+                          c->options.mtu_discover_type,
+                          c->options.rcvbuf,
+-                         c->options.sndbuf);
++                         c->options.sndbuf,
++                         flags);
+ }
+ /*
+diff -ur openvpn-2.0_rc16/manage.c openvpn-2.0_rc16MH/manage.c
+--- openvpn-2.0_rc16/manage.c  2005-01-14 21:04:11.000000000 -0700
++++ openvpn-2.0_rc16MH/manage.c        2005-02-24 20:13:31.000000000 -0700
+@@ -746,13 +746,16 @@
+ man_accept (struct management *man)
+ {
+   struct gc_arena gc = gc_new ();
++  struct link_socket_actual act;
+   /*
+    * Accept the TCP client.
+    */
+-  man->connection.sd_cli = socket_do_accept (man->connection.sd_top, &man->connection.remote, false);
++  man->connection.sd_cli = socket_do_accept (man->connection.sd_top, &act, false);
+   if (socket_defined (man->connection.sd_cli))
+     {
++      man->connection.remote = act.dest;
++
+       if (socket_defined (man->connection.sd_top))
+       {
+ #ifdef WIN32
+@@ -1121,9 +1124,9 @@
+       /*
+        * Initialize socket address
+        */
+-      ms->local.sin_family = AF_INET;
+-      ms->local.sin_addr.s_addr = 0;
+-      ms->local.sin_port = htons (port);
++      ms->local.sa.sin_family = AF_INET;
++      ms->local.sa.sin_addr.s_addr = 0;
++      ms->local.sa.sin_port = htons (port);
+       /*
+        * Run management over tunnel, or
+@@ -1135,7 +1138,7 @@
+       }
+       else
+       {
+-        ms->local.sin_addr.s_addr = getaddr
++        ms->local.sa.sin_addr.s_addr = getaddr
+           (GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL, addr, 0, NULL, NULL);
+       }
+       
+@@ -1382,7 +1385,7 @@
+       && man->connection.state == MS_INITIAL)
+     {
+       /* listen on our local TUN/TAP IP address */
+-      man->settings.local.sin_addr.s_addr = htonl (tun_local_ip);
++      man->settings.local.sa.sin_addr.s_addr = htonl (tun_local_ip);
+       man_connection_init (man);
+     }
+diff -ur openvpn-2.0_rc16/manage.h openvpn-2.0_rc16MH/manage.h
+--- openvpn-2.0_rc16/manage.h  2005-01-09 17:46:29.000000000 -0700
++++ openvpn-2.0_rc16MH/manage.h        2005-02-24 20:01:50.000000000 -0700
+@@ -186,7 +186,7 @@
+ struct man_settings {
+   bool defined;
+-  struct sockaddr_in local;
++  struct openvpn_sockaddr local;
+   bool up_query_passwords;
+   bool management_over_tunnel;
+   struct user_pass up;
+@@ -213,7 +213,7 @@
+   socket_descriptor_t sd_top;
+   socket_descriptor_t sd_cli;
+-  struct sockaddr_in remote;
++  struct openvpn_sockaddr remote;
+ #ifdef WIN32
+   struct net_event_win32 ne32;
+diff -ur openvpn-2.0_rc16/mroute.c openvpn-2.0_rc16MH/mroute.c
+--- openvpn-2.0_rc16/mroute.c  2005-01-09 17:46:41.000000000 -0700
++++ openvpn-2.0_rc16MH/mroute.c        2005-02-24 20:20:57.000000000 -0700
+@@ -169,28 +169,29 @@
+ }
+ /*
+- * Translate a struct sockaddr_in (saddr)
++ * Translate a struct openvpn_sockaddr (osaddr)
+  * to a struct mroute_addr (addr).
+  */
+-bool
+-mroute_extract_sockaddr_in (struct mroute_addr *addr, const struct sockaddr_in *saddr, bool use_port)
++bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr,
++                                    const struct openvpn_sockaddr *osaddr,
++                                    bool use_port)
+ {
+-  if (saddr->sin_family == AF_INET)
++  if (osaddr->sa.sin_family == AF_INET)
+     {
+       if (use_port)
+       {
+         addr->type = MR_ADDR_IPV4 | MR_WITH_PORT;
+         addr->netbits = 0;
+         addr->len = 6;
+-        memcpy (addr->addr, &saddr->sin_addr.s_addr, 4);
+-        memcpy (addr->addr + 4, &saddr->sin_port, 2);
++        memcpy (addr->addr, &osaddr->sa.sin_addr.s_addr, 4);
++        memcpy (addr->addr + 4, &osaddr->sa.sin_port, 2);
+       }
+       else
+       {
+         addr->type = MR_ADDR_IPV4;
+         addr->netbits = 0;
+         addr->len = 4;
+-        memcpy (addr->addr, &saddr->sin_addr.s_addr, 4);
++        memcpy (addr->addr, &osaddr->sa.sin_addr.s_addr, 4);
+       }
+       return true;
+     }
+diff -ur openvpn-2.0_rc16/mroute.h openvpn-2.0_rc16MH/mroute.h
+--- openvpn-2.0_rc16/mroute.h  2005-01-09 17:46:41.000000000 -0700
++++ openvpn-2.0_rc16MH/mroute.h        2005-02-24 20:19:05.000000000 -0700
+@@ -95,9 +95,11 @@
+                                             struct buffer *buf,
+                                             int tunnel_type);
+-bool mroute_extract_sockaddr_in (struct mroute_addr *addr,
+-                               const struct sockaddr_in *saddr,
+-                               bool use_port);
++struct openvpn_sockaddr;
++
++bool mroute_extract_openvpn_sockaddr (struct mroute_addr *addr,
++                                    const struct openvpn_sockaddr *osaddr,
++                                    bool use_port);
+ bool mroute_learnable_address (const struct mroute_addr *addr);
+diff -ur openvpn-2.0_rc16/mtcp.c openvpn-2.0_rc16MH/mtcp.c
+--- openvpn-2.0_rc16/mtcp.c    2005-02-05 01:55:09.000000000 -0700
++++ openvpn-2.0_rc16MH/mtcp.c  2005-02-24 20:18:27.000000000 -0700
+@@ -160,7 +160,7 @@
+   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);
+-  if (!mroute_extract_sockaddr_in (&mi->real, &mi->context.c2.link_socket->info.lsa->actual, true))
++  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");
+       return false;
+diff -ur openvpn-2.0_rc16/mudp.c openvpn-2.0_rc16MH/mudp.c
+--- openvpn-2.0_rc16/mudp.c    2005-02-05 01:55:09.000000000 -0700
++++ openvpn-2.0_rc16MH/mudp.c  2005-02-24 20:23:14.000000000 -0700
+@@ -52,7 +52,7 @@
+   struct multi_instance *mi = NULL;
+   struct hash *hash = m->hash;
+-  if (mroute_extract_sockaddr_in (&real, &m->top.c2.from, true))
++  if (mroute_extract_openvpn_sockaddr (&real, &m->top.c2.from.dest, true))
+     {
+       struct hash_element *he;
+       const uint32_t hv = hash_value (hash, &real);
+diff -ur openvpn-2.0_rc16/multi.c openvpn-2.0_rc16MH/multi.c
+--- openvpn-2.0_rc16/multi.c   2005-01-18 22:23:17.000000000 -0700
++++ openvpn-2.0_rc16MH/multi.c 2005-02-24 20:27:42.000000000 -0700
+@@ -939,13 +939,13 @@
+                      in_addr_t a,
+                      int netbits) /* -1 if host route, otherwise # of network bits in address */
+ {
+-  struct sockaddr_in remote_si;
++  struct openvpn_sockaddr remote_si;
+   struct mroute_addr addr;
+   CLEAR (remote_si);
+-  remote_si.sin_family = AF_INET;
+-  remote_si.sin_addr.s_addr = htonl (a);
+-  ASSERT (mroute_extract_sockaddr_in (&addr, &remote_si, false));
++  remote_si.sa.sin_family = AF_INET;
++  remote_si.sa.sin_addr.s_addr = htonl (a);
++  ASSERT (mroute_extract_openvpn_sockaddr (&addr, &remote_si, false));
+   if (netbits >= 0)
+     {
+@@ -2009,15 +2009,15 @@
+   struct multi_context *m = (struct multi_context *) arg;
+   struct hash_iterator hi;
+   struct hash_element *he;
+-  struct sockaddr_in saddr;
++  struct openvpn_sockaddr saddr;
+   struct mroute_addr maddr;
+   int count = 0;
+   CLEAR (saddr);
+-  saddr.sin_family = AF_INET;
+-  saddr.sin_addr.s_addr = htonl (addr);
+-  saddr.sin_port = htons (port);
+-  if (mroute_extract_sockaddr_in (&maddr, &saddr, true))
++  saddr.sa.sin_family = AF_INET;
++  saddr.sa.sin_addr.s_addr = htonl (addr);
++  saddr.sa.sin_port = htons (port);
++  if (mroute_extract_openvpn_sockaddr (&maddr, &saddr, true))
+     {
+       hash_iterator_init (m->iter, &hi, true);
+       while ((he = hash_iterator_next (&hi)))
+diff -ur openvpn-2.0_rc16/openvpn.h openvpn-2.0_rc16MH/openvpn.h
+--- openvpn-2.0_rc16/openvpn.h 2005-01-09 17:46:29.000000000 -0700
++++ openvpn-2.0_rc16MH/openvpn.h       2005-02-24 18:53:27.000000000 -0700
+@@ -210,8 +210,8 @@
+   struct link_socket_info *link_socket_info;
+   const struct link_socket *accept_from; /* possibly do accept() on a parent link_socket */
+-  struct sockaddr_in to_link_addr;     /* IP address of remote */
+-  struct sockaddr_in from;               /* address of incoming datagram */
++  struct link_socket_actual *to_link_addr;    /* IP address of remote */
++  struct link_socket_actual from;               /* address of incoming datagram */
+   /* MTU frame parameters */
+   struct frame frame;
+diff -ur openvpn-2.0_rc16/options.c openvpn-2.0_rc16MH/options.c
+--- openvpn-2.0_rc16/options.c 2005-02-10 19:18:08.000000000 -0700
++++ openvpn-2.0_rc16MH/options.c       2005-02-25 21:11:12.000000000 -0700
+@@ -172,6 +172,9 @@
+   "--ping-timer-rem: Run the --ping-exit/--ping-restart timer only if we have a\n"
+   "                  remote address.\n"
+   "--ping n        : Ping remote once every n seconds over TCP/UDP port.\n"
++#if ENABLE_IP_PKTINFO
++  "--multihome     : Configure a multi-homed UDP server.\n"
++#endif
+   "--fast-io       : (experimental) Optimize TUN/TAP/UDP writes.\n"
+ #ifdef ENABLE_OCC
+   "--explicit-exit-notify n : (experimental) on exit, send exit signal to remote.\n"
+@@ -1034,6 +1037,10 @@
+   SHOW_INT (rcvbuf);
+   SHOW_INT (sndbuf);
++#if ENABLE_IP_PKTINFO
++  SHOW_BOOL (multihome);
++#endif
++
+ #ifdef ENABLE_HTTP_PROXY
+   if (o->http_proxy_options)
+     show_http_proxy_options (o->http_proxy_options);
+@@ -2997,6 +3004,13 @@
+       VERIFY_PERMISSION (OPT_P_GENERAL);
+       options->mlock = true;
+     }
++#if ENABLE_IP_PKTINFO
++  else if (streq (p[0], "multihome"))
++    {
++      VERIFY_PERMISSION (OPT_P_GENERAL);
++      options->multihome = true;
++    }
++#endif
+   else if (streq (p[0], "verb") && p[1])
+     {
+       ++i;
+diff -ur openvpn-2.0_rc16/options.h openvpn-2.0_rc16MH/options.h
+--- openvpn-2.0_rc16/options.h 2005-02-10 16:37:25.000000000 -0700
++++ openvpn-2.0_rc16MH/options.h       2005-02-25 21:11:13.000000000 -0700
+@@ -223,6 +223,10 @@
+   /* optimize TUN/TAP/UDP writes */
+   bool fast_io;
++#if ENABLE_IP_PKTINFO
++  bool multihome;
++#endif
++
+ #ifdef USE_LZO
+   bool comp_lzo;
+   bool comp_lzo_adaptive;
+diff -ur openvpn-2.0_rc16/ping-inline.h openvpn-2.0_rc16MH/ping-inline.h
+--- openvpn-2.0_rc16/ping-inline.h     2005-01-09 17:46:41.000000000 -0700
++++ openvpn-2.0_rc16MH/ping-inline.h   2005-02-24 19:56:53.000000000 -0700
+@@ -38,7 +38,7 @@
+       && event_timeout_trigger (&c->c2.ping_rec_interval,
+                               &c->c2.timeval,
+                               (!c->options.ping_timer_remote
+-                               || addr_defined (&c->c1.link_socket_addr.actual))
++                               || link_socket_actual_defined (&c->c1.link_socket_addr.actual))
+                               ? ETT_DEFAULT : 15))
+     check_ping_restart_dowork (c);
+ }
+Only in openvpn-2.0_rc16MH/plugin: common
+diff -ur openvpn-2.0_rc16/socket.c openvpn-2.0_rc16MH/socket.c
+--- openvpn-2.0_rc16/socket.c  2005-02-05 01:42:13.000000000 -0700
++++ openvpn-2.0_rc16MH/socket.c        2005-02-25 21:41:34.000000000 -0700
+@@ -237,7 +237,7 @@
+ static void
+ update_remote (const char* host,
+-             struct sockaddr_in *addr,
++             struct openvpn_sockaddr *addr,
+              bool *changed)
+ {
+   if (host && addr)
+@@ -248,9 +248,9 @@
+                                         1,
+                                         NULL,
+                                         NULL);
+-      if (new_addr && addr->sin_addr.s_addr != new_addr)
++      if (new_addr && addr->sa.sin_addr.s_addr != new_addr)
+       {
+-        addr->sin_addr.s_addr = new_addr;
++        addr->sa.sin_addr.s_addr = new_addr;
+         *changed = true;
+       }
+     }
+@@ -440,12 +440,19 @@
+ }
+ static socket_descriptor_t
+-create_socket_udp (void)
++create_socket_udp (const unsigned int flags)
+ {
+   socket_descriptor_t sd;
+   if ((sd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+     msg (M_SOCKERR, "UDP: Cannot create UDP socket");
++#if ENABLE_IP_PKTINFO
++  else if (flags & SF_USE_IP_PKTINFO)
++    {
++      int pad = 1;
++      setsockopt (sd, SOL_IP, IP_PKTINFO, (void*)&pad, sizeof(pad));
++    }
++#endif
+   return sd;
+ }
+@@ -455,7 +462,7 @@
+   /* create socket */
+   if (sock->info.proto == PROTO_UDPv4)
+     {
+-      sock->sd = create_socket_udp ();
++      sock->sd = create_socket_udp (sock->socket_flags);
+ #ifdef ENABLE_SOCKS
+       if (sock->socks_proxy)
+@@ -479,7 +486,7 @@
+ static void
+ socket_do_listen (socket_descriptor_t sd,
+-                const struct sockaddr_in *local,
++                const struct openvpn_sockaddr *local,
+                 bool do_listen,
+                 bool do_set_nonblock)
+ {
+@@ -501,16 +508,18 @@
+ socket_descriptor_t
+ socket_do_accept (socket_descriptor_t sd,
+-                struct sockaddr_in *remote,
++                struct link_socket_actual *act,
+                 const bool nowait)
+ {
+-  socklen_t remote_len = sizeof (*remote);
++  socklen_t remote_len = sizeof (act->dest.sa);
+   socket_descriptor_t new_sd = SOCKET_UNDEFINED;
++  CLEAR (*act);
++
+ #ifdef HAVE_GETPEERNAME
+   if (nowait)
+     {
+-      new_sd = getpeername (sd, (struct sockaddr *) remote, &remote_len);
++      new_sd = getpeername (sd, (struct sockaddr *) &act->dest.sa, &remote_len);
+       if (!socket_defined (new_sd))
+       msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: getpeername() failed");
+@@ -523,14 +532,14 @@
+ #endif
+   else
+     {
+-      new_sd = accept (sd, (struct sockaddr *) remote, &remote_len);
++      new_sd = accept (sd, (struct sockaddr *) &act->dest.sa, &remote_len);
+     }
+   if (!socket_defined (new_sd))
+     {
+       msg (D_LINK_ERRORS | M_ERRNO_SOCK, "TCP: accept(%d) failed", sd);
+     }
+-  else if (remote_len != sizeof (*remote))
++  else if (remote_len != sizeof (act->dest.sa))
+     {
+       msg (D_LINK_ERRORS, "TCP: Received strange incoming connection with unknown address length=%d", remote_len);
+       openvpn_close_socket (new_sd);
+@@ -540,28 +549,30 @@
+ }
+ static void
+-tcp_connection_established (const struct sockaddr_in *remote)
++tcp_connection_established (const struct link_socket_actual *act)
+ {
+   struct gc_arena gc = gc_new ();
+   msg (M_INFO, "TCP connection established with %s", 
+-       print_sockaddr (remote, &gc));
++       print_link_socket_actual (act, &gc));
+   gc_free (&gc);
+ }
+ static int
+ socket_listen_accept (socket_descriptor_t sd,
+-                    struct sockaddr_in *remote,
++                    struct link_socket_actual *act,
+                     const char *remote_dynamic,
+                     bool *remote_changed,
+-                    const struct sockaddr_in *local,
++                    const struct openvpn_sockaddr *local,
+                     bool do_listen,
+                     bool nowait,
+                     volatile int *signal_received)
+ {
+   struct gc_arena gc = gc_new ();
+-  struct sockaddr_in remote_verify = *remote;
++  //struct openvpn_sockaddr *remote = &act->dest;
++  struct openvpn_sockaddr remote_verify = act->dest;
+   int new_sd = SOCKET_UNDEFINED;
++  CLEAR (*act);
+   socket_do_listen (sd, local, do_listen, true);
+   while (true)
+@@ -590,17 +601,17 @@
+       if (status <= 0)
+       continue;
+-      new_sd = socket_do_accept (sd, remote, nowait);
++      new_sd = socket_do_accept (sd, act, nowait);
+       if (socket_defined (new_sd))
+       {
+         update_remote (remote_dynamic, &remote_verify, remote_changed);
+         if (addr_defined (&remote_verify)
+-            && !addr_match (&remote_verify, remote))
++            && !addr_match (&remote_verify, &act->dest))
+           {
+             msg (M_WARN,
+                  "TCP NOTE: Rejected connection attempt from %s due to --remote setting",
+-                 print_sockaddr (remote, &gc));
++                 print_link_socket_actual (act, &gc));
+             if (openvpn_close_socket (new_sd))
+               msg (M_SOCKERR, "TCP: close socket failed (new_sd)");
+           }
+@@ -613,7 +624,7 @@
+   if (!nowait && openvpn_close_socket (sd))
+     msg (M_SOCKERR, "TCP: close socket failed (sd)");
+-  tcp_connection_established (remote);
++  tcp_connection_established (act);
+   gc_free (&gc);
+   return new_sd;
+@@ -621,7 +632,7 @@
+ static void
+ socket_connect (socket_descriptor_t *sd,
+-              struct sockaddr_in *remote,
++              struct openvpn_sockaddr *remote,
+               struct remote_list *remote_list,
+               const char *remote_dynamic,
+               bool *remote_changed,
+@@ -634,8 +645,8 @@
+        print_sockaddr (remote, &gc));
+   while (true)
+     {
+-      const int status = connect (*sd, (struct sockaddr *) remote,
+-                                sizeof (*remote));
++      const int status = connect (*sd, (struct sockaddr *) &remote->sa,
++                                sizeof (remote->sa));
+       get_signal (signal_received);
+       if (*signal_received)
+@@ -656,7 +667,7 @@
+       {
+         remote_list_next (remote_list);
+         remote_dynamic = remote_list_host (remote_list);
+-        remote->sin_port = htons (remote_list_port (remote_list));
++        remote->sa.sin_port = htons (remote_list_port (remote_list));
+         *remote_changed = true;
+       }
+@@ -716,22 +727,22 @@
+   /* resolve local address if undefined */
+   if (!addr_defined (&sock->info.lsa->local))
+     {
+-      sock->info.lsa->local.sin_family = AF_INET;
+-      sock->info.lsa->local.sin_addr.s_addr =
++      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.sin_port = htons (sock->local_port);
++      sock->info.lsa->local.sa.sin_port = htons (sock->local_port);
+     }
+   
+   /* bind to local address/port */
+   if (sock->bind_local)
+     {
+-      if (bind (sock->sd, (struct sockaddr *) &sock->info.lsa->local,
+-              sizeof (sock->info.lsa->local)))
++      if (bind (sock->sd, (struct sockaddr *) &sock->info.lsa->local.sa,
++              sizeof (sock->info.lsa->local.sa)))
+       {
+         const int errnum = openvpn_errno_socket ();
+         msg (M_FATAL, "TCP/UDP: Socket bind failed on local address %s: %s",
+@@ -755,8 +766,8 @@
+       /* resolve remote address if undefined */
+       if (!addr_defined (&sock->info.lsa->remote))
+       {
+-        sock->info.lsa->remote.sin_family = AF_INET;
+-        sock->info.lsa->remote.sin_addr.s_addr = 0;
++        sock->info.lsa->remote.sa.sin_family = AF_INET;
++        sock->info.lsa->remote.sa.sin_addr.s_addr = 0;
+         if (sock->remote_host)
+           {
+@@ -794,7 +805,7 @@
+                 ASSERT (0);
+               }
+-            sock->info.lsa->remote.sin_addr.s_addr = getaddr (
++            sock->info.lsa->remote.sa.sin_addr.s_addr = getaddr (
+                   flags,
+                   sock->remote_host,
+                   retry,
+@@ -821,19 +832,22 @@
+               }
+           }
+-        sock->info.lsa->remote.sin_port = htons (sock->remote_port);
++        sock->info.lsa->remote.sa.sin_port = htons (sock->remote_port);
+       }
+   
+       /* should we re-use previous active remote address? */
+-      if (addr_defined (&sock->info.lsa->actual))
++      if (link_socket_actual_defined (&sock->info.lsa->actual))
+       {
+         msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
+-             print_sockaddr (&sock->info.lsa->actual, &gc));
++             print_link_socket_actual (&sock->info.lsa->actual, &gc));
+         if (remote_dynamic)
+           *remote_dynamic = NULL;
+       }
+       else
+-      sock->info.lsa->actual = sock->info.lsa->remote;
++      {
++        CLEAR (sock->info.lsa->actual);
++        sock->info.lsa->actual.dest = sock->info.lsa->remote;
++      }
+       /* remember that we finished */
+       sock->did_resolve_remote = true;
+@@ -884,7 +898,8 @@
+                        int connect_retry_seconds,
+                        int mtu_discover_type,
+                        int rcvbuf,
+-                       int sndbuf)
++                       int sndbuf,
++                       const unsigned int socket_flags)
+ {
+   const char *remote_host;
+   int remote_port;
+@@ -920,6 +935,8 @@
+   sock->socket_buffer_sizes.rcvbuf = rcvbuf;
+   sock->socket_buffer_sizes.sndbuf = sndbuf;
++  sock->socket_flags = socket_flags;
++
+   sock->info.proto = proto;
+   sock->info.remote_float = remote_float;
+   sock->info.lsa = lsa;
+@@ -1097,7 +1114,7 @@
+       else if (sock->info.proto == PROTO_TCPv4_CLIENT)
+       {
+         socket_connect (&sock->sd,
+-                        &sock->info.lsa->actual,
++                        &sock->info.lsa->actual.dest,
+                         sock->remote_list,
+                         remote_dynamic,
+                         &remote_changed,
+@@ -1135,7 +1152,7 @@
+       else if (sock->info.proto == PROTO_UDPv4 && sock->socks_proxy)
+       {
+         socket_connect (&sock->ctrl_sd,
+-                        &sock->info.lsa->actual,
++                        &sock->info.lsa->actual.dest,
+                         NULL,
+                         remote_dynamic,
+                         &remote_changed,
+@@ -1147,7 +1164,8 @@
+         establish_socks_proxy_udpassoc (sock->socks_proxy,
+                                         sock->ctrl_sd,
+-                                        sock->sd, &sock->socks_relay,
++                                        sock->sd,
++                                        &sock->socks_relay.dest,
+                                         signal_received);
+         if (*signal_received)
+@@ -1156,8 +1174,9 @@
+         sock->remote_host = sock->proxy_dest_host;
+         sock->remote_port = sock->proxy_dest_port;
+         sock->did_resolve_remote = false;
+-        sock->info.lsa->actual.sin_addr.s_addr = 0;
+-        sock->info.lsa->remote.sin_addr.s_addr = 0;
++
++        sock->info.lsa->actual.dest.sa.sin_addr.s_addr = 0;
++        sock->info.lsa->remote.sa.sin_addr.s_addr = 0;
+         resolve_remote (sock, 1, NULL, signal_received);
+@@ -1172,7 +1191,7 @@
+       if (remote_changed)
+       {
+         msg (M_INFO, "TCP/UDP: Dynamic remote address changed during TCP connection establishment");
+-        sock->info.lsa->remote.sin_addr.s_addr = sock->info.lsa->actual.sin_addr.s_addr;
++        sock->info.lsa->remote.sa.sin_addr.s_addr = sock->info.lsa->actual.dest.sa.sin_addr.s_addr;
+       }
+     }
+@@ -1206,12 +1225,15 @@
+     msg (M_INFO, "%s link local%s: %s",
+        proto2ascii (sock->info.proto, true),
+        (sock->bind_local ? " (bound)" : ""),
+-       print_sockaddr_ex (&sock->info.lsa->local, sock->bind_local, ":", &gc));
++       print_sockaddr_ex (&sock->info.lsa->local, ":", sock->bind_local ? PS_SHOW_PORT : 0, &gc));
+   /* print active remote address */
+   msg (M_INFO, "%s link remote: %s",
+        proto2ascii (sock->info.proto, true),
+-       print_sockaddr_ex (&sock->info.lsa->actual, addr_defined (&sock->info.lsa->actual), ":", &gc));
++       print_link_socket_actual_ex (&sock->info.lsa->actual,
++                                  ":",
++                                  PS_SHOW_PORT_IF_DEFINED,
++                                  &gc));
+  done:
+   gc_free (&gc);
+@@ -1276,19 +1298,19 @@
+ void
+ setenv_trusted (struct env_set *es, const struct link_socket_info *info)
+ {
+-  setenv_sockaddr (es, "trusted", &info->lsa->actual, SA_IP_PORT);
++  setenv_link_socket_actual (es, "trusted", &info->lsa->actual, SA_IP_PORT);
+ }
+ void
+ link_socket_connection_initiated (const struct buffer *buf,
+                                 struct link_socket_info *info,
+-                                const struct sockaddr_in *addr,
++                                const struct link_socket_actual *act,
+                                 const char *common_name,
+                                 struct env_set *es)
+ {
+   struct gc_arena gc = gc_new ();
+   
+-  info->lsa->actual = *addr; /* Note: skip this line for --force-dest */
++  info->lsa->actual = *act; /* Note: skip this line for --force-dest */
+   setenv_trusted (es, info);
+   info->connection_established = true;
+@@ -1297,7 +1319,7 @@
+     struct buffer out = alloc_buf_gc (256, &gc);
+     if (common_name)
+       buf_printf (&out, "[%s] ", common_name);
+-    buf_printf (&out, "Peer Connection Initiated with %s", print_sockaddr (&info->lsa->actual, &gc));
++    buf_printf (&out, "Peer Connection Initiated with %s", print_link_socket_actual (&info->lsa->actual, &gc));
+     msg (M_INFO, "%s", BSTR (&out));
+   }
+@@ -1307,7 +1329,7 @@
+   /* Process --ipchange plugin */
+   if (plugin_defined (info->plugins, OPENVPN_PLUGIN_IPCHANGE))
+     {
+-      const char *addr_ascii = print_sockaddr_ex (&info->lsa->actual, true, " ", &gc);
++      const char *addr_ascii = print_sockaddr_ex (&info->lsa->actual.dest, " ", PS_SHOW_PORT, &gc);
+       if (plugin_call (info->plugins, OPENVPN_PLUGIN_IPCHANGE, addr_ascii, es))
+       msg (M_WARN, "WARNING: ipchange plugin call failed");
+     }
+@@ -1319,7 +1341,7 @@
+       setenv_str (es, "script_type", "ipchange");
+       buf_printf (&out, "%s %s",
+                 info->ipchange_command,
+-                print_sockaddr_ex (&info->lsa->actual, true, " ", &gc));
++                print_sockaddr_ex (&info->lsa->actual.dest, " ", PS_SHOW_PORT, &gc));
+       system_check (BSTR (&out), es, S_SCRIPT, "ip-change command failed");
+     }
+@@ -1329,14 +1351,14 @@
+ void
+ link_socket_bad_incoming_addr (struct buffer *buf,
+                              const struct link_socket_info *info,
+-                             const struct sockaddr_in *from_addr)
++                             const struct link_socket_actual *from_addr)
+ {
+   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_sockaddr (from_addr, &gc),
+-       (int)from_addr->sin_family,
++       print_link_socket_actual (from_addr, &gc),
++       (int)from_addr->dest.sa.sin_family,
+        print_sockaddr (&info->lsa->remote, &gc));
+   buf->len = 0;
+@@ -1354,10 +1376,10 @@
+ {
+   const struct link_socket_addr *lsa = info->lsa;
+-  if (addr_defined (&lsa->actual))
+-    return ntohl (lsa->actual.sin_addr.s_addr);
++  if (link_socket_actual_defined (&lsa->actual))
++    return ntohl (lsa->actual.dest.sa.sin_addr.s_addr);
+   else if (addr_defined (&lsa->remote))
+-    return ntohl (lsa->remote.sin_addr.s_addr);
++    return ntohl (lsa->remote.sa.sin_addr.s_addr);
+   else
+     return 0;
+ }
+@@ -1550,29 +1572,69 @@
+  */
+ const char *
+-print_sockaddr (const struct sockaddr_in *addr, struct gc_arena *gc)
++print_sockaddr (const struct openvpn_sockaddr *addr, struct gc_arena *gc)
+ {
+-  return print_sockaddr_ex(addr, true, ":", gc);
++  return print_sockaddr_ex (addr, ":", PS_SHOW_PORT, gc);
+ }
+ const char *
+-print_sockaddr_ex (const struct sockaddr_in *addr, bool do_port, const char* separator, struct gc_arena *gc)
++print_sockaddr_ex (const struct openvpn_sockaddr *addr,
++                 const char* separator,
++                 const unsigned int flags,
++                 struct gc_arena *gc)
+ {
+-  struct buffer out = alloc_buf_gc (64, gc);
+-  const int port = ntohs (addr->sin_port);
++  if (addr)
++    {
++      struct buffer out = alloc_buf_gc (64, gc);
++      const int port = ntohs (addr->sa.sin_port);
+-  mutex_lock_static (L_INET_NTOA);
+-  buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sin_addr) : "[undef]"));
+-  mutex_unlock_static (L_INET_NTOA);
++      mutex_lock_static (L_INET_NTOA);
++      buf_printf (&out, "%s", (addr_defined (addr) ? inet_ntoa (addr->sa.sin_addr) : "[undef]"));
++      mutex_unlock_static (L_INET_NTOA);
+-  if (do_port && port)
+-    {
+-      if (separator)
+-      buf_printf (&out, "%s", separator);
++      if (((flags & PS_SHOW_PORT) || (addr_defined (addr) && (flags & PS_SHOW_PORT_IF_DEFINED)))
++        && port)
++      {
++        if (separator)
++          buf_printf (&out, "%s", separator);
+-      buf_printf (&out, "%d", port);
++        buf_printf (&out, "%d", port);
++      }
++      return BSTR (&out);
+     }
+-  return BSTR (&out);
++  else
++    return "[NULL]";
++}
++
++const char *
++print_link_socket_actual (const struct link_socket_actual *act, struct gc_arena *gc)
++{
++  return print_link_socket_actual_ex (act, ":", PS_SHOW_PORT|PS_SHOW_PKTINFO, gc);
++}
++
++const char *
++print_link_socket_actual_ex (const struct link_socket_actual *act,
++                           const char *separator,
++                           const unsigned int flags,
++                           struct gc_arena *gc)
++{
++  if (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)
++      {
++        struct openvpn_sockaddr sa;
++        CLEAR (sa);
++        sa.sa.sin_addr = act->pi.ipi_spec_dst;
++        buf_printf (&out, " (via %s)", print_sockaddr_ex (&sa, separator, 0, gc));
++      }
++#endif
++      return BSTR (&out);
++    }
++  else
++    return "[NULL]";
+ }
+ /*
+@@ -1599,7 +1661,7 @@
+ /* set environmental variables for ip/port in *addr */
+ void
+-setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct sockaddr_in *addr, const bool flags)
++setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct openvpn_sockaddr *addr, const bool flags)
+ {
+   char name_buf[256];
+@@ -1609,13 +1671,13 @@
+     openvpn_snprintf (name_buf, sizeof (name_buf), "%s", name_prefix);
+   mutex_lock_static (L_INET_NTOA);
+-  setenv_str (es, name_buf, inet_ntoa (addr->sin_addr));
++  setenv_str (es, name_buf, inet_ntoa (addr->sa.sin_addr));
+   mutex_unlock_static (L_INET_NTOA);
+-  if ((flags & SA_IP_PORT) && addr->sin_port)
++  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->sin_port));
++      setenv_int (es, name_buf, ntohs (addr->sa.sin_port));
+     }
+ }
+@@ -1624,13 +1686,22 @@
+ {
+   if (addr || !(flags & SA_SET_IF_NONZERO))
+     {
+-      struct sockaddr_in si;
++      struct openvpn_sockaddr si;
+       CLEAR (si);
+-      si.sin_addr.s_addr = htonl (addr);
++      si.sa.sin_addr.s_addr = htonl (addr);
+       setenv_sockaddr (es, name_prefix, &si, flags);
+     }
+ }
++void
++setenv_link_socket_actual (struct env_set *es,
++                         const char *name_prefix,
++                         const struct link_socket_actual *act,
++                         const bool flags)
++{
++  setenv_sockaddr (es, name_prefix, &act->dest, flags);
++}
++
+ /*
+  * Convert protocol names between index and ascii form.
+  */
+@@ -1760,19 +1831,72 @@
+ #ifndef WIN32
++#if ENABLE_IP_PKTINFO
++
++struct openvpn_pktinfo
++{
++  struct cmsghdr cmsghdr;
++  struct in_pktinfo in_pktinfo;
++};
++
++static socklen_t
++link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
++                                  struct buffer *buf,
++                                  int maxsize,
++                                  struct link_socket_actual *from)
++{
++  struct iovec iov;
++  struct openvpn_pktinfo opi;
++  struct msghdr mesg;
++  socklen_t fromlen = sizeof (from->dest.sa);
++
++  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_namelen = fromlen;
++  mesg.msg_control = &opi;
++  mesg.msg_controllen = sizeof (opi);
++  buf->len = recvmsg (sock->sd, &mesg, 0);
++  if (buf->len >= 0)
++    {
++      struct cmsghdr *cmsg;
++      fromlen = mesg.msg_namelen;
++      cmsg = CMSG_FIRSTHDR (&mesg);
++      if (cmsg != NULL
++        && CMSG_NXTHDR (&mesg, cmsg) == NULL
++        && cmsg->cmsg_level == SOL_IP 
++        && cmsg->cmsg_type == IP_PKTINFO
++        && 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;
++      }
++    }
++  return fromlen;
++}
++#endif
++
+ int
+ link_socket_read_udp_posix (struct link_socket *sock,
+                           struct buffer *buf,
+                           int maxsize,
+-                          struct sockaddr_in *from)
++                          struct link_socket_actual *from)
+ {
+-  socklen_t fromlen = sizeof (*from);
+-  CLEAR (*from);
++  socklen_t fromlen = sizeof (from->dest.sa);
++  from->dest.sa.sin_addr.s_addr = 0;
+   ASSERT (buf_safe (buf, maxsize));
+-  buf->len = recvfrom (sock->sd, BPTR (buf), maxsize, 0,
+-                     (struct sockaddr *) from, &fromlen);
+-  if (fromlen != sizeof (*from))
+-    bad_address_length (fromlen, sizeof (*from));
++#if ENABLE_IP_PKTINFO
++  if (sock->socket_flags & 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));
+   return buf->len;
+ }
+@@ -1785,7 +1909,7 @@
+ int
+ link_socket_write_tcp (struct link_socket *sock,
+                      struct buffer *buf,
+-                     struct sockaddr_in *to)
++                     struct link_socket_actual *to)
+ {
+   packet_size_type len = BLEN (buf);
+   dmsg (D_STREAM_DEBUG, "STREAM: WRITE %d offset=%d", (int)len, buf->offset);
+@@ -1799,6 +1923,41 @@
+ #endif
+ }
++#if ENABLE_IP_PKTINFO
++
++int
++link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
++                                   struct buffer *buf,
++                                   struct link_socket_actual *to)
++{
++  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;
++  return sendmsg (sock->sd, &mesg, 0);
++}
++
++#endif
++
+ /*
+  * Win32 overlapped socket I/O functions.
+  */
+@@ -1913,7 +2072,7 @@
+ }
+ int
+-socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct sockaddr_in *to)
++socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct link_socket_actual *to)
+ {
+   if (sock->writes.iostate == IOSTATE_INITIAL)
+     {
+@@ -1937,7 +2096,7 @@
+       {
+         /* set destination address for UDP writes */
+         sock->writes.addr_defined = true;
+-        sock->writes.addr = *to;
++        sock->writes.addr = to->dest.sa;
+         sock->writes.addrlen = sizeof (sock->writes.addr);
+         status = WSASendTo(
+@@ -2013,11 +2172,10 @@
+ }
+ int
+-socket_finalize (
+-               SOCKET s,
++socket_finalize (SOCKET s,
+                struct overlapped_io *io,
+                struct buffer *buf,
+-               struct sockaddr_in *from)
++               struct link_socket_actual *from)
+ {
+   int ret = -1;
+   BOOL status;
+@@ -2094,10 +2252,10 @@
+       {
+         if (io->addrlen != sizeof (io->addr))
+           bad_address_length (io->addrlen, sizeof (io->addr));
+-        *from = io->addr;
++        from->dest.sa = io->addr;
+       }
+       else
+-      CLEAR (*from);
++      CLEAR (from->dest.sa);
+     }
+   
+   if (buf)
+diff -ur openvpn-2.0_rc16/socket.h openvpn-2.0_rc16MH/socket.h
+--- openvpn-2.0_rc16/socket.h  2005-02-05 01:36:31.000000000 -0700
++++ openvpn-2.0_rc16MH/socket.h        2005-02-25 21:13:53.000000000 -0700
+@@ -78,12 +78,29 @@
+ /* convert a packet_size_type from network to host order */
+ #define ntohps(x) ntohs(x)
++/* OpenVPN sockaddr struct */
++struct openvpn_sockaddr
++{
++  int dummy; // JYFIXME
++  struct sockaddr_in sa;
++};
++
++/* actual address of remote, based on source address of received packets */
++struct link_socket_actual
++{
++  int dummy; // JYFIXME
++  struct openvpn_sockaddr dest;
++#if ENABLE_IP_PKTINFO
++  struct in_pktinfo pi;
++#endif
++};
++
+ /* IP addresses which are persistant across SIGUSR1s */
+ struct link_socket_addr
+ {
+-  struct sockaddr_in local;
+-  struct sockaddr_in remote; /* initial remote */
+-  struct sockaddr_in actual; /* remote may change due to --float */
++  struct openvpn_sockaddr local;
++  struct openvpn_sockaddr remote;   /* initial remote */
++  struct link_socket_actual actual; /* reply to this address */
+ };
+ struct link_socket_info
+@@ -186,6 +203,9 @@
+   struct buffer stream_buf_data;
+   bool stream_reset;
++# define SF_USE_IP_PKTINFO (1<<0)
++  unsigned int socket_flags;
++
+ #ifdef ENABLE_HTTP_PROXY
+   /* HTTP proxy */
+   struct http_proxy_info *http_proxy;
+@@ -194,7 +214,7 @@
+ #ifdef ENABLE_SOCKS
+   /* Socks proxy */
+   struct socks_proxy_info *socks_proxy;
+-  struct sockaddr_in socks_relay; /* Socks UDP relay address */
++  struct link_socket_actual socks_relay; /* Socks UDP relay address */
+ #endif
+ #if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_SOCKS)
+@@ -230,13 +250,13 @@
+ int socket_send_queue (struct link_socket *sock,
+                      struct buffer *buf,
+-                     const struct sockaddr_in *to);
++                     const struct link_socket_actual *to);
+ int socket_finalize (
+                    SOCKET s,
+                    struct overlapped_io *io,
+                    struct buffer *buf,
+-                   struct sockaddr_in *from);
++                   struct link_socket_actual *from);
+ #else
+@@ -277,29 +297,41 @@
+                        int connect_retry_seconds,
+                        int mtu_discover_type,
+                        int rcvbuf,
+-                       int sndbuf);
++                       int sndbuf,
++                       const unsigned int socket_flags);
+ void link_socket_init_phase2 (struct link_socket *sock,
+                             const struct frame *frame,
+                             volatile int *signal_received);
+-void link_socket_post_fork (const struct link_socket *sock,
+-                          const struct sockaddr_in *remote);
+-
+ void socket_adjust_frame_parameters (struct frame *frame, int proto);
+ void frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto);
+ void link_socket_close (struct link_socket *sock);
+-const char *print_sockaddr_ex (const struct sockaddr_in *addr,
+-                             bool do_port,
++#define PS_SHOW_PORT_IF_DEFINED (1<<0)
++#define PS_SHOW_PORT            (1<<1)
++#define PS_SHOW_PKTINFO         (1<<2)
++
++const char *print_sockaddr_ex (const struct openvpn_sockaddr *addr,
+                              const char* separator,
++                             const unsigned int flags,
+                              struct gc_arena *gc);
+-const char *print_sockaddr (const struct sockaddr_in *addr,
++
++const char *print_sockaddr (const struct openvpn_sockaddr *addr,
+                           struct gc_arena *gc);
++const char *print_link_socket_actual_ex (const struct link_socket_actual *act,
++                                       const char* separator,
++                                       const unsigned int flags,
++                                       struct gc_arena *gc);
++
++const char *print_link_socket_actual (const struct link_socket_actual *act,
++                                    struct gc_arena *gc);
++
++
+ #define IA_EMPTY_IF_UNDEF (1<<0)
+ #define IA_NET_ORDER      (1<<1)
+ const char *print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc);
+@@ -308,7 +340,7 @@
+ #define SA_SET_IF_NONZERO (1<<1)
+ void setenv_sockaddr (struct env_set *es,
+                     const char *name_prefix,
+-                    const struct sockaddr_in *addr,
++                    const struct openvpn_sockaddr *addr,
+                     const bool flags);
+ void setenv_in_addr_t (struct env_set *es,
+@@ -316,19 +348,24 @@
+                      in_addr_t addr,
+                      const bool flags);
++void setenv_link_socket_actual (struct env_set *es,
++                              const char *name_prefix,
++                              const struct link_socket_actual *act,
++                              const bool flags);
++
+ void bad_address_length (int actual, int expected);
+ in_addr_t link_socket_current_remote (const struct link_socket_info *info);
+ void link_socket_connection_initiated (const struct buffer *buf,
+                                      struct link_socket_info *info,
+-                                     const struct sockaddr_in *addr,
++                                     const struct link_socket_actual *addr,
+                                      const char *common_name,
+                                      struct env_set *es);
+ void link_socket_bad_incoming_addr (struct buffer *buf,
+                                   const struct link_socket_info *info,
+-                                  const struct sockaddr_in *from_addr);
++                                  const struct link_socket_actual *from_addr);
+ void link_socket_bad_outgoing_addr (void);
+@@ -349,7 +386,7 @@
+ socket_descriptor_t create_socket_tcp (void);
+ socket_descriptor_t socket_do_accept (socket_descriptor_t sd,
+-                                    struct sockaddr_in *remote,
++                                    struct link_socket_actual *act,
+                                     const bool nowait);
+ /*
+@@ -440,33 +477,39 @@
+ }
+ static inline bool
+-addr_defined (const struct sockaddr_in *addr)
++addr_defined (const struct openvpn_sockaddr *addr)
+ {
+-  return addr->sin_addr.s_addr != 0;
++  return addr->sa.sin_addr.s_addr != 0;
+ }
+ static inline bool
+-addr_match (const struct sockaddr_in *a1, const struct sockaddr_in *a2)
++link_socket_actual_defined (const struct link_socket_actual *act)
+ {
+-  return a1->sin_addr.s_addr == a2->sin_addr.s_addr;
++  return act && addr_defined (&act->dest);
++}
++
++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;
+ }
+ static inline in_addr_t
+-addr_host (const struct sockaddr_in *s)
++addr_host (const struct openvpn_sockaddr *s)
+ {
+-  return ntohl (s->sin_addr.s_addr);
++  return ntohl (s->sa.sin_addr.s_addr);
+ }
+ static inline bool
+-addr_port_match (const struct sockaddr_in *a1, const struct sockaddr_in *a2)
++addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
+ {
+-  return a1->sin_addr.s_addr == a2->sin_addr.s_addr
+-    && a1->sin_port == a2->sin_port;
++  return a1->sa.sin_addr.s_addr == a2->sa.sin_addr.s_addr
++    && a1->sa.sin_port == a2->sa.sin_port;
+ }
+ static inline bool
+-addr_match_proto (const struct sockaddr_in *a1,
+-                const struct sockaddr_in *a2,
++addr_match_proto (const struct openvpn_sockaddr *a1,
++                const struct openvpn_sockaddr *a2,
+                 const int proto)
+ {
+   return link_socket_proto_connection_oriented (proto)
+@@ -475,6 +518,12 @@
+ }
+ static inline bool
++link_socket_actual_match (const struct link_socket_actual *a1, const struct link_socket_actual *a2)
++{
++  return addr_port_match (&a1->dest, &a2->dest);
++}
++
++static inline bool
+ socket_connection_reset (const struct link_socket *sock, int status)
+ {
+   if (link_socket_connection_oriented (sock))
+@@ -497,17 +546,17 @@
+ static inline bool
+ link_socket_verify_incoming_addr (struct buffer *buf,
+                                 const struct link_socket_info *info,
+-                                const struct sockaddr_in *from_addr)
++                                const struct link_socket_actual *from_addr)
+ {
+   if (buf->len > 0)
+     {
+-      if (from_addr->sin_family != AF_INET)
++      if (from_addr->dest.sa.sin_family != AF_INET)
+       return false;
+-      if (!addr_defined (from_addr))
++      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, &info->lsa->remote, info->proto))
++      if (addr_match_proto (&from_addr->dest, &info->lsa->remote, info->proto))
+       return true;
+     }
+   return false;
+@@ -516,21 +565,18 @@
+ static inline void
+ link_socket_get_outgoing_addr (struct buffer *buf,
+                             const struct link_socket_info *info,
+-                            struct sockaddr_in *addr)
++                            struct link_socket_actual **act)
+ {
+   if (buf->len > 0)
+     {
+       struct link_socket_addr *lsa = info->lsa;
+-      if (addr_defined (&lsa->actual))
+-      {
+-        addr->sin_family = lsa->actual.sin_family;
+-        addr->sin_addr.s_addr = lsa->actual.sin_addr.s_addr;
+-        addr->sin_port = lsa->actual.sin_port;
+-      }
++      if (link_socket_actual_defined (&lsa->actual))
++      *act = &lsa->actual;
+       else
+       {
+         link_socket_bad_outgoing_addr ();
+         buf->len = 0;
++        *act = NULL;
+       }
+     }
+ }
+@@ -538,7 +584,7 @@
+ static inline void
+ link_socket_set_outgoing_addr (const struct buffer *buf,
+                              struct link_socket_info *info,
+-                             const struct sockaddr_in *addr,
++                             const struct link_socket_actual *act,
+                              const char *common_name,
+                              struct env_set *es)
+ {
+@@ -548,14 +594,14 @@
+       if (
+         /* new or changed address? */
+         (!info->connection_established
+-         || !addr_match_proto (addr, &lsa->actual, info->proto))
++         || !addr_match_proto (&act->dest, &lsa->actual.dest, info->proto))
+         /* address undef or address == remote or --float */
+         && (info->remote_float
+             || !addr_defined (&lsa->remote)
+-            || addr_match_proto (addr, &lsa->remote, info->proto))
++            || addr_match_proto (&act->dest, &lsa->remote, info->proto))
+         )
+       {
+-        link_socket_connection_initiated (buf, info, addr, common_name, es);
++        link_socket_connection_initiated (buf, info, act, common_name, es);
+       }
+     }
+ }
+@@ -592,7 +638,7 @@
+ static inline int
+ link_socket_read_udp_win32 (struct link_socket *sock,
+                           struct buffer *buf,
+-                          struct sockaddr_in *from)
++                          struct link_socket_actual *from)
+ {
+   return socket_finalize (sock->sd, &sock->reads, buf, from);
+ }
+@@ -602,7 +648,7 @@
+ int link_socket_read_udp_posix (struct link_socket *sock,
+                               struct buffer *buf,
+                               int maxsize,
+-                              struct sockaddr_in *from);
++                              struct link_socket_actual *from);
+ #endif
+@@ -611,7 +657,7 @@
+ link_socket_read (struct link_socket *sock,
+                 struct buffer *buf,
+                 int maxsize,
+-                struct sockaddr_in *from)
++                struct link_socket_actual *from)
+ {
+   if (sock->info.proto == PROTO_UDPv4)
+     {
+@@ -627,7 +673,7 @@
+   else if (sock->info.proto == PROTO_TCPv4_SERVER || sock->info.proto == PROTO_TCPv4_CLIENT)
+     {
+       /* from address was returned by accept */
+-      *from = sock->info.lsa->actual;
++      from->dest.sa = sock->info.lsa->actual.dest.sa;
+       return link_socket_read_tcp (sock, buf);
+     }
+   else
+@@ -643,14 +689,14 @@
+ int link_socket_write_tcp (struct link_socket *sock,
+                          struct buffer *buf,
+-                         struct sockaddr_in *to);
++                         struct link_socket_actual *to);
+ #ifdef WIN32
+ static inline int
+ link_socket_write_win32 (struct link_socket *sock,
+                        struct buffer *buf,
+-                       struct sockaddr_in *to)
++                       struct link_socket_actual *to)
+ {
+   int err = 0;
+   int status = 0;
+@@ -675,17 +721,26 @@
+ static inline int
+ link_socket_write_udp_posix (struct link_socket *sock,
+                            struct buffer *buf,
+-                           struct sockaddr_in *to)
++                           struct link_socket_actual *to)
+ {
+-  return sendto (sock->sd, BPTR (buf), BLEN (buf), 0,
+-               (struct sockaddr *) to,
+-               (socklen_t) sizeof (*to));
++#if ENABLE_IP_PKTINFO
++  int link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
++                                         struct buffer *buf,
++                                         struct link_socket_actual *to);
++
++  if (sock->socket_flags & SF_USE_IP_PKTINFO)
++    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));
+ }
+ static inline int
+ link_socket_write_tcp_posix (struct link_socket *sock,
+                            struct buffer *buf,
+-                           struct sockaddr_in *to)
++                           struct link_socket_actual *to)
+ {
+   return send (sock->sd, BPTR (buf), BLEN (buf), MSG_NOSIGNAL);
+ }
+@@ -695,7 +750,7 @@
+ static inline int
+ link_socket_write_udp (struct link_socket *sock,
+                      struct buffer *buf,
+-                     struct sockaddr_in *to)
++                     struct link_socket_actual *to)
+ {
+ #ifdef WIN32
+   return link_socket_write_win32 (sock, buf, to);
+@@ -708,7 +763,7 @@
+ static inline int
+ link_socket_write (struct link_socket *sock,
+                  struct buffer *buf,
+-                 struct sockaddr_in *to)
++                 struct link_socket_actual *to)
+ {
+   if (sock->info.proto == PROTO_UDPv4)
+     {
+diff -ur openvpn-2.0_rc16/socks.c openvpn-2.0_rc16MH/socks.c
+--- openvpn-2.0_rc16/socks.c   2005-01-09 17:46:29.000000000 -0700
++++ openvpn-2.0_rc16MH/socks.c 2005-02-24 22:52:32.000000000 -0700
+@@ -149,7 +149,8 @@
+ }
+ static bool
+-recv_socks_reply (socket_descriptor_t sd, struct sockaddr_in *addr,
++recv_socks_reply (socket_descriptor_t sd,
++                struct openvpn_sockaddr *addr,
+                 volatile int *signal_received)
+ {
+   char atyp = '\0';
+@@ -160,9 +161,9 @@
+   if (addr != NULL)
+     {
+-      addr->sin_family = AF_INET;
+-      addr->sin_addr.s_addr = htonl (INADDR_ANY);
+-      addr->sin_port = htons (0);
++      addr->sa.sin_family = AF_INET;
++      addr->sa.sin_addr.s_addr = htonl (INADDR_ANY);
++      addr->sa.sin_port = htons (0);
+     }
+   while (len < 4 + alen + 2)
+@@ -249,8 +250,8 @@
+   /* ATYP == 1 (IP V4 address) */
+   if (atyp == '\x01' && addr != NULL)
+     {
+-      memcpy (&addr->sin_addr, buf + 4, sizeof (addr->sin_addr));
+-      memcpy (&addr->sin_port, buf + 8, sizeof (addr->sin_port));
++      memcpy (&addr->sa.sin_addr, buf + 4, sizeof (addr->sa.sin_addr));
++      memcpy (&addr->sa.sin_port, buf + 8, sizeof (addr->sa.sin_port));
+     }
+@@ -311,7 +312,7 @@
+ establish_socks_proxy_udpassoc (struct socks_proxy_info *p,
+                               socket_descriptor_t ctrl_sd, /* already open to proxy */
+                               socket_descriptor_t udp_sd,
+-                              struct sockaddr_in *relay_addr,
++                              struct openvpn_sockaddr *relay_addr,
+                               volatile int *signal_received)
+ {
+   if (!socks_handshake (ctrl_sd, signal_received))
+@@ -353,7 +354,7 @@
+  */
+ void
+ socks_process_incoming_udp (struct buffer *buf,
+-                          struct sockaddr_in *from)
++                          struct link_socket_actual *from)
+ {
+   int atyp;
+@@ -368,8 +369,8 @@
+   if (atyp != 1)              /* ATYP == 1 (IP V4) */
+     goto error;
+-  buf_read (buf, &from->sin_addr, sizeof (from->sin_addr));
+-  buf_read (buf, &from->sin_port, sizeof (from->sin_port));
++  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));
+   return;
+@@ -386,7 +387,7 @@
+  */
+ int
+ socks_process_outgoing_udp (struct buffer *buf,
+-                          struct sockaddr_in *to)
++                          const struct link_socket_actual *to)
+ {
+   /* 
+    * Get a 10 byte subset buffer prepended to buf --
+@@ -401,8 +402,8 @@
+   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->sin_addr, sizeof (to->sin_addr));
+-  buf_write (&head, &to->sin_port, sizeof (to->sin_port));
++  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));
+   return 10;
+ }
+diff -ur openvpn-2.0_rc16/socks.h openvpn-2.0_rc16MH/socks.h
+--- openvpn-2.0_rc16/socks.h   2005-01-09 17:46:29.000000000 -0700
++++ openvpn-2.0_rc16MH/socks.h 2005-02-24 22:52:11.000000000 -0700
+@@ -35,6 +35,9 @@
+ #include "buffer.h"
++struct openvpn_sockaddr;
++struct link_socket_actual;
++
+ struct socks_proxy_info {
+   bool defined;
+   bool retry;
+@@ -59,14 +62,14 @@
+ void establish_socks_proxy_udpassoc (struct socks_proxy_info *p,
+                                    socket_descriptor_t ctrl_sd, /* already open to proxy */
+                                    socket_descriptor_t udp_sd,
+-                                   struct sockaddr_in *relay_addr,
++                                   struct openvpn_sockaddr *relay_addr,
+                                    volatile int *signal_received);
+ void socks_process_incoming_udp (struct buffer *buf,
+-                              struct sockaddr_in *from);
++                              struct link_socket_actual *from);
+ int socks_process_outgoing_udp (struct buffer *buf,
+-                              struct sockaddr_in *to);
++                              const struct link_socket_actual *to);
+ #endif
+ #endif
+diff -ur openvpn-2.0_rc16/ssl.c openvpn-2.0_rc16MH/ssl.c
+--- openvpn-2.0_rc16/ssl.c     2005-02-15 21:12:55.000000000 -0700
++++ openvpn-2.0_rc16MH/ssl.c   2005-02-25 14:47:45.000000000 -0700
+@@ -362,7 +362,7 @@
+ static void
+ setenv_untrusted (struct tls_session *session)
+ {
+-  setenv_sockaddr (session->opt->es, "untrusted", &session->untrusted_sockaddr, SA_IP_PORT);
++  setenv_link_socket_actual (session->opt->es, "untrusted", &session->untrusted_addr, SA_IP_PORT);
+ }
+ static void
+@@ -1784,7 +1784,7 @@
+ write_control_auth (struct tls_session *session,
+                   struct key_state *ks,
+                   struct buffer *buf,
+-                  struct sockaddr_in *to_link_addr,
++                  struct link_socket_actual **to_link_addr,
+                   int opcode,
+                   int max_ack,
+                   bool prepend_ack)
+@@ -1792,7 +1792,7 @@
+   uint8_t *header;
+   struct buffer null = clear_buf ();
+-  ASSERT (addr_defined (&ks->remote_addr));
++  ASSERT (link_socket_actual_defined (&ks->remote_addr));
+   ASSERT (reliable_ack_write
+         (ks->rec_ack, buf, &ks->session_id_remote, max_ack, prepend_ack));
+   ASSERT (session_id_write_prepend (&session->session_id, buf));
+@@ -1804,7 +1804,7 @@
+       openvpn_encrypt (buf, null, &session->tls_auth, NULL);
+       ASSERT (swap_hmac (buf, &session->tls_auth, false));
+     }
+-  *to_link_addr = ks->remote_addr;
++  *to_link_addr = &ks->remote_addr;
+ }
+ /*
+@@ -1813,7 +1813,7 @@
+ static bool
+ read_control_auth (struct buffer *buf,
+                  const struct crypto_options *co,
+-                 const struct sockaddr_in *from)
++                 const struct link_socket_actual *from)
+ {
+   struct gc_arena gc = gc_new ();
+@@ -1826,7 +1826,7 @@
+       {
+         msg (D_TLS_ERRORS,
+              "TLS Error: cannot locate HMAC in incoming packet from %s",
+-             print_sockaddr (from, &gc));
++             print_link_socket_actual (from, &gc));
+         gc_free (&gc);
+         return false;
+       }
+@@ -1838,7 +1838,7 @@
+       {
+         msg (D_TLS_ERRORS,
+              "TLS Error: incoming packet authentication failed from %s",
+-             print_sockaddr (from, &gc));
++             print_link_socket_actual (from, &gc));
+         gc_free (&gc);
+         return false;
+       }
+@@ -2720,7 +2720,7 @@
+ tls_process (struct tls_multi *multi,
+            struct tls_session *session,
+            struct buffer *to_link,
+-           struct sockaddr_in *to_link_addr,
++           struct link_socket_actual **to_link_addr,
+            struct link_socket_info *to_link_socket_info,
+            interval_t *wakeup)
+ {
+@@ -3113,7 +3113,7 @@
+ bool
+ tls_multi_process (struct tls_multi *multi,
+                  struct buffer *to_link,
+-                 struct sockaddr_in *to_link_addr,
++                 struct link_socket_actual **to_link_addr,
+                  struct link_socket_info *to_link_socket_info,
+                  interval_t *wakeup)
+ {
+@@ -3137,7 +3137,7 @@
+       /* set initial remote address */
+       if (i == TM_ACTIVE && ks->state == S_INITIAL &&
+-        addr_defined (&to_link_socket_info->lsa->actual))
++        link_socket_actual_defined (&to_link_socket_info->lsa->actual))
+       ks->remote_addr = to_link_socket_info->lsa->actual;
+       dmsg (D_TLS_DEBUG,
+@@ -3146,17 +3146,30 @@
+          state_name (ks->state),
+          session_id_print (&session->session_id, &gc),
+          session_id_print (&ks->session_id_remote, &gc),
+-         print_sockaddr (&ks->remote_addr, &gc));
++         print_link_socket_actual (&ks->remote_addr, &gc));
+-      if (ks->state >= S_INITIAL && addr_defined (&ks->remote_addr))
++      if (ks->state >= S_INITIAL && link_socket_actual_defined (&ks->remote_addr))
+       {
++        struct link_socket_actual *tla = NULL;
++
+         update_time ();
+-        if (tls_process (multi, session, to_link, to_link_addr,
++        if (tls_process (multi, session, to_link, &tla,
+                          to_link_socket_info, wakeup))
+           active = true;
+         /*
++         * If tls_process produced an outgoing packet,
++         * return the link_socket_actual object (which
++         * contains the outgoing address).
++         */
++        if (tla)
++          {
++            multi->to_link_addr = *tla;
++            *to_link_addr = &multi->to_link_addr;
++          }
++
++        /*
+          * If tls_process hits an error:
+          * (1) If the session has an unexpired lame duck key, preserve it.
+          * (2) Reinitialize the session.
+@@ -3275,7 +3288,7 @@
+ bool
+ tls_pre_decrypt (struct tls_multi *multi,
+-               struct sockaddr_in *from,
++               const struct link_socket_actual *from,
+                struct buffer *buf,
+                struct crypto_options *opt)
+ {
+@@ -3317,7 +3330,7 @@
+             if (DECRYPT_KEY_ENABLED (multi, ks)
+                 && key_id == ks->key_id
+                 && ks->authenticated
+-                && addr_port_match(from, &ks->remote_addr))
++                && link_socket_actual_match (from, &ks->remote_addr))
+               {
+                 /* return appropriate data channel decrypt key in opt */
+                 opt->key_ctx_bi = &ks->key;
+@@ -3330,7 +3343,7 @@
+                 ks->n_bytes += buf->len;
+                 dmsg (D_TLS_DEBUG,
+                      "TLS: data channel, key_id=%d, IP=%s",
+-                     key_id, print_sockaddr (from, &gc));
++                     key_id, print_link_socket_actual (from, &gc));
+                 gc_free (&gc);
+                 return ret;
+               }
+@@ -3343,14 +3356,14 @@
+                      key_id,
+                      ks->key_id,
+                      ks->authenticated,
+-                     addr_port_match (from, &ks->remote_addr));
++                     link_socket_actual_match (from, &ks->remote_addr));
+               }
+ #endif
+           }
+         msg (D_TLS_ERRORS,
+              "TLS Error: local/remote TLS keys are out of sync: %s [%d]",
+-             print_sockaddr (from, &gc), key_id);
++             print_link_socket_actual (from, &gc), key_id);
+         goto error;
+       }
+       else                      /* control channel packet */
+@@ -3364,7 +3377,7 @@
+           {
+             msg (D_TLS_ERRORS,
+                  "TLS Error: unknown opcode received from %s op=%d",
+-                 print_sockaddr (from, &gc), op);
++                 print_link_socket_actual (from, &gc), op);
+             goto error;
+           }
+@@ -3379,7 +3392,7 @@
+               {
+                 msg (D_TLS_ERRORS,
+                      "TLS Error: client->client or server->server connection attempted from %s",
+-                     print_sockaddr (from, &gc));
++                     print_link_socket_actual (from, &gc));
+                 goto error;
+               }
+           }
+@@ -3388,7 +3401,7 @@
+          * Authenticate Packet
+          */
+         dmsg (D_TLS_DEBUG, "TLS: control channel, op=%s, IP=%s",
+-             packet_opcode_name (op), print_sockaddr (from, &gc));
++             packet_opcode_name (op), print_link_socket_actual (from, &gc));
+         /* get remote session-id */
+         {
+@@ -3398,7 +3411,7 @@
+             {
+               msg (D_TLS_ERRORS,
+                    "TLS Error: session-id not found in packet from %s",
+-                   print_sockaddr (from, &gc));
++                   print_link_socket_actual (from, &gc));
+               goto error;
+             }
+         }
+@@ -3415,9 +3428,9 @@
+                  state_name (ks->state),
+                  session_id_print (&session->session_id, &gc),
+                  session_id_print (&sid, &gc),
+-                 print_sockaddr (from, &gc),
++                 print_link_socket_actual (from, &gc),
+                  session_id_print (&ks->session_id_remote, &gc),
+-                 print_sockaddr (&ks->remote_addr, &gc));
++                 print_link_socket_actual (&ks->remote_addr, &gc));
+             if (session_id_equal (&ks->session_id_remote, &sid))
+               /* found a match */
+@@ -3462,7 +3475,7 @@
+                   {
+                     msg (D_TLS_ERRORS,
+                          "TLS Error: Cannot accept new session request from %s due to --single-session [1]",
+-                         print_sockaddr (from, &gc));
++                         print_link_socket_actual (from, &gc));
+                     goto error;
+                   }
+@@ -3478,13 +3491,13 @@
+                 msg (D_TLS_DEBUG_LOW,
+                      "TLS: Initial packet from %s, sid=%s",
+-                     print_sockaddr (from, &gc),
++                     print_link_socket_actual (from, &gc),
+                      session_id_print (&sid, &gc));
+                 do_burst = true;
+                 new_link = true;
+                 i = TM_ACTIVE;
+-                session->untrusted_sockaddr = *from;
++                session->untrusted_addr = *from;
+               }
+           }
+@@ -3504,7 +3517,7 @@
+               {
+                 msg (D_TLS_ERRORS,
+                      "TLS Error: Cannot accept new session request from %s due to --single-session [2]",
+-                     print_sockaddr (from, &gc));
++                     print_link_socket_actual (from, &gc));
+                 goto error;
+               }
+             
+@@ -3527,11 +3540,11 @@
+              */
+             msg (D_TLS_DEBUG_LOW,
+                  "TLS: new session incoming connection from %s",
+-                 print_sockaddr (from, &gc));
++                 print_link_socket_actual (from, &gc));
+             new_link = true;
+             i = TM_UNTRUSTED;
+-            session->untrusted_sockaddr = *from;
++            session->untrusted_addr = *from;
+           }
+         else
+           {
+@@ -3545,7 +3558,7 @@
+               {
+                 msg (D_TLS_ERRORS,
+                      "TLS Error: Unroutable control packet received from %s (si=%d op=%s)",
+-                     print_sockaddr (from, &gc),
++                     print_link_socket_actual (from, &gc),
+                      i,
+                      packet_opcode_name (op));
+                 goto error;
+@@ -3554,10 +3567,10 @@
+             /*
+              * Verify remote IP address
+              */
+-            if (!new_link && !addr_port_match (&ks->remote_addr, from))
++            if (!new_link && !link_socket_actual_match (&ks->remote_addr, from))
+               {
+                 msg (D_TLS_ERRORS, "TLS Error: Received control packet from unexpected IP addr: %s",
+-                    print_sockaddr (from, &gc));
++                    print_link_socket_actual (from, &gc));
+                 goto error;
+               }
+@@ -3619,11 +3632,11 @@
+               ks->remote_addr = *from;
+               ++multi->n_sessions;
+             }
+-          else if (!addr_port_match (&ks->remote_addr, from))
++          else if (!link_socket_actual_match (&ks->remote_addr, from))
+             {
+               msg (D_TLS_ERRORS,
+                    "TLS Error: Existing session control channel packet from unknown IP address: %s",
+-                   print_sockaddr (from, &gc));
++                   print_link_socket_actual (from, &gc));
+               goto error;
+             }
+@@ -3720,8 +3733,9 @@
+  */
+ bool
+ tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,
+-                    const struct sockaddr_in *from,
++                    const struct link_socket_actual *from,
+                     const struct buffer *buf)
++
+ {
+   struct gc_arena gc = gc_new ();
+   bool ret = false;
+@@ -3748,7 +3762,7 @@
+          */
+         dmsg (D_TLS_STATE_ERRORS,
+              "TLS State Error: No TLS state for client %s, opcode=%d",
+-             print_sockaddr (from, &gc),
++             print_link_socket_actual (from, &gc),
+              op);
+         goto error;
+       }
+@@ -3758,7 +3772,7 @@
+         dmsg (D_TLS_STATE_ERRORS,
+              "TLS State Error: Unknown key ID (%d) received from %s -- 0 was expected",
+              key_id,
+-             print_sockaddr (from, &gc));
++             print_link_socket_actual (from, &gc));
+         goto error;
+       }
+@@ -3767,7 +3781,7 @@
+         dmsg (D_TLS_STATE_ERRORS,
+              "TLS State Error: Large packet (size %d) received from %s -- a packet no larger than %d bytes was expected",
+              buf->len,
+-             print_sockaddr (from, &gc),
++             print_link_socket_actual (from, &gc),
+              EXPANDED_SIZE_DYNAMIC (&tas->frame));
+         goto error;
+       }
+diff -ur openvpn-2.0_rc16/ssl.h openvpn-2.0_rc16MH/ssl.h
+--- openvpn-2.0_rc16/ssl.h     2005-01-18 22:59:20.000000000 -0700
++++ openvpn-2.0_rc16MH/ssl.h   2005-02-25 14:47:49.000000000 -0700
+@@ -345,8 +345,8 @@
+   time_t must_die;            /* this object is destroyed at this time */
+   int initial_opcode;         /* our initial P_ opcode */
+-  struct session_id session_id_remote; /* peer's random session ID */
+-  struct sockaddr_in remote_addr;      /* peer's IP addr */
++  struct session_id session_id_remote;   /* peer's random session ID */
++  struct link_socket_actual remote_addr; /* peer's IP addr */
+   struct packet_id packet_id;        /* for data channel, to prevent replay attacks */
+   struct key_ctx_bi key;             /* data channel keys for encrypt/decrypt/hmac */
+@@ -489,7 +489,7 @@
+   bool verified;                /* true if peer certificate was verified against CA */
+   /* not-yet-authenticated incoming client */
+-  struct sockaddr_in untrusted_sockaddr;
++  struct link_socket_actual untrusted_addr;
+   struct key_state key[KS_SIZE];
+ };
+@@ -536,6 +536,12 @@
+   struct key_state *save_ks;  /* temporary pointer used between pre/post routines */
+   /*
++   * Used to return outgoing address from
++   * tls_multi_process.
++   */
++  struct link_socket_actual to_link_addr;
++
++  /*
+    * Number of sessions negotiated thus far.
+    */
+   int n_sessions;
+@@ -591,19 +597,19 @@
+ bool tls_multi_process (struct tls_multi *multi,
+                       struct buffer *to_link,
+-                      struct sockaddr_in *to_link_addr,
++                      struct link_socket_actual **to_link_addr,
+                       struct link_socket_info *to_link_socket_info,
+                       interval_t *wakeup);
+ void tls_multi_free (struct tls_multi *multi, bool clear);
+ bool tls_pre_decrypt (struct tls_multi *multi,
+-                    struct sockaddr_in *from,
++                    const struct link_socket_actual *from,
+                     struct buffer *buf,
+                     struct crypto_options *opt);
+ bool tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,
+-                         const struct sockaddr_in *from,
++                         const struct link_socket_actual *from,
+                          const struct buffer *buf);
+ void tls_pre_encrypt (struct tls_multi *multi,
+diff -ur openvpn-2.0_rc16/syshead.h openvpn-2.0_rc16MH/syshead.h
+--- openvpn-2.0_rc16/syshead.h 2005-01-09 17:46:27.000000000 -0700
++++ openvpn-2.0_rc16MH/syshead.h       2005-02-25 21:23:50.000000000 -0700
+@@ -291,6 +291,15 @@
+ #endif
+ /*
++ * Does this platform support linux-style IP_PKTINFO?
++ */
++#if defined(ENABLE_MULTIHOME) && defined(HAVE_IN_PKTINFO) && defined(IP_PKTINFO) && defined(HAVE_MSGHDR) && defined(HAVE_CMSGHDR) && defined(HAVE_IOVEC) && defined(CMSG_FIRSTHDR) && defined(CMSG_NXTHDR) && defined(HAVE_RECVMSG) && defined(HAVE_SENDMSG)
++#define ENABLE_IP_PKTINFO 1
++#else
++#define ENABLE_IP_PKTINFO 0
++#endif
++
++/*
+  * Disable ESEC
+  */
+ #if 0
This page took 0.201816 seconds and 4 git commands to generate.