Justin Bradford's proxy support patch. Currently supports only HTTP
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 23 Mar 2002 17:47:21 +0000 (17:47 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Sat, 23 Mar 2002 17:47:21 +0000 (17:47 +0000)
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.

git-svn-id: svn://svn.tartarus.org/sgt/putty@1598 cda61777-01e9-0310-a592-d414129be87e

15 files changed:
Makefile
Recipe
network.h
portfwd.c
proxy.c [new file with mode: 0644]
proxy.h [new file with mode: 0644]
putty.h
raw.c
rlogin.c
settings.c
ssh.c
telnet.c
windlg.c
winnet.c
x11fwd.c

index 3cc9484..d095aee 100644 (file)
--- a/Makefile
+++ b/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 
diff --git a/Recipe b/Recipe
index 4452cbf..d032be8 100644 (file)
--- a/Recipe
+++ b/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
index 2cab438..8f1b2be 100644 (file)
--- a/network.h
+++ b/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
index 732bfc5..919d27d 100644 (file)
--- a/portfwd.c
+++ b/portfwd.c
@@ -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;
diff --git a/proxy.c b/proxy.c
new file mode 100644 (file)
index 0000000..b773f25
--- /dev/null
+++ b/proxy.c
@@ -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;
+}
diff --git a/proxy.h b/proxy.h
new file mode 100644 (file)
index 0000000..43d92cb
--- /dev/null
+++ b/proxy.h
@@ -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
diff --git a/putty.h b/putty.h
index 79f0b8d..e2e4d0d 100644 (file)
--- a/putty.h
+++ b/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
diff --git a/raw.c b/raw.c
index 0d27bb7..58b060c 100644 (file)
--- a/raw.c
+++ b/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;
 
index a80d12e..4038a2f 100644 (file)
--- a/rlogin.c
+++ b/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;
 
index 55955ac..8764bb3 100644 (file)
@@ -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));
diff --git a/ssh.c b/ssh.c
index 94da21d..6cc79bf 100644 (file)
--- a/ssh.c
+++ b/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;
index 5e5fb24..8b3de1e 100644 (file)
--- a/telnet.c
+++ b/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;
 
index 316115e..f4a63de 100644 (file)
--- a/windlg.c
+++ b/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,
index 0dac18e..068b9b4 100644 (file)
--- a/winnet.c
+++ b/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)
index 480d856..6f7be40 100644 (file)
--- a/x11fwd.c
+++ b/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;