/** * OpenVPN Proxy * ------------- * Convert TCP-Connections for OpenVPN into UDP-connections * * This work is distributed within the terms of * creative commons attribution-share alike 3.0 germany * * See http://creativecommons.org/licenses/by-sa/3.0/ for more information * * @author Bernd Holzmueller * @revision 01 * @license http://creativecommons.org/licenses/by-sa/3.0/de/ Creative Commons Attribution-Share Alike 3.0 Germany * @homepage http://oss.tiggerswelt.net/openvpn_proxy * @copyright Copyright © 2008 tiggersWelt.net */ #include #include #include #include #include #include #include #include #include #include #define READ_BUFFER 4096 struct proxy_con { int client; int server; uint16_t length; uint16_t pos; char *buffer; struct event ev_client; struct event ev_server; }; struct sockaddr_in openvpn_addr; void client_remove (struct proxy_con *con, char *reason) { event_del (&con->ev_client); event_del (&con->ev_server); close (con->client); close (con->server); free (con->buffer); free (con); } void client_read (int fd, short event, void *arg) { struct proxy_con *con = arg; int len = 0, remain = 0; /* Reschedule ourself */ event_add (&con->ev_client, NULL); /* Retrive length of packet (if new one) */ if (con->length < 1) { if (read (fd, &con->length, sizeof (con->length)) <= 0) return client_remove (con, "client-connection was closed"); con->length = ntohs (con->length); /* Check if memory was left allocated */ if (con->buffer != 0) free (con->buffer); /* Allocate new buffer-space */ if ((con->buffer = malloc (sizeof (char *) * con->length)) == 0) return client_remove (con, "out of memory"); con->pos = 0; } /* Calculate remaining packet-size */ remain = con->length - con->pos; /* Get remaining data from socket */ if (remain > 0) { char buffer [remain]; if ((len = read (fd, &buffer, remain)) <= 0) return client_remove (con, "client-connection was closed"); /* Append new data to buffer */ memcpy (con->buffer + con->pos, &buffer, len); remain -= len; con->pos += len; } /* Check if buffer was filled completely */ if (remain <= 0) { /* Forward the data to our OpenVPN-Server */ write (con->server, con->buffer, con->length); /* Reset the buffer */ free (con->buffer); con->pos = 0; con->length = 0; con->buffer = 0; } } void server_read (int fd, short event, void *arg) { struct proxy_con *con = arg; char buffer [READ_BUFFER]; int len = 0; uint16_t size = 0; /* Reschedule ourself */ event_add (&con->ev_server, NULL); /* Read incomming data */ if ((len = read (fd, &buffer, READ_BUFFER)) <= 0) return client_remove (con, "server-connection was closed"); /* Create a forward-buffer */ char *forward; if ((forward = malloc (len + sizeof (size))) == 0) return client_remove (con, "out of memory"); /* fill the buffer with data */ size = htons (len); memcpy (forward, &size, sizeof (size)); memcpy (forward + sizeof (size), &buffer, len); /* Forward the data to the client */ write (con->client, forward, len + sizeof (size)); free (forward); } void new_connection (int fd, short event, void *arg) { struct sockaddr_in client_addr; struct proxy_con *con; int len = 0; /* Allocate memory for new structure */ con = malloc (sizeof (struct proxy_con)); bzero (con, sizeof (struct proxy_con)); /* Reschedule ourself */ event_add (arg, NULL); /* Accept incoming connection */ if ((con->client = accept (fd, (struct sockaddr *)&client_addr, &len)) <= 0) { free (con); return; } /* Create the SOCKS-Client */ if (((con->server = socket (AF_INET, SOCK_DGRAM, 0)) < 0) || (connect (con->server, (struct sockaddr *)&openvpn_addr, sizeof (openvpn_addr)) != 0)) { close (con->client); free (con); return; } /* Setup events for this new connection */ event_set (&con->ev_client, con->client, EV_READ, client_read, con); event_set (&con->ev_server, con->server, EV_READ, server_read, con); event_add (&con->ev_client, NULL); event_add (&con->ev_server, NULL); /* Setup structure */ con->length = 0; con->pos = 0; con->buffer = 0; } int main (int argc, char **argv) { struct sockaddr_in addr; struct event ev_server; int addrlen = sizeof (addr); int serverfd = 0; int on = 1; int foreground = 0; short bindport = 1194; char *bindhost = "0.0.0.0"; short ovpnport = 1194; char *ovpnhost = "217.11.57.9"; char c; /* Parse the commandline */ while ((c = getopt (argc, argv, "fp:H:s:S:h")) != EOF) switch (c) { case 'f': /* Keep in foreground */ foreground = 1; break; case 'p': /* Try to bind to this port */ if (!(bindport = atoi (optarg))) { fprintf (stderr, "Invalid port %s\n", optarg); return 1; } break; case 'H': /* Try to bind to this IP */ bindhost = optarg; break; case 's': /* Use this port on the OpenVPN-Server */ if (!(ovpnport = atoi (optarg))) { fprintf (stderr, "Invalid port %s\n", optarg); return 1; } break; case 'S': /* Use this IP for the OpenVPN-Server */ ovpnhost = optarg; break; case 'h': /* Print help */ printf ("openvpn_proxy - libevent-based OpenVPN-Connection TCP-to-UDP translator\n"); printf ("Usage: %s [-f] [-p Port] [-H IP-Address] [-s port] [-S IP-Address]\n\n", argv [0]); printf ("\t-f\tDo not fork into background upon execution\n"); printf ("\t-p\tBind our server-socket to this port\n"); printf ("\t-H\tListen on this IP-Address for incomming connections\n"); printf ("\t-s\tExpect OpenVPN-Server on this Port\n"); printf ("\t-S\tExpect OpenVPN-Server on this IP-Address\n"); printf ("\n"); return 0; } /* Handle the forking stuff */ if (foreground != 1) { /* Try to fork into background */ if ((foreground = fork ()) < 0) { perror("fork"); return 1; } /* Fork was successfull and we are the parent */ if (foreground) return 0; /* Close our filehandles */ fclose (stdin); fclose (stdout); fclose (stderr); setsid (); setpgrp (); signal (SIGCHLD, SIG_IGN); } /* Prepare address of SOCKS5-Server */ bzero (&openvpn_addr, sizeof (openvpn_addr)); openvpn_addr.sin_family = AF_INET; openvpn_addr.sin_port = htons (ovpnport); if (inet_pton (AF_INET, ovpnhost, &openvpn_addr.sin_addr.s_addr) <= 0) { perror ("Could not parse OpenVPN-Host"); return 1; } /* Create our server socket */ if ((serverfd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { perror ("Could not create socket"); return 1; } bzero (&addr, sizeof (addr)); addr.sin_family = AF_INET; addr.sin_port = htons (bindport); if (inet_pton (AF_INET, bindhost, &addr.sin_addr.s_addr) <= 0) { perror ("Could not parse Host"); return 1; } setsockopt (serverfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof (on)); if (bind (serverfd, (struct sockaddr *)&addr, sizeof (addr)) < 0) { perror ("Could not bind our socket"); return 1; } if (listen (serverfd, SOMAXCONN) < 0) { perror ("listen failed"); return 1; } /* Setup Event-Handing */ event_init (); event_set (&ev_server, serverfd, EV_READ, new_connection, &ev_server); event_add (&ev_server, NULL); event_dispatch (); return 0; }