netarch

Network Archaeology library for Python
git clone https://git.woozle.org/neale/netarch.git

commit
c3ced6f
parent
93498f1
author
Neale Pickett
date
2020-09-21 14:00:59 -0600 MDT
more py3 fixes
5 files changed,  +186, -194
M ip.py
A .gitignore
+1, -0
1@@ -0,0 +1 @@
2+__pycache__
M __init__.py
+15, -153
  1@@ -3,154 +3,8 @@
  2 import binascii
  3 import sys
  4 import struct
  5+from . import ip
  6 
  7-stdch = (
  8-    '␀·········␊··␍··'
  9-    '················'
 10-    ' !"#$%&\'()*+,-./'
 11-    '0123456789:;<=>?'
 12-    '@ABCDEFGHIJKLMNO'
 13-    'PQRSTUVWXYZ[\]^_'
 14-    '`abcdefghijklmno'
 15-    'pqrstuvwxyz{|}~·'
 16-    '················'
 17-    '················'
 18-    '················'
 19-    '················'
 20-    '················'
 21-    '················'
 22-    '················'
 23-    '················'
 24-)
 25-
 26-decch = (
 27-    '␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏'
 28-    '␐␑␒␓␔␕␖␗␘␙␚·····'
 29-    '␠!"#$%&\'()*+,-./'
 30-    '0123456789:;<=>?'
 31-    '@ABCDEFGHIJKLMNO'
 32-    'PQRSTUVWXYZ[\]^_'
 33-    '`abcdefghijklmno'
 34-    'pqrstuvwxyz{|}~␡'
 35-    '················'
 36-    '················'
 37-    '················'
 38-    '················'
 39-    '················'
 40-    '················'
 41-    '················'
 42-    '················'
 43-)
 44-
 45-cgach = (
 46-    '□☺☻♥♦♣♠•◘○◙♂♀♪♫☼'
 47-	'►◄↕‼¶§▬↨↑↓→←∟↔▲▼'
 48-	' !"#$%&\'()*+,-./'
 49-	'0123456789:;<=>?'
 50-	'@ABCDEFGHIJKLMNO'
 51-	'PQRSTUVWXYZ[\]^_'
 52-	'`abcdefghijklmno'
 53-	'pqrstuvwxyz{|}~⌂'
 54-	'ÇüéâäàåçêëèïîìÄÅ'
 55-	'ÉæÆôöòûùÿÖÜ¢£¥₧ƒ'
 56-	'áíóúñѪº¿⌐¬½¼¡«»'
 57-	'░▒▓│┤╡╢╖╕╣║╗╝╜╛┐'
 58-	'└┴┬├─┼╞╟╚╔╩╦╠═╬╧'
 59-	'╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀'
 60-	'αßΓπΣσµτΦΘΩδ∞φε∩'
 61-	'≡±≥≤⌠⌡÷≈°∙·√ⁿ²■¤'
 62-)
 63-
 64-fluffych = (
 65-    '·☺☻♥♦♣♠•◘○◙♂♀♪♫☼'
 66-	'►◄↕‼¶§▬↨↑↓→←∟↔▲▼'
 67-	' !"#$%&\'()*+,-./'
 68-	'0123456789:;<=>?'
 69-	'@ABCDEFGHIJKLMNO'
 70-	'PQRSTUVWXYZ[\]^_'
 71-	'`abcdefghijklmno'
 72-	'pqrstuvwxyz{|}~⌂'
 73-	'ÇüéâäàåçêëèïîìÄÅ'
 74-	'ÉæÆôöòûùÿÖÜ¢£¥₧ƒ'
 75-	'áíóúñѪº¿⌐¬½¼¡«»'
 76-	'░▒▓│┤╡╢╖╕╣║╗╝╜╛┐'
 77-	'└┴┬├─┼╞╟╚╔╩╦╠═╬╧'
 78-	'╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀'
 79-	'αßΓπΣσµτΦΘΩδ∞φε∩'
 80-	'≡±≥≤⌠⌡÷≈°∀∃√ⁿ²■¤'
 81-)
 82-
 83-
 84-def unpack(fmt, buf):
 85-    """Unpack buf based on fmt, return the remainder."""
 86-
 87-    size = struct.calcsize(fmt)
 88-    vals = struct.unpack(fmt, bytes(buf[:size]))
 89-    return vals + (buf[size:],)
 90-
 91-
 92-class HexDumper:
 93-    def __init__(self, output, charset=fluffych):
 94-        self.offset = 0
 95-        self.last = None
 96-        self.elided = False
 97-        self.hexes = []
 98-        self.chars = []
 99-        self.charset = charset
100-        self.output = output
101-
102-    def _spit(self):
103-        if self.chars == self.last:
104-            if not self.elided:
105-                self.output.write('*\n')
106-                self.elided = True
107-            self.hexes = []
108-            self.chars = []
109-            return
110-        self.last = self.chars[:]
111-        self.elided = False
112-
113-        pad = 16 - len(self.chars)
114-        self.hexes += ['  '] * pad
115-
116-        self.output.write('{:08x}  '.format(self.offset - len(self.chars)))
117-        self.output.write(' '.join(self.hexes[:8]))
118-        self.output.write('  ')
119-        self.output.write(' '.join(self.hexes[8:]))
120-        self.output.write('  ')
121-        self.output.write(''.join(self.chars))
122-        self.output.write('\n')
123-
124-        self.hexes = []
125-        self.chars = []
126-
127-    def add(self, b):
128-        if self.offset and self.offset % 16 == 0:
129-            self._spit()
130-
131-        if b is None:
132-            h = '⬜'
133-            c = '�'
134-        else:
135-            h = '{:02x}'.format(b)
136-            c = self.charset[b]
137-        self.chars.append(c)
138-        self.hexes.append(h)
139-
140-        self.offset += 1
141-
142-    def done(self):
143-        self._spit()
144-        self.output.write('{:08x}\n'.format(self.offset))
145-
146-
147-def hexdump(buf, f=sys.stdout, charset=fluffych):
148-    "Print a hex dump of buf"
149-
150-    h = HexDumper(output=f, charset=charset)
151-    for b in buf:
152-        h.add(b)
153-    h.done()
154 
155 
156 def cstring(buf):
157@@ -160,10 +14,6 @@ def cstring(buf):
158     return buf[:i]
159 
160 
161-def md5sum(txt):
162-    return md5.new(txt).hexdigest()
163-
164-
165 def assert_equal(a, b):
166     assert a == b, ('%r != %r' % (a, b))
167 
168@@ -218,7 +68,7 @@ class BitVector:
169         """Iterate from LSB to MSB"""
170 
171         v = self._val
172-        for i in xrange(self._len):
173+        for _ in range(self._len):
174             yield int(v & 1)
175             v >>= 1
176 
177@@ -282,7 +132,7 @@ import string
178 b64alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
179 
180 def from_b64(s, alphabet, codec='base64'):
181-    tr = string.maketrans(alphabet, b64alpha)
182+    tr = alphabet.maketrans(b64alpha)
183     t = s.translate(tr)
184     return t.decode(codec)
185 
186@@ -330,3 +180,15 @@ def _registry(encoding):
187                 Esab64StreamReader, Esab64StreamWriter)
188 
189 codecs.register(_registry)
190+
191+def main(session):
192+    s = None
193+    reseq = ip.Dispatch(*sys.argv[1:])
194+    for _, d in reseq:
195+        srv, first, chunk = d
196+        if not s:
197+            s = session(first)
198+        s.handle(srv, first, chunk, reseq.last)
199+
200+Session = ip.Session
201+Packet = ip.Packet
M dumbdecode.py
+7, -15
 1@@ -1,20 +1,12 @@
 2 #! /usr/bin/python3
 3 
 4-import sys
 5-from netarch import ip
 6-from netarch import *
 7+import netarch
 8 
 9-class DumbPacket(ip.Packet):
10-    def parse(self, data):
11-        self.payload = data
12+class DumbPacket(netarch.Packet):
13+	def parse(self, data):
14+		self.payload = data
15 
16-class DumbSession(ip.Session):
17-    Packet = DumbPacket
18+class DumbSession(netarch.Session):
19+	Packet = DumbPacket
20 
21-s = None
22-reseq = ip.Dispatch(*sys.argv[1:])
23-for h, d in reseq:
24-    srv, first, chunk = d
25-    if not s:
26-        s = DumbSession(first)
27-    s.handle(srv, first, chunk, reseq.last)
28+netarch.main(DumbSession)
A hexdump.py
+140, -0
  1@@ -0,0 +1,140 @@
  2+import sys
  3+
  4+stdch = (
  5+    '␀·········␊··␍··'
  6+    '················'
  7+    ' !"#$%&\'()*+,-./'
  8+    '0123456789:;<=>?'
  9+    '@ABCDEFGHIJKLMNO'
 10+    'PQRSTUVWXYZ[\\]^_'
 11+    '`abcdefghijklmno'
 12+    'pqrstuvwxyz{|}~·'
 13+    '················'
 14+    '················'
 15+    '················'
 16+    '················'
 17+    '················'
 18+    '················'
 19+    '················'
 20+    '················'
 21+)
 22+
 23+decch = (
 24+    '␀␁␂␃␄␅␆␇␈␉␊␋␌␍␎␏'
 25+    '␐␑␒␓␔␕␖␗␘␙␚·····'
 26+    '␠!"#$%&\'()*+,-./'
 27+    '0123456789:;<=>?'
 28+    '@ABCDEFGHIJKLMNO'
 29+    'PQRSTUVWXYZ[\\]^_'
 30+    '`abcdefghijklmno'
 31+    'pqrstuvwxyz{|}~␡'
 32+    '················'
 33+    '················'
 34+    '················'
 35+    '················'
 36+    '················'
 37+    '················'
 38+    '················'
 39+    '················'
 40+)
 41+
 42+cgach = (
 43+    '□☺☻♥♦♣♠•◘○◙♂♀♪♫☼'
 44+	'►◄↕‼¶§▬↨↑↓→←∟↔▲▼'
 45+	' !"#$%&\'()*+,-./'
 46+	'0123456789:;<=>?'
 47+	'@ABCDEFGHIJKLMNO'
 48+	'PQRSTUVWXYZ[\\]^_'
 49+	'`abcdefghijklmno'
 50+	'pqrstuvwxyz{|}~⌂'
 51+	'ÇüéâäàåçêëèïîìÄÅ'
 52+	'ÉæÆôöòûùÿÖÜ¢£¥₧ƒ'
 53+	'áíóúñѪº¿⌐¬½¼¡«»'
 54+	'░▒▓│┤╡╢╖╕╣║╗╝╜╛┐'
 55+	'└┴┬├─┼╞╟╚╔╩╦╠═╬╧'
 56+	'╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀'
 57+	'αßΓπΣσµτΦΘΩδ∞φε∩'
 58+	'≡±≥≤⌠⌡÷≈°∙·√ⁿ²■¤'
 59+)
 60+
 61+fluffych = (
 62+    '·☺☻♥♦♣♠•◘○◙♂♀♪♫☼'
 63+	'►◄↕‼¶§▬↨↑↓→←∟↔▲▼'
 64+	' !"#$%&\'()*+,-./'
 65+	'0123456789:;<=>?'
 66+	'@ABCDEFGHIJKLMNO'
 67+	'PQRSTUVWXYZ[\\]^_'
 68+	'`abcdefghijklmno'
 69+	'pqrstuvwxyz{|}~⌂'
 70+	'ÇüéâäàåçêëèïîìÄÅ'
 71+	'ÉæÆôöòûùÿÖÜ¢£¥₧ƒ'
 72+	'áíóúñѪº¿⌐¬½¼¡«»'
 73+	'░▒▓│┤╡╢╖╕╣║╗╝╜╛┐'
 74+	'└┴┬├─┼╞╟╚╔╩╦╠═╬╧'
 75+	'╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀'
 76+	'αßΓπΣσµτΦΘΩδ∞φε∩'
 77+	'≡±≥≤⌠⌡÷≈°∀∃√ⁿ²■¤'
 78+)
 79+
 80+class HexDumper:
 81+    def __init__(self, output, charset=fluffych):
 82+        self.offset = 0
 83+        self.last = None
 84+        self.elided = False
 85+        self.hexes = []
 86+        self.chars = []
 87+        self.charset = charset
 88+        self.output = output
 89+
 90+    def _spit(self):
 91+        if self.chars == self.last:
 92+            if not self.elided:
 93+                self.output.write('*\n')
 94+                self.elided = True
 95+            self.hexes = []
 96+            self.chars = []
 97+            return
 98+        self.last = self.chars[:]
 99+        self.elided = False
100+
101+        pad = 16 - len(self.chars)
102+        self.hexes += ['  '] * pad
103+
104+        self.output.write('{:08x}  '.format(self.offset - len(self.chars)))
105+        self.output.write(' '.join(self.hexes[:8]))
106+        self.output.write('  ')
107+        self.output.write(' '.join(self.hexes[8:]))
108+        self.output.write('  ')
109+        self.output.write(''.join(self.chars))
110+        self.output.write('\n')
111+
112+        self.hexes = []
113+        self.chars = []
114+
115+    def add(self, b):
116+        if self.offset and self.offset % 16 == 0:
117+            self._spit()
118+
119+        if b is None:
120+            h = '⬜'
121+            c = '�'
122+        else:
123+            h = '{:02x}'.format(b)
124+            c = self.charset[b]
125+        self.chars.append(c)
126+        self.hexes.append(h)
127+
128+        self.offset += 1
129+
130+    def done(self):
131+        self._spit()
132+        self.output.write('{:08x}\n'.format(self.offset))
133+
134+
135+def hexdump(buf, f=sys.stdout, charset=fluffych):
136+    "Print a hex dump of buf"
137+
138+    h = HexDumper(output=f, charset=charset)
139+    for b in buf:
140+        h.add(b)
141+    h.done()
M ip.py
+23, -26
 1@@ -13,12 +13,20 @@ try:
 2     import pcap
 3 except ImportError:
 4     warnings.warn("Using slow pure-python pcap library")
 5-    import netarch.py_pcap as pcap
 6+    from . import py_pcap as pcap
 7 import os
 8 import cgi
 9 import urllib.parse
10-from netarch import unpack, hexdump
11-from netarch.trilobytes import TriloBytes
12+from .hexdump import hexdump
13+from .trilobytes import TriloBytes
14+
15+def unpack(fmt, buf):
16+    """Unpack buf based on fmt, return the remainder."""
17+
18+    size = struct.calcsize(fmt)
19+    vals = struct.unpack(fmt, bytes(buf[:size]))
20+    return vals + (buf[size:],)
21+
22 
23 def unpack_nybbles(byte):
24     return (byte >> 4, byte & 0x0F)
25@@ -65,7 +73,6 @@ class Frame:
26              p) = unpack('!HHBBH6si6si', p)
27             self.saddr = self.ar_sip
28             self.daddr = self.ar_tip
29-            self.__repr__ = self.__arp_repr__
30         elif self.eth_type == IP:
31             # IP
32             (self.ihlvers,
33@@ -146,18 +153,18 @@ class Frame:
34     dst_addr = property(get_dst_addr)
35 
36     def __repr__(self):
37-        return ('<Frame %s %s:%r(%08x) -> %s:%r(%08x) length %d>' %
38-                (self.name,
39-                 self.src_addr, self.sport, self.seq,
40-                 self.dst_addr, self.dport, self.ack,
41-                 len(self.payload)))
42-
43-    def __arp_repr__(self):
44-        return '<Frame %s %s(%s) -> %s(%s)>' % (self.name,
45-                                                str_of_eth(self.ar_sha),
46-                                                self.src_addr,
47-                                                str_of_eth(self.ar_tha),
48-                                                self.dst_addr)
49+        if self.eth_type == ARP:
50+            return '<Frame %s %s(%s) -> %s(%s)>' % (self.name,
51+                                                    str_of_eth(self.ar_sha),
52+                                                    self.src_addr,
53+                                                    str_of_eth(self.ar_tha),
54+                                                    self.dst_addr)
55+        else:
56+            return ('<Frame %s %s:%r(%08x) -> %s:%r(%08x) length %d>' %
57+                    (self.name,
58+                    self.src_addr, self.sport, self.seq,
59+                    self.dst_addr, self.dport, self.ack,
60+                    len(self.payload)))
61 
62 class TCP_Recreate:
63     closed = True
64@@ -360,16 +367,6 @@ class TCP_Resequence:
65         return (xdi, first, gs)
66 
67 
68-    def handle(self, pkt):
69-        """Stub.
70-
71-        This function will never be called, it is immediately overridden
72-        by __init__.  The current value of self.handle is the state.
73-        """
74-
75-        raise NotImplementedError()
76-
77-
78     def handle_handshake(self, pkt):
79         if not self.first:
80             self.first = pkt