]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
svn merge -r 618:619 $SO/patches/openvpn-2-0_rc16-mh/openvpn
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Sat, 15 Oct 2005 08:44:02 +0000 (08:44 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Sat, 15 Oct 2005 08:44:02 +0000 (08:44 +0000)
Merged --multihome patch + aggregated sockflags.
Pre-2.1_beta3

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@622 e7ae566f-a301-0410-adde-c780ea21d3b5

20 files changed:
ChangeLog
configure.ac
forward.c
manage.c
manage.h
mroute.c
mroute.h
mtcp.c
mudp.c
multi.c
openvpn.h
options.c
ping-inline.h
socket.c
socket.h
socks.c
socks.h
ssl.c
ssl.h
syshead.h

index 5bbdca1d737874a4dc3311ee0b9181674fa34d60..04c8567a89cb718de218cfb4200bca6e551e8cc3 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,12 +11,11 @@ $Id$
   from the file specified by --ca regardless if the pkcs12 file
   contains a CA cert or not (Mathias Sundman).
 * Merged --capath patch (Thomas Noel).
-* NOTE TO PACKAGE MAINTAINERS: Moved "plugin"
-  directory to "plugins".  This is
-  to work around a strange problem with the
-  "make dist" target in the automake-generated
-  makefile, where the target tries to do a
-  rather bogus "gcc -g -O2 -I. plugin.c -o plugin".
+* Merged --multihome patch.
+* NOTE TO PACKAGE MAINTAINERS: Moved "plugin" directory to "plugins".
+  This is to work around a strange problem with the "make dist"
+  target in the automake-generated makefile, where the target tries to
+  do a rather bogus "gcc -g -O2 -I. plugin.c -o plugin".
 
 2005.10.13 -- Version 2.1-beta2
 
index 9faae979833ef2c4324cc49a72b2c34be41998a2..844778f898b6afff4159efe17048425ff7049d0d 100644 (file)
@@ -95,6 +95,12 @@ AC_ARG_ENABLE(fragment,
    [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"],
@@ -342,6 +348,11 @@ AC_CHECK_TYPE(
        [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)
@@ -367,7 +378,7 @@ AC_CHECK_FUNCS(daemon chroot getpwnam setuid nice system getpid dup dup2 dnl
               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
@@ -605,6 +616,11 @@ if test "$HTTP_PROXY" = "yes"; then
    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])
index e1023efafe5c80dea03348b30980fb64382210c1..11d6d289adc4dddc02bd2a2f5661475f9b1869f3 100644 (file)
--- a/forward.c
+++ b/forward.c
@@ -571,12 +571,12 @@ socks_postprocess_incoming_link (struct context *c)
 
 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;
     }
 }
@@ -616,7 +616,10 @@ read_incoming_link (struct context *c)
   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))
     {
@@ -687,7 +690,7 @@ process_incoming_link (struct context *c)
   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));
 
   /*
@@ -985,7 +988,7 @@ process_outgoing_link (struct context *c)
        * 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 */
@@ -1020,12 +1023,12 @@ process_outgoing_link (struct context *c)
          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
@@ -1035,7 +1038,9 @@ process_outgoing_link (struct context *c)
            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 */
@@ -1059,7 +1064,7 @@ process_outgoing_link (struct context *c)
          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);
        }
@@ -1068,7 +1073,7 @@ process_outgoing_link (struct context *c)
     {
       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));
     }
index f76ec7a13c399963508fb4b4c51f854f8afe09d2..2d1bcbbd03da1605912ff63004d97d721f363072 100644 (file)
--- a/manage.c
+++ b/manage.c
@@ -770,13 +770,16 @@ static void
 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
@@ -1145,9 +1148,9 @@ man_settings_init (struct man_settings *ms,
       /*
        * 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
@@ -1159,7 +1162,7 @@ man_settings_init (struct man_settings *ms,
        }
       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);
        }
       
@@ -1406,7 +1409,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.sin_addr.s_addr = htonl (tun_local_ip);
+      man->settings.local.sa.sin_addr.s_addr = htonl (tun_local_ip);
       man_connection_init (man);
     }
 
index 80152268e21848a949422f7fb1fc2eed6590c5a3..5d059fa9dfeff02e731e8833ccca1cee1c45c10c 100644 (file)
--- a/manage.h
+++ b/manage.h
@@ -188,7 +188,7 @@ struct man_persist {
 
 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;
@@ -215,7 +215,7 @@ struct man_connection {
 
   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;
index 0a7bcf638c43e182e52f9db25224371a8920e2f1..a7d1215bae65f364db82347f094aa23226cdd3b3 100644 (file)
--- a/mroute.c
+++ b/mroute.c
@@ -168,28 +168,29 @@ mroute_extract_addr_from_packet (struct mroute_addr *src,
 }
 
 /*
- * 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;
     }
index 87e952cc4fdcf58d65e39fe0a620e2c49af90378..fb7bee72e81a68ede1eea13a944b85cafe4e3d4e 100644 (file)
--- a/mroute.h
+++ b/mroute.h
@@ -94,9 +94,11 @@ unsigned int mroute_extract_addr_from_packet (struct mroute_addr *src,
                                              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 --git a/mtcp.c b/mtcp.c
index a71801ff139cded72554dcc69ff3646b1a5c36bf..6ec99740aca66943335ea5fb74c65246c8a2808f 100644 (file)
--- a/mtcp.c
+++ b/mtcp.c
@@ -159,7 +159,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);
-  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 --git a/mudp.c b/mudp.c
index 750dc8f871494b9fed2fa459e001deea1f2650eb..fa2ae17c5e097fbe05d65c08f4aa526aff98236a 100644 (file)
--- a/mudp.c
+++ b/mudp.c
@@ -51,7 +51,7 @@ multi_get_create_instance_udp (struct multi_context *m)
   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 --git a/multi.c b/multi.c
index 7bccfed874d1f3aba4b1e5a10238ff448ca0465e..a42c561beaba27553ed058b62ba6da5796f304ba 100644 (file)
--- a/multi.c
+++ b/multi.c
@@ -982,13 +982,13 @@ multi_learn_in_addr_t (struct multi_context *m,
                       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)
     {
@@ -2180,15 +2180,15 @@ management_callback_kill_by_addr (void *arg, const in_addr_t addr, const int por
   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)))
index 5c93c8d778a2e85b721282fbdcfadae7a1277c37..78bb67bf8f3a956141bbc34dba6d6dc506017aab 100644 (file)
--- a/openvpn.h
+++ b/openvpn.h
@@ -205,8 +205,8 @@ struct context_2
   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;
index 08956748f956feec5d70931c1d1646117c33221f..c9ed15df8fe4d4f6a8a14c41fa750577e132fc5d 100644 (file)
--- a/options.c
+++ b/options.c
@@ -175,6 +175,9 @@ static const char usage_message[] =
   "--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"
   "--remap-usr1 s  : On SIGUSR1 signals, remap signal (s='SIGHUP' or 'SIGTERM').\n"
   "--persist-tun   : Keep tun/tap device open across SIGUSR1 or --ping-restart.\n"
@@ -3281,6 +3284,13 @@ add_option (struct options *options,
       VERIFY_PERMISSION (OPT_P_GENERAL);
       options->mlock = true;
     }
+#if ENABLE_IP_PKTINFO
+  else if (streq (p[0], "multihome"))
+    {
+      VERIFY_PERMISSION (OPT_P_GENERAL);
+      options->sockflags |= SF_USE_IP_PKTINFO;
+    }
+#endif
   else if (streq (p[0], "verb") && p[1])
     {
       ++i;
index bf7fd8134085c08bc09e7eb36b0e1921d231ae53..14463def592e2fdef7251efcb0b91ee3d33ae2c3 100644 (file)
@@ -37,7 +37,7 @@ check_ping_restart (struct context *c)
       && 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);
 }
index c7172ac61674d4393aaf7144c4b6747ee0ca0899..35d38a1bb58dc814272f29165bace051ab71aaf0 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -236,7 +236,7 @@ openvpn_inet_aton (const char *dotted_quad, struct in_addr *addr)
 
 static void
 update_remote (const char* host,
-              struct sockaddr_in *addr,
+              struct openvpn_sockaddr *addr,
               bool *changed)
 {
   if (host && addr)
@@ -247,9 +247,9 @@ update_remote (const char* host,
                                          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;
        }
     }
@@ -492,12 +492,19 @@ create_socket_tcp (void)
 }
 
 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;
 }
 
@@ -507,7 +514,7 @@ create_socket (struct link_socket *sock)
   /* create socket */
   if (sock->info.proto == PROTO_UDPv4)
     {
-      sock->sd = create_socket_udp ();
+      sock->sd = create_socket_udp (sock->sockflags);
 
 #ifdef ENABLE_SOCKS
       if (sock->socks_proxy)
@@ -531,7 +538,7 @@ create_socket (struct link_socket *sock)
 
 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)
 {
@@ -553,16 +560,18 @@ socket_do_listen (socket_descriptor_t sd,
 
 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");
@@ -575,14 +584,14 @@ socket_do_accept (socket_descriptor_t sd,
 #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);
@@ -592,28 +601,30 @@ socket_do_accept (socket_descriptor_t sd,
 }
 
 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)
@@ -645,17 +656,17 @@ socket_listen_accept (socket_descriptor_t sd,
          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)");
            }
@@ -668,7 +679,7 @@ socket_listen_accept (socket_descriptor_t sd,
   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;
@@ -676,7 +687,7 @@ socket_listen_accept (socket_descriptor_t sd,
 
 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,
@@ -689,8 +700,8 @@ socket_connect (socket_descriptor_t *sd,
        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)
@@ -711,7 +722,7 @@ socket_connect (socket_descriptor_t *sd,
        {
          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;
        }
 
@@ -771,22 +782,22 @@ resolve_bind_local (struct link_socket *sock)
   /* 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",
@@ -810,8 +821,8 @@ resolve_remote (struct link_socket *sock,
       /* 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)
            {
@@ -856,7 +867,7 @@ resolve_remote (struct link_socket *sock,
                  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,
@@ -883,19 +894,22 @@ resolve_remote (struct link_socket *sock,
                }
            }
 
-         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;
@@ -1162,7 +1176,7 @@ link_socket_init_phase2 (struct link_socket *sock,
       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,
@@ -1200,7 +1214,7 @@ link_socket_init_phase2 (struct link_socket *sock,
       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,
@@ -1212,7 +1226,8 @@ link_socket_init_phase2 (struct link_socket *sock,
 
          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)
@@ -1221,8 +1236,9 @@ link_socket_init_phase2 (struct link_socket *sock,
          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);
 
@@ -1237,7 +1253,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.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;
        }
     }
 
@@ -1274,12 +1290,15 @@ link_socket_init_phase2 (struct link_socket *sock,
     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);
@@ -1344,19 +1363,19 @@ socket_adjust_frame_parameters (struct frame *frame, int proto)
 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;
 
@@ -1365,7 +1384,7 @@ link_socket_connection_initiated (const struct buffer *buf,
     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));
   }
 
@@ -1375,7 +1394,7 @@ link_socket_connection_initiated (const struct buffer *buf,
   /* 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, NULL, es))
        msg (M_WARN, "WARNING: ipchange plugin call failed");
     }
@@ -1387,7 +1406,7 @@ link_socket_connection_initiated (const struct buffer *buf,
       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");
     }
 
@@ -1397,14 +1416,14 @@ link_socket_connection_initiated (const struct buffer *buf,
 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;
 
@@ -1422,10 +1441,10 @@ link_socket_current_remote (const struct link_socket_info *info)
 {
   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;
 }
@@ -1618,29 +1637,69 @@ socket_listen_event_handle (struct link_socket *s)
  */
 
 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]";
 }
 
 /*
@@ -1667,7 +1726,7 @@ print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena *gc)
 
 /* 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];
 
@@ -1677,13 +1736,13 @@ setenv_sockaddr (struct env_set *es, const char *name_prefix, const struct socka
     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));
     }
 }
 
@@ -1692,13 +1751,22 @@ setenv_in_addr_t (struct env_set *es, const char *name_prefix, in_addr_t addr, c
 {
   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.
  */
@@ -1828,19 +1896,72 @@ link_socket_read_tcp (struct link_socket *sock,
 
 #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->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));
   return buf->len;
 }
 
@@ -1853,7 +1974,7 @@ link_socket_read_udp_posix (struct link_socket *sock,
 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);
@@ -1867,6 +1988,41 @@ link_socket_write_tcp (struct link_socket *sock,
 #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.
  */
@@ -1981,7 +2137,7 @@ socket_recv_queue (struct link_socket *sock, int maxsize)
 }
 
 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)
     {
@@ -2005,7 +2161,7 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct so
        {
          /* 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(
@@ -2081,11 +2237,10 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct so
 }
 
 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;
@@ -2162,10 +2317,10 @@ socket_finalize (
        {
          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)
index 4efcfcfffde100b8fa4e28c55e74fea1d0250061..b73f7630d7fce0c7b763536c031bf7d5c33c9d69 100644 (file)
--- a/socket.h
+++ b/socket.h
@@ -77,12 +77,29 @@ typedef uint16_t packet_size_type;
 /* 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
@@ -180,7 +197,8 @@ struct link_socket
 
   bool did_resolve_remote;
 
-# define SF_TCP_NODELAY (1<<0)
+# define SF_USE_IP_PKTINFO (1<<0)
+# define SF_TCP_NODELAY (1<<1)
   unsigned int sockflags;
 
   /* for stream sockets */
@@ -196,7 +214,7 @@ struct link_socket
 #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)
@@ -232,13 +250,13 @@ int socket_recv_queue (struct link_socket *sock, int maxsize);
 
 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
 
@@ -286,23 +304,34 @@ 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);
@@ -311,7 +340,7 @@ const char *print_in_addr_t (in_addr_t addr, unsigned int flags, struct gc_arena
 #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,
@@ -319,19 +348,24 @@ void setenv_in_addr_t (struct env_set *es,
                       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);
 
@@ -355,7 +389,7 @@ int openvpn_inet_aton (const char *dotted_quad, struct in_addr *addr);
 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);
 
 /*
@@ -447,33 +481,39 @@ link_socket_connection_oriented (const struct link_socket *sock)
 }
 
 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)
@@ -481,6 +521,12 @@ addr_match_proto (const struct sockaddr_in *a1,
     : addr_port_match (a1, a2);
 }
 
+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)
 {
@@ -504,17 +550,17 @@ socket_connection_reset (const struct link_socket *sock, int status)
 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;
@@ -523,21 +569,18 @@ link_socket_verify_incoming_addr (struct buffer *buf,
 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;
        }
     }
 }
@@ -545,7 +588,7 @@ link_socket_get_outgoing_addr (struct buffer *buf,
 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)
 {
@@ -555,14 +598,14 @@ link_socket_set_outgoing_addr (const struct buffer *buf,
       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);
        }
     }
 }
@@ -599,7 +642,7 @@ int link_socket_read_tcp (struct link_socket *sock,
 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);
 }
@@ -609,7 +652,7 @@ link_socket_read_udp_win32 (struct link_socket *sock,
 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
 
@@ -618,7 +661,7 @@ static inline int
 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)
     {
@@ -634,7 +677,7 @@ link_socket_read (struct link_socket *sock,
   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
@@ -650,14 +693,14 @@ link_socket_read (struct link_socket *sock,
 
 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;
@@ -682,17 +725,26 @@ link_socket_write_win32 (struct link_socket *sock,
 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->sockflags & 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);
 }
@@ -702,7 +754,7 @@ link_socket_write_tcp_posix (struct link_socket *sock,
 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);
@@ -715,7 +767,7 @@ link_socket_write_udp (struct link_socket *sock,
 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 --git a/socks.c b/socks.c
index 22bdfa4789ac8e08a86b99e21b9a12e536148f0c..66cf20995835c97e0d5acf103c6a6477cd9f5674 100644 (file)
--- a/socks.c
+++ b/socks.c
@@ -148,7 +148,8 @@ socks_handshake (socket_descriptor_t sd, volatile int *signal_received)
 }
 
 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';
@@ -159,9 +160,9 @@ recv_socks_reply (socket_descriptor_t sd, struct sockaddr_in *addr,
 
   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)
@@ -248,8 +249,8 @@ recv_socks_reply (socket_descriptor_t sd, struct sockaddr_in *addr,
   /* 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));
     }
 
 
@@ -310,7 +311,7 @@ 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)
 {
   if (!socks_handshake (ctrl_sd, signal_received))
@@ -352,7 +353,7 @@ establish_socks_proxy_udpassoc (struct socks_proxy_info *p,
  */
 void
 socks_process_incoming_udp (struct buffer *buf,
-                           struct sockaddr_in *from)
+                           struct link_socket_actual *from)
 {
   int atyp;
 
@@ -367,8 +368,8 @@ socks_process_incoming_udp (struct buffer *buf,
   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;
 
@@ -385,7 +386,7 @@ socks_process_incoming_udp (struct buffer *buf,
  */
 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 --
@@ -400,8 +401,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->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 --git a/socks.h b/socks.h
index 12958b811865eb2ae68537522df82b3df6676cb6..3d3f06732711be1e8457cec038644bfafd1e9a0a 100644 (file)
--- a/socks.h
+++ b/socks.h
@@ -34,6 +34,9 @@
 
 #include "buffer.h"
 
+struct openvpn_sockaddr;
+struct link_socket_actual;
+
 struct socks_proxy_info {
   bool defined;
   bool retry;
@@ -58,14 +61,14 @@ void establish_socks_proxy_passthru (struct socks_proxy_info *p,
 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 --git a/ssl.c b/ssl.c
index 60516a838011c3d834197e44d8619867c5415ec4..2d65d82bafa1fa8932f4223cb78f9e8e3079c737 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -374,7 +374,7 @@ extract_x509_field (const char *x509, const char *field_name, char *out, int siz
 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
@@ -1860,7 +1860,7 @@ static void
 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)
@@ -1868,7 +1868,7 @@ write_control_auth (struct tls_session *session,
   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));
@@ -1880,7 +1880,7 @@ write_control_auth (struct tls_session *session,
       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;
 }
 
 /*
@@ -1889,7 +1889,7 @@ write_control_auth (struct tls_session *session,
 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 ();
 
@@ -1902,7 +1902,7 @@ read_control_auth (struct buffer *buf,
        {
          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;
        }
@@ -1914,7 +1914,7 @@ read_control_auth (struct buffer *buf,
        {
          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;
        }
@@ -2803,7 +2803,7 @@ static bool
 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)
 {
@@ -3197,7 +3197,7 @@ error:
 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)
 {
@@ -3223,7 +3223,7 @@ tls_multi_process (struct tls_multi *multi,
 
       /* 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,
@@ -3232,16 +3232,29 @@ tls_multi_process (struct tls_multi *multi,
           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.
@@ -3361,7 +3374,7 @@ tls_multi_process (struct tls_multi *multi,
 
 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)
 {
@@ -3403,7 +3416,7 @@ tls_pre_decrypt (struct tls_multi *multi,
              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;
@@ -3416,7 +3429,7 @@ tls_pre_decrypt (struct tls_multi *multi,
                  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;
                }
@@ -3429,14 +3442,14 @@ tls_pre_decrypt (struct tls_multi *multi,
                       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 */
@@ -3450,7 +3463,7 @@ tls_pre_decrypt (struct tls_multi *multi,
            {
              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;
            }
 
@@ -3465,7 +3478,7 @@ tls_pre_decrypt (struct tls_multi *multi,
                {
                  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;
                }
            }
@@ -3474,7 +3487,7 @@ tls_pre_decrypt (struct tls_multi *multi,
           * 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 */
          {
@@ -3484,7 +3497,7 @@ tls_pre_decrypt (struct tls_multi *multi,
              {
                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;
              }
          }
@@ -3501,9 +3514,9 @@ tls_pre_decrypt (struct tls_multi *multi,
                   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 */
@@ -3548,7 +3561,7 @@ tls_pre_decrypt (struct tls_multi *multi,
                    {
                      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;
                    }
 
@@ -3564,13 +3577,13 @@ tls_pre_decrypt (struct tls_multi *multi,
 
                  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;
                }
            }
 
@@ -3590,7 +3603,7 @@ tls_pre_decrypt (struct tls_multi *multi,
                {
                  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;
                }
              
@@ -3613,11 +3626,11 @@ tls_pre_decrypt (struct tls_multi *multi,
               */
              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
            {
@@ -3631,7 +3644,7 @@ tls_pre_decrypt (struct tls_multi *multi,
                {
                  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;
@@ -3640,10 +3653,10 @@ tls_pre_decrypt (struct tls_multi *multi,
              /*
               * 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;
                }
 
@@ -3705,11 +3718,11 @@ tls_pre_decrypt (struct tls_multi *multi,
                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;
              }
 
@@ -3807,8 +3820,9 @@ tls_pre_decrypt (struct tls_multi *multi,
  */
 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;
@@ -3835,7 +3849,7 @@ tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,
           */
          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;
        }
@@ -3845,7 +3859,7 @@ tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,
          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;
        }
 
@@ -3854,7 +3868,7 @@ tls_pre_decrypt_lite (const struct tls_auth_standalone *tas,
          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 --git a/ssl.h b/ssl.h
index 77c2e73241f59e3572c76162a9d8f8d966709ae6..0e41690d312ac1142ef5345ec05d004156ea9222 100644 (file)
--- a/ssl.h
+++ b/ssl.h
@@ -344,8 +344,8 @@ struct key_state
   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 */
@@ -488,7 +488,7 @@ struct tls_session
   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];
 };
@@ -534,6 +534,12 @@ struct tls_multi
    */
   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.
    */
@@ -590,19 +596,19 @@ void tls_multi_init_set_options(struct tls_multi* multi,
 
 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,
index e354ef4167cc1fe516dedd20c656dbf4a2b35edf..a786e65ab4f380f3629e8a65b11951dd4137be4b 100644 (file)
--- a/syshead.h
+++ b/syshead.h
 #define EXTENDED_SOCKET_ERROR_CAPABILITY 0
 #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
  */