rdbx_driver.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. /*
  2. * rdbx_driver.c
  3. *
  4. * driver for the rdbx implementation (replay database with extended range)
  5. *
  6. * David A. McGrew
  7. * Cisco Systems, Inc.
  8. */
  9. /*
  10. *
  11. * Copyright (c) 2001-2006, Cisco Systems, Inc.
  12. * All rights reserved.
  13. *
  14. * Redistribution and use in source and binary forms, with or without
  15. * modification, are permitted provided that the following conditions
  16. * are met:
  17. *
  18. * Redistributions of source code must retain the above copyright
  19. * notice, this list of conditions and the following disclaimer.
  20. *
  21. * Redistributions in binary form must reproduce the above
  22. * copyright notice, this list of conditions and the following
  23. * disclaimer in the documentation and/or other materials provided
  24. * with the distribution.
  25. *
  26. * Neither the name of the Cisco Systems, Inc. nor the names of its
  27. * contributors may be used to endorse or promote products derived
  28. * from this software without specific prior written permission.
  29. *
  30. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  31. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  32. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  33. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  34. * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  35. * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  36. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  37. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39. * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  40. * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
  41. * OF THE POSSIBILITY OF SUCH DAMAGE.
  42. *
  43. */
  44. #include <stdio.h> /* for printf() */
  45. #include "getopt_s.h" /* for local getopt() */
  46. #include "rdbx.h"
  47. #ifdef ROC_TEST
  48. #error "rdbx_t won't work with ROC_TEST - bitmask same size as seq_median"
  49. #endif
  50. #include "ut_sim.h"
  51. err_status_t
  52. test_replay_dbx(int num_trials, unsigned long ws);
  53. double
  54. rdbx_check_adds_per_second(int num_trials, unsigned long ws);
  55. void
  56. usage(char *prog_name) {
  57. printf("usage: %s [ -t | -v ]\n", prog_name);
  58. exit(255);
  59. }
  60. int
  61. main (int argc, char *argv[]) {
  62. double rate;
  63. err_status_t status;
  64. int q;
  65. unsigned do_timing_test = 0;
  66. unsigned do_validation = 0;
  67. /* process input arguments */
  68. while (1) {
  69. q = getopt_s(argc, argv, "tv");
  70. if (q == -1)
  71. break;
  72. switch (q) {
  73. case 't':
  74. do_timing_test = 1;
  75. break;
  76. case 'v':
  77. do_validation = 1;
  78. break;
  79. default:
  80. usage(argv[0]);
  81. }
  82. }
  83. printf("rdbx (replay database w/ extended range) test driver\n"
  84. "David A. McGrew\n"
  85. "Cisco Systems, Inc.\n");
  86. if (!do_validation && !do_timing_test)
  87. usage(argv[0]);
  88. if (do_validation) {
  89. printf("testing rdbx_t (ws=128)...\n");
  90. status = test_replay_dbx(1 << 12, 128);
  91. if (status) {
  92. printf("failed\n");
  93. exit(1);
  94. }
  95. printf("passed\n");
  96. printf("testing rdbx_t (ws=1024)...\n");
  97. status = test_replay_dbx(1 << 12, 1024);
  98. if (status) {
  99. printf("failed\n");
  100. exit(1);
  101. }
  102. printf("passed\n");
  103. }
  104. if (do_timing_test) {
  105. rate = rdbx_check_adds_per_second(1 << 18, 128);
  106. printf("rdbx_check/replay_adds per second (ws=128): %e\n", rate);
  107. rate = rdbx_check_adds_per_second(1 << 18, 1024);
  108. printf("rdbx_check/replay_adds per second (ws=1024): %e\n", rate);
  109. }
  110. return 0;
  111. }
  112. void
  113. print_rdbx(rdbx_t *rdbx) {
  114. char buf[2048];
  115. printf("rdbx: {%llu, %s}\n",
  116. (unsigned long long)(rdbx->index),
  117. bitvector_bit_string(&rdbx->bitmask, buf, sizeof(buf))
  118. );
  119. }
  120. /*
  121. * rdbx_check_add(rdbx, idx) checks a known-to-be-good idx against
  122. * rdbx, then adds it. if a failure is detected (i.e., the check
  123. * indicates that the value is already in rdbx) then
  124. * err_status_algo_fail is returned.
  125. *
  126. */
  127. err_status_t
  128. rdbx_check_add(rdbx_t *rdbx, uint32_t idx) {
  129. int delta;
  130. xtd_seq_num_t est;
  131. delta = index_guess(&rdbx->index, &est, idx);
  132. if (rdbx_check(rdbx, delta) != err_status_ok) {
  133. printf("replay_check failed at index %u\n", idx);
  134. return err_status_algo_fail;
  135. }
  136. /*
  137. * in practice, we'd authenticate the packet containing idx, using
  138. * the estimated value est, at this point
  139. */
  140. if (rdbx_add_index(rdbx, delta) != err_status_ok) {
  141. printf("rdbx_add_index failed at index %u\n", idx);
  142. return err_status_algo_fail;
  143. }
  144. return err_status_ok;
  145. }
  146. /*
  147. * rdbx_check_expect_failure(rdbx_t *rdbx, uint32_t idx)
  148. *
  149. * checks that a sequence number idx is in the replay database
  150. * and thus will be rejected
  151. */
  152. err_status_t
  153. rdbx_check_expect_failure(rdbx_t *rdbx, uint32_t idx) {
  154. int delta;
  155. xtd_seq_num_t est;
  156. err_status_t status;
  157. delta = index_guess(&rdbx->index, &est, idx);
  158. status = rdbx_check(rdbx, delta);
  159. if (status == err_status_ok) {
  160. printf("delta: %d ", delta);
  161. printf("replay_check failed at index %u (false positive)\n", idx);
  162. return err_status_algo_fail;
  163. }
  164. return err_status_ok;
  165. }
  166. err_status_t
  167. rdbx_check_add_unordered(rdbx_t *rdbx, uint32_t idx) {
  168. int delta;
  169. xtd_seq_num_t est;
  170. err_status_t rstat;
  171. delta = index_guess(&rdbx->index, &est, idx);
  172. rstat = rdbx_check(rdbx, delta);
  173. if ((rstat != err_status_ok) && (rstat != err_status_replay_old)) {
  174. printf("replay_check_add_unordered failed at index %u\n", idx);
  175. return err_status_algo_fail;
  176. }
  177. if (rstat == err_status_replay_old) {
  178. return err_status_ok;
  179. }
  180. if (rdbx_add_index(rdbx, delta) != err_status_ok) {
  181. printf("rdbx_add_index failed at index %u\n", idx);
  182. return err_status_algo_fail;
  183. }
  184. return err_status_ok;
  185. }
  186. err_status_t
  187. test_replay_dbx(int num_trials, unsigned long ws) {
  188. rdbx_t rdbx;
  189. uint32_t idx, ircvd;
  190. ut_connection utc;
  191. err_status_t status;
  192. int num_fp_trials;
  193. status = rdbx_init(&rdbx, ws);
  194. if (status) {
  195. printf("replay_init failed with error code %d\n", status);
  196. exit(1);
  197. }
  198. /*
  199. * test sequential insertion
  200. */
  201. printf("\ttesting sequential insertion...");
  202. for (idx=0; idx < num_trials; idx++) {
  203. status = rdbx_check_add(&rdbx, idx);
  204. if (status)
  205. return status;
  206. }
  207. printf("passed\n");
  208. /*
  209. * test for false positives by checking all of the index
  210. * values which we've just added
  211. *
  212. * note that we limit the number of trials here, since allowing the
  213. * rollover counter to roll over would defeat this test
  214. */
  215. num_fp_trials = num_trials % 0x10000;
  216. if (num_fp_trials == 0) {
  217. printf("warning: no false positive tests performed\n");
  218. }
  219. printf("\ttesting for false positives...");
  220. for (idx=0; idx < num_fp_trials; idx++) {
  221. status = rdbx_check_expect_failure(&rdbx, idx);
  222. if (status)
  223. return status;
  224. }
  225. printf("passed\n");
  226. /* re-initialize */
  227. rdbx_dealloc(&rdbx);
  228. if (rdbx_init(&rdbx, ws) != err_status_ok) {
  229. printf("replay_init failed\n");
  230. return err_status_init_fail;
  231. }
  232. /*
  233. * test non-sequential insertion
  234. *
  235. * this test covers only fase negatives, since the values returned
  236. * by ut_next_index(...) are distinct
  237. */
  238. ut_init(&utc);
  239. printf("\ttesting non-sequential insertion...");
  240. for (idx=0; idx < num_trials; idx++) {
  241. ircvd = ut_next_index(&utc);
  242. status = rdbx_check_add_unordered(&rdbx, ircvd);
  243. if (status)
  244. return status;
  245. status = rdbx_check_expect_failure(&rdbx, ircvd);
  246. if (status)
  247. return status;
  248. }
  249. printf("passed\n");
  250. /* re-initialize */
  251. rdbx_dealloc(&rdbx);
  252. if (rdbx_init(&rdbx, ws) != err_status_ok) {
  253. printf("replay_init failed\n");
  254. return err_status_init_fail;
  255. }
  256. /*
  257. * test insertion with large gaps.
  258. * check for false positives for each insertion.
  259. */
  260. printf("\ttesting insertion with large gaps...");
  261. for (idx=0, ircvd=0; idx < num_trials; idx++, ircvd += (1 << (rand() % 12))) {
  262. status = rdbx_check_add(&rdbx, ircvd);
  263. if (status)
  264. return status;
  265. status = rdbx_check_expect_failure(&rdbx, ircvd);
  266. if (status)
  267. return status;
  268. }
  269. printf("passed\n");
  270. rdbx_dealloc(&rdbx);
  271. return err_status_ok;
  272. }
  273. #include <time.h> /* for clock() */
  274. #include <stdlib.h> /* for random() */
  275. double
  276. rdbx_check_adds_per_second(int num_trials, unsigned long ws) {
  277. uint32_t i;
  278. int delta;
  279. rdbx_t rdbx;
  280. xtd_seq_num_t est;
  281. clock_t timer;
  282. int failures; /* count number of failures */
  283. if (rdbx_init(&rdbx, ws) != err_status_ok) {
  284. printf("replay_init failed\n");
  285. exit(1);
  286. }
  287. failures = 0;
  288. timer = clock();
  289. for(i=0; i < num_trials; i++) {
  290. delta = index_guess(&rdbx.index, &est, i);
  291. if (rdbx_check(&rdbx, delta) != err_status_ok)
  292. ++failures;
  293. else
  294. if (rdbx_add_index(&rdbx, delta) != err_status_ok)
  295. ++failures;
  296. }
  297. timer = clock() - timer;
  298. printf("number of failures: %d \n", failures);
  299. rdbx_dealloc(&rdbx);
  300. return (double) CLOCKS_PER_SEC * num_trials / timer;
  301. }