PageRenderTime 30ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/test/integration/security.py

https://github.com/gsliepen/tinc
Python | 130 lines | 116 code | 10 blank | 4 comment | 5 complexity | ee0692b6b22d7af0c8886f90766fb18b MD5 | raw file
  1. #!/usr/bin/env python3
  2. """Test tinc protocol security."""
  3. import asyncio
  4. import typing as T
  5. from testlib import check
  6. from testlib.log import log
  7. from testlib.proc import Tinc, Script
  8. from testlib.test import Test
  9. from testlib.feature import SANDBOX_LEVEL
  10. TIMEOUT = 2
  11. async def recv(read: asyncio.StreamReader, out: T.List[bytes]) -> None:
  12. """Receive data until connection is closed."""
  13. while not read.at_eof():
  14. rec = await read.read(1)
  15. out.append(rec)
  16. async def send(port: int, buf: str, delay: float = 0) -> bytes:
  17. """Send data and receive response."""
  18. raw = f"{buf}\n".encode("utf-8")
  19. read, write = await asyncio.open_connection(host="localhost", port=port)
  20. if delay:
  21. await asyncio.sleep(delay)
  22. received: T.List[bytes] = []
  23. try:
  24. write.write(raw)
  25. await asyncio.wait_for(recv(read, received), timeout=1)
  26. except asyncio.TimeoutError:
  27. log.info('received: "%s"', received)
  28. return b"".join(received)
  29. raise RuntimeError("test should not have reached this line")
  30. async def test_id_timeout(foo: Tinc) -> None:
  31. """Test that peer does not send its ID before us."""
  32. log.info("no ID sent by peer if we don't send ID before the timeout")
  33. data = await send(foo.port, "0 bar 17.7", delay=TIMEOUT * 1.5)
  34. check.false(data)
  35. async def test_tarpitted(foo: Tinc) -> None:
  36. """Test that peer sends its ID if we send first and are in tarpit."""
  37. log.info("ID sent if initiator sends first, but still tarpitted")
  38. data = await send(foo.port, "0 bar 17.7")
  39. check.has_prefix(data, f"0 {foo} 17.7".encode("utf-8"))
  40. async def test_invalid_id_own(foo: Tinc) -> None:
  41. """Test that peer does not accept its own ID."""
  42. log.info("own ID not allowed")
  43. data = await send(foo.port, f"0 {foo} 17.7")
  44. check.false(data)
  45. async def test_invalid_id_unknown(foo: Tinc) -> None:
  46. """Test that peer does not accept unknown ID."""
  47. log.info("no unknown IDs allowed")
  48. data = await send(foo.port, "0 baz 17.7")
  49. check.false(data)
  50. async def test_null_metakey(foo: Tinc) -> None:
  51. """Test that NULL metakey is not accepted."""
  52. null_metakey = f"""
  53. 0 {foo} 17.0\
  54. 1 0 672 0 0 834188619F4D943FD0F4B1336F428BD4AC06171FEABA66BD2356BC9593F0ECD643F\
  55. 0E4B748C670D7750DFDE75DC9F1D8F65AB1026F5ED2A176466FBA4167CC567A2085ABD070C1545B\
  56. 180BDA86020E275EA9335F509C57786F4ED2378EFFF331869B856DDE1C05C461E4EECAF0E2FB97A\
  57. F77B7BC2AD1B34C12992E45F5D1254BBF0C3FB224ABB3E8859594A83B6CA393ED81ECAC9221CE6B\
  58. C71A727BCAD87DD80FC0834B87BADB5CB8FD3F08BEF90115A8DF1923D7CD9529729F27E1B8ABD83\
  59. C4CF8818AE10257162E0057A658E265610B71F9BA4B365A20C70578FAC65B51B91100392171BA12\
  60. A440A5E93C4AA62E0C9B6FC9B68F953514AAA7831B4B2C31C4
  61. """.strip()
  62. log.info("no NULL METAKEY allowed")
  63. data = await send(foo.port, null_metakey)
  64. check.false(data)
  65. def init(ctx: Test) -> Tinc:
  66. """Initialize new test nodes."""
  67. foo = ctx.node()
  68. stdin = f"""
  69. init {foo}
  70. set Port 0
  71. set DeviceType dummy
  72. set Address localhost
  73. set PingTimeout {TIMEOUT}
  74. set AutoConnect no
  75. set Subnet 10.96.96.1
  76. set Sandbox {SANDBOX_LEVEL}
  77. """
  78. foo.cmd(stdin=stdin)
  79. foo.add_script(Script.SUBNET_UP)
  80. foo.start()
  81. foo[Script.SUBNET_UP].wait()
  82. return foo
  83. async def run_tests(ctx: Test) -> None:
  84. """Run all tests."""
  85. foo = init(ctx)
  86. log.info("getting into tarpit")
  87. await test_id_timeout(foo)
  88. log.info("starting other tests")
  89. await asyncio.gather(
  90. test_invalid_id_own(foo),
  91. test_invalid_id_unknown(foo),
  92. test_null_metakey(foo),
  93. )
  94. loop = asyncio.get_event_loop()
  95. with Test("security") as context:
  96. loop.run_until_complete(run_tests(context))