diff --git a/examples/socks_server/Makefile b/examples/socks_server/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..bce5271d19822fe499d8a2e9dad8ff562e42bf2d
--- /dev/null
+++ b/examples/socks_server/Makefile
@@ -0,0 +1,5 @@
+PROG = socks_server
+# NOTE(lsm): -DMG_ENABLE_IPV6 won't work for the mingw build
+MODULE_CFLAGS = -DMG_ENABLE_SOCKS=1 # -DMG_ENABLE_DEBUG=1
+#SSL_LIB=openssl
+include ../examples.mk
diff --git a/examples/socks_server/socks_server.c b/examples/socks_server/socks_server.c
new file mode 100644
index 0000000000000000000000000000000000000000..a99768a7fe4ad72a44feeb73f9160debb6d623c1
--- /dev/null
+++ b/examples/socks_server/socks_server.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 Cesanta Software Limited
+ * All rights reserved
+ *
+ * Use curl to test, e.g.
+ * curl -i --socks5 127.0.0.1:1080 www.met.ie
+ */
+
+#include "mongoose.h"
+
+static const char *s_listening_addr = "1080";
+
+int main(void) {
+  struct mg_mgr mgr;
+  struct mg_connection *c;
+
+  mg_mgr_init(&mgr, NULL);
+
+  if ((c = mg_bind(&mgr, s_listening_addr, NULL)) == NULL) {
+    fprintf(stderr, "mg_bind(%s) failed\n", s_listening_addr);
+    exit(EXIT_FAILURE);
+  }
+  mg_set_protocol_socks(c);
+
+  printf("Starting socks5 proxy server on %s\n", s_listening_addr);
+  for (;;) {
+    mg_mgr_poll(&mgr, 1000);
+  }
+  mg_mgr_free(&mgr);
+
+  return 0;
+}
diff --git a/mongoose.c b/mongoose.c
index cb5a10bdd87cd923602ad6bb774c2ccdc2bd9b61..fe0901a52e88247841d559ab894d12337d7e435f 100644
--- a/mongoose.c
+++ b/mongoose.c
@@ -3231,6 +3231,31 @@ struct mg_connection *mg_tun_if_find_conn(struct mg_tun_client *client,
 
 #endif /* CS_MONGOOSE_SRC_NET_IF_TUN_H_ */
 #ifdef MG_MODULE_LINES
+#line 1 "mongoose/src/net_if_socks.h"
+#endif
+/*
+* Copyright (c) 2014-2017 Cesanta Software Limited
+* All rights reserved
+*/
+
+#ifndef CS_MONGOOSE_SRC_NET_IF_SOCKS_H_
+#define CS_MONGOOSE_SRC_NET_IF_SOCKS_H_
+
+#if MG_ENABLE_SOCKS
+/* Amalgamated: #include "mongoose/src/net_if.h" */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+extern const struct mg_iface_vtable mg_socks_iface_vtable;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif /* MG_ENABLE_SOCKS */
+#endif /* CS_MONGOOSE_SRC_NET_IF_SOCKS_H_ */
+#ifdef MG_MODULE_LINES
 #line 1 "mongoose/src/net_if.c"
 #endif
 /* Amalgamated: #include "mongoose/src/net_if.h" */
@@ -3240,12 +3265,12 @@ struct mg_connection *mg_tun_if_find_conn(struct mg_tun_client *client,
 
 extern const struct mg_iface_vtable mg_default_iface_vtable;
 
+const struct mg_iface_vtable *mg_ifaces[] = {
+  &mg_default_iface_vtable,
 #if MG_ENABLE_TUN
-const struct mg_iface_vtable *mg_ifaces[] = {&mg_default_iface_vtable,
-                                             &mg_tun_iface_vtable};
-#else
-const struct mg_iface_vtable *mg_ifaces[] = {&mg_default_iface_vtable};
+  &mg_tun_iface_vtable,
 #endif
+};
 
 int mg_num_ifaces = (int) (sizeof(mg_ifaces) / sizeof(mg_ifaces[0]));
 
@@ -4022,6 +4047,220 @@ const struct mg_iface_vtable mg_default_iface_vtable = MG_SOCKET_IFACE_VTABLE;
 
 #endif /* MG_ENABLE_NET_IF_SOCKET */
 #ifdef MG_MODULE_LINES
+#line 1 "mongoose/src/net_if_socks.c"
+#endif
+/*
+ * Copyright (c) 2014-2016 Cesanta Software Limited
+ * All rights reserved
+ */
+
+#if MG_ENABLE_SOCKS
+
+#define MG_SOCKS_HANDSHAKE_DONE MG_F_USER_1
+#define MG_SOCKS_CONNECT_DONE MG_F_USER_2
+
+struct socksdata {
+  char *proxy_addr;        /* HOST:PORT of the socks5 proxy server */
+  struct mg_connection *s; /* Respective connection to the server */
+  struct mg_connection *c; /* Connection to the client */
+  struct mbuf tmp;         /* Temporary buffer for sent data */
+};
+
+static void socks_if_disband(struct socksdata *d) {
+  LOG(LL_DEBUG, ("disbanding proxy %p %p", d->c, d->s));
+  if (d->c) d->c->flags |= MG_F_SEND_AND_CLOSE;
+  if (d->s) d->s->flags |= MG_F_SEND_AND_CLOSE;
+  d->c = d->s = NULL;
+}
+
+static void socks_if_handler(struct mg_connection *c, int ev, void *ev_data) {
+  struct socksdata *d = (struct socksdata *) c->user_data;
+  if (ev == MG_EV_CONNECT) {
+    int res = *(int *) ev_data;
+    if (res == 0) {
+      /* Send handshake to the proxy server */
+      unsigned char buf[] = {MG_SOCKS_VERSION, 1, MG_SOCKS_HANDSHAKE_NOAUTH};
+      mg_send(d->s, buf, sizeof(buf));
+      LOG(LL_DEBUG, ("Sent handshake to %s", d->proxy_addr));
+    } else {
+      LOG(LL_ERROR, ("Cannot connect to %s: %d", d->proxy_addr, res));
+      d->c->flags |= MG_F_CLOSE_IMMEDIATELY;
+    }
+  } else if (ev == MG_EV_CLOSE) {
+    socks_if_disband(d);
+  } else if (ev == MG_EV_RECV) {
+    /* Handle handshake reply */
+    if (!(c->flags & MG_SOCKS_HANDSHAKE_DONE)) {
+      /* TODO(lsm): process IPv6 too */
+      unsigned char buf[10] = {MG_SOCKS_VERSION, MG_SOCKS_CMD_CONNECT, 0,
+                               MG_SOCKS_ADDR_IPV4};
+      if (c->recv_mbuf.len < 2) return;
+      if ((unsigned char) c->recv_mbuf.buf[1] == MG_SOCKS_HANDSHAKE_FAILURE) {
+        LOG(LL_ERROR, ("Server kicked us out"));
+        socks_if_disband(d);
+        return;
+      }
+      mbuf_remove(&c->recv_mbuf, 2);
+      c->flags |= MG_SOCKS_HANDSHAKE_DONE;
+
+      /* Send connect request */
+      memcpy(buf + 4, &d->c->sa.sin.sin_addr, 4);
+      memcpy(buf + 8, &d->c->sa.sin.sin_port, 2);
+      mg_send(c, buf, sizeof(buf));
+    }
+    /* Process connect request */
+    if ((c->flags & MG_SOCKS_HANDSHAKE_DONE) &&
+        !(c->flags & MG_SOCKS_CONNECT_DONE)) {
+      if (c->recv_mbuf.len < 10) return;
+      if (c->recv_mbuf.buf[1] != MG_SOCKS_SUCCESS) {
+        LOG(LL_ERROR, ("Socks connection error: %d", c->recv_mbuf.buf[1]));
+        socks_if_disband(d);
+        return;
+      }
+      mbuf_remove(&c->recv_mbuf, 10);
+      c->flags |= MG_SOCKS_CONNECT_DONE;
+      /* Connected. Move sent data from client, if any, to server */
+      if (d->s && d->c) {
+        mbuf_append(&d->s->send_mbuf, d->tmp.buf, d->tmp.len);
+        mbuf_free(&d->tmp);
+      }
+    }
+    /* All flags are set, we're in relay mode */
+    if ((c->flags & MG_SOCKS_CONNECT_DONE) && d->c && d->s) {
+      mbuf_append(&d->c->recv_mbuf, d->s->recv_mbuf.buf, d->s->recv_mbuf.len);
+      mbuf_remove(&d->s->recv_mbuf, d->s->recv_mbuf.len);
+    }
+  }
+}
+
+static void mg_socks_if_connect_tcp(struct mg_connection *c,
+                                    const union socket_address *sa) {
+  struct socksdata *d = (struct socksdata *) c->iface->data;
+  d->c = c;
+  d->s = mg_connect(c->mgr, d->proxy_addr, socks_if_handler);
+  d->s->user_data = d;
+  LOG(LL_DEBUG, ("%p %s", c, d->proxy_addr));
+  (void) sa;
+}
+
+static void mg_socks_if_connect_udp(struct mg_connection *c) {
+  (void) c;
+}
+
+static int mg_socks_if_listen_tcp(struct mg_connection *c,
+                                  union socket_address *sa) {
+  (void) c;
+  (void) sa;
+  return 0;
+}
+
+static int mg_socks_if_listen_udp(struct mg_connection *c,
+                                  union socket_address *sa) {
+  (void) c;
+  (void) sa;
+  return -1;
+}
+
+static void mg_socks_if_tcp_send(struct mg_connection *c, const void *buf,
+                                 size_t len) {
+  struct socksdata *d = (struct socksdata *) c->iface->data;
+  LOG(LL_DEBUG, ("%p -> %p %d %d", c, buf, (int) len, (int) c->send_mbuf.len));
+  if (d && d->s && d->s->flags & MG_SOCKS_CONNECT_DONE) {
+    mbuf_append(&d->s->send_mbuf, d->tmp.buf, d->tmp.len);
+    mbuf_append(&d->s->send_mbuf, buf, len);
+    mbuf_free(&d->tmp);
+  } else {
+    mbuf_append(&d->tmp, buf, len);
+  }
+}
+
+static void mg_socks_if_udp_send(struct mg_connection *c, const void *buf,
+                                 size_t len) {
+  (void) c;
+  (void) buf;
+  (void) len;
+}
+
+static void mg_socks_if_recved(struct mg_connection *c, size_t len) {
+  (void) c;
+  (void) len;
+}
+
+static int mg_socks_if_create_conn(struct mg_connection *c) {
+  (void) c;
+  return 1;
+}
+
+static void mg_socks_if_destroy_conn(struct mg_connection *c) {
+  c->iface->vtable->free(c->iface);
+  MG_FREE(c->iface);
+  c->iface = NULL;
+  LOG(LL_DEBUG, ("%p", c));
+}
+
+static void mg_socks_if_sock_set(struct mg_connection *c, sock_t sock) {
+  (void) c;
+  (void) sock;
+}
+
+static void mg_socks_if_init(struct mg_iface *iface) {
+  (void) iface;
+}
+
+static void mg_socks_if_free(struct mg_iface *iface) {
+  struct socksdata *d = (struct socksdata *) iface->data;
+  LOG(LL_DEBUG, ("%p", iface));
+  if (d != NULL) {
+    socks_if_disband(d);
+    MG_FREE(d->proxy_addr);
+    MG_FREE(d);
+    iface->data = NULL;
+  }
+}
+
+static void mg_socks_if_add_conn(struct mg_connection *c) {
+  c->sock = INVALID_SOCKET;
+}
+
+static void mg_socks_if_remove_conn(struct mg_connection *c) {
+  (void) c;
+}
+
+static time_t mg_socks_if_poll(struct mg_iface *iface, int timeout_ms) {
+  LOG(LL_DEBUG, ("%p", iface));
+  (void) iface;
+  (void) timeout_ms;
+  return (time_t) cs_time();
+}
+
+static void mg_socks_if_get_conn_addr(struct mg_connection *c, int remote,
+                                      union socket_address *sa) {
+  LOG(LL_DEBUG, ("%p", c));
+  (void) c;
+  (void) remote;
+  (void) sa;
+}
+
+const struct mg_iface_vtable mg_socks_iface_vtable = {
+    mg_socks_if_init,        mg_socks_if_free,
+    mg_socks_if_add_conn,    mg_socks_if_remove_conn,
+    mg_socks_if_poll,        mg_socks_if_listen_tcp,
+    mg_socks_if_listen_udp,  mg_socks_if_connect_tcp,
+    mg_socks_if_connect_udp, mg_socks_if_tcp_send,
+    mg_socks_if_udp_send,    mg_socks_if_recved,
+    mg_socks_if_create_conn, mg_socks_if_destroy_conn,
+    mg_socks_if_sock_set,    mg_socks_if_get_conn_addr,
+};
+
+struct mg_iface *mg_socks_mk_iface(struct mg_mgr *mgr, const char *proxy_addr) {
+  struct mg_iface *iface = mg_if_create_iface(&mg_socks_iface_vtable, mgr);
+  iface->data = MG_CALLOC(1, sizeof(struct socksdata));
+  ((struct socksdata *) iface->data)->proxy_addr = strdup(proxy_addr);
+  return iface;
+}
+
+#endif
+#ifdef MG_MODULE_LINES
 #line 1 "mongoose/src/net_if_tun.c"
 #endif
 /*
@@ -9222,7 +9461,7 @@ static void mg_handle_incoming_websocket_frame(struct mg_connection *nc,
 static struct mg_ws_proto_data *mg_ws_get_proto_data(struct mg_connection *nc) {
   struct mg_http_proto_data *htd = mg_http_get_proto_data(nc);
   return (htd != NULL ? &htd->ws_data : NULL);
-};
+}
 
 static int mg_deliver_websocket_data(struct mg_connection *nc) {
   /* Using unsigned char *, cause of integer arithmetic below */
@@ -12559,6 +12798,167 @@ struct mg_connection *mg_sntp_get_time(struct mg_mgr *mgr,
 
 #endif /* MG_ENABLE_SNTP */
 #ifdef MG_MODULE_LINES
+#line 1 "mongoose/src/socks.c"
+#endif
+/*
+ * Copyright (c) 2017 Cesanta Software Limited
+ * All rights reserved
+ */
+
+#if MG_ENABLE_SOCKS
+
+/* Amalgamated: #include "mongoose/src/internal.h" */
+/* Amalgamated: #include "mongoose/src/socks.h" */
+
+/*
+ *  https://www.ietf.org/rfc/rfc1928.txt paragraph 3, handle client handshake
+ *
+ *  +----+----------+----------+
+ *  |VER | NMETHODS | METHODS  |
+ *  +----+----------+----------+
+ *  | 1  |    1     | 1 to 255 |
+ *  +----+----------+----------+
+ */
+static void mg_socks5_handshake(struct mg_connection *c) {
+  struct mbuf *r = &c->recv_mbuf;
+  if (r->buf[0] != MG_SOCKS_VERSION) {
+    c->flags |= MG_F_CLOSE_IMMEDIATELY;
+  } else if (r->len > 2 && (size_t) r->buf[1] + 2 <= r->len) {
+    /* https://www.ietf.org/rfc/rfc1928.txt paragraph 3 */
+    unsigned char reply[2] = {MG_SOCKS_VERSION, MG_SOCKS_HANDSHAKE_FAILURE};
+    int i;
+    for (i = 2; i < r->buf[1] + 2; i++) {
+      /* TODO(lsm): support other auth methods */
+      if (r->buf[i] == MG_SOCKS_HANDSHAKE_NOAUTH) reply[1] = r->buf[i];
+    }
+    mbuf_remove(r, 2 + r->buf[1]);
+    mg_send(c, reply, sizeof(reply));
+    c->flags |= MG_F_USER_1;  /* Mark handshake done */
+  }
+}
+
+static void disband(struct mg_connection *c) {
+  struct mg_connection *c2 = (struct mg_connection *) c->user_data;
+  if (c2 != NULL) {
+    c2->flags |= MG_F_SEND_AND_CLOSE;
+    c2->user_data = NULL;
+  }
+  c->flags |= MG_F_SEND_AND_CLOSE;
+  c->user_data = NULL;
+}
+
+static void relay_data(struct mg_connection *c) {
+  struct mg_connection *c2 = (struct mg_connection *) c->user_data;
+  if (c2 != NULL) {
+    mg_send(c2, c->recv_mbuf.buf, c->recv_mbuf.len);
+    mbuf_remove(&c->recv_mbuf, c->recv_mbuf.len);
+  } else {
+    c->flags |= MG_F_SEND_AND_CLOSE;
+  }
+}
+
+static void serv_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
+  if (ev == MG_EV_CLOSE) {
+    disband(c);
+  } else if (ev == MG_EV_RECV) {
+    relay_data(c);
+  } else if (ev == MG_EV_CONNECT) {
+    int res = * (int *) ev_data;
+    if (res != 0) LOG(LL_ERROR, ("connect error: %d", res));
+  }
+}
+
+static void mg_socks5_connect(struct mg_connection *c, const char *addr) {
+  struct mg_connection *serv = mg_connect(c->mgr, addr, serv_ev_handler);
+  serv->user_data = c;
+  c->user_data = serv;
+}
+
+/*
+ *  Request, https://www.ietf.org/rfc/rfc1928.txt paragraph 4
+ *
+ *  +----+-----+-------+------+----------+----------+
+ *  |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
+ *  +----+-----+-------+------+----------+----------+
+ *  | 1  |  1  | X'00' |  1   | Variable |    2     |
+ *  +----+-----+-------+------+----------+----------+
+ */
+static void mg_socks5_handle_request(struct mg_connection *c) {
+  struct mbuf *r = &c->recv_mbuf;
+  unsigned char *p = (unsigned char *) r->buf;
+  unsigned char addr_len = 4, reply = MG_SOCKS_SUCCESS;
+  int ver, cmd, atyp;
+  char addr[300];
+
+  if (r->len < 8) return; /* return if not fully buffered. min DST.ADDR is 2 */
+  ver = p[0];
+  cmd = p[1];
+  atyp = p[3];
+
+  /* TODO(lsm): support other commands */
+  if (ver != MG_SOCKS_VERSION || cmd != MG_SOCKS_CMD_CONNECT) {
+    reply = MG_SOCKS_CMD_NOT_SUPPORTED;
+  } else if (atyp == MG_SOCKS_ADDR_IPV4) {
+    addr_len = 4;
+    if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
+    snprintf(addr, sizeof(addr), "%d.%d.%d.%d:%d", p[4], p[5], p[6], p[7],
+             p[8] << 8 | p[9]);
+    mg_socks5_connect(c, addr);
+  } else if (atyp == MG_SOCKS_ADDR_IPV6) {
+    addr_len = 16;
+    if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
+    snprintf(addr, sizeof(addr), "[%x:%x:%x:%x:%x:%x:%x:%x]:%d",
+             p[4] << 8 | p[5], p[6] << 8 | p[7], p[8] << 8 | p[9],
+             p[10] << 8 | p[11], p[12] << 8 | p[13], p[14] << 8 | p[15],
+             p[16] << 8 | p[17], p[18] << 8 | p[19], p[20] << 8 | p[21]);
+    mg_socks5_connect(c, addr);
+  } else if (atyp == MG_SOCKS_ADDR_DOMAIN) {
+    addr_len = p[4] + 1;
+    if (r->len < (size_t) addr_len + 6) return; /* return if not buffered */
+    snprintf(addr, sizeof(addr), "%.*s:%d", p[4], p + 5,
+             p[4 + addr_len] << 8 | p[4 + addr_len + 1]);
+    mg_socks5_connect(c, addr);
+  } else {
+    reply = MG_SOCKS_ADDR_NOT_SUPPORTED;
+  }
+
+  /*
+   *  Reply, https://www.ietf.org/rfc/rfc1928.txt paragraph 5
+   *
+   *  +----+-----+-------+------+----------+----------+
+   *  |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
+   *  +----+-----+-------+------+----------+----------+
+   *  | 1  |  1  | X'00' |  1   | Variable |    2     |
+   *  +----+-----+-------+------+----------+----------+
+   */
+  {
+    unsigned char buf[] = {MG_SOCKS_VERSION, reply, 0};
+    mg_send(c, buf, sizeof(buf));
+  }
+  mg_send(c, r->buf + 3, addr_len + 1 + 2);
+
+  mbuf_remove(r, 6 + addr_len); /* Remove request from the input stream */
+  c->flags |= MG_F_USER_2;      /* Mark ourselves as connected */
+}
+
+static void socks_handler(struct mg_connection *c, int ev, void *ev_data) {
+  if (ev == MG_EV_RECV) {
+    if (!(c->flags & MG_F_USER_1)) mg_socks5_handshake(c);
+    if (c->flags & MG_F_USER_1 && !(c->flags & MG_F_USER_2)) {
+      mg_socks5_handle_request(c);
+    }
+    if (c->flags & MG_F_USER_2) relay_data(c);
+  } else if (ev == MG_EV_CLOSE) {
+    disband(c);
+  }
+  (void) ev_data;
+}
+
+void mg_set_protocol_socks(struct mg_connection *c) {
+  c->proto_handler = socks_handler;
+}
+#endif
+#ifdef MG_MODULE_LINES
 #line 1 "common/platforms/cc3200/cc3200_libc.c"
 #endif
 /*
diff --git a/mongoose.h b/mongoose.h
index 685797c5dfccb9319c53eaa63d61f9b4ad8344be..ec57113583fc3822519dc0b32c09695f235637c9 100644
--- a/mongoose.h
+++ b/mongoose.h
@@ -3029,6 +3029,10 @@ struct {								\
 #define MG_ENABLE_MQTT 1
 #endif
 
+#ifndef MG_ENABLE_SOCKS
+#define MG_ENABLE_SOCKS 0
+#endif
+
 #ifndef MG_ENABLE_MQTT_BROKER
 #define MG_ENABLE_MQTT_BROKER 0
 #endif
@@ -6032,3 +6036,69 @@ struct mg_connection *mg_sntp_get_time(struct mg_mgr *mgr,
 #endif
 
 #endif /* CS_MONGOOSE_SRC_SNTP_H_ */
+#ifdef MG_MODULE_LINES
+#line 1 "mongoose/src/socks.h"
+#endif
+/*
+ * Copyright (c) 2017 Cesanta Software Limited
+ * All rights reserved
+ */
+
+#ifndef CS_MONGOOSE_SRC_SOCKS_H_
+#define CS_MONGOOSE_SRC_SOCKS_H_
+
+#if MG_ENABLE_SOCKS
+
+#define MG_SOCKS_VERSION 5
+
+/* SOCKS5 handshake methods */
+enum mg_socks_handshake_method {
+  MG_SOCKS_HANDSHAKE_NOAUTH = 0,     /* Handshake method - no authentication */
+  MG_SOCKS_HANDSHAKE_GSSAPI = 1,     /* Handshake method - GSSAPI auth */
+  MG_SOCKS_HANDSHAKE_USERPASS = 2,   /* Handshake method - user/password auth */
+  MG_SOCKS_HANDSHAKE_FAILURE = 0xff, /* Handshake method - failure */
+};
+
+/* SOCKS5 commands */
+enum mg_socks_command {
+  MG_SOCKS_CMD_CONNECT = 1,        /* Command: CONNECT */
+  MG_SOCKS_CMD_BIND = 2,           /* Command: BIND */
+  MG_SOCKS_CMD_UDP_ASSOCIATE = 3,  /* Command: UDP ASSOCIATE */
+};
+
+/* SOCKS5 address types */
+enum mg_socks_address_type {
+  MG_SOCKS_ADDR_IPV4 = 1,          /* Address type: IPv4 */
+  MG_SOCKS_ADDR_DOMAIN = 3,        /* Address type: Domain name */
+  MG_SOCKS_ADDR_IPV6 = 4,          /* Address type: IPv6 */
+};
+
+/* SOCKS5 response codes */
+enum mg_socks_response {
+  MG_SOCKS_SUCCESS = 0,            /* Response: success */
+  MG_SOCKS_FAILURE = 1,            /* Response: failure */
+  MG_SOCKS_NOT_ALLOWED = 2,        /* Response: connection not allowed */
+  MG_SOCKS_NET_UNREACHABLE = 3,    /* Response: network unreachable */
+  MG_SOCKS_HOST_UNREACHABLE = 4,   /* Response: network unreachable */
+  MG_SOCKS_CONN_REFUSED = 5,       /* Response: network unreachable */
+  MG_SOCKS_TTL_EXPIRED = 6,        /* Response: network unreachable */
+  MG_SOCKS_CMD_NOT_SUPPORTED = 7,  /* Response: network unreachable */
+  MG_SOCKS_ADDR_NOT_SUPPORTED = 8, /* Response: network unreachable */
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/* Turn the connection into the SOCKS server */
+void mg_set_protocol_socks(struct mg_connection *c);
+
+/* Create socks tunnel for the client connection */
+struct mg_iface *mg_socks_mk_iface(struct mg_mgr *, const char *proxy_addr);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+#endif