1
0
mirror of https://github.com/winscp/winscp.git synced 2026-10-24 02:28:55 +03:00
Files
winscp/source/putty/proxy/socks4.c
Martin Prikryl f670f4ebb1 Resetting differences to official PuTTY that are no longer needed
Most, if not all, were for compatibility with the classic C++Builder compiler (declarations in the middle of code + inline structure initializers)

Source commit: a9f38c3a07777e538c3c6e0fbdd38e9d68327dfa
2025-12-06 01:29:35 +01:00

137 lines
3.8 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",
};