···11+/*
22+ * WiFiPPP
33+ * Copyright (c) 2021 joshua stein <jcs@jcs.org>
44+ *
55+ * Permission to use, copy, modify, and distribute this software for any
66+ * purpose with or without fee is hereby granted, provided that the above
77+ * copyright notice and this permission notice appear in all copies.
88+ *
99+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616+ */
1717+1818+#include "SocksClient.h"
1919+#include "wifippp.h"
2020+2121+enum {
2222+ STATE_DEAD = 0,
2323+ STATE_INIT,
2424+ STATE_METHOD,
2525+ STATE_REQUEST,
2626+ STATE_PROXY,
2727+};
2828+2929+#define VERSION_SOCKS5 0x05
3030+3131+#define METHOD_MIN_LENGTH 3
3232+#define METHOD_AUTH_NONE 0x0
3333+3434+#define REQUEST_MIN_LENGTH 9
3535+#define REQUEST_COMMAND_CONNECT 0x1
3636+#define REQUEST_ATYP_IP 0x1
3737+#define REQUEST_ATYP_HOSTNAME 0x3
3838+#define REQUEST_ATYP_IP6 0x4
3939+4040+#define REPLY_SUCCESS 0x0
4141+#define REPLY_FAIL 0x1
4242+#define REPLY_EPERM 0x02
4343+#define REPLY_NET_UNREACHABLE 0x03
4444+#define REPLY_HOST_UNREACHABLE 0x04
4545+#define REPLY_CONN_REFUSED 0x05
4646+#define REPLY_TTL_EXPIRED 0x06
4747+#define REPLY_BAD_COMMAND 0x07
4848+#define REPLY_BAD_ADDRESS 0x08
4949+5050+SocksClient::~SocksClient()
5151+{
5252+}
5353+5454+SocksClient::SocksClient(int _slot, WiFiClient _client)
5555+ : slot(_slot), client(_client)
5656+{
5757+ state = STATE_INIT;
5858+5959+ memset(buf, 0, sizeof(buf));
6060+ buflen = 0;
6161+6262+ syslog.logf(LOG_DEBUG, "[%d] in socks client init with ip %s", slot,
6363+ client.remoteIP().toString().c_str());
6464+}
6565+6666+bool
6767+SocksClient::done()
6868+{
6969+ if (state == STATE_DEAD)
7070+ return true;
7171+7272+ if (!client.connected())
7373+ return true;
7474+7575+ return false;
7676+}
7777+7878+void
7979+SocksClient::process()
8080+{
8181+ if (state == STATE_DEAD)
8282+ return;
8383+8484+ if (client.available() && sizeof(buf) - buflen > 0)
8585+ buflen += client.read(buf + buflen, sizeof(buf) - buflen);
8686+8787+ switch (state) {
8888+ case STATE_INIT:
8989+ if (buflen >= METHOD_MIN_LENGTH) {
9090+ state = STATE_METHOD;
9191+ break;
9292+ }
9393+ break;
9494+ case STATE_METHOD:
9595+ verify_method();
9696+ break;
9797+ }
9898+}
9999+100100+void
101101+SocksClient::verify_method()
102102+{
103103+ if (state != STATE_METHOD) {
104104+ syslog.logf(LOG_ERR, "[%d] %s but state %d", slot, __func__,
105105+ state);
106106+ state = STATE_DEAD;
107107+ return;
108108+ }
109109+110110+ if (buflen < METHOD_MIN_LENGTH)
111111+ return;
112112+113113+ if (buf[0] != VERSION_SOCKS5) {
114114+ syslog.logf(LOG_ERR, "[%d] unsupported version 0x%x", slot,
115115+ buf[0]);
116116+ fail_close(REPLY_FAIL);
117117+ return;
118118+ }
119119+}
120120+121121+void
122122+SocksClient::fail_close(char code)
123123+{
124124+ unsigned char msg[] = {
125125+ VERSION_SOCKS5,
126126+ code,
127127+ 0,
128128+ REQUEST_ATYP_IP,
129129+ 0, 0, 0, 0,
130130+ 0, 0,
131131+ };
132132+133133+ client.write(msg, sizeof(msg));
134134+135135+ state = STATE_DEAD;
136136+ client.stop();
137137+ server.stop();
138138+}
+40
SocksClient.h
···11+/*
22+ * WiFiPPP
33+ * Copyright (c) 2021 joshua stein <jcs@jcs.org>
44+ *
55+ * Permission to use, copy, modify, and distribute this software for any
66+ * purpose with or without fee is hereby granted, provided that the above
77+ * copyright notice and this permission notice appear in all copies.
88+ *
99+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616+ */
1717+1818+#pragma once
1919+2020+#include <WiFiClient.h>
2121+2222+class SocksClient : public WiFiClient {
2323+public:
2424+ virtual ~SocksClient();
2525+ SocksClient(int _slot, WiFiClient _client);
2626+2727+ bool done();
2828+ void process();
2929+ void verify_method();
3030+ void fail_close(char code);
3131+3232+ int state;
3333+ int slot;
3434+ WiFiClient client;
3535+ WiFiClient server;
3636+3737+private:
3838+ unsigned char buf[64];
3939+ size_t buflen;
4040+};
+76
socks.cpp
···11+/*
22+ * WiFiPPP
33+ * Copyright (c) 2021 joshua stein <jcs@jcs.org>
44+ *
55+ * Permission to use, copy, modify, and distribute this software for any
66+ * purpose with or without fee is hereby granted, provided that the above
77+ * copyright notice and this permission notice appear in all copies.
88+ *
99+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1010+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1111+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1212+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1313+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1414+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1515+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1616+ */
1717+1818+#include "wifippp.h"
1919+#include <WiFiClient.h>
2020+#include <WiFiServer.h>
2121+#include "SocksClient.h"
2222+2323+WiFiServer socks_server(1080);
2424+2525+#define MAX_SOCKS_CLIENTS 5
2626+SocksClient *socks_clients[MAX_SOCKS_CLIENTS] = { nullptr };
2727+2828+void
2929+socks_setup(void)
3030+{
3131+ socks_server.begin();
3232+}
3333+3434+void
3535+socks_process(void)
3636+{
3737+ int i;
3838+3939+ if (socks_server.hasClient()) {
4040+ int slot = -1;
4141+4242+ for (i = 0; i < MAX_SOCKS_CLIENTS; i++) {
4343+ if (!socks_clients[i] || socks_clients[i]->done()) {
4444+ if (socks_clients[i])
4545+ delete socks_clients[i];
4646+ slot = i;
4747+ break;
4848+ }
4949+ }
5050+5151+ syslog.logf(LOG_DEBUG, "new SOCKS client, slot %d", slot);
5252+5353+ if (slot > -1) {
5454+ WiFiClient client = socks_server.available();
5555+ if (client.connected())
5656+ socks_clients[slot] = new SocksClient(slot,
5757+ client);
5858+ else
5959+ syslog.logf(LOG_ERR, "found slot %d for new "
6060+ "connection but not connected", slot);
6161+ }
6262+ }
6363+6464+ for (i = 0; i < MAX_SOCKS_CLIENTS; i++) {
6565+ if (!socks_clients[i])
6666+ continue;
6767+6868+ if (socks_clients[i]->done()) {
6969+ delete socks_clients[i];
7070+ socks_clients[i] = nullptr;
7171+ continue;
7272+ }
7373+7474+ socks_clients[i]->process();
7575+ }
7676+}
···3232 int b = -1, i;
3333 long now = millis();
34343535+ socks_process();
3636+3537 switch (state) {
3638 case STATE_AT:
3739 if (Serial.available() && (b = Serial.read()))