4 Komitmen bccfea33ef ... 31b9303062

Pembuat SHA1 Pesan Tanggal
  Iru Cai 31b9303062 h3c: fix cstp_options 2 tahun lalu
  Iru Cai 10ebcfff82 h3c: it works now... 2 tahun lalu
  Iru Cai 1362954a9e h3c: add some mainloop code 2 tahun lalu
  Iru Cai 1887129160 h3c: configure vpn parameters 2 tahun lalu
3 mengubah file dengan 173 tambahan dan 12 penghapusan
  1. 166 12
      h3c.c
  2. 1 0
      library.c
  3. 6 0
      openconnect-internal.h

+ 166 - 12
h3c.c

@@ -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)

+ 1 - 0
library.c

@@ -275,6 +275,7 @@ static const struct vpn_proto openconnect_protos[] = {
 		.description = N_("H3C TLS VPN compatible with iNode SSL VPN client"),
 		.proto = PROTO_H3C,
 		.flags = 0, /* do we need this? */
+		.vpn_close_session = h3c_bye,
 		.tcp_connect = h3c_connect,
 		.tcp_mainloop = h3c_mainloop,
 		.add_http_headers = h3c_http_headers,

+ 6 - 0
openconnect-internal.h

@@ -216,6 +216,11 @@ struct pkt {
 			uint16_t proto;
 			unsigned char hdr[18];
 		} ppp;
+		struct {
+		  unsigned char pad[20];
+		  uint16_t type;
+		  uint16_t len;
+		} h3c;
 #ifdef HAVE_VHOST
 		struct {
 			unsigned char pad[12];
@@ -1346,6 +1351,7 @@ int fortinet_dtls_catch_svrhello(struct openconnect_info *vpninfo, struct pkt *p
 
 /* h3c.c */
 int h3c_connect(struct openconnect_info *vpninfo);
+int h3c_bye(struct openconnect_info *vpninfo, const char *reason);
 int h3c_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable);
 void h3c_http_headers(struct openconnect_info *vpninfo, struct oc_text_buf *buf);
 int h3c_obtain_cookie(struct openconnect_info *vpninfo);