|
@@ -69,6 +69,35 @@ static int h3c_request_user_auth(struct openconnect_info *vpninfo, char *usernam
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int h3c_get_vpn_param_from_headers(struct openconnect_info *vpninfo, char *k, char *v)
|
|
|
+{
|
|
|
+ bool set_value = true;
|
|
|
+ if (strcmp(k, "IPADDRESS") == 0) {
|
|
|
+ vpninfo->ip_info.addr = strdup(v);
|
|
|
+ } else if (strcmp(k, "SUBNETMASK") == 0) {
|
|
|
+ if (strcmp(v, "24") == 0) {
|
|
|
+ vpninfo->ip_info.netmask = strdup("255.255.255.0");
|
|
|
+ } else {
|
|
|
+ vpn_progress(vpninfo, PRG_ERR,
|
|
|
+ "Unknown net mask %s\n",
|
|
|
+ v);
|
|
|
+ }
|
|
|
+ } else if (strcmp(k, "GATEWAY") == 0) {
|
|
|
+ vpninfo->ip_info.gateway_addr = strdup(v);
|
|
|
+ } else {
|
|
|
+ set_value = false;
|
|
|
+ }
|
|
|
+ if (set_value && vpninfo->dump_http_traffic) {
|
|
|
+ char buf[1000];
|
|
|
+ strcpy(buf, k);
|
|
|
+ strcat(buf, ":");
|
|
|
+ strcat(buf, v);
|
|
|
+ dump_buf(vpninfo, '<', buf);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static int h3c_authenticate(struct openconnect_info *vpninfo)
|
|
|
{
|
|
|
int ret;
|
|
@@ -211,7 +240,28 @@ do_login:
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-do_visit_login_url:
|
|
|
+ do_visit_login_url:
|
|
|
+ if (login_url[0] == '/') {
|
|
|
+ add_option_dup(&vpninfo->cstp_options, "login_url", login_url + 1, -1);
|
|
|
+ } else {
|
|
|
+ add_option_dup(&vpninfo->cstp_options, "login_url", login_url, -1);
|
|
|
+ }
|
|
|
+ if (logout_url[0] == '/') {
|
|
|
+ add_option_dup(&vpninfo->cstp_options, "logout_url", logout_url + 1, -1);
|
|
|
+ } else {
|
|
|
+ add_option_dup(&vpninfo->cstp_options, "logout_url", logout_url, -1);
|
|
|
+ }
|
|
|
+ if (checkonline_url[0] == '/') {
|
|
|
+ add_option_dup(&vpninfo->cstp_options, "checkonline_url", checkonline_url + 1, -1);
|
|
|
+ } else {
|
|
|
+ add_option_dup(&vpninfo->cstp_options, "checkonline_url", checkonline_url, -1);
|
|
|
+ }
|
|
|
+ if (challenge_url[0] == '/') {
|
|
|
+ add_option_dup(&vpninfo->cstp_options, "challenge_url", challenge_url + 1, -1);
|
|
|
+ } else {
|
|
|
+ add_option_dup(&vpninfo->cstp_options, "challenge_url", challenge_url, -1);
|
|
|
+ }
|
|
|
+
|
|
|
char username[1000], password[1000];
|
|
|
assert (h3c_request_user_auth(vpninfo, username, password) == 0);
|
|
|
assert(login_url != NULL && logout_url != NULL && checkonline_url != NULL && challenge_url != NULL);
|
|
@@ -234,17 +284,21 @@ do_visit_login_url:
|
|
|
dump_buf(vpninfo, '<', login_resp);
|
|
|
}
|
|
|
|
|
|
- // we just logout ...
|
|
|
- if (logout_url[0] == '/') {
|
|
|
- vpninfo->urlpath = strdup(logout_url + 1);
|
|
|
- } else {
|
|
|
- vpninfo->urlpath = strdup(logout_url);
|
|
|
- }
|
|
|
+ // get VPN parameter
|
|
|
+ vpninfo->urlpath = (char*)"";
|
|
|
buf_truncate(reqbuf);
|
|
|
- char *logout_resp = NULL;
|
|
|
- ret = do_https_request(vpninfo, "GET", NULL, NULL, &logout_resp, NULL, HTTP_BODY_ON_ERROR);
|
|
|
-
|
|
|
-out:
|
|
|
+ buf_truncate(request_data);
|
|
|
+ char *handshake_resp = NULL;
|
|
|
+ do_https_request(vpninfo, "NET_EXTEND", NULL, request_data, &handshake_resp, h3c_get_vpn_param_from_headers, HTTP_BODY_ON_ERROR);
|
|
|
+ /* ignore the error */
|
|
|
+ ret = 0;
|
|
|
+
|
|
|
+ monitor_fd_new(vpninfo, ssl);
|
|
|
+ monitor_read_fd(vpninfo, ssl);
|
|
|
+ monitor_except_fd(vpninfo, ssl);
|
|
|
+ vpninfo->ip_info.mtu = 1400;
|
|
|
+
|
|
|
+ out:
|
|
|
buf_free(reqbuf);
|
|
|
return ret;
|
|
|
}
|
|
@@ -254,9 +308,109 @@ int h3c_connect(struct openconnect_info *vpninfo)
|
|
|
return h3c_authenticate(vpninfo);
|
|
|
}
|
|
|
|
|
|
+int h3c_bye(struct openconnect_info *vpninfo, const char *reason)
|
|
|
+{
|
|
|
+ char *logout_url = NULL;
|
|
|
+ for (struct oc_vpn_option *opt = vpninfo->cstp_options; opt != NULL; opt = opt->next) {
|
|
|
+ if (strcmp(opt->option, "logout_url") == 0) {
|
|
|
+ logout_url = opt->value;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (logout_url != NULL) {
|
|
|
+ char *logout_resp = NULL;
|
|
|
+ vpninfo->urlpath = strdup(logout_url);
|
|
|
+ int ret = do_https_request(vpninfo, "GET", NULL, NULL, &logout_resp, NULL, HTTP_BODY_ON_ERROR);
|
|
|
+ return ret;
|
|
|
+ }
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
+static void h3c_handle_outgoing(struct openconnect_info *vpninfo)
|
|
|
+{
|
|
|
+ vpninfo->ssl_times.last_tx = time(NULL);
|
|
|
+ unmonitor_write_fd(vpninfo, ssl);
|
|
|
+
|
|
|
+ vpn_progress(vpninfo, PRG_TRACE, _("Packet outgoing:\n"));
|
|
|
+ store_le16(&vpninfo->current_ssl_pkt->h3c.type, 1);
|
|
|
+ store_be16(&vpninfo->current_ssl_pkt->h3c.len, vpninfo->current_ssl_pkt->len);
|
|
|
+ int ret = ssl_nonblock_write(vpninfo, 0, &vpninfo->current_ssl_pkt->h3c.type, vpninfo->current_ssl_pkt->len + 4);
|
|
|
+ if (ret < 0) {
|
|
|
+ vpn_progress(vpninfo, PRG_ERR, _("Send packet failed\n"));
|
|
|
+ /* TODO: we don't know what to do now */
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
int h3c_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable)
|
|
|
{
|
|
|
- return 0;
|
|
|
+ while (readable) {
|
|
|
+ /* Some servers send us packets that are larger than
|
|
|
+ negotiated MTU. We reserve some extra space to
|
|
|
+ handle that */
|
|
|
+ int receive_mtu = MAX(16384, vpninfo->deflate_pkt_size ? : vpninfo->ip_info.mtu);
|
|
|
+ int len;
|
|
|
+
|
|
|
+ if (!vpninfo->cstp_pkt) {
|
|
|
+ vpninfo->partial_rec_size = 0;
|
|
|
+ vpninfo->cstp_pkt = alloc_pkt(vpninfo, receive_mtu);
|
|
|
+ if (!vpninfo->cstp_pkt) {
|
|
|
+ vpn_progress(vpninfo, PRG_ERR, _("Allocation failed\n"));
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ len = ssl_nonblock_read(vpninfo, 0,
|
|
|
+ vpninfo->cstp_pkt->data + vpninfo->partial_rec_size,
|
|
|
+ receive_mtu - vpninfo->partial_rec_size);
|
|
|
+ if (!len)
|
|
|
+ break;
|
|
|
+ if (len < 0) {
|
|
|
+ /* goto do_reconnect; */
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (vpninfo->partial_rec_size) {
|
|
|
+ vpn_progress(vpninfo, PRG_DEBUG,
|
|
|
+ _("Received %d more bytes after partial %d\n"),
|
|
|
+ len, vpninfo->partial_rec_size);
|
|
|
+ len += vpninfo->partial_rec_size;
|
|
|
+ vpninfo->partial_rec_size = len;
|
|
|
+ }
|
|
|
+
|
|
|
+ vpninfo->ssl_times.last_rx = time(NULL);
|
|
|
+
|
|
|
+ unsigned char *buf = vpninfo->cstp_pkt->data;
|
|
|
+
|
|
|
+ if (buf[0] == 1) {
|
|
|
+ uint16_t iplen = load_be16(buf + 2);
|
|
|
+ if (len - 4 >= iplen) {
|
|
|
+ if (len - 4 != iplen) {
|
|
|
+ dump_buf_hex(vpninfo, PRG_DEBUG, '>', buf, len);
|
|
|
+ }
|
|
|
+ memmove(buf, buf + 4, len - 4);
|
|
|
+ vpninfo->cstp_pkt->len = len - 4;
|
|
|
+ vpninfo->partial_rec_size = 0;
|
|
|
+ vpn_progress(vpninfo, PRG_TRACE,
|
|
|
+ _("Moved down %d bytes after previous packet\n"), len);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ dump_buf_hex(vpninfo, PRG_ERR, '>', buf, len);
|
|
|
+ }
|
|
|
+
|
|
|
+ queue_packet(&vpninfo->incoming_queue, vpninfo->cstp_pkt);
|
|
|
+ vpninfo->cstp_pkt = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (vpninfo->current_ssl_pkt) {
|
|
|
+ /* TODO: we don't know what to do yet */
|
|
|
+ h3c_handle_outgoing(vpninfo);
|
|
|
+ vpninfo->current_ssl_pkt = NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ while (vpninfo->current_ssl_pkt = dequeue_packet(&vpninfo->outgoing_queue)) {
|
|
|
+ h3c_handle_outgoing(vpninfo);
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
}
|
|
|
|
|
|
void h3c_http_headers(struct openconnect_info *vpninfo, struct oc_text_buf *buf)
|