Fix some memory issues in test_dns.c
[tor.git] / src / test / test_dns.c
blobad81914ccb4b5dccc1b5ab9be6ef4b2799e75fe9
1 #include "or.h"
2 #include "test.h"
4 #define DNS_PRIVATE
6 #include "dns.h"
7 #include "connection.h"
9 static void
10 test_dns_clip_ttl(void *arg)
12 (void)arg;
14 uint32_t ttl_mid = MIN_DNS_TTL / 2 + MAX_DNS_TTL / 2;
16 tt_int_op(dns_clip_ttl(MIN_DNS_TTL - 1),==,MIN_DNS_TTL);
17 tt_int_op(dns_clip_ttl(ttl_mid),==,ttl_mid);
18 tt_int_op(dns_clip_ttl(MAX_DNS_TTL + 1),==,MAX_DNS_TTL);
20 done:
21 return;
24 static void
25 test_dns_expiry_ttl(void *arg)
27 (void)arg;
29 uint32_t ttl_mid = MIN_DNS_TTL / 2 + MAX_DNS_ENTRY_AGE / 2;
31 tt_int_op(dns_get_expiry_ttl(MIN_DNS_TTL - 1),==,MIN_DNS_TTL);
32 tt_int_op(dns_get_expiry_ttl(ttl_mid),==,ttl_mid);
33 tt_int_op(dns_get_expiry_ttl(MAX_DNS_ENTRY_AGE + 1),==,MAX_DNS_ENTRY_AGE);
35 done:
36 return;
39 static int resolve_retval = 0;
40 static int resolve_made_conn_pending = 0;
41 static char *resolved_name = NULL;
42 static cached_resolve_t *cache_entry = NULL;
44 static int n_fake_impl = 0;
46 /** This will be our configurable substitute for <b>dns_resolve_impl</b> in
47 * dns.c. It will return <b>resolve_retval</b>,
48 * and set <b>resolve_made_conn_pending</b> to
49 * <b>made_connection_pending_out</b>. It will set <b>hostname_out</b>
50 * to a duplicate of <b>resolved_name</b> and it will set <b>resolve_out</b>
51 * to <b>cache_entry</b>. Lastly, it will increment <b>n_fake_impl</b< by
52 * 1.
54 static int
55 dns_resolve_fake_impl(edge_connection_t *exitconn, int is_resolve,
56 or_circuit_t *oncirc, char **hostname_out,
57 int *made_connection_pending_out,
58 cached_resolve_t **resolve_out)
60 (void)oncirc;
61 (void)exitconn;
62 (void)is_resolve;
64 if (made_connection_pending_out)
65 *made_connection_pending_out = resolve_made_conn_pending;
67 if (hostname_out && resolved_name)
68 *hostname_out = tor_strdup(resolved_name);
70 if (resolve_out && cache_entry)
71 *resolve_out = cache_entry;
73 n_fake_impl++;
75 return resolve_retval;
78 static edge_connection_t *conn_for_resolved_cell = NULL;
80 static int n_send_resolved_cell_replacement = 0;
81 static uint8_t last_answer_type = 0;
82 static cached_resolve_t *last_resolved;
84 static void
85 send_resolved_cell_replacement(edge_connection_t *conn, uint8_t answer_type,
86 const cached_resolve_t *resolved)
88 conn_for_resolved_cell = conn;
90 last_answer_type = answer_type;
91 last_resolved = (cached_resolve_t *)resolved;
93 n_send_resolved_cell_replacement++;
96 static int n_send_resolved_hostname_cell_replacement = 0;
98 static char *last_resolved_hostname = NULL;
100 static void
101 send_resolved_hostname_cell_replacement(edge_connection_t *conn,
102 const char *hostname)
104 conn_for_resolved_cell = conn;
106 tor_free(last_resolved_hostname);
107 last_resolved_hostname = tor_strdup(hostname);
109 n_send_resolved_hostname_cell_replacement++;
112 static int n_dns_cancel_pending_resolve_replacement = 0;
114 static void
115 dns_cancel_pending_resolve_replacement(const char *address)
117 (void) address;
118 n_dns_cancel_pending_resolve_replacement++;
121 static int n_connection_free = 0;
122 static connection_t *last_freed_conn = NULL;
124 static void
125 connection_free_replacement(connection_t *conn)
127 n_connection_free++;
129 last_freed_conn = conn;
132 static void
133 test_dns_resolve_outer(void *arg)
135 (void) arg;
136 int retval;
137 int prev_n_send_resolved_hostname_cell_replacement;
138 int prev_n_send_resolved_cell_replacement;
139 int prev_n_connection_free;
140 cached_resolve_t *fake_resolved = tor_malloc(sizeof(cached_resolve_t));
141 edge_connection_t *exitconn = tor_malloc(sizeof(edge_connection_t));
142 edge_connection_t *nextconn = tor_malloc(sizeof(edge_connection_t));
144 or_circuit_t *on_circuit = tor_malloc(sizeof(or_circuit_t));
145 memset(on_circuit,0,sizeof(or_circuit_t));
146 on_circuit->base_.magic = OR_CIRCUIT_MAGIC;
148 memset(fake_resolved,0,sizeof(cached_resolve_t));
149 memset(exitconn,0,sizeof(edge_connection_t));
150 memset(nextconn,0,sizeof(edge_connection_t));
152 MOCK(dns_resolve_impl,dns_resolve_fake_impl);
153 MOCK(send_resolved_cell,send_resolved_cell_replacement);
154 MOCK(send_resolved_hostname_cell,send_resolved_hostname_cell_replacement);
157 * CASE 1: dns_resolve_impl returns 1 and sets a hostname. purpose is
158 * EXIT_PURPOSE_RESOLVE.
160 * We want dns_resolve() to call send_resolved_hostname_cell() for a
161 * given exit connection (represented by edge_connection_t object)
162 * with a hostname it received from _impl.
165 prev_n_send_resolved_hostname_cell_replacement =
166 n_send_resolved_hostname_cell_replacement;
168 exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;
169 exitconn->on_circuit = &(on_circuit->base_);
171 resolve_retval = 1;
172 resolved_name = tor_strdup("www.torproject.org");
174 retval = dns_resolve(exitconn);
176 tt_int_op(retval,==,1);
177 tt_str_op(resolved_name,==,last_resolved_hostname);
178 tt_assert(conn_for_resolved_cell == exitconn);
179 tt_int_op(n_send_resolved_hostname_cell_replacement,==,
180 prev_n_send_resolved_hostname_cell_replacement + 1);
181 tt_assert(exitconn->on_circuit == NULL);
183 tor_free(last_resolved_hostname);
184 // implies last_resolved_hostname = NULL;
186 /* CASE 2: dns_resolve_impl returns 1, but does not set hostname.
187 * Instead, it yields cached_resolve_t object.
189 * We want dns_resolve to call send_resolved_cell on exitconn with
190 * RESOLVED_TYPE_AUTO and the cached_resolve_t object from _impl.
193 tor_free(resolved_name);
194 resolved_name = NULL;
196 exitconn->on_circuit = &(on_circuit->base_);
198 cache_entry = fake_resolved;
200 prev_n_send_resolved_cell_replacement =
201 n_send_resolved_cell_replacement;
203 retval = dns_resolve(exitconn);
205 tt_int_op(retval,==,1);
206 tt_assert(conn_for_resolved_cell == exitconn);
207 tt_int_op(n_send_resolved_cell_replacement,==,
208 prev_n_send_resolved_cell_replacement + 1);
209 tt_assert(last_resolved == fake_resolved);
210 tt_int_op(last_answer_type,==,0xff);
211 tt_assert(exitconn->on_circuit == NULL);
213 /* CASE 3: The purpose of exit connection is not EXIT_PURPOSE_RESOLVE
214 * and _impl returns 1.
216 * We want dns_resolve to prepend exitconn to n_streams linked list.
217 * We don't want it to send any cells about hostname being resolved.
220 exitconn->base_.purpose = EXIT_PURPOSE_CONNECT;
221 exitconn->on_circuit = &(on_circuit->base_);
223 on_circuit->n_streams = nextconn;
225 prev_n_send_resolved_cell_replacement =
226 n_send_resolved_cell_replacement;
228 prev_n_send_resolved_hostname_cell_replacement =
229 n_send_resolved_hostname_cell_replacement;
231 retval = dns_resolve(exitconn);
233 tt_int_op(retval,==,1);
234 tt_assert(on_circuit->n_streams == exitconn);
235 tt_assert(exitconn->next_stream == nextconn);
236 tt_int_op(prev_n_send_resolved_cell_replacement,==,
237 n_send_resolved_cell_replacement);
238 tt_int_op(prev_n_send_resolved_hostname_cell_replacement,==,
239 n_send_resolved_hostname_cell_replacement);
241 /* CASE 4: _impl returns 0.
243 * We want dns_resolve() to set exitconn state to
244 * EXIT_CONN_STATE_RESOLVING and prepend exitconn to resolving_streams
245 * linked list.
248 exitconn->on_circuit = &(on_circuit->base_);
250 resolve_retval = 0;
252 exitconn->next_stream = NULL;
253 on_circuit->resolving_streams = nextconn;
255 retval = dns_resolve(exitconn);
257 tt_int_op(retval,==,0);
258 tt_int_op(exitconn->base_.state,==,EXIT_CONN_STATE_RESOLVING);
259 tt_assert(on_circuit->resolving_streams == exitconn);
260 tt_assert(exitconn->next_stream == nextconn);
262 /* CASE 5: _impl returns -1 when purpose of exitconn is
263 * EXIT_PURPOSE_RESOLVE. We want dns_resolve to call send_resolved_cell
264 * on exitconn with type being RESOLVED_TYPE_ERROR.
267 MOCK(dns_cancel_pending_resolve,dns_cancel_pending_resolve_replacement);
268 MOCK(connection_free,connection_free_replacement);
270 exitconn->on_circuit = &(on_circuit->base_);
271 exitconn->base_.purpose = EXIT_PURPOSE_RESOLVE;
273 resolve_retval = -1;
275 prev_n_send_resolved_cell_replacement =
276 n_send_resolved_cell_replacement;
278 prev_n_connection_free = n_connection_free;
280 retval = dns_resolve(exitconn);
282 tt_int_op(retval,==,-1);
283 tt_int_op(n_send_resolved_cell_replacement,==,
284 prev_n_send_resolved_cell_replacement + 1);
285 tt_int_op(last_answer_type,==,RESOLVED_TYPE_ERROR);
286 tt_int_op(n_dns_cancel_pending_resolve_replacement,==,1);
287 tt_int_op(n_connection_free,==,prev_n_connection_free + 1);
288 tt_assert(last_freed_conn == TO_CONN(exitconn));
290 done:
291 UNMOCK(dns_resolve_impl);
292 UNMOCK(send_resolved_cell);
293 UNMOCK(send_resolved_hostname_cell);
294 UNMOCK(dns_cancel_pending_resolve);
295 UNMOCK(connection_free);
296 tor_free(on_circuit);
297 tor_free(exitconn);
298 tor_free(nextconn);
299 tor_free(resolved_name);
300 tor_free(fake_resolved);
301 tor_free(last_resolved_hostname);
302 return;
305 struct testcase_t dns_tests[] = {
306 { "clip_ttl", test_dns_clip_ttl, 0, NULL, NULL },
307 { "expiry_ttl", test_dns_expiry_ttl, 0, NULL, NULL },
308 { "resolve_outer", test_dns_resolve_outer, TT_FORK, NULL, NULL },
309 END_OF_TESTCASES