1#!/usr/bin/python3 2 3# 4# Tests of the packet assembler/disassembler routines. 5# 6# only tests the simple packers for now. next is to test the 7# classes: Hpacker/Hunpacker, 8# Qpacker/Unpacker, then Mpacker/Munpacker 9# 10# Start doing unpleasant tests with broken data, truncations, that 11# sort of thing. 12 13import sys ; sys.path.insert(0, '..') 14import DNS 15import socket 16import unittest 17 18TestCompleted = "TestCompleted" # exc. 19 20class Int16Packing(unittest.TestCase): 21 knownValues = ( ( 10, b'\x00\n'), 22 ( 500, b'\x01\xf4' ), 23 ( 5340, b'\x14\xdc' ), 24 ( 51298, b'\xc8b'), 25 ( 65535, b'\xff\xff'), 26 ) 27 28 def test16bitPacking(self): 29 """ pack16bit should give known output for known input """ 30 for i,s in self.knownValues: 31 result = DNS.Lib.pack16bit(i) 32 self.assertEqual(s,result) 33 34 def test16bitUnpacking(self): 35 """ unpack16bit should give known output for known input """ 36 for i,s in self.knownValues: 37 result = DNS.Lib.unpack16bit(s) 38 self.assertEqual(i,result) 39 40class Int32Packing(unittest.TestCase): 41 knownValues = ( ( 10, b'\x00\x00\x00\n'), 42 ( 500, b'\x00\x00\x01\xf4' ), 43 ( 5340, b'\x00\x00\x14\xdc' ), 44 ( 51298, b'\x00\x00\xc8b'), 45 ( 65535, b'\x00\x00\xff\xff'), 46 ( 33265535, b'\x01\xfb\x97\x7f' ), 47 ( 147483647, b'\x08\xcak\xff' ), 48 ( 2147483647, b'\x7f\xff\xff\xff' ), 49 ) 50 def test32bitPacking(self): 51 """ pack32bit should give known output for known input """ 52 for i,s in self.knownValues: 53 result = DNS.Lib.pack32bit(i) 54 self.assertEqual(s,result) 55 56 def test32bitUnpacking(self): 57 """ unpack32bit should give known output for known input """ 58 for i,s in self.knownValues: 59 result = DNS.Lib.unpack32bit(s) 60 self.assertEqual(i,result) 61 62 63class IPaddrPacking(unittest.TestCase): 64 knownValues = ( 65 ('127.0.0.1', 2130706433 ), 66 ('10.99.23.13', 174266125 ), 67 ('192.35.59.45', 3223534381), # Not signed anymore - it's all long now. 68 ('255.255.255.255', 4294967295) # No longer -1 69 ) 70 71 def testIPaddrPacking(self): 72 """ addr2bin should give known output for known input """ 73 for i,s in self.knownValues: 74 result = DNS.Lib.addr2bin(i) 75 self.assertEqual(s,result) 76 77 def testIPaddrUnpacking(self): 78 """ bin2addr should give known output for known input """ 79 for i,s in self.knownValues: 80 result = DNS.Lib.bin2addr(s) 81 self.assertEqual(i,result) 82 83class PackerClassPacking(unittest.TestCase): 84 knownPackValues = [ 85 ( ['www.ekit.com'], b'\x03www\x04ekit\x03com\x00' ), 86 ( ['ns1.ekorp.com', 'ns2.ekorp.com', 'ns3.ekorp.com'], 87 b'\x03ns1\x05ekorp\x03com\x00\x03ns2\xc0\x04\x03ns3\xc0\x04'), 88 ( ['a.root-servers.net.', 'b.root-servers.net.', 89 'c.root-servers.net.', 'd.root-servers.net.', 90 'e.root-servers.net.', 'f.root-servers.net.'], 91 b'\x01a\x0croot-servers\x03net\x00\x01b\xc0\x02\x01c\xc0'+ 92 b'\x02\x01d\xc0\x02\x01e\xc0\x02\x01f\xc0\x02' ), 93 ] 94 knownUnpackValues = [ 95 ( ['www.ekit.com'], b'\x03www\x04ekit\x03com\x00' ), 96 ( ['ns1.ekorp.com', 'ns2.ekorp.com', 'ns3.ekorp.com'], 97 b'\x03ns1\x05ekorp\x03com\x00\x03ns2\xc0\x04\x03ns3\xc0\x04'), 98 ( ['a.root-servers.net', 'b.root-servers.net', 99 'c.root-servers.net', 'd.root-servers.net', 100 'e.root-servers.net', 'f.root-servers.net'], 101 b'\x01a\x0croot-servers\x03net\x00\x01b\xc0\x02\x01c\xc0'+ 102 b'\x02\x01d\xc0\x02\x01e\xc0\x02\x01f\xc0\x02' ), 103 ] 104 105 def testPackNames(self): 106 from DNS.Lib import Packer 107 for namelist,result in self.knownPackValues: 108 p = Packer() 109 for n in namelist: 110 p.addname(n) 111 self.assertEqual(p.getbuf(),result) 112 113 def testUnpackNames(self): 114 from DNS.Lib import Unpacker 115 for namelist,result in self.knownUnpackValues: 116 u = Unpacker(result) 117 names = [] 118 for i in range(len(namelist)): 119 n = u.getname() 120 names.append(n) 121 self.assertEqual(names, namelist) 122 123""" def testUnpackerLimitCheck(self): 124 # FIXME: Don't understand what this test should do. If my guess is right, 125 # then the code is working ~OK. 126 from DNS.Lib import Unpacker 127 u=Unpacker(b'\x03ns1\x05ekorp\x03com\x00\x03ns2\xc0\x04\x03ns3\xc0\x04') 128 u.getname() ; u.getname() ; u.getname() 129 # 4th call should fail 130 self.assertRaises(IndexError, u.getname)""" 131 132class testUnpackingMangled(unittest.TestCase): 133 "addA(self, name, klass, ttl, address)" 134 packerCorrect = b'\x05www02\x04ekit\x03com\x00\x00\x01\x00\x01\x00\x01Q\x80\x00\x04\xc0\xa8\n\x02' 135 def testWithoutRR(self): 136 u = DNS.Lib.RRunpacker(self.packerCorrect) 137 u.getAdata() 138 def testWithTwoRRs(self): 139 u = DNS.Lib.RRunpacker(self.packerCorrect) 140 u.getRRheader() 141 self.assertRaises(DNS.Lib.UnpackError, u.getRRheader) 142 def testWithNoGetData(self): 143 u = DNS.Lib.RRunpacker(self.packerCorrect) 144 u.getRRheader() 145 self.assertRaises(DNS.Lib.UnpackError, u.endRR) 146 147class PackerTestCase(unittest.TestCase): 148 " base class for tests of Packing code. Laziness on my part, I know. " 149 def setUp(self): 150 self.RRpacker = DNS.Lib.RRpacker 151 self.RRunpacker = DNS.Lib.RRunpacker 152 153 def testPacker(self): 154 p = self.RRpacker() 155 check = self.doPack(p) 156 if (p is not None) and (check is not TestCompleted): 157 return self.checkPackResult(p) 158 159 def checkPackResult(self, buf): 160 if not hasattr(self, 'packerExpectedResult'): 161 if self.__class__.__name__ != 'PackerTestCase': 162 print("P***", self, repr(buf.getbuf())) #cheat testcase 163 else: 164 return self.assertEqual(buf.getbuf(), 165 self.packerExpectedResult) 166 167 def checkUnpackResult(self, rrbits, specbits): 168 if not hasattr(self, 'unpackerExpectedResult'): 169 if self.__class__.__name__ != 'PackerTestCase': 170 print("U***", self, repr((rrbits,specbits))) #cheat testcase 171 else: 172 return self.assertEqual((rrbits, specbits), 173 self.unpackerExpectedResult) 174 175 def testUnpacker(self): 176 if self.doUnpack is not None: 177 if hasattr(self.__class__, 'doUnpack') \ 178 and hasattr(self, 'packerExpectedResult'): 179 u = self.RRunpacker(self.packerExpectedResult) 180 rrbits = u.getRRheader()[:4] 181 specbits = self.doUnpack(u) 182 try: 183 u.endRR() 184 except DNS.Lib.UnpackError: 185 self.assertEqual(0, 'Not at end of RR!') 186 return self.checkUnpackResult(rrbits, specbits) 187 else: 188 me = self.__class__.__name__ 189 if me != 'PackerTestCase': 190 self.assertEquals(self.__class__.__name__, 191 'Unpack NotImplemented') 192 193 def doPack(self, p): 194 " stub. don't test the base class " 195 return None 196 197 def doUnpack(self, p): 198 " stub. don't test the base class " 199 return None 200 201 202class testPackingOfCNAME(PackerTestCase): 203 "addCNAME(self, name, klass, ttl, cname)" 204 def doPack(self,p): 205 p.addCNAME('www.sub.domain', DNS.Class.IN, 3600, 'realhost.sub.domain') 206 def doUnpack(self, u): 207 return u.getCNAMEdata() 208 209 unpackerExpectedResult = (('www.sub.domain', DNS.Type.CNAME, DNS.Class.IN, 3600), 'realhost.sub.domain') 210 packerExpectedResult = \ 211 b'\x03www\x03sub\x06domain\x00\x00\x05\x00\x01\x00'+ \ 212 b'\x00\x0e\x10\x00\x0b\x08realhost\xc0\x04' 213 214class testPackingOfCNAME2(PackerTestCase): 215 "addCNAME(self, name, klass, ttl, cname)" 216 def doPack(self,p): 217 p.addCNAME('www.cust.com', DNS.Class.IN, 200, 'www023.big.isp.com') 218 def doUnpack(self, u): 219 return u.getCNAMEdata() 220 unpackerExpectedResult = (('www.cust.com', DNS.Type.CNAME, DNS.Class.IN, 200), 'www023.big.isp.com') 221 packerExpectedResult = \ 222 b'\x03www\x04cust\x03com\x00\x00\x05\x00\x01\x00'+ \ 223 b'\x00\x00\xc8\x00\x11\x06www023\x03big\x03isp\xc0\t' 224 225class testPackingOfCNAME3(PackerTestCase): 226 "addCNAME(self, name, klass, ttl, cname)" 227 def doPack(self,p): 228 p.addCNAME('www.fred.com', DNS.Class.IN, 86400, 'webhost.loa.com') 229 def doUnpack(self, u): 230 return u.getCNAMEdata() 231 unpackerExpectedResult = (('www.fred.com', DNS.Type.CNAME, DNS.Class.IN, 86400), 'webhost.loa.com') 232 packerExpectedResult = \ 233 b'\x03www\x04fred\x03com\x00\x00\x05\x00\x01\x00\x01Q'+ \ 234 b'\x80\x00\x0e\x07webhost\x03loa\xc0\t' 235 236class testPackingOfHINFO(PackerTestCase): 237 "addHINFO(self, name, klass, ttl, cpu, os)" 238 def doPack(self,p): 239 p.addHINFO('www.sub.domain.com', DNS.Class.IN, 3600, 'i686', 'linux') 240 def doUnpack(self, u): 241 return u.getHINFOdata() 242 unpackerExpectedResult = (('www.sub.domain.com', 13, 1, 3600), ('i686', 'linux')) 243 packerExpectedResult = \ 244 b'\x03www\x03sub\x06domain\x03com\x00\x00\r\x00\x01'+ \ 245 b'\x00\x00\x0e\x10\x00\x0b\x04i686\x05linux' 246 247class testPackingOfHINFO2(PackerTestCase): 248 "addHINFO(self, name, klass, ttl, cpu, os)" 249 def doPack(self,p): 250 p.addHINFO('core1.lax.foo.com', DNS.Class.IN, 3600, 'cisco', 'ios') 251 def doUnpack(self, u): 252 return u.getHINFOdata() 253 unpackerExpectedResult = (('core1.lax.foo.com', 13, 1, 3600), ('cisco', 'ios')) 254 packerExpectedResult = \ 255 b'\x05core1\x03lax\x03foo\x03com\x00\x00\r\x00\x01'+ \ 256 b'\x00\x00\x0e\x10\x00\n\x05cisco\x03ios' 257 258class testPackingOfMX(PackerTestCase): 259 "addMX(self, name, klass, ttl, preference, exchange)" 260 def doPack(self, p): 261 p.addMX('sub.domain.com', DNS.Class.IN, 86400, 10, 'mailhost1.isp.com') 262 def doUnpack(self, u): 263 return u.getMXdata() 264 packerExpectedResult = \ 265 b'\x03sub\x06domain\x03com\x00\x00\x0f\x00\x01'+ \ 266 b'\x00\x01Q\x80\x00\x12\x00\n\tmailhost1\x03isp\xc0\x0b' 267 unpackerExpectedResult = (('sub.domain.com', 15, 1, 86400), (10, 'mailhost1.isp.com')) 268 269class testPackingOfMX2(PackerTestCase): 270 "addMX(self, name, klass, ttl, preference, exchange)" 271 def doPack(self, p): 272 p.addMX('ekit-inc.com.', DNS.Class.IN, 86400, 10, 'mx1.ekorp.com') 273 p.addMX('ekit-inc.com.', DNS.Class.IN, 86400, 20, 'mx2.ekorp.com') 274 p.addMX('ekit-inc.com.', DNS.Class.IN, 86400, 30, 'mx3.ekorp.com') 275 def doUnpack(self, u): 276 res = [u.getMXdata(),] 277 dummy = u.getRRheader()[:4] 278 res += u.getMXdata() 279 dummy = u.getRRheader()[:4] 280 res += u.getMXdata() 281 return res 282 unpackerExpectedResult = (('ekit-inc.com', 15, 1, 86400), [(10, 'mx1.ekorp.com'), 20, 'mx2.ekorp.com', 30, 'mx3.ekorp.com']) 283 packerExpectedResult = \ 284 b'\x08ekit-inc\x03com\x00\x00\x0f\x00\x01\x00\x01Q\x80\x00'+\ 285 b'\x0e\x00\n\x03mx1\x05ekorp\xc0\t\x00\x00\x0f\x00\x01\x00'+\ 286 b'\x01Q\x80\x00\x08\x00\x14\x03mx2\xc0\x1e\x00\x00\x0f\x00'+\ 287 b'\x01\x00\x01Q\x80\x00\x08\x00\x1e\x03mx3\xc0\x1e' 288 289class testPackingOfNS(PackerTestCase): 290 "addNS(self, name, klass, ttl, nsdname)" 291 def doPack(self, p): 292 p.addNS('ekit-inc.com', DNS.Class.IN, 86400, 'ns1.ekorp.com') 293 def doUnpack(self, u): 294 return u.getNSdata() 295 unpackerExpectedResult = (('ekit-inc.com', 2, 1, 86400), 'ns1.ekorp.com') 296 packerExpectedResult = b'\x08ekit-inc\x03com\x00\x00\x02\x00\x01\x00\x01Q\x80\x00\x0c\x03ns1\x05ekorp\xc0\t' 297 298class testPackingOfPTR(PackerTestCase): 299 "addPTR(self, name, klass, ttl, ptrdname)" 300 def doPack(self, p): 301 p.addPTR('www.ekit-inc.com', DNS.Class.IN, 3600, 'www-real01.ekorp.com') 302 def doUnpack(self, u): 303 return u.getPTRdata() 304 unpackerExpectedResult = (('www.ekit-inc.com', 12, 1, 3600), 'www-real01.ekorp.com') 305 packerExpectedResult = b'\x03www\x08ekit-inc\x03com\x00\x00\x0c\x00\x01\x00\x00\x0e\x10\x00\x13\nwww-real01\x05ekorp\xc0\r' 306 307class testPackingOfSOA(PackerTestCase): 308 """addSOA(self, name, klass, ttl, mname, 309 rname, serial, refresh, retry, expire, minimum)""" 310 def doPack(self, p): 311 p.addSOA('ekit-inc.com', DNS.Class.IN, 3600, 'ns1.ekorp.com', 312 'hostmaster.ekit-inc.com', 2002020301, 100, 200, 300, 400) 313 def doUnpack(self, u): 314 return u.getSOAdata() 315 unpackerExpectedResult = (('ekit-inc.com', 6, 1, 3600), ('ns1.ekorp.com', 'hostmaster', ('serial', 2002020301), ('refresh ', 100, '1 minutes'), ('retry', 200, '3 minutes'), ('expire', 300, '5 minutes'), ('minimum', 400, '6 minutes'))) 316 packerExpectedResult = b'\x08ekit-inc\x03com\x00\x00\x06\x00\x01\x00\x00\x0e\x10\x00,\x03ns1\x05ekorp\xc0\t\nhostmaster\x00wTg\xcd\x00\x00\x00d\x00\x00\x00\xc8\x00\x00\x01,\x00\x00\x01\x90' 317 318 319class testPackingOfA(PackerTestCase): 320 "addA(self, name, klass, ttl, address)" 321 def doPack(self, p): 322 p.addA('www02.ekit.com', DNS.Class.IN, 86400, '192.168.10.2') 323 def doUnpack(self, u): 324 return u.getAdata() 325 unpackerExpectedResult = (('www02.ekit.com', 1, 1, 86400), '192.168.10.2') 326 packerExpectedResult = b'\x05www02\x04ekit\x03com\x00\x00\x01\x00\x01\x00\x01Q\x80\x00\x04\xc0\xa8\n\x02' 327 328class testPackingOfA2(PackerTestCase): 329 "addA(self, name, ttl, address)" 330 def doPack(self, p): 331 p.addA('www.ekit.com', DNS.Class.IN, 86400, '10.98.1.0') 332 def doUnpack(self, u): 333 return u.getAdata() 334 unpackerExpectedResult = (('www.ekit.com', 1, 1, 86400), '10.98.1.0') 335 packerExpectedResult = b'\x03www\x04ekit\x03com\x00\x00\x01\x00\x01\x00\x01Q\x80\x00\x04\nb\x01\x00' 336 337class testPackingOfA3(PackerTestCase): 338 "addA(self, name, ttl, address)" 339 def doPack(self, p): 340 p.addA('www.zol.com', DNS.Class.IN, 86400, '192.168.10.4') 341 p.addA('www.zol.com', DNS.Class.IN, 86400, '192.168.10.3') 342 p.addA('www.zol.com', DNS.Class.IN, 86400, '192.168.10.2') 343 p.addA('www.zol.com', DNS.Class.IN, 86400, '192.168.10.1') 344 def doUnpack(self, u): 345 u1,d1,u2,d2,u3,d3,u4=u.getAdata(),u.getRRheader(),u.getAdata(),u.getRRheader(),u.getAdata(),u.getRRheader(),u.getAdata() 346 return u1,u2,u3,u4 347 unpackerExpectedResult = (('www.zol.com', 1, 1, 86400), ('192.168.10.4', '192.168.10.3', '192.168.10.2', '192.168.10.1')) 348 packerExpectedResult = b'\x03www\x03zol\x03com\x00\x00\x01\x00\x01\x00\x01Q\x80\x00\x04\xc0\xa8\n\x04\x00\x00\x01\x00\x01\x00\x01Q\x80\x00\x04\xc0\xa8\n\x03\x00\x00\x01\x00\x01\x00\x01Q\x80\x00\x04\xc0\xa8\n\x02\x00\x00\x01\x00\x01\x00\x01Q\x80\x00\x04\xc0\xa8\n\x01' 349 350class testPackingOfTXT(PackerTestCase): 351 "addTXT(self, name, klass, ttl, list)" 352 def doPack(self, p): 353 p.addTXT('ekit-inc.com', DNS.Class.IN, 3600, 'this is a text record') 354 def doUnpack(self, u): 355 return u.getTXTdata() 356 packerExpectedResult = b'\x08ekit-inc\x03com\x00\x00\x10\x00\x01\x00\x00\x0e\x10\x00\x16\x15this is a text record' 357 unpackerExpectedResult = (('ekit-inc.com', 16, 1, 3600), [b'this is a text record']) 358 359# check what the maximum/minimum &c of TXT records are. 360class testPackingOfTXT2(PackerTestCase): 361 "addTXT(self, name, klass, ttl, list)" 362 def doPack(self, p): 363 f = lambda p=p:p.addTXT('ekit-inc.com', DNS.Class.IN, 3600, 'the quick brown fox jumped over the lazy brown dog\n'*20) 364 self.assertRaises(ValueError, f) 365 return TestCompleted 366 doUnpack = None 367 368class testPackingOfAAAAText(PackerTestCase): 369 "addAAAA(self, name, klass, ttl, address)" 370 def setUp(self): 371 self.RRpacker = DNS.Lib.RRpacker 372 self.RRunpacker = DNS.Lib.RRunpackerText 373 374 def doPack(self, p): 375 addAAAA(p, 'google.com', DNS.Class.IN, 4, '2607:f8b0:4005:802::1005') 376 def doUnpack(self, u): 377 r = u.getAAAAdata() 378 return r 379 packerExpectedResult = b'\x06google\x03com\x00\x00\x1c\x00\x01\x00\x00\x00\x04\x00\x10&\x07\xf8\xb0@\x05\x08\x02\x00\x00\x00\x00\x00\x00\x10\x05' 380 unpackerExpectedResult = (('google.com', DNS.Type.AAAA, DNS.Class.IN, 4), '2607:f8b0:4005:802::1005') 381 382class testPackingOfAAAABinary(PackerTestCase): 383 "addAAAA(self, name, klass, ttl, address)" 384 def setUp(self): 385 self.RRpacker = DNS.Lib.RRpacker 386 self.RRunpacker = DNS.Lib.RRunpackerBinary 387 388 def doPack(self, p): 389 addAAAA(p, 'google.com', DNS.Class.IN, 4, '2607:f8b0:4005:802::1005') 390 def doUnpack(self, u): 391 self.assertFalse(hasattr(u, "getAAAAdata")) 392 r = u.getbytes(16) 393 return r 394 packerExpectedResult = b'\x06google\x03com\x00\x00\x1c\x00\x01\x00\x00\x00\x04\x00\x10&\x07\xf8\xb0@\x05\x08\x02\x00\x00\x00\x00\x00\x00\x10\x05' 395 unpackerExpectedResult = (('google.com', DNS.Type.AAAA, DNS.Class.IN, 4), b'&\x07\xf8\xb0@\x05\x08\x02\x00\x00\x00\x00\x00\x00\x10\x05') 396 397class testPackingOfAAAAInteger(PackerTestCase): 398 "addAAAA(self, name, klass, ttl, address)" 399 def setUp(self): 400 self.RRpacker = DNS.Lib.RRpacker 401 self.RRunpacker = DNS.Lib.RRunpackerInteger 402 403 def doPack(self, p): 404 addAAAA(p, 'google.com', DNS.Class.IN, 4, '2607:f8b0:4005:802::1005') 405 def doUnpack(self, u): 406 r = u.getAAAAdata() 407 return r 408 packerExpectedResult = b'\x06google\x03com\x00\x00\x1c\x00\x01\x00\x00\x00\x04\x00\x10&\x07\xf8\xb0@\x05\x08\x02\x00\x00\x00\x00\x00\x00\x10\x05' 409 unpackerExpectedResult = (('google.com', DNS.Type.AAAA, DNS.Class.IN, 4), 50552053919387978162022445795852161029) 410 411def addAAAA(p, name, klass, ttl, address): 412 """Add AAAA record to a packer. 413 """ 414 addr_buf = socket.inet_pton(socket.AF_INET6, address) 415 p.addRRheader(name, DNS.Type.AAAA, klass, ttl) 416 p.buf = p.buf + addr_buf 417 p.endRR() 418 return p 419 420#class testPackingOfQuestion(PackerTestCase): 421# "addQuestion(self, qname, qtype, qclass)" 422# def doPack(self, p): 423# self.assertEquals(0,"NotImplemented") 424 425def test_suite(): 426 from unittest import TestLoader 427 return TestLoader().loadTestsFromName(__name__) 428 429if __name__ == "__main__": 430 unittest.main() 431