1 /* check-sources:disable-copyright-check */
2 #include <droplet.h>
3 #include <check.h>
4 #include <arpa/inet.h>
5 #include <unistd.h>
6 #include <netdb.h>
7 #include "utest_main.h"
8 
9 dpl_status_t dpl_addrlist_get_nth(dpl_addrlist_t* addrlist,
10                                   int n,
11                                   dpl_addr_t** addrp);
12 
13 /* create an empty addrlist */
START_TEST(empty_test)14 START_TEST(empty_test)
15 {
16   dpl_addrlist_t* addrlist;
17   dpl_addr_t* addrp = NULL;
18   char* s = NULL;
19 
20   addrlist = dpl_addrlist_create("4244");
21   dpl_assert_ptr_not_null(addrlist);
22 
23   /* an empty addrlist has a zero count */
24   dpl_assert_int_eq(0, dpl_addrlist_count(addrlist));
25 
26   /* an empty addrlist has no elements to get */
27   dpl_assert_int_eq(DPL_ENOENT, dpl_addrlist_get_nth(addrlist, 0, &addrp));
28 
29   /* an empty addrlist is described as a non-NULL empty string */
30   s = dpl_addrlist_get(addrlist);
31   dpl_assert_str_eq(s, "");
32 
33   free(s);
34   dpl_addrlist_free(addrlist);
35 }
36 END_TEST
37 
START_TEST(default_default_port_test)38 START_TEST(default_default_port_test)
39 {
40   dpl_addrlist_t* addrlist;
41   dpl_status_t r;
42   char* s;
43 
44   /* create the addrlist */
45   addrlist = dpl_addrlist_create(NULL);
46   dpl_assert_ptr_not_null(addrlist);
47 
48   r = dpl_addrlist_add_from_str(addrlist, "192.168.1.1");
49   dpl_assert_int_eq(DPL_SUCCESS, r);
50   dpl_assert_int_eq(1, dpl_addrlist_count(addrlist));
51 
52   /* verify the string form of the addrlist */
53   s = dpl_addrlist_get(addrlist);
54   dpl_assert_str_eq(s, "192.168.1.1:80");
55 
56   free(s);
57   dpl_addrlist_free(addrlist);
58 }
59 END_TEST
60 
START_TEST(multiple_add_test)61 START_TEST(multiple_add_test)
62 {
63   dpl_addrlist_t* addrlist;
64   dpl_status_t r;
65 
66   /* create the addrlist */
67   addrlist = dpl_addrlist_create(NULL);
68   dpl_assert_ptr_not_null(addrlist);
69 
70   /* add an address */
71   r = dpl_addrlist_add_from_str(addrlist, "192.168.1.1:80");
72   dpl_assert_int_eq(DPL_SUCCESS, r);
73   dpl_assert_int_eq(1, dpl_addrlist_count(addrlist));
74 
75   /* adding the same address again is a no-op (well not
76    * quite but close enough). */
77   r = dpl_addrlist_add_from_str(addrlist, "192.168.1.1:80");
78   dpl_assert_int_eq(DPL_SUCCESS, r);
79   dpl_assert_int_eq(1, dpl_addrlist_count(addrlist));
80 
81   /* an address which is the same IP but a different
82    * port counts as a different address */
83   r = dpl_addrlist_add_from_str(addrlist, "192.168.1.1:8080");
84   dpl_assert_int_eq(DPL_SUCCESS, r);
85   dpl_assert_int_eq(2, dpl_addrlist_count(addrlist));
86 
87   dpl_addrlist_free(addrlist);
88 }
89 END_TEST
90 
START_TEST(create_from_str_1_test)91 START_TEST(create_from_str_1_test)
92 {
93   dpl_addrlist_t* addrlist;
94   dpl_addr_t* addrp = NULL;
95   dpl_status_t r;
96   char *s, ident[INET_ADDRSTRLEN];
97 
98   /* create the addrlist */
99   addrlist = dpl_addrlist_create_from_str("4244", "192.168.1.1");
100   dpl_assert_ptr_not_null(addrlist);
101 
102   /* verify length */
103   dpl_assert_int_eq(1, dpl_addrlist_count(addrlist));
104 
105   /* verify getting elements by index */
106   r = dpl_addrlist_get_nth(addrlist, 0, &addrp);
107   dpl_assert_int_eq(DPL_SUCCESS, r);
108   dpl_assert_ptr_not_null(addrp);
109   dpl_assert_str_eq(addrp->host, "192.168.1.1");
110   dpl_assert_str_eq(addrp->portstr, "4244");
111   dpl_assert_ptr_not_null(addrp->h);
112   dpl_assert_int_eq(addrp->h->h_addrtype, AF_INET);
113   inet_ntop(addrp->h->h_addrtype, addrp->h->h_addr, ident, sizeof(ident));
114   dpl_assert_str_eq(ident, "192.168.1.1");
115   dpl_assert_int_eq(addrp->port, 4244);
116 
117   /* indexes wrap modulo the count */
118   r = dpl_addrlist_get_nth(addrlist, 1, &addrp);
119   dpl_assert_ptr_not_null(addrp);
120   dpl_assert_str_eq(addrp->host, "192.168.1.1");
121   dpl_assert_str_eq(addrp->portstr, "4244");
122   dpl_assert_ptr_not_null(addrp->h);
123   dpl_assert_int_eq(addrp->h->h_addrtype, AF_INET);
124   inet_ntop(addrp->h->h_addrtype, addrp->h->h_addr, ident, sizeof(ident));
125   dpl_assert_str_eq(ident, "192.168.1.1");
126   dpl_assert_int_eq(addrp->port, 4244);
127 
128   r = dpl_addrlist_get_nth(addrlist, 347, &addrp);
129   dpl_assert_ptr_not_null(addrp);
130   dpl_assert_str_eq(addrp->host, "192.168.1.1");
131   dpl_assert_str_eq(addrp->portstr, "4244");
132   dpl_assert_ptr_not_null(addrp->h);
133   dpl_assert_int_eq(addrp->h->h_addrtype, AF_INET);
134   inet_ntop(addrp->h->h_addrtype, addrp->h->h_addr, ident, sizeof(ident));
135   dpl_assert_str_eq(ident, "192.168.1.1");
136   dpl_assert_int_eq(addrp->port, 4244);
137 
138   /* verify the string form of the addrlist */
139   s = dpl_addrlist_get(addrlist);
140   dpl_assert_str_eq(s, "192.168.1.1:4244");
141 
142   free(s);
143   dpl_addrlist_free(addrlist);
144 }
145 END_TEST
146 
START_TEST(create_from_str_3_test)147 START_TEST(create_from_str_3_test)
148 {
149   dpl_addrlist_t* addrlist;
150   dpl_addr_t* addrp = NULL;
151   dpl_status_t r;
152   int i;
153   char *s, ident[INET_ADDRSTRLEN];
154   int port_position[3] = {0, 0, 0};
155   int port_counts[3] = {0, 0, 0};
156   char expstr[256] = "";
157 
158   /* create the addrlist */
159   addrlist = dpl_addrlist_create_from_str(
160       "4244", "192.168.1.1:4242,192.168.1.2:4243,192.168.1.3");
161   dpl_assert_ptr_not_null(addrlist);
162 
163   /* verify length */
164   dpl_assert_int_eq(3, dpl_addrlist_count(addrlist));
165 
166   /* verify getting elements by index */
167   /* indexes wrap modulo the count */
168 
169   for (i = 0; i < 12; i++) {
170     r = dpl_addrlist_get_nth(addrlist, i, &addrp);
171     dpl_assert_int_eq(DPL_SUCCESS, r);
172     dpl_assert_ptr_not_null(addrp);
173     dpl_assert_ptr_not_null(addrp->h);
174 
175     fail_unless(addrp->port >= 4242, NULL);
176     fail_unless(addrp->port <= 4244, NULL);
177 
178     inet_ntop(addrp->h->h_addrtype, addrp->h->h_addr, ident, sizeof(ident));
179 
180     if (addrp->port == 4242) {
181       dpl_assert_str_eq(addrp->host, "192.168.1.1");
182       dpl_assert_str_eq(addrp->portstr, "4242");
183       dpl_assert_str_eq(ident, "192.168.1.1");
184       port_counts[0]++;
185     } else if (addrp->port == 4243) {
186       dpl_assert_str_eq(addrp->host, "192.168.1.2");
187       dpl_assert_str_eq(addrp->portstr, "4243");
188       dpl_assert_str_eq(ident, "192.168.1.2");
189       port_counts[1]++;
190     } else /* 4244 */
191     {
192       dpl_assert_str_eq(addrp->host, "192.168.1.3");
193       dpl_assert_str_eq(addrp->portstr, "4244");
194       dpl_assert_str_eq(ident, "192.168.1.3");
195       port_counts[2]++;
196     }
197 
198     if (port_position[i % 3])
199       dpl_assert_int_eq(port_position[i % 3], addrp->port);
200     else
201       port_position[i % 3] = addrp->port;
202   }
203   dpl_assert_int_eq(port_counts[0], 4);
204   dpl_assert_int_eq(port_counts[1], 4);
205   dpl_assert_int_eq(port_counts[2], 4);
206 
207   /* verify the string form of the addrlist */
208   /* this is tough because the list is randomised internally */
209 
210   for (i = 0; i < 3; i++) {
211     if (i) strcat(expstr, ",");
212     if (port_position[i] == 4242)
213       strcat(expstr, "192.168.1.1:4242");
214     else if (port_position[i] == 4243)
215       strcat(expstr, "192.168.1.2:4243");
216     else if (port_position[i] == 4244)
217       strcat(expstr, "192.168.1.3:4244");
218   }
219 
220   s = dpl_addrlist_get(addrlist);
221   dpl_assert_str_eq(s, expstr);
222 
223   free(s);
224   dpl_addrlist_free(addrlist);
225 }
226 END_TEST
227 
228 /* Return a "host:port" pair for the i'th address in the addrlist */
get_nth(dpl_addrlist_t * addrlist,int i)229 static char* get_nth(dpl_addrlist_t* addrlist, int i)
230 {
231   dpl_addr_t* addrp = NULL;
232   dpl_status_t r;
233   char* addr;
234 
235   r = dpl_addrlist_get_nth(addrlist, i, &addrp);
236   dpl_assert_int_eq(DPL_SUCCESS, r);
237   dpl_assert_ptr_not_null(addrp);
238   dpl_assert_ptr_not_null(addrp->h);
239 
240   addr = malloc(DPL_ADDR_IDENT_STRLEN);
241   dpl_assert_ptr_not_null(addr);
242 
243   return dpl_addr_get_ident(addrp->h, addrp->port, addr, DPL_ADDR_IDENT_STRLEN);
244 }
245 
compare_addrs(const void * va,const void * vb)246 static int compare_addrs(const void* va, const void* vb)
247 {
248   return strcmp(*(const char**)va, *(const char**)vb);
249 }
250 
discover_traversible(dpl_addrlist_t * addrlist)251 static char* discover_traversible(dpl_addrlist_t* addrlist)
252 {
253   int n;
254   int i;
255   int j;
256   char* s;
257   dpl_status_t r;
258   char* addr;
259 #define MAXADDRS 32
260   int naddrs = 0;
261   char* addrs[MAXADDRS];
262 
263   n = dpl_addrlist_count(addrlist);
264   for (i = 0; i < n; i++) {
265     addr = get_nth(addrlist, i);
266 
267     for (j = 0; j < naddrs; j++) {
268       if (!strcmp(addr, addrs[j])) break;
269     }
270     if (j == naddrs) {
271       dpl_assert_int_ne(naddrs, MAXADDRS);
272       addrs[naddrs++] = addr;
273     } else
274       free(addr);
275   }
276 
277   /* sort the results into a predictable order */
278   qsort(addrs, naddrs, sizeof(char*), compare_addrs);
279 
280   /* concatenate the strings into one big one */
281   n = 0;
282   for (i = 0; i < naddrs; i++) n += strlen(addrs[i]) + 1;
283 
284   s = malloc(n);
285   dpl_assert_ptr_not_null(s);
286   s[0] = '\0';
287 
288   for (i = 0; i < naddrs; i++) {
289     if (i) strcat(s, ",");
290     strcat(s, addrs[i]);
291     free(addrs[i]);
292   }
293 
294   return s;
295 }
296 
297 
START_TEST(blacklist_test)298 START_TEST(blacklist_test)
299 {
300   dpl_addrlist_t* addrlist;
301   dpl_status_t r;
302   const char* exp;
303   char* act;
304 #define PORT "80"
305 #define ADDR1_H "192.168.1.1"
306 #define ADDR1 ADDR1_H ":" PORT
307 #define ADDR2_H "192.168.1.2"
308 #define ADDR2 ADDR2_H ":" PORT
309 #define ADDR3_H "192.168.1.3"
310 #define ADDR3 ADDR3_H ":" PORT
311 
312   /* create the addrlist */
313   addrlist = dpl_addrlist_create_from_str(NULL, ADDR1 "," ADDR2 "," ADDR3);
314   dpl_assert_ptr_not_null(addrlist);
315   dpl_assert_int_eq(3, dpl_addrlist_count(addrlist));
316   exp = ADDR1 "," ADDR2 "," ADDR3;
317   act = discover_traversible(addrlist);
318   dpl_assert_str_eq(exp, act);
319   free(act);
320 
321   /* attempting to blacklist an unknown address fails safely */
322   r = dpl_addrlist_blacklist(addrlist, "192.168.1.32", PORT, 30 /*seconds*/);
323   dpl_assert_int_eq(DPL_ENOENT, r);
324   dpl_assert_int_eq(3, dpl_addrlist_count(addrlist));
325   exp = ADDR1 "," ADDR2 "," ADDR3;
326   act = discover_traversible(addrlist);
327   dpl_assert_str_eq(exp, act);
328   free(act);
329 
330   /* blacklisting an address succeeds and makes the address untraversible */
331   r = dpl_addrlist_blacklist(addrlist, ADDR2_H, PORT, 30 /*seconds*/);
332   dpl_assert_int_eq(DPL_SUCCESS, r);
333   /* note - count includes non-traversible addresses */
334   dpl_assert_int_eq(3, dpl_addrlist_count(addrlist));
335   act = discover_traversible(addrlist);
336   exp = ADDR1 "," ADDR3;
337   dpl_assert_str_eq(exp, act);
338   free(act);
339 
340   /* blacklisting the same address again is a no-op (well not
341    * quite but close enough). */
342   r = dpl_addrlist_blacklist(addrlist, ADDR2_H, PORT, 30 /*seconds*/);
343   dpl_assert_int_eq(DPL_SUCCESS, r);
344   dpl_assert_int_eq(3, dpl_addrlist_count(addrlist));
345   act = discover_traversible(addrlist);
346   exp = ADDR1 "," ADDR3;
347   dpl_assert_str_eq(exp, act);
348   free(act);
349 
350   /* un-blacklisting the address makes it traversible again */
351   r = dpl_addrlist_unblacklist(addrlist, ADDR2_H, PORT);
352   dpl_assert_int_eq(DPL_SUCCESS, r);
353   dpl_assert_int_eq(3, dpl_addrlist_count(addrlist));
354   act = discover_traversible(addrlist);
355   exp = ADDR1 "," ADDR2 "," ADDR3;
356   dpl_assert_str_eq(exp, act);
357   free(act);
358 
359   /* attempting to un-blacklist an unknown address fails safely */
360   r = dpl_addrlist_unblacklist(addrlist, "192.168.1.32", PORT);
361   dpl_assert_int_eq(DPL_ENOENT, r);
362   dpl_assert_int_eq(3, dpl_addrlist_count(addrlist));
363   act = discover_traversible(addrlist);
364   exp = ADDR1 "," ADDR2 "," ADDR3;
365   dpl_assert_str_eq(exp, act);
366   free(act);
367 
368   dpl_addrlist_free(addrlist);
369 #undef ADDR1_H
370 #undef ADDR1
371 #undef ADDR2_H
372 #undef ADDR2
373 #undef ADDR3_H
374 #undef ADDR3
375 #undef PORT
376 }
377 END_TEST
378 
timeval_to_usec(const struct timeval * a)379 static uint64_t timeval_to_usec(const struct timeval* a)
380 {
381   return a->tv_sec * 1000000 + a->tv_usec;
382 }
383 
elapsed_usec(const struct timeval * start)384 static uint64_t elapsed_usec(const struct timeval* start)
385 {
386   struct timeval now;
387   gettimeofday(&now, NULL);
388   return timeval_to_usec(&now) - timeval_to_usec(start);
389 }
390 
391 #define SECONDS (1000000)   /* in microseconds */
392 #define MILLISECONDS (1000) /* in microseconds */
393 
394 /*
395  * Test that blacklisting is effective for a limited time period.
396  * Note that <check.h> provides no facility for doing time warps
397  * in the test process so we have to actually sleep.
398  */
START_TEST(blacklist_timeout_test)399 START_TEST(blacklist_timeout_test)
400 {
401   dpl_addrlist_t* addrlist;
402   unsigned long elapsed;
403   dpl_status_t r;
404   const char* exp;
405   char* act;
406   struct timeval start;
407 #define PORT "80"
408 #define ADDR1_H "192.168.1.1"
409 #define ADDR1 ADDR1_H ":" PORT
410 #define ADDR2_H "192.168.1.2"
411 #define ADDR2 ADDR2_H ":" PORT
412 #define ADDR3_H "192.168.1.3"
413 #define ADDR3 ADDR3_H ":" PORT
414 
415   /* create the addrlist */
416   addrlist = dpl_addrlist_create_from_str(NULL, ADDR1 "," ADDR2 "," ADDR3);
417   dpl_assert_ptr_not_null(addrlist);
418   dpl_assert_int_eq(3, dpl_addrlist_count(addrlist));
419   exp = ADDR1 "," ADDR2 "," ADDR3;
420   act = discover_traversible(addrlist);
421   dpl_assert_str_eq(exp, act);
422   free(act);
423 
424   /* blacklisting an address succeeds */
425   gettimeofday(&start, NULL);
426   r = dpl_addrlist_blacklist(addrlist, ADDR2_H, PORT, 2 /*seconds*/);
427   dpl_assert_int_eq(DPL_SUCCESS, r);
428 
429   while (elapsed_usec(&start) < 1 * SECONDS) {
430     //       fprintf(stderr, "elapsed: %lu usec\n", elapsed_usec(&start));
431     //       fflush(stderr);
432     /* address is not traversible before expiry */
433     dpl_assert_int_eq(3, dpl_addrlist_count(addrlist));
434     act = discover_traversible(addrlist);
435     exp = ADDR1 "," ADDR3;
436     dpl_assert_str_eq(exp, act);
437     free(act);
438 
439     usleep(100 * MILLISECONDS);
440   }
441 
442   /* sleep a little more to make sure we're over the expiry */
443   usleep(1500 * MILLISECONDS);
444 
445   /* address is traversible again after expiry */
446   dpl_assert_int_eq(3, dpl_addrlist_count(addrlist));
447   act = discover_traversible(addrlist);
448   exp = ADDR1 "," ADDR2 "," ADDR3;
449   dpl_assert_str_eq(exp, act);
450   free(act);
451 
452   dpl_addrlist_free(addrlist);
453 #undef ADDR1_H
454 #undef ADDR1
455 #undef ADDR2_H
456 #undef ADDR2
457 #undef ADDR3_H
458 #undef ADDR3
459 #undef PORT
460 }
461 END_TEST
462 
463 /* Passing addrlist=null to various functions fails cleanly */
START_TEST(null_test)464 START_TEST(null_test)
465 {
466   dpl_addr_t* addrp = NULL;
467   char* s;
468 
469   /* dpl_addrlist_get() has an odd return for this corner case, but whatever */
470   s = dpl_addrlist_get(NULL);
471   dpl_assert_str_eq(s, "");
472   free(s);
473 
474   dpl_assert_int_eq(0, dpl_addrlist_count(NULL));
475   dpl_addrlist_free(NULL);
476   dpl_assert_int_eq(DPL_FAILURE,
477                     dpl_addrlist_blacklist(NULL, "192.168.1.32", "80", 30));
478   dpl_assert_int_eq(DPL_FAILURE,
479                     dpl_addrlist_unblacklist(NULL, "192.168.1.32", "80"));
480   dpl_assert_int_eq(DPL_FAILURE,
481                     dpl_addrlist_set_from_str(NULL, "192.168.1.32"));
482   dpl_assert_ptr_null(dpl_addrlist_create_from_str(NULL, NULL));
483   dpl_addrlist_lock(NULL);
484   dpl_addrlist_unlock(NULL);
485   dpl_assert_int_eq(DPL_ENOENT, dpl_addrlist_get_nth(NULL, 1, &addrp));
486   dpl_assert_int_eq(DPL_FAILURE, dpl_addrlist_add(NULL, "192.168.1.32", "80"));
487 }
488 END_TEST
489 
490 
addrlist_suite(void)491 Suite* addrlist_suite(void)
492 {
493   Suite* s = suite_create("addrlist");
494   TCase* t = tcase_create("base");
495   tcase_add_test(t, empty_test);
496   tcase_add_test(t, default_default_port_test);
497   tcase_add_test(t, multiple_add_test);
498   tcase_add_test(t, create_from_str_1_test);
499   tcase_add_test(t, create_from_str_3_test);
500   tcase_add_test(t, blacklist_test);
501   tcase_add_test(t, blacklist_timeout_test);
502   tcase_add_test(t, null_test);
503   suite_add_tcase(s, t);
504   return s;
505 }
506