blob: fae4f6540a02f90f0232a9f436d17a9beb33606e [file] [log] [blame]
Alexe0c5b9e2019-04-23 18:51:23 -05001import json
2import os
3import platform
4import sys
5from copy import deepcopy
6from multiprocessing.dummy import Pool
7from subprocess import PIPE, Popen
8
9_os = platform.system()
10_packets = {}
11
12_defaults = {
13 "ip": None,
14 "size": 0,
15 "fragmentation": False,
16 "count": 1,
17 "exit_timeout": 1,
18 "response_timeout": 1,
19 "numeric": True
20}
21
22_help_message = \
23 "Invalid parameters. Use: 'ping.py [PKT_SIZE] <IP>' or 'ping.py n.json'\n"
24
25_template = {
26 "returncode": -1,
27 "stdout": "",
28 "stderr": ""
29}
30
31
32def shell(command):
33 _ps = Popen(
34 " ".join(command),
35 shell=True,
36 stdout=PIPE,
37 stderr=PIPE
38 )
39 _out = _ps.communicate()
40 _err = _out[1]
41 _out = _out[0]
42 return _ps.returncode, _out, _err
43
44
45def write_help():
46 _t = deepcopy(_template)
47 _t["returncode"] = 1
48 _t["stderr"] = _help_message
49 write_outcome(_t)
50
51
52def write_outcome(_params):
53 sys.stdout.write(json.dumps(_params))
54
55
56def do_ping(_params):
57 # Load params and defaults
58 _d = deepcopy(_defaults)
59 for key in _params:
60 _d[key] = _params[key]
61
62 # Build cmd
63 _cmd = ["ping"]
64 if _os == "Darwin":
65 if not _d["fragmentation"]:
66 _cmd.append("-D")
67 if _d["exit_timeout"]:
68 _cmd += ["-t", str(_d["exit_timeout"])]
69 elif _os == "Linux":
70 if not _d["fragmentation"]:
71 _cmd += ["-M", "do"]
72 if _d["exit_timeout"]:
73 _cmd += ["-w", str(_d["exit_timeout"])]
74 else:
75 # Windows or other OS
76 _t = deepcopy(_template)
77 _t["returncode"] = 1
78 _t["stderr"] = \
79 "ping.py: '{}' support not implemented".format(_os)
80 write_outcome(_t)
81 sys.exit(1)
82
83 if _d["size"]:
84 _cmd += ["-s", str(_d["size"])]
85 if _d["count"]:
86 _cmd += ["-c", str(_d["count"])]
87 if _d["numeric"]:
88 _cmd.append("-n")
89 if _d["response_timeout"]:
90 _cmd += ["-W", str(_d["response_timeout"])]
91
92 _cmd.append(_d["ip"])
93 # sys.stdout.write("# {}\n".format(" ".join(_cmd)))
94 _r, _out, _err = shell(_cmd)
95
96 # TODO: parse results, latency, etc
97 _t = deepcopy(_template)
98 _t["returncode"] = _r
99 _t["stdout"] = _out
100 _t["stderr"] = _err
101 _params.update(_t)
102 return _params
103
104
105def load_targets(filename):
106 # load target ips from json
107 with open(filename, "r") as f:
108 j = json.load(f)
109
110 return j
111
112
113if len(sys.argv) < 2:
114 # no params given
115 write_help()
116elif len(sys.argv) < 3:
117 # one param: decide if it json file or IP
118 _arg = sys.argv[1]
119 if os.path.isfile(_arg):
120 _packets = load_targets(_arg)
121 # up to 15 packets at once
122 pool = Pool(15)
123 # prepare threaded map
124 _param_map = []
Alex3bc95f62020-03-05 17:00:04 -0600125 for _node, _data in _packets.items():
Alexe0c5b9e2019-04-23 18:51:23 -0500126 if isinstance(_data, list):
127 for target in _data:
128 _param_map.append(target)
129 elif isinstance(_data, dict):
130 _param_map.append(_data)
131 else:
132 _t = deepcopy(_template)
133 _t["returncode"] = 1
134 _t["stderr"] = \
135 "TypeError: 'list' or 'dict' expected. " \
136 "Got '{}': '{}'".format(
137 type(_data).__name__,
138 _data
139 )
140 _packets[_node] = _t
141 _threaded_out = pool.map(do_ping, _param_map)
142 for _out in _threaded_out:
143 if isinstance(_packets[_out["tgt_host"]], dict):
144 _packets[_out["tgt_host"]] = _out
145 elif isinstance(_packets[_out["tgt_host"]], list):
146 _packets[_out["tgt_host"]][_out["ip_index"]] = _out
147 sys.stdout.write(json.dumps(_packets))
148 else:
149 # IP given
150 _ip = sys.argv[1]
151 write_outcome(do_ping(_ip))
152elif len(sys.argv) < 4:
153 # two params: size and IP
154 _s = sys.argv[1]
155 _ip = sys.argv[2]
156 write_outcome(do_ping(_ip, size=_s))
157else:
158 # too many params given
159 write_help()