| CODENOTIFIER | HelpYou are not signed inSign in |
Project: Putty
Revision: 8150
Author: jacob
Date: 20 Aug 2008 18:21:04
Changes:Fix for portfwd-addr-family: on Unix, when a tunnel is specified as "Auto"
(rather than IPv4 or IPv6-only; this is the default), try to open up listening
sockets on both address families, rather than (unhelpfully) just IPv6. (And
don't open one if the other can't be bound, in a nod to CVE-2008-1483.)
Based on a patch from Ben A L Jemmett.
| ... | ...@@ -31,6 +31,16 @@ | |
| 31 | 31 | # define X11_UNIX_PATH "/tmp/.X11-unix/X" |
| 32 | 32 | #endif |
| 33 | 33 | |
| 34 | /* | |
| 35 | * We used to typedef struct Socket_tag *Socket. | |
| 36 | * | |
| 37 | * Since we have made the networking abstraction slightly more | |
| 38 | * abstract, Socket no longer means a tcp socket (it could mean | |
| 39 | * an ssl socket). So now we must use Actual_Socket when we know | |
| 40 | * we are talking about a tcp socket. | |
| 41 | */ | |
| 42 | typedef struct Socket_tag *Actual_Socket; | |
| 43 | ||
| 34 | 44 | struct Socket_tag { |
| 35 | 45 | struct socket_function_table *fn; |
| 36 | 46 | /* the above variable absolutely *must* be the first in this structure */ |
| ... | ...@@ -54,18 +64,15 @@ | |
| 54 | 64 | int nodelay, keepalive; /* for connect()-type sockets */ |
| 55 | 65 | int privport, port; /* and again */ |
| 56 | 66 | SockAddr addr; |
| 67 | /* | |
| 68 | * We sometimes need pairs of Socket structures to be linked: | |
| 69 | * if we are listening on the same IPv6 and v4 port, for | |
| 70 | * example. So here we define `parent' and `child' pointers to | |
| 71 | * track this link. | |
| 72 | */ | |
| 73 | Actual_Socket parent, child; | |
| 57 | 74 | }; |
| 58 | 75 | |
| 59 | /* | |
| 60 | * We used to typedef struct Socket_tag *Socket. | |
| 61 | * | |
| 62 | * Since we have made the networking abstraction slightly more | |
| 63 | * abstract, Socket no longer means a tcp socket (it could mean | |
| 64 | * an ssl socket). So now we must use Actual_Socket when we know | |
| 65 | * we are talking about a tcp socket. | |
| 66 | */ | |
| 67 | typedef struct Socket_tag *Actual_Socket; | |
| 68 | ||
| 69 | 76 | struct SockAddr_tag { |
| 70 | 77 | const char *error; |
| 71 | 78 | /* |
| ... | ...@@ -426,6 +433,7 @@ | |
| 426 | 433 | ret->pending_error = 0; |
| 427 | 434 | ret->oobpending = FALSE; |
| 428 | 435 | ret->listener = 0; |
| 436 | ret->parent = ret->child = NULL; | |
| 429 | 437 | ret->addr = NULL; |
| 430 | 438 | ret->connected = 1; |
| 431 | 439 | |
| ... | ...@@ -651,6 +659,7 @@ | |
| 651 | 659 | ret->frozen_readable = 0; |
| 652 | 660 | ret->localhost_only = 0; /* unused, but best init anyway */ |
| 653 | 661 | ret->pending_error = 0; |
| 662 | ret->parent = ret->child = NULL; | |
| 654 | 663 | ret->oobpending = FALSE; |
| 655 | 664 | ret->listener = 0; |
| 656 | 665 | ret->addr = addr; |
| ... | ...@@ -672,7 +681,7 @@ | |
| 672 | 681 | return (Socket) ret; |
| 673 | 682 | } |
| 674 | 683 | |
| 675 | Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, int address_family) | |
| 684 | Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only, int orig_address_family) | |
| 676 | 685 | { |
| 677 | 686 | int s; |
| 678 | 687 | #ifndef NO_IPV6 |
| ... | ...@@ -685,6 +694,7 @@ | |
| 685 | 694 | struct sockaddr_in a; |
| 686 | 695 | Actual_Socket ret; |
| 687 | 696 | int retcode; |
| 697 | int address_family; | |
| 688 | 698 | int on = 1; |
| 689 | 699 | |
| 690 | 700 | /* |
| ... | ...@@ -701,6 +711,7 @@ | |
| 701 | 711 | ret->frozen_readable = 0; |
| 702 | 712 | ret->localhost_only = local_host_only; |
| 703 | 713 | ret->pending_error = 0; |
| 714 | ret->parent = ret->child = NULL; | |
| 704 | 715 | ret->oobpending = FALSE; |
| 705 | 716 | ret->listener = 1; |
| 706 | 717 | ret->addr = NULL; |
| ... | ...@@ -709,9 +720,9 @@ | |
| 709 | 720 | * Translate address_family from platform-independent constants |
| 710 | 721 | * into local reality. |
| 711 | 722 | */ |
| 712 | address_family = (address_family == ADDRTYPE_IPV4 ? AF_INET : | |
| 723 | address_family = (orig_address_family == ADDRTYPE_IPV4 ? AF_INET : | |
| 713 | 724 | #ifndef NO_IPV6 |
| 714 | address_family == ADDRTYPE_IPV6 ? AF_INET6 : | |
| 725 | orig_address_family == ADDRTYPE_IPV6 ? AF_INET6 : | |
| 715 | 726 | #endif |
| 716 | 727 | AF_UNSPEC); |
| 717 | 728 | |
| ... | ...@@ -823,6 +834,32 @@ | |
| 823 | 834 | return (Socket) ret; |
| 824 | 835 | } |
| 825 | 836 | |
| 837 | #ifndef NO_IPV6 | |
| 838 | /* | |
| 839 | * If we were given ADDRTYPE_UNSPEC, we must also create an | |
| 840 | * IPv4 listening socket and link it to this one. | |
| 841 | */ | |
| 842 | if (address_family == AF_INET6 && orig_address_family == ADDRTYPE_UNSPEC) { | |
| 843 | Actual_Socket other; | |
| 844 | ||
| 845 | other = (Actual_Socket) sk_newlistener(srcaddr, port, plug, | |
| 846 | local_host_only, ADDRTYPE_IPV4); | |
| 847 | ||
| 848 | if (other) { | |
| 849 | if (!other->error) { | |
| 850 | other->parent = ret; | |
| 851 | ret->child = other; | |
| 852 | } else { | |
| 853 | /* If we couldn't create a listening socket on IPv4 as well | |
| 854 | * as IPv6, we must return an error overall. */ | |
| 855 | close(s); | |
| 856 | sfree(ret); | |
| 857 | return (Socket) other; | |
| 858 | } | |
| 859 | } | |
| 860 | } | |
| 861 | #endif | |
| 862 | ||
| 826 | 863 | ret->s = s; |
| 827 | 864 | |
| 828 | 865 | uxsel_tell(ret); |
| ... | ...@@ -835,6 +872,9 @@ | |
| 835 | 872 | { |
| 836 | 873 | Actual_Socket s = (Actual_Socket) sock; |
| 837 | 874 | |
| 875 | if (s->child) | |
| 876 | sk_tcp_close((Socket)s->child); | |
| 877 | ||
| 838 | 878 | uxsel_del(s->s); |
| 839 | 879 | del234(sktree, s); |
| 840 | 880 | close(s->s); |