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