client: added socks5 proxy support
authorAndy Ning <andy.ning@windriver.com>
Fri, 5 May 2017 15:38:34 +0000 (11:38 -0400)
committerAndy Green <andy@warmcat.com>
Tue, 16 May 2017 22:18:45 +0000 (06:18 +0800)
AG:

 - move creation info members to end of struct
 - add LWS_WITH_SOCKS5 CMake var, defaults to OFF
 - cast away some warnings about signed / unsigned in strncpy

Signed-off-by: Andy Ning <andy.ning@windriver.com>
CMakeLists.txt
lib/client-handshake.c
lib/client.c
lib/context.c
lib/libwebsockets.c
lib/libwebsockets.h
lib/private-libwebsockets.h
lws_config.h.in

index 4f1fd54..c0606f0 100644 (file)
@@ -118,6 +118,7 @@ option(LWS_FALLBACK_GETHOSTBYNAME "Also try to do dns resolution using gethostby
 option(LWS_WITH_ZIP_FOPS "Support serving pre-zipped files" ON)
 option(LWS_AVOID_SIGPIPE_IGN "Android 7+ seems to need this" OFF)
 option(LWS_WITH_STATS "Keep statistics of lws internal operations" OFF)
+option(LWS_WITH_SOCKS5 "Allow use of SOCKS5 proxy on client connections" OFF)
 
 if (LWS_WITH_LWSWS)
  message(STATUS "LWS_WITH_LWSWS --> Enabling LWS_WITH_PLUGINS and LWS_WITH_LIBUV")
@@ -1770,6 +1771,7 @@ message(" LWS_WITH_ESP32 = ${LWS_WITH_ESP32}")
 message(" LWS_WITH_ZIP_FOPS = ${LWS_WITH_ZIP_FOPS}")
 message(" LWS_AVOID_SIGPIPE_IGN = ${LWS_AVOID_SIGPIPE_IGN}")
 message(" LWS_WITH_STATS = ${LWS_WITH_STATS}")
+message(" LWS_WITH_SOCKS5 = ${LWS_WITH_SOCKS5}")
 
 message("---------------------------------------------------------------------")
 
index c844053..a9f8665 100644 (file)
@@ -26,6 +26,7 @@ lws_client_connect_2(struct lws *wsi)
 
        /* proxy? */
 
+       /* http proxy */
        if (wsi->vhost->http_proxy_port) {
                plen = sprintf((char *)pt->serv_buf,
                        "CONNECT %s:%u HTTP/1.0\x0d\x0a"
@@ -49,7 +50,26 @@ lws_client_connect_2(struct lws *wsi)
 #endif
                        server_addr4.sin_port = htons(wsi->vhost->http_proxy_port);
 
-       } else {
+       }
+#if defined(LWS_WITH_SOCKS5)
+       /* socks proxy */
+       else if (wsi->vhost->socks_proxy_port) {
+               socks_generate_msg(wsi, SOCKS_MSG_GREETING, (size_t *)&plen);
+               lwsl_client("%s\n", "Sending SOCKS Greeting.");
+
+               ads = wsi->vhost->socks_proxy_address;
+
+#ifdef LWS_USE_IPV6
+               if (LWS_IPV6_ENABLED(wsi->vhost)) {
+                       memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
+                       server_addr6.sin6_port = htons(wsi->vhost->socks_proxy_port);
+               } else
+#endif
+                       server_addr4.sin_port = htons(wsi->vhost->socks_proxy_port);
+
+       }
+#endif
+       else {
                ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
 #ifdef LWS_USE_IPV6
                if (LWS_IPV6_ENABLED(wsi->vhost)) {
@@ -275,6 +295,7 @@ lws_client_connect_2(struct lws *wsi)
 
        /* we are connected to server, or proxy */
 
+       /* http proxy */
        if (wsi->vhost->http_proxy_port) {
 
                /*
@@ -303,6 +324,26 @@ lws_client_connect_2(struct lws *wsi)
 
                return wsi;
        }
+#if defined(LWS_WITH_SOCKS5)
+       /* socks proxy */
+       else if (wsi->vhost->socks_proxy_port) {
+               n = send(wsi->desc.sockfd, (char *)pt->serv_buf, plen,
+                        MSG_NOSIGNAL);
+               if (n < 0) {
+                       lwsl_debug("ERROR writing greeting to socks proxy"
+                               "socket.\n");
+                       cce = "socks write failed";
+                       goto failed;
+               }
+
+               lws_set_timeout(wsi, PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY,
+                               AWAITING_TIMEOUT);
+
+               wsi->mode = LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY;
+
+               return wsi;
+       }
+#endif
 
        /*
         * provoke service to issue the handshake directly
@@ -754,7 +795,10 @@ lws_client_connect_via_info2(struct lws *wsi)
                                          stash->method))
                        goto bail1;
 
-       lws_free_set_NULL(wsi->u.hdr.stash);
+#if defined(LWS_WITH_SOCKS5)
+       if (!wsi->vhost->socks_proxy_port)
+               lws_free_set_NULL(wsi->u.hdr.stash);
+#endif
 
        /*
         * Check with each extension if it is able to route and proxy this
@@ -782,7 +826,10 @@ lws_client_connect_via_info2(struct lws *wsi)
        return lws_client_connect_2(wsi);
 
 bail1:
-       lws_free_set_NULL(wsi->u.hdr.stash);
+#if defined(LWS_WITH_SOCKS5)
+       if (!wsi->vhost->socks_proxy_port)
+               lws_free_set_NULL(wsi->u.hdr.stash);
+#endif
 
        return NULL;
 }
@@ -836,3 +883,73 @@ lws_client_connect(struct lws_context *context, const char *address,
        return lws_client_connect_via_info(&i);
 }
 
+#if defined(LWS_WITH_SOCKS5)
+void socks_generate_msg(struct lws *wsi, enum socks_msg_type type,
+                       size_t *msg_len)
+{
+       struct lws_context *context = wsi->context;
+       struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
+       size_t len = 0;
+
+       if (type == SOCKS_MSG_GREETING) {
+               /* socks version, version 5 only */
+               pt->serv_buf[len++] = SOCKS_VERSION_5;
+               /* number of methods */
+               pt->serv_buf[len++] = 2;
+               /* username password method */
+               pt->serv_buf[len++] = SOCKS_AUTH_USERNAME_PASSWORD;
+               /* no authentication method */
+               pt->serv_buf[len++] = SOCKS_AUTH_NO_AUTH;
+       }
+       else if (type == SOCKS_MSG_USERNAME_PASSWORD) {
+               size_t user_len = 0;
+               size_t passwd_len = 0;
+
+               user_len = strlen(wsi->vhost->socks_user);
+               passwd_len = strlen(wsi->vhost->socks_password);
+
+               /* the subnegotiation version */
+               pt->serv_buf[len++] = SOCKS_SUBNEGOTIATION_VERSION_1;
+               /* length of the user name */
+               pt->serv_buf[len++] = user_len;
+               /* user name */
+               strncpy((char *)&pt->serv_buf[len], wsi->vhost->socks_user,
+                       context->pt_serv_buf_size - len);
+               len += user_len;
+               /* length of the password */
+               pt->serv_buf[len++] = passwd_len;
+               /* password */
+               strncpy((char *)&pt->serv_buf[len], wsi->vhost->socks_password,
+                       context->pt_serv_buf_size - len);
+               len += passwd_len;
+       }
+       else if (type == SOCKS_MSG_CONNECT) {
+               size_t len_index = 0;
+               short net_num = 0;
+               char *net_buf = (char*)&net_num;
+
+               /* socks version */
+               pt->serv_buf[len++] = SOCKS_VERSION_5;
+               /* socks command */
+               pt->serv_buf[len++] = SOCKS_COMMAND_CONNECT;
+               /* reserved */
+               pt->serv_buf[len++] = 0;
+               /* address type */
+               pt->serv_buf[len++] = SOCKS_ATYP_DOMAINNAME;
+               len_index = len;
+               len++;
+               /* the address we tell SOCKS proxy to connect to */
+               strncpy((char *)&(pt->serv_buf[len]), wsi->u.hdr.stash->address,
+                       context->pt_serv_buf_size - len);
+               len += strlen(wsi->u.hdr.stash->address);
+               net_num = htons((short)wsi->c_port);
+               /* the port we tell SOCKS proxy to connect to */
+               pt->serv_buf[len++] = net_buf[0];
+               pt->serv_buf[len++] = net_buf[1];
+               /* the length of the address, excluding port */
+               pt->serv_buf[len_index] = strlen(wsi->u.hdr.stash->address);
+       }
+
+       *msg_len = len;
+}
+#endif
index 1919f03..4b643ac 100755 (executable)
@@ -81,7 +81,10 @@ lws_client_socket_service(struct lws_context *context, struct lws *wsi,
        const char *cce = NULL;
        unsigned char c;
        char *sb = p;
-       int n, len;
+       int n = 0, len = 0;
+#if defined(LWS_WITH_SOCKS5)
+       char conn_mode = 0, pending_timeout = 0;
+#endif
 
        switch (wsi->mode) {
 
@@ -101,6 +104,195 @@ lws_client_socket_service(struct lws_context *context, struct lws *wsi,
                /* either still pending connection, or changed mode */
                return 0;
 
+#if defined(LWS_WITH_SOCKS5)
+       /* SOCKS Greeting Reply */
+       case LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY:
+
+               /* handle proxy hung up on us */
+
+               if (pollfd->revents & LWS_POLLHUP) {
+
+                       lwsl_warn("SOCKS connection %p (fd=%d) dead\n",
+                                 (void *)wsi, pollfd->fd);
+
+                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+                       return 0;
+               }
+
+               n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
+               if (n < 0) {
+                       if (LWS_ERRNO == LWS_EAGAIN) {
+                               lwsl_debug("SOCKS read returned EAGAIN..."
+                                       "retrying\n");
+                               return 0;
+                       }
+
+                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+                       lwsl_err("ERROR reading from SOCKS socket\n");
+                       return 0;
+               }
+
+               /* processing greeting reply */
+               if (pt->serv_buf[0] == SOCKS_VERSION_5
+                       && pt->serv_buf[1] == SOCKS_AUTH_NO_AUTH)
+               {
+                       lwsl_client("%s\n", "SOCKS greeting reply received "
+                               "- No Authentication Method");
+                       socks_generate_msg(wsi, SOCKS_MSG_CONNECT, (size_t *)&len);
+
+                       conn_mode = LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY;
+                       pending_timeout = PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
+                       lwsl_client("%s\n", "Sending SOCKS connect command");
+               }
+               else if (pt->serv_buf[0] == SOCKS_VERSION_5
+                               && pt->serv_buf[1] == SOCKS_AUTH_USERNAME_PASSWORD)
+               {
+                       lwsl_client("%s\n", "SOCKS greeting reply received "
+                               "- User Name Password Method");
+                       socks_generate_msg(wsi, SOCKS_MSG_USERNAME_PASSWORD,
+                               (size_t *)&len);
+
+                       conn_mode = LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY;
+                       pending_timeout = PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY;
+                       lwsl_client("%s\n", "Sending SOCKS user/password");
+               }
+               else
+               {
+                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+                       lwsl_err("ERROR SOCKS greeting reply failed, method "
+                               "code: %d\n", pt->serv_buf[1]);
+                       return 0;
+               }
+
+               n = send(wsi->desc.sockfd, (char *)pt->serv_buf, len,
+                        MSG_NOSIGNAL);
+               if (n < 0) {
+                       lwsl_debug("ERROR writing socks command to socks proxy "
+                               "socket\n");
+                       return 0;
+               }
+
+               lws_set_timeout(wsi, pending_timeout, AWAITING_TIMEOUT);
+               wsi->mode = conn_mode;
+
+               break;
+       /* SOCKS auth Reply */
+       case LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY:
+
+               /* handle proxy hung up on us */
+
+               if (pollfd->revents & LWS_POLLHUP) {
+
+                       lwsl_warn("SOCKS connection %p (fd=%d) dead\n",
+                                 (void *)wsi, pollfd->fd);
+
+                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+                       return 0;
+               }
+
+               n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
+               if (n < 0) {
+                       if (LWS_ERRNO == LWS_EAGAIN) {
+                               lwsl_debug("SOCKS read returned EAGAIN... "
+                                       "retrying\n");
+                               return 0;
+                       }
+
+                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+                       lwsl_err("ERROR reading from socks socket\n");
+                       return 0;
+               }
+
+               /* processing auth reply */
+               if (pt->serv_buf[0] == SOCKS_SUBNEGOTIATION_VERSION_1
+                       && pt->serv_buf[1] == SOCKS_SUBNEGOTIATION_STATUS_SUCCESS)
+               {
+                       lwsl_client("%s\n", "SOCKS password reply recieved - "
+                               "successful");
+                       socks_generate_msg(wsi, SOCKS_MSG_CONNECT, (size_t *)&len);
+
+                       conn_mode = LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY;
+                       pending_timeout =
+                               PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY;
+                       lwsl_client("%s\n", "Sending SOCKS connect command");
+               }
+               else
+               {
+                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+                       lwsl_err("ERROR : SOCKS user/password reply failed, "
+                               "error code: %d\n", pt->serv_buf[1]);
+                       return 0;
+               }
+
+               n = send(wsi->desc.sockfd, (char *)pt->serv_buf, len,
+                        MSG_NOSIGNAL);
+               if (n < 0) {
+                       lwsl_debug("ERROR writing connect command to SOCKS "
+                               "socket\n");
+                       return 0;
+               }
+
+               lws_set_timeout(wsi, pending_timeout, AWAITING_TIMEOUT);
+               wsi->mode = conn_mode;
+
+               break;
+
+       /* SOCKS connect command Reply */
+       case LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY:
+
+               /* handle proxy hung up on us */
+
+               if (pollfd->revents & LWS_POLLHUP) {
+
+                       lwsl_warn("SOCKS connection %p (fd=%d) dead\n",
+                                 (void *)wsi, pollfd->fd);
+
+                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+                       return 0;
+               }
+
+               n = recv(wsi->desc.sockfd, sb, context->pt_serv_buf_size, 0);
+               if (n < 0) {
+                       if (LWS_ERRNO == LWS_EAGAIN) {
+                               lwsl_debug("SOCKS read returned EAGAIN... "
+                                       "retrying\n");
+                               return 0;
+                       }
+
+                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+                       lwsl_err("ERROR reading from socks socket\n");
+                       return 0;
+               }
+
+               /* processing connect reply */
+               if (pt->serv_buf[0] == SOCKS_VERSION_5
+                       && pt->serv_buf[1] == SOCKS_REQUEST_REPLY_SUCCESS)
+               {
+                       lwsl_client("%s\n", "SOCKS connect reply recieved - "
+                               "successful");
+               }
+               else
+               {
+                       lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
+                       lwsl_err("ERROR SOCKS connect reply failed, error "
+                               "code: %d\n", pt->serv_buf[1]);
+                       return 0;
+               }
+
+               /* free stash since we are done with it */
+               lws_free_set_NULL(wsi->u.hdr.stash);
+
+               if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
+                       wsi->vhost->socks_proxy_address))
+                       goto bail3;
+               wsi->c_port = wsi->vhost->socks_proxy_port;
+
+               /* clear his proxy connection timeout */
+
+               lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+
+               goto start_ws_hanshake;
+#endif
        case LWSCM_WSCL_WAITING_PROXY_REPLY:
 
                /* handle proxy hung up on us */
@@ -149,6 +341,9 @@ lws_client_socket_service(struct lws_context *context, struct lws *wsi,
                 * take care of our lws_callback_on_writable
                 * happening at a time when there's no real connection yet
                 */
+#if defined(LWS_WITH_SOCKS5)
+start_ws_hanshake:
+#endif
                if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
                        return -1;
 
index f791ca6..e9945c7 100644 (file)
@@ -497,9 +497,14 @@ lws_create_vhost(struct lws_context *context,
 #if !defined(LWS_WITH_ESP8266)
        vh->http_proxy_port = 0;
        vh->http_proxy_address[0] = '\0';
+#if defined(LWS_WITH_SOCKS5)
+       vh->socks_proxy_port = 0;
+       vh->socks_proxy_address[0] = '\0';
+#endif
 
        /* either use proxy from info, or try get it from env var */
 
+       /* http proxy */
        if (info->http_proxy_address) {
                /* override for backwards compatibility */
                if (info->http_proxy_port)
@@ -512,7 +517,23 @@ lws_create_vhost(struct lws_context *context,
                        lws_set_proxy(vh, p);
 #endif
        }
+#if defined(LWS_WITH_SOCKS5)
+       /* socks proxy */
+       if (info->socks_proxy_address) {
+               /* override for backwards compatibility */
+               if (info->socks_proxy_port)
+                       vh->socks_proxy_port = info->socks_proxy_port;
+               lws_set_socks(vh, info->socks_proxy_address);
+       } else {
+#ifdef LWS_HAVE_GETENV
+               p = getenv("socks_proxy");
+               if (p)
+                       lws_set_socks(vh, p);
 #endif
+       }
+#endif
+#endif
+
        vh->ka_time = info->ka_time;
        vh->ka_interval = info->ka_interval;
        vh->ka_probes = info->ka_probes;
index 9fd89cd..b8e8974 100755 (executable)
@@ -1325,6 +1325,79 @@ auth_too_long:
        return -1;
 }
 
+#if defined(LWS_WITH_SOCKS5)
+LWS_VISIBLE int
+lws_set_socks(struct lws_vhost *vhost, const char *socks)
+{
+#if !defined(LWS_WITH_ESP8266)
+       char *p_at, *p_colon;
+       char user[96];
+       char password[96];
+
+       if (!socks)
+               return -1;
+
+       vhost->socks_user[0] = '\0';
+       vhost->socks_password[0] = '\0';
+
+       p_at = strchr(socks, '@');
+       if (p_at) { /* auth is around */
+               if ((unsigned int)(p_at - socks) > (sizeof(user)
+                       + sizeof(password) - 2)) {
+                       lwsl_err("Socks auth too long\n");
+                       goto bail;
+               }
+
+               p_colon = strchr(socks, ':');
+               if (p_colon) {
+                       if ((unsigned int)(p_colon - socks) > (sizeof(user)
+                               - 1) ) {
+                               lwsl_err("Socks user too long\n");
+                               goto bail;
+                       }
+                       if ((unsigned int)(p_at - p_colon) > (sizeof(password)
+                               - 1) ) {
+                               lwsl_err("Socks password too long\n");
+                               goto bail;
+                       }
+               }
+               strncpy(vhost->socks_user, socks, p_colon - socks);
+               strncpy(vhost->socks_password, p_colon + 1,
+                       p_at - (p_colon + 1));
+
+               lwsl_info(" Socks auth, user: %s, password: %s\n",
+                       vhost->socks_user, vhost->socks_password );
+
+               socks = p_at + 1;
+       }
+
+       strncpy(vhost->socks_proxy_address, socks,
+                               sizeof(vhost->socks_proxy_address) - 1);
+       vhost->socks_proxy_address[sizeof(vhost->socks_proxy_address) - 1]
+               = '\0';
+
+       p_colon = strchr(vhost->socks_proxy_address, ':');
+       if (!p_colon && !vhost->socks_proxy_port) {
+               lwsl_err("socks_proxy needs to be address:port\n");
+               return -1;
+       } else {
+               if (p_colon) {
+                       *p_colon = '\0';
+                       vhost->socks_proxy_port = atoi(p_colon + 1);
+               }
+       }
+
+       lwsl_info(" Socks %s:%u\n", vhost->socks_proxy_address,
+                       vhost->socks_proxy_port);
+
+       return 0;
+
+bail:
+#endif
+       return -1;
+}
+#endif
+
 LWS_VISIBLE const struct lws_protocols *
 lws_get_protocol(struct lws *wsi)
 {
index 4eb0cd0..185a569 100644 (file)
@@ -1812,7 +1812,7 @@ struct lws_context_creation_info {
        /**< VHOST + CONTEXT: 0, or LWS_SERVER_OPTION_... bitfields */
        void *user;
        /**< CONTEXT: optional user pointer that can be recovered via the context
*             pointer using lws_context_user */
       *              pointer using lws_context_user */
        int ka_time;
        /**< CONTEXT: 0 for no TCP keepalive, otherwise apply this keepalive
         * timeout to all libwebsocket sockets, client or server */
@@ -1955,6 +1955,11 @@ struct lws_context_creation_info {
         */
        int simultaneous_ssl_restriction;
        /**< CONTEXT: 0 (no limit) or limit of simultaneous SSL sessions possible.*/
+       const char *socks_proxy_address;
+       /**< VHOST: If non-NULL, attempts to proxy via the given address.
+        * If proxy auth is required, use format "username:password\@server:port" */
+       unsigned int socks_proxy_port;
+       /**< VHOST: If socks_proxy_address was non-NULL, uses this port */
 
        /* Add new things just above here ---^
         * This is part of the ABI, don't needlessly break compatibility
@@ -2070,6 +2075,25 @@ lws_context_is_deprecated(struct lws_context *context);
 LWS_VISIBLE LWS_EXTERN int
 lws_set_proxy(struct lws_vhost *vhost, const char *proxy);
 
+/**
+ * lws_set_socks() - Setup socks to lws_context.
+ * \param vhost:       pointer to struct lws_vhost you want set socks for
+ * \param socks: pointer to c string containing socks in format address:port
+ *
+ * Returns 0 if socks string was parsed and socks was setup.
+ * Returns -1 if socks is NULL or has incorrect format.
+ *
+ * This is only required if your OS does not provide the socks_proxy
+ * environment variable (eg, OSX)
+ *
+ *   IMPORTANT! You should call this function right after creation of the
+ *   lws_context and before call to connect. If you call this
+ *   function after connect behavior is undefined.
+ *   This function will override proxy settings made on lws_context
+ *   creation with genenv() call.
+ */
+LWS_VISIBLE LWS_EXTERN int
+lws_set_socks(struct lws_vhost *vhost, const char *socks);
 
 struct lws_vhost;
 
@@ -3471,6 +3495,9 @@ enum pending_timeout {
        PENDING_TIMEOUT_WS_PONG_CHECK_SEND_PING                 = 16,
        PENDING_TIMEOUT_WS_PONG_CHECK_GET_PONG                  = 17,
        PENDING_TIMEOUT_CLIENT_ISSUE_PAYLOAD                    = 18,
+       PENDING_TIMEOUT_AWAITING_SOCKS_GREETING_REPLY           = 19,
+       PENDING_TIMEOUT_AWAITING_SOCKS_CONNECT_REPLY            = 20,
+       PENDING_TIMEOUT_AWAITING_SOCKS_AUTH_REPLY               = 21,
 
        /****** add new things just above ---^ ******/
 };
index 8de93dc..ad61015 100644 (file)
@@ -574,12 +574,75 @@ enum connection_mode {
        LWSCM_WSCL_WAITING_SERVER_REPLY,
        LWSCM_WSCL_WAITING_EXTENSION_CONNECT,
        LWSCM_WSCL_PENDING_CANDIDATE_CHILD,
+       LWSCM_WSCL_WAITING_SOCKS_GREETING_REPLY,
+       LWSCM_WSCL_WAITING_SOCKS_CONNECT_REPLY,
+       LWSCM_WSCL_WAITING_SOCKS_AUTH_REPLY,
 
        /****** add new things just above ---^ ******/
 
 
 };
 
+/* enums of socks version */
+enum socks_version {
+       SOCKS_VERSION_4 = 4,
+       SOCKS_VERSION_5 = 5
+};
+
+/* enums of subnegotiation version */
+enum socks_subnegotiation_version {
+       SOCKS_SUBNEGOTIATION_VERSION_1 = 1,
+};
+
+/* enums of socks commands */
+enum socks_command {
+       SOCKS_COMMAND_CONNECT = 1,
+       SOCKS_COMMAND_BIND = 2,
+       SOCKS_COMMAND_UDP_ASSOCIATE = 3
+};
+
+/* enums of socks address type */
+enum socks_atyp {
+       SOCKS_ATYP_IPV4 = 1,
+       SOCKS_ATYP_DOMAINNAME = 3,
+       SOCKS_ATYP_IPV6 = 4
+};
+
+/* enums of socks authentication methods */
+enum socks_auth_method {
+       SOCKS_AUTH_NO_AUTH = 0,
+       SOCKS_AUTH_GSSAPI = 1,
+       SOCKS_AUTH_USERNAME_PASSWORD = 2
+};
+
+/* enums of subnegotiation status */
+enum socks_subnegotiation_status {
+       SOCKS_SUBNEGOTIATION_STATUS_SUCCESS = 0,
+};
+
+/* enums of socks request reply */
+enum socks_request_reply {
+       SOCKS_REQUEST_REPLY_SUCCESS = 0,
+       SOCKS_REQUEST_REPLY_FAILURE_GENERAL = 1,
+       SOCKS_REQUEST_REPLY_CONNECTION_NOT_ALLOWED = 2,
+       SOCKS_REQUEST_REPLY_NETWORK_UNREACHABLE = 3,
+       SOCKS_REQUEST_REPLY_HOST_UNREACHABLE = 4,
+       SOCKS_REQUEST_REPLY_CONNECTION_REFUSED = 5,
+       SOCKS_REQUEST_REPLY_TTL_EXPIRED = 6,
+       SOCKS_REQUEST_REPLY_COMMAND_NOT_SUPPORTED = 7,
+       SOCKS_REQUEST_REPLY_ATYP_NOT_SUPPORTED = 8
+};
+
+/* enums used to generate socks messages */
+enum socks_msg_type {
+       /* greeting */
+       SOCKS_MSG_GREETING,
+       /* credential, user name and password */
+       SOCKS_MSG_USERNAME_PASSWORD,
+       /* connect command */
+       SOCKS_MSG_CONNECT
+};
+
 enum {
        LWS_RXFLOW_ALLOW = (1 << 0),
        LWS_RXFLOW_PENDING_CHANGE = (1 << 1),
@@ -774,6 +837,11 @@ struct lws_vhost {
 #if !defined(LWS_WITH_ESP8266)
        char http_proxy_address[128];
        char proxy_basic_auth_token[128];
+#if defined(LWS_WITH_SOCKS5)
+       char socks_proxy_address[128];
+       char socks_user[96];
+       char socks_password[96];
+#endif
 #endif
 #if defined(LWS_WITH_ESP8266)
        /* listen sockets need a place to hang their hat */
@@ -801,6 +869,9 @@ struct lws_vhost {
 
        int listen_port;
        unsigned int http_proxy_port;
+#if defined(LWS_WITH_SOCKS5)
+       unsigned int socks_proxy_port;
+#endif
        unsigned int options;
        int count_protocols;
        int ka_time;
@@ -2103,6 +2174,10 @@ static inline uint64_t lws_stats_atomic_max(struct lws_context * context,
        (void)context; (void)pt; (void)index; (void)val; return 0; }
 #endif
 
+/* socks */
+void socks_generate_msg(struct lws *wsi, enum socks_msg_type type,
+                       size_t *msg_len);
+
 #ifdef __cplusplus
 };
 #endif
index 96c1705..c9a0a1f 100644 (file)
 #cmakedefine LWS_FALLBACK_GETHOSTBYNAME
 
 #cmakedefine LWS_WITH_STATS
+#cmakedefine LWS_WITH_SOCKS5
 
 /* OpenSSL various APIs */