]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Added optional journal directory argument to "port-share" directive, for reporting...
authorJames Yonan <james@openvpn.net>
Sun, 13 Mar 2011 06:59:25 +0000 (06:59 +0000)
committerDavid Sommerseth <dazo@users.sourceforge.net>
Mon, 25 Apr 2011 20:13:22 +0000 (22:13 +0200)
git-svn-id: http://svn.openvpn.net/projects/branches/BETA21@7031 e7ae566f-a301-0410-adde-c780ea21d3b5

error.c
event.c
init.c
openvpn.8
options.c
options.h
ps.c
ps.h

diff --git a/error.c b/error.c
index 873718ce7abdb8893f6123e5f3368a5bd5ba96ec..9cf4547e5e1f702373b0f5433e7d39bd0cdc19fd 100644 (file)
--- a/error.c
+++ b/error.c
@@ -353,7 +353,7 @@ void x_msg (const unsigned int flags, const char *format, ...)
     }
 
   if (flags & M_FATAL)
-    msg (M_INFO, "Exiting");
+    msg (M_INFO, "Exiting due to fatal error");
 
   mutex_unlock_static (L_MSG);
   
@@ -690,35 +690,38 @@ msg_thread_uninit (void)
 void
 openvpn_exit (const int status)
 {
-  void tun_abort();
+  if (!forked)
+    {
+      void tun_abort();
 #ifdef ENABLE_PLUGIN
-  void plugin_abort (void);
+      void plugin_abort (void);
 #endif
 
-  tun_abort();
+      tun_abort();
 
 #ifdef WIN32
-  uninit_win32 ();
+      uninit_win32 ();
 #endif
 
-  close_syslog ();
+      close_syslog ();
 
 #ifdef ENABLE_PLUGIN
-  plugin_abort ();
+      plugin_abort ();
 #endif
 
 #if PORT_SHARE
-  if (port_share)
-    port_share_abort (port_share);
+      if (port_share)
+       port_share_abort (port_share);
 #endif
 
 #ifdef ABORT_ON_ERROR
-  if (status == OPENVPN_EXIT_STATUS_ERROR)
-    abort ();
+      if (status == OPENVPN_EXIT_STATUS_ERROR)
+       abort ();
 #endif
 
-  if (status == OPENVPN_EXIT_STATUS_GOOD)
-    perf_output_results ();
+      if (status == OPENVPN_EXIT_STATUS_GOOD)
+       perf_output_results ();
+    }
 
   exit (status);
 }
diff --git a/event.c b/event.c
index 6a9161b494e15cbb490ef086cad8693458eb7d1e..51b17b3d11cd318346a9552087c8f01caeaf2b29 100644 (file)
--- a/event.c
+++ b/event.c
@@ -522,10 +522,10 @@ ep_ctl (struct event_set *es, event_t event, unsigned int rwflags, void *arg)
       if (errno == ENOENT)
        {
          if (epoll_ctl (eps->epfd, EPOLL_CTL_ADD, event, &ev) < 0)
-           msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_ADD failed");
+           msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_ADD failed, sd=%d", (int)event);
        }
       else
-       msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_MOD failed");
+       msg (M_ERR, "EVENT: epoll_ctl EPOLL_CTL_MOD failed, sd=%d", (int)event);
     }
 }
 
diff --git a/init.c b/init.c
index 70357e191114383bc9afd9bc713cc4336a21237e..4214233e6c17146cb8b5a44499041636b351bd85 100644 (file)
--- a/init.c
+++ b/init.c
@@ -520,7 +520,9 @@ init_port_share (struct context *c)
   if (!port_share && (c->options.port_share_host && c->options.port_share_port))
     {
       port_share = port_share_open (c->options.port_share_host,
-                                   c->options.port_share_port);
+                                   c->options.port_share_port,
+                                   MAX_RW_SIZE_LINK (&c->c2.frame),
+                                   c->options.port_share_journal_dir);
       if (port_share == NULL)
        msg (M_FATAL, "Fatal error: Port sharing failed");
     }
index c5eb3caa93e4cb0ed336550c49c55103c330bc80..037ba7e1d43d4fe0db4b0fc3d331a02df88b90cc 100644 (file)
--- a/openvpn.8
+++ b/openvpn.8
@@ -3240,7 +3240,7 @@ disable the remapping feature.  Don't use this option unless you
 know what you are doing!
 .\"*********************************************************
 .TP
-.B --port-share host port
+.B --port-share host port [dir]
 When run in TCP server mode, share the OpenVPN port with
 another application, such as an HTTPS server.  If OpenVPN
 senses a connection to its port which is using a non-OpenVPN
@@ -3250,6 +3250,16 @@ Currently only designed to work with HTTP/HTTPS,
 though it would be theoretically possible to extend to
 other protocols such as ssh.
 
+.B dir
+specifies an optional directory where a temporary file with name N
+containing content C will be dynamically generated for each proxy
+connection, where N is the source IP:port of the client connection
+and C is the source IP:port of the connection to the proxy
+receiver.  This directory can be used as a dictionary by
+the proxy receiver to determine the origin of the connection.
+Each generated file will be automatically deleted when the proxied
+connection is torn down.
+
 Not implemented on Windows.
 .\"*********************************************************
 .SS Client Mode
index e8e0d7a7a5cb0b6eef0edfeabbdd18b50adc9ab7..8ace13fc07c4691ff0a3734eceb4fbcc033841fe 100644 (file)
--- a/options.c
+++ b/options.c
@@ -427,8 +427,9 @@ static const char usage_message[] =
   "--max-clients n : Allow a maximum of n simultaneously connected clients.\n"
   "--max-routes-per-client n : Allow a maximum of n internal routes per client.\n"
 #if PORT_SHARE
-  "--port-share host port : When run in TCP mode, proxy incoming HTTPS sessions\n"
-  "                  to a web server at host:port.\n"
+  "--port-share host port [dir] : When run in TCP mode, proxy incoming HTTPS\n"
+  "                  sessions to a web server at host:port.  dir specifies an\n"
+  "                  optional directory to write origin IP:port data.\n"
 #endif
 #endif
   "\n"
@@ -5101,6 +5102,7 @@ add_option (struct options *options,
 
       options->port_share_host = p[1];
       options->port_share_port = port;
+      options->port_share_journal_dir = p[3];
     }
 #endif
   else if (streq (p[0], "client-to-client"))
index fd9eb7c3e0f4bd09d3eed6746c2ae8bd08c8ea61..74ba9d42c2be7210cadc1082321ffb0ee3961625 100644 (file)
--- a/options.h
+++ b/options.h
@@ -430,6 +430,7 @@ struct options
 #if PORT_SHARE
   char *port_share_host;
   int port_share_port;
+  const char *port_share_journal_dir;
 #endif
 #endif
 
diff --git a/ps.c b/ps.c
index c77e7694797492ac793c3186dc19e9503fdd41a4..26cf4cb5f7bc69b3423172a55bbab5399c5df1e5 100644 (file)
--- a/ps.c
+++ b/ps.c
@@ -69,6 +69,7 @@ struct proxy_connection {
   bool buffer_initial;
   int rwflags;
   int sd;
+  char *jfn;
 };
 
 #if 0
@@ -226,7 +227,7 @@ port_share_sendmsg (const socket_descriptor_t sd,
 
       status = sendmsg (sd, &mesg, MSG_NOSIGNAL);
       if (status == -1)
-       msg (M_WARN, "PORT SHARE: sendmsg failed (unable to communicate with background process)");
+       msg (M_WARN|M_ERRNO_SOCK, "PORT SHARE: sendmsg failed (unable to communicate with background process)");
 
       close_socket_if_defined (sd_null[0]);
       close_socket_if_defined (sd_null[1]);
@@ -273,6 +274,12 @@ proxy_entry_mark_for_close (struct proxy_connection *pc, struct event_set *es)
       pc->buffer_initial = false;
       pc->rwflags = 0;
       pc->defined = false;
+      if (pc->jfn)
+       {
+         unlink (pc->jfn);
+         free (pc->jfn);
+         pc->jfn = NULL;
+       }
       if (cp && cp->defined && cp->counterpart == pc)
        proxy_entry_mark_for_close (cp, es);
     }
@@ -308,6 +315,48 @@ proxy_list_housekeeping (struct proxy_connection **list)
     }
 }
 
+/*
+ * Record IP/port of client in filesystem, so that server receiving
+ * the proxy can determine true client origin.
+ */
+static void
+journal_add (const char *journal_dir, struct proxy_connection *pc, struct proxy_connection *cp)
+{
+  struct gc_arena gc = gc_new ();
+  struct openvpn_sockaddr from, to;
+  socklen_t slen, dlen;
+  int fnlen;
+  char *jfn;
+  int fd;
+
+  slen = sizeof(from.sa);
+  dlen = sizeof(to.sa);
+  if (!getpeername (pc->sd, (struct sockaddr *) &from.sa, &slen)
+      && !getsockname (cp->sd, (struct sockaddr *) &to.sa, &dlen))
+    {
+      const char *f = print_sockaddr_ex (&from, ":", PS_SHOW_PORT, &gc);
+      const char *t = print_sockaddr_ex (&to, ":", PS_SHOW_PORT, &gc);
+      fnlen =  strlen(journal_dir) + strlen(t) + 2;
+      jfn = (char *) malloc(fnlen);
+      check_malloc_return (jfn);
+      openvpn_snprintf (jfn, fnlen, "%s/%s", journal_dir, t);
+      dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: client origin %s -> %s", jfn, f);
+      fd = open (jfn, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP);
+      if (fd != -1)
+       {
+         write(fd, f, strlen(f));
+         close (fd);
+         cp->jfn = jfn;
+       }
+      else
+       {
+         msg (M_WARN|M_ERRNO, "PORT SHARE: unable to write journal file in %s", jfn);
+         free (jfn);
+       }
+    }
+  gc_free (&gc);
+}
+
 /*
  * Cleanup function, on proxy process exit.
  */
@@ -361,7 +410,8 @@ proxy_entry_new (struct proxy_connection **list,
                 const in_addr_t server_addr,
                 const int server_port,
                 const socket_descriptor_t sd_client,
-                struct buffer *initial_data)
+                struct buffer *initial_data,
+                const char *journal_dir)
 {
   struct openvpn_sockaddr osaddr;
   socket_descriptor_t sd_server;
@@ -371,7 +421,11 @@ proxy_entry_new (struct proxy_connection **list,
 
   /* connect to port share server */
   sock_addr_set (&osaddr, server_addr, server_port);
-  sd_server = create_socket_tcp ();
+  if ((sd_server = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
+    {
+      msg (M_WARN|M_ERRNO_SOCK, "PORT SHARE PROXY: cannot create socket");
+      return false;
+    }
   status = openvpn_connect (sd_server, &osaddr, 5, NULL);
   if (status)
     {
@@ -408,6 +462,10 @@ proxy_entry_new (struct proxy_connection **list,
 
   /* add to list */
   *list = pc;
+
+  /* add journal entry */
+  if (journal_dir)
+    journal_add (journal_dir, pc, cp);
   
   dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: NEW CONNECTION [c=%d s=%d]", (int)sd_client, (int)sd_server);
 
@@ -429,9 +487,14 @@ control_message_from_parent (const socket_descriptor_t sd_control,
                             struct proxy_connection **list,
                             struct event_set *es,
                             const in_addr_t server_addr,
-                            const int server_port)
+                            const int server_port,
+                            const int max_initial_buf,
+                            const char *journal_dir)
 {
-  struct buffer buf = alloc_buf (PROXY_CONNECTION_BUFFER_SIZE);
+  /* this buffer needs to be large enough to handle the largest buffer
+     that might be returned by the link_socket_read call in read_incoming_link. */
+  struct buffer buf = alloc_buf (max_initial_buf);
+
   struct msghdr mesg;
   struct cmsghdr* h;
   struct iovec iov[2];
@@ -467,7 +530,7 @@ control_message_from_parent (const socket_descriptor_t sd_control,
          || h->cmsg_level  != SOL_SOCKET
          || h->cmsg_type   != SCM_RIGHTS )
        {
-         ret = false;
+         msg (M_WARN, "PORT SHARE PROXY: received unknown message");
        }
       else
        {
@@ -482,7 +545,8 @@ control_message_from_parent (const socket_descriptor_t sd_control,
                                   server_addr,
                                   server_port,
                                   received_fd,
-                                  &buf))
+                                  &buf,
+                                  journal_dir))
                {
                  CLEAR (buf); /* we gave the buffer to proxy_entry_new */
                }
@@ -517,6 +581,7 @@ proxy_connection_io_recv (struct proxy_connection *pc)
     {
       if (!status)
        return IOSTAT_READ_ERROR;
+      dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: read[%d] %d", (int)pc->sd, status);
       pc->buf.len = status;
     }
   return IOSTAT_GOOD;
@@ -544,7 +609,7 @@ proxy_connection_io_send (struct proxy_connection *pc, int *bytes_sent)
        }
       else
        {
-         /*dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: wrote[%d] %d", (int)sd, status);*/
+         dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: wrote[%d] %d", (int)sd, status);
          pc->buf.len = 0;
          pc->buf.offset = 0;
        }
@@ -627,6 +692,8 @@ proxy_connection_io_dispatch (struct proxy_connection *pc,
   int rwflags_pc = pc->rwflags;
   int rwflags_cp = cp->rwflags;
 
+  ASSERT(pc->defined && cp->defined && cp->counterpart == pc);
+
   if (rwflags & EVENT_READ)
     {
       const int status = proxy_connection_io_xfer (pc, max_transfer_per_iteration);
@@ -653,7 +720,11 @@ proxy_connection_io_dispatch (struct proxy_connection *pc,
  * This is the main function for the port share proxy background process.
  */
 static void
-port_share_proxy (const in_addr_t hostaddr, const int port, const socket_descriptor_t sd_control)
+port_share_proxy (const in_addr_t hostaddr,
+                 const int port,
+                 const socket_descriptor_t sd_control,
+                 const int max_initial_buf,
+                 const char *journal_dir)
 {
   if (send_control (sd_control, RESPONSE_INIT_SUCCEEDED) >= 0)
     {
@@ -687,7 +758,7 @@ port_share_proxy (const in_addr_t hostaddr, const int port, const socket_descrip
                  const struct event_set_return *e = &esr[i];
                  if (e->arg == sd_control_marker)
                    {
-                     if (!control_message_from_parent (sd_control, &list, es, hostaddr, port))
+                     if (!control_message_from_parent (sd_control, &list, es, hostaddr, port, max_initial_buf, journal_dir))
                        goto done;
                    }
                  else
@@ -713,7 +784,7 @@ port_share_proxy (const in_addr_t hostaddr, const int port, const socket_descrip
       proxy_list_close (&list);
       event_free (es);
     }
-  msg (D_PS_PROXY, "PORT SHARE PROXY: proxy exiting");
+  msg (M_INFO, "PORT SHARE PROXY: proxy exiting");
 }
 
 /*
@@ -721,7 +792,10 @@ port_share_proxy (const in_addr_t hostaddr, const int port, const socket_descrip
  * share proxy.
  */
 struct port_share *
-port_share_open (const char *host, const int port)
+port_share_open (const char *host,
+                const int port,
+                const int max_initial_buf,
+                const char *journal_dir)
 {
   pid_t pid;
   socket_descriptor_t fd[2];
@@ -766,6 +840,10 @@ port_share_open (const char *host, const int port)
       /* don't let future subprocesses inherit child socket */
       set_cloexec (fd[0]);
 
+      /* note that this will cause possible EAGAIN when writing to
+         control socket if proxy process is backlogged */
+      set_nonblock (fd[0]);
+
       /* wait for background child process to initialize */
       status = recv_control (fd[0]);
       if (status == RESPONSE_INIT_SUCCEEDED)
@@ -796,7 +874,7 @@ port_share_open (const char *host, const int port)
       prng_init (NULL, 0);
 
       /* execute the event loop */
-      port_share_proxy (hostaddr, port, fd[1]);
+      port_share_proxy (hostaddr, port, fd[1], max_initial_buf, journal_dir);
 
       openvpn_close_socket (fd[1]);
 
diff --git a/ps.h b/ps.h
index d488a72fc0fedcda708b650573686ec655e2b6b4..4280635d2f31677d534c925beb3abde848404d06 100644 (file)
--- a/ps.h
+++ b/ps.h
@@ -44,7 +44,9 @@ struct port_share {
 extern struct port_share *port_share;
 
 struct port_share *port_share_open (const char *host,
-                                   const int port);
+                                   const int port,
+                                   const int max_initial_buf,
+                                   const char *journal_dir);
 
 void port_share_close (struct port_share *ps);
 void port_share_abort (struct port_share *ps);