2
0

bio_tfo_test.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /*
  2. * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
  3. *
  4. * Licensed under the Apache License 2.0 (the "License"). You may not use
  5. * this file except in compliance with the License. You can obtain a copy
  6. * in the file LICENSE in the source distribution or at
  7. * https://www.openssl.org/source/license.html
  8. */
  9. #include <openssl/bio.h>
  10. #include "internal/e_os.h"
  11. #include "internal/sockets.h"
  12. #include "internal/bio_tfo.h"
  13. #include "testutil.h"
  14. /* If OS support is added in crypto/bio/bio_tfo.h, add it here */
  15. #if defined(OPENSSL_SYS_LINUX)
  16. # define GOOD_OS 1
  17. #elif defined(__FreeBSD__)
  18. # define GOOD_OS 1
  19. #elif defined(OPENSSL_SYS_MACOSX)
  20. # define GOOD_OS 1
  21. #else
  22. # ifdef GOOD_OS
  23. # undef GOOD_OS
  24. # endif
  25. #endif
  26. #if !defined(OPENSSL_NO_TFO) && defined(GOOD_OS)
  27. /*
  28. * This test is to ensure that if TCP Fast Open is configured, that socket
  29. * connections will still work. These tests are able to detect if TCP Fast
  30. * Open works, but the tests will pass as long as the socket connects.
  31. *
  32. * The first test function tests the socket interface as implemented as BIOs.
  33. *
  34. * The second test functions tests the socket interface as implemented as fds.
  35. *
  36. * The tests are run 5 times. The first time is without TFO.
  37. * The second test will create the TCP fast open cookie,
  38. * this can be seen in `ip tcp_metrics` and in /proc/net/netstat/ on Linux.
  39. * e.g. on Linux 4.15.0-135-generic:
  40. * $ grep '^TcpExt:' /proc/net/netstat | cut -d ' ' -f 84-90 | column -t
  41. * The third attempt will use the cookie and actually do TCP fast open.
  42. * The 4th time is client-TFO only, the 5th time is server-TFO only.
  43. */
  44. # define SOCKET_DATA "FooBar"
  45. # define SOCKET_DATA_LEN sizeof(SOCKET_DATA)
  46. static int test_bio_tfo(int idx)
  47. {
  48. BIO *cbio = NULL;
  49. BIO *abio = NULL;
  50. BIO *sbio = NULL;
  51. int ret = 0;
  52. int sockerr = 0;
  53. const char *port;
  54. int server_tfo = 0;
  55. int client_tfo = 0;
  56. size_t bytes;
  57. char read_buffer[20];
  58. switch (idx) {
  59. default:
  60. case 0:
  61. break;
  62. case 1:
  63. case 2:
  64. server_tfo = 1;
  65. client_tfo = 1;
  66. break;
  67. case 3:
  68. client_tfo = 1;
  69. break;
  70. case 4:
  71. server_tfo = 1;
  72. break;
  73. }
  74. /* ACCEPT SOCKET */
  75. if (!TEST_ptr(abio = BIO_new_accept("localhost:0"))
  76. || !TEST_true(BIO_set_nbio_accept(abio, 1))
  77. || !TEST_true(BIO_set_tfo_accept(abio, server_tfo))
  78. || !TEST_int_gt(BIO_do_accept(abio), 0)
  79. || !TEST_ptr(port = BIO_get_accept_port(abio))) {
  80. sockerr = get_last_socket_error();
  81. goto err;
  82. }
  83. /* Note: first BIO_do_accept will basically do the bind/listen */
  84. /* CLIENT SOCKET */
  85. if (!TEST_ptr(cbio = BIO_new_connect("localhost"))
  86. || !TEST_long_gt(BIO_set_conn_port(cbio, port), 0)
  87. || !TEST_long_gt(BIO_set_nbio(cbio, 1), 0)
  88. || !TEST_long_gt(BIO_set_tfo(cbio, client_tfo), 0)) {
  89. sockerr = get_last_socket_error();
  90. goto err;
  91. }
  92. /* FIRST ACCEPT: no connection should be established */
  93. if (BIO_do_accept(abio) <= 0) {
  94. if (!BIO_should_retry(abio)) {
  95. sockerr = get_last_socket_error();
  96. BIO_printf(bio_err, "Error: failed without EAGAIN\n");
  97. goto err;
  98. }
  99. } else {
  100. sbio = BIO_pop(abio);
  101. BIO_printf(bio_err, "Error: accepted unknown connection\n");
  102. goto err;
  103. }
  104. /* CONNECT ATTEMPT: different behavior based on TFO support */
  105. if (BIO_do_connect(cbio) <= 0) {
  106. sockerr = get_last_socket_error();
  107. if (sockerr == EOPNOTSUPP) {
  108. BIO_printf(bio_err, "Skip: TFO not enabled/supported for client\n");
  109. goto success;
  110. } else if (sockerr != EINPROGRESS) {
  111. BIO_printf(bio_err, "Error: failed without EINPROGRESSn");
  112. goto err;
  113. }
  114. }
  115. /* macOS needs some time for this to happen, so put in a select */
  116. if (!TEST_int_ge(BIO_wait(abio, time(NULL) + 2, 0), 0)) {
  117. sockerr = get_last_socket_error();
  118. BIO_printf(bio_err, "Error: socket wait failed\n");
  119. goto err;
  120. }
  121. /* SECOND ACCEPT: if TFO is supported, this will still fail until data is sent */
  122. if (BIO_do_accept(abio) <= 0) {
  123. if (!BIO_should_retry(abio)) {
  124. sockerr = get_last_socket_error();
  125. BIO_printf(bio_err, "Error: failed without EAGAIN\n");
  126. goto err;
  127. }
  128. } else {
  129. if (idx == 0)
  130. BIO_printf(bio_err, "Success: non-TFO connection accepted without data\n");
  131. else if (idx == 1)
  132. BIO_printf(bio_err, "Ignore: connection accepted before data, possibly no TFO cookie, or TFO may not be enabled\n");
  133. else if (idx == 4)
  134. BIO_printf(bio_err, "Success: connection accepted before data, client TFO is disabled\n");
  135. else
  136. BIO_printf(bio_err, "Warning: connection accepted before data, TFO may not be enabled\n");
  137. sbio = BIO_pop(abio);
  138. goto success;
  139. }
  140. /* SEND DATA: this should establish the actual TFO connection */
  141. if (!TEST_true(BIO_write_ex(cbio, SOCKET_DATA, SOCKET_DATA_LEN, &bytes))) {
  142. sockerr = get_last_socket_error();
  143. goto err;
  144. }
  145. /* macOS needs some time for this to happen, so put in a select */
  146. if (!TEST_int_ge(BIO_wait(abio, time(NULL) + 2, 0), 0)) {
  147. sockerr = get_last_socket_error();
  148. BIO_printf(bio_err, "Error: socket wait failed\n");
  149. goto err;
  150. }
  151. /* FINAL ACCEPT: if TFO is enabled, socket should be accepted at *this* point */
  152. if (BIO_do_accept(abio) <= 0) {
  153. sockerr = get_last_socket_error();
  154. BIO_printf(bio_err, "Error: socket not accepted\n");
  155. goto err;
  156. }
  157. BIO_printf(bio_err, "Success: Server accepted socket after write\n");
  158. if (!TEST_ptr(sbio = BIO_pop(abio))
  159. || !TEST_true(BIO_read_ex(sbio, read_buffer, sizeof(read_buffer), &bytes))
  160. || !TEST_size_t_eq(bytes, SOCKET_DATA_LEN)
  161. || !TEST_strn_eq(read_buffer, SOCKET_DATA, SOCKET_DATA_LEN)) {
  162. sockerr = get_last_socket_error();
  163. goto err;
  164. }
  165. success:
  166. sockerr = 0;
  167. ret = 1;
  168. err:
  169. if (sockerr != 0) {
  170. const char *errstr = strerror(sockerr);
  171. if (errstr != NULL)
  172. BIO_printf(bio_err, "last errno: %d=%s\n", sockerr, errstr);
  173. }
  174. BIO_free(cbio);
  175. BIO_free(abio);
  176. BIO_free(sbio);
  177. return ret;
  178. }
  179. static int test_fd_tfo(int idx)
  180. {
  181. struct sockaddr_storage sstorage;
  182. socklen_t slen;
  183. struct addrinfo *ai = NULL;
  184. struct addrinfo hints;
  185. int ret = 0;
  186. int cfd = -1; /* client socket */
  187. int afd = -1; /* accept socket */
  188. int sfd = -1; /* server accepted socket */
  189. BIO_ADDR *baddr = NULL;
  190. char read_buffer[20];
  191. int bytes_read;
  192. int server_flags = BIO_SOCK_NONBLOCK;
  193. int client_flags = BIO_SOCK_NONBLOCK;
  194. int sockerr = 0;
  195. unsigned short port;
  196. void *addr;
  197. size_t addrlen;
  198. switch (idx) {
  199. default:
  200. case 0:
  201. break;
  202. case 1:
  203. case 2:
  204. server_flags |= BIO_SOCK_TFO;
  205. client_flags |= BIO_SOCK_TFO;
  206. break;
  207. case 3:
  208. client_flags |= BIO_SOCK_TFO;
  209. break;
  210. case 4:
  211. server_flags |= BIO_SOCK_TFO;
  212. break;
  213. }
  214. /* ADDRESS SETUP */
  215. memset(&hints, 0, sizeof(hints));
  216. hints.ai_family = AF_UNSPEC;
  217. hints.ai_socktype = SOCK_STREAM;
  218. if (!TEST_int_eq(getaddrinfo(NULL, "0", &hints, &ai), 0))
  219. goto err;
  220. switch (ai->ai_family) {
  221. case AF_INET:
  222. port = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
  223. addr = &((struct sockaddr_in *)ai->ai_addr)->sin_addr;
  224. addrlen = sizeof(((struct sockaddr_in *)ai->ai_addr)->sin_addr);
  225. BIO_printf(bio_err, "Using IPv4\n");
  226. break;
  227. case AF_INET6:
  228. port = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port;
  229. addr = &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
  230. addrlen = sizeof(((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr);
  231. BIO_printf(bio_err, "Using IPv6\n");
  232. break;
  233. default:
  234. BIO_printf(bio_err, "Unknown address family %d\n", ai->ai_family);
  235. goto err;
  236. }
  237. if (!TEST_ptr(baddr = BIO_ADDR_new())
  238. || !TEST_true(BIO_ADDR_rawmake(baddr, ai->ai_family, addr, addrlen, port)))
  239. goto err;
  240. /* ACCEPT SOCKET */
  241. if (!TEST_int_ge(afd = BIO_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, 0), 0)
  242. || !TEST_true(BIO_listen(afd, baddr, server_flags)))
  243. goto err;
  244. /* UPDATE ADDRESS WITH PORT */
  245. slen = sizeof(sstorage);
  246. if (!TEST_int_ge(getsockname(afd, (struct sockaddr *)&sstorage, &slen), 0))
  247. goto err;
  248. switch (sstorage.ss_family) {
  249. case AF_INET:
  250. port = ((struct sockaddr_in *)&sstorage)->sin_port;
  251. addr = &((struct sockaddr_in *)&sstorage)->sin_addr;
  252. addrlen = sizeof(((struct sockaddr_in *)&sstorage)->sin_addr);
  253. break;
  254. case AF_INET6:
  255. port = ((struct sockaddr_in6 *)&sstorage)->sin6_port;
  256. addr = &((struct sockaddr_in6 *)&sstorage)->sin6_addr;
  257. addrlen = sizeof(((struct sockaddr_in6 *)&sstorage)->sin6_addr);
  258. break;
  259. default:
  260. goto err;
  261. }
  262. if(!TEST_true(BIO_ADDR_rawmake(baddr, sstorage.ss_family, addr, addrlen, port)))
  263. goto err;
  264. /* CLIENT SOCKET */
  265. if (!TEST_int_ge(cfd = BIO_socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol, 0), 0))
  266. goto err;
  267. /* FIRST ACCEPT: no connection should be established */
  268. sfd = BIO_accept_ex(afd, NULL, 0);
  269. if (sfd == -1) {
  270. sockerr = get_last_socket_error();
  271. /* Note: Windows would hit WSAEWOULDBLOCK */
  272. if (sockerr != EAGAIN) {
  273. BIO_printf(bio_err, "Error: failed without EAGAIN\n");
  274. goto err;
  275. }
  276. } else {
  277. BIO_printf(bio_err, "Error: accepted unknown connection\n");
  278. goto err;
  279. }
  280. /* CONNECT ATTEMPT: different behavior based on TFO support */
  281. if (!BIO_connect(cfd, baddr, client_flags)) {
  282. sockerr = get_last_socket_error();
  283. if (sockerr == EOPNOTSUPP) {
  284. BIO_printf(bio_err, "Skip: TFO not enabled/supported for client\n");
  285. goto success;
  286. } else {
  287. /* Note: Windows would hit WSAEWOULDBLOCK */
  288. if (sockerr != EINPROGRESS) {
  289. BIO_printf(bio_err, "Error: failed without EINPROGRESS\n");
  290. goto err;
  291. }
  292. }
  293. }
  294. /* macOS needs some time for this to happen, so put in a select */
  295. if (!TEST_int_ge(BIO_socket_wait(afd, 1, time(NULL) + 2), 0)) {
  296. sockerr = get_last_socket_error();
  297. BIO_printf(bio_err, "Error: socket wait failed\n");
  298. goto err;
  299. }
  300. /* SECOND ACCEPT: if TFO is supported, this will still fail until data is sent */
  301. sfd = BIO_accept_ex(afd, NULL, 0);
  302. if (sfd == -1) {
  303. sockerr = get_last_socket_error();
  304. /* Note: Windows would hit WSAEWOULDBLOCK */
  305. if (sockerr != EAGAIN) {
  306. BIO_printf(bio_err, "Error: failed without EAGAIN\n");
  307. goto err;
  308. }
  309. } else {
  310. if (idx == 0)
  311. BIO_printf(bio_err, "Success: non-TFO connection accepted without data\n");
  312. else if (idx == 1)
  313. BIO_printf(bio_err, "Ignore: connection accepted before data, possibly no TFO cookie, or TFO may not be enabled\n");
  314. else if (idx == 4)
  315. BIO_printf(bio_err, "Success: connection accepted before data, client TFO is disabled\n");
  316. else
  317. BIO_printf(bio_err, "Warning: connection accepted before data, TFO may not be enabled\n");
  318. goto success;
  319. }
  320. /* SEND DATA: this should establish the actual TFO connection */
  321. #ifdef OSSL_TFO_SENDTO
  322. if (!TEST_int_ge(sendto(cfd, SOCKET_DATA, SOCKET_DATA_LEN, OSSL_TFO_SENDTO,
  323. (struct sockaddr *)&sstorage, slen), 0)) {
  324. sockerr = get_last_socket_error();
  325. goto err;
  326. }
  327. #else
  328. if (!TEST_int_ge(writesocket(cfd, SOCKET_DATA, SOCKET_DATA_LEN), 0)) {
  329. sockerr = get_last_socket_error();
  330. goto err;
  331. }
  332. #endif
  333. /* macOS needs some time for this to happen, so put in a select */
  334. if (!TEST_int_ge(BIO_socket_wait(afd, 1, time(NULL) + 2), 0)) {
  335. sockerr = get_last_socket_error();
  336. BIO_printf(bio_err, "Error: socket wait failed\n");
  337. goto err;
  338. }
  339. /* FINAL ACCEPT: if TFO is enabled, socket should be accepted at *this* point */
  340. sfd = BIO_accept_ex(afd, NULL, 0);
  341. if (sfd == -1) {
  342. sockerr = get_last_socket_error();
  343. BIO_printf(bio_err, "Error: socket not accepted\n");
  344. goto err;
  345. }
  346. BIO_printf(bio_err, "Success: Server accepted socket after write\n");
  347. bytes_read = readsocket(sfd, read_buffer, sizeof(read_buffer));
  348. if (!TEST_int_eq(bytes_read, SOCKET_DATA_LEN)
  349. || !TEST_strn_eq(read_buffer, SOCKET_DATA, SOCKET_DATA_LEN)) {
  350. sockerr = get_last_socket_error();
  351. goto err;
  352. }
  353. success:
  354. sockerr = 0;
  355. ret = 1;
  356. err:
  357. if (sockerr != 0) {
  358. const char *errstr = strerror(sockerr);
  359. if (errstr != NULL)
  360. BIO_printf(bio_err, "last errno: %d=%s\n", sockerr, errstr);
  361. }
  362. if (ai != NULL)
  363. freeaddrinfo(ai);
  364. BIO_ADDR_free(baddr);
  365. BIO_closesocket(cfd);
  366. BIO_closesocket(sfd);
  367. BIO_closesocket(afd);
  368. return ret;
  369. }
  370. #endif
  371. int setup_tests(void)
  372. {
  373. #if !defined(OPENSSL_NO_TFO) && defined(GOOD_OS)
  374. ADD_ALL_TESTS(test_bio_tfo, 5);
  375. ADD_ALL_TESTS(test_fd_tfo, 5);
  376. #endif
  377. return 1;
  378. }