cosmetics
[tomato.git] / release / src / router / openvpn / proxy.c
blob6e5a30a0375977c450a596fc7f8a85f3ce1dbd8f
1 /*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
8 * Copyright (C) 2002-2009 OpenVPN Technologies, Inc. <sales@openvpn.net>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program (see the file COPYING included with this
21 * distribution); if not, write to the Free Software Foundation, Inc.,
22 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "syshead.h"
27 #include "common.h"
28 #include "misc.h"
29 #include "win32.h"
30 #include "socket.h"
31 #include "fdmisc.h"
32 #include "proxy.h"
33 #include "base64.h"
34 #include "ntlm.h"
36 #ifdef WIN32
37 #include "ieproxy.h"
38 #endif
40 #include "memdbg.h"
42 #ifdef ENABLE_HTTP_PROXY
44 /* cached proxy username/password */
45 static struct user_pass static_proxy_user_pass;
47 static bool
48 recv_line (socket_descriptor_t sd,
49 char *buf,
50 int len,
51 const int timeout_sec,
52 const bool verbose,
53 struct buffer *lookahead,
54 volatile int *signal_received)
56 struct buffer la;
57 int lastc = 0;
59 CLEAR (la);
60 if (lookahead)
61 la = *lookahead;
63 while (true)
65 int status;
66 ssize_t size;
67 fd_set reads;
68 struct timeval tv;
69 uint8_t c;
71 if (buf_defined (&la))
73 ASSERT (buf_init (&la, 0));
76 FD_ZERO (&reads);
77 FD_SET (sd, &reads);
78 tv.tv_sec = timeout_sec;
79 tv.tv_usec = 0;
81 status = select (sd + 1, &reads, NULL, NULL, &tv);
83 get_signal (signal_received);
84 if (*signal_received)
85 goto error;
87 /* timeout? */
88 if (status == 0)
90 if (verbose)
91 msg (D_LINK_ERRORS | M_ERRNO_SOCK, "recv_line: TCP port read timeout expired");
92 goto error;
95 /* error */
96 if (status < 0)
98 if (verbose)
99 msg (D_LINK_ERRORS | M_ERRNO_SOCK, "recv_line: TCP port read failed on select()");
100 goto error;
103 /* read single char */
104 size = recv (sd, &c, 1, MSG_NOSIGNAL);
106 /* error? */
107 if (size != 1)
109 if (verbose)
110 msg (D_LINK_ERRORS | M_ERRNO_SOCK, "recv_line: TCP port read failed on recv()");
111 goto error;
114 #if 0
115 if (isprint(c))
116 msg (M_INFO, "PROXY: read '%c' (%d)", c, (int)c);
117 else
118 msg (M_INFO, "PROXY: read (%d)", (int)c);
119 #endif
121 /* store char in buffer */
122 if (len > 1)
124 *buf++ = c;
125 --len;
128 /* also store char in lookahead buffer */
129 if (buf_defined (&la))
131 buf_write_u8 (&la, c);
132 if (!isprint(c) && !isspace(c)) /* not ascii? */
134 if (verbose)
135 msg (D_LINK_ERRORS | M_ERRNO_SOCK, "recv_line: Non-ASCII character (%d) read on recv()", (int)c);
136 *lookahead = la;
137 return false;
141 /* end of line? */
142 if (lastc == '\r' && c == '\n')
143 break;
145 lastc = c;
148 /* append trailing null */
149 if (len > 0)
150 *buf++ = '\0';
152 return true;
154 error:
155 return false;
158 static bool
159 send_line (socket_descriptor_t sd,
160 const char *buf)
162 const ssize_t size = send (sd, buf, strlen (buf), MSG_NOSIGNAL);
163 if (size != (ssize_t) strlen (buf))
165 msg (D_LINK_ERRORS | M_ERRNO_SOCK, "send_line: TCP port write failed on send()");
166 return false;
168 return true;
171 static bool
172 send_line_crlf (socket_descriptor_t sd,
173 const char *src)
175 bool ret;
177 struct buffer buf = alloc_buf (strlen (src) + 3);
178 ASSERT (buf_write (&buf, src, strlen (src)));
179 ASSERT (buf_write (&buf, "\r\n", 3));
180 ret = send_line (sd, BSTR (&buf));
181 free_buf (&buf);
182 return ret;
185 static bool
186 send_crlf (socket_descriptor_t sd)
188 return send_line_crlf (sd, "");
191 uint8_t *
192 make_base64_string2 (const uint8_t *str, int src_len, struct gc_arena *gc)
194 uint8_t *ret = NULL;
195 char *b64out = NULL;
196 ASSERT (base64_encode ((const void *)str, src_len, &b64out) >= 0);
197 ret = (uint8_t *) string_alloc (b64out, gc);
198 free (b64out);
199 return ret;
202 uint8_t *
203 make_base64_string (const uint8_t *str, struct gc_arena *gc)
205 return make_base64_string2 (str, strlen ((const char *)str), gc);
208 static const char *
209 username_password_as_base64 (const struct http_proxy_info *p,
210 struct gc_arena *gc)
212 struct buffer out = alloc_buf_gc (strlen (p->up.username) + strlen (p->up.password) + 2, gc);
213 ASSERT (strlen (p->up.username) > 0);
214 buf_printf (&out, "%s:%s", p->up.username, p->up.password);
215 return (const char *)make_base64_string ((const uint8_t*)BSTR (&out), gc);
218 static void
219 get_user_pass_http (struct http_proxy_info *p, const bool force)
221 if (!static_proxy_user_pass.defined || force)
223 get_user_pass (&static_proxy_user_pass,
224 p->options.auth_file,
225 "HTTP Proxy",
226 GET_USER_PASS_MANAGEMENT);
227 p->up = static_proxy_user_pass;
231 struct http_proxy_info *
232 http_proxy_new (const struct http_proxy_options *o,
233 struct auto_proxy_info *auto_proxy_info)
235 struct http_proxy_info *p;
236 struct http_proxy_options opt;
238 if (auto_proxy_info)
240 if (o && o->server)
242 /* if --http-proxy explicitly given, disable auto-proxy */
243 auto_proxy_info = NULL;
245 else
247 /* if no --http-proxy explicitly given and no auto settings, fail */
248 if (!auto_proxy_info->http.server)
249 return NULL;
251 if (o)
253 opt = *o;
255 else
257 CLEAR (opt);
259 /* These settings are only used for --auto-proxy */
260 opt.timeout = 5;
261 opt.http_version = "1.0";
264 opt.server = auto_proxy_info->http.server;
265 opt.port = auto_proxy_info->http.port;
266 opt.auth_retry = true;
268 o = &opt;
272 if (!o || !o->server)
273 msg (M_FATAL, "HTTP_PROXY: server not specified");
275 ASSERT (legal_ipv4_port (o->port));
277 ALLOC_OBJ_CLEAR (p, struct http_proxy_info);
278 p->options = *o;
280 /* parse authentication method */
281 p->auth_method = HTTP_AUTH_NONE;
282 if (o->auth_method_string)
284 if (!strcmp (o->auth_method_string, "none"))
285 p->auth_method = HTTP_AUTH_NONE;
286 else if (!strcmp (o->auth_method_string, "basic"))
287 p->auth_method = HTTP_AUTH_BASIC;
288 else if (!strcmp (o->auth_method_string, "ntlm"))
289 p->auth_method = HTTP_AUTH_NTLM;
290 else if (!strcmp (o->auth_method_string, "ntlm2"))
291 p->auth_method = HTTP_AUTH_NTLM2;
292 else
293 msg (M_FATAL, "ERROR: unknown HTTP authentication method: '%s' -- only the 'none', 'basic', 'ntlm', or 'ntlm2' methods are currently supported",
294 o->auth_method_string);
297 /* only basic and NTLM/NTLMv2 authentication supported so far */
298 if (p->auth_method == HTTP_AUTH_BASIC || p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2)
300 get_user_pass_http (p, true);
303 #if !NTLM
304 if (p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2)
305 msg (M_FATAL, "Sorry, this version of " PACKAGE_NAME " was built without NTLM Proxy support.");
306 #endif
308 p->defined = true;
309 return p;
312 void
313 http_proxy_close (struct http_proxy_info *hp)
315 free (hp);
318 bool
319 establish_http_proxy_passthru (struct http_proxy_info *p,
320 socket_descriptor_t sd, /* already open to proxy */
321 const char *host, /* openvpn server remote */
322 const int port, /* openvpn server port */
323 struct buffer *lookahead,
324 volatile int *signal_received)
326 struct gc_arena gc = gc_new ();
327 char buf[256];
328 char buf2[128];
329 char get[80];
330 int status;
331 int nparms;
332 bool ret = false;
334 /* get user/pass if not previously given or if --auto-proxy is being used */
335 if (p->auth_method == HTTP_AUTH_BASIC
336 || p->auth_method == HTTP_AUTH_NTLM)
337 get_user_pass_http (p, false);
339 /* format HTTP CONNECT message */
340 openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s",
341 host,
342 port,
343 p->options.http_version);
345 msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
347 /* send HTTP CONNECT message to proxy */
348 if (!send_line_crlf (sd, buf))
349 goto error;
351 /* send User-Agent string if provided */
352 if (p->options.user_agent)
354 openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s",
355 p->options.user_agent);
356 if (!send_line_crlf (sd, buf))
357 goto error;
360 /* auth specified? */
361 switch (p->auth_method)
363 case HTTP_AUTH_NONE:
364 break;
366 case HTTP_AUTH_BASIC:
367 openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Basic %s",
368 username_password_as_base64 (p, &gc));
369 msg (D_PROXY, "Attempting Basic Proxy-Authorization");
370 dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf);
371 openvpn_sleep (1);
372 if (!send_line_crlf (sd, buf))
373 goto error;
374 break;
376 #if NTLM
377 case HTTP_AUTH_NTLM:
378 case HTTP_AUTH_NTLM2:
379 /* keep-alive connection */
380 openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive");
381 if (!send_line_crlf (sd, buf))
382 goto error;
384 openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s",
385 ntlm_phase_1 (p, &gc));
386 msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 1");
387 dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf);
388 openvpn_sleep (1);
389 if (!send_line_crlf (sd, buf))
390 goto error;
391 break;
392 #endif
394 default:
395 ASSERT (0);
398 /* send empty CR, LF */
399 openvpn_sleep (1);
400 if (!send_crlf (sd))
401 goto error;
403 /* receive reply from proxy */
404 if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received))
405 goto error;
407 /* remove trailing CR, LF */
408 chomp (buf);
410 msg (D_PROXY, "HTTP proxy returned: '%s'", buf);
412 /* parse return string */
413 nparms = sscanf (buf, "%*s %d", &status);
415 /* check for a "407 Proxy Authentication Required" response */
416 if (nparms >= 1 && status == 407)
418 msg (D_PROXY, "Proxy requires authentication");
420 /* check for NTLM */
421 if (p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2)
423 #if NTLM
424 /* look for the phase 2 response */
426 while (true)
428 if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received))
429 goto error;
430 chomp (buf);
431 msg (D_PROXY, "HTTP proxy returned: '%s'", buf);
433 openvpn_snprintf (get, sizeof get, "%%*s NTLM %%%ds", (int) sizeof (buf2) - 1);
434 nparms = sscanf (buf, get, buf2);
435 buf2[127] = 0; /* we only need the beginning - ensure it's null terminated. */
437 /* check for "Proxy-Authenticate: NTLM TlRM..." */
438 if (nparms == 1)
440 /* parse buf2 */
441 msg (D_PROXY, "auth string: '%s'", buf2);
442 break;
445 /* if we are here then auth string was got */
446 msg (D_PROXY, "Received NTLM Proxy-Authorization phase 2 response");
448 /* receive and discard everything else */
449 while (recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received))
452 /* now send the phase 3 reply */
454 /* format HTTP CONNECT message */
455 openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s",
456 host,
457 port,
458 p->options.http_version);
460 msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
462 /* send HTTP CONNECT message to proxy */
463 if (!send_line_crlf (sd, buf))
464 goto error;
466 /* keep-alive connection */
467 openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive");
468 if (!send_line_crlf (sd, buf))
469 goto error;
472 /* send HOST etc, */
473 openvpn_sleep (1);
474 openvpn_snprintf (buf, sizeof(buf), "Host: %s", host);
475 msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
476 if (!send_line_crlf (sd, buf))
477 goto error;
479 msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3");
481 const char *np3 = ntlm_phase_3 (p, buf2, &gc);
482 if (!np3)
484 msg (D_PROXY, "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server");
485 goto error;
487 openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", np3);
490 msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
491 openvpn_sleep (1);
492 if (!send_line_crlf (sd, buf))
493 goto error;
494 /* ok so far... */
495 /* send empty CR, LF */
496 openvpn_sleep (1);
497 if (!send_crlf (sd))
498 goto error;
500 /* receive reply from proxy */
501 if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received))
502 goto error;
504 /* remove trailing CR, LF */
505 chomp (buf);
507 msg (D_PROXY, "HTTP proxy returned: '%s'", buf);
509 /* parse return string */
510 nparms = sscanf (buf, "%*s %d", &status);
511 #else
512 ASSERT (0); /* No NTLM support */
513 #endif
515 else if (p->auth_method == HTTP_AUTH_NONE && p->options.auth_retry)
518 * Proxy needs authentication, but we don't have a user/pass.
519 * Now we will change p->auth_method and return true so that
520 * our caller knows to call us again on a newly opened socket.
521 * JYFIXME: This code needs to check proxy error output and set
522 * JYFIXME: p->auth_method = HTTP_AUTH_NTLM if necessary.
524 p->auth_method = HTTP_AUTH_BASIC;
525 ret = true;
526 goto done;
528 else
529 goto error;
533 /* check return code, success = 200 */
534 if (nparms < 1 || status != 200)
536 msg (D_LINK_ERRORS, "HTTP proxy returned bad status");
537 #if 0
538 /* DEBUGGING -- show a multi-line HTTP error response */
539 while (true)
541 if (!recv_line (sd, buf, sizeof (buf), p->options.timeout, true, NULL, signal_received))
542 goto error;
543 chomp (buf);
544 msg (D_PROXY, "HTTP proxy returned: '%s'", buf);
546 #endif
547 goto error;
550 /* receive line from proxy and discard */
551 if (!recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received))
552 goto error;
555 * Toss out any extraneous chars, but don't throw away the
556 * start of the OpenVPN data stream (put it in lookahead).
558 while (recv_line (sd, NULL, 0, 2, false, lookahead, signal_received))
561 #if 0
562 if (lookahead && BLEN (lookahead))
563 msg (M_INFO, "HTTP PROXY: lookahead: %s", format_hex (BPTR (lookahead), BLEN (lookahead), 0));
564 #endif
566 done:
567 gc_free (&gc);
568 return ret;
570 error:
571 /* on error, should we exit or restart? */
572 if (!*signal_received)
573 *signal_received = (p->options.retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- HTTP proxy error */
574 gc_free (&gc);
575 return ret;
578 #else
579 static void dummy(void) {}
580 #endif /* ENABLE_HTTP_PROXY */
582 #ifdef GENERAL_PROXY_SUPPORT
584 #ifdef WIN32
586 #if 0
587 char *
588 get_windows_internet_string (const DWORD dwOption, struct gc_arena *gc)
590 DWORD size = 0;
591 char *ret = NULL;
593 /* Initially, get size of return buffer */
594 InternetQueryOption (NULL, dwOption, NULL, &size);
595 if (size)
597 /* Now get actual info */
598 ret = (INTERNET_PROXY_INFO *) gc_malloc (size, false, gc);
599 if (!InternetQueryOption (NULL, dwOption, (LPVOID) ret, &size))
600 ret = NULL;
602 return ret;
604 #endif
606 static INTERNET_PROXY_INFO *
607 get_windows_proxy_settings (struct gc_arena *gc)
609 DWORD size = 0;
610 INTERNET_PROXY_INFO *ret = NULL;
612 /* Initially, get size of return buffer */
613 InternetQueryOption (NULL, INTERNET_OPTION_PROXY, NULL, &size);
614 if (size)
616 /* Now get actual info */
617 ret = (INTERNET_PROXY_INFO *) gc_malloc (size, false, gc);
618 if (!InternetQueryOption (NULL, INTERNET_OPTION_PROXY, (LPVOID) ret, &size))
619 ret = NULL;
621 return ret;
624 static const char *
625 parse_windows_proxy_setting (const char *str, struct auto_proxy_info_entry *e, struct gc_arena *gc)
627 char buf[128];
628 const char *ret = NULL;
629 struct buffer in;
631 CLEAR (*e);
633 buf_set_read (&in, (const uint8_t *)str, strlen (str));
635 if (strchr (str, '=') != NULL)
637 if (buf_parse (&in, '=', buf, sizeof (buf)))
638 ret = string_alloc (buf, gc);
641 if (buf_parse (&in, ':', buf, sizeof (buf)))
642 e->server = string_alloc (buf, gc);
644 if (e->server && buf_parse (&in, '\0', buf, sizeof (buf)))
645 e->port = atoi (buf);
647 return ret;
650 static void
651 parse_windows_proxy_setting_list (const char *str, const char *type, struct auto_proxy_info_entry *e, struct gc_arena *gc)
653 struct gc_arena gc_local = gc_new ();
654 struct auto_proxy_info_entry el;
656 CLEAR (*e);
657 if (type)
659 char buf[128];
660 struct buffer in;
662 buf_set_read (&in, (const uint8_t *)str, strlen (str));
663 if (strchr (str, '=') != NULL)
665 while (buf_parse (&in, ' ', buf, sizeof (buf)))
667 const char *t = parse_windows_proxy_setting (buf, &el, &gc_local);
668 if (t && !strcmp (t, type))
669 goto found;
673 else
675 if (!parse_windows_proxy_setting (str, &el, &gc_local))
676 goto found;
678 goto done;
680 found:
681 if (el.server && el.port > 0)
683 e->server = string_alloc (el.server, gc);
684 e->port = el.port;
687 done:
688 gc_free (&gc_local);
691 static const char *
692 win_proxy_access_type (const DWORD dwAccessType)
694 switch (dwAccessType)
696 case INTERNET_OPEN_TYPE_DIRECT:
697 return "INTERNET_OPEN_TYPE_DIRECT";
698 case INTERNET_OPEN_TYPE_PROXY:
699 return "INTERNET_OPEN_TYPE_PROXY";
700 default:
701 return "[UNKNOWN]";
705 void
706 show_win_proxy_settings (const int msglevel)
708 INTERNET_PROXY_INFO *info;
709 struct gc_arena gc = gc_new ();
711 info = get_windows_proxy_settings (&gc);
712 msg (msglevel, "PROXY INFO: %s %s",
713 win_proxy_access_type (info->dwAccessType),
714 info->lpszProxy ? info->lpszProxy : "[NULL]");
716 gc_free (&gc);
719 struct auto_proxy_info *
720 get_proxy_settings (char **err, struct gc_arena *gc)
722 struct gc_arena gc_local = gc_new ();
723 INTERNET_PROXY_INFO *info;
724 struct auto_proxy_info *pi;
726 ALLOC_OBJ_CLEAR_GC (pi, struct auto_proxy_info, gc);
728 if (err)
729 *err = NULL;
731 info = get_windows_proxy_settings (&gc_local);
733 if (!info)
735 if (err)
736 *err = "PROXY: failed to obtain windows proxy info";
737 goto done;
740 switch (info->dwAccessType)
742 case INTERNET_OPEN_TYPE_DIRECT:
743 break;
744 case INTERNET_OPEN_TYPE_PROXY:
745 if (!info->lpszProxy)
746 break;
747 parse_windows_proxy_setting_list (info->lpszProxy, NULL, &pi->http, gc);
748 if (!pi->http.server)
749 parse_windows_proxy_setting_list (info->lpszProxy, "http", &pi->http, gc);
750 parse_windows_proxy_setting_list (info->lpszProxy, "socks", &pi->socks, gc);
751 break;
752 default:
753 if (err)
754 *err = "PROXY: unknown proxy type";
755 break;
758 done:
759 gc_free (&gc_local);
760 return pi;
763 #else
765 struct auto_proxy_info *
766 get_proxy_settings (char **err, struct gc_arena *gc)
768 #if 1
769 if (err)
770 *err = string_alloc ("PROXY: automatic detection not supported on this OS", gc);
771 return NULL;
772 #else /* test --auto-proxy feature */
773 struct auto_proxy_info *pi;
774 ALLOC_OBJ_CLEAR_GC (pi, struct auto_proxy_info, gc);
775 pi->http.server = "10.10.0.2";
776 pi->http.port = 4000;
777 return pi;
778 #endif
781 #endif
783 #endif /* GENERAL_PROXY_SUPPORT */