mirror of
https://github.com/winscp/winscp.git
synced 2026-10-24 02:28:55 +03:00
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
137 lines
3.8 KiB
C
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",
|
|
};
|