From 4086f344e458681bb70696bc990413885f8f8a3f Mon Sep 17 00:00:00 2001 From: emdee Date: Sun, 2 Oct 2022 03:36:34 +0000 Subject: [PATCH] Added nmap testing --- README.md | 30 +++++++++++- logging_tox_savefile.py | 100 +++++++++++++++++++++++++++------------- 2 files changed, 97 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 43d0b0a..c4b6eab 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ to stdout usage: logging_tox_savefile.py [-h] [--output OUTPUT] [--command {info,decrypt,nodes}] [--indent INDENT] - [--info {info,repr,yaml,json,pprint}] + [--info {info,repr,yaml,json,pprint,nmap_udp,nmap_tcp}] [--nodes {select_tcp,select_udp,select_version,nmap_tcp,nmap_udp}] [--download_nodes_url DOWNLOAD_NODES_URL] [profile] @@ -40,7 +40,7 @@ Optional arguments: --command {info,decrypt,nodes} Action command - default: info --output OUTPUT Destination for info/decrypt/nodes - defaults to stdout - --info {info,repr,yaml,json,pprint} + --info {info,repr,yaml,json,pprint,nmap_udp,nmap_tcp} Format for info command --nodes {select_tcp,select_udp,select_version,nmap_tcp,nmap_udp} Action for nodes command (requires jq) @@ -48,6 +48,32 @@ Optional arguments: --download_nodes_url DOWNLOAD_NODES_URL ``` +### --command info + +```info``` will output the profile on stdout, or to a file with ```--output``` + +Choose one of ```{info,repr,yaml,json,pprint}``` +for the format for info command. + +Choose one of ```{nmap_udp,nmap_tcp}``` +to run tests using ```nmap``` for the ```DHT``` and ```TCP_RELAY``` +sections of the profile. Reguires ```nmap``` and uses ```sudo```. + +### --command nodes + +Takes a DHTnodes.json file as an argument. +Choose one of ```{select_tcp,select_udp,select_version}``` +for ```--nodes``` to select TCP nodes, UDP nodes or nodes with the latest version. +Requires ```jq```. + +Choose one of ```{nmap_tcp,nmap_udp}``` +to run tests using ```nmap``` for the ```tcp``` and ```udp``` +nodes. Reguires ```nmap``` and uses ```sudo```. + +### --command decrypt + +Decrypt a profile. + ## Requirements If you want to read encrypted profiles, you need to download diff --git a/logging_tox_savefile.py b/logging_tox_savefile.py index f9c6423..a3ba88f 100644 --- a/logging_tox_savefile.py +++ b/logging_tox_savefile.py @@ -30,7 +30,8 @@ commands, or the filename of the nodes file for the nodes command. choices=['select_tcp', 'select_udp', 'nmap_tcp', 'select_version', 'nmap_udp'] select_udp - select udp nodes select_tcp - select tcp nodes - nmap_tcp - test tcp nodes with namp + nmap_udp - test UDP nodes with nmap + nmap_tcp - test TCP nodes with nmap select_version - select nodes that are the latest version download - download nodes from --download_nodes_url --download_nodes_url https://nodes.tox.chat/json @@ -335,17 +336,17 @@ The Node Info data structure contains a Transport Protocol, a Socket af = 'IPv6' alen = 16 ipaddr = inet_ntop(AF_INET6, result[delta+1:delta+1+alen]) - total = 1 + alen + 2 + 32 - port = int(struct.unpack_from(">H", result, delta+1+alen)[0]) - pk = bin_to_hex(result[delta+1+alen+2:delta+1+alen+2+32], 32) - LOG.info(f"DHTnode #{relay} bytes={length} status={status} ip={ipv} af={af} ip={ipaddr} port={port} pk={pk}") - lIN += [{"Bytes": length, - "Status": status, - "Ip": ipv, - "Af": af, - "Ip": ipaddr, - "Port": port, - "Pk": pk}] + total = 1 + alen + 2 + 32 + port = int(struct.unpack_from(">H", result, delta+1+alen)[0]) + pk = bin_to_hex(result[delta+1+alen+2:delta+1+alen+2+32], 32) + LOG.info(f"DHTnode #{relay} bytes={length} status={status} ip={ipv} af={af} ip={ipaddr} port={port} pk={pk}") + lIN += [{"Bytes": length, + "Status": status, + "Ip": ipv, + "Af": af, + "Ip": ipaddr, + "Port": port, + "Pk": pk}] if bUSE_NMAP: cmd = f"nmap -Pn -n -sT -p T:{port} {ipaddr}" @@ -400,7 +401,7 @@ def lProcessDHTnodes(state, index, length, result): return lIN def process_chunk(index, state): - global lOUT, bOUT, iTOTAL + global lOUT, bOUT, iTOTAL, aOUT length = struct.unpack_from(" 0: LOG.debug(f"TODO process_chunk {dSTATE_TYPE[data_type]} bytes={length}") else: LOG.info(f"NO {dSTATE_TYPE[data_type]}") - lOUT += [{"Conferences": []}] + lOUT += [{"CONFERENCES": []}]; aOUT.update({"CONFERENCES": []}) elif data_type != MESSENGER_STATE_TYPE_END: LOG.warn("UNRECOGNIZED datatype={datatype}") @@ -518,7 +521,7 @@ jq '.|with_entries(select(.key|match("nodes"))).nodes[]|select(.status_tcp)|sele else echo INFO $ip "${ports[*]}" cmd="nmap -Pn -n -sT -p T:"`echo "${ports[*]}" |sed -e 's/ /,/g'` - dbug $cmd $ip + echo DBUG $cmd $ip $cmd $ip | grep /tcp fi ip="" @@ -552,6 +555,31 @@ def vBashFileNmapUdp(): os.chmod(sFile, 0o0775) return sFile +def vOsSystemNmapUdp(l, oArgs): + iErrs = 0 + for elt in aOUT["DHT"]: + cmd = f"sudo nmap -Pn -n -sU -p U:{elt['port']} {elt['ipaddr']}" + iErrs += os.system(cmd +f" >> {oArgs.output} 2>&1") + if iErrs: + LOG.warn(f"{oArgs.info} {iErrs} ERRORs to {oArgs.output}") + print(f"{oArgs.info} {iErrs} ERRORs to {oArgs.output}") + else: + LOG.info(f"{oArgs.info} NO errors to {oArgs.output}") + print(f"{oArgs.info} NO errors to {oArgs.output}") + +def vOsSystemNmapTcp(l, oArgs): + iErrs = 0 + for elt in l: + cmd = f"sudo nmap -Pn -n -sT -p T:{elt['port']} {elt['ipaddr']}" + print(f"{oArgs.info} NO errors to {oArgs.output}") + iErrs += os.system(cmd +f" >> {oArgs.output} 2>&1") + if iErrs: + LOG.warn(f"{oArgs.info} {iErrs} ERRORs to {oArgs.output}") + print(f"{oArgs.info} {iErrs} ERRORs to {oArgs.output}") + else: + LOG.info(f"{oArgs.info} NO errors to {oArgs.output}") + print(f"{oArgs.info} NO errors to {oArgs.output}") + def vSetupLogging(loglevel=logging.DEBUG): global LOG if coloredlogs: @@ -588,7 +616,7 @@ def oMainArgparser(_=None): parser.add_argument('--indent', type=int, default=2, help='Indent for yaml/json/pprint') parser.add_argument('--info', type=str, default='info', - choices=['info', 'repr', 'yaml','json', 'pprint'], + choices=['info', 'repr', 'yaml','json', 'pprint', 'nmap_tcp', 'nmap_udp'], help='Format for info command') choices = [] if bHAVE_JQ: @@ -702,26 +730,36 @@ if __name__ == '__main__': # toxEsave assert bSAVE[:8] == bOUT, "Not a Tox profile" - lOUT = [] + iErrs = 0 + lOUT = []; aOUT = {} process_chunk(len(bOUT), bSAVE) if lOUT: if oArgs.output: - oStream = open(oArgs.output, 'rb') + oStream = open(oArgs.output, 'wb') else: oStream = sys.stdout if oArgs.info == 'yaml' and yaml: - yaml.dump(lOUT, stream=oStream, indent=oArgs.indent) + yaml.dump(aOUT, stream=oStream, indent=oArgs.indent) oStream.write('\n') elif oArgs.info == 'json' and json: - json.dump(lOUT, oStream, indent=oArgs.indent) + json.dump(aOUT, oStream, indent=oArgs.indent) oStream.write('\n') elif oArgs.info == 'repr': - oStream.write(repr(lOUT)) + oStream.write(repr(aOUT)) oStream.write('\n') elif oArgs.info == 'pprint': - pprint(lOUT, stream=oStream, indent=oArgs.indent, width=80) + pprint(aOUT, stream=oStream, indent=oArgs.indent, width=80) elif oArgs.info == 'info': pass + elif oArgs.info == 'nmap_tcp': + assert oArgs.output, "--output required for this command" + oStream.close() + vOsSystemNmapTcp(aOUT["TCP_RELAY"], oArgs) + elif oArgs.info == 'nmap_udp': + assert oArgs.output, "--output required for this command" + oStream.close() + vOsSystemNmapUdp(aOUT["DHT"], oArgs) + # were short repacking as we read - 446 bytes missing LOG.debug(f"len bSAVE={len(bSAVE)} bOUT={len(bOUT)} delta={len(bSAVE) - len(bOUT)} iTOTAL={iTOTAL}")