1% Tests for Scapy's p0fv2 module. 2 3~ p0f 4 5 6############ 7############ 8+ Basic p0f module tests 9 10= Module loading 11load_module('p0fv2') 12 13= Fetch database 14~ netaccess 15 16try: 17 from urllib.request import urlopen 18except ImportError: 19 from urllib2 import urlopen 20 21def _load_database(file): 22 for i in range(10): 23 try: 24 with open(file, 'wb') as fd: 25 fd.write(urlopen('https://raw.githubusercontent.com/p0f/p0f/4b4d1f384abebbb9b1b25b8f3c6df5ad7ab365f7/' + file).read()) 26 break 27 except: 28 raise 29 pass 30 31_load_database("p0f.fp") 32conf.p0f_base = "p0f.fp" 33_load_database("p0fa.fp") 34conf.p0fa_base = "p0fa.fp" 35_load_database("p0fr.fp") 36conf.p0fr_base = "p0fr.fp" 37_load_database("p0fo.fp") 38conf.p0fo_base = "p0fo.fp" 39 40p0f_load_knowledgebases() 41 42############ 43############ 44+ Default tests 45 46= Test p0f 47~ netaccess 48 49pkt = Ether(b'\x14\x0cv\x8f\xfe(\xd0P\x99V\xdd\xf9\x08\x00E\x00\x0045+@\x00\x80\x06\x00\x00\xc0\xa8\x00w(M\xe2\xf9\xda\xcb\x01\xbbcc\xdd\x1e\x00\x00\x00\x00\x80\x02\xfa\xf0\xcc\x8c\x00\x00\x02\x04\x05\xb4\x01\x03\x03\x08\x01\x01\x04\x02') 50 51assert p0f(pkt) == [('@Windows', 'XP/2000 (RFC1323+, w+, tstamp-)', 0)] 52 53= Test prnp0f 54~ netaccess 55 56with ContextManagerCaptureOutput() as cmco: 57 prnp0f(pkt) 58 assert cmco.get_output() == '192.168.0.119:56011 - @Windows XP/2000 (RFC1323+, w+, tstamp-)\n -> 40.77.226.249:https (S) (distance 0)\n' 59 60############ 61############ 62+ Tests for p0f_impersonate 63 64# XXX: a lot of pieces of p0f_impersonate don't have tests yet. 65 66= Impersonate when window size must be multiple of some integer 67sig = ('%467', 64, 1, 60, 'M*,W*', '.', 'Phony Sys', '1.0') 68pkt = p0f_impersonate(IP()/TCP(), signature=sig) 69assert pkt.payload.window % 467 == 0 70 71= Handle unusual flags ("F") quirk 72sig = ('1024', 64, 0, 60, 'W*', 'F', 'Phony Sys', '1.0') 73pkt = p0f_impersonate(IP()/TCP(), signature=sig) 74assert (pkt.payload.flags & 40) in (8, 32, 40) 75 76= Use valid option values from original packet 77sig = ('S4', 64, 1, 60, 'M*,W*,T', '.', 'Phony Sys', '1.0') 78opts = [('MSS', 1400), ('WScale', 3), ('Timestamp', (97256, 0))] 79pkt = p0f_impersonate(IP()/TCP(options=opts), signature=sig) 80assert pkt.payload.options == opts 81 82= Use valid option values when multiples required 83sig = ('S4', 64, 1, 60, 'M%37,W%19', '.', 'Phony Sys', '1.0') 84opts = [('MSS', 37*15), ('WScale', 19*12)] 85pkt = p0f_impersonate(IP()/TCP(options=opts), signature=sig) 86assert pkt.payload.options == opts 87 88= Discard non-multiple option values when multiples required 89sig = ('S4', 64, 1, 60, 'M%37,W%19', '.', 'Phony Sys', '1.0') 90opts = [('MSS', 37*15 + 1), ('WScale', 19*12 + 1)] 91pkt = p0f_impersonate(IP()/TCP(options=opts), signature=sig) 92assert pkt.payload.options[0][1] % 37 == 0 93assert pkt.payload.options[1][1] % 19 == 0 94 95= Discard bad timestamp values 96sig = ('S4', 64, 1, 60, 'M*,T', '.', 'Phony Sys', '1.0') 97opts = [('Timestamp', (0, 1000))] 98pkt = p0f_impersonate(IP()/TCP(options=opts), signature=sig) 99# since option is "T" and not "T0": 100assert pkt.payload.options[1][1][0] > 0 101# since T quirk is not present: 102assert pkt.payload.options[1][1][1] == 0 103 104= Discard 2nd timestamp of 0 if "T" quirk is present 105sig = ('S4', 64, 1, 60, 'M*,T', 'T', 'Phony Sys', '1.0') 106opts = [('Timestamp', (54321, 0))] 107pkt = p0f_impersonate(IP()/TCP(options=opts), signature=sig) 108assert pkt.payload.options[1][1][1] > 0 109 110+ Clear temp files 111 112= Remove fp files 113def _rem(f): 114 try: 115 os.remove(f) 116 except: 117 pass 118 119_rem("p0f.fp") 120_rem("p0fa.fp") 121_rem("p0fr.fp") 122_rem("p0fo.fp") 123