Add support for proxying through an external command.
authorGuus Sliepen <guus@tinc-vpn.org>
Thu, 19 Apr 2012 13:18:31 +0000 (15:18 +0200)
committerGuus Sliepen <guus@tinc-vpn.org>
Thu, 19 Apr 2012 13:18:31 +0000 (15:18 +0200)
Proxy type "exec" can be used to have an external script or binary set
up an outgoing connection. Standard input and output will be used to
exchange data with the external command. The variables REMOTEADDRESS and
REMOTEPORT are set to the intended destination address and port.

src/net_socket.c
src/netutl.c
src/protocol_auth.c

index 544cd6e204f0bbeb0165ced1427448e5b8bf2b1b..457392ef21df53bd479f9e20c0d9f683b4663c10 100644 (file)
@@ -294,13 +294,62 @@ void retry_outgoing(outgoing_t *outgoing) {
 void finish_connecting(connection_t *c) {
        ifdebug(CONNECTIONS) logger(LOG_INFO, "Connected to %s (%s)", c->name, c->hostname);
 
-       configure_tcp(c);
+       if(proxytype != PROXY_EXEC)
+               configure_tcp(c);
 
        c->last_ping_time = now;
 
        send_id(c);
 }
 
+static void do_outgoing_pipe(connection_t *c, char *command) {
+#ifndef HAVE_MINGW
+       int fd[2];
+
+       if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd)) {
+               logger(LOG_ERR, "Could not create socketpair: %s\n", strerror(errno));
+               return;
+       }
+
+       if(fork()) {
+               c->socket = fd[0];
+               close(fd[1]);
+               logger(LOG_DEBUG, "Using proxy %s", command);
+               return;
+       }
+
+       close(0);
+       close(1);
+       close(fd[0]);
+       dup2(fd[1], 0);
+       dup2(fd[1], 1);
+       close(fd[1]);
+
+       // Other filedescriptors should be closed automatically by CLOEXEC
+
+       char *host = NULL;
+       char *port = NULL;
+
+       sockaddr2str(&c->address, &host, &port);
+       setenv("REMOTEADDRESS", host, true);
+       setenv("REMOTEPORT", port, true);
+       setenv("NODE", c->name, true);
+       setenv("NAME", myself->name, true);
+       if(netname)
+               setenv("NETNAME", netname, true);
+
+       int result = system(command);
+       if(result < 0)
+               logger(LOG_ERR, "Could not execute %s: %s\n", command, strerror(errno));
+       else if(result)
+               logger(LOG_ERR, "%s exited with non-zero status %d", command, result);
+       exit(result);
+#else
+       logger(LOG_ERR, "Proxy type exec not supported on this platform!");
+       return false;
+#endif
+}
+
 void do_outgoing_connection(connection_t *c) {
        char *address, *port, *space;
        struct addrinfo *proxyai;
@@ -361,7 +410,10 @@ begin:
 
        if(!proxytype) {
                c->socket = socket(c->address.sa.sa_family, SOCK_STREAM, IPPROTO_TCP);
-       } else {
+               configure_tcp(c);
+       } if(proxytype == PROXY_EXEC) {
+               do_outgoing_pipe(c, proxyhost);
+       }  else {
                proxyai = str2addrinfo(proxyhost, proxyport, SOCK_STREAM);
                if(!proxyai)
                        goto begin;
@@ -378,22 +430,22 @@ begin:
        fcntl(c->socket, F_SETFD, FD_CLOEXEC);
 #endif
 
+       if(proxytype != PROXY_EXEC) {
 #if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
-       int option = 1;
-       if(c->address.sa.sa_family == AF_INET6)
-               setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
+               int option = 1;
+               if(c->address.sa.sa_family == AF_INET6)
+                       setsockopt(c->socket, SOL_IPV6, IPV6_V6ONLY, (void *)&option, sizeof option);
 #endif
 
-       bind_to_interface(c->socket);
-
-       /* Optimize TCP settings */
-
-//     configure_tcp(c);
+               bind_to_interface(c->socket);
+       }
 
        /* Connect */
 
        if(!proxytype) {
                result = connect(c->socket, &c->address.sa, SALEN(c->address.sa));
+       } else if(proxytype == PROXY_EXEC) {
+               result = 0;
        } else {
                result = connect(c->socket, proxyai->ai_addr, proxyai->ai_addrlen);
                freeaddrinfo(proxyai);
index 11a06ed4847c44b69db822be634ab1a6297e751c..c57b24ff1e2dd86a554b24e63187b3885ca0a164 100644 (file)
@@ -83,8 +83,10 @@ void sockaddr2str(const sockaddr_t *sa, char **addrstr, char **portstr) {
        int err;
 
        if(sa->sa.sa_family == AF_UNKNOWN) {
-               *addrstr = xstrdup(sa->unknown.address);
-               *portstr = xstrdup(sa->unknown.port);
+               if(addrstr)
+                       *addrstr = xstrdup(sa->unknown.address);
+               if(portstr)
+                       *portstr = xstrdup(sa->unknown.port);
                return;
        }
 
index 81189332495ccd7b1a0618ada156a5358d31ca74..4c721a44982f3b52ef75a016f56563202d779eab 100644 (file)
@@ -117,6 +117,8 @@ static bool send_proxyrequest(connection_t *c) {
                case PROXY_SOCKS4A:
                        logger(LOG_ERR, "Proxy type not implemented yet");
                        return false;
+               case PROXY_EXEC:
+                       return true;
                default:
                        logger(LOG_ERR, "Unknown proxy type");
                        return false;