Esempio n. 1
0
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 ();
}
Esempio n. 2
0
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;
}