test_ip.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. # Copyright (c) Twisted Matrix Laboratories.
  2. # See LICENSE for details.
  3. from twisted.trial import unittest
  4. from twisted.python import components
  5. from twisted.pair import ip, raw
  6. from zope import interface
  7. @interface.implementer(raw.IRawDatagramProtocol)
  8. class MyProtocol:
  9. def __init__(self, expecting):
  10. self.expecting = list(expecting)
  11. def datagramReceived(self, data, **kw):
  12. assert self.expecting, 'Got a packet when not expecting anymore.'
  13. expectData, expectKw = self.expecting.pop(0)
  14. expectKwKeys = expectKw.keys()
  15. expectKwKeys = list(sorted(expectKwKeys))
  16. kwKeys = kw.keys()
  17. kwKeys = list(sorted(kwKeys))
  18. assert expectKwKeys == kwKeys, "Expected %r, got %r" % (expectKwKeys, kwKeys)
  19. for k in expectKwKeys:
  20. assert expectKw[k] == kw[k], "Expected %s=%r, got %r" % (k, expectKw[k], kw[k])
  21. assert expectKw == kw, "Expected %r, got %r" % (expectKw, kw)
  22. assert expectData == data, "Expected %r, got %r" % (expectData, data)
  23. class IPTests(unittest.TestCase):
  24. def testPacketParsing(self):
  25. proto = ip.IPProtocol()
  26. p1 = MyProtocol([
  27. (b'foobar', {
  28. 'partial': 0,
  29. 'dest': '1.2.3.4',
  30. 'source': '5.6.7.8',
  31. 'protocol': 0x0F,
  32. 'version': 4,
  33. 'ihl': 20,
  34. 'tos': 7,
  35. 'tot_len': 20+6,
  36. 'fragment_id': 0xDEAD,
  37. 'fragment_offset': 0x1EEF,
  38. 'dont_fragment': 0,
  39. 'more_fragments': 1,
  40. 'ttl': 0xC0,
  41. }),
  42. ])
  43. proto.addProto(0x0F, p1)
  44. proto.datagramReceived(b"\x54" #ihl version
  45. + b"\x07" #tos
  46. + b"\x00\x1a" #tot_len
  47. + b"\xDE\xAD" #id
  48. + b"\xBE\xEF" #frag_off
  49. + b"\xC0" #ttl
  50. + b"\x0F" #protocol
  51. + b"FE" #checksum
  52. + b"\x05\x06\x07\x08"
  53. + b"\x01\x02\x03\x04"
  54. + b"foobar",
  55. partial=0,
  56. dest='dummy',
  57. source='dummy',
  58. protocol='dummy',
  59. )
  60. assert not p1.expecting, \
  61. 'Should not expect any more packets, but still want %r' % p1.expecting
  62. def testMultiplePackets(self):
  63. proto = ip.IPProtocol()
  64. p1 = MyProtocol([
  65. (b'foobar', {
  66. 'partial': 0,
  67. 'dest': '1.2.3.4',
  68. 'source': '5.6.7.8',
  69. 'protocol': 0x0F,
  70. 'version': 4,
  71. 'ihl': 20,
  72. 'tos': 7,
  73. 'tot_len': 20+6,
  74. 'fragment_id': 0xDEAD,
  75. 'fragment_offset': 0x1EEF,
  76. 'dont_fragment': 0,
  77. 'more_fragments': 1,
  78. 'ttl': 0xC0,
  79. }),
  80. (b'quux', {
  81. 'partial': 1,
  82. 'dest': '5.4.3.2',
  83. 'source': '6.7.8.9',
  84. 'protocol': 0x0F,
  85. 'version': 4,
  86. 'ihl': 20,
  87. 'tos': 7,
  88. 'tot_len': 20+6,
  89. 'fragment_id': 0xDEAD,
  90. 'fragment_offset': 0x1EEF,
  91. 'dont_fragment': 0,
  92. 'more_fragments': 1,
  93. 'ttl': 0xC0,
  94. }),
  95. ])
  96. proto.addProto(0x0F, p1)
  97. proto.datagramReceived(b"\x54" #ihl version
  98. + b"\x07" #tos
  99. + b"\x00\x1a" #tot_len
  100. + b"\xDE\xAD" #id
  101. + b"\xBE\xEF" #frag_off
  102. + b"\xC0" #ttl
  103. + b"\x0F" #protocol
  104. + b"FE" #checksum
  105. + b"\x05\x06\x07\x08"
  106. + b"\x01\x02\x03\x04"
  107. + b"foobar",
  108. partial=0,
  109. dest='dummy',
  110. source='dummy',
  111. protocol='dummy',
  112. )
  113. proto.datagramReceived(b"\x54" #ihl version
  114. + b"\x07" #tos
  115. + b"\x00\x1a" #tot_len
  116. + b"\xDE\xAD" #id
  117. + b"\xBE\xEF" #frag_off
  118. + b"\xC0" #ttl
  119. + b"\x0F" #protocol
  120. + b"FE" #checksum
  121. + b"\x06\x07\x08\x09"
  122. + b"\x05\x04\x03\x02"
  123. + b"quux",
  124. partial=1,
  125. dest='dummy',
  126. source='dummy',
  127. protocol='dummy',
  128. )
  129. assert not p1.expecting, \
  130. 'Should not expect any more packets, but still want %r' % p1.expecting
  131. def testMultipleSameProtos(self):
  132. proto = ip.IPProtocol()
  133. p1 = MyProtocol([
  134. (b'foobar', {
  135. 'partial': 0,
  136. 'dest': '1.2.3.4',
  137. 'source': '5.6.7.8',
  138. 'protocol': 0x0F,
  139. 'version': 4,
  140. 'ihl': 20,
  141. 'tos': 7,
  142. 'tot_len': 20+6,
  143. 'fragment_id': 0xDEAD,
  144. 'fragment_offset': 0x1EEF,
  145. 'dont_fragment': 0,
  146. 'more_fragments': 1,
  147. 'ttl': 0xC0,
  148. }),
  149. ])
  150. p2 = MyProtocol([
  151. (b'foobar', {
  152. 'partial': 0,
  153. 'dest': '1.2.3.4',
  154. 'source': '5.6.7.8',
  155. 'protocol': 0x0F,
  156. 'version': 4,
  157. 'ihl': 20,
  158. 'tos': 7,
  159. 'tot_len': 20+6,
  160. 'fragment_id': 0xDEAD,
  161. 'fragment_offset': 0x1EEF,
  162. 'dont_fragment': 0,
  163. 'more_fragments': 1,
  164. 'ttl': 0xC0,
  165. }),
  166. ])
  167. proto.addProto(0x0F, p1)
  168. proto.addProto(0x0F, p2)
  169. proto.datagramReceived(b"\x54" #ihl version
  170. + b"\x07" #tos
  171. + b"\x00\x1a" #tot_len
  172. + b"\xDE\xAD" #id
  173. + b"\xBE\xEF" #frag_off
  174. + b"\xC0" #ttl
  175. + b"\x0F" #protocol
  176. + b"FE" #checksum
  177. + b"\x05\x06\x07\x08"
  178. + b"\x01\x02\x03\x04"
  179. + b"foobar",
  180. partial=0,
  181. dest='dummy',
  182. source='dummy',
  183. protocol='dummy',
  184. )
  185. assert not p1.expecting, \
  186. 'Should not expect any more packets, but still want %r' % p1.expecting
  187. assert not p2.expecting, \
  188. 'Should not expect any more packets, but still want %r' % p2.expecting
  189. def testWrongProtoNotSeen(self):
  190. proto = ip.IPProtocol()
  191. p1 = MyProtocol([])
  192. proto.addProto(1, p1)
  193. proto.datagramReceived(b"\x54" #ihl version
  194. + b"\x07" #tos
  195. + b"\x00\x1a" #tot_len
  196. + b"\xDE\xAD" #id
  197. + b"\xBE\xEF" #frag_off
  198. + b"\xC0" #ttl
  199. + b"\x0F" #protocol
  200. + b"FE" #checksum
  201. + b"\x05\x06\x07\x08"
  202. + b"\x01\x02\x03\x04"
  203. + b"foobar",
  204. partial=0,
  205. dest='dummy',
  206. source='dummy',
  207. protocol='dummy',
  208. )
  209. def testDemuxing(self):
  210. proto = ip.IPProtocol()
  211. p1 = MyProtocol([
  212. (b'foobar', {
  213. 'partial': 0,
  214. 'dest': '1.2.3.4',
  215. 'source': '5.6.7.8',
  216. 'protocol': 0x0F,
  217. 'version': 4,
  218. 'ihl': 20,
  219. 'tos': 7,
  220. 'tot_len': 20+6,
  221. 'fragment_id': 0xDEAD,
  222. 'fragment_offset': 0x1EEF,
  223. 'dont_fragment': 0,
  224. 'more_fragments': 1,
  225. 'ttl': 0xC0,
  226. }),
  227. (b'quux', {
  228. 'partial': 1,
  229. 'dest': '5.4.3.2',
  230. 'source': '6.7.8.9',
  231. 'protocol': 0x0F,
  232. 'version': 4,
  233. 'ihl': 20,
  234. 'tos': 7,
  235. 'tot_len': 20+6,
  236. 'fragment_id': 0xDEAD,
  237. 'fragment_offset': 0x1EEF,
  238. 'dont_fragment': 0,
  239. 'more_fragments': 1,
  240. 'ttl': 0xC0,
  241. }),
  242. ])
  243. proto.addProto(0x0F, p1)
  244. p2 = MyProtocol([
  245. (b'quux', {
  246. 'partial': 1,
  247. 'dest': '5.4.3.2',
  248. 'source': '6.7.8.9',
  249. 'protocol': 0x0A,
  250. 'version': 4,
  251. 'ihl': 20,
  252. 'tos': 7,
  253. 'tot_len': 20+6,
  254. 'fragment_id': 0xDEAD,
  255. 'fragment_offset': 0x1EEF,
  256. 'dont_fragment': 0,
  257. 'more_fragments': 1,
  258. 'ttl': 0xC0,
  259. }),
  260. (b'foobar', {
  261. 'partial': 0,
  262. 'dest': '1.2.3.4',
  263. 'source': '5.6.7.8',
  264. 'protocol': 0x0A,
  265. 'version': 4,
  266. 'ihl': 20,
  267. 'tos': 7,
  268. 'tot_len': 20+6,
  269. 'fragment_id': 0xDEAD,
  270. 'fragment_offset': 0x1EEF,
  271. 'dont_fragment': 0,
  272. 'more_fragments': 1,
  273. 'ttl': 0xC0,
  274. }),
  275. ])
  276. proto.addProto(0x0A, p2)
  277. proto.datagramReceived(b"\x54" #ihl version
  278. + b"\x07" #tos
  279. + b"\x00\x1a" #tot_len
  280. + b"\xDE\xAD" #id
  281. + b"\xBE\xEF" #frag_off
  282. + b"\xC0" #ttl
  283. + b"\x0A" #protocol
  284. + b"FE" #checksum
  285. + b"\x06\x07\x08\x09"
  286. + b"\x05\x04\x03\x02"
  287. + b"quux",
  288. partial=1,
  289. dest='dummy',
  290. source='dummy',
  291. protocol='dummy',
  292. )
  293. proto.datagramReceived(b"\x54" #ihl version
  294. + b"\x07" #tos
  295. + b"\x00\x1a" #tot_len
  296. + b"\xDE\xAD" #id
  297. + b"\xBE\xEF" #frag_off
  298. + b"\xC0" #ttl
  299. + b"\x0F" #protocol
  300. + b"FE" #checksum
  301. + b"\x05\x06\x07\x08"
  302. + b"\x01\x02\x03\x04"
  303. + b"foobar",
  304. partial=0,
  305. dest='dummy',
  306. source='dummy',
  307. protocol='dummy',
  308. )
  309. proto.datagramReceived(b"\x54" #ihl version
  310. + b"\x07" #tos
  311. + b"\x00\x1a" #tot_len
  312. + b"\xDE\xAD" #id
  313. + b"\xBE\xEF" #frag_off
  314. + b"\xC0" #ttl
  315. + b"\x0F" #protocol
  316. + b"FE" #checksum
  317. + b"\x06\x07\x08\x09"
  318. + b"\x05\x04\x03\x02"
  319. + b"quux",
  320. partial=1,
  321. dest='dummy',
  322. source='dummy',
  323. protocol='dummy',
  324. )
  325. proto.datagramReceived(b"\x54" #ihl version
  326. + b"\x07" #tos
  327. + b"\x00\x1a" #tot_len
  328. + b"\xDE\xAD" #id
  329. + b"\xBE\xEF" #frag_off
  330. + b"\xC0" #ttl
  331. + b"\x0A" #protocol
  332. + b"FE" #checksum
  333. + b"\x05\x06\x07\x08"
  334. + b"\x01\x02\x03\x04"
  335. + b"foobar",
  336. partial=0,
  337. dest='dummy',
  338. source='dummy',
  339. protocol='dummy',
  340. )
  341. assert not p1.expecting, \
  342. 'Should not expect any more packets, but still want %r' % p1.expecting
  343. assert not p2.expecting, \
  344. 'Should not expect any more packets, but still want %r' % p2.expecting
  345. def testAddingBadProtos_WrongLevel(self):
  346. """Adding a wrong level protocol raises an exception."""
  347. e = ip.IPProtocol()
  348. try:
  349. e.addProto(42, "silliness")
  350. except components.CannotAdapt:
  351. pass
  352. else:
  353. raise AssertionError('addProto must raise an exception for bad protocols')
  354. def testAddingBadProtos_TooSmall(self):
  355. """Adding a protocol with a negative number raises an exception."""
  356. e = ip.IPProtocol()
  357. try:
  358. e.addProto(-1, MyProtocol([]))
  359. except TypeError as e:
  360. if e.args == ('Added protocol must be positive or zero',):
  361. pass
  362. else:
  363. raise
  364. else:
  365. raise AssertionError('addProto must raise an exception for bad protocols')
  366. def testAddingBadProtos_TooBig(self):
  367. """Adding a protocol with a number >=2**32 raises an exception."""
  368. e = ip.IPProtocol()
  369. try:
  370. e.addProto(2**32, MyProtocol([]))
  371. except TypeError as e:
  372. if e.args == ('Added protocol must fit in 32 bits',):
  373. pass
  374. else:
  375. raise
  376. else:
  377. raise AssertionError('addProto must raise an exception for bad protocols')
  378. def testAddingBadProtos_TooBig2(self):
  379. """Adding a protocol with a number >=2**32 raises an exception."""
  380. e = ip.IPProtocol()
  381. try:
  382. e.addProto(2**32+1, MyProtocol([]))
  383. except TypeError as e:
  384. if e.args == ('Added protocol must fit in 32 bits',):
  385. pass
  386. else:
  387. raise
  388. else:
  389. raise AssertionError('addProto must raise an exception for bad protocols')