mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
Justin Bradford's proxy support patch. Currently supports only HTTP
CONNECT, but contains an extensible framework to allow other proxies. Apparently SOCKS and ad-hoc-telnet-proxy are already planned (the GUI mentions them already even though they don't work yet). GUI includes full configurability and allows definition of exclusion zones. Rock and roll. [originally from svn r1598]
This commit is contained in:
parent
869989e7e6
commit
eabd704d1e
9
Makefile
9
Makefile
@ -96,7 +96,7 @@ GOBJS1 = window.$(OBJ) windlg.$(OBJ) winctrls.$(OBJ) terminal.$(OBJ)
|
||||
GOBJS2 = sizetip.$(OBJ) wcwidth.$(OBJ) unicode.$(OBJ) logging.$(OBJ)
|
||||
GOBJS3 = printing.$(OBJ)
|
||||
##-- objects putty puttytel plink
|
||||
LOBJS1 = telnet.$(OBJ) raw.$(OBJ) rlogin.$(OBJ) ldisc.$(OBJ) winnet.$(OBJ)
|
||||
LOBJS1 = telnet.$(OBJ) raw.$(OBJ) rlogin.$(OBJ) ldisc.$(OBJ) winnet.$(OBJ) proxy.$(OBJ)
|
||||
##-- objects putty plink
|
||||
POBJS = be_all.$(OBJ)
|
||||
##-- objects puttytel
|
||||
@ -104,9 +104,9 @@ TOBJS = be_nossh.$(OBJ)
|
||||
##-- objects plink
|
||||
PLOBJS = plink.$(OBJ) logging.$(OBJ)
|
||||
##-- objects pscp
|
||||
SOBJS = scp.$(OBJ) winnet.$(OBJ) be_none.$(OBJ) wildcard.$(OBJ)
|
||||
SOBJS = scp.$(OBJ) winnet.$(OBJ) proxy.$(OBJ) be_none.$(OBJ) wildcard.$(OBJ)
|
||||
##-- objects psftp
|
||||
FOBJS = psftp.$(OBJ) winnet.$(OBJ) be_none.$(OBJ)
|
||||
FOBJS = psftp.$(OBJ) winnet.$(OBJ) proxy.$(OBJ) be_none.$(OBJ)
|
||||
##-- objects pscp psftp
|
||||
SFOBJS = sftp.$(OBJ) int64.$(OBJ) logging.$(OBJ)
|
||||
##-- objects putty puttytel pscp psftp plink
|
||||
@ -303,7 +303,8 @@ pageantc.$(OBJ): pageantc.c puttymem.h
|
||||
plink.$(OBJ): plink.c network.h misc.h puttymem.h storage.h putty.h tree234.h
|
||||
portfwd.$(OBJ): portfwd.c network.h misc.h puttymem.h int64.h ssh.h putty.h
|
||||
printing.$(OBJ): printing.c network.h misc.h puttymem.h putty.h
|
||||
psftp.$(OBJ): psftp.c network.h misc.h sftp.h ssh.h storage.h int64.h puttymem.h putty.h
|
||||
proxy.$(OBJ): proxy.c proxy.h network.h
|
||||
psftp.$(OBJ): psftp.c network.h misc.h sftp.h ssh.h storage.h int64.h puttymem.h putty.h
|
||||
puttygen.$(OBJ): puttygen.c network.h misc.h puttymem.h int64.h winstuff.h ssh.h putty.h
|
||||
raw.$(OBJ): raw.c network.h misc.h puttymem.h putty.h
|
||||
rlogin.$(OBJ): rlogin.c network.h misc.h puttymem.h putty.h
|
||||
|
2
Recipe
2
Recipe
@ -105,7 +105,7 @@ SFTP = sftp int64 logging
|
||||
|
||||
# Miscellaneous objects appearing in all the network utilities (not
|
||||
# Pageant or PuTTYgen).
|
||||
MISC = misc version winstore settings tree234 winnet
|
||||
MISC = misc version winstore settings tree234 winnet proxy
|
||||
|
||||
# Standard libraries, and the same with WinSocks 1 and 2.
|
||||
LIBS = advapi32.lib user32.lib gdi32.lib comctl32.lib comdlg32.lib
|
||||
|
16
network.h
16
network.h
@ -27,6 +27,9 @@ struct socket_function_table {
|
||||
int (*write) (Socket s, char *data, int len);
|
||||
int (*write_oob) (Socket s, char *data, int len);
|
||||
void (*flush) (Socket s);
|
||||
void (*set_private_ptr) (Socket s, void *ptr);
|
||||
void *(*get_private_ptr) (Socket s);
|
||||
void (*set_frozen) (Socket s, int is_frozen);
|
||||
/* ignored by tcp, but vital for ssl */
|
||||
char *(*socket_error) (Socket s);
|
||||
};
|
||||
@ -60,6 +63,13 @@ struct plug_function_table {
|
||||
*/
|
||||
};
|
||||
|
||||
/* proxy indirection layer */
|
||||
Socket new_connection(SockAddr addr, char *hostname,
|
||||
int port, int privport,
|
||||
int oobinline, int nodelay, Plug plug);
|
||||
Socket new_listener(int port, Plug plug, int local_host_only);
|
||||
|
||||
/* socket functions */
|
||||
|
||||
void sk_init(void); /* called once at program startup */
|
||||
void sk_cleanup(void); /* called just before program exit */
|
||||
@ -95,8 +105,8 @@ Socket sk_register(void *sock, Plug plug);
|
||||
* This is perhaps unnecessary now that we have the notion of a plug,
|
||||
* but there is some existing code that uses it, so it stays.
|
||||
*/
|
||||
void sk_set_private_ptr(Socket s, void *ptr);
|
||||
void *sk_get_private_ptr(Socket s);
|
||||
#define sk_set_private_ptr(s, ptr) (((*s)->set_private_ptr) (s, ptr))
|
||||
#define sk_get_private_ptr(s) (((*s)->get_private_ptr) (s))
|
||||
|
||||
/*
|
||||
* Special error values are returned from sk_namelookup and sk_new
|
||||
@ -123,7 +133,7 @@ char *sk_addr_error(SockAddr addr);
|
||||
* associated local socket in order to avoid unbounded buffer
|
||||
* growth.
|
||||
*/
|
||||
void sk_set_frozen(Socket sock, int is_frozen);
|
||||
#define sk_set_frozen(s, is_frozen) (((*s)->set_frozen) (s, is_frozen))
|
||||
|
||||
/*
|
||||
* Call this after an operation that might have tried to send on a
|
||||
|
@ -138,7 +138,7 @@ char *pfd_newconnect(Socket *s, char *hostname, int port, void *c)
|
||||
pr->ready = 1;
|
||||
pr->c = c;
|
||||
|
||||
pr->s = *s = sk_new(addr, port, 0, 1, 0, (Plug) pr);
|
||||
pr->s = *s = new_connection(addr, dummy_realhost, port, 0, 1, 0, (Plug) pr);
|
||||
if ((err = sk_socket_error(*s))) {
|
||||
sfree(pr);
|
||||
return err;
|
||||
@ -227,7 +227,7 @@ char *pfd_addforward(char *desthost, int destport, int port)
|
||||
pr->ready = 0;
|
||||
pr->waiting = NULL;
|
||||
|
||||
pr->s = s = sk_newlistener(port, (Plug) pr, !cfg.lport_acceptall);
|
||||
pr->s = s = new_listener(port, (Plug) pr, !cfg.lport_acceptall);
|
||||
if ((err = sk_socket_error(s))) {
|
||||
sfree(pr);
|
||||
return err;
|
||||
|
594
proxy.c
Normal file
594
proxy.c
Normal file
@ -0,0 +1,594 @@
|
||||
/*
|
||||
* Network proxy abstraction in PuTTY
|
||||
*
|
||||
* A proxy layer, if necessary, wedges itself between the network
|
||||
* code and the higher level backend.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#define DEFINE_PLUG_METHOD_MACROS
|
||||
#include "putty.h"
|
||||
#include "network.h"
|
||||
#include "proxy.h"
|
||||
|
||||
/*
|
||||
* Call this when proxy negotiation is complete, so that this
|
||||
* socket can begin working normally.
|
||||
*/
|
||||
void proxy_activate (Proxy_Socket p)
|
||||
{
|
||||
void *data;
|
||||
int len;
|
||||
|
||||
p->lock_close =
|
||||
p->lock_write =
|
||||
p->lock_write_oob =
|
||||
p->lock_receive =
|
||||
p->lock_flush =
|
||||
p->lock_closing =
|
||||
p->lock_sent =
|
||||
p->lock_accepting =
|
||||
p->lock_freeze = 1;
|
||||
|
||||
p->state = PROXY_STATE_ACTIVE;
|
||||
|
||||
/* let's try to keep extra receive events from coming through */
|
||||
sk_set_frozen(p->sub_socket, 1);
|
||||
|
||||
while (bufchain_size(&p->pending_oob_output_data) > 0) {
|
||||
bufchain_prefix(&p->pending_oob_output_data, &data, &len);
|
||||
sk_write_oob(p->sub_socket, data, len);
|
||||
bufchain_consume(&p->pending_oob_output_data, len);
|
||||
}
|
||||
bufchain_clear(&p->pending_oob_output_data);
|
||||
|
||||
while (bufchain_size(&p->pending_output_data) > 0) {
|
||||
bufchain_prefix(&p->pending_output_data, &data, &len);
|
||||
sk_write(p->sub_socket, data, len);
|
||||
bufchain_consume(&p->pending_output_data, len);
|
||||
}
|
||||
bufchain_clear(&p->pending_output_data);
|
||||
|
||||
p->lock_write_oob = 0;
|
||||
p->lock_write = 0;
|
||||
|
||||
if (p->pending_flush) sk_flush(p->sub_socket);
|
||||
p->lock_flush = 0;
|
||||
|
||||
while (bufchain_size(&p->pending_input_data) > 0) {
|
||||
bufchain_prefix(&p->pending_input_data, &data, &len);
|
||||
plug_receive(p->plug, 0, data, len);
|
||||
bufchain_consume(&p->pending_input_data, len);
|
||||
}
|
||||
bufchain_clear(&p->pending_input_data);
|
||||
p->lock_receive = 0;
|
||||
|
||||
/* now set the underlying socket to whatever freeze state they wanted */
|
||||
sk_set_frozen(p->sub_socket, p->freeze);
|
||||
p->lock_freeze = 0;
|
||||
|
||||
p->lock_sent = 0;
|
||||
p->lock_accepting = 0;
|
||||
p->lock_closing = 0;
|
||||
p->lock_close = 0;
|
||||
}
|
||||
|
||||
/* basic proxy socket functions */
|
||||
|
||||
static Plug sk_proxy_plug (Socket s, Plug p)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
Plug ret = ps->plug;
|
||||
if (p)
|
||||
ps->plug = p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void sk_proxy_close (Socket s)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
|
||||
while (ps->lock_close) ;
|
||||
sk_close(ps->sub_socket);
|
||||
sfree(ps);
|
||||
}
|
||||
|
||||
static int sk_proxy_write (Socket s, char *data, int len)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
|
||||
while (ps->lock_write) ;
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
bufchain_add(&ps->pending_output_data, data, len);
|
||||
return bufchain_size(&ps->pending_output_data);
|
||||
}
|
||||
return sk_write(ps->sub_socket, data, len);
|
||||
}
|
||||
|
||||
static int sk_proxy_write_oob (Socket s, char *data, int len)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
|
||||
while (ps->lock_write_oob) ;
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
bufchain_clear(&ps->pending_output_data);
|
||||
bufchain_clear(&ps->pending_oob_output_data);
|
||||
bufchain_add(&ps->pending_oob_output_data, data, len);
|
||||
return len;
|
||||
}
|
||||
return sk_write_oob(ps->sub_socket, data, len);
|
||||
}
|
||||
|
||||
static void sk_proxy_flush (Socket s)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
|
||||
while (ps->lock_flush) ;
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
ps->pending_flush = 1;
|
||||
return;
|
||||
}
|
||||
sk_flush(ps->sub_socket);
|
||||
}
|
||||
|
||||
static void sk_proxy_set_private_ptr (Socket s, void *ptr)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
sk_set_private_ptr(ps->sub_socket, ptr);
|
||||
}
|
||||
|
||||
static void * sk_proxy_get_private_ptr (Socket s)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
return sk_get_private_ptr(ps->sub_socket);
|
||||
}
|
||||
|
||||
static void sk_proxy_set_frozen (Socket s, int is_frozen)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
|
||||
while (ps->lock_freeze) ;
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
ps->freeze = is_frozen;
|
||||
return;
|
||||
}
|
||||
sk_set_frozen(ps->sub_socket, is_frozen);
|
||||
}
|
||||
|
||||
static char * sk_proxy_socket_error (Socket s)
|
||||
{
|
||||
Proxy_Socket ps = (Proxy_Socket) s;
|
||||
if (ps->error != NULL || ps->sub_socket == NULL) {
|
||||
return ps->error;
|
||||
}
|
||||
return sk_socket_error(ps->sub_socket);
|
||||
}
|
||||
|
||||
/* basic proxy plug functions */
|
||||
|
||||
static int plug_proxy_closing (Plug p, char *error_msg,
|
||||
int error_code, int calling_back)
|
||||
{
|
||||
Proxy_Plug pp = (Proxy_Plug) p;
|
||||
Proxy_Socket ps = pp->proxy_socket;
|
||||
|
||||
while (ps->lock_closing) ;
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
ps->closing_error_msg = error_msg;
|
||||
ps->closing_error_code = error_code;
|
||||
ps->closing_calling_back = calling_back;
|
||||
return ps->negotiate(ps, PROXY_CHANGE_CLOSING);
|
||||
}
|
||||
return plug_closing(ps->plug, error_msg,
|
||||
error_code, calling_back);
|
||||
}
|
||||
|
||||
static int plug_proxy_receive (Plug p, int urgent, char *data, int len)
|
||||
{
|
||||
Proxy_Plug pp = (Proxy_Plug) p;
|
||||
Proxy_Socket ps = pp->proxy_socket;
|
||||
|
||||
while (ps->lock_receive) ;
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
/* we will lose the urgentness of this data, but since most,
|
||||
* if not all, of this data will be consumed by the negotiation
|
||||
* process, hopefully it won't affect the protocol above us
|
||||
*/
|
||||
bufchain_add(&ps->pending_input_data, data, len);
|
||||
ps->receive_urgent = urgent;
|
||||
ps->receive_data = data;
|
||||
ps->receive_len = len;
|
||||
return ps->negotiate(ps, PROXY_CHANGE_RECEIVE);
|
||||
}
|
||||
return plug_receive(ps->plug, urgent, data, len);
|
||||
}
|
||||
|
||||
static void plug_proxy_sent (Plug p, int bufsize)
|
||||
{
|
||||
Proxy_Plug pp = (Proxy_Plug) p;
|
||||
Proxy_Socket ps = pp->proxy_socket;
|
||||
|
||||
while (ps->lock_sent) ;
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
ps->sent_bufsize = bufsize;
|
||||
ps->negotiate(ps, PROXY_CHANGE_SENT);
|
||||
return;
|
||||
}
|
||||
plug_sent(ps->plug, bufsize);
|
||||
}
|
||||
|
||||
static int plug_proxy_accepting (Plug p, void *sock)
|
||||
{
|
||||
Proxy_Plug pp = (Proxy_Plug) p;
|
||||
Proxy_Socket ps = pp->proxy_socket;
|
||||
|
||||
while (ps->lock_accepting) ;
|
||||
if (ps->state != PROXY_STATE_ACTIVE) {
|
||||
ps->accepting_sock = sock;
|
||||
return ps->negotiate(ps, PROXY_CHANGE_ACCEPTING);
|
||||
}
|
||||
return plug_accepting(ps->plug, sock);
|
||||
}
|
||||
|
||||
static int proxy_for_destination (SockAddr addr, char * hostname, int port)
|
||||
{
|
||||
int s = 0, e = 0;
|
||||
char hostip[64];
|
||||
int hostip_len, hostname_len;
|
||||
char * exclude_list;
|
||||
|
||||
/* we want a string representation of the IP address for comparisons */
|
||||
sk_getaddr(addr, hostip, 64);
|
||||
|
||||
hostip_len = strlen(hostip);
|
||||
hostname_len = strlen(hostname);
|
||||
|
||||
exclude_list = cfg.proxy_exclude_list;
|
||||
|
||||
/* now parse the exclude list, and see if either our IP
|
||||
* or hostname matches anything in it.
|
||||
*/
|
||||
|
||||
while (exclude_list[s]) {
|
||||
while (exclude_list[s] &&
|
||||
(isspace(exclude_list[s]) ||
|
||||
exclude_list[s] == ',')) s++;
|
||||
|
||||
if (!exclude_list[s]) break;
|
||||
|
||||
e = s;
|
||||
|
||||
while (exclude_list[e] &&
|
||||
(isalnum(exclude_list[e]) ||
|
||||
exclude_list[e] == '-' ||
|
||||
exclude_list[e] == '.' ||
|
||||
exclude_list[e] == '*')) e++;
|
||||
|
||||
if (exclude_list[s] == '*') {
|
||||
/* wildcard at beginning of entry */
|
||||
|
||||
if (strnicmp(hostip + hostip_len - (e - s - 1),
|
||||
exclude_list + s + 1, e - s - 1) == 0 ||
|
||||
strnicmp(hostname + hostname_len - (e - s - 1),
|
||||
exclude_list + s + 1, e - s - 1) == 0)
|
||||
return 0; /* IP/hostname range excluded. do not use proxy. */
|
||||
|
||||
} else if (exclude_list[e-1] == '*') {
|
||||
/* wildcard at end of entry */
|
||||
|
||||
if (strnicmp(hostip, exclude_list + s, e - s - 1) == 0 ||
|
||||
strnicmp(hostname, exclude_list + s, e - s - 1) == 0)
|
||||
return 0; /* IP/hostname range excluded. do not use proxy. */
|
||||
|
||||
} else {
|
||||
/* no wildcard at either end, so let's try an absolute
|
||||
* match (ie. a specific IP)
|
||||
*/
|
||||
|
||||
if (stricmp(hostip, exclude_list + s) == 0)
|
||||
return 0; /* IP/hostname excluded. do not use proxy. */
|
||||
if (stricmp(hostname, exclude_list + s) == 0)
|
||||
return 0; /* IP/hostname excluded. do not use proxy. */
|
||||
}
|
||||
|
||||
s = e;
|
||||
}
|
||||
|
||||
/* no matches in the exclude list, so use the proxy */
|
||||
return 1;
|
||||
}
|
||||
|
||||
Socket new_connection(SockAddr addr, char *hostname,
|
||||
int port, int privport,
|
||||
int oobinline, int nodelay, Plug plug)
|
||||
{
|
||||
static struct socket_function_table socket_fn_table = {
|
||||
sk_proxy_plug,
|
||||
sk_proxy_close,
|
||||
sk_proxy_write,
|
||||
sk_proxy_write_oob,
|
||||
sk_proxy_flush,
|
||||
sk_proxy_set_private_ptr,
|
||||
sk_proxy_get_private_ptr,
|
||||
sk_proxy_set_frozen,
|
||||
sk_proxy_socket_error
|
||||
};
|
||||
|
||||
static struct plug_function_table plug_fn_table = {
|
||||
plug_proxy_closing,
|
||||
plug_proxy_receive,
|
||||
plug_proxy_sent,
|
||||
plug_proxy_accepting
|
||||
};
|
||||
|
||||
if (cfg.proxy_type != PROXY_NONE &&
|
||||
proxy_for_destination(addr, hostname, port))
|
||||
{
|
||||
Proxy_Socket ret;
|
||||
Proxy_Plug pplug;
|
||||
SockAddr proxy_addr;
|
||||
char * proxy_canonical_name;
|
||||
|
||||
ret = smalloc(sizeof(struct Socket_proxy_tag));
|
||||
ret->fn = &socket_fn_table;
|
||||
ret->plug = plug;
|
||||
ret->remote_addr = addr;
|
||||
ret->remote_port = port;
|
||||
|
||||
bufchain_init(&ret->pending_input_data);
|
||||
bufchain_init(&ret->pending_output_data);
|
||||
bufchain_init(&ret->pending_oob_output_data);
|
||||
|
||||
ret->lock_close =
|
||||
ret->lock_write =
|
||||
ret->lock_write_oob =
|
||||
ret->lock_receive =
|
||||
ret->lock_flush =
|
||||
ret->lock_closing =
|
||||
ret->lock_sent =
|
||||
ret->lock_accepting = 0;
|
||||
|
||||
ret->sub_socket = NULL;
|
||||
ret->state = PROXY_STATE_NEW;
|
||||
|
||||
if (cfg.proxy_type == PROXY_HTTP) {
|
||||
ret->negotiate = proxy_http_negotiate;
|
||||
} else if (cfg.proxy_type == PROXY_SOCKS) {
|
||||
ret->negotiate = proxy_socks_negotiate;
|
||||
} else if (cfg.proxy_type == PROXY_TELNET) {
|
||||
ret->negotiate = proxy_telnet_negotiate;
|
||||
} else {
|
||||
ret->error = "Network error: Unknown proxy method";
|
||||
return (Socket) ret;
|
||||
}
|
||||
|
||||
/* create the proxy plug to map calls from the actual
|
||||
* socket into our proxy socket layer */
|
||||
pplug = smalloc(sizeof(struct Plug_proxy_tag));
|
||||
pplug->fn = &plug_fn_table;
|
||||
pplug->proxy_socket = ret;
|
||||
|
||||
/* look-up proxy */
|
||||
proxy_addr = sk_namelookup(cfg.proxy_host,
|
||||
&proxy_canonical_name);
|
||||
sfree(proxy_canonical_name);
|
||||
|
||||
/* create the actual socket we will be using,
|
||||
* connected to our proxy server and port.
|
||||
*/
|
||||
ret->sub_socket = sk_new(proxy_addr, cfg.proxy_port,
|
||||
privport, oobinline,
|
||||
nodelay, (Plug) pplug);
|
||||
if (sk_socket_error(ret->sub_socket) != NULL)
|
||||
return (Socket) ret;
|
||||
|
||||
sk_addr_free(proxy_addr);
|
||||
|
||||
/* start the proxy negotiation process... */
|
||||
sk_set_frozen(ret->sub_socket, 0);
|
||||
ret->negotiate(ret, PROXY_CHANGE_NEW);
|
||||
|
||||
return (Socket) ret;
|
||||
}
|
||||
|
||||
/* no proxy, so just return the direct socket */
|
||||
return sk_new(addr, port, privport, oobinline, nodelay, plug);
|
||||
}
|
||||
|
||||
Socket new_listener(int port, Plug plug, int local_host_only)
|
||||
{
|
||||
/* TODO: SOCKS (and potentially others) support inbound
|
||||
* TODO: connections via the proxy. support them.
|
||||
*/
|
||||
|
||||
return sk_newlistener(port, plug, local_host_only);
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* HTTP CONNECT proxy type.
|
||||
*/
|
||||
|
||||
static int get_line_end (char * data, int len)
|
||||
{
|
||||
int off = 0;
|
||||
|
||||
while (off < len)
|
||||
{
|
||||
if (data[off] == '\n') {
|
||||
/* we have a newline */
|
||||
off++;
|
||||
|
||||
/* is that the only thing on this line? */
|
||||
if (off <= 2) return off;
|
||||
|
||||
/* if not, then there is the possibility that this header
|
||||
* continues onto the next line, if it starts with a space
|
||||
* or a tab.
|
||||
*/
|
||||
|
||||
if (off + 1 < len &&
|
||||
data[off+1] != ' ' &&
|
||||
data[off+1] != '\t') return off;
|
||||
|
||||
/* the line does continue, so we have to keep going
|
||||
* until we see an the header's "real" end of line.
|
||||
*/
|
||||
off++;
|
||||
}
|
||||
|
||||
off++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int proxy_http_negotiate (Proxy_Socket p, int change)
|
||||
{
|
||||
if (p->state == PROXY_STATE_NEW) {
|
||||
/* we are just beginning the proxy negotiate process,
|
||||
* so we'll send off the initial bits of the request.
|
||||
* for this proxy method, it's just a simple HTTP
|
||||
* request
|
||||
*/
|
||||
char buf[1024], dest[21];
|
||||
|
||||
sk_getaddr(p->remote_addr, dest, 20);
|
||||
|
||||
sprintf(buf, "CONNECT %s:%i HTTP/1.1\r\nHost: %s:%i\r\n\r\n",
|
||||
dest, p->remote_port, dest, p->remote_port);
|
||||
sk_write(p->sub_socket, buf, strlen(buf));
|
||||
|
||||
p->state = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (change == PROXY_CHANGE_CLOSING) {
|
||||
/* if our proxy negotiation process involves closing and opening
|
||||
* new sockets, then we would want to intercept this closing
|
||||
* callback when we were expecting it. if we aren't anticipating
|
||||
* a socket close, then some error must have occurred. we'll
|
||||
* just pass those errors up to the backend.
|
||||
*/
|
||||
return plug_closing(p->plug, p->closing_error_msg,
|
||||
p->closing_error_code,
|
||||
p->closing_calling_back);
|
||||
}
|
||||
|
||||
if (change == PROXY_CHANGE_SENT) {
|
||||
/* some (or all) of what we wrote to the proxy was sent.
|
||||
* we don't do anything new, however, until we receive the
|
||||
* proxy's response. we might want to set a timer so we can
|
||||
* timeout the proxy negotiation after a while...
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (change == PROXY_CHANGE_ACCEPTING) {
|
||||
/* we should _never_ see this, as we are using our socket to
|
||||
* connect to a proxy, not accepting inbound connections.
|
||||
* what should we do? close the socket with an appropriate
|
||||
* error message?
|
||||
*/
|
||||
return plug_accepting(p->plug, p->accepting_sock);
|
||||
}
|
||||
|
||||
if (change == PROXY_CHANGE_RECEIVE) {
|
||||
/* we have received data from the underlying socket, which
|
||||
* we'll need to parse, process, and respond to appropriately.
|
||||
*/
|
||||
|
||||
void *data;
|
||||
int len;
|
||||
int eol;
|
||||
|
||||
if (p->state == 1) {
|
||||
|
||||
int min_ver, maj_ver, status;
|
||||
|
||||
/* get the status line */
|
||||
bufchain_prefix(&p->pending_input_data, &data, &len);
|
||||
eol = get_line_end(data, len);
|
||||
if (eol < 0) return 1;
|
||||
|
||||
sscanf((char *)data, "HTTP/%i.%i %i", &maj_ver, &min_ver, &status);
|
||||
|
||||
/* remove the status line from the input buffer. */
|
||||
bufchain_consume(&p->pending_input_data, eol);
|
||||
|
||||
/* TODO: we need to support Proxy-Auth headers */
|
||||
|
||||
if (status < 200 || status > 299) {
|
||||
/* error */
|
||||
/* TODO: return a more specific error message,
|
||||
* TODO: based on the status code.
|
||||
*/
|
||||
plug_closing(p->plug, "Network error: Error while communicating with proxy",
|
||||
PROXY_ERROR_GENERAL, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
p->state = 2;
|
||||
}
|
||||
|
||||
if (p->state == 2) {
|
||||
|
||||
/* get headers. we're done when we get a
|
||||
* header of length 2, (ie. just "\r\n")
|
||||
*/
|
||||
|
||||
bufchain_prefix(&p->pending_input_data, &data, &len);
|
||||
eol = get_line_end(data, len);
|
||||
while (eol > 2)
|
||||
{
|
||||
/* TODO: Proxy-Auth stuff. in some cases, we will
|
||||
* TODO: need to extract information from headers.
|
||||
*/
|
||||
bufchain_consume(&p->pending_input_data, eol);
|
||||
bufchain_prefix(&p->pending_input_data, &data, &len);
|
||||
eol = get_line_end(data, len);
|
||||
}
|
||||
|
||||
if (eol == 2) {
|
||||
/* we're done */
|
||||
bufchain_consume(&p->pending_input_data, 2);
|
||||
proxy_activate(p);
|
||||
/* proxy activate will have dealt with
|
||||
* whatever is left of the buffer */
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
plug_closing(p->plug, "Network error: Unexpected proxy error",
|
||||
PROXY_ERROR_UNEXPECTED, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* SOCKS proxy type (as yet unimplemented).
|
||||
*/
|
||||
|
||||
int proxy_socks_negotiate (Proxy_Socket p, int change)
|
||||
{
|
||||
p->error = "Network error: SOCKS proxy implementation is incomplete";
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------------------
|
||||
* `Telnet' proxy type (as yet unimplemented).
|
||||
*
|
||||
* (This is for ad-hoc proxies where you connect to the proxy's
|
||||
* telnet port and send a command such as `connect host port'. The
|
||||
* command is configurable, since this proxy type is typically not
|
||||
* standardised or at all well-defined.)
|
||||
*/
|
||||
|
||||
int proxy_telnet_negotiate (Proxy_Socket p, int change)
|
||||
{
|
||||
p->error = "Network error: Telnet proxy implementation is incomplete";
|
||||
return 0;
|
||||
}
|
119
proxy.h
Normal file
119
proxy.h
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
* Network proxy abstraction in PuTTY
|
||||
*
|
||||
* A proxy layer, if necessary, wedges itself between the
|
||||
* network code and the higher level backend.
|
||||
*
|
||||
* Supported proxies: HTTP CONNECT, generic telnet
|
||||
* In progress: SOCKS
|
||||
*/
|
||||
|
||||
#ifndef PUTTY_PROXY_H
|
||||
#define PUTTY_PROXY_H
|
||||
|
||||
#define PROXY_ERROR_GENERAL 8000
|
||||
#define PROXY_ERROR_UNEXPECTED 8001
|
||||
|
||||
typedef struct Socket_proxy_tag * Proxy_Socket;
|
||||
|
||||
struct Socket_proxy_tag {
|
||||
struct socket_function_table *fn;
|
||||
/* the above variable absolutely *must* be the first in this structure */
|
||||
|
||||
char * error;
|
||||
|
||||
Socket sub_socket;
|
||||
Plug plug;
|
||||
SockAddr remote_addr;
|
||||
int remote_port;
|
||||
|
||||
bufchain pending_output_data;
|
||||
bufchain pending_oob_output_data;
|
||||
int pending_flush;
|
||||
bufchain pending_input_data;
|
||||
|
||||
#define PROXY_STATE_NEW -1
|
||||
#define PROXY_STATE_ACTIVE 0
|
||||
|
||||
int state; /* proxy states greater than 0 are implementation
|
||||
* dependent, but represent various stages/states
|
||||
* of the initialization/setup/negotiation with the
|
||||
* proxy server.
|
||||
*/
|
||||
int freeze; /* should we freeze the underlying socket when
|
||||
* we are done with the proxy negotiation? this
|
||||
* simply caches the value of sk_set_frozen calls.
|
||||
*/
|
||||
|
||||
#define PROXY_CHANGE_NEW -1
|
||||
#define PROXY_CHANGE_CLOSING 0
|
||||
#define PROXY_CHANGE_SENT 1
|
||||
#define PROXY_CHANGE_RECEIVE 2
|
||||
#define PROXY_CHANGE_ACCEPTING 3
|
||||
|
||||
/* something has changed (a call from the sub socket
|
||||
* layer into our Proxy Plug layer, or we were just
|
||||
* created, etc), so the proxy layer needs to handle
|
||||
* this change (the type of which is the second argument)
|
||||
* and further the proxy negotiation process.
|
||||
*/
|
||||
|
||||
int (*negotiate) (Proxy_Socket /* this */, int /* change type */);
|
||||
|
||||
/* current arguments of plug handlers
|
||||
* (for use by proxy's negotiate function)
|
||||
*/
|
||||
|
||||
/* closing */
|
||||
char *closing_error_msg;
|
||||
int closing_error_code;
|
||||
int closing_calling_back;
|
||||
|
||||
/* receive */
|
||||
int receive_urgent;
|
||||
char *receive_data;
|
||||
int receive_len;
|
||||
|
||||
/* sent */
|
||||
int sent_bufsize;
|
||||
|
||||
/* accepting */
|
||||
void *accepting_sock;
|
||||
|
||||
/* spin locks, for the critical switch from negotiating
|
||||
* to active state. we have to dump all of our pending
|
||||
* buffers without new events (read, writes, etc) corrupting
|
||||
* things. we should not have built up a large amount of
|
||||
* pending data during negotiation, so hopefully this will
|
||||
* not have a large effect on performance.
|
||||
*/
|
||||
|
||||
char lock_close;
|
||||
char lock_write;
|
||||
char lock_write_oob;
|
||||
char lock_receive;
|
||||
char lock_flush;
|
||||
char lock_closing;
|
||||
char lock_sent;
|
||||
char lock_accepting;
|
||||
char lock_freeze;
|
||||
|
||||
};
|
||||
|
||||
typedef struct Plug_proxy_tag * Proxy_Plug;
|
||||
|
||||
struct Plug_proxy_tag {
|
||||
struct plug_function_table *fn;
|
||||
/* the above variable absolutely *must* be the first in this structure */
|
||||
|
||||
Proxy_Socket proxy_socket;
|
||||
|
||||
};
|
||||
|
||||
extern void proxy_activate (Proxy_Socket);
|
||||
|
||||
extern int proxy_http_negotiate (Proxy_Socket, int);
|
||||
extern int proxy_telnet_negotiate (Proxy_Socket, int);
|
||||
extern int proxy_socks_negotiate (Proxy_Socket, int);
|
||||
|
||||
#endif
|
9
putty.h
9
putty.h
@ -242,6 +242,15 @@ typedef struct {
|
||||
int warn_on_close;
|
||||
int ping_interval; /* in seconds */
|
||||
int tcp_nodelay;
|
||||
/* Proxy options */
|
||||
char proxy_exclude_list[512];
|
||||
enum { PROXY_NONE, PROXY_HTTP, PROXY_SOCKS, PROXY_TELNET } proxy_type;
|
||||
char proxy_host[512];
|
||||
int proxy_port;
|
||||
char proxy_username[32];
|
||||
char proxy_password[32];
|
||||
char proxy_telnet_command[512];
|
||||
int proxy_socks_version;
|
||||
/* SSH options */
|
||||
char remote_cmd[512];
|
||||
char remote_cmd2[512]; /* fallback if the first fails
|
||||
|
2
raw.c
2
raw.c
@ -92,7 +92,7 @@ static char *raw_init(char *host, int port, char **realhost, int nodelay)
|
||||
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
|
||||
logevent(buf);
|
||||
}
|
||||
s = sk_new(addr, port, 0, 1, nodelay, &fn_table_ptr);
|
||||
s = new_connection(addr, *realhost, port, 0, 1, nodelay, &fn_table_ptr);
|
||||
if ((err = sk_socket_error(s)))
|
||||
return err;
|
||||
|
||||
|
2
rlogin.c
2
rlogin.c
@ -122,7 +122,7 @@ static char *rlogin_init(char *host, int port, char **realhost, int nodelay)
|
||||
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
|
||||
logevent(buf);
|
||||
}
|
||||
s = sk_new(addr, port, 1, 0, nodelay, &fn_table_ptr);
|
||||
s = new_connection(addr, *realhost, port, 1, 0, nodelay, &fn_table_ptr);
|
||||
if ((err = sk_socket_error(s)))
|
||||
return err;
|
||||
|
||||
|
27
settings.c
27
settings.c
@ -148,6 +148,17 @@ void save_settings(char *section, int do_host, Config * cfg)
|
||||
write_setting_i(sesskey, "TCPNoDelay", cfg->tcp_nodelay);
|
||||
write_setting_s(sesskey, "TerminalType", cfg->termtype);
|
||||
write_setting_s(sesskey, "TerminalSpeed", cfg->termspeed);
|
||||
|
||||
/* proxy settings */
|
||||
write_setting_s(sesskey, "ProxyExcludeList", cfg->proxy_exclude_list);
|
||||
write_setting_i(sesskey, "ProxyType", cfg->proxy_type);
|
||||
write_setting_s(sesskey, "ProxyHost", cfg->proxy_host);
|
||||
write_setting_i(sesskey, "ProxyPort", cfg->proxy_port);
|
||||
write_setting_s(sesskey, "ProxyUsername", cfg->proxy_username);
|
||||
write_setting_s(sesskey, "ProxyPassword", cfg->proxy_password);
|
||||
write_setting_s(sesskey, "ProxyTelnetCommand", cfg->proxy_telnet_command);
|
||||
write_setting_i(sesskey, "ProxySOCKSVersion", cfg->proxy_socks_version);
|
||||
|
||||
{
|
||||
char buf[2 * sizeof(cfg->environmt)], *p, *q;
|
||||
p = buf;
|
||||
@ -343,6 +354,22 @@ void load_settings(char *section, int do_host, Config * cfg)
|
||||
sizeof(cfg->termtype));
|
||||
gpps(sesskey, "TerminalSpeed", "38400,38400", cfg->termspeed,
|
||||
sizeof(cfg->termspeed));
|
||||
|
||||
/* proxy settings */
|
||||
gpps(sesskey, "ProxyExcludeList", "", cfg->proxy_exclude_list,
|
||||
sizeof(cfg->proxy_exclude_list));
|
||||
gppi(sesskey, "ProxyType", PROXY_NONE, &cfg->proxy_type);
|
||||
gpps(sesskey, "ProxyHost", "proxy", cfg->proxy_host,
|
||||
sizeof(cfg->proxy_host));
|
||||
gppi(sesskey, "ProxyPort", 80, &cfg->proxy_port);
|
||||
gpps(sesskey, "ProxyUsername", "", cfg->proxy_username,
|
||||
sizeof(cfg->proxy_username));
|
||||
gpps(sesskey, "ProxyPassword", "", cfg->proxy_password,
|
||||
sizeof(cfg->proxy_password));
|
||||
gpps(sesskey, "ProxyTelnetCommand", "connect %host %port",
|
||||
cfg->proxy_telnet_command, sizeof(cfg->proxy_telnet_command));
|
||||
gppi(sesskey, "ProxySOCKSVersion", 5, &cfg->proxy_socks_version);
|
||||
|
||||
{
|
||||
char buf[2 * sizeof(cfg->environmt)], *p, *q;
|
||||
gpps(sesskey, "Environment", "", buf, sizeof(buf));
|
||||
|
2
ssh.c
2
ssh.c
@ -1872,7 +1872,7 @@ static char *connect_to_host(char *host, int port, char **realhost, int nodelay)
|
||||
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
|
||||
logevent(buf);
|
||||
}
|
||||
s = sk_new(addr, port, 0, 1, nodelay, &fn_table_ptr);
|
||||
s = new_connection(addr, *realhost, port, 0, 1, nodelay, &fn_table_ptr);
|
||||
if ((err = sk_socket_error(s))) {
|
||||
s = NULL;
|
||||
return err;
|
||||
|
2
telnet.c
2
telnet.c
@ -636,7 +636,7 @@ static char *telnet_init(char *host, int port, char **realhost, int nodelay)
|
||||
sprintf(buf, "Connecting to %.100s port %d", addrbuf, port);
|
||||
logevent(buf);
|
||||
}
|
||||
s = sk_new(addr, port, 0, 1, nodelay, &fn_table_ptr);
|
||||
s = new_connection(addr, *realhost, port, 0, 1, nodelay, &fn_table_ptr);
|
||||
if ((err = sk_socket_error(s)))
|
||||
return err;
|
||||
|
||||
|
145
windlg.c
145
windlg.c
@ -438,6 +438,32 @@ enum { IDCX_ABOUT =
|
||||
IDC_NODELAY,
|
||||
connectionpanelend,
|
||||
|
||||
proxypanelstart,
|
||||
IDC_TITLE_PROXY,
|
||||
IDC_BOX_PROXY1,
|
||||
IDC_PROXYTYPESTATIC,
|
||||
IDC_PROXYTYPENONE,
|
||||
IDC_PROXYTYPEHTTP,
|
||||
IDC_PROXYTYPESOCKS,
|
||||
IDC_PROXYTYPETELNET,
|
||||
IDC_PROXYHOSTSTATIC,
|
||||
IDC_PROXYHOSTEDIT,
|
||||
IDC_PROXYPORTSTATIC,
|
||||
IDC_PROXYPORTEDIT,
|
||||
IDC_PROXYEXCLUDESTATIC,
|
||||
IDC_PROXYEXCLUDEEDIT,
|
||||
IDC_PROXYUSERSTATIC,
|
||||
IDC_PROXYUSEREDIT,
|
||||
IDC_PROXYPASSSTATIC,
|
||||
IDC_PROXYPASSEDIT,
|
||||
IDC_BOX_PROXY2,
|
||||
IDC_PROXYTELNETCMDSTATIC,
|
||||
IDC_PROXYTELNETCMDEDIT,
|
||||
IDC_PROXYSOCKSVERSTATIC,
|
||||
IDC_PROXYSOCKSVER5,
|
||||
IDC_PROXYSOCKSVER4,
|
||||
proxypanelend,
|
||||
|
||||
telnetpanelstart,
|
||||
IDC_TITLE_TELNET,
|
||||
IDC_BOX_TELNET1,
|
||||
@ -1243,6 +1269,20 @@ static void init_dlg_ctrls(HWND hwnd, int keepsess)
|
||||
CheckDlgButton(hwnd, IDC_LPORT_ALL, cfg.lport_acceptall);
|
||||
CheckDlgButton(hwnd, IDC_RPORT_ALL, cfg.rport_acceptall);
|
||||
CheckRadioButton(hwnd, IDC_PFWDLOCAL, IDC_PFWDREMOTE, IDC_PFWDLOCAL);
|
||||
|
||||
/* proxy config */
|
||||
CheckRadioButton(hwnd, IDC_PROXYTYPENONE, IDC_PROXYTYPETELNET,
|
||||
cfg.proxy_type == PROXY_HTTP ? IDC_PROXYTYPEHTTP :
|
||||
cfg.proxy_type == PROXY_SOCKS ? IDC_PROXYTYPESOCKS :
|
||||
cfg.proxy_type == PROXY_TELNET ? IDC_PROXYTYPETELNET : IDC_PROXYTYPENONE);
|
||||
SetDlgItemText(hwnd, IDC_PROXYHOSTEDIT, cfg.proxy_host);
|
||||
SetDlgItemInt(hwnd, IDC_PROXYPORTEDIT, cfg.proxy_port, FALSE);
|
||||
SetDlgItemText(hwnd, IDC_PROXYEXCLUDEEDIT, cfg.proxy_exclude_list);
|
||||
SetDlgItemText(hwnd, IDC_PROXYTELNETCMDEDIT, cfg.proxy_telnet_command);
|
||||
SetDlgItemText(hwnd, IDC_PROXYUSEREDIT, cfg.proxy_username);
|
||||
SetDlgItemText(hwnd, IDC_PROXYPASSEDIT, cfg.proxy_password);
|
||||
CheckRadioButton(hwnd, IDC_PROXYSOCKSVER5, IDC_PROXYSOCKSVER4,
|
||||
cfg.proxy_socks_version == 4 ? IDC_PROXYSOCKSVER4 : IDC_PROXYSOCKSVER5);
|
||||
}
|
||||
|
||||
struct treeview_faff {
|
||||
@ -1687,6 +1727,41 @@ static void create_controls(HWND hwnd, int dlgtype, int panel)
|
||||
}
|
||||
}
|
||||
|
||||
if (panel == proxypanelstart) {
|
||||
/* The Proxy panel. Accelerators used: [acgoh] ntslypeuwmv */
|
||||
struct ctlpos cp;
|
||||
ctlposinit(&cp, hwnd, 80, 3, 13);
|
||||
if (dlgtype == 0) {
|
||||
bartitle(&cp, "Options controlling proxy usage",
|
||||
IDC_TITLE_PROXY);
|
||||
beginbox(&cp, "Proxy basics", IDC_BOX_PROXY1);
|
||||
radioline(&cp, "Proxy type:", IDC_PROXYTYPESTATIC, 4,
|
||||
"&None", IDC_PROXYTYPENONE,
|
||||
"H&TTP", IDC_PROXYTYPEHTTP,
|
||||
"&SOCKS", IDC_PROXYTYPESOCKS,
|
||||
"Te&lnet", IDC_PROXYTYPETELNET, NULL);
|
||||
multiedit(&cp,
|
||||
"Prox&y Host", IDC_PROXYHOSTSTATIC, IDC_PROXYHOSTEDIT, 80,
|
||||
"&Port", IDC_PROXYPORTSTATIC, IDC_PROXYPORTEDIT, 20, NULL);
|
||||
multiedit(&cp,
|
||||
"&Exclude Hosts/IPs", IDC_PROXYEXCLUDESTATIC,
|
||||
IDC_PROXYEXCLUDEEDIT, 100, NULL);
|
||||
staticedit(&cp, "&Username", IDC_PROXYUSERSTATIC,
|
||||
IDC_PROXYUSEREDIT, 60);
|
||||
staticedit(&cp, "Pass&word", IDC_PROXYPASSSTATIC,
|
||||
IDC_PROXYPASSEDIT, 60);
|
||||
endbox(&cp);
|
||||
beginbox(&cp, "Misc. proxy settings", IDC_BOX_PROXY2);
|
||||
multiedit(&cp,
|
||||
"Telnet co&mmand", IDC_PROXYTELNETCMDSTATIC,
|
||||
IDC_PROXYTELNETCMDEDIT, 100, NULL);
|
||||
radioline(&cp, "SOCKS &Version", IDC_PROXYSOCKSVERSTATIC,
|
||||
2, "Version 5", IDC_PROXYSOCKSVER5, "Version 4",
|
||||
IDC_PROXYSOCKSVER4, NULL);
|
||||
endbox(&cp);
|
||||
}
|
||||
}
|
||||
|
||||
if (panel == telnetpanelstart) {
|
||||
/* The Telnet panel. Accelerators used: [acgoh] svldr bftk */
|
||||
struct ctlpos cp;
|
||||
@ -1957,6 +2032,7 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
|
||||
treeview_insert(&tvfaff, 1, "Colours");
|
||||
treeview_insert(&tvfaff, 0, "Connection");
|
||||
if (dlgtype == 0) {
|
||||
treeview_insert(&tvfaff, 1, "Proxy");
|
||||
treeview_insert(&tvfaff, 1, "Telnet");
|
||||
treeview_insert(&tvfaff, 1, "Rlogin");
|
||||
if (backends[3].backend != NULL) {
|
||||
@ -2040,6 +2116,8 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
|
||||
create_controls(hwnd, dlgtype, tunnelspanelstart);
|
||||
if (!strcmp(buffer, "Connection"))
|
||||
create_controls(hwnd, dlgtype, connectionpanelstart);
|
||||
if (!strcmp(buffer, "Proxy"))
|
||||
create_controls(hwnd, dlgtype, proxypanelstart);
|
||||
if (!strcmp(buffer, "Telnet"))
|
||||
create_controls(hwnd, dlgtype, telnetpanelstart);
|
||||
if (!strcmp(buffer, "Rlogin"))
|
||||
@ -2741,6 +2819,73 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg,
|
||||
GetDlgItemText(hwnd, IDC_TTEDIT, cfg.termtype,
|
||||
sizeof(cfg.termtype) - 1);
|
||||
break;
|
||||
|
||||
/* proxy config */
|
||||
case IDC_PROXYHOSTEDIT:
|
||||
if (HIWORD(wParam) == EN_CHANGE)
|
||||
GetDlgItemText(hwnd, IDC_PROXYHOSTEDIT, cfg.proxy_host,
|
||||
sizeof(cfg.proxy_host) - 1);
|
||||
break;
|
||||
case IDC_PROXYPORTEDIT:
|
||||
if (HIWORD(wParam) == EN_CHANGE) {
|
||||
GetDlgItemText(hwnd, IDC_PROXYPORTEDIT, portname, 31);
|
||||
if (isdigit(portname[0]))
|
||||
MyGetDlgItemInt(hwnd, IDC_PROXYPORTEDIT, &cfg.proxy_port);
|
||||
else {
|
||||
service = getservbyname(portname, NULL);
|
||||
if (service)
|
||||
cfg.proxy_port = ntohs(service->s_port);
|
||||
else
|
||||
cfg.proxy_port = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDC_PROXYEXCLUDEEDIT:
|
||||
if (HIWORD(wParam) == EN_CHANGE)
|
||||
GetDlgItemText(hwnd, IDC_PROXYEXCLUDEEDIT,
|
||||
cfg.proxy_exclude_list,
|
||||
sizeof(cfg.proxy_exclude_list) - 1);
|
||||
break;
|
||||
case IDC_PROXYUSEREDIT:
|
||||
if (HIWORD(wParam) == EN_CHANGE)
|
||||
GetDlgItemText(hwnd, IDC_PROXYUSEREDIT,
|
||||
cfg.proxy_username,
|
||||
sizeof(cfg.proxy_username) - 1);
|
||||
break;
|
||||
case IDC_PROXYPASSEDIT:
|
||||
if (HIWORD(wParam) == EN_CHANGE)
|
||||
GetDlgItemText(hwnd, IDC_PROXYPASSEDIT,
|
||||
cfg.proxy_password,
|
||||
sizeof(cfg.proxy_password) - 1);
|
||||
break;
|
||||
case IDC_PROXYTELNETCMDEDIT:
|
||||
if (HIWORD(wParam) == EN_CHANGE)
|
||||
GetDlgItemText(hwnd, IDC_PROXYTELNETCMDEDIT,
|
||||
cfg.proxy_telnet_command,
|
||||
sizeof(cfg.proxy_telnet_command) - 1);
|
||||
break;
|
||||
case IDC_PROXYSOCKSVER5:
|
||||
case IDC_PROXYSOCKSVER4:
|
||||
if (HIWORD(wParam) == BN_CLICKED ||
|
||||
HIWORD(wParam) == BN_DOUBLECLICKED) {
|
||||
cfg.proxy_socks_version =
|
||||
IsDlgButtonChecked(hwnd, IDC_PROXYSOCKSVER4) ? 4 : 5;
|
||||
}
|
||||
break;
|
||||
case IDC_PROXYTYPENONE:
|
||||
case IDC_PROXYTYPEHTTP:
|
||||
case IDC_PROXYTYPESOCKS:
|
||||
case IDC_PROXYTYPETELNET:
|
||||
if (HIWORD(wParam) == BN_CLICKED ||
|
||||
HIWORD(wParam) == BN_DOUBLECLICKED) {
|
||||
cfg.proxy_type =
|
||||
IsDlgButtonChecked(hwnd, IDC_PROXYTYPEHTTP) ? PROXY_HTTP :
|
||||
IsDlgButtonChecked(hwnd, IDC_PROXYTYPESOCKS) ? PROXY_SOCKS :
|
||||
IsDlgButtonChecked(hwnd, IDC_PROXYTYPETELNET) ? PROXY_TELNET :
|
||||
PROXY_NONE;
|
||||
}
|
||||
break;
|
||||
|
||||
case IDC_LGFEDIT:
|
||||
if (HIWORD(wParam) == EN_CHANGE)
|
||||
GetDlgItemText(hwnd, IDC_LGFEDIT, cfg.logfilename,
|
||||
|
18
winnet.c
18
winnet.c
@ -393,6 +393,9 @@ static void sk_tcp_flush(Socket s)
|
||||
static void sk_tcp_close(Socket s);
|
||||
static int sk_tcp_write(Socket s, char *data, int len);
|
||||
static int sk_tcp_write_oob(Socket s, char *data, int len);
|
||||
static void sk_tcp_set_private_ptr(Socket s, void *ptr);
|
||||
static void *sk_tcp_get_private_ptr(Socket s);
|
||||
static void sk_tcp_set_frozen(Socket s, int is_frozen);
|
||||
static char *sk_tcp_socket_error(Socket s);
|
||||
|
||||
extern char *do_select(SOCKET skt, int startup);
|
||||
@ -405,6 +408,9 @@ Socket sk_register(void *sock, Plug plug)
|
||||
sk_tcp_write,
|
||||
sk_tcp_write_oob,
|
||||
sk_tcp_flush,
|
||||
sk_tcp_set_private_ptr,
|
||||
sk_tcp_get_private_ptr,
|
||||
sk_tcp_set_frozen,
|
||||
sk_tcp_socket_error
|
||||
};
|
||||
|
||||
@ -459,6 +465,9 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
|
||||
sk_tcp_write,
|
||||
sk_tcp_write_oob,
|
||||
sk_tcp_flush,
|
||||
sk_tcp_set_private_ptr,
|
||||
sk_tcp_get_private_ptr,
|
||||
sk_tcp_set_frozen,
|
||||
sk_tcp_socket_error
|
||||
};
|
||||
|
||||
@ -633,6 +642,9 @@ Socket sk_newlistener(int port, Plug plug, int local_host_only)
|
||||
sk_tcp_write,
|
||||
sk_tcp_write_oob,
|
||||
sk_tcp_flush,
|
||||
sk_tcp_set_private_ptr,
|
||||
sk_tcp_get_private_ptr,
|
||||
sk_tcp_set_frozen,
|
||||
sk_tcp_socket_error
|
||||
};
|
||||
|
||||
@ -1043,13 +1055,13 @@ void net_pending_errors(void)
|
||||
* Each socket abstraction contains a `void *' private field in
|
||||
* which the client can keep state.
|
||||
*/
|
||||
void sk_set_private_ptr(Socket sock, void *ptr)
|
||||
static void sk_tcp_set_private_ptr(Socket sock, void *ptr)
|
||||
{
|
||||
Actual_Socket s = (Actual_Socket) sock;
|
||||
s->private_ptr = ptr;
|
||||
}
|
||||
|
||||
void *sk_get_private_ptr(Socket sock)
|
||||
static void *sk_tcp_get_private_ptr(Socket sock)
|
||||
{
|
||||
Actual_Socket s = (Actual_Socket) sock;
|
||||
return s->private_ptr;
|
||||
@ -1070,7 +1082,7 @@ static char *sk_tcp_socket_error(Socket sock)
|
||||
return s->error;
|
||||
}
|
||||
|
||||
void sk_set_frozen(Socket sock, int is_frozen)
|
||||
static void sk_tcp_set_frozen(Socket sock, int is_frozen)
|
||||
{
|
||||
Actual_Socket s = (Actual_Socket) sock;
|
||||
if (s->frozen == is_frozen)
|
||||
|
2
x11fwd.c
2
x11fwd.c
@ -188,7 +188,7 @@ char *x11_init(Socket * s, char *display, void *c)
|
||||
pr->throttled = pr->throttle_override = 0;
|
||||
pr->c = c;
|
||||
|
||||
pr->s = *s = sk_new(addr, port, 0, 1, 0, (Plug) pr);
|
||||
pr->s = *s = new_connection(addr, dummy_realhost, port, 0, 1, 0, (Plug) pr);
|
||||
if ((err = sk_socket_error(*s))) {
|
||||
sfree(pr);
|
||||
return err;
|
||||
|
Loading…
Reference in New Issue
Block a user