File: zmap_wrapper.py

package info (click to toggle)
zmap 4.3.4-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,628 kB
  • sloc: ansic: 15,033; python: 1,085; yacc: 125; sh: 120; lex: 28; makefile: 4
file content (135 lines) | stat: -rw-r--r-- 4,925 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import re
import subprocess
import sys

PACKET_SEP = "-" * 54


class Wrapper:
    def __init__(self, port="80", subnet="", num_of_ips=-1, threads=-1, shards=-1, shard=-1, seed=-1, iplayer=False,
                 dryrun=True, output_file="", max_runtime=-1, max_cooldown=-1, blocklist_file="", allowlist_file="",
                 list_of_ips_file="", probes="", source_ip="", source_port="", source_mac="", rate=-1, max_targets=""):
        self.port = port
        self.subnet = subnet
        self.num_of_ips = num_of_ips
        self.threads = threads
        self.shards = shards
        self.shard = shard
        self.seed = seed
        self.iplayer = iplayer
        self.dryrun = dryrun
        self.output_file = output_file
        self.max_runtime = max_runtime
        self.max_cooldown = max_cooldown
        self.blocklist_file = blocklist_file
        self.allowlist_file = allowlist_file
        self.list_of_ips_file = list_of_ips_file
        self.probes = probes
        self.source_ip = source_ip
        self.source_port = source_port
        self.source_mac = source_mac
        self.rate = rate
        self.max_targets = max_targets


    def run(self):
        args = ["../../src/zmap"]
        args.extend(["-p", str(self.port)])
        if self.subnet:
            args.extend(self.subnet.split())
        if self.num_of_ips != -1:
            args.extend(["-n", str(self.num_of_ips)])
        if self.threads != -1:
            args.extend(["-T", str(self.threads)])
        if self.shards != -1:
            args.extend(["--shards=" + str(self.shards)])
        if self.shard != -1:
            args.extend(["--shard=" + str(self.shard)])
        if self.seed != -1:
            args.extend(["--seed=" + str(self.seed)])
        if self.iplayer:
            args.extend(["--iplayer"])
        if self.dryrun:
            args.extend(["--dryrun"])
        if self.output_file:
            args.extend(["-o", self.output_file])
        if self.max_runtime != -1:
            args.extend(["--max-runtime="+ str(self.max_runtime)])
        if self.max_cooldown != -1:
            args.extend(["-c", str(self.max_cooldown)])
        if self.blocklist_file:
            args.extend(["--blocklist-file=" + self.blocklist_file])
        if self.allowlist_file:
            args.extend(["--allowlist-file=" + self.allowlist_file])
        if self.list_of_ips_file:
            args.extend(["--list-of-ips-file=" + self.list_of_ips_file])
        if self.probes:
            args.extend(["--probes=" + self.probes])
        if self.source_ip:
            args.extend(["--source-ip=" + self.source_ip])
        if self.source_port:
            args.extend(["--source-port=" + self.source_port])
        if self.source_mac:
            args.extend(["--source-mac=" + self.source_mac])
        if self.rate != -1:
            args.extend(["--rate=" + str(self.rate)])
        if self.max_targets != "":
            args.extend(["--max-targets=" + str(self.max_targets)])

        test_output = subprocess.run(args, stdout=subprocess.PIPE).stdout.decode('utf-8')
        packets = parse_output_into_obj_list(test_output)
        return packets


def parse_output_into_obj_list(zmap_output: str):
    """
    Chunks the entire ZMap output stream into individual packet outputs, and passes this to parse_packet_string
    """
    packets = []
    blocks = zmap_output.split(PACKET_SEP)
    for block in blocks:
        block = block.strip()
        if not block:
            continue
        packets.append(parse_packet_string(block))

    return packets


def parse_packet_string(block):
    """
    Parses a string of packet output from zmap into a dictionary object storing the packet's fields
    """
    # reg ex strings to find the fields we're interested in
    tcp_pattern = re.compile(r"tcp { source: (\d+) \| dest: (\d+) \| seq: (\d+) \| checksum: (.+?) }")
    ip_pattern = re.compile(r"ip { saddr: ([\d.]+) \| daddr: ([\d.]+) \| checksum: (.+?) }")
    eth_pattern = re.compile(r"eth { shost: ([\w:]+) \| dhost: ([\w:]+) }")

    tcp_match = tcp_pattern.search(block)
    ip_match = ip_pattern.search(block)
    eth_match = eth_pattern.search(block)
    packet = {}

    if tcp_match:
        packet["tcp"] = {
            "source": tcp_match.group(1),
            "dest": tcp_match.group(2),
            "seq": int(tcp_match.group(3)),
            "checksum": tcp_match.group(4)
        }
    if ip_match:
        packet["ip"] = {
            "saddr": ip_match.group(1),
            "daddr": ip_match.group(2),
            "checksum": ip_match.group(3)
        }
    if eth_match:
        packet["eth"] = {
            "shost": eth_match.group(1),
            "dhost": eth_match.group(2)
        }

    if len(packet) == 0:
        # packet object is empty, cannot proceed
        sys.exit("packet output \"{}\" has no expected fields: \"tcp\", \"ip\", or \"eth\"".format(block))
    return packet