1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-02-04 14:12:24 +00:00

Rewrite of Unix sk_newlistener() which should fix any possible

problems involving trying to bind an IPv6 socket to an IPv4 address.

[originally from svn r5115]
This commit is contained in:
Simon Tatham 2005-01-16 12:37:19 +00:00
parent 178a66ea0f
commit 8167dfd406

View File

@ -575,9 +575,11 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i
#ifndef NO_IPV6 #ifndef NO_IPV6
struct addrinfo hints, *ai; struct addrinfo hints, *ai;
char portstr[6]; char portstr[6];
struct sockaddr_in6 a6;
#endif #endif
struct sockaddr *addr;
int addrlen;
struct sockaddr_in a; struct sockaddr_in a;
int err;
Actual_Socket ret; Actual_Socket ret;
int retcode; int retcode;
int on = 1; int on = 1;
@ -625,7 +627,6 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i
address_family = AF_INET; address_family = AF_INET;
s = socket(address_family, SOCK_STREAM, 0); s = socket(address_family, SOCK_STREAM, 0);
} }
ret->s = s;
if (s < 0) { if (s < 0) {
ret->error = error_string(errno); ret->error = error_string(errno);
@ -636,12 +637,11 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on));
/* BSD IP stacks need sockaddr_in zeroed before filling in */ retcode = -1;
memset(&a,'\0',sizeof(struct sockaddr_in)); addr = NULL; addrlen = -1; /* placate optimiser */
if (srcaddr != NULL) {
#ifndef NO_IPV6 #ifndef NO_IPV6
#if 0
memset(&a6,'\0',sizeof(struct sockaddr_in6));
#endif
hints.ai_flags = AI_NUMERICHOST; hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = address_family; hints.ai_family = address_family;
hints.ai_socktype = 0; hints.ai_socktype = 0;
@ -651,62 +651,56 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i
hints.ai_canonname = NULL; hints.ai_canonname = NULL;
hints.ai_next = NULL; hints.ai_next = NULL;
sprintf(portstr, "%d", port); sprintf(portstr, "%d", port);
if (srcaddr != NULL && getaddrinfo(srcaddr, portstr, &hints, &ai) == 0) retcode = getaddrinfo(srcaddr, portstr, &hints, &ai);
retcode = bind(s, ai->ai_addr, ai->ai_addrlen); addr = ai->ai_addr;
else addrlen = ai->ai_addrlen;
#if 0 #else
{ memset(&a,'\0',sizeof(struct sockaddr_in));
/*
* FIXME: Need two listening sockets, in principle, one for v4
* and one for v6
*/
if (local_host_only)
a6.sin6_addr = in6addr_loopback;
else
a6.sin6_addr = in6addr_any;
a6.sin6_port = htons(port);
} else
#endif
#endif
{
int got_addr = 0;
a.sin_family = AF_INET; a.sin_family = AF_INET;
a.sin_port = htons(port);
/*
* Bind to source address. First try an explicitly
* specified one...
*/
if (srcaddr) {
a.sin_addr.s_addr = inet_addr(srcaddr); a.sin_addr.s_addr = inet_addr(srcaddr);
if (a.sin_addr.s_addr != (in_addr_t)(-1)) { if (a.sin_addr.s_addr != (in_addr_t)(-1)) {
/* Override localhost_only with specified listen addr. */ /* Override localhost_only with specified listen addr. */
ret->localhost_only = ipv4_is_loopback(a.sin_addr); ret->localhost_only = ipv4_is_loopback(a.sin_addr);
got_addr = 1; got_addr = 1;
} }
addr = (struct sockaddr *)a;
addrlen = sizeof(a);
retcode = 0;
#endif
} }
/* if (retcode != 0) {
* ... and failing that, go with one of the standard ones. #ifndef NO_IPV6
*/ if (address_family == AF_INET6) {
if (!got_addr) { memset(&a6,'\0',sizeof(struct sockaddr_in6));
a6.sin6_family = AF_INET6;
a6.sin6_port = htons(port);
if (local_host_only)
a6.sin6_addr = in6addr_loopback;
else
a6.sin6_addr = in6addr_any;
addr = (struct sockaddr *)&a6;
addrlen = sizeof(a6);
} else
#endif
{
memset(&a,'\0',sizeof(struct sockaddr_in));
a.sin_family = AF_INET;
a.sin_port = htons(port);
if (local_host_only) if (local_host_only)
a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
else else
a.sin_addr.s_addr = htonl(INADDR_ANY); a.sin_addr.s_addr = htonl(INADDR_ANY);
addr = (struct sockaddr *)&a;
addrlen = sizeof(a);
}
} }
a.sin_port = htons((short)port); retcode = bind(s, addr, addrlen);
retcode = bind(s, (struct sockaddr *) &a, sizeof(a)); if (retcode < 0) {
} close(s);
ret->error = error_string(errno);
if (retcode >= 0) {
err = 0;
} else {
err = errno;
}
if (err) {
ret->error = error_string(err);
return (Socket) ret; return (Socket) ret;
} }
@ -717,6 +711,8 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i
return (Socket) ret; return (Socket) ret;
} }
ret->s = s;
uxsel_tell(ret); uxsel_tell(ret);
add234(sktree, ret); add234(sktree, ret);