1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 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 %d)",
(int)data[0], SOCKS4_REPLY_VERSION);
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",
};
|