mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-03-22 06:38:37 -05:00
For local and dynamic port forwardings (i.e. the ones which listen
on a local port), the `Auto' protocol option on the Tunnels panel should always produce a port you can connect to in _either_ of IPv4 and v6, because the aim is for the user not to have to know or care which one they're using. This was not the case on Windows, and now is. Also, updated the docs to give more detail on issues like this. [originally from svn r5083]
This commit is contained in:
parent
79629c729c
commit
c57e9f0672
@ -2494,12 +2494,15 @@ incoming connections in both IPv4 and (if available) IPv6
|
|||||||
\b for a remote-to-local port forwarding, PuTTY will choose a
|
\b for a remote-to-local port forwarding, PuTTY will choose a
|
||||||
sensible protocol for the outgoing connection.
|
sensible protocol for the outgoing connection.
|
||||||
|
|
||||||
\# FIXME: work out what this paragraph means, reword it for clarity,
|
Note that some operating systems may listen for incoming connections
|
||||||
\# and reinstate it.
|
in IPv4 even if you specifically asked for IPv6, because their IPv4
|
||||||
Note that on Windows the address space for IPv4 and IPv6 is
|
and IPv6 protocol stacks are linked together. Apparently Linux does
|
||||||
completely disjunct, so listening on IPv6 won't make PuTTY listen on
|
this, and Windows does not. So if you're running PuTTY on Windows
|
||||||
IPv4. This behaviour may be different on most remote hosts when they
|
and you tick \q{IPv6} for a local or dynamic port forwarding, it
|
||||||
are not operating Windows.
|
will \e{only} be usable by connecting to it using IPv6; whereas if
|
||||||
|
you do the same on Linux, you can also use it with IPv4. However,
|
||||||
|
ticking \q{Auto} should always give you a port which you can connect
|
||||||
|
to using either protocol.
|
||||||
|
|
||||||
\H{config-ssh-bugs} The Bugs panel
|
\H{config-ssh-bugs} The Bugs panel
|
||||||
|
|
||||||
|
@ -24,6 +24,16 @@ const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
|
|||||||
#define ipv4_is_loopback(addr) \
|
#define ipv4_is_loopback(addr) \
|
||||||
((p_ntohl(addr.s_addr) & 0xFF000000L) == 0x7F000000L)
|
((p_ntohl(addr.s_addr) & 0xFF000000L) == 0x7F000000L)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 {
|
||||||
const struct socket_function_table *fn;
|
const 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 */
|
||||||
@ -42,17 +52,14 @@ struct Socket_tag {
|
|||||||
int sending_oob;
|
int sending_oob;
|
||||||
int oobinline;
|
int oobinline;
|
||||||
int pending_error; /* in case send() returns error */
|
int pending_error; /* in case send() returns error */
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We used to typedef struct Socket_tag *Socket.
|
* We sometimes need pairs of Socket structures to be linked:
|
||||||
*
|
* if we are listening on the same IPv6 and v4 port, for
|
||||||
* Since we have made the networking abstraction slightly more
|
* example. So here we define `parent' and `child' pointers to
|
||||||
* abstract, Socket no longer means a tcp socket (it could mean
|
* track this link.
|
||||||
* 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;
|
Actual_Socket parent, child;
|
||||||
|
};
|
||||||
|
|
||||||
struct SockAddr_tag {
|
struct SockAddr_tag {
|
||||||
char *error;
|
char *error;
|
||||||
@ -618,6 +625,7 @@ Socket sk_register(void *sock, Plug plug)
|
|||||||
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->s = (SOCKET)sock;
|
ret->s = (SOCKET)sock;
|
||||||
|
|
||||||
@ -682,6 +690,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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open socket.
|
* Open socket.
|
||||||
@ -837,7 +846,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
|
|||||||
}
|
}
|
||||||
|
|
||||||
Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,
|
Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,
|
||||||
int address_family)
|
int orig_address_family)
|
||||||
{
|
{
|
||||||
static const struct socket_function_table fn_table = {
|
static const struct socket_function_table fn_table = {
|
||||||
sk_tcp_plug,
|
sk_tcp_plug,
|
||||||
@ -863,6 +872,8 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,
|
|||||||
int retcode;
|
int retcode;
|
||||||
int on = 1;
|
int on = 1;
|
||||||
|
|
||||||
|
int address_family;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create Socket structure.
|
* Create Socket structure.
|
||||||
*/
|
*/
|
||||||
@ -877,25 +888,26 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,
|
|||||||
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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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);
|
||||||
|
|
||||||
#ifndef NO_IPV6
|
/*
|
||||||
/* Let's default to IPv6, this shouldn't hurt anybody
|
* Our default, if passed the `don't care' value
|
||||||
* If the stack supports IPv6 it will also allow IPv4 connections. */
|
* ADDRTYPE_UNSPEC, is to listen on IPv4. If IPv6 is supported,
|
||||||
if (address_family == AF_UNSPEC) address_family = AF_INET6;
|
* we will also set up a second socket listening on IPv6, but
|
||||||
#else
|
* the v4 one is primary since that ought to work even on
|
||||||
/* No other choice, default to IPv4 */
|
* non-v6-supporting systems.
|
||||||
|
*/
|
||||||
if (address_family == AF_UNSPEC) address_family = AF_INET;
|
if (address_family == AF_UNSPEC) address_family = AF_INET;
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open socket.
|
* Open socket.
|
||||||
@ -974,6 +986,7 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
p_closesocket(s);
|
||||||
ret->error = winsock_error_string(err);
|
ret->error = winsock_error_string(err);
|
||||||
return (Socket) ret;
|
return (Socket) ret;
|
||||||
}
|
}
|
||||||
@ -989,12 +1002,35 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only,
|
|||||||
* window, or an EventSelect on an event object. */
|
* window, or an EventSelect on an event object. */
|
||||||
errstr = do_select(s, 1);
|
errstr = do_select(s, 1);
|
||||||
if (errstr) {
|
if (errstr) {
|
||||||
|
p_closesocket(s);
|
||||||
ret->error = errstr;
|
ret->error = errstr;
|
||||||
return (Socket) ret;
|
return (Socket) ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
add234(sktree, ret);
|
add234(sktree, ret);
|
||||||
|
|
||||||
|
#ifndef NO_IPV6
|
||||||
|
/*
|
||||||
|
* If we were given ADDRTYPE_UNSPEC, we must also create an
|
||||||
|
* IPv6 listening socket and link it to this one.
|
||||||
|
*/
|
||||||
|
if (address_family == AF_INET && orig_address_family == ADDRTYPE_UNSPEC) {
|
||||||
|
Actual_Socket other;
|
||||||
|
|
||||||
|
other = (Actual_Socket) sk_newlistener(srcaddr, port, plug,
|
||||||
|
local_host_only, ADDRTYPE_IPV6);
|
||||||
|
|
||||||
|
if (other) {
|
||||||
|
if (!other->error) {
|
||||||
|
other->parent = ret;
|
||||||
|
ret->child = other;
|
||||||
|
} else {
|
||||||
|
sfree(other);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
return (Socket) ret;
|
return (Socket) ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1003,6 +1039,9 @@ static void sk_tcp_close(Socket sock)
|
|||||||
extern char *do_select(SOCKET skt, int startup);
|
extern char *do_select(SOCKET skt, int startup);
|
||||||
Actual_Socket s = (Actual_Socket) sock;
|
Actual_Socket s = (Actual_Socket) sock;
|
||||||
|
|
||||||
|
if (s->child)
|
||||||
|
sk_tcp_close((Socket)s->child);
|
||||||
|
|
||||||
del234(sktree, s);
|
del234(sktree, s);
|
||||||
do_select(s->s, 0);
|
do_select(s->s, 0);
|
||||||
p_closesocket(s->s);
|
p_closesocket(s->s);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user