1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 01:18:00 +00:00
putty-source/proxy/socks4.c
Simon Tatham 963aebc260 Tiny fixes in the SOCKS proxy code.
Just happened to jump out at me in an eyeball inspection just now. I
carefully moved all the protocol byte-value constants into a header
file with mnemonic names, but I still hard-coded SOCKS4_REPLY_VERSION
in the text of one diagnostic, and I got the wrong one of
SOCKS5_REQUEST_VERSION and SOCKS5_REPLY_VERSION at one point in the
code. Both benign (the right value was there, juste called by the
wrong name).

Also fixed some missing whitespace, in passing. (Probably the line it
was missing from had once been squashed up closer to the right margin.)

(cherry picked from commit 1cd0f1787f)
2023-11-18 09:11:33 +00:00

137 lines
3.7 KiB
C

/*
* 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",
};