Handle IPv6 literal [] in connection, accept https:// URL for server
authorDavid Woodhouse <David.Woodhouse@intel.com>
Fri, 1 Jan 2010 22:54:25 +0000 (22:54 +0000)
committerDavid Woodhouse <David.Woodhouse@intel.com>
Fri, 1 Jan 2010 22:54:25 +0000 (22:54 +0000)
Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
http.c
main.c
openconnect.8
openconnect.h
openconnect.html
ssl.c

diff --git a/http.c b/http.c
index 1120732..013a19a 100644 (file)
--- a/http.c
+++ b/http.c
@@ -445,28 +445,36 @@ char *local_strcasestr(const char *haystack, const char *needle)
 #define strcasestr local_strcasestr
 #endif
 
-int parse_url(char *url, char **res_proto, char **res_host, int *res_port, char **res_path)
+int parse_url(char *url, char **res_proto, char **res_host, int *res_port,
+             char **res_path, int default_port)
 {
        char *proto = url;
        char *host, *path, *port_str;
        int port;
 
        host = strstr(url, "://");
-       if (!host)
-               return -EINVAL;
-       *host = 0;
-       host += 3;
-
-       if (!strcasecmp(proto, "https"))
-               port = 443;
-       else if (!strcasecmp(proto, "http"))
-               port = 80;
-       else if (!strcasecmp(proto, "socks") ||
-                !strcasecmp(proto, "socks4") ||
-                !strcasecmp(proto, "socks5"))
-               port = 1080;
-       else
-               return -EPROTONOSUPPORT;
+       if (host) {
+               *host = 0;
+               host += 3;
+
+               if (!strcasecmp(proto, "https"))
+                       port = 443;
+               else if (!strcasecmp(proto, "http"))
+                       port = 80;
+               else if (!strcasecmp(proto, "socks") ||
+                        !strcasecmp(proto, "socks4") ||
+                        !strcasecmp(proto, "socks5"))
+                       port = 1080;
+               else
+                       return -EPROTONOSUPPORT;
+       } else {
+               if (default_port) {
+                       proto = NULL;
+                       port = default_port;
+                       host = url;
+               } else
+                       return -EINVAL;
+       }
 
        path = strchr(host, '/');
        if (path) {
@@ -485,14 +493,9 @@ int parse_url(char *url, char **res_proto, char **res_host, int *res_port, char
                        port = new_port;
                }
        }
-       /* Check for IPv6 literal (RFC2732) */
-       if (host[0] == '[' && host[strlen(host)-1] == ']') {
-               host[strlen(host)-1] = 0;
-               host++;
-       }
 
        if (res_proto)
-               *res_proto = strdup(proto);
+               *res_proto = proto ? strdup(proto) : NULL;
        if (res_host)
                *res_host = strdup(host);
        if (res_port)
@@ -582,7 +585,7 @@ int openconnect_obtain_cookie(struct openconnect_info *vpninfo)
                        free(vpninfo->urlpath);
                        vpninfo->urlpath = NULL;
 
-                       ret = parse_url(vpninfo->redirect_url, NULL, &host, &port, &vpninfo->urlpath);
+                       ret = parse_url(vpninfo->redirect_url, NULL, &host, &port, &vpninfo->urlpath, 0);
                        if (ret) {
                                vpninfo->progress(vpninfo, PRG_ERR, "Failed to parse redirected URL '%s': %s\n",
                                                  vpninfo->redirect_url, strerror(-ret));
diff --git a/main.c b/main.c
index 0fefe41..eaf9b53 100644 (file)
--- a/main.c
+++ b/main.c
@@ -305,7 +305,7 @@ int main(int argc, char **argv)
                case 'P': {
                        char *url = strdup(optarg);
                        char *scheme;
-                       parse_url(url, &scheme, &vpninfo->proxy, &vpninfo->proxy_port, NULL);
+                       parse_url(url, &scheme, &vpninfo->proxy, &vpninfo->proxy_port, NULL, 80);
                        if (scheme && strcmp(scheme, "http")) {
                                fprintf(stderr, "Non-http proxy not supported\n");
                                exit(1);
@@ -416,8 +416,27 @@ int main(int argc, char **argv)
        if (config_lookup_host(vpninfo, argv[optind]))
                exit(1);
 
-       if (!vpninfo->hostname)
-               vpninfo->hostname = strdup(argv[optind]);
+       if (!vpninfo->hostname) {
+               char *url = strdup(argv[optind]);
+               char *scheme;
+               char *group;
+
+               if (parse_url(url, &scheme, &vpninfo->hostname, &vpninfo->port,
+                             &group, 443)) {
+                       fprintf(stderr, "Failed to parse server URL '%s'\n",
+                               url);
+                       exit(1);
+               }
+               if (scheme && strcmp(scheme, "https")) {
+                       fprintf(stderr, "Only https:// permitted for server URL\n");
+                       exit(1);
+               }
+               if (group) {
+                       free(vpninfo->urlpath);
+                       vpninfo->urlpath = group;
+               }
+               free(scheme);
+       }
 
 #ifdef SSL_UI
        set_openssl_ui();
index c878692..830f75d 100644 (file)
@@ -147,7 +147,7 @@ openconnect \- Connect to Cisco AnyConnect VPN
 .B --useragent
 .I STRING
 ]
-\fIserver\fR
+[https://]\fIserver\fR[:\fIport\fR][/\fIgroup\fR]
 
 .SH DESCRIPTION
 The program
index 0530290..ee50169 100644 (file)
@@ -324,7 +324,8 @@ int parse_xml_response(struct openconnect_info *vpninfo, char *response,
 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);
+int parse_url(char *url, char **res_proto, char **res_host, int *res_port,
+             char **res_path, int default_port);
 
 /* ssl_ui.c */
 int set_openssl_ui(void);
index 49323b1..abc84ee 100644 (file)
@@ -173,6 +173,7 @@ For full changelog entries including the latest development, see
 <UL>
   <LI><B>OpenConnect HEAD</B><BR>
      <UL>
+       <LI>Allow server to be specified with <TT>https://</TT> URL, including port and pathname (which Cisco calls 'UserGroup')</LI>
        <LI>Support connection through HTTP proxy.</LI>
        <LI>Handle HTTP redirection with port numbers.</LI>
        <LI>Handle HTTP redirection with IPv6 literal addresses.</LI>
@@ -387,6 +388,6 @@ An <TT>openconnect</TT> <A HREF="http://www.freebsd.org/cgi/cvsweb.cgi/ports/sec
 <hr>
 <address>David Woodhouse &lt;<A HREF="mailto:dwmw2@infradead.org">dwmw2@infradead.org</A>&gt;</address>
 <!-- hhmts start -->
-Last modified: Fri Jan  1 22:08:53 GMT 2010
+Last modified: Fri Jan  1 22:50:54 GMT 2010
 <!-- hhmts end -->
 </body> </html>
diff --git a/ssl.c b/ssl.c
index 7222c6f..1be286e 100644 (file)
--- a/ssl.c
+++ b/ssl.c
@@ -518,7 +518,17 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
                        snprintf(port, 5, "%d", vpninfo->port);
                }
 
+               if (hostname[0] == '[' && hostname[strlen(hostname)-1] == ']') {
+                       hostname = strndup(hostname + 1, strlen(hostname) - 2);
+                       if (!hostname)
+                               return -ENOMEM;
+                       hints.ai_flags |= AI_NUMERICHOST;
+               }
+
                err = getaddrinfo(hostname, port, &hints, &result);
+               if (hints.ai_flags & AI_NUMERICHOST)
+                       free(hostname);
+
                if (err) {
                        vpninfo->progress(vpninfo, PRG_ERR, "getaddrinfo failed: %s\n",
                                          gai_strerror(err));
@@ -560,7 +570,8 @@ int openconnect_open_https(struct openconnect_info *vpninfo)
                freeaddrinfo(result);
                
                if (ssl_sock < 0) {
-                       vpninfo->progress(vpninfo, PRG_ERR, "Failed to connect to host %s\n", hostname);
+                       vpninfo->progress(vpninfo, PRG_ERR, "Failed to connect to host %s\n",
+                                         vpninfo->proxy?:vpninfo->hostname);
                        return -EINVAL;
                }
        }