test_pcap_comparator.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. #!/usr/bin/python3
  2. import sys, os
  3. import subprocess, shlex
  4. import time
  5. import unittest
  6. import random
  7. import scapy.all
  8. from TestUtil import PcapComparator, ID2TExecution
  9. # this dictionary holds the generators (functions) for the parameters
  10. # that will be passed to the MembershipMgmtCommAttack
  11. # items need the parameter-name as key and a function that will be called
  12. # without parameters and returns a valid value for that parameter as value
  13. # WARNING: parameters will be passed via command line, make sure your values
  14. # get converted to string correctly
  15. _random_bool = lambda: random.random() < 0.5
  16. ID2T_PARAMETER_GENERATORS = {
  17. "bots.count": lambda: random.randint(3, 6),
  18. # "file.csv":,
  19. # "file.xml":,
  20. "hidden_mark": _random_bool,
  21. # "interval.selection.end":,
  22. # "interval.selection.start":,
  23. # "interval.selection.strategy":,
  24. # "ip.reuse.external":,
  25. # "ip.reuse.local":,
  26. # "ip.reuse.total":,
  27. "multiport": _random_bool,
  28. "nat.present": _random_bool,
  29. "packet.padding": lambda: random.randint(0, 100),
  30. "packets.limit": lambda: random.randint(50, 150),
  31. "packets.per-second": lambda: random.randint(1000, 2000) / 100,
  32. "ttl.from.caida": _random_bool,
  33. }
  34. class PcapComparison(unittest.TestCase):
  35. ID2T_PATH = ".."
  36. ID2T_LOCATION = ID2T_PATH + "/" + "id2t"
  37. NUM_ITERATIONS_PER_PARAMS = 3
  38. NUM_ITERATIONS = 5
  39. PCAP_ENVIRONMENT_VALUE = "ID2T_SRC_PCAP"
  40. SEED_ENVIRONMENT_VALUE = "ID2T_SEED"
  41. DEFAULT_PCAP = "resources/telnet-raw.pcap"
  42. DEFAULT_SEED = "42"
  43. def __init__(self, *args, **kwargs):
  44. unittest.TestCase.__init__(self, *args, **kwargs)
  45. # params to call id2t with, as a list[list[str]]
  46. # do a round of testing for each list[str] we get
  47. # if none generate some params itself
  48. self.id2t_params = None
  49. def set_id2t_params(self, params: "list[list[str]]"):
  50. self.id2t_params = params
  51. def setUp(self):
  52. self.executions = []
  53. def test_determinism(self):
  54. input_pcap = os.environ.get(self.PCAP_ENVIRONMENT_VALUE, self.DEFAULT_PCAP)
  55. seed = os.environ.get(self.SEED_ENVIRONMENT_VALUE, self.DEFAULT_SEED)
  56. if self.id2t_params is None:
  57. self.id2t_params = self.random_id2t_params()
  58. for params in self.id2t_params:
  59. self.do_test_round(input_pcap, seed, params)
  60. def do_test_round(self, input_pcap, seed, additional_params):
  61. generated_pcap = None
  62. for i in range(self.NUM_ITERATIONS_PER_PARAMS):
  63. execution = ID2TExecution(input_pcap, seed=seed)
  64. self.print_warning("The command that gets executed is:", execution.get_run_command(additional_params))
  65. self.executions.append(execution)
  66. try:
  67. execution.run(additional_params)
  68. except AssertionError as e:
  69. self.print_warning(execution.get_output())
  70. self.assertEqual(execution.get_return_code(), 0, "For some reason id2t completed with an error")
  71. raise e
  72. self.print_warning(execution.get_output())
  73. pcap = execution.get_pcap_filename()
  74. if generated_pcap is not None:
  75. try:
  76. self.compare_pcaps(generated_pcap, pcap)
  77. except AssertionError as e:
  78. execution.keep_file(pcap)
  79. self.executions[-2].keep_file(generated_pcap)
  80. raise e
  81. else:
  82. generated_pcap = pcap
  83. self.print_warning()
  84. time.sleep(1) # let some time pass between calls because files are based on the time
  85. def tearDown(self):
  86. self.print_warning("Cleaning up files generated by the test-calls...")
  87. for id2t_run in self.executions:
  88. for file in id2t_run.get_files_for_deletion():
  89. self.print_warning(file)
  90. id2t_run.cleanup()
  91. self.print_warning("Done")
  92. kept = [file for file in id2t_run.get_kept_files() for id2t_run in self.executions]
  93. self.print_warning("The following files have been kept: " + ", ".join(kept))
  94. def compare_pcaps(self, one: str, other: str):
  95. PcapComparator().compare_files(self.ID2T_PATH + "/" + one, self.ID2T_PATH + "/" + other)
  96. def print_warning(self, *text):
  97. print(*text, file=sys.stderr)
  98. def random_id2t_params(self):
  99. """
  100. :return: A list of parameter-lists for id2t, useful if you want several
  101. iterations
  102. """
  103. param_list = []
  104. for i in range(self.NUM_ITERATIONS):
  105. param_list.append(self.random_id2t_param_set())
  106. return param_list
  107. def random_id2t_param_set(self):
  108. """
  109. Create a list of parameters to call the membersmgmtcommattack with
  110. :return: a list of command-line parameters
  111. """
  112. param = lambda key, val: "%s=%s" % (str(key), str(val))
  113. number_of_keys = min(random.randint(2, 5), len(ID2T_PARAMETER_GENERATORS))
  114. keys = random.sample(list(ID2T_PARAMETER_GENERATORS), number_of_keys)
  115. params = []
  116. for key in keys:
  117. generator = ID2T_PARAMETER_GENERATORS[key]
  118. params.append(param(key, generator()))
  119. return params
  120. if __name__ == "__main__":
  121. import sys
  122. # parameters for this program are interpreted as id2t-parameters
  123. id2t_args = sys.argv[1:]
  124. comparison = PcapComparison("test_determinism")
  125. if id2t_args: comparison.set_id2t_params([id2t_args])
  126. suite = unittest.TestSuite()
  127. suite.addTest(comparison)
  128. unittest.TextTestRunner().run(suite)