1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-25 01:02: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
struct addrinfo hints, *ai;
char portstr[6];
struct sockaddr_in6 a6;
#endif
struct sockaddr *addr;
int addrlen;
struct sockaddr_in a;
int err;
Actual_Socket ret;
int retcode;
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;
s = socket(address_family, SOCK_STREAM, 0);
}
ret->s = s;
if (s < 0) {
ret->error = error_string(errno);
@ -636,77 +637,70 @@ 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));
/* BSD IP stacks need sockaddr_in zeroed before filling in */
memset(&a,'\0',sizeof(struct sockaddr_in));
retcode = -1;
addr = NULL; addrlen = -1; /* placate optimiser */
if (srcaddr != NULL) {
#ifndef NO_IPV6
#if 0
memset(&a6,'\0',sizeof(struct sockaddr_in6));
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = address_family;
hints.ai_socktype = 0;
hints.ai_protocol = 0;
hints.ai_addrlen = 0;
hints.ai_addr = NULL;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
sprintf(portstr, "%d", port);
retcode = getaddrinfo(srcaddr, portstr, &hints, &ai);
addr = ai->ai_addr;
addrlen = ai->ai_addrlen;
#else
memset(&a,'\0',sizeof(struct sockaddr_in));
a.sin_family = AF_INET;
a.sin_port = htons(port);
a.sin_addr.s_addr = inet_addr(srcaddr);
if (a.sin_addr.s_addr != (in_addr_t)(-1)) {
/* Override localhost_only with specified listen addr. */
ret->localhost_only = ipv4_is_loopback(a.sin_addr);
got_addr = 1;
}
addr = (struct sockaddr *)a;
addrlen = sizeof(a);
retcode = 0;
#endif
hints.ai_flags = AI_NUMERICHOST;
hints.ai_family = address_family;
hints.ai_socktype = 0;
hints.ai_protocol = 0;
hints.ai_addrlen = 0;
hints.ai_addr = NULL;
hints.ai_canonname = NULL;
hints.ai_next = NULL;
sprintf(portstr, "%d", port);
if (srcaddr != NULL && getaddrinfo(srcaddr, portstr, &hints, &ai) == 0)
retcode = bind(s, ai->ai_addr, ai->ai_addrlen);
else
#if 0
{
/*
* 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;
}
/*
* Bind to source address. First try an explicitly
* specified one...
*/
if (srcaddr) {
a.sin_addr.s_addr = inet_addr(srcaddr);
if (a.sin_addr.s_addr != (in_addr_t)(-1)) {
/* Override localhost_only with specified listen addr. */
ret->localhost_only = ipv4_is_loopback(a.sin_addr);
got_addr = 1;
}
}
/*
* ... and failing that, go with one of the standard ones.
*/
if (!got_addr) {
if (retcode != 0) {
#ifndef NO_IPV6
if (address_family == AF_INET6) {
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)
a.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
else
a.sin_addr.s_addr = htonl(INADDR_ANY);
}
a.sin_port = htons((short)port);
retcode = bind(s, (struct sockaddr *) &a, sizeof(a));
addr = (struct sockaddr *)&a;
addrlen = sizeof(a);
}
}
if (retcode >= 0) {
err = 0;
} else {
err = errno;
}
if (err) {
ret->error = error_string(err);
retcode = bind(s, addr, addrlen);
if (retcode < 0) {
close(s);
ret->error = error_string(errno);
return (Socket) ret;
}
@ -717,6 +711,8 @@ Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, i
return (Socket) ret;
}
ret->s = s;
uxsel_tell(ret);
add234(sktree, ret);