mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-05-28 15:24:49 -05:00
Fix for portfwd-addr-family: on Unix, when a tunnel is specified as "Auto"
(rather than IPv4 or IPv6-only; this is the default), try to open up listening sockets on both address families, rather than (unhelpfully) just IPv6. (And don't open one if the other can't be bound, in a nod to CVE-2008-1483.) Based on a patch from Ben A L Jemmett. [originally from svn r8150] [this svn revision also touched putty-wishlist]
This commit is contained in:
parent
ea09aca2d1
commit
6e2bd31d32
66
unix/uxnet.c
66
unix/uxnet.c
@ -31,6 +31,16 @@
|
||||
# define X11_UNIX_PATH "/tmp/.X11-unix/X"
|
||||
#endif
|
||||
|
||||
/*
|
||||
* We used to typedef struct Socket_tag *Socket.
|
||||
*
|
||||
* Since we have made the networking abstraction slightly more
|
||||
* abstract, Socket no longer means a tcp socket (it could mean
|
||||
* an ssl socket). So now we must use Actual_Socket when we know
|
||||
* we are talking about a tcp socket.
|
||||
*/
|
||||
typedef struct Socket_tag *Actual_Socket;
|
||||
|
||||
struct Socket_tag {
|
||||
struct socket_function_table *fn;
|
||||
/* the above variable absolutely *must* be the first in this structure */
|
||||
@ -54,18 +64,15 @@ struct Socket_tag {
|
||||
int nodelay, keepalive; /* for connect()-type sockets */
|
||||
int privport, port; /* and again */
|
||||
SockAddr addr;
|
||||
/*
|
||||
* We sometimes need pairs of Socket structures to be linked:
|
||||
* if we are listening on the same IPv6 and v4 port, for
|
||||
* example. So here we define `parent' and `child' pointers to
|
||||
* track this link.
|
||||
*/
|
||||
Actual_Socket parent, child;
|
||||
};
|
||||
|
||||
/*
|
||||
* We used to typedef struct Socket_tag *Socket.
|
||||
*
|
||||
* Since we have made the networking abstraction slightly more
|
||||
* abstract, Socket no longer means a tcp socket (it could mean
|
||||
* an ssl socket). So now we must use Actual_Socket when we know
|
||||
* we are talking about a tcp socket.
|
||||
*/
|
||||
typedef struct Socket_tag *Actual_Socket;
|
||||
|
||||
struct SockAddr_tag {
|
||||
const char *error;
|
||||
/*
|
||||
@ -426,6 +433,7 @@ Socket sk_register(OSSocket sockfd, Plug plug)
|
||||
ret->pending_error = 0;
|
||||
ret->oobpending = FALSE;
|
||||
ret->listener = 0;
|
||||
ret->parent = ret->child = NULL;
|
||||
ret->addr = NULL;
|
||||
ret->connected = 1;
|
||||
|
||||
@ -651,6 +659,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
|
||||
ret->frozen_readable = 0;
|
||||
ret->localhost_only = 0; /* unused, but best init anyway */
|
||||
ret->pending_error = 0;
|
||||
ret->parent = ret->child = NULL;
|
||||
ret->oobpending = FALSE;
|
||||
ret->listener = 0;
|
||||
ret->addr = addr;
|
||||
@ -672,7 +681,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
|
||||
return (Socket) ret;
|
||||
}
|
||||
|
||||
Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, int address_family)
|
||||
Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, int orig_address_family)
|
||||
{
|
||||
int s;
|
||||
#ifndef NO_IPV6
|
||||
@ -685,6 +694,7 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i
|
||||
struct sockaddr_in a;
|
||||
Actual_Socket ret;
|
||||
int retcode;
|
||||
int address_family;
|
||||
int on = 1;
|
||||
|
||||
/*
|
||||
@ -701,6 +711,7 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i
|
||||
ret->frozen_readable = 0;
|
||||
ret->localhost_only = local_host_only;
|
||||
ret->pending_error = 0;
|
||||
ret->parent = ret->child = NULL;
|
||||
ret->oobpending = FALSE;
|
||||
ret->listener = 1;
|
||||
ret->addr = NULL;
|
||||
@ -709,9 +720,9 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i
|
||||
* Translate address_family from platform-independent constants
|
||||
* into local reality.
|
||||
*/
|
||||
address_family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
|
||||
address_family = (orig_address_family == ADDRTYPE_IPV4 ? AF_INET :
|
||||
#ifndef NO_IPV6
|
||||
address_family == ADDRTYPE_IPV6 ? AF_INET6 :
|
||||
orig_address_family == ADDRTYPE_IPV6 ? AF_INET6 :
|
||||
#endif
|
||||
AF_UNSPEC);
|
||||
|
||||
@ -823,6 +834,32 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i
|
||||
return (Socket) ret;
|
||||
}
|
||||
|
||||
#ifndef NO_IPV6
|
||||
/*
|
||||
* If we were given ADDRTYPE_UNSPEC, we must also create an
|
||||
* IPv4 listening socket and link it to this one.
|
||||
*/
|
||||
if (address_family == AF_INET6 && orig_address_family == ADDRTYPE_UNSPEC) {
|
||||
Actual_Socket other;
|
||||
|
||||
other = (Actual_Socket) sk_newlistener(srcaddr, port, plug,
|
||||
local_host_only, ADDRTYPE_IPV4);
|
||||
|
||||
if (other) {
|
||||
if (!other->error) {
|
||||
other->parent = ret;
|
||||
ret->child = other;
|
||||
} else {
|
||||
/* If we couldn't create a listening socket on IPv4 as well
|
||||
* as IPv6, we must return an error overall. */
|
||||
close(s);
|
||||
sfree(ret);
|
||||
return (Socket) other;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ret->s = s;
|
||||
|
||||
uxsel_tell(ret);
|
||||
@ -835,6 +872,9 @@ static void sk_tcp_close(Socket sock)
|
||||
{
|
||||
Actual_Socket s = (Actual_Socket) sock;
|
||||
|
||||
if (s->child)
|
||||
sk_tcp_close((Socket)s->child);
|
||||
|
||||
uxsel_del(s->s);
|
||||
del234(sktree, s);
|
||||
close(s->s);
|
||||
|
Loading…
x
Reference in New Issue
Block a user