mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-26 01:32:25 +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:
parent
178a66ea0f
commit
8167dfd406
124
unix/uxnet.c
124
unix/uxnet.c
@ -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,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));
|
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
|
hints.ai_flags = AI_NUMERICHOST;
|
||||||
memset(&a6,'\0',sizeof(struct sockaddr_in6));
|
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
|
#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;
|
|
||||||
|
|
||||||
/*
|
if (retcode != 0) {
|
||||||
* Bind to source address. First try an explicitly
|
#ifndef NO_IPV6
|
||||||
* specified one...
|
if (address_family == AF_INET6) {
|
||||||
*/
|
memset(&a6,'\0',sizeof(struct sockaddr_in6));
|
||||||
if (srcaddr) {
|
a6.sin6_family = AF_INET6;
|
||||||
a.sin_addr.s_addr = inet_addr(srcaddr);
|
a6.sin6_port = htons(port);
|
||||||
if (a.sin_addr.s_addr != (in_addr_t)(-1)) {
|
if (local_host_only)
|
||||||
/* Override localhost_only with specified listen addr. */
|
a6.sin6_addr = in6addr_loopback;
|
||||||
ret->localhost_only = ipv4_is_loopback(a.sin_addr);
|
else
|
||||||
got_addr = 1;
|
a6.sin6_addr = in6addr_any;
|
||||||
}
|
addr = (struct sockaddr *)&a6;
|
||||||
}
|
addrlen = sizeof(a6);
|
||||||
|
} else
|
||||||
/*
|
#endif
|
||||||
* ... and failing that, go with one of the standard ones.
|
{
|
||||||
*/
|
memset(&a,'\0',sizeof(struct sockaddr_in));
|
||||||
if (!got_addr) {
|
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, (struct sockaddr *) &a, sizeof(a));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retcode >= 0) {
|
retcode = bind(s, addr, addrlen);
|
||||||
err = 0;
|
if (retcode < 0) {
|
||||||
} else {
|
close(s);
|
||||||
err = errno;
|
ret->error = error_string(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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user