Added optional journal directory argument to "port-share" directive, for reporting client IP origins of proxied connections.

git-svn-id: http://svn.openvpn.net/projects/branches/BETA21@7031 e7ae566f-a301-0410-adde-c780ea21d3b5
This commit is contained in:
James Yonan 2011-03-13 06:59:25 +00:00 committed by David Sommerseth
parent 6c34e74f13
commit 1c5ff7722d
8 changed files with 131 additions and 33 deletions

29
error.c
View File

@ -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);
}

View File

@ -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);
}
}

4
init.c
View File

@ -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");
}

View File

@ -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

View File

@ -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"))

View File

@ -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

104
ps.c
View File

@ -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]);

4
ps.h
View File

@ -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);