void read_incoming_link (struct context *c) { /* * Set up for recvfrom call to read datagram * sent to our TCP/UDP port. */ int status; /*ASSERT (!c->c2.to_tun.len);*/ perf_push (PERF_READ_IN_LINK); c->c2.buf = c->c2.buffers->read_link_buf; ASSERT (buf_init (&c->c2.buf, FRAME_HEADROOM_ADJ (&c->c2.frame, FRAME_HEADROOM_MARKER_READ_LINK))); status = link_socket_read (c->c2.link_socket, &c->c2.buf, MAX_RW_SIZE_LINK (&c->c2.frame), &c->c2.from); if (socket_connection_reset (c->c2.link_socket, status)) { #if PORT_SHARE if (port_share && socket_foreign_protocol_detected (c->c2.link_socket)) { const struct buffer *fbuf = socket_foreign_protocol_head (c->c2.link_socket); const int sd = socket_foreign_protocol_sd (c->c2.link_socket); port_share_redirect (port_share, fbuf, sd); register_signal (c, SIGTERM, "port-share-redirect"); } else #endif { /* received a disconnect from a connection-oriented protocol */ if (c->options.inetd) { register_signal (c, SIGTERM, "connection-reset-inetd"); msg (D_STREAM_ERRORS, "Connection reset, inetd/xinetd exit [%d]", status); } else { #ifdef ENABLE_OCC if (event_timeout_defined(&c->c2.explicit_exit_notification_interval)) { msg (D_STREAM_ERRORS, "Connection reset during exit notification period, ignoring [%d]", status); openvpn_sleep(1); } else #endif { register_signal (c, SIGUSR1, "connection-reset"); /* SOFT-SIGUSR1 -- TCP connection reset */ msg (D_STREAM_ERRORS, "Connection reset, restarting [%d]", status); } } } perf_pop (); return; } /* check recvfrom status */ check_status (status, "read", c->c2.link_socket, NULL); #ifdef ENABLE_SOCKS /* Remove socks header if applicable */ socks_postprocess_incoming_link (c); #endif perf_pop (); }
bool establish_http_proxy_passthru (struct http_proxy_info *p, socket_descriptor_t sd, /* already open to proxy */ const char *host, /* openvpn server remote */ const int port, /* openvpn server port */ struct buffer *lookahead, volatile int *signal_received) { struct gc_arena gc = gc_new (); char buf[256]; char buf2[128]; char get[80]; int status; int nparms; bool ret = false; /* get user/pass if not previously given or if --auto-proxy is being used */ if (p->auth_method == HTTP_AUTH_BASIC || p->auth_method == HTTP_AUTH_NTLM) get_user_pass_http (p, false); /* format HTTP CONNECT message */ openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s\r\nHOST: %s:%d", host, port, p->options.http_version, host, port); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; /* send User-Agent string if provided */ if (p->options.user_agent) { openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s", p->options.user_agent); if (!send_line_crlf (sd, buf)) goto error; } /* auth specified? */ switch (p->auth_method) { case HTTP_AUTH_NONE: break; case HTTP_AUTH_BASIC: openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: Basic %s", username_password_as_base64 (p, &gc)); msg (D_PROXY, "Attempting Basic Proxy-Authorization"); dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); openvpn_sleep (1); if (!send_line_crlf (sd, buf)) goto error; break; #if NTLM case HTTP_AUTH_NTLM: case HTTP_AUTH_NTLM2: /* keep-alive connection */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); if (!send_line_crlf (sd, buf)) goto error; openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", ntlm_phase_1 (p, &gc)); msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 1"); dmsg (D_SHOW_KEYS, "Send to HTTP proxy: '%s'", buf); openvpn_sleep (1); if (!send_line_crlf (sd, buf)) goto error; break; #endif default: ASSERT (0); } /* send empty CR, LF */ openvpn_sleep (1); if (!send_crlf (sd)) goto error; /* receive reply from proxy */ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); /* parse return string */ nparms = sscanf (buf, "%*s %d", &status); /* check for a "407 Proxy Authentication Required" response */ if (nparms >= 1 && status == 407) { msg (D_PROXY, "Proxy requires authentication"); /* check for NTLM */ if (p->auth_method == HTTP_AUTH_NTLM || p->auth_method == HTTP_AUTH_NTLM2) { #if NTLM /* look for the phase 2 response */ while (true) { if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); openvpn_snprintf (get, sizeof get, "%%*s NTLM %%%ds", (int) sizeof (buf2) - 1); nparms = sscanf (buf, get, buf2); buf2[127] = 0; /* we only need the beginning - ensure it's null terminated. */ /* check for "Proxy-Authenticate: NTLM TlRM..." */ if (nparms == 1) { /* parse buf2 */ msg (D_PROXY, "auth string: '%s'", buf2); break; } } /* if we are here then auth string was got */ msg (D_PROXY, "Received NTLM Proxy-Authorization phase 2 response"); /* receive and discard everything else */ while (recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received)) ; /* now send the phase 3 reply */ /* format HTTP CONNECT message */ openvpn_snprintf (buf, sizeof(buf), "CONNECT %s:%d HTTP/%s", host, port, p->options.http_version); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); /* send HTTP CONNECT message to proxy */ if (!send_line_crlf (sd, buf)) goto error; /* keep-alive connection */ openvpn_snprintf (buf, sizeof(buf), "Proxy-Connection: Keep-Alive"); if (!send_line_crlf (sd, buf)) goto error; /* send HOST etc, */ openvpn_sleep (1); openvpn_snprintf (buf, sizeof(buf), "Host: %s", host); msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); if (!send_line_crlf (sd, buf)) goto error; msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3"); { const char *np3 = ntlm_phase_3 (p, buf2, &gc); if (!np3) { msg (D_PROXY, "NTLM Proxy-Authorization phase 3 failed: received corrupted data from proxy server"); goto error; } openvpn_snprintf (buf, sizeof(buf), "Proxy-Authorization: NTLM %s", np3); } msg (D_PROXY, "Send to HTTP proxy: '%s'", buf); openvpn_sleep (1); if (!send_line_crlf (sd, buf)) goto error; /* ok so far... */ /* send empty CR, LF */ openvpn_sleep (1); if (!send_crlf (sd)) goto error; /* receive reply from proxy */ if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) goto error; /* remove trailing CR, LF */ chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); /* parse return string */ nparms = sscanf (buf, "%*s %d", &status); #else ASSERT (0); /* No NTLM support */ #endif } else if (p->auth_method == HTTP_AUTH_NONE && p->options.auth_retry) { /* * Proxy needs authentication, but we don't have a user/pass. * Now we will change p->auth_method and return true so that * our caller knows to call us again on a newly opened socket. * JYFIXME: This code needs to check proxy error output and set * JYFIXME: p->auth_method = HTTP_AUTH_NTLM if necessary. */ p->auth_method = HTTP_AUTH_BASIC; ret = true; goto done; } else goto error; } /* check return code, success = 200 */ if (nparms < 1 || status != 200) { msg (D_LINK_ERRORS, "HTTP proxy returned bad status"); #if 0 /* DEBUGGING -- show a multi-line HTTP error response */ while (true) { if (!recv_line (sd, buf, sizeof (buf), p->options.timeout, true, NULL, signal_received)) goto error; chomp (buf); msg (D_PROXY, "HTTP proxy returned: '%s'", buf); } #endif goto error; } /* receive line from proxy and discard */ if (!recv_line (sd, NULL, 0, p->options.timeout, true, NULL, signal_received)) goto error; /* * Toss out any extraneous chars, but don't throw away the * start of the OpenVPN data stream (put it in lookahead). */ while (recv_line (sd, NULL, 0, 2, false, lookahead, signal_received)) ; #if 0 if (lookahead && BLEN (lookahead)) msg (M_INFO, "HTTP PROXY: lookahead: %s", format_hex (BPTR (lookahead), BLEN (lookahead), 0)); #endif done: gc_free (&gc); return ret; error: /* on error, should we exit or restart? */ if (!*signal_received) *signal_received = (p->options.retry ? SIGUSR1 : SIGTERM); /* SOFT-SIGUSR1 -- HTTP proxy error */ gc_free (&gc); return ret; }