You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rspamd_upstream_test.c 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * Copyright (c) 2014, Vsevolod Stakhov
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions are met:
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. *
  14. * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
  15. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  18. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "config.h"
  26. #include "rspamd.h"
  27. #include "ottery.h"
  28. #include <math.h>
  29. const char *test_upstream_list = "microsoft.com:443:1,google.com:80:2,kernel.org:443:3";
  30. const char *new_upstream_list = "freebsd.org:80";
  31. char test_key[32];
  32. static void
  33. rspamd_upstream_test_method (struct upstream_list *ls,
  34. enum rspamd_upstream_rotation rot, const gchar *expected)
  35. {
  36. struct upstream *up;
  37. if (rot != RSPAMD_UPSTREAM_HASHED) {
  38. up = rspamd_upstream_get (ls, rot, NULL, 0);
  39. g_assert (up != NULL);
  40. g_assert (strcmp (rspamd_upstream_name (up), expected) == 0);
  41. }
  42. else {
  43. up = rspamd_upstream_get (ls, RSPAMD_UPSTREAM_HASHED, test_key,
  44. sizeof (test_key));
  45. g_assert (up != NULL);
  46. g_assert (strcmp (rspamd_upstream_name (up), expected) == 0);
  47. }
  48. }
  49. static void
  50. rspamd_upstream_timeout_handler (int fd, short what, void *arg)
  51. {
  52. struct rspamd_dns_resolver *resolver = (struct rspamd_dns_resolver *)arg;
  53. rdns_resolver_release (resolver->r);
  54. }
  55. void
  56. rspamd_upstream_test_func (void)
  57. {
  58. struct upstream_list *ls, *nls;
  59. struct upstream *up, *upn;
  60. struct event_base *ev_base = event_init ();
  61. struct rspamd_dns_resolver *resolver;
  62. struct rspamd_config *cfg;
  63. gint i, success = 0;
  64. const gint assumptions = 100500;
  65. gdouble p;
  66. struct event ev;
  67. struct timeval tv;
  68. rspamd_inet_addr_t *addr, *next_addr, *paddr;
  69. cfg = rspamd_config_new ();
  70. cfg->dns_retransmits = 2;
  71. cfg->dns_timeout = 0.5;
  72. cfg->upstream_max_errors = 1;
  73. cfg->upstream_revive_time = 0.5;
  74. cfg->upstream_error_time = 2;
  75. resolver = dns_resolver_init (NULL, ev_base, cfg);
  76. rspamd_upstreams_library_config (cfg, cfg->ups_ctx, ev_base, resolver->r);
  77. /*
  78. * Test v4/v6 priorities
  79. */
  80. nls = rspamd_upstreams_create (cfg->ups_ctx);
  81. g_assert (rspamd_upstreams_add_upstream (nls, "127.0.0.1", 0, NULL));
  82. up = rspamd_upstream_get (nls, RSPAMD_UPSTREAM_RANDOM, NULL, 0);
  83. rspamd_parse_inet_address (&paddr, "127.0.0.2", 0);
  84. g_assert (rspamd_upstream_add_addr (up, paddr));
  85. rspamd_parse_inet_address (&paddr, "::1", 0);
  86. g_assert (rspamd_upstream_add_addr (up, paddr));
  87. /* Rewind to start */
  88. addr = rspamd_upstream_addr (up);
  89. addr = rspamd_upstream_addr (up);
  90. /* cur should be zero here */
  91. addr = rspamd_upstream_addr (up);
  92. next_addr = rspamd_upstream_addr (up);
  93. g_assert (rspamd_inet_address_get_af (addr) == AF_INET);
  94. g_assert (rspamd_inet_address_get_af (next_addr) == AF_INET);
  95. next_addr = rspamd_upstream_addr (up);
  96. g_assert (rspamd_inet_address_get_af (next_addr) == AF_INET6);
  97. next_addr = rspamd_upstream_addr (up);
  98. g_assert (rspamd_inet_address_get_af (next_addr) == AF_INET);
  99. next_addr = rspamd_upstream_addr (up);
  100. g_assert (rspamd_inet_address_get_af (next_addr) == AF_INET);
  101. next_addr = rspamd_upstream_addr (up);
  102. g_assert (rspamd_inet_address_get_af (next_addr) == AF_INET6);
  103. /* Test errors with IPv6 */
  104. rspamd_upstream_fail (up);
  105. /* Now we should have merely IPv4 addresses in rotation */
  106. addr = rspamd_upstream_addr (up);
  107. for (i = 0; i < 256; i++) {
  108. next_addr = rspamd_upstream_addr (up);
  109. g_assert (rspamd_inet_address_get_af (addr) == AF_INET);
  110. g_assert (rspamd_inet_address_get_af (next_addr) == AF_INET);
  111. g_assert (rspamd_inet_address_compare (addr, next_addr) != 0);
  112. addr = next_addr;
  113. }
  114. rspamd_upstreams_destroy (nls);
  115. ls = rspamd_upstreams_create (cfg->ups_ctx);
  116. g_assert (rspamd_upstreams_parse_line (ls, test_upstream_list, 443, NULL));
  117. g_assert (rspamd_upstreams_count (ls) == 3);
  118. /* Test master-slave rotation */
  119. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_MASTER_SLAVE, "kernel.org");
  120. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_MASTER_SLAVE, "kernel.org");
  121. /* Test round-robin rotation */
  122. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "kernel.org");
  123. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "kernel.org");
  124. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "google.com");
  125. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "kernel.org");
  126. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "google.com");
  127. rspamd_upstream_test_method (ls, RSPAMD_UPSTREAM_ROUND_ROBIN, "microsoft.com");
  128. /* Test stable hashing */
  129. nls = rspamd_upstreams_create (cfg->ups_ctx);
  130. g_assert (rspamd_upstreams_parse_line (nls, test_upstream_list, 443, NULL));
  131. g_assert (rspamd_upstreams_parse_line (nls, new_upstream_list, 443, NULL));
  132. for (i = 0; i < assumptions; i ++) {
  133. ottery_rand_bytes (test_key, sizeof (test_key));
  134. up = rspamd_upstream_get (ls, RSPAMD_UPSTREAM_HASHED, test_key,
  135. sizeof (test_key));
  136. upn = rspamd_upstream_get (nls, RSPAMD_UPSTREAM_HASHED, test_key,
  137. sizeof (test_key));
  138. if (strcmp (rspamd_upstream_name (up), rspamd_upstream_name (upn)) == 0) {
  139. success ++;
  140. }
  141. }
  142. p = 1.0 - fabs (3.0 / 4.0 - (gdouble)success / (gdouble)assumptions);
  143. /*
  144. * P value is calculated as following:
  145. * when we add/remove M upstreams from the list, the probability of hash
  146. * miss should be close to the relation N / (N + M), where N is the size of
  147. * the previous upstreams list.
  148. */
  149. msg_debug ("p value for hash consistency: %.6f", p);
  150. g_assert (p > 0.9);
  151. rspamd_upstreams_destroy (nls);
  152. /* Upstream fail test */
  153. evtimer_set (&ev, rspamd_upstream_timeout_handler, resolver);
  154. event_base_set (ev_base, &ev);
  155. up = rspamd_upstream_get (ls, RSPAMD_UPSTREAM_MASTER_SLAVE, NULL, 0);
  156. for (i = 0; i < 100; i ++) {
  157. rspamd_upstream_fail (up);
  158. }
  159. g_assert (rspamd_upstreams_alive (ls) == 2);
  160. tv.tv_sec = 2;
  161. tv.tv_usec = 0;
  162. event_add (&ev, &tv);
  163. event_base_loop (ev_base, 0);
  164. g_assert (rspamd_upstreams_alive (ls) == 3);
  165. rspamd_upstreams_destroy (ls);
  166. REF_RELEASE (cfg);
  167. }