From 3b9971b7e87ee0571f5008acd5f9966939566d32 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Sat, 15 Feb 2014 13:51:03 +0100 Subject: [PATCH] Added support for the "new" type of IP6 support in AnyConnect. If the client sends "X-CSTP-Full-IPv6-Capability: true", then we use the headers: X-CSTP-Address-IP6: 2001:db8:1000:1000::1/64 X-CSTP-Split-Include-IP6: 2001:db8:1000:1001::/64 X-CSTP-Split-Include-IP6: 2001:db8:1000:1002::/64 (see corresponding openconnect change) --- src/config.c | 6 ++-- src/group-config.c | 7 +++-- src/ipc.proto | 13 +++++---- src/main-auth.c | 1 + src/main-misc.c | 4 +++ src/vpn.h | 3 ++ src/worker-auth.c | 2 ++ src/worker-misc.c | 1 + src/worker-vpn.c | 72 +++++++++++++++++++++++++++++++++++----------- src/worker.h | 5 ++++ 10 files changed, 86 insertions(+), 28 deletions(-) diff --git a/src/config.c b/src/config.c index 93642a8f..4536f6c1 100644 --- a/src/config.c +++ b/src/config.c @@ -112,7 +112,6 @@ static struct cfg_options available_options[] = { { .name = "ipv6-nbns", .type = OPTION_MULTI_LINE, .mandatory = 0 }, /* alias nbns */ { .name = "ipv6-network", .type = OPTION_STRING, .mandatory = 0 }, - { .name = "ipv6-netmask", .type = OPTION_STRING, .mandatory = 0 }, { .name = "ipv6-prefix", .type = OPTION_NUMERIC, .mandatory = 0 }, { .name = "route-add-cmd", .type = OPTION_STRING, .mandatory = 0 }, { .name = "route-del-cmd", .type = OPTION_STRING, .mandatory = 0 }, @@ -416,11 +415,12 @@ unsigned force_cert_auth; READ_STRING("ipv4-netmask", config->network.ipv4_netmask); READ_STRING("ipv6-network", config->network.ipv6); - READ_STRING("ipv6-netmask", config->network.ipv6_netmask); READ_NUMERIC("ipv6-prefix", prefix); - if (prefix > 0) + if (prefix > 0) { config->network.ipv6_netmask = ipv6_prefix_to_mask(prefix); + config->network.ipv6_prefix = prefix; + } READ_MULTI_LINE("custom-header", config->custom_header, config->custom_header_size); READ_MULTI_LINE("split-dns", config->split_dns, config->split_dns_size); diff --git a/src/group-config.c b/src/group-config.c index a16c582f..99a004a3 100644 --- a/src/group-config.c +++ b/src/group-config.c @@ -52,7 +52,6 @@ static struct cfg_options available_options[] = { { .name = "ipv6-network", .type = OPTION_STRING }, { .name = "ipv4-netmask", .type = OPTION_STRING }, { .name = "ipv6-prefix", .type = OPTION_NUMERIC }, - { .name = "ipv6-netmask", .type = OPTION_STRING }, { .name = "rx-data-per-sec", .type = OPTION_NUMERIC, }, { .name = "tx-data-per-sec", .type = OPTION_NUMERIC, }, { .name = "net-priority", .type = OPTION_STRING, }, @@ -168,10 +167,12 @@ unsigned prefix = 0; READ_RAW_STRING("ipv4-network", config->ipv4_network); READ_RAW_STRING("ipv6-network", config->ipv6_network); READ_RAW_STRING("ipv4-netmask", config->ipv4_netmask); - READ_RAW_STRING("ipv6-netmask", config->ipv6_netmask); + READ_RAW_NUMERIC("ipv6-prefix", prefix); - if (prefix > 0) + if (prefix > 0) { config->ipv6_netmask = ipv6_prefix_to_mask(prefix); + config->ipv6_prefix = prefix; + } READ_RAW_NUMERIC("rx-data-per-sec", config->rx_per_sec); READ_RAW_NUMERIC("tx-data-per-sec", config->tx_per_sec); diff --git a/src/ipc.proto b/src/ipc.proto index 52537d5d..1073732d 100644 --- a/src/ipc.proto +++ b/src/ipc.proto @@ -91,12 +91,13 @@ message auth_reply_msg /* additional config */ optional string ipv4_netmask = 15; optional string ipv6_netmask = 16; - optional uint32 rx_per_sec = 17; - optional uint32 tx_per_sec = 18; - optional uint32 net_priority = 19; - repeated string routes = 20; - repeated string dns = 21; - repeated string nbns = 22; + optional uint32 ipv6_prefix = 17; + optional uint32 rx_per_sec = 18; + optional uint32 tx_per_sec = 19; + optional uint32 net_priority = 20; + repeated string routes = 21; + repeated string dns = 22; + repeated string nbns = 23; } /* RESUME_FETCH_REQ + RESUME_DELETE_REQ */ diff --git a/src/main-auth.c b/src/main-auth.c index 783ee86b..65de485a 100644 --- a/src/main-auth.c +++ b/src/main-auth.c @@ -109,6 +109,7 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc, msg.ipv4_netmask = proc->config.ipv4_netmask; msg.ipv6_netmask = proc->config.ipv6_netmask; + msg.ipv6_prefix = proc->config.ipv6_prefix; if (proc->config.rx_per_sec != 0) { msg.has_rx_per_sec = 1; msg.rx_per_sec = proc->config.rx_per_sec; diff --git a/src/main-misc.c b/src/main-misc.c index a085af42..bf4ae8e7 100644 --- a/src/main-misc.c +++ b/src/main-misc.c @@ -216,6 +216,10 @@ static int read_additional_config_file(main_server_st * s, struct proc_st *proc, cfg.ipv6_netmask = NULL; } + if (proc->config.ipv6_prefix != 0) { + proc->config.ipv6_prefix = cfg.ipv6_prefix; + } + if (proc->config.cgroup == NULL) { proc->config.cgroup = cfg.cgroup; cfg.cgroup = NULL; diff --git a/src/vpn.h b/src/vpn.h index 44f09dac..9f03a3e2 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -125,6 +125,7 @@ struct group_cfg_st { char *ipv4_network; char *ipv6_network; + unsigned ipv6_prefix; char *ipv4_netmask; char *ipv6_netmask; @@ -142,6 +143,8 @@ struct vpn_st { char *ipv4; char *ipv4_local; /* local IPv4 address */ char *ipv6_netmask; + unsigned ipv6_prefix; + char *ipv6; char *ipv6_local; /* local IPv6 address */ unsigned int mtu; diff --git a/src/worker-auth.c b/src/worker-auth.c index 30b901a3..00c5c11f 100644 --- a/src/worker-auth.c +++ b/src/worker-auth.c @@ -310,6 +310,8 @@ static int recv_auth_reply(worker_st * ws, char *txt, size_t max_txt_size) strdup(msg->ipv6_netmask); } + ws->config->network.ipv6_prefix = msg->ipv6_prefix; + if (msg->has_rx_per_sec) ws->config->rx_per_sec = msg->rx_per_sec; diff --git a/src/worker-misc.c b/src/worker-misc.c index 424ee9ba..a5159df6 100644 --- a/src/worker-misc.c +++ b/src/worker-misc.c @@ -164,6 +164,7 @@ int complete_vpn_info(worker_st * ws, struct vpn_st *vinfo) vinfo->ipv4_netmask = ws->config->network.ipv4_netmask; vinfo->ipv6_netmask = ws->config->network.ipv6_netmask; + vinfo->ipv6_prefix = ws->config->network.ipv6_prefix; if (ws->config->network.mtu != 0) { vinfo->mtu = ws->config->network.mtu; diff --git a/src/worker-vpn.c b/src/worker-vpn.c index b36538fb..cf1b098e 100644 --- a/src/worker-vpn.c +++ b/src/worker-vpn.c @@ -181,6 +181,7 @@ int url_cb(http_parser * parser, const char *at, size_t length) #define STR_HDR_CMTU "X-CSTP-MTU" #define STR_HDR_ATYPE "X-CSTP-Address-Type" #define STR_HDR_HOST "X-CSTP-Hostname" +#define STR_HDR_FULL_IPV6 "X-CSTP-Full-IPv6-Capability" #define CS_ESALSA20 "OC-DTLS1_2-ESALSA20-SHA" #define CS_SALSA20 "OC-DTLS1_2-SALSA20-SHA" @@ -327,6 +328,11 @@ static void value_check(struct worker_st *ws, struct http_req_st *req) NULL) req->no_ipv6 = 1; break; + case HEADER_FULL_IPV6: + if (memmem(value, value_length, "true", 4) != + NULL) + ws->full_ipv6 = 1; + break; case HEADER_DTLS_MTU: req->dtls_mtu = atoi((char *)value); break; @@ -443,6 +449,10 @@ static void header_check(struct http_req_st *req) strncmp((char *)req->header.data, STR_HDR_USER_AGENT, req->header.length) == 0) { req->next_header = HEADER_USER_AGENT; + } else if (req->header.length == sizeof(STR_HDR_FULL_IPV6) - 1 && + strncmp((char *)req->header.data, STR_HDR_FULL_IPV6, + req->header.length) == 0) { + req->next_header = HEADER_FULL_IPV6; } else { req->next_header = 0; } @@ -1024,7 +1034,7 @@ static int connect_handler(worker_st * ws) unsigned tls_pending, dtls_pending = 0, i; time_t udp_recv_time = 0, now; struct timespec tnow; - unsigned mtu_overhead = 0; + unsigned mtu_overhead = 0, ip6; int sndbuf; socklen_t sl; bandwidth_st b_tx; @@ -1140,16 +1150,23 @@ static int connect_handler(worker_st * ws) if (ws->vinfo.ipv6 && req->no_ipv6 == 0) { oclog(ws, LOG_DEBUG, "sending IPv6 %s", ws->vinfo.ipv6); - ret = - tls_printf(ws->session, "X-CSTP-Address: %s\r\n", - ws->vinfo.ipv6); - SEND_ERR(ret); - - if (ws->vinfo.ipv6_netmask) { + if (ws->full_ipv6 && ws->vinfo.ipv6_prefix) { ret = - tls_printf(ws->session, "X-CSTP-Netmask: %s\r\n", - ws->vinfo.ipv6_netmask); + tls_printf(ws->session, "X-CSTP-Address-IP6: %s/%u\r\n", + ws->vinfo.ipv6, ws->vinfo.ipv6_prefix); SEND_ERR(ret); + } else { + ret = + tls_printf(ws->session, "X-CSTP-Address: %s\r\n", + ws->vinfo.ipv6); + SEND_ERR(ret); + + if (ws->vinfo.ipv6_netmask) { + ret = + tls_printf(ws->session, "X-CSTP-Netmask: %s\r\n", + ws->vinfo.ipv6_netmask); + SEND_ERR(ret); + } } } @@ -1185,25 +1202,48 @@ static int connect_handler(worker_st * ws) } for (i = 0; i < ws->vinfo.routes_size; i++) { - if (req->no_ipv6 != 0 && strchr(ws->vinfo.routes[i], ':') != 0) + if (strchr(ws->vinfo.routes[i], ':') != 0) + ip6 = 1; + else + ip6 = 0; + + if (req->no_ipv6 != 0 && ip6 != 0) continue; if (req->no_ipv4 != 0 && strchr(ws->vinfo.routes[i], '.') != 0) continue; oclog(ws, LOG_DEBUG, "adding route %s", ws->vinfo.routes[i]); - ret = tls_printf(ws->session, - "X-CSTP-Split-Include: %s\r\n", - ws->vinfo.routes[i]); + + if (ip6 != 0 && ws->full_ipv6) { + ret = tls_printf(ws->session, + "X-CSTP-Split-Include-IP6: %s\r\n", + ws->vinfo.routes[i]); + } else { + ret = tls_printf(ws->session, + "X-CSTP-Split-Include: %s\r\n", + ws->vinfo.routes[i]); + } SEND_ERR(ret); } for (i = 0; i < ws->routes_size; i++) { - if (req->no_ipv6 != 0 && strchr(ws->routes[i], ':') != 0) + if (strchr(ws->routes[i], ':') != 0) + ip6 = 1; + else + ip6 = 0; + + if (req->no_ipv6 != 0 && ip6 != 0) continue; if (req->no_ipv4 != 0 && strchr(ws->routes[i], '.') != 0) continue; oclog(ws, LOG_DEBUG, "adding private route %s", ws->routes[i]); - ret = tls_printf(ws->session, - "X-CSTP-Split-Include: %s\r\n", ws->routes[i]); + + if (ip6 != 0 && ws->full_ipv6) { + ret = tls_printf(ws->session, + "X-CSTP-Split-Include-IP6: %s\r\n", ws->routes[i]); + } else { + ret = tls_printf(ws->session, + "X-CSTP-Split-Include: %s\r\n", ws->routes[i]); + } SEND_ERR(ret); } ret = diff --git a/src/worker.h b/src/worker.h index b959000d..ace73bf5 100644 --- a/src/worker.h +++ b/src/worker.h @@ -51,6 +51,7 @@ enum { HEADER_DTLS_MTU, HEADER_DTLS_CIPHERSUITE, HEADER_CONNECTION, + HEADER_FULL_IPV6, HEADER_USER_AGENT, }; @@ -146,6 +147,10 @@ typedef struct worker_st { unsigned last_bad_mtu; unsigned conn_mtu; + /* Indicates whether the new IPv6 headers will + * be sent or the old */ + unsigned full_ipv6; + /* Buffer used by worker */ uint8_t * buffer; unsigned buffer_size;