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")
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("---------------------------------------------------------------------")
/* proxy? */
+ /* http proxy */
if (wsi->vhost->http_proxy_port) {
plen = sprintf((char *)pt->serv_buf,
"CONNECT %s:%u HTTP/1.0\x0d\x0a"
#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)) {
/* we are connected to server, or proxy */
+ /* http proxy */
if (wsi->vhost->http_proxy_port) {
/*
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
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
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;
}
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
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) {
/* 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 */
* 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;
#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)
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;
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)
{
/**< 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 */
*/
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
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;
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 ---^ ******/
};
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),
#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 */
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;
(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
#cmakedefine LWS_FALLBACK_GETHOSTBYNAME
#cmakedefine LWS_WITH_STATS
+#cmakedefine LWS_WITH_SOCKS5
/* OpenSSL various APIs */