Пример #1
0
void
port_share_close(struct port_share *ps)
{
    if (ps)
    {
        if (ps->foreground_fd >= 0)
        {
            /* tell background process to exit */
            port_share_sendmsg(ps->foreground_fd, COMMAND_EXIT, NULL, SOCKET_UNDEFINED);

            /* wait for background process to exit */
            dmsg(D_PS_PROXY_DEBUG, "PORT SHARE: waiting for background process to exit");
            if (ps->background_pid > 0)
            {
                waitpid(ps->background_pid, NULL, 0);
            }
            dmsg(D_PS_PROXY_DEBUG, "PORT SHARE: background process exited");

            openvpn_close_socket(ps->foreground_fd);
            ps->foreground_fd = -1;
        }

        free(ps);
    }
}
Пример #2
0
static inline void
close_socket_if_defined(const socket_descriptor_t sd)
{
    if (socket_defined(sd))
    {
        openvpn_close_socket(sd);
    }
}
Пример #3
0
/*
 * Close most of parent's fds.
 * Keep stdin/stdout/stderr, plus one
 * other fd which is presumed to be
 * our pipe back to parent.
 * Admittedly, a bit of a kludge,
 * but posix doesn't give us a kind
 * of FD_CLOEXEC which will stop
 * fds from crossing a fork().
 */
static void
close_fds_except (int keep)
{
  socket_descriptor_t i;
  closelog ();
  for (i = 3; i <= 100; ++i)
    {
      if (i != keep)
	openvpn_close_socket (i);
    }
}
Пример #4
0
static void
proxy_entry_close_sd (struct proxy_connection *pc, struct event_set *es)
{
  if (pc->defined && socket_defined (pc->sd))
    {
      dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: delete sd=%d", (int)pc->sd);
      if (es)
	event_del (es, pc->sd);
      openvpn_close_socket (pc->sd);
      pc->sd = SOCKET_UNDEFINED;
    }
}
Пример #5
0
void
port_share_abort (struct port_share *ps)
{
  if (ps)
    {
      /* tell background process to exit */
      if (ps->foreground_fd >= 0)
	{
	  send_control (ps->foreground_fd, COMMAND_EXIT);
	  openvpn_close_socket (ps->foreground_fd);
	  ps->foreground_fd = -1;
	}
    }
}
Пример #6
0
/*
 * Called from the main OpenVPN process to enable the port
 * share proxy.
 */
struct port_share *
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];
  in_addr_t hostaddr;
  struct port_share *ps;

  ALLOC_OBJ_CLEAR (ps, struct port_share);
  ps->foreground_fd = -1;
  ps->background_pid = -1;

  /*
   * Get host's IP address
   */
  hostaddr = getaddr (GETADDR_RESOLVE|GETADDR_HOST_ORDER|GETADDR_FATAL, host, 0, NULL, NULL);

  /*
   * Make a socket for foreground and background processes
   * to communicate.
   */
  if (socketpair (PF_UNIX, SOCK_DGRAM, 0, fd) == -1)
    {
      msg (M_WARN, "PORT SHARE: socketpair call failed");
      goto error;
    }

  /*
   * Fork off background proxy process.
   */
  pid = fork ();

  if (pid)
    {
      int status;

      /*
       * Foreground Process
       */

      ps->background_pid = pid;

      /* close our copy of child's socket */
      openvpn_close_socket (fd[1]);

      /* don't let future subprocesses inherit child socket */
      set_cloexec (fd[0]);

      /* wait for background child process to initialize */
      status = recv_control (fd[0]);
      if (status == RESPONSE_INIT_SUCCEEDED)
	{
	  /* note that this will cause possible EAGAIN when writing to
	     control socket if proxy process is backlogged */
	  set_nonblock (fd[0]);

	  ps->foreground_fd = fd[0];
	  return ps;
	}
      else
	{
	  msg (M_ERR, "PORT SHARE: unexpected init recv_control status=%d", status);
	}
    }
  else
    {
      /*
       * Background Process
       */

      /* Ignore most signals (the parent will receive them) */
      set_signals ();

      /* Let msg know that we forked */
      msg_forked ();

#ifdef ENABLE_MANAGEMENT
      /* Don't interact with management interface */
      management = NULL;
#endif

      /* close all parent fds except our socket back to parent */
      close_fds_except (fd[1]);

      /* no blocking on control channel back to parent */
      set_nonblock (fd[1]);

      /* initialize prng */
      prng_init (NULL, 0);

      /* execute the event loop */
      port_share_proxy (hostaddr, port, fd[1], max_initial_buf, journal_dir);

      openvpn_close_socket (fd[1]);

      exit (0);
      return 0; /* NOTREACHED */
    }

 error:
  port_share_close (ps);
  return NULL;
}
Пример #7
0
/*
 * This function runs in the context of the background proxy process.
 * Receive a control message from the parent (sent by the port_share_sendmsg
 * function above) and act on it.  Return false if the proxy process should
 * exit, true otherwise.
 */
static bool
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 max_initial_buf,
			     const char *journal_dir)
{
  /* 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];
  char command = 0;
  ssize_t status;
  int ret = true;

  CLEAR (mesg);

  iov[0].iov_base = &command;
  iov[0].iov_len = sizeof (command);
  iov[1].iov_base = BPTR (&buf);
  iov[1].iov_len = BCAP (&buf);
  mesg.msg_iov = iov;
  mesg.msg_iovlen = 2;

  mesg.msg_controllen = cmsg_size ();
  mesg.msg_control = (char *) malloc (mesg.msg_controllen);
  check_malloc_return (mesg.msg_control);
  mesg.msg_flags = 0;

  h = CMSG_FIRSTHDR(&mesg);
  h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t));
  h->cmsg_level = SOL_SOCKET;
  h->cmsg_type = SCM_RIGHTS;
  *((socket_descriptor_t*)CMSG_DATA(h)) = SOCKET_UNDEFINED;

  status = recvmsg (sd_control, &mesg, MSG_NOSIGNAL);
  if (status != -1)
    {
      if (   h == NULL
	  || h->cmsg_len    != CMSG_LEN(sizeof(socket_descriptor_t))
	  || h->cmsg_level  != SOL_SOCKET
	  || h->cmsg_type   != SCM_RIGHTS )
	{
	  msg (M_WARN, "PORT SHARE PROXY: received unknown message");
	}
      else
	{
	  const socket_descriptor_t received_fd = *((socket_descriptor_t*)CMSG_DATA(h));
	  dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED sd=%d", (int)received_fd);

	  if (status >= 2 && command == COMMAND_REDIRECT)
	    {
	      buf.len = status - 1;
	      if (proxy_entry_new (list,
				   es,
				   server_addr,
				   server_port,
				   received_fd,
				   &buf,
				   journal_dir))
		{
		  CLEAR (buf); /* we gave the buffer to proxy_entry_new */
		}
	      else
		{
		  openvpn_close_socket (received_fd);
		}
	    }
	  else if (status >= 1 && command == COMMAND_EXIT)
	    {
	      dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED COMMAND_EXIT");
	      openvpn_close_socket (received_fd); /* null socket */
	      ret = false;
	    }
	}
    }
  free (mesg.msg_control);
  free_buf (&buf);
  return ret;
}
Пример #8
0
/*
 * Create a new pair of proxy_connection entries, one for each
 * socket file descriptor involved in the proxy.  We are given
 * the client fd, and we should derive our own server fd by connecting
 * to the server given by server_addr/server_port.  Return true
 * on success and false on failure to connect to server.
 */
static bool
proxy_entry_new (struct proxy_connection **list,
		 struct event_set *es,
		 const in_addr_t server_addr,
		 const int server_port,
		 const socket_descriptor_t sd_client,
		 struct buffer *initial_data,
		 const char *journal_dir)
{
  struct openvpn_sockaddr osaddr;
  socket_descriptor_t sd_server;
  int status;
  struct proxy_connection *pc;
  struct proxy_connection *cp;

  /* connect to port share server */
  sock_addr_set (&osaddr, server_addr, server_port);
  if ((sd_server = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    {
      msg (M_WARN|M_ERRNO, "PORT SHARE PROXY: cannot create socket");
      return false;
    }
  status = openvpn_connect (sd_server, &osaddr, 5, NULL);
  if (status)
    {
      msg (M_WARN, "PORT SHARE PROXY: connect to port-share server failed");
      openvpn_close_socket (sd_server);
      return false;
    }
  dmsg (D_PS_PROXY_DEBUG, "PORT SHARE PROXY: connect to port-share server succeeded");

  set_nonblock (sd_client);
  set_nonblock (sd_server);

  /* allocate 2 new proxy_connection objects */
  ALLOC_OBJ_CLEAR (pc, struct proxy_connection);
  ALLOC_OBJ_CLEAR (cp, struct proxy_connection);

  /* client object */
  pc->defined = true;
  pc->next = cp;
  pc->counterpart = cp;
  pc->buf = *initial_data;
  pc->buffer_initial = true;
  pc->rwflags = EVENT_UNDEF;
  pc->sd = sd_client;

  /* server object */
  cp->defined = true;
  cp->next = *list;
  cp->counterpart = pc;
  cp->buf = alloc_buf (PROXY_CONNECTION_BUFFER_SIZE);
  cp->buffer_initial = false;
  cp->rwflags = EVENT_UNDEF;
  cp->sd = sd_server;

  /* 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);

  /* set initial i/o states */
  proxy_connection_io_requeue (pc, EVENT_READ, es);
  proxy_connection_io_requeue (cp, EVENT_READ|EVENT_WRITE, es);
  
  return true;
}