⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 proxy.c

📁 远程登陆工具软件源码 用于远程登陆unix
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (data[off] == '\n') {
	    /* we have a newline */
	    off++;

	    /* is that the only thing on this line? */
	    if (off <= 2) return off;

	    /* if not, then there is the possibility that this header
	     * continues onto the next line, if it starts with a space
	     * or a tab.
	     */

	    if (off + 1 < len &&
		data[off+1] != ' ' &&
		data[off+1] != '\t') return off;

	    /* the line does continue, so we have to keep going
	     * until we see an the header's "real" end of line.
	     */
	    off++;
	}

	off++;
    }

    return -1;
}

int proxy_http_negotiate (Proxy_Socket p, int change)
{
    if (p->state == PROXY_STATE_NEW) {
	/* we are just beginning the proxy negotiate process,
	 * so we'll send off the initial bits of the request.
	 * for this proxy method, it's just a simple HTTP
	 * request
	 */
	char *buf, dest[512];

	sk_getaddr(p->remote_addr, dest, lenof(dest));

	buf = dupprintf("CONNECT %s:%i HTTP/1.1\r\nHost: %s:%i\r\n",
			dest, p->remote_port, dest, p->remote_port);
	sk_write(p->sub_socket, buf, strlen(buf));
	sfree(buf);

	if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) {
	    char buf[sizeof(p->cfg.proxy_username)+sizeof(p->cfg.proxy_password)];
	    char buf2[sizeof(buf)*4/3 + 100];
	    int i, j, len;
	    sprintf(buf, "%s:%s", p->cfg.proxy_username, p->cfg.proxy_password);
	    len = strlen(buf);
	    sprintf(buf2, "Proxy-Authorization: Basic ");
	    for (i = 0, j = strlen(buf2); i < len; i += 3, j += 4)
		base64_encode_atom((unsigned char *)(buf+i),
				   (len-i > 3 ? 3 : len-i), buf2+j);
	    strcpy(buf2+j, "\r\n");
	    sk_write(p->sub_socket, buf2, strlen(buf2));
	}

	sk_write(p->sub_socket, "\r\n", 2);

	p->state = 1;
	return 0;
    }

    if (change == PROXY_CHANGE_CLOSING) {
	/* if our proxy negotiation process involves closing and opening
	 * new sockets, then we would want to intercept this closing
	 * callback when we were expecting it. if we aren't anticipating
	 * a socket close, then some error must have occurred. we'll
	 * just pass those errors up to the backend.
	 */
	return plug_closing(p->plug, p->closing_error_msg,
			    p->closing_error_code,
			    p->closing_calling_back);
    }

    if (change == PROXY_CHANGE_SENT) {
	/* some (or all) of what we wrote to the proxy was sent.
	 * we don't do anything new, however, until we receive the
	 * proxy's response. we might want to set a timer so we can
	 * timeout the proxy negotiation after a while...
	 */
	return 0;
    }

    if (change == PROXY_CHANGE_ACCEPTING) {
	/* we should _never_ see this, as we are using our socket to
	 * connect to a proxy, not accepting inbound connections.
	 * what should we do? close the socket with an appropriate
	 * error message?
	 */
	return plug_accepting(p->plug, p->accepting_sock);
    }

    if (change == PROXY_CHANGE_RECEIVE) {
	/* we have received data from the underlying socket, which
	 * we'll need to parse, process, and respond to appropriately.
	 */

	char *data, *datap;
	int len;
	int eol;

	if (p->state == 1) {

	    int min_ver, maj_ver, status;

	    /* get the status line */
	    len = bufchain_size(&p->pending_input_data);
	    assert(len > 0);	       /* or we wouldn't be here */
	    data = snewn(len+1, char);
	    bufchain_fetch(&p->pending_input_data, data, len);
	    /*
	     * We must NUL-terminate this data, because Windows
	     * sscanf appears to require a NUL at the end of the
	     * string because it strlens it _first_. Sigh.
	     */
	    data[len] = '\0';

	    eol = get_line_end(data, len);
	    if (eol < 0) {
		sfree(data);
		return 1;
	    }

	    status = -1;
	    /* We can't rely on whether the %n incremented the sscanf return */
	    if (sscanf((char *)data, "HTTP/%i.%i %n",
		       &maj_ver, &min_ver, &status) < 2 || status == -1) {
		plug_closing(p->plug, "Proxy error: HTTP response was absent",
			     PROXY_ERROR_GENERAL, 0);
		sfree(data);
		return 1;
	    }

	    /* remove the status line from the input buffer. */
	    bufchain_consume(&p->pending_input_data, eol);
	    if (data[status] != '2') {
		/* error */
		char *buf;
		data[eol] = '\0';
		while (eol > status &&
		       (data[eol-1] == '\r' || data[eol-1] == '\n'))
		    data[--eol] = '\0';
		buf = dupprintf("Proxy error: %s", data+status);
		plug_closing(p->plug, buf, PROXY_ERROR_GENERAL, 0);
		sfree(buf);
		sfree(data);
		return 1;
	    }

	    sfree(data);

	    p->state = 2;
	}

	if (p->state == 2) {

	    /* get headers. we're done when we get a
	     * header of length 2, (ie. just "\r\n")
	     */

	    len = bufchain_size(&p->pending_input_data);
	    assert(len > 0);	       /* or we wouldn't be here */
	    data = snewn(len, char);
	    datap = data;
	    bufchain_fetch(&p->pending_input_data, data, len);

	    eol = get_line_end(datap, len);
	    if (eol < 0) {
		sfree(data);
		return 1;
	    }
	    while (eol > 2)
	    {
		bufchain_consume(&p->pending_input_data, eol);
		datap += eol;
		len   -= eol;
		eol = get_line_end(datap, len);
	    }

	    if (eol == 2) {
		/* we're done */
		bufchain_consume(&p->pending_input_data, 2);
		proxy_activate(p);
		/* proxy activate will have dealt with
		 * whatever is left of the buffer */
		sfree(data);
		return 1;
	    }

	    sfree(data);
	    return 1;
	}
    }

    plug_closing(p->plug, "Proxy error: unexpected proxy error",
		 PROXY_ERROR_UNEXPECTED, 0);
    return 1;
}

/* ----------------------------------------------------------------------
 * SOCKS proxy type.
 */

/* SOCKS version 4 */
int proxy_socks4_negotiate (Proxy_Socket p, int change)
{
    if (p->state == PROXY_CHANGE_NEW) {

	/* request format:
	 *  version number (1 byte) = 4
	 *  command code (1 byte)
	 *    1 = CONNECT
	 *    2 = BIND
	 *  dest. port (2 bytes) [network order]
	 *  dest. address (4 bytes)
	 *  user ID (variable length, null terminated string)
	 */

	int length, type, namelen;
	char *command, addr[4], hostname[512];

	type = sk_addrtype(p->remote_addr);
	if (type == ADDRTYPE_IPV6) {
	    plug_closing(p->plug, "Proxy error: SOCKS version 4 does"
			 " not support IPv6", PROXY_ERROR_GENERAL, 0);
	    return 1;
	} else if (type == ADDRTYPE_IPV4) {
	    namelen = 0;
	    sk_addrcopy(p->remote_addr, addr);
	} else {		       /* type == ADDRTYPE_NAME */
	    assert(type == ADDRTYPE_NAME);
	    sk_getaddr(p->remote_addr, hostname, lenof(hostname));
	    namelen = strlen(hostname) + 1;   /* include the NUL */
	    addr[0] = addr[1] = addr[2] = 0;
	    addr[3] = 1;
	}

	length = strlen(p->cfg.proxy_username) + namelen + 9;
	command = snewn(length, char);
	strcpy(command + 8, p->cfg.proxy_username);

	command[0] = 4; /* version 4 */
	command[1] = 1; /* CONNECT command */

	/* port */
	command[2] = (char) (p->remote_port >> 8) & 0xff;
	command[3] = (char) p->remote_port & 0xff;

	/* address */
	memcpy(command + 4, addr, 4);

	/* hostname */
	memcpy(command + 8 + strlen(p->cfg.proxy_username) + 1,
	       hostname, namelen);

	sk_write(p->sub_socket, command, length);
	sfree(command);

	p->state = 1;
	return 0;
    }

    if (change == PROXY_CHANGE_CLOSING) {
	/* if our proxy negotiation process involves closing and opening
	 * new sockets, then we would want to intercept this closing
	 * callback when we were expecting it. if we aren't anticipating
	 * a socket close, then some error must have occurred. we'll
	 * just pass those errors up to the backend.
	 */
	return plug_closing(p->plug, p->closing_error_msg,
			    p->closing_error_code,
			    p->closing_calling_back);
    }

    if (change == PROXY_CHANGE_SENT) {
	/* some (or all) of what we wrote to the proxy was sent.
	 * we don't do anything new, however, until we receive the
	 * proxy's response. we might want to set a timer so we can
	 * timeout the proxy negotiation after a while...
	 */
	return 0;
    }

    if (change == PROXY_CHANGE_ACCEPTING) {
	/* we should _never_ see this, as we are using our socket to
	 * connect to a proxy, not accepting inbound connections.
	 * what should we do? close the socket with an appropriate
	 * error message?
	 */
	return plug_accepting(p->plug, p->accepting_sock);
    }

    if (change == PROXY_CHANGE_RECEIVE) {
	/* we have received data from the underlying socket, which
	 * we'll need to parse, process, and respond to appropriately.
	 */

	if (p->state == 1) {
	    /* response format:
	     *  version number (1 byte) = 4
	     *  reply code (1 byte)
	     *    90 = request granted
	     *    91 = request rejected or failed
	     *    92 = request rejected due to lack of IDENTD on client
	     *    93 = request rejected due to difference in user ID 
	     *         (what we sent vs. what IDENTD said)
	     *  dest. port (2 bytes)
	     *  dest. address (4 bytes)
	     */

	    char data[8];

	    if (bufchain_size(&p->pending_input_data) < 8)
		return 1;	       /* not got anything yet */
	    
	    /* get the response */
	    bufchain_fetch(&p->pending_input_data, data, 8);

	    if (data[0] != 0) {
		plug_closing(p->plug, "Proxy error: SOCKS proxy responded with "
				      "unexpected reply code version",
			     PROXY_ERROR_GENERAL, 0);
		return 1;
	    }

	    if (data[1] != 90) {

		switch (data[1]) {
		  case 92:
		    plug_closing(p->plug, "Proxy error: SOCKS server wanted IDENTD on client",
				 PROXY_ERROR_GENERAL, 0);
		    break;
		  case 93:
		    plug_closing(p->plug, "Proxy error: Username and IDENTD on client don't agree",
				 PROXY_ERROR_GENERAL, 0);
		    break;
		  case 91:
		  default:
		    plug_closing(p->plug, "Proxy error: Error while communicating with proxy",
				 PROXY_ERROR_GENERAL, 0);
		    break;
		}

		return 1;
	    }
	    bufchain_consume(&p->pending_input_data, 8);

	    /* we're done */
	    proxy_activate(p);
	    /* proxy activate will have dealt with
	     * whatever is left of the buffer */
	    return 1;
	}
    }

    plug_closing(p->plug, "Proxy error: unexpected proxy error",
		 PROXY_ERROR_UNEXPECTED, 0);
    return 1;
}

/* SOCKS version 5 */
int proxy_socks5_negotiate (Proxy_Socket p, int change)
{
    if (p->state == PROXY_CHANGE_NEW) {

	/* initial command:
	 *  version number (1 byte) = 5
	 *  number of available authentication methods (1 byte)
	 *  available authentication methods (1 byte * previous value)
	 *    authentication methods:
	 *     0x00 = no authentication
	 *     0x01 = GSSAPI
	 *     0x02 = username/password
	 *     0x03 = CHAP
	 */

	char command[4];
	int len;

	command[0] = 5; /* version 5 */
	if (p->cfg.proxy_username[0] || p->cfg.proxy_password[0]) {
	    command[1] = 2;	       /* two methods supported: */
	    command[2] = 0x00;	       /* no authentication */
	    command[3] = 0x02;	       /* username/password */
	    len = 4;
	} else {
	    command[1] = 1;	       /* one methods supported: */
	    command[2] = 0x00;	       /* no authentication */
	    len = 3;
	}

	sk_write(p->sub_socket, command, len);

	p->state = 1;
	return 0;
    }

    if (change == PROXY_CHANGE_CLOSING) {
	/* if our proxy negotiation process involves closing and opening
	 * new sockets, then we would want to intercept this closing
	 * callback when we were expecting it. if we aren't anticipating
	 * a socket close, then some error must have occurred. we'll
	 * just pass those errors up to the backend.
	 */
	return plug_closing(p->plug, p->closing_error_msg,
			    p->closing_error_code,
			    p->closing_calling_back);
    }

    if (change == PROXY_CHANGE_SENT) {
	/* some (or all) of what we wrote to the proxy was sent.
	 * we don't do anything new, however, until we receive the
	 * proxy's response. we might want to set a timer so we can
	 * timeout the proxy negotiation after a while...
	 */
	return 0;
    }

    if (change == PROXY_CHANGE_ACCEPTING) {
	/* we should _never_ see this, as we are using our socket to
	 * connect to a proxy, not accepting inbound connections.
	 * what should we do? close the socket with an appropriate
	 * error message?
	 */
	return plug_accepting(p->plug, p->accepting_sock);
    }

    if (change == PROXY_CHANGE_RECEIVE) {
	/* we have received data from the underlying socket, which
	 * we'll need to parse, process, and respond to appropriately.
	 */

	if (p->state == 1) {

	    /* initial response:
	     *  version number (1 byte) = 5
	     *  authentication method (1 byte)
	     *    authentication methods:
	     *     0x00 = no authentication
	     *     0x01 = GSSAPI
	     *     0x02 = username/password 
	     *     0x03 = CHAP
	     *     0xff = no acceptable methods
	     */
	    char data[2];

	    if (bufchain_size(&p->pending_input_data) < 2)
		return 1;	       /* not got anything yet */

	    /* get the response */
	    bufchain_fetch(&p->pending_input_data, data, 2);

	    if (data[0] != 5) {
		plug_closing(p->plug, "Proxy error: SOCKS proxy returned unexpected version",
			     PROXY_ERROR_GENERAL, 0);
		return 1;
	    }

	    if (data[1] == 0x00) p->state = 2; /* no authentication needed */
	    else if (data[1] == 0x01) p->state = 4; /* GSSAPI authentication */
	    else if (data[1] == 0x02) p->state = 5; /* username/password authentication */
	    else if (data[1] == 0x03) p->state = 6; /* CHAP authentication */
	    else {
		plug_closing(p->plug, "Proxy error: SOCKS proxy did not accept our authentication",
			     PROXY_ERROR_GENERAL, 0);
		return 1;
	    }
	    bufchain_consume(&p->pending_input_data, 2);
	}

	if (p->state == 7) {

	    /* password authentication reply format:
	     *  version number (1 bytes) = 1
	     *  reply code (1 byte)
	     *    0 = succeeded
	     *    >0 = failed
	     */
	    char data[2];

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -