dtls.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662
  1. /*
  2. * OpenConnect (SSL + DTLS) VPN client
  3. *
  4. * Copyright © 2008-2015 Intel Corporation.
  5. *
  6. * Author: David Woodhouse <dwmw2@infradead.org>
  7. *
  8. * This program is free software; you can redistribute it and/or
  9. * modify it under the terms of the GNU Lesser General Public License
  10. * version 2.1, as published by the Free Software Foundation.
  11. *
  12. * This program is distributed in the hope that it will be useful, but
  13. * WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * Lesser General Public License for more details.
  16. */
  17. #include <config.h>
  18. #include "openconnect-internal.h"
  19. #include <unistd.h>
  20. #include <sys/types.h>
  21. #include <fcntl.h>
  22. #ifndef _WIN32
  23. #include <netinet/in.h>
  24. #include <sys/socket.h>
  25. #endif
  26. #include <errno.h>
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include <stdio.h>
  30. /*
  31. * The master-secret is generated randomly by the client. The server
  32. * responds with a DTLS Session-ID. These, done over the HTTPS
  33. * connection, are enough to 'resume' a DTLS session, bypassing all
  34. * the normal setup of a normal DTLS connection.
  35. *
  36. * Cisco use a version of the protocol which predates RFC4347, but
  37. * isn't quite the same as the pre-RFC version of the protocol which
  38. * was in OpenSSL 0.9.8e -- it includes backports of some later
  39. * OpenSSL patches.
  40. *
  41. * The openssl/ directory of this source tree should contain both a
  42. * small patch against OpenSSL 0.9.8e to make it support Cisco's
  43. * snapshot of the protocol, and a larger patch against newer OpenSSL
  44. * which gives us an option to use the old protocol again.
  45. *
  46. * Cisco's server also seems to respond to the official version of the
  47. * protocol, with a change in the ChangeCipherSpec packet which implies
  48. * that it does know the difference and isn't just repeating the version
  49. * number seen in the ClientHello. But although I can make the handshake
  50. * complete by hacking tls1_mac() to use the _old_ protocol version
  51. * number when calculating the MAC, the server still seems to be ignoring
  52. * my subsequent data packets. So we use the old protocol, which is what
  53. * their clients use anyway.
  54. */
  55. char *openconnect_bin2hex(const char *prefix, const uint8_t *data, unsigned len)
  56. {
  57. struct oc_text_buf *buf;
  58. char *p = NULL;
  59. buf = buf_alloc();
  60. if (prefix)
  61. buf_append(buf, "%s", prefix);
  62. buf_append_hex(buf, data, len);
  63. if (!buf_error(buf)) {
  64. p = buf->data;
  65. buf->data = NULL;
  66. }
  67. buf_free(buf);
  68. return p;
  69. }
  70. char *openconnect_bin2base64(const char *prefix, const uint8_t *data, unsigned len)
  71. {
  72. struct oc_text_buf *buf;
  73. char *p = NULL;
  74. buf = buf_alloc();
  75. if (prefix)
  76. buf_append(buf, "%s", prefix);
  77. buf_append_base64(buf, data, len, 0);
  78. if (!buf_error(buf)) {
  79. p = buf->data;
  80. buf->data = NULL;
  81. }
  82. buf_free(buf);
  83. return p;
  84. }
  85. static int connect_dtls_socket(struct openconnect_info *vpninfo, int *timeout)
  86. {
  87. int dtls_fd, ret;
  88. /* Sanity check for the removal of new_dtls_{fd,ssl} */
  89. if (vpninfo->dtls_fd != -1) {
  90. vpn_progress(vpninfo, PRG_ERR, _("DTLS connection attempted with an existing fd\n"));
  91. vpninfo->dtls_attempt_period = 0;
  92. return -EINVAL;
  93. }
  94. if (!vpninfo->dtls_addr) {
  95. vpn_progress(vpninfo, PRG_ERR, _("No DTLS address\n"));
  96. vpninfo->dtls_attempt_period = 0;
  97. return -EINVAL;
  98. }
  99. if (vpninfo->proto->proto == PROTO_ANYCONNECT && !vpninfo->dtls_cipher) {
  100. /* We probably didn't offer it any ciphers it liked */
  101. vpn_progress(vpninfo, PRG_ERR, _("Server offered no DTLS cipher option\n"));
  102. vpninfo->dtls_attempt_period = 0;
  103. return -EINVAL;
  104. }
  105. if (vpninfo->proxy) {
  106. /* XXX: Theoretically, SOCKS5 proxies can do UDP too */
  107. vpn_progress(vpninfo, PRG_ERR, _("No DTLS when connected via proxy\n"));
  108. vpninfo->dtls_attempt_period = 0;
  109. return -EINVAL;
  110. }
  111. dtls_fd = udp_connect(vpninfo);
  112. if (dtls_fd < 0)
  113. return -EINVAL;
  114. ret = start_dtls_handshake(vpninfo, dtls_fd);
  115. if (ret) {
  116. closesocket(dtls_fd);
  117. return ret;
  118. }
  119. vpninfo->dtls_state = DTLS_CONNECTING;
  120. vpninfo->dtls_fd = dtls_fd;
  121. monitor_fd_new(vpninfo, dtls);
  122. monitor_read_fd(vpninfo, dtls);
  123. monitor_except_fd(vpninfo, dtls);
  124. time(&vpninfo->new_dtls_started);
  125. return dtls_try_handshake(vpninfo, timeout);
  126. }
  127. void dtls_close(struct openconnect_info *vpninfo)
  128. {
  129. if (vpninfo->dtls_ssl) {
  130. dtls_ssl_free(vpninfo);
  131. unmonitor_fd(vpninfo, dtls);
  132. closesocket(vpninfo->dtls_fd);
  133. vpninfo->dtls_ssl = NULL;
  134. vpninfo->dtls_fd = -1;
  135. }
  136. vpninfo->dtls_state = DTLS_SLEEPING;
  137. }
  138. int dtls_reconnect(struct openconnect_info *vpninfo, int *timeout)
  139. {
  140. dtls_close(vpninfo);
  141. if (vpninfo->dtls_state == DTLS_DISABLED)
  142. return -EINVAL;
  143. vpninfo->dtls_state = DTLS_SLEEPING;
  144. return connect_dtls_socket(vpninfo, timeout);
  145. }
  146. int dtls_setup(struct openconnect_info *vpninfo)
  147. {
  148. if (vpninfo->dtls_state == DTLS_DISABLED ||
  149. vpninfo->dtls_state == DTLS_NOSECRET)
  150. return -EINVAL;
  151. if (!vpninfo->dtls_attempt_period)
  152. return 0;
  153. if (!vpninfo->dtls_addr) {
  154. vpn_progress(vpninfo, PRG_ERR, _("No DTLS address\n"));
  155. vpninfo->dtls_attempt_period = 0;
  156. return -EINVAL;
  157. }
  158. if (vpninfo->dtls_times.rekey <= 0)
  159. vpninfo->dtls_times.rekey_method = REKEY_NONE;
  160. if (connect_dtls_socket(vpninfo, NULL))
  161. return -EINVAL;
  162. vpn_progress(vpninfo, PRG_DEBUG,
  163. _("DTLS initialised. DPD %d, Keepalive %d\n"),
  164. vpninfo->dtls_times.dpd, vpninfo->dtls_times.keepalive);
  165. return 0;
  166. }
  167. int udp_tos_update(struct openconnect_info *vpninfo, struct pkt *pkt)
  168. {
  169. int tos;
  170. /* Extract TOS field from IP header (IPv4 and IPv6 differ) */
  171. switch(pkt->data[0] >> 4) {
  172. case 4:
  173. tos = pkt->data[1];
  174. break;
  175. case 6:
  176. tos = (load_be16(pkt->data) >> 4) & 0xff;
  177. break;
  178. default:
  179. vpn_progress(vpninfo, PRG_ERR,
  180. _("Unknown packet (len %d) received: %02x %02x %02x %02x...\n"),
  181. pkt->len, pkt->data[0], pkt->data[1], pkt->data[2], pkt->data[3]);
  182. return -EINVAL;
  183. }
  184. /* set the actual value */
  185. if (tos != vpninfo->dtls_tos_current) {
  186. vpn_progress(vpninfo, PRG_DEBUG, _("TOS this: %d, TOS last: %d\n"),
  187. tos, vpninfo->dtls_tos_current);
  188. if (setsockopt(vpninfo->dtls_fd, vpninfo->dtls_tos_proto,
  189. vpninfo->dtls_tos_optname, (void *)&tos, sizeof(tos)))
  190. vpn_perror(vpninfo, _("UDP setsockopt"));
  191. else
  192. vpninfo->dtls_tos_current = tos;
  193. }
  194. return 0;
  195. }
  196. int dtls_mainloop(struct openconnect_info *vpninfo, int *timeout, int readable)
  197. {
  198. int work_done = 0;
  199. char magic_pkt;
  200. if (vpninfo->dtls_need_reconnect) {
  201. vpninfo->dtls_need_reconnect = 0;
  202. dtls_reconnect(vpninfo, timeout);
  203. return 1;
  204. }
  205. if (vpninfo->dtls_state == DTLS_CONNECTING) {
  206. dtls_try_handshake(vpninfo, timeout);
  207. if (vpninfo->dtls_state != DTLS_CONNECTED) {
  208. vpninfo->delay_tunnel_reason = "DTLS MTU detection";
  209. return 0;
  210. }
  211. return 1;
  212. }
  213. if (vpninfo->dtls_state == DTLS_SLEEPING) {
  214. int when = vpninfo->new_dtls_started + vpninfo->dtls_attempt_period - time(NULL);
  215. if (when <= 0) {
  216. vpn_progress(vpninfo, PRG_DEBUG, _("Attempt new DTLS connection\n"));
  217. if (connect_dtls_socket(vpninfo, timeout) < 0)
  218. *timeout = 1000;
  219. } else if ((when * 1000) < *timeout) {
  220. *timeout = when * 1000;
  221. }
  222. return 0;
  223. }
  224. /* Nothing to do here for Cisco DTLS as it is preauthenticated */
  225. if (vpninfo->dtls_state == DTLS_CONNECTED)
  226. vpninfo->dtls_state = DTLS_ESTABLISHED;
  227. while (readable) {
  228. int len = MAX(16384, vpninfo->ip_info.mtu);
  229. unsigned char *buf;
  230. if (vpninfo->incoming_queue.count >= vpninfo->max_qlen) {
  231. work_done = 1;
  232. break;
  233. }
  234. if (!vpninfo->dtls_pkt) {
  235. vpninfo->dtls_pkt = alloc_pkt(vpninfo, len);
  236. if (!vpninfo->dtls_pkt) {
  237. vpn_progress(vpninfo, PRG_ERR, _("Allocation failed\n"));
  238. break;
  239. }
  240. }
  241. buf = vpninfo->dtls_pkt->data - 1;
  242. len = ssl_nonblock_read(vpninfo, 1, buf, len + 1);
  243. if (len <= 0)
  244. break;
  245. vpn_progress(vpninfo, PRG_TRACE,
  246. _("Received DTLS packet 0x%02x of %d bytes\n"),
  247. buf[0], len);
  248. vpninfo->dtls_times.last_rx = time(NULL);
  249. switch (buf[0]) {
  250. case AC_PKT_DATA:
  251. vpninfo->dtls_pkt->len = len - 1;
  252. queue_packet(&vpninfo->incoming_queue, vpninfo->dtls_pkt);
  253. vpninfo->dtls_pkt = NULL;
  254. work_done = 1;
  255. break;
  256. case AC_PKT_DPD_OUT:
  257. vpn_progress(vpninfo, PRG_DEBUG, _("Got DTLS DPD request\n"));
  258. /* FIXME: What if the packet doesn't get through? */
  259. magic_pkt = AC_PKT_DPD_RESP;
  260. if (ssl_nonblock_write(vpninfo, 1, &magic_pkt, 1) != 1)
  261. vpn_progress(vpninfo, PRG_ERR,
  262. _("Failed to send DPD response. Expect disconnect\n"));
  263. continue;
  264. case AC_PKT_DPD_RESP:
  265. vpn_progress(vpninfo, PRG_DEBUG, _("Got DTLS DPD response\n"));
  266. break;
  267. case AC_PKT_KEEPALIVE:
  268. vpn_progress(vpninfo, PRG_DEBUG, _("Got DTLS Keepalive\n"));
  269. break;
  270. case AC_PKT_COMPRESSED:
  271. if (!vpninfo->dtls_compr) {
  272. vpn_progress(vpninfo, PRG_ERR,
  273. _("Compressed DTLS packet received when compression not enabled\n"));
  274. goto unknown_pkt;
  275. }
  276. decompress_and_queue_packet(vpninfo, vpninfo->dtls_compr,
  277. vpninfo->dtls_pkt->data, len - 1);
  278. break;
  279. default:
  280. vpn_progress(vpninfo, PRG_ERR,
  281. _("Unknown DTLS packet type %02x, len %d\n"),
  282. buf[0], len);
  283. if (1) {
  284. /* Some versions of OpenSSL have bugs with receiving out-of-order
  285. * packets. Not only do they wrongly decide to drop packets if
  286. * two packets get swapped in transit, but they also _fail_ to
  287. * drop the packet in non-blocking mode; instead they return
  288. * the appropriate length of garbage. So don't abort... for now. */
  289. break;
  290. } else {
  291. unknown_pkt:
  292. vpninfo->quit_reason = "Unknown packet received";
  293. return 1;
  294. }
  295. }
  296. }
  297. switch (keepalive_action(&vpninfo->dtls_times, timeout)) {
  298. case KA_REKEY: {
  299. int ret;
  300. vpn_progress(vpninfo, PRG_INFO, _("DTLS rekey due\n"));
  301. if (vpninfo->dtls_times.rekey_method == REKEY_SSL) {
  302. time(&vpninfo->new_dtls_started);
  303. vpninfo->dtls_state = DTLS_CONNECTING;
  304. ret = dtls_try_handshake(vpninfo, timeout);
  305. if (ret) {
  306. vpn_progress(vpninfo, PRG_ERR, _("DTLS Rehandshake failed; reconnecting.\n"));
  307. return connect_dtls_socket(vpninfo, timeout);
  308. }
  309. }
  310. return 1;
  311. }
  312. case KA_DPD_DEAD:
  313. vpn_progress(vpninfo, PRG_ERR, _("DTLS Dead Peer Detection detected dead peer!\n"));
  314. /* Fall back to SSL, and start a new DTLS connection */
  315. dtls_reconnect(vpninfo, timeout);
  316. return 1;
  317. case KA_DPD:
  318. vpn_progress(vpninfo, PRG_DEBUG, _("Send DTLS DPD\n"));
  319. magic_pkt = AC_PKT_DPD_OUT;
  320. if (ssl_nonblock_write(vpninfo, 1, &magic_pkt, 1) != 1)
  321. vpn_progress(vpninfo, PRG_ERR,
  322. _("Failed to send DPD request. Expect disconnect\n"));
  323. /* last_dpd will just have been set */
  324. vpninfo->dtls_times.last_tx = vpninfo->dtls_times.last_dpd;
  325. work_done = 1;
  326. break;
  327. case KA_KEEPALIVE:
  328. /* No need to send an explicit keepalive
  329. if we have real data to send */
  330. if (vpninfo->outgoing_queue.head)
  331. break;
  332. vpn_progress(vpninfo, PRG_DEBUG, _("Send DTLS Keepalive\n"));
  333. magic_pkt = AC_PKT_KEEPALIVE;
  334. if (ssl_nonblock_write(vpninfo, 1, &magic_pkt, 1) != 1)
  335. vpn_progress(vpninfo, PRG_ERR,
  336. _("Failed to send keepalive request. Expect disconnect\n"));
  337. time(&vpninfo->dtls_times.last_tx);
  338. work_done = 1;
  339. break;
  340. case KA_NONE:
  341. ;
  342. }
  343. /* Service outgoing packet queue */
  344. unmonitor_write_fd(vpninfo, dtls);
  345. while (vpninfo->outgoing_queue.head) {
  346. struct pkt *this = dequeue_packet(&vpninfo->outgoing_queue);
  347. struct pkt *send_pkt = this;
  348. int ret;
  349. /* If TOS optname is set, we want to copy the TOS/TCLASS header
  350. to the outer UDP packet */
  351. if (vpninfo->dtls_tos_optname)
  352. udp_tos_update(vpninfo, this);
  353. /* One byte of header */
  354. this->cstp.hdr[7] = AC_PKT_DATA;
  355. /* We can compress into vpninfo->deflate_pkt unless CSTP
  356. * currently has a compressed packet pending — which it
  357. * shouldn't if DTLS is active. */
  358. if (vpninfo->dtls_compr &&
  359. vpninfo->current_ssl_pkt != vpninfo->deflate_pkt &&
  360. !compress_packet(vpninfo, vpninfo->dtls_compr, this)) {
  361. send_pkt = vpninfo->deflate_pkt;
  362. send_pkt->cstp.hdr[7] = AC_PKT_COMPRESSED;
  363. }
  364. ret = ssl_nonblock_write(vpninfo, 1, &send_pkt->cstp.hdr[7], send_pkt->len + 1);
  365. if (ret <= 0) {
  366. /* Zero is -EAGAIN; just requeue. dtls_nonblock_write()
  367. * will have added the socket to the poll wfd list. */
  368. requeue_packet(&vpninfo->outgoing_queue, this);
  369. if (ret < 0) {
  370. /* If it's a real error, kill the DTLS connection so
  371. the requeued packet will be sent over SSL */
  372. dtls_reconnect(vpninfo, timeout);
  373. work_done = 1;
  374. }
  375. return work_done;
  376. }
  377. time(&vpninfo->dtls_times.last_tx);
  378. vpn_progress(vpninfo, PRG_TRACE,
  379. _("Sent DTLS packet of %d bytes; DTLS send returned %d\n"),
  380. this->len, ret);
  381. free_pkt(vpninfo, this);
  382. }
  383. return work_done;
  384. }
  385. /* This symbol is missing in glibc < 2.22 (bug 18643). */
  386. #if defined(__linux__) && !defined(HAVE_IPV6_PATHMTU)
  387. # define HAVE_IPV6_PATHMTU 1
  388. # define IPV6_PATHMTU 61
  389. #endif
  390. #define PKT_INTERVAL_MS 50
  391. /* Performs a binary search to detect MTU.
  392. * @buf: is preallocated with MTU size
  393. *
  394. * Returns: new MTU or 0
  395. */
  396. static int probe_mtu(struct openconnect_info *vpninfo, unsigned char *buf)
  397. {
  398. int max, min, cur, ret, absolute_min, last;
  399. int tries = 0; /* Number of loops in bin search - includes resends */
  400. uint32_t id, id_len;
  401. struct timeval start_tv, now_tv, last_tv;
  402. absolute_min = 576;
  403. if (vpninfo->ip_info.addr6)
  404. absolute_min = 1280;
  405. /* We'll assume that it is at least functional, and permits the bare
  406. * minimum MTU for the protocol(s) it transports. All else is mad. */
  407. min = absolute_min;
  408. /* First send a probe at the configured maximum. Most of the time, this
  409. one will probably work. */
  410. last = cur = max = vpninfo->ip_info.mtu;
  411. if (max <= min)
  412. goto fail;
  413. /* Generate unique ID */
  414. if (openconnect_random(&id, sizeof(id)) < 0)
  415. goto fail;
  416. vpn_progress(vpninfo, PRG_DEBUG,
  417. _("Initiating MTU detection (min=%d, max=%d)\n"), min, max);
  418. gettimeofday(&start_tv, NULL);
  419. last_tv = start_tv;
  420. while (1) {
  421. int wait_ms;
  422. #ifdef HAVE_IPV6_PATHMTU
  423. if (vpninfo->peer_addr->sa_family == AF_INET6) {
  424. struct ip6_mtuinfo mtuinfo;
  425. socklen_t len = sizeof(mtuinfo);
  426. int newmax;
  427. if (getsockopt(vpninfo->dtls_fd, IPPROTO_IPV6, IPV6_PATHMTU, &mtuinfo, &len) >= 0) {
  428. newmax = mtuinfo.ip6m_mtu;
  429. if (newmax > 0) {
  430. newmax = dtls_set_mtu(vpninfo, newmax) - /*ipv6*/40 - /*udp*/20 - /*oc dtls*/1;
  431. if (absolute_min > newmax)
  432. goto fail;
  433. if (max > newmax)
  434. max = newmax;
  435. if (cur > newmax)
  436. cur = newmax;
  437. }
  438. }
  439. }
  440. #endif
  441. buf[0] = AC_PKT_DPD_OUT;
  442. id_len = id + cur;
  443. memcpy(&buf[1], &id_len, sizeof(id_len));
  444. vpn_progress(vpninfo, PRG_TRACE,
  445. _("Sending MTU DPD probe (%u bytes)\n"), cur);
  446. ret = openconnect_dtls_write(vpninfo, buf, cur + 1);
  447. if (ret != cur + 1) {
  448. vpn_progress(vpninfo, PRG_ERR,
  449. _("Failed to send DPD request (%d %d)\n"), cur, ret);
  450. if (cur == max) {
  451. max = --cur;
  452. if (cur >= absolute_min)
  453. continue;
  454. }
  455. goto fail;
  456. }
  457. if (last == cur)
  458. tries++;
  459. else {
  460. tries = 0;
  461. last = cur;
  462. }
  463. memset(buf, 0, sizeof(id)+1);
  464. keep_waiting:
  465. gettimeofday(&now_tv, NULL);
  466. if (now_tv.tv_sec > start_tv.tv_sec + 10) {
  467. if (absolute_min == min) {
  468. /* Hm, we never got *anything* back successfully? */
  469. vpn_progress(vpninfo, PRG_ERR,
  470. _("Too long time in MTU detect loop; assuming negotiated MTU.\n"));
  471. goto fail;
  472. } else {
  473. vpn_progress(vpninfo, PRG_ERR,
  474. _("Too long time in MTU detect loop; MTU set to %d.\n"), min);
  475. ret = min;
  476. goto out;
  477. }
  478. }
  479. wait_ms = PKT_INTERVAL_MS -
  480. ((now_tv.tv_sec - last_tv.tv_sec) * 1000) -
  481. ((now_tv.tv_usec - last_tv.tv_usec) / 1000);
  482. if (wait_ms <= 0 || wait_ms > PKT_INTERVAL_MS)
  483. wait_ms = PKT_INTERVAL_MS;
  484. ret = openconnect_dtls_read(vpninfo, buf, max+1, wait_ms);
  485. if (ret > 0 && (buf[0] != AC_PKT_DPD_RESP || !memcpy(&id_len, &buf[1], sizeof(id_len)) ||
  486. id_len != id + ret - 1)) {
  487. vpn_progress(vpninfo, PRG_DEBUG,
  488. _("Received unexpected packet (%.2x) in MTU detection; skipping.\n"), (unsigned)buf[0]);
  489. goto keep_waiting;
  490. }
  491. if (ret == -ETIMEDOUT) {
  492. if (tries >= 6) {
  493. vpn_progress(vpninfo, PRG_DEBUG,
  494. _("No response to size %u after %d tries; declare MTU is %u\n"),
  495. last, tries, min);
  496. ret = min;
  497. goto out;
  498. }
  499. } else if (ret < 0) {
  500. vpn_progress(vpninfo, PRG_ERR,
  501. _("Failed to recv DPD request (%d)\n"), ret);
  502. goto fail;
  503. } else if (ret > 0) {
  504. vpn_progress(vpninfo, PRG_TRACE,
  505. _("Received MTU DPD probe (%u bytes)\n"), ret - 1);
  506. ret--;
  507. tries = 0;
  508. }
  509. if (ret == max)
  510. goto out;
  511. if (ret > min) {
  512. min = ret;
  513. if (min >= last) {
  514. cur = (min + max + 1) / 2;
  515. } else {
  516. cur = (min + last + 1) / 2;
  517. }
  518. } else {
  519. cur = (min + last + 1) / 2;
  520. }
  521. }
  522. fail:
  523. ret = 0;
  524. out:
  525. return ret;
  526. }
  527. void dtls_detect_mtu(struct openconnect_info *vpninfo)
  528. {
  529. int mtu;
  530. int prev_mtu = vpninfo->ip_info.mtu;
  531. unsigned char *buf;
  532. if (vpninfo->proto->proto != PROTO_ANYCONNECT)
  533. return;
  534. if (vpninfo->ip_info.mtu < 1 + sizeof(uint32_t))
  535. return;
  536. /* detect MTU */
  537. buf = calloc(1, 1 + vpninfo->ip_info.mtu);
  538. if (!buf) {
  539. vpn_progress(vpninfo, PRG_ERR, _("Allocation failed\n"));
  540. return;
  541. }
  542. mtu = probe_mtu(vpninfo, buf);
  543. if (mtu == 0)
  544. goto skip_mtu;
  545. vpninfo->ip_info.mtu = mtu;
  546. if (prev_mtu != vpninfo->ip_info.mtu) {
  547. vpn_progress(vpninfo, PRG_INFO,
  548. _("Detected MTU of %d bytes (was %d)\n"), vpninfo->ip_info.mtu, prev_mtu);
  549. } else {
  550. vpn_progress(vpninfo, PRG_DEBUG,
  551. _("No change in MTU after detection (was %d)\n"), prev_mtu);
  552. }
  553. skip_mtu:
  554. free(buf);
  555. }