Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'proxy/socks4.c')
-rw-r--r--proxy/socks4.c136
1 files changed, 136 insertions, 0 deletions
diff --git a/proxy/socks4.c b/proxy/socks4.c
new file mode 100644
index 00000000..ac85ec05
--- /dev/null
+++ b/proxy/socks4.c
@@ -0,0 +1,136 @@
+/*
+ * SOCKS 4 proxy negotiation.
+ */
+
+#include "putty.h"
+#include "network.h"
+#include "proxy.h"
+#include "socks.h"
+#include "sshcr.h"
+
+typedef struct Socks4ProxyNegotiator {
+ int crLine;
+ ProxyNegotiator pn;
+} Socks4ProxyNegotiator;
+
+static ProxyNegotiator *proxy_socks4_new(const ProxyNegotiatorVT *vt)
+{
+ Socks4ProxyNegotiator *s = snew(Socks4ProxyNegotiator);
+ s->pn.vt = vt;
+ s->crLine = 0;
+ return &s->pn;
+}
+
+static void proxy_socks4_free(ProxyNegotiator *pn)
+{
+ Socks4ProxyNegotiator *s = container_of(pn, Socks4ProxyNegotiator, pn);
+ sfree(s);
+}
+
+static void proxy_socks4_process_queue(ProxyNegotiator *pn)
+{
+ Socks4ProxyNegotiator *s = container_of(pn, Socks4ProxyNegotiator, pn);
+
+ crBegin(s->crLine);
+
+ {
+ char hostname[512];
+ bool write_hostname = false;
+
+ /*
+ * SOCKS 4 request packet:
+ *
+ * byte version
+ * byte command
+ * uint16 destination port number
+ * uint32 destination IPv4 address (or something in the
+ * SOCKS4A_NAME_FOLLOWS range)
+ * asciz username
+ * asciz destination hostname (if we sent SOCKS4A_NAME_FOLLOWS_*)
+ */
+
+ put_byte(pn->output, SOCKS4_REQUEST_VERSION);
+ put_byte(pn->output, SOCKS_CMD_CONNECT);
+ put_uint16(pn->output, pn->ps->remote_port);
+
+ switch (sk_addrtype(pn->ps->remote_addr)) {
+ case ADDRTYPE_IPV4: {
+ char addr[4];
+ sk_addrcopy(pn->ps->remote_addr, addr);
+ put_data(pn->output, addr, 4);
+ break;
+ }
+ case ADDRTYPE_NAME:
+ put_uint32(pn->output, SOCKS4A_NAME_FOLLOWS_BASE);
+ sk_getaddr(pn->ps->remote_addr, hostname, lenof(hostname));
+ write_hostname = true;
+ break;
+ case ADDRTYPE_IPV6:
+ pn->error = dupstr("SOCKS version 4 does not support IPv6");
+ crStopV;
+ }
+
+ put_asciz(pn->output, conf_get_str(pn->ps->conf, CONF_proxy_username));
+
+ if (write_hostname)
+ put_asciz(pn->output, hostname);
+ }
+
+ crReturnV;
+
+ {
+ unsigned char data[8];
+ crMaybeWaitUntilV(bufchain_try_fetch_consume(pn->input, data, 8));
+
+ /*
+ * SOCKS 4 response packet:
+ *
+ * byte version
+ * byte status
+ * uint16 port number
+ * uint32 IPv4 address
+ *
+ * We don't need to worry about the port and destination address.
+ */
+
+ if (data[0] != SOCKS4_REPLY_VERSION) {
+ pn->error = dupprintf("SOCKS proxy response contained reply "
+ "version number %d (expected 0)",
+ (int)data[0]);
+ crStopV;
+ }
+
+ switch (data[1]) {
+ case SOCKS4_RESP_SUCCESS:
+ pn->done = true;
+ break;
+
+ case SOCKS4_RESP_FAILURE:
+ pn->error = dupstr("SOCKS server reported failure to connect");
+ break;
+
+ case SOCKS4_RESP_WANT_IDENTD:
+ pn->error = dupstr("SOCKS server wanted IDENTD on client");
+ break;
+
+ case SOCKS4_RESP_IDENTD_MISMATCH:
+ pn->error = dupstr("Username and IDENTD on client don't agree");
+ break;
+
+ default:
+ pn->error = dupprintf("SOCKS server sent unrecognised error "
+ "code %d", (int)data[1]);
+ break;
+ }
+ crStopV;
+ }
+
+ crFinishV;
+}
+
+const struct ProxyNegotiatorVT socks4_proxy_negotiator_vt = {
+ .new = proxy_socks4_new,
+ .free = proxy_socks4_free,
+ .process_queue = proxy_socks4_process_queue,
+ .type = "SOCKS 4",
+};