changeset 121:8c39e8e90dbd

More work on proxy handling.
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 22 Jun 2014 02:12:17 +0300
parents 41c2638ee537
children 452adc41ccf5
files th_network.c th_network.h
diffstat 2 files changed, 152 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/th_network.c	Sun Jun 22 01:25:35 2014 +0300
+++ b/th_network.c	Sun Jun 22 02:12:17 2014 +0300
@@ -16,11 +16,18 @@
 
 enum
 {
-    TH_SOCKS5_AUTH_NONE = 0,
-    TH_SOCKS5_AUTH_USER = 2,
+    SOCKS5_AUTH_NONE = 0,
+    SOCKS5_AUTH_USER = 2,
 };
 
 
+enum
+{
+    SOCKS5_ADDR_IPV4 = 0x01,
+    SOCKS5_ADDR_DOMAIN = 0x03,
+    SOCKS5_ADDR_IPV6 = 0x04,
+};
+
 static const char *th_proxy_types[] =
 {
     "none",
@@ -31,6 +38,23 @@
 };
 
 
+static const char *th_socks5_results_msgs[] =
+{
+    "Succeeded",
+    "General SOCKS server failure",
+    "Connection not allowed by ruleset",
+    "Network unreachable",
+    "Host unreachable",
+    "Connection refused",
+    "TTL expired",
+    "Command not supported",
+    "Address type not supported",
+};
+
+static const int th_socks5_results_msgs_num = sizeof(th_socks5_results_msgs) / sizeof(th_socks5_results_msgs[0]);
+
+
+
 static int th_get_socket_errno(void)
 {
     return errno;
@@ -152,6 +176,28 @@
 }
 
 
+int th_conn_set_proxy_mode(th_conn_t *conn, const int mode)
+{
+    if (conn == NULL)
+        return THERR_NULLPTR;
+
+    conn->proxy.mode = mode;
+
+    return THERR_OK;
+}
+
+
+int th_conn_set_proxy_addr_type(th_conn_t *conn, const int atype)
+{
+    if (conn == NULL)
+        return THERR_NULLPTR;
+
+    conn->proxy.addr_type = atype;
+
+    return THERR_OK;
+}
+
+
 int th_conn_set_proxy_auth_user(th_conn_t *conn, const char *userid, const char *passwd)
 {
     if (conn == NULL)
@@ -213,23 +259,54 @@
 {
     th_growbuf_t buf;
     uint8_t *ptr;
-    int err = THERR_INIT_FAIL;
+    int cmd, err = THERR_INIT_FAIL;
 
     (void) host;
     th_growbuf_init(&buf, 128);
     th_conn_msg(conn, THLOG_INFO, "Initializing SOCKS 4/a proxy negotiation.\n");
 
+    switch (conn->proxy.mode)
+    {
+        case TH_PROXY_CMD_CONNECT: cmd = 1; break;
+        case TH_PROXY_CMD_BIND: cmd = 2; break;
+        default:
+            err = THERR_NOT_SUPPORTED;
+            th_conn_err(conn, err, "Invalid SOCKS 4 command/mode, unsupported.\n");
+            goto out;
+    }
+
     // Create SOCKS 4 handshake
     th_growbuf_put_u8(&buf, 4);  // Protocol version
-    th_growbuf_put_u8(&buf, TH_PROXY_CMD_CONNECT); // Command
+    th_growbuf_put_u8(&buf, cmd); // Command
     th_growbuf_put_u16_be(&buf, port);
-    if (conn->proxy.type == TH_PROXY_SOCKS4A)
-        th_growbuf_put_u32_be(&buf, 0x00000032);
-    else
-        th_growbuf_put_str(&buf, (uint8_t *) &(conn->addr.s_addr), sizeof(conn->addr.s_addr));
+    
+    switch (conn->proxy.addr_type)
+    {
+        case TH_PROXY_ADDR_IPV4:
+            th_growbuf_put_str(&buf, (uint8_t *) &(conn->addr.s_addr), sizeof(conn->addr.s_addr));
+            break;
+        
+        case TH_PROXY_ADDR_DOMAIN:
+            if (conn->proxy.type == TH_PROXY_SOCKS4A)
+                th_growbuf_put_u32_be(&buf, 0x00000032);
+            else
+            {
+                err = THERR_INIT_FAIL;
+                th_conn_err(conn, err,
+                    "Invalid proxy settings, SOCKS 4 in use, but domain address type requested. SOCKS 4a or 5 required for host atype.\n");
+                goto out;
+            }
+            break;
+        
+        default:
+            err = THERR_INIT_FAIL;
+            th_conn_err(conn, err,
+                "Invalid proxy settings for SOCKS 4, unsupported address type requrested.\n");
+            goto out;
+    }
 
     th_growbuf_puts(&buf, conn->proxy.userid, TRUE);
-    if (conn->proxy.type == TH_PROXY_SOCKS4A)
+    if (conn->proxy.addr_type == TH_PROXY_ADDR_DOMAIN)
         th_growbuf_puts(&buf, conn->host, TRUE);
 
     // Send request
@@ -277,24 +354,34 @@
 
 static int th_conn_socks5_negotiate(th_conn_t *conn, const int port, const char *host)
 {
-    size_t userid_len = 0, passwd_len = 0;
     th_growbuf_t buf;
     uint8_t *ptr;
-    int avail, auth, err = THERR_INIT_FAIL;
+    int cmd, avail, auth, err = THERR_INIT_FAIL;
 
     th_growbuf_init(&buf, 256);
     th_conn_msg(conn, THLOG_INFO, "Initializing SOCKS 5 proxy negotiation.\n");
 
+    switch (conn->proxy.mode)
+    {
+        case TH_PROXY_CMD_CONNECT: cmd = 1; break;
+        case TH_PROXY_CMD_BIND: cmd = 2; break;
+        case TH_PROXY_CMD_ASSOC_UDP: cmd = 3; break;
+        default:
+            err = THERR_NOT_SUPPORTED;
+            th_conn_err(conn, err, "Invalid SOCKS 5 command/mode, unsupported.\n");
+            goto out;
+    }
+
     switch (conn->proxy.auth_type)
     {
         case TH_PROXY_AUTH_NONE:
             avail = 1;
-            auth = TH_SOCKS5_AUTH_NONE;
+            auth = SOCKS5_AUTH_NONE;
             break;
 
         case TH_PROXY_AUTH_USER:
             avail = 2;
-            auth = TH_SOCKS5_AUTH_USER;
+            auth = SOCKS5_AUTH_USER;
             if (conn->proxy.userid == NULL || conn->proxy.passwd == NULL)
             {
                 err = THERR_INVALID_DATA;
@@ -303,9 +390,8 @@
                 goto out;
             }
 
-            userid_len = strlen(conn->proxy.userid);
-            passwd_len = strlen(conn->proxy.passwd);
-            if (userid_len > 255 || passwd_len > 255)
+            if (strlen(conn->proxy.userid) > 255 ||
+                strlen(conn->proxy.passwd) > 255)
             {
                 err = THERR_INVALID_DATA;
                 th_conn_err(conn, err,
@@ -356,15 +442,15 @@
         goto out;
     }
     else
-    if (auth == TH_SOCKS5_AUTH_USER)
+    if (auth == SOCKS5_AUTH_USER)
     {
         // Attempt user/pass authentication (RFC 1929)
         th_growbuf_clear(&buf);
         
         th_growbuf_put_u8(&buf, 0x01);
-        th_growbuf_put_u8(&buf, userid_len);
+        th_growbuf_put_u8(&buf, strlen(conn->proxy.userid));
         th_growbuf_puts(&buf, conn->proxy.userid, FALSE);
-        th_growbuf_put_u8(&buf, passwd_len);
+        th_growbuf_put_u8(&buf, strlen(conn->proxy.passwd));
         th_growbuf_puts(&buf, conn->proxy.passwd, FALSE);
 
         // Send request
@@ -393,25 +479,50 @@
         }
     }
     else
-    if (auth != TH_SOCKS5_AUTH_NONE)
+    if (auth != SOCKS5_AUTH_NONE)
     {
         err = THERR_NOT_SUPPORTED;
-        th_conn_err(conn, THERR_NOT_SUPPORTED,
+        th_conn_err(conn, err,
             "Proxy server chose an unsupported SOCKS 5 authentication method %d.\n",
             auth);
         goto out;
     }
 
-
-#if 0
+#if 1
     // Form client connection request packet
     th_growbuf_clear(&buf);
+    th_growbuf_put_u8(&buf, 0x05); // Protocol version
+    th_growbuf_put_u8(&buf, cmd); // Command
+    th_growbuf_put_u8(&buf, 0x00); // Reserved
 
-    th_growbuf_put_u8(&buf, 0x05); // Protocol version
-    th_growbuf_put_u8(&buf, cmd);
-    th_growbuf_put_u8(&buf, 0x00);
-    th_growbuf_put_u8(&buf, SOCKS5_ADDR_IPV4);
-    th_growbuf_put_str(&buf, conn->addr.s_addr, sizeof(conn->addr.s_addr));
+    switch (conn->proxy.addr_type)
+    {
+        case TH_PROXY_ADDR_IPV4:
+            th_growbuf_put_u8(&buf, SOCKS5_ADDR_IPV4);
+            th_growbuf_put_str(&buf, (uint8_t *) &(conn->addr.s_addr), sizeof(conn->addr.s_addr));
+            break;
+
+        case TH_PROXY_ADDR_IPV6:
+            th_growbuf_put_u8(&buf, SOCKS5_ADDR_IPV6);
+            //th_growbuf_put_str(&buf, (uint8_t *) &(conn->addr.s_addr), sizeof(conn->addr.s_addr));
+            break;
+        
+        case TH_PROXY_ADDR_DOMAIN:
+            cmd = strlen(conn->host);
+            if (cmd < 1 || cmd > 255)
+            {
+                err = THERR_NOT_SUPPORTED;
+                th_conn_err(conn, err,
+                    "Domain address type requested, but domain name longer than 255 characters (%d).\n", cmd);
+                goto out;
+            }
+
+            th_growbuf_put_u8(&buf, SOCKS5_ADDR_DOMAIN);
+            th_growbuf_put_u8(&buf, cmd);
+            th_growbuf_put_str(&buf, conn->host, cmd);
+            break;
+    }
+
     th_growbuf_put_u16_be(&buf, port);
 
     // Send request
@@ -434,10 +545,10 @@
     if (*ptr != 0)
     {
         err = THERR_INIT_FAIL;
-        if (*ptr >= 0 && *ptr < sizeof())
-            th_conn_err(conn, err, "%s.\n", th_socks5_results_msgs[*ptr]);
+        if (*ptr < th_socks5_results_msgs_num)
+            th_conn_err(conn, err, "SOCKS 5 error: %s.\n", th_socks5_results_msgs[*ptr]);
         else
-            th_conn_err(conn, err ".Unknown\n");
+            th_conn_err(conn, err, "Unknown SOCKS 5 result code 0x02x.\n", *ptr);
         goto out;
     }
     ptr++;
--- a/th_network.h	Sun Jun 22 01:25:35 2014 +0300
+++ b/th_network.h	Sun Jun 22 02:12:17 2014 +0300
@@ -66,6 +66,13 @@
 
 enum
 {
+    TH_PROXY_ADDR_IPV4 = 0,
+    TH_PROXY_ADDR_DOMAIN,
+    TH_PROXY_ADDR_IPV6,
+};
+
+enum
+{
     TH_PROXY_AUTH_NONE,
     TH_PROXY_AUTH_USER,
 };
@@ -89,6 +96,7 @@
         int port;
         struct in_addr addr;
         char *userid, *passwd;
+        int mode, addr_type;
     } proxy;
 
     // Target host data
@@ -129,6 +137,8 @@
 void        th_conn_msg(th_conn_t *conn, int loglevel, const char *fmt, ...);
 
 int         th_conn_set_proxy(th_conn_t *conn, int type, int port, const char *host, int auth_type);
+int         th_conn_set_proxy_mode(th_conn_t *conn, const int mode);
+int         th_conn_set_proxy_addr_type(th_conn_t *conn, const int atype);
 int         th_conn_set_proxy_auth_user(th_conn_t *conn, const char *userid, const char *passwd);
 int         th_conn_open(th_conn_t *conn, const int port, const char *host);
 int         th_conn_close(th_conn_t *);