mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-05-31 00:40:28 -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"
|
# define X11_UNIX_PATH "/tmp/.X11-unix/X"
|
||||||
#endif
|
#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_tag {
|
||||||
struct socket_function_table *fn;
|
struct socket_function_table *fn;
|
||||||
/* the above variable absolutely *must* be the first in this structure */
|
/* 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 nodelay, keepalive; /* for connect()-type sockets */
|
||||||
int privport, port; /* and again */
|
int privport, port; /* and again */
|
||||||
SockAddr addr;
|
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 {
|
struct SockAddr_tag {
|
||||||
const char *error;
|
const char *error;
|
||||||
/*
|
/*
|
||||||
@ -426,6 +433,7 @@ Socket sk_register(OSSocket sockfd, Plug plug)
|
|||||||
ret->pending_error = 0;
|
ret->pending_error = 0;
|
||||||
ret->oobpending = FALSE;
|
ret->oobpending = FALSE;
|
||||||
ret->listener = 0;
|
ret->listener = 0;
|
||||||
|
ret->parent = ret->child = NULL;
|
||||||
ret->addr = NULL;
|
ret->addr = NULL;
|
||||||
ret->connected = 1;
|
ret->connected = 1;
|
||||||
|
|
||||||
@ -651,6 +659,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
|
|||||||
ret->frozen_readable = 0;
|
ret->frozen_readable = 0;
|
||||||
ret->localhost_only = 0; /* unused, but best init anyway */
|
ret->localhost_only = 0; /* unused, but best init anyway */
|
||||||
ret->pending_error = 0;
|
ret->pending_error = 0;
|
||||||
|
ret->parent = ret->child = NULL;
|
||||||
ret->oobpending = FALSE;
|
ret->oobpending = FALSE;
|
||||||
ret->listener = 0;
|
ret->listener = 0;
|
||||||
ret->addr = addr;
|
ret->addr = addr;
|
||||||
@ -672,7 +681,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
|
|||||||
return (Socket) ret;
|
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;
|
int s;
|
||||||
#ifndef NO_IPV6
|
#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;
|
struct sockaddr_in a;
|
||||||
Actual_Socket ret;
|
Actual_Socket ret;
|
||||||
int retcode;
|
int retcode;
|
||||||
|
int address_family;
|
||||||
int on = 1;
|
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->frozen_readable = 0;
|
||||||
ret->localhost_only = local_host_only;
|
ret->localhost_only = local_host_only;
|
||||||
ret->pending_error = 0;
|
ret->pending_error = 0;
|
||||||
|
ret->parent = ret->child = NULL;
|
||||||
ret->oobpending = FALSE;
|
ret->oobpending = FALSE;
|
||||||
ret->listener = 1;
|
ret->listener = 1;
|
||||||
ret->addr = NULL;
|
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
|
* Translate address_family from platform-independent constants
|
||||||
* into local reality.
|
* into local reality.
|
||||||
*/
|
*/
|
||||||
address_family = (address_family == ADDRTYPE_IPV4 ? AF_INET :
|
address_family = (orig_address_family == ADDRTYPE_IPV4 ? AF_INET :
|
||||||
#ifndef NO_IPV6
|
#ifndef NO_IPV6
|
||||||
address_family == ADDRTYPE_IPV6 ? AF_INET6 :
|
orig_address_family == ADDRTYPE_IPV6 ? AF_INET6 :
|
||||||
#endif
|
#endif
|
||||||
AF_UNSPEC);
|
AF_UNSPEC);
|
||||||
|
|
||||||
@ -823,6 +834,32 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i
|
|||||||
return (Socket) ret;
|
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;
|
ret->s = s;
|
||||||
|
|
||||||
uxsel_tell(ret);
|
uxsel_tell(ret);
|
||||||
@ -835,6 +872,9 @@ static void sk_tcp_close(Socket sock)
|
|||||||
{
|
{
|
||||||
Actual_Socket s = (Actual_Socket) sock;
|
Actual_Socket s = (Actual_Socket) sock;
|
||||||
|
|
||||||
|
if (s->child)
|
||||||
|
sk_tcp_close((Socket)s->child);
|
||||||
|
|
||||||
uxsel_del(s->s);
|
uxsel_del(s->s);
|
||||||
del234(sktree, s);
|
del234(sktree, s);
|
||||||
close(s->s);
|
close(s->s);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user