test_dns.c 8.6 KB

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