From 9c6d3f1b75621d38260ff93734de0120b2fcb3f9 Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Fri, 1 Jan 2010 22:09:25 +0000 Subject: [PATCH] =?utf8?q?Add=20proxy=20support=20(based=20on=20P=C3=A1l?= =?utf8?q?=20Dorogi's=20version)?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Signed-off-by: David Woodhouse --- http.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++++ main.c | 24 +++++++++++-- openconnect.8 | 13 +++++++ openconnect.h | 5 +++ openconnect.html | 3 +- ssl.c | 52 ++++++++++++++++++++------- 6 files changed, 172 insertions(+), 16 deletions(-) diff --git a/http.c b/http.c index 8e8e5815..c784ddcf 100644 --- a/http.c +++ b/http.c @@ -708,3 +708,94 @@ char *openconnect_create_useragent(char *base) return uagent; } + +static int proxy_gets(int fd, char *buf, size_t len) +{ + int i = 0; + int ret; + + if (len < 2) + return -EINVAL; + + while ( (ret = read(fd, buf + i, 1)) == 1) { + if (buf[i] == '\n') { + buf[i] = 0; + if (i && buf[i-1] == '\r') { + buf[i-1] = 0; + i--; + } + return i; + } + i++; + + if (i >= len - 1) { + buf[i] = 0; + return i; + } + } + if (ret < 0) + ret = -errno; + + buf[i] = 0; + return i ?: ret; +} + + +int process_http_proxy(struct openconnect_info *vpninfo, int ssl_sock) +{ + char buf[MAX_BUF_LEN]; + int count, buflen, result; + + sprintf(buf, "CONNECT %s:%d HTTP/1.1\r\n", vpninfo->hostname, vpninfo->port); + sprintf(buf + strlen(buf), "Host: %s\r\n", vpninfo->hostname); + sprintf(buf + strlen(buf), "User-Agent: %s\r\n", vpninfo->useragent); + sprintf(buf + strlen(buf), "Proxy-Connection: keep-alive\r\n"); + sprintf(buf + strlen(buf), "Connection: keep-alive\r\n"); + sprintf(buf + strlen(buf), "Accept-Encoding: identity\r\n"); + sprintf(buf + strlen(buf), "\r\n"); + + vpninfo->progress(vpninfo, PRG_INFO, "Requesting proxy connection to %s:%d\n", + vpninfo->hostname, vpninfo->port); + + buflen = strlen(buf); + for (count = 0; count < buflen; ) { + int i = write(ssl_sock, buf + count, buflen - count); + if (i < 0) { + i = -errno; + vpninfo->progress(vpninfo, PRG_ERR, "Sending proxy request failed: %s\n", + strerror(errno)); + return i; + } + count += i; + } + + if (proxy_gets(ssl_sock, buf, sizeof(buf)) < 0) { + vpninfo->progress(vpninfo, PRG_ERR, "Error fetching proxy response\n"); + return -EIO; + } + + if (strncmp(buf, "HTTP/1.", 7) || (buf[7] != '0' && buf[7] != '1') || + buf[8] != ' ' || !(result = atoi(buf+9))) { + vpninfo->progress(vpninfo, PRG_ERR, "Failed to parse proxy response '%s'\n", + buf); + return -EINVAL; + } + + if (result != 200) { + vpninfo->progress(vpninfo, PRG_ERR, "Proxy CONNECT request failed: %s\n", + buf); + return -EIO; + } + + while ((count = proxy_gets(ssl_sock, buf, sizeof(buf)))) { + if (count < 0) { + vpninfo->progress(vpninfo, PRG_ERR, "Failed to read proxy response\n"); + return -EIO; + } + vpninfo->progress(vpninfo, PRG_ERR, + "Unexpected continuation line after CONNECT response: '%s'\n", + buf); + } + + return 0; +} diff --git a/main.c b/main.c index a170ecec..973b6029 100644 --- a/main.c +++ b/main.c @@ -68,6 +68,7 @@ static struct option long_options[] = { {"syslog", 0, 0, 'l'}, {"key-type", 1, 0, 'K'}, {"key-password", 1, 0, 'p'}, + {"proxy", 1, 0, 'P'}, {"user", 1, 0, 'u'}, {"verbose", 0, 0, 'v'}, {"version", 0, 0, 'V'}, @@ -89,6 +90,7 @@ static struct option long_options[] = { {"useragent", 1, 0, 0x03}, {"csd-user", 1, 0, 0x04}, {"disable-ipv6", 0, 0, 0x05}, + {"no-proxy", 0, 0, 0x06}, {NULL, 0, 0, 0}, }; @@ -109,10 +111,12 @@ void usage(void) printf(" -i, --interface=IFNAME Use IFNAME for tunnel interface\n"); printf(" -l, --syslog Use syslog for progress messages\n"); printf(" -U, --setuid=USER Drop privileges after connecting\n"); - printf(" --csd-user=USER Drop privileges during CSD execution\n"); + printf(" --csd-user=USER Drop privileges during CSD execution\n"); printf(" -m, --mtu=MTU Request MTU from server\n"); printf(" -p, --key-password=PASS Set key passphrase or TPM SRK PIN\n"); printf(" --key-password-from-fsid Key passphrase is fsid of file system\n"); + printf(" -P, --proxy=URL Set proxy server\n"); + printf(" --no-proxy Disable proxy\n"); printf(" -q, --quiet Less output\n"); printf(" -Q, --queue-len=LEN Set packet queue limit to LEN pkts\n"); printf(" -s, --script=SCRIPT Use vpnc-compatible config script\n"); @@ -202,7 +206,7 @@ int main(int argc, char **argv) else vpninfo->localname = "localhost"; - while ((opt = getopt_long(argc, argv, "bC:c:Ddg:hi:k:K:lp:Q:qSs:U:u:Vvx:", + while ((opt = getopt_long(argc, argv, "bC:c:Ddg:hi:k:K:lpP:Q:qSs:U:u:Vvx:", long_options, NULL))) { if (opt < 0) break; @@ -298,6 +302,22 @@ int main(int argc, char **argv) case 'p': vpninfo->cert_password = optarg; break; + case 'P': { + char *url = strdup(optarg); + char *scheme; + parse_url(url, &scheme, &vpninfo->proxy, &vpninfo->proxy_port, NULL); + if (scheme && strcmp(scheme, "http")) { + fprintf(stderr, "Non-http proxy not supported\n"); + exit(1); + } + free(scheme); + free(url); + vpninfo->dtls_attempt_period = 0; + break; + } + case 0x06: + free(vpninfo->proxy); + vpninfo->proxy = NULL; case 's': vpninfo->vpnc_script = optarg; break; diff --git a/openconnect.8 b/openconnect.8 index 39b42504..c8786929 100644 --- a/openconnect.8 +++ b/openconnect.8 @@ -62,6 +62,13 @@ openconnect \- Connect to Cisco AnyConnect VPN .I PASS ] [ +.B -P,--proxy +.I PROXY +] +[ +.B --no-proxy +] +[ .B --key-password-from-fsid ] [ @@ -221,6 +228,12 @@ from server .B -p,--key-password=PASS Provide passphrase for certificate file, or SRK (System Root Key) PIN for TPM .TP +.B -P,--proxy=PROXY +Use HTTP proxy for connection +.TP +.B --no-proxy +Disable use of HTTP proxy +.TP .B --key-password-from-fsid Passphrase for certificate file is automatically generated from the fsid of the file system on which it is stored diff --git a/openconnect.h b/openconnect.h index e6e45dd2..2ce13c61 100644 --- a/openconnect.h +++ b/openconnect.h @@ -143,6 +143,9 @@ struct openconnect_info { char sid_tokencode[9]; char sid_nexttokencode[9]; + char *proxy; + int proxy_port; + const char *localname; char *hostname; int port; @@ -320,6 +323,8 @@ int parse_xml_response(struct openconnect_info *vpninfo, char *response, /* http.c */ int openconnect_obtain_cookie(struct openconnect_info *vpninfo); char *openconnect_create_useragent(char *base); +int process_http_proxy(struct openconnect_info *vpninfo, int ssl_sock); +int parse_url(char *url, char **res_proto, char **res_host, int *res_port, char **res_path); /* ssl_ui.c */ int set_openssl_ui(void); diff --git a/openconnect.html b/openconnect.html index 1b94f96f..49323b13 100644 --- a/openconnect.html +++ b/openconnect.html @@ -173,6 +173,7 @@ For full changelog entries including the latest development, see