diff options
author | Christian Grothoff <christian@grothoff.org> | 2013-09-17 13:23:07 +0000 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2013-09-17 13:23:07 +0000 |
commit | 0ac8167bf788134f942c72e0deea6f22af382e87 (patch) | |
tree | 5ac4798e97000f9ddee0722f761f00c041d8e868 /src/gns/gnunet-gns-proxy.c | |
parent | 7a02c0cc81e84a455d3281e9635d636c78c41351 (diff) | |
download | gnunet-0ac8167bf788134f942c72e0deea6f22af382e87.tar.gz gnunet-0ac8167bf788134f942c72e0deea6f22af382e87.zip |
starting to clean up socks5 handling
Diffstat (limited to 'src/gns/gnunet-gns-proxy.c')
-rw-r--r-- | src/gns/gnunet-gns-proxy.c | 629 |
1 files changed, 411 insertions, 218 deletions
diff --git a/src/gns/gnunet-gns-proxy.c b/src/gns/gnunet-gns-proxy.c index 217404f39..7deee988f 100644 --- a/src/gns/gnunet-gns-proxy.c +++ b/src/gns/gnunet-gns-proxy.c | |||
@@ -60,6 +60,13 @@ | |||
60 | #define POSTBUFFERSIZE 4096 | 60 | #define POSTBUFFERSIZE 4096 |
61 | 61 | ||
62 | /** | 62 | /** |
63 | * Size of the read/write buffers for Socks. Uses | ||
64 | * 256 bytes for the hostname (at most), plus a few | ||
65 | * bytes overhead for the messages. | ||
66 | */ | ||
67 | #define SOCKS_BUFFERSIZE (256 + 32) | ||
68 | |||
69 | /** | ||
63 | * Port for plaintext HTTP. | 70 | * Port for plaintext HTTP. |
64 | */ | 71 | */ |
65 | #define HTTP_PORT 80 | 72 | #define HTTP_PORT 80 |
@@ -97,22 +104,89 @@ | |||
97 | 104 | ||
98 | 105 | ||
99 | /** | 106 | /** |
100 | * The socks phases | 107 | * Commands in Socks5. |
108 | */ | ||
109 | enum Socks5Commands | ||
110 | { | ||
111 | /** | ||
112 | * Establish TCP/IP stream. | ||
113 | */ | ||
114 | SOCKS5_CMD_TCP_STREAM = 1, | ||
115 | |||
116 | /** | ||
117 | * Establish TCP port binding. | ||
118 | */ | ||
119 | SOCKS5_CMD_TCP_PORT = 2, | ||
120 | |||
121 | /** | ||
122 | * Establish UDP port binding. | ||
123 | */ | ||
124 | SOCKS5_CMD_UDP_PORT = 3 | ||
125 | }; | ||
126 | |||
127 | |||
128 | /** | ||
129 | * Address types in Socks5. | ||
130 | */ | ||
131 | enum Socks5AddressType | ||
132 | { | ||
133 | /** | ||
134 | * IPv4 address. | ||
135 | */ | ||
136 | SOCKS5_AT_IPV4 = 1, | ||
137 | |||
138 | /** | ||
139 | * IPv4 address. | ||
140 | */ | ||
141 | SOCKS5_AT_DOMAINNAME = 3, | ||
142 | |||
143 | /** | ||
144 | * IPv6 address. | ||
145 | */ | ||
146 | SOCKS5_AT_IPV6 = 4 | ||
147 | |||
148 | }; | ||
149 | |||
150 | |||
151 | /** | ||
152 | * Status codes in Socks5 response. | ||
153 | */ | ||
154 | enum Socks5StatusCode | ||
155 | { | ||
156 | SOCKS5_STATUS_REQUEST_GRANTED = 0, | ||
157 | SOCKS5_STATUS_GENERAL_FAILURE = 1, | ||
158 | SOCKS5_STATUS_CONNECTION_NOT_ALLOWED_BY_RULE = 2, | ||
159 | SOCKS5_STATUS_NETWORK_UNREACHABLE = 3, | ||
160 | SOCKS5_STATUS_HOST_UNREACHABLE = 4, | ||
161 | SOCKS5_STATUS_CONNECTION_REFUSED_BY_HOST = 5, | ||
162 | SOCKS5_STATUS_TTL_EXPIRED = 6, | ||
163 | SOCKS5_STATUS_COMMAND_NOT_SUPPORTED = 7, | ||
164 | SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED = 8 | ||
165 | }; | ||
166 | |||
167 | |||
168 | /** | ||
169 | * The socks phases. | ||
101 | */ | 170 | */ |
102 | enum SocksPhase | 171 | enum SocksPhase |
103 | { | 172 | { |
104 | /** | 173 | /** |
105 | * We're waiting to get the request. | 174 | * We're waiting to get the client hello. |
106 | */ | 175 | */ |
107 | SOCKS5_INIT, | 176 | SOCKS5_INIT, |
108 | 177 | ||
109 | /** | 178 | /** |
110 | * FIXME. | 179 | * We're waiting to get the initial request. |
111 | */ | 180 | */ |
112 | SOCKS5_REQUEST, | 181 | SOCKS5_REQUEST, |
113 | 182 | ||
114 | /** | 183 | /** |
115 | * FIXME. | 184 | * We are currently resolving the destination. |
185 | */ | ||
186 | SOCKS5_RESOLVING, | ||
187 | |||
188 | /** | ||
189 | * We're in transfer mode. | ||
116 | */ | 190 | */ |
117 | SOCKS5_DATA_TRANSFER | 191 | SOCKS5_DATA_TRANSFER |
118 | }; | 192 | }; |
@@ -190,11 +264,6 @@ struct Socks5Request | |||
190 | struct GNUNET_NETWORK_Handle *remote_sock; | 264 | struct GNUNET_NETWORK_Handle *remote_sock; |
191 | 265 | ||
192 | /** | 266 | /** |
193 | * The socks state | ||
194 | */ | ||
195 | enum SocksPhase state; | ||
196 | |||
197 | /** | ||
198 | * Client socket read task | 267 | * Client socket read task |
199 | */ | 268 | */ |
200 | GNUNET_SCHEDULER_TaskIdentifier rtask; | 269 | GNUNET_SCHEDULER_TaskIdentifier rtask; |
@@ -217,22 +286,32 @@ struct Socks5Request | |||
217 | /** | 286 | /** |
218 | * Read buffer | 287 | * Read buffer |
219 | */ | 288 | */ |
220 | char rbuf[2048]; | 289 | char rbuf[SOCKS_BUFFERSIZE]; |
221 | 290 | ||
222 | /** | 291 | /** |
223 | * Write buffer | 292 | * Write buffer |
224 | */ | 293 | */ |
225 | char wbuf[2048]; | 294 | char wbuf[SOCKS_BUFFERSIZE]; |
226 | 295 | ||
227 | /** | 296 | /** |
228 | * Length of data in read buffer | 297 | * Number of bytes already in read buffer |
229 | */ | 298 | */ |
230 | unsigned int rbuf_len; | 299 | size_t rbuf_len; |
231 | 300 | ||
232 | /** | 301 | /** |
233 | * Length of data in write buffer | 302 | * Number of bytes already in write buffer |
303 | */ | ||
304 | size_t wbuf_len; | ||
305 | |||
306 | /** | ||
307 | * Once known, what's the target address for the connection? | ||
234 | */ | 308 | */ |
235 | unsigned int wbuf_len; | 309 | struct sockaddr_storage destination_address; |
310 | |||
311 | /** | ||
312 | * The socks state | ||
313 | */ | ||
314 | enum SocksPhase state; | ||
236 | 315 | ||
237 | /** | 316 | /** |
238 | * This handle is scheduled for cleanup? | 317 | * This handle is scheduled for cleanup? |
@@ -538,10 +617,26 @@ struct Socks5ClientHelloMessage | |||
538 | */ | 617 | */ |
539 | uint8_t num_auth_methods; | 618 | uint8_t num_auth_methods; |
540 | 619 | ||
620 | /* followed by supported authentication methods, 1 byte per method */ | ||
621 | |||
622 | }; | ||
623 | |||
624 | |||
625 | /** | ||
626 | * Server hello in Socks5 protocol. | ||
627 | */ | ||
628 | struct Socks5ServerHelloMessage | ||
629 | { | ||
541 | /** | 630 | /** |
542 | * FIXME: this is not a message format... | 631 | * Should be #SOCKS_VERSION_5. |
543 | */ | 632 | */ |
544 | char* auth_methods; | 633 | uint8_t version; |
634 | |||
635 | /** | ||
636 | * Chosen authentication method, for us always #SOCKS_AUTH_NONE, | ||
637 | * which skips the authentication step. | ||
638 | */ | ||
639 | uint8_t auth_method; | ||
545 | }; | 640 | }; |
546 | 641 | ||
547 | 642 | ||
@@ -556,45 +651,29 @@ struct Socks5ClientRequestMessage | |||
556 | uint8_t version; | 651 | uint8_t version; |
557 | 652 | ||
558 | /** | 653 | /** |
559 | * FIXME: what goes here? | 654 | * Command code, we only uspport #SOCKS5_CMD_TCP_STREAM. |
560 | */ | 655 | */ |
561 | uint8_t command; | 656 | uint8_t command; |
562 | 657 | ||
563 | /** | 658 | /** |
564 | * FIXME: what goes here? | 659 | * Reserved, always zero. |
565 | */ | 660 | */ |
566 | uint8_t resvd; | 661 | uint8_t resvd; |
567 | 662 | ||
568 | /** | 663 | /** |
569 | * FIXME: what goes here? | 664 | * Address type, an `enum Socks5AddressType`. |
570 | */ | 665 | */ |
571 | uint8_t addr_type; | 666 | uint8_t addr_type; |
572 | 667 | ||
573 | /* | 668 | /* |
574 | * followed by either an ip4/ipv6 address | 669 | * Followed by either an ip4/ipv6 address or a domain name with a |
575 | * or a domain name with a length field in front | 670 | * length field (uint8_t) in front (depending on @e addr_type). |
671 | * followed by port number in network byte order (uint16_t). | ||
576 | */ | 672 | */ |
577 | }; | 673 | }; |
578 | 674 | ||
579 | 675 | ||
580 | /** | 676 | /** |
581 | * Server hello in Socks5 protocol. | ||
582 | */ | ||
583 | struct Socks5ServerHelloMessage | ||
584 | { | ||
585 | /** | ||
586 | * Should be #SOCKS_VERSION_5. | ||
587 | */ | ||
588 | uint8_t version; | ||
589 | |||
590 | /** | ||
591 | * FIXME: what goes here? | ||
592 | */ | ||
593 | uint8_t auth_method; | ||
594 | }; | ||
595 | |||
596 | |||
597 | /** | ||
598 | * Server response to client requests in Socks5 protocol. | 677 | * Server response to client requests in Socks5 protocol. |
599 | */ | 678 | */ |
600 | struct Socks5ServerResponseMessage | 679 | struct Socks5ServerResponseMessage |
@@ -605,24 +684,26 @@ struct Socks5ServerResponseMessage | |||
605 | uint8_t version; | 684 | uint8_t version; |
606 | 685 | ||
607 | /** | 686 | /** |
608 | * FIXME: what goes here? | 687 | * Status code, an `enum Socks5StatusCode` |
609 | */ | 688 | */ |
610 | uint8_t reply; | 689 | uint8_t reply; |
611 | 690 | ||
612 | /** | 691 | /** |
613 | * FIXME: what goes here? | 692 | * Always zero. |
614 | */ | 693 | */ |
615 | uint8_t reserved; | 694 | uint8_t reserved; |
616 | 695 | ||
617 | /** | 696 | /** |
618 | * FIXME: what goes here? | 697 | * Address type, an `enum Socks5AddressType`. |
619 | */ | 698 | */ |
620 | uint8_t addr_type; | 699 | uint8_t addr_type; |
621 | 700 | ||
622 | /** | 701 | /* |
623 | * FIXME: what goes here? | 702 | * Followed by either an ip4/ipv6 address or a domain name with a |
703 | * length field (uint8_t) in front (depending on @e addr_type). | ||
704 | * followed by port number in network byte order (uint16_t). | ||
624 | */ | 705 | */ |
625 | uint8_t add_port[18]; | 706 | |
626 | }; | 707 | }; |
627 | 708 | ||
628 | 709 | ||
@@ -747,6 +828,7 @@ static struct GNUNET_IDENTITY_Operation *id_op; | |||
747 | */ | 828 | */ |
748 | static const struct GNUNET_CONFIGURATION_Handle *cfg; | 829 | static const struct GNUNET_CONFIGURATION_Handle *cfg; |
749 | 830 | ||
831 | |||
750 | /** | 832 | /** |
751 | * Clean up s5r handles | 833 | * Clean up s5r handles |
752 | * | 834 | * |
@@ -774,6 +856,24 @@ cleanup_s5r (struct Socks5Request *s5r) | |||
774 | 856 | ||
775 | 857 | ||
776 | /** | 858 | /** |
859 | * Remove the first @a len bytes from the beginning of the read buffer. | ||
860 | * | ||
861 | * @param s5r the handle clear the read buffer for | ||
862 | * @param len number of bytes in read buffer to advance | ||
863 | */ | ||
864 | static void | ||
865 | clear_from_s5r_rbuf (struct Socks5Request *s5r, | ||
866 | size_t len) | ||
867 | { | ||
868 | GNUNET_assert (len <= s5r->rbuf_len); | ||
869 | memmove (s5r->rbuf, | ||
870 | &s5r->rbuf[len], | ||
871 | s5r->rbuf_len - len); | ||
872 | s5r->rbuf_len -= len; | ||
873 | } | ||
874 | |||
875 | |||
876 | /** | ||
777 | * Checks if name is in tld | 877 | * Checks if name is in tld |
778 | * | 878 | * |
779 | * @param name the name to check | 879 | * @param name the name to check |
@@ -2665,6 +2765,63 @@ add_handle_to_ssl_mhd (struct GNUNET_NETWORK_Handle *h, | |||
2665 | 2765 | ||
2666 | 2766 | ||
2667 | /** | 2767 | /** |
2768 | * Return a server response message indicating a failure to the client. | ||
2769 | * | ||
2770 | * @param s5r request to return failure code for | ||
2771 | * @param sc status code to return | ||
2772 | */ | ||
2773 | static void | ||
2774 | signal_socks_failure (struct Socks5Request *s5r, | ||
2775 | enum Socks5StatusCode sc) | ||
2776 | { | ||
2777 | struct Socks5ServerResponseMessage *s_resp; | ||
2778 | |||
2779 | s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len]; | ||
2780 | memset (s_resp, 0, sizeof (struct Socks5ServerResponseMessage)); | ||
2781 | s_resp->version = SOCKS_VERSION_5; | ||
2782 | s_resp->reply = sc; | ||
2783 | s5r->cleanup = GNUNET_YES; | ||
2784 | s5r->cleanup_sock = GNUNET_YES; | ||
2785 | if (GNUNET_SCHEDULER_NO_TASK != s5r->wtask) | ||
2786 | s5r->wtask = | ||
2787 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2788 | s5r->sock, | ||
2789 | &do_write, s5r); | ||
2790 | } | ||
2791 | |||
2792 | |||
2793 | /** | ||
2794 | * Return a server response message indicating success. | ||
2795 | * | ||
2796 | * @param s5r request to return success status message for | ||
2797 | */ | ||
2798 | static void | ||
2799 | signal_socks_success (struct Socks5Request *s5r) | ||
2800 | { | ||
2801 | struct Socks5ServerResponseMessage *s_resp; | ||
2802 | |||
2803 | s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf[s5r->wbuf_len]; | ||
2804 | s_resp->version = SOCKS_VERSION_5; | ||
2805 | s_resp->reply = SOCKS5_STATUS_REQUEST_GRANTED; | ||
2806 | s_resp->reserved = 0; | ||
2807 | s_resp->addr_type = SOCKS5_AT_IPV4; | ||
2808 | /* zero out IPv4 address and port */ | ||
2809 | memset (&s_resp[1], | ||
2810 | 0, | ||
2811 | sizeof (struct in_addr) + sizeof (uint16_t)); | ||
2812 | s5r->wbuf_len += sizeof (struct Socks5ServerResponseMessage) + | ||
2813 | sizeof (struct in_addr) + sizeof (uint16_t); | ||
2814 | s5r->cleanup = GNUNET_YES; | ||
2815 | s5r->cleanup_sock = GNUNET_NO; | ||
2816 | if (GNUNET_SCHEDULER_NO_TASK == s5r->wtask) | ||
2817 | s5r->wtask = | ||
2818 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2819 | s5r->sock, | ||
2820 | &do_write, s5r); | ||
2821 | } | ||
2822 | |||
2823 | |||
2824 | /** | ||
2668 | * Read data from incoming Socks5 connection | 2825 | * Read data from incoming Socks5 connection |
2669 | * | 2826 | * |
2670 | * @param cls the closure with the `struct Socks5Request` | 2827 | * @param cls the closure with the `struct Socks5Request` |
@@ -2674,213 +2831,249 @@ static void | |||
2674 | do_s5r_read (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc) | 2831 | do_s5r_read (void* cls, const struct GNUNET_SCHEDULER_TaskContext *tc) |
2675 | { | 2832 | { |
2676 | struct Socks5Request *s5r = cls; | 2833 | struct Socks5Request *s5r = cls; |
2677 | struct Socks5ClientHelloMessage *c_hello; | 2834 | const struct Socks5ClientHelloMessage *c_hello; |
2678 | struct Socks5ServerHelloMessage *s_hello; | 2835 | struct Socks5ServerHelloMessage *s_hello; |
2679 | struct Socks5ClientRequestMessage *c_req; | 2836 | const struct Socks5ClientRequestMessage *c_req; |
2680 | struct Socks5ServerResponseMessage *s_resp; | ||
2681 | int ret; | 2837 | int ret; |
2682 | char domain[256]; | 2838 | ssize_t rlen; |
2683 | uint8_t dom_len; | 2839 | size_t alen; |
2684 | uint16_t req_port; | ||
2685 | struct hostent *phost; | ||
2686 | uint32_t remote_ip; | ||
2687 | struct sockaddr_in remote_addr; | ||
2688 | struct in_addr *r_sin_addr; | ||
2689 | 2840 | ||
2690 | s5r->rtask = GNUNET_SCHEDULER_NO_TASK; | 2841 | s5r->rtask = GNUNET_SCHEDULER_NO_TASK; |
2691 | if ( (NULL != tc->read_ready) && | 2842 | if ( (NULL != tc->read_ready) && |
2692 | (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->sock)) ) | 2843 | (GNUNET_NETWORK_fdset_isset (tc->read_ready, s5r->sock)) ) |
2693 | s5r->rbuf_len = GNUNET_NETWORK_socket_recv (s5r->sock, s5r->rbuf, | ||
2694 | sizeof (s5r->rbuf)); | ||
2695 | else | ||
2696 | s5r->rbuf_len = 0; | ||
2697 | if (0 == s5r->rbuf_len) | ||
2698 | { | 2844 | { |
2699 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2845 | rlen = GNUNET_NETWORK_socket_recv (s5r->sock, |
2700 | "socks5 client disconnected.\n"); | 2846 | &s5r->rbuf[s5r->rbuf_len], |
2701 | cleanup_s5r (s5r); | 2847 | sizeof (s5r->rbuf) - s5r->rbuf_len); |
2702 | return; | 2848 | if (rlen <= 0) |
2849 | { | ||
2850 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2851 | "socks5 client disconnected.\n"); | ||
2852 | cleanup_s5r (s5r); | ||
2853 | return; | ||
2854 | } | ||
2855 | s5r->rbuf_len += rlen; | ||
2703 | } | 2856 | } |
2857 | s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2858 | s5r->sock, | ||
2859 | &do_s5r_read, s5r); | ||
2704 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2860 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
2705 | "Processing socks data in state %d\n", | 2861 | "Processing %u bytes of socks data in state %d\n", |
2862 | s5r->rbuf_len, | ||
2706 | s5r->state); | 2863 | s5r->state); |
2707 | switch (s5r->state) | 2864 | switch (s5r->state) |
2708 | { | 2865 | { |
2709 | case SOCKS5_INIT: | 2866 | case SOCKS5_INIT: |
2710 | /* FIXME: failed to check if we got enough data yet! */ | 2867 | c_hello = (const struct Socks5ClientHelloMessage*) &s5r->rbuf; |
2711 | c_hello = (struct Socks5ClientHelloMessage*) &s5r->rbuf; | 2868 | if ( (s5r->rbuf_len < sizeof (struct Socks5ClientHelloMessage)) || |
2712 | GNUNET_assert (c_hello->version == SOCKS_VERSION_5); | 2869 | (s5r->rbuf_len < sizeof (struct Socks5ClientHelloMessage) + c_hello->num_auth_methods) ) |
2713 | s_hello = (struct Socks5ServerHelloMessage*) &s5r->wbuf; | 2870 | return; /* need more data */ |
2714 | s5r->wbuf_len = sizeof( struct Socks5ServerHelloMessage ); | 2871 | if (SOCKS_VERSION_5 != c_hello->version) |
2715 | s_hello->version = c_hello->version; | 2872 | { |
2873 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2874 | _("Unsupported socks version %d\n"), | ||
2875 | (int) c_hello->version); | ||
2876 | cleanup_s5r (s5r); | ||
2877 | return; | ||
2878 | } | ||
2879 | clear_from_s5r_rbuf (s5r, | ||
2880 | sizeof (struct Socks5ClientHelloMessage) + c_hello->num_auth_methods); | ||
2881 | GNUNET_assert (0 == s5r->wbuf_len); | ||
2882 | s_hello = (struct Socks5ServerHelloMessage *) &s5r->wbuf; | ||
2883 | s5r->wbuf_len = sizeof (struct Socks5ServerHelloMessage); | ||
2884 | s_hello->version = SOCKS_VERSION_5; | ||
2716 | s_hello->auth_method = SOCKS_AUTH_NONE; | 2885 | s_hello->auth_method = SOCKS_AUTH_NONE; |
2717 | /* Write response to client */ | 2886 | GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == s5r->wtask); |
2718 | s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | 2887 | s5r->wtask = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, |
2719 | s5r->sock, | 2888 | s5r->sock, |
2720 | &do_write, s5r); | 2889 | &do_write, s5r); |
2721 | s5r->rtask = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2722 | s5r->sock, | ||
2723 | &do_s5r_read, s5r); | ||
2724 | s5r->state = SOCKS5_REQUEST; | 2890 | s5r->state = SOCKS5_REQUEST; |
2725 | return; | 2891 | return; |
2726 | case SOCKS5_REQUEST: | 2892 | case SOCKS5_REQUEST: |
2727 | /* FIXME: failed to check if we got enough data yet!? */ | 2893 | c_req = (const struct Socks5ClientRequestMessage *) &s5r->rbuf; |
2728 | c_req = (struct Socks5ClientRequestMessage *) &s5r->rbuf; | 2894 | if (s5r->rbuf_len < sizeof (struct Socks5ClientRequestMessage)) |
2729 | s_resp = (struct Socks5ServerResponseMessage *) &s5r->wbuf; | 2895 | return; |
2730 | //Only 10 byte for ipv4 response! | 2896 | switch (c_req->command) |
2731 | s5r->wbuf_len = 10;//sizeof (struct Socks5ServerResponseMessage); | ||
2732 | GNUNET_assert (c_req->addr_type == 3); | ||
2733 | dom_len = *((uint8_t*)(&(c_req->addr_type) + 1)); | ||
2734 | memset(domain, 0, sizeof(domain)); | ||
2735 | strncpy(domain, (char*)(&(c_req->addr_type) + 2), dom_len); | ||
2736 | req_port = *((uint16_t*)(&(c_req->addr_type) + 2 + dom_len)); | ||
2737 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2738 | "Requested connection is to %s:%d\n", | ||
2739 | domain, | ||
2740 | ntohs(req_port)); | ||
2741 | if (is_tld (domain, GNUNET_GNS_TLD) || | ||
2742 | is_tld (domain, GNUNET_GNS_TLD_ZKEY)) | ||
2743 | { | 2897 | { |
2744 | /* GNS TLD */ | 2898 | case SOCKS5_CMD_TCP_STREAM: |
2745 | ret = MHD_NO; | 2899 | /* handled below */ |
2746 | if (ntohs (req_port) == HTTPS_PORT) | 2900 | break; |
2747 | { | 2901 | default: |
2748 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2902 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, |
2749 | "Requested connection is HTTPS\n"); | 2903 | _("Unsupported socks command %d\n"), |
2750 | ret = add_handle_to_ssl_mhd ( s5r->sock, domain ); | 2904 | (int) c_req->command); |
2751 | } | 2905 | signal_socks_failure (s5r, |
2752 | else if (NULL != httpd) | 2906 | SOCKS5_STATUS_COMMAND_NOT_SUPPORTED); |
2753 | { | ||
2754 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2755 | "Requested connection is HTTP\n"); | ||
2756 | ret = add_handle_to_mhd (s5r->sock, httpd ); | ||
2757 | } | ||
2758 | |||
2759 | if (ret != MHD_YES) | ||
2760 | { | ||
2761 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2762 | _("Failed to start HTTP server\n")); | ||
2763 | s_resp->version = 0x05; | ||
2764 | s_resp->reply = 0x01; | ||
2765 | s5r->cleanup = GNUNET_YES; | ||
2766 | s5r->cleanup_sock = GNUNET_YES; | ||
2767 | s5r->wtask = | ||
2768 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2769 | s5r->sock, | ||
2770 | &do_write, s5r); | ||
2771 | return; | ||
2772 | } | ||
2773 | |||
2774 | /* Signal success */ | ||
2775 | s_resp->version = 0x05; | ||
2776 | s_resp->reply = 0x00; | ||
2777 | s_resp->reserved = 0x00; | ||
2778 | s_resp->addr_type = 0x01; | ||
2779 | |||
2780 | s5r->cleanup = GNUNET_YES; | ||
2781 | s5r->cleanup_sock = GNUNET_NO; | ||
2782 | s5r->wtask = | ||
2783 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2784 | s5r->sock, | ||
2785 | &do_write, s5r); | ||
2786 | run_httpds (); | ||
2787 | return; | 2907 | return; |
2788 | } | 2908 | } |
2789 | else | 2909 | switch (c_req->addr_type) |
2790 | { | 2910 | { |
2791 | /* non-GNS TLD, use DNS to resolve */ | 2911 | case SOCKS5_AT_IPV4: |
2792 | /* FIXME: make asynchronous! */ | ||
2793 | phost = (struct hostent *) gethostbyname (domain); | ||
2794 | if (phost == NULL) | ||
2795 | { | 2912 | { |
2796 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2913 | const struct in_addr *v4 = (const struct in_addr *) &c_req[1]; |
2797 | "Resolve %s error!\n", domain ); | 2914 | const uint16_t *port = (const uint16_t *) &v4[1]; |
2798 | s_resp->version = 0x05; | 2915 | struct sockaddr_in *in; |
2799 | s_resp->reply = 0x01; | 2916 | |
2800 | s5r->cleanup = GNUNET_YES; | 2917 | alen = sizeof (struct in_addr); |
2801 | s5r->cleanup_sock = GNUNET_YES; | 2918 | if (s5r->rbuf_len < sizeof (struct Socks5ClientRequestMessage) + |
2802 | s5r->wtask = | 2919 | alen + sizeof (uint16_t)) |
2803 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | 2920 | return; /* need more data */ |
2804 | s5r->sock, | 2921 | in = (struct sockaddr_in *) &s5r->destination_address; |
2805 | &do_write, s5r); | 2922 | in->sin_family = AF_INET; |
2806 | return; | 2923 | in->sin_addr = *v4; |
2807 | } | 2924 | in->sin_port = *port; |
2808 | |||
2809 | s5r->remote_sock = GNUNET_NETWORK_socket_create (AF_INET, | ||
2810 | SOCK_STREAM, | ||
2811 | 0); | ||
2812 | r_sin_addr = (struct in_addr*)(phost->h_addr); | ||
2813 | remote_ip = r_sin_addr->s_addr; | ||
2814 | memset(&remote_addr, 0, sizeof(remote_addr)); | ||
2815 | remote_addr.sin_family = AF_INET; | ||
2816 | #if HAVE_SOCKADDR_IN_SIN_LEN | 2925 | #if HAVE_SOCKADDR_IN_SIN_LEN |
2817 | remote_addr.sin_len = sizeof (remote_addr); | 2926 | in->sin_len = sizeof (*in); |
2818 | #endif | 2927 | #endif |
2819 | remote_addr.sin_addr.s_addr = remote_ip; | 2928 | s5r->state = SOCKS5_DATA_TRANSFER; |
2820 | remote_addr.sin_port = req_port; | ||
2821 | |||
2822 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2823 | "target server: %s:%u\n", inet_ntoa(remote_addr.sin_addr), | ||
2824 | ntohs(req_port)); | ||
2825 | |||
2826 | if ((GNUNET_OK != | ||
2827 | GNUNET_NETWORK_socket_connect ( s5r->remote_sock, | ||
2828 | (const struct sockaddr*)&remote_addr, | ||
2829 | sizeof (remote_addr))) | ||
2830 | && (errno != EINPROGRESS)) | ||
2831 | { | ||
2832 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect"); | ||
2833 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
2834 | "socket request error...\n"); | ||
2835 | s_resp->version = 0x05; | ||
2836 | s_resp->reply = 0x01; | ||
2837 | s5r->wtask = | ||
2838 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2839 | s5r->sock, | ||
2840 | &do_write, s5r); | ||
2841 | //TODO see above | ||
2842 | return; | ||
2843 | } | 2929 | } |
2844 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2930 | break; |
2845 | "new remote connection\n"); | 2931 | case SOCKS5_AT_DOMAINNAME: |
2846 | s_resp->version = 0x05; | ||
2847 | s_resp->reply = 0x00; | ||
2848 | s_resp->reserved = 0x00; | ||
2849 | s_resp->addr_type = 0x01; | ||
2850 | s5r->state = SOCKS5_DATA_TRANSFER; | ||
2851 | s5r->wtask = | ||
2852 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2853 | s5r->sock, | ||
2854 | &do_write, s5r); | ||
2855 | s5r->rtask = | ||
2856 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2857 | s5r->sock, | ||
2858 | &do_s5r_read, s5r); | ||
2859 | } | ||
2860 | return; | ||
2861 | case SOCKS5_DATA_TRANSFER: | ||
2862 | { | ||
2863 | if ((s5r->remote_sock == NULL) || (s5r->rbuf_len == 0)) | ||
2864 | { | 2932 | { |
2933 | const uint8_t *dom_len; | ||
2934 | const char *dom_name; | ||
2935 | const uint16_t *port; | ||
2936 | char domain[256]; | ||
2937 | struct hostent *phost; | ||
2938 | uint32_t remote_ip; | ||
2939 | struct sockaddr_in remote_addr; | ||
2940 | struct in_addr *r_sin_addr; | ||
2941 | |||
2942 | dom_len = (const uint8_t *) &c_req[1]; | ||
2943 | alen = *dom_len + 1; | ||
2944 | if (s5r->rbuf_len < sizeof (struct Socks5ClientRequestMessage) + | ||
2945 | alen + sizeof (uint16_t)) | ||
2946 | return; /* need more data */ | ||
2947 | dom_name = (const char *) &dom_len[1]; | ||
2948 | port = (const uint16_t*) &dom_name[*dom_len]; | ||
2949 | |||
2950 | |||
2951 | strncpy (domain, dom_name, *dom_len); | ||
2952 | domain[*dom_len] = '\0'; | ||
2953 | |||
2865 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 2954 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, |
2866 | "Closing connection to client\n"); | 2955 | "Requested connection is to %s:%d\n", |
2867 | cleanup_s5r (s5r); | 2956 | domain, |
2868 | return; | 2957 | ntohs (*port)); |
2958 | |||
2959 | if (is_tld (domain, GNUNET_GNS_TLD) || | ||
2960 | is_tld (domain, GNUNET_GNS_TLD_ZKEY)) | ||
2961 | { | ||
2962 | /* GNS TLD */ | ||
2963 | ret = MHD_NO; | ||
2964 | if (ntohs (*port) == HTTPS_PORT) | ||
2965 | { | ||
2966 | ret = add_handle_to_ssl_mhd (s5r->sock, domain); | ||
2967 | } | ||
2968 | else | ||
2969 | { | ||
2970 | ret = add_handle_to_mhd (s5r->sock, httpd); | ||
2971 | } | ||
2972 | if (ret != MHD_YES) | ||
2973 | { | ||
2974 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
2975 | _("Failed to start HTTP server\n")); | ||
2976 | signal_socks_failure (s5r, | ||
2977 | SOCKS5_STATUS_GENERAL_FAILURE); | ||
2978 | return; | ||
2979 | } | ||
2980 | } | ||
2981 | else | ||
2982 | { | ||
2983 | /* non-GNS TLD, use DNS to resolve */ | ||
2984 | /* FIXME: make asynchronous! */ | ||
2985 | phost = (struct hostent *) gethostbyname (domain); | ||
2986 | if (phost == NULL) | ||
2987 | { | ||
2988 | GNUNET_log (GNUNET_ERROR_TYPE_WARNING, | ||
2989 | "Failed to resolve `%s'!\n", | ||
2990 | domain); | ||
2991 | signal_socks_failure (s5r, | ||
2992 | SOCKS5_STATUS_GENERAL_FAILURE); | ||
2993 | return; | ||
2994 | } | ||
2995 | |||
2996 | s5r->remote_sock = GNUNET_NETWORK_socket_create (AF_INET, | ||
2997 | SOCK_STREAM, | ||
2998 | 0); | ||
2999 | r_sin_addr = (struct in_addr*)(phost->h_addr); | ||
3000 | remote_ip = r_sin_addr->s_addr; | ||
3001 | memset(&remote_addr, 0, sizeof(remote_addr)); | ||
3002 | remote_addr.sin_family = AF_INET; | ||
3003 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
3004 | remote_addr.sin_len = sizeof (remote_addr); | ||
3005 | #endif | ||
3006 | remote_addr.sin_addr.s_addr = remote_ip; | ||
3007 | remote_addr.sin_port = *port; | ||
3008 | |||
3009 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | ||
3010 | "target server: %s:%u\n", | ||
3011 | inet_ntoa(remote_addr.sin_addr), | ||
3012 | ntohs(*port)); | ||
3013 | |||
3014 | if ((GNUNET_OK != | ||
3015 | GNUNET_NETWORK_socket_connect ( s5r->remote_sock, | ||
3016 | (const struct sockaddr*)&remote_addr, | ||
3017 | sizeof (remote_addr))) | ||
3018 | && (errno != EINPROGRESS)) | ||
3019 | { | ||
3020 | GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "connect"); | ||
3021 | signal_socks_failure (s5r, | ||
3022 | SOCKS5_STATUS_NETWORK_UNREACHABLE); | ||
3023 | return; | ||
3024 | } | ||
3025 | s5r->state = SOCKS5_DATA_TRANSFER; | ||
3026 | } | ||
3027 | break; | ||
2869 | } | 3028 | } |
2870 | GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, | 3029 | case SOCKS5_AT_IPV6: |
2871 | "forwarding %d bytes from client\n", s5r->rbuf_len); | ||
2872 | s5r->fwdwtask = | ||
2873 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
2874 | s5r->remote_sock, | ||
2875 | &do_write_remote, s5r); | ||
2876 | if (s5r->fwdrtask == GNUNET_SCHEDULER_NO_TASK) | ||
2877 | { | 3030 | { |
2878 | s5r->fwdrtask = | 3031 | const struct in6_addr *v6 = (const struct in6_addr *) &c_req[1]; |
2879 | GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL, | 3032 | const uint16_t *port = (const uint16_t *) &v6[1]; |
2880 | s5r->remote_sock, | 3033 | struct sockaddr_in6 *in; |
2881 | &do_read_remote, s5r); | 3034 | |
3035 | alen = sizeof (struct in6_addr); | ||
3036 | if (s5r->rbuf_len < sizeof (struct Socks5ClientRequestMessage) + | ||
3037 | alen + sizeof (uint16_t)) | ||
3038 | return; /* need more data */ | ||
3039 | in = (struct sockaddr_in6 *) &s5r->destination_address; | ||
3040 | in->sin6_family = AF_INET6; | ||
3041 | in->sin6_addr = *v6; | ||
3042 | in->sin6_port = *port; | ||
3043 | #if HAVE_SOCKADDR_IN_SIN_LEN | ||
3044 | in->sin6_len = sizeof (*in); | ||
3045 | #endif | ||
3046 | s5r->state = SOCKS5_DATA_TRANSFER; | ||
2882 | } | 3047 | } |
3048 | break; | ||
3049 | default: | ||
3050 | GNUNET_log (GNUNET_ERROR_TYPE_ERROR, | ||
3051 | _("Unsupported socks address type %d\n"), | ||
3052 | (int) c_req->addr_type); | ||
3053 | signal_socks_failure (s5r, | ||
3054 | SOCKS5_STATUS_ADDRESS_TYPE_NOT_SUPPORTED); | ||
3055 | return; | ||
3056 | } | ||
3057 | clear_from_s5r_rbuf (s5r, | ||
3058 | sizeof (struct Socks5ClientRequestMessage) + | ||
3059 | alen + sizeof (uint16_t)); | ||
3060 | if (0 != s5r->rbuf_len) | ||
3061 | { | ||
3062 | /* read more bytes than healthy, why did the client send more? */ | ||
3063 | GNUNET_break_op (0); | ||
3064 | signal_socks_failure (s5r, | ||
3065 | SOCKS5_STATUS_GENERAL_FAILURE); | ||
3066 | return; | ||
2883 | } | 3067 | } |
3068 | signal_socks_success (s5r); | ||
3069 | run_httpds (); // needed here!? | ||
3070 | return; | ||
3071 | case SOCKS5_DATA_TRANSFER: | ||
3072 | GNUNET_assert (0 < s5r->rbuf_len); | ||
3073 | if (GNUNET_SCHEDULER_NO_TASK == s5r->wtask) | ||
3074 | GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL, | ||
3075 | s5r->remote_sock, | ||
3076 | &do_write /* _remote */, s5r); | ||
2884 | return; | 3077 | return; |
2885 | default: | 3078 | default: |
2886 | GNUNET_break (0); | 3079 | GNUNET_break (0); |