test_dns.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. #include "or.h"
  2. #include "test.h"
  3. #define DNS_PRIVATE
  4. #include "dns.h"
  5. #include "connection.h"
  6. #define NS_MODULE dns
  7. #define NS_SUBMODULE clip_ttl
  8. static void
  9. NS(test_main)(void *arg)
  10. {
  11. (void)arg;
  12. uint32_t ttl_mid = MIN_DNS_TTL / 2 + MAX_DNS_TTL / 2;
  13. tt_int_op(dns_clip_ttl(MIN_DNS_TTL - 1),==,MIN_DNS_TTL);
  14. tt_int_op(dns_clip_ttl(ttl_mid),==,ttl_mid);
  15. tt_int_op(dns_clip_ttl(MAX_DNS_TTL + 1),==,MAX_DNS_TTL);
  16. done:
  17. return;
  18. }
  19. #undef NS_SUBMODULE
  20. #define NS_SUBMODULE expiry_ttl
  21. static void
  22. NS(test_main)(void *arg)
  23. {
  24. (void)arg;
  25. uint32_t ttl_mid = MIN_DNS_TTL / 2 + MAX_DNS_ENTRY_AGE / 2;
  26. tt_int_op(dns_get_expiry_ttl(MIN_DNS_TTL - 1),==,MIN_DNS_TTL);
  27. tt_int_op(dns_get_expiry_ttl(ttl_mid),==,ttl_mid);
  28. tt_int_op(dns_get_expiry_ttl(MAX_DNS_ENTRY_AGE + 1),==,MAX_DNS_ENTRY_AGE);
  29. done:
  30. return;
  31. }
  32. #undef NS_SUBMODULE
  33. #define NS_SUBMODULE resolve
  34. static int resolve_retval = 0;
  35. static int resolve_made_conn_pending = 0;
  36. static char *resolved_name = NULL;
  37. static cached_resolve_t *cache_entry = NULL;
  38. static int n_fake_impl = 0;
  39. /** This will be our configurable substitute for <b>dns_resolve_impl</b> in
  40. * dns.c. It will return <b>resolve_retval</b>,
  41. * and set <b>resolve_made_conn_pending</b> to
  42. * <b>made_connection_pending_out</b>. It will set <b>hostname_out</b>
  43. * to a duplicate of <b>resolved_name</b> and it will set <b>resolve_out</b>
  44. * to <b>cache_entry</b>. Lastly, it will increment <b>n_fake_impl</b< by
  45. * 1.
  46. */
  47. static int
  48. dns_resolve_fake_impl(edge_connection_t *exitconn, int is_resolve,
  49. or_circuit_t *oncirc, char **hostname_out,
  50. int *made_connection_pending_out,
  51. cached_resolve_t **resolve_out)
  52. {
  53. (void)oncirc;
  54. (void)exitconn;
  55. (void)is_resolve;
  56. if (made_connection_pending_out)
  57. *made_connection_pending_out = resolve_made_conn_pending;
  58. if (hostname_out && resolved_name)
  59. *hostname_out = tor_strdup(resolved_name);
  60. if (resolve_out && cache_entry)
  61. *resolve_out = cache_entry;
  62. n_fake_impl++;
  63. return resolve_retval;
  64. }
  65. static edge_connection_t *conn_for_resolved_cell = NULL;
  66. static int n_send_resolved_cell_replacement = 0;
  67. static uint8_t last_answer_type = 0;
  68. static cached_resolve_t *last_resolved;
  69. static void
  70. send_resolved_cell_replacement(edge_connection_t *conn, uint8_t answer_type,
  71. const cached_resolve_t *resolved)
  72. {
  73. conn_for_resolved_cell = conn;
  74. last_answer_type = answer_type;
  75. last_resolved = (cached_resolve_t *)resolved;
  76. n_send_resolved_cell_replacement++;
  77. }
  78. static int n_send_resolved_hostname_cell_replacement = 0;
  79. static char *last_resolved_hostname = NULL;
  80. static void
  81. send_resolved_hostname_cell_replacement(edge_connection_t *conn,
  82. const char *hostname)
  83. {
  84. conn_for_resolved_cell = conn;
  85. tor_free(last_resolved_hostname);
  86. last_resolved_hostname = tor_strdup(hostname);
  87. n_send_resolved_hostname_cell_replacement++;
  88. }
  89. static int n_dns_cancel_pending_resolve_replacement = 0;
  90. static void
  91. dns_cancel_pending_resolve_replacement(const char *address)
  92. {
  93. (void) address;
  94. n_dns_cancel_pending_resolve_replacement++;
  95. }
  96. static int n_connection_free = 0;
  97. static connection_t *last_freed_conn = NULL;
  98. static void
  99. connection_free_replacement(connection_t *conn)
  100. {
  101. n_connection_free++;
  102. last_freed_conn = conn;
  103. }
  104. static void
  105. NS(test_main)(void *arg)
  106. {
  107. (void) arg;
  108. int retval;
  109. int prev_n_send_resolved_hostname_cell_replacement;
  110. int prev_n_send_resolved_cell_replacement;
  111. int prev_n_connection_free;
  112. cached_resolve_t *fake_resolved = tor_malloc(sizeof(cached_resolve_t));
  113. edge_connection_t *exitconn = tor_malloc(sizeof(edge_connection_t));
  114. edge_connection_t *nextconn = tor_malloc(sizeof(edge_connection_t));
  115. or_circuit_t *on_circuit = tor_malloc(sizeof(or_circuit_t));
  116. memset(on_circuit,0,sizeof(or_circuit_t));
  117. on_circuit->base_.magic = OR_CIRCUIT_MAGIC;
  118. memset(fake_resolved,0,sizeof(cached_resolve_t));
  119. memset(exitconn,0,sizeof(edge_connection_t));
  120. memset(nextconn,0,sizeof(edge_connection_t));
  121. MOCK(dns_resolve_impl,dns_resolve_fake_impl);
  122. MOCK(send_resolved_cell,send_resolved_cell_replacement);
  123. MOCK(send_resolved_hostname_cell,send_resolved_hostname_cell_replacement);
  124. /*
  125. * CASE 1: dns_resolve_impl returns 1 and sets a hostname. purpose is
  126. * EXIT_PURPOSE_RESOLVE.
  127. *
  128. * We want dns_resolve() to call send_resolved_hostname_cell() for a
  129. * given exit connection (represented by edge_connection_t object)
  130. * with a hostname it received from _impl.
  131. */
  132. prev_n_send_resolved_hostname_cell_replacement =
  133. n_send_resolved_hostname_cell_replacement;
  134. exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;
  135. exitconn->on_circuit = &(on_circuit->base_);
  136. resolve_retval = 1;
  137. resolved_name = tor_strdup("www.torproject.org");
  138. retval = dns_resolve(exitconn);
  139. tt_int_op(retval,==,1);
  140. tt_str_op(resolved_name,==,last_resolved_hostname);
  141. tt_assert(conn_for_resolved_cell == exitconn);
  142. tt_int_op(n_send_resolved_hostname_cell_replacement,==,
  143. prev_n_send_resolved_hostname_cell_replacement + 1);
  144. tt_assert(exitconn->on_circuit == NULL);
  145. tor_free(last_resolved_hostname);
  146. // implies last_resolved_hostname = NULL;
  147. /* CASE 2: dns_resolve_impl returns 1, but does not set hostname.
  148. * Instead, it yields cached_resolve_t object.
  149. *
  150. * We want dns_resolve to call send_resolved_cell on exitconn with
  151. * RESOLVED_TYPE_AUTO and the cached_resolve_t object from _impl.
  152. */
  153. tor_free(resolved_name);
  154. resolved_name = NULL;
  155. exitconn->on_circuit = &(on_circuit->base_);
  156. cache_entry = fake_resolved;
  157. prev_n_send_resolved_cell_replacement =
  158. n_send_resolved_cell_replacement;
  159. retval = dns_resolve(exitconn);
  160. tt_int_op(retval,==,1);
  161. tt_assert(conn_for_resolved_cell == exitconn);
  162. tt_int_op(n_send_resolved_cell_replacement,==,
  163. prev_n_send_resolved_cell_replacement + 1);
  164. tt_assert(last_resolved == fake_resolved);
  165. tt_int_op(last_answer_type,==,0xff);
  166. tt_assert(exitconn->on_circuit == NULL);
  167. /* CASE 3: The purpose of exit connection is not EXIT_PURPOSE_RESOLVE
  168. * and _impl returns 1.
  169. *
  170. * We want dns_resolve to prepend exitconn to n_streams linked list.
  171. * We don't want it to send any cells about hostname being resolved.
  172. */
  173. exitconn->base_.purpose = EXIT_PURPOSE_CONNECT;
  174. exitconn->on_circuit = &(on_circuit->base_);
  175. on_circuit->n_streams = nextconn;
  176. prev_n_send_resolved_cell_replacement =
  177. n_send_resolved_cell_replacement;
  178. prev_n_send_resolved_hostname_cell_replacement =
  179. n_send_resolved_hostname_cell_replacement;
  180. retval = dns_resolve(exitconn);
  181. tt_int_op(retval,==,1);
  182. tt_assert(on_circuit->n_streams == exitconn);
  183. tt_assert(exitconn->next_stream == nextconn);
  184. tt_int_op(prev_n_send_resolved_cell_replacement,==,
  185. n_send_resolved_cell_replacement);
  186. tt_int_op(prev_n_send_resolved_hostname_cell_replacement,==,
  187. n_send_resolved_hostname_cell_replacement);
  188. /* CASE 4: _impl returns 0.
  189. *
  190. * We want dns_resolve() to set exitconn state to
  191. * EXIT_CONN_STATE_RESOLVING and prepend exitconn to resolving_streams
  192. * linked list.
  193. */
  194. exitconn->on_circuit = &(on_circuit->base_);
  195. resolve_retval = 0;
  196. exitconn->next_stream = NULL;
  197. on_circuit->resolving_streams = nextconn;
  198. retval = dns_resolve(exitconn);
  199. tt_int_op(retval,==,0);
  200. tt_int_op(exitconn->base_.state,==,EXIT_CONN_STATE_RESOLVING);
  201. tt_assert(on_circuit->resolving_streams == exitconn);
  202. tt_assert(exitconn->next_stream == nextconn);
  203. /* CASE 5: _impl returns -1 when purpose of exitconn is
  204. * EXIT_PURPOSE_RESOLVE. We want dns_resolve to call send_resolved_cell
  205. * on exitconn with type being RESOLVED_TYPE_ERROR.
  206. */
  207. MOCK(dns_cancel_pending_resolve,dns_cancel_pending_resolve_replacement);
  208. MOCK(connection_free,connection_free_replacement);
  209. exitconn->on_circuit = &(on_circuit->base_);
  210. exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;
  211. resolve_retval = -1;
  212. prev_n_send_resolved_cell_replacement =
  213. n_send_resolved_cell_replacement;
  214. prev_n_connection_free = n_connection_free;
  215. retval = dns_resolve(exitconn);
  216. tt_int_op(retval,==,-1);
  217. tt_int_op(n_send_resolved_cell_replacement,==,
  218. prev_n_send_resolved_cell_replacement + 1);
  219. tt_int_op(last_answer_type,==,RESOLVED_TYPE_ERROR);
  220. tt_int_op(n_dns_cancel_pending_resolve_replacement,==,1);
  221. tt_int_op(n_connection_free,==,prev_n_connection_free + 1);
  222. tt_assert(last_freed_conn == TO_CONN(exitconn));
  223. done:
  224. UNMOCK(dns_resolve_impl);
  225. UNMOCK(send_resolved_cell);
  226. UNMOCK(send_resolved_hostname_cell);
  227. UNMOCK(dns_cancel_pending_resolve);
  228. UNMOCK(connection_free);
  229. tor_free(on_circuit);
  230. tor_free(exitconn);
  231. tor_free(nextconn);
  232. tor_free(resolved_name);
  233. tor_free(fake_resolved);
  234. tor_free(last_resolved_hostname);
  235. return;
  236. }
  237. #undef NS_SUBMODULE
  238. struct testcase_t dns_tests[] = {
  239. TEST_CASE(clip_ttl),
  240. TEST_CASE(expiry_ttl),
  241. TEST_CASE(resolve),
  242. END_OF_TESTCASES
  243. };
  244. #undef NS_MODULE