X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/6971bbe7b9416836100a7df98bd2f5e09d5e0697..6ee9b735013c0e636b027b77e9f6ba57a96e142f:/winnet.c diff --git a/winnet.c b/winnet.c index 5b853e10..9d3f66c2 100644 --- a/winnet.c +++ b/winnet.c @@ -55,6 +55,9 @@ #include "network.h" #include "tree234.h" +#define ipv4_is_loopback(addr) \ + ((ntohl(addr.s_addr) & 0xFF000000L) == 0x7F000000L) + struct Socket_tag { struct socket_function_table *fn; /* the above variable absolutely *must* be the first in this structure */ @@ -370,7 +373,7 @@ void sk_getaddr(SockAddr addr, char *buf, int buflen) int sk_addrtype(SockAddr addr) { - return addr->family; + return (addr->family == AF_INET ? ADDRTYPE_IPV4 : ADDRTYPE_IPV6); } void sk_addrcopy(SockAddr addr, char *buf) @@ -380,10 +383,10 @@ void sk_addrcopy(SockAddr addr, char *buf) #endif struct in_addr a; a.s_addr = htonl(addr->address); - strncpy(buf, (char*) &a.s_addr, 4); + memcpy(buf, (char*) &a.s_addr, 4); #ifdef IPV6 } else { - strncpy(buf, (char*) addr->ai, 16); + memcpy(buf, (char*) addr->ai, 16); } #endif } @@ -654,7 +657,7 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline, return (Socket) ret; } -Socket sk_newlistener(int port, Plug plug, int local_host_only) +Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only) { static struct socket_function_table fn_table = { sk_tcp_plug, @@ -716,6 +719,8 @@ Socket sk_newlistener(int port, Plug plug, int local_host_only) if (addr->family == AF_INET6) { memset(&a6, 0, sizeof(a6)); a6.sin6_family = AF_INET6; + /* FIXME: srcaddr is ignored for IPv6, because I (SGT) don't + * know how to do it. :-) */ if (local_host_only) a6.sin6_addr = in6addr_loopback; else @@ -724,11 +729,32 @@ Socket sk_newlistener(int port, Plug plug, int local_host_only) } else #endif { + int got_addr = 0; a.sin_family = AF_INET; - if (local_host_only) - a.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - else - a.sin_addr.s_addr = htonl(INADDR_ANY); + + /* + * 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 != INADDR_NONE) { + /* 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 (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); } #ifdef IPV6 @@ -833,7 +859,9 @@ void try_send(Actual_Socket s) s->pending_error = err; return; } else { - logevent(winsock_error_string(err)); + /* We're inside the Windows frontend here, so we know + * that the frontend handle is unnecessary. */ + logevent(NULL, winsock_error_string(err)); fatalbox("%s", winsock_error_string(err)); } } else { @@ -899,6 +927,25 @@ int select_result(WPARAM wParam, LPARAM lParam) u_long atmark; /* wParam is the socket itself */ + + /* + * One user has reported an assertion failure in tree234 which + * indicates a null element pointer has been passed to a + * find*234 function. The following find234 is the only one in + * the whole program that I can see being capable of doing + * this, hence I'm forced to conclude that WinSock is capable + * of sending me netevent messages with wParam==0. I want to + * know what the rest of the message is if it does so! + */ + if (wParam == 0) { + char *str; + str = dupprintf("Strange WinSock message: wp=%08x lp=%08x", + (int)wParam, (int)lParam); + logevent(NULL, str); + connection_fatal(NULL, str); + sfree(str); + } + s = find234(sktree, (void *) wParam, cmpforsearch); if (!s) return 1; /* boggle */ @@ -972,7 +1019,9 @@ int select_result(WPARAM wParam, LPARAM lParam) if (ret <= 0) { char *str = (ret == 0 ? "Internal networking trouble" : winsock_error_string(WSAGetLastError())); - logevent(str); + /* We're inside the Windows frontend here, so we know + * that the frontend handle is unnecessary. */ + logevent(NULL, str); fatalbox("%s", str); } else { return plug_receive(s->plug, 2, buf, ret); @@ -1024,8 +1073,7 @@ int select_result(WPARAM wParam, LPARAM lParam) break; } - if (s->localhost_only && - ntohl(isa.sin_addr.s_addr) != INADDR_LOOPBACK) { + if (s->localhost_only && !ipv4_is_loopback(isa.sin_addr)) { closesocket(t); /* dodgy WinSock let nonlocal through */ } else if (plug_accepting(s->plug, (void*)t)) { closesocket(t); /* denied or error */ @@ -1134,3 +1182,13 @@ SOCKET next_socket(int *state) Actual_Socket s = index234(sktree, (*state)++); return s ? s->s : INVALID_SOCKET; } + +int net_service_lookup(char *service) +{ + struct servent *se; + se = getservbyname(service, NULL); + if (se != NULL) + return ntohs(se->s_port); + else + return 0; +}