|
@@ -24,18 +24,18 @@ import fcntl
|
|
import struct
|
|
import struct
|
|
import argparse
|
|
import argparse
|
|
if sys.version_info.major == 2:
|
|
if sys.version_info.major == 2:
|
|
- import commands as subprocess
|
|
|
|
|
|
+ import commands as subprocess
|
|
elif sys.version_info.major == 3:
|
|
elif sys.version_info.major == 3:
|
|
- import subprocess
|
|
|
|
|
|
+ import subprocess
|
|
|
|
|
|
def _to_str(inp):
|
|
def _to_str(inp):
|
|
- if sys.version_info.major == 2:
|
|
|
|
- return inp
|
|
|
|
- else:
|
|
|
|
- return "".join( chr(x) for x in inp)
|
|
|
|
-
|
|
|
|
|
|
+ if sys.version_info.major == 2:
|
|
|
|
+ return inp
|
|
|
|
+ else:
|
|
|
|
+ return "".join( chr(x) for x in inp)
|
|
|
|
+
|
|
|
|
|
|
-VERSION = "0.90"
|
|
|
|
|
|
+VERSION = "1.00"
|
|
|
|
|
|
PROC_TCP4 = "/proc/net/tcp"
|
|
PROC_TCP4 = "/proc/net/tcp"
|
|
PROC_UDP4 = "/proc/net/udp"
|
|
PROC_UDP4 = "/proc/net/udp"
|
|
@@ -61,11 +61,11 @@ payloadH = False
|
|
payloadHl = False
|
|
payloadHl = False
|
|
fillter = ""
|
|
fillter = ""
|
|
|
|
|
|
-def get_conn_info(proto,hosts,ports):
|
|
|
|
|
|
+def get_conn_info(proto,hosts,ports,ipvers):
|
|
''' returns: pid, exe, uid '''
|
|
''' returns: pid, exe, uid '''
|
|
uid = 0
|
|
uid = 0
|
|
|
|
|
|
- line_array = _proc4load(proto,hosts,ports)
|
|
|
|
|
|
+ line_array = _proc4load(proto,hosts,ports,ipvers)
|
|
|
|
|
|
if line_array == 0:
|
|
if line_array == 0:
|
|
return ['?','?','?']
|
|
return ['?','?','?']
|
|
@@ -96,25 +96,25 @@ def get_conn_info(proto,hosts,ports):
|
|
return [pid, exe, uid]
|
|
return [pid, exe, uid]
|
|
|
|
|
|
|
|
|
|
-def _proc4load(proto,hosts,ports):
|
|
|
|
|
|
+def _proc4load(proto,hosts,ports,ipvers):
|
|
''' Read the table of tcp/udp connections
|
|
''' Read the table of tcp/udp connections
|
|
tcp/udp: "sl, local_address, rem_address, st, tx_queue rx_queue, tr tm->when, retrnsmt, uid , timeout, inode ,..."
|
|
tcp/udp: "sl, local_address, rem_address, st, tx_queue rx_queue, tr tm->when, retrnsmt, uid , timeout, inode ,..."
|
|
---- TCP states from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/net/tcp_states.h?id=HEAD
|
|
---- TCP states from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/net/tcp_states.h?id=HEAD
|
|
enum {
|
|
enum {
|
|
- TCP_ESTABLISHED = 1,
|
|
|
|
- TCP_SYN_SENT,
|
|
|
|
- TCP_SYN_RECV,
|
|
|
|
- TCP_FIN_WAIT1,
|
|
|
|
- TCP_FIN_WAIT2,
|
|
|
|
- TCP_TIME_WAIT,
|
|
|
|
- TCP_CLOSE,
|
|
|
|
- TCP_CLOSE_WAIT,
|
|
|
|
- TCP_LAST_ACK,
|
|
|
|
- TCP_LISTEN,
|
|
|
|
- TCP_CLOSING, /* Now a valid state */
|
|
|
|
- TCP_NEW_SYN_RECV,
|
|
|
|
-
|
|
|
|
- TCP_MAX_STATES /* Leave at the end! */
|
|
|
|
|
|
+ TCP_ESTABLISHED = 1,
|
|
|
|
+ TCP_SYN_SENT,
|
|
|
|
+ TCP_SYN_RECV,
|
|
|
|
+ TCP_FIN_WAIT1,
|
|
|
|
+ TCP_FIN_WAIT2,
|
|
|
|
+ TCP_TIME_WAIT,
|
|
|
|
+ TCP_CLOSE,
|
|
|
|
+ TCP_CLOSE_WAIT,
|
|
|
|
+ TCP_LAST_ACK,
|
|
|
|
+ TCP_LISTEN,
|
|
|
|
+ TCP_CLOSING, /* Now a valid state */
|
|
|
|
+ TCP_NEW_SYN_RECV,
|
|
|
|
+
|
|
|
|
+ TCP_MAX_STATES /* Leave at the end! */
|
|
};
|
|
};
|
|
----------
|
|
----------
|
|
'''
|
|
'''
|
|
@@ -124,7 +124,10 @@ def _proc4load(proto,hosts,ports):
|
|
|
|
|
|
if proto == IPPROTO_UDP:
|
|
if proto == IPPROTO_UDP:
|
|
try:
|
|
try:
|
|
- with open(PROC_UDP4,'r') as f:
|
|
|
|
|
|
+ procv = PROC_UDP4
|
|
|
|
+ if ipvers == 6:
|
|
|
|
+ procv = PROC_UDP6
|
|
|
|
+ with open(procv,'r') as f:
|
|
next(f)
|
|
next(f)
|
|
for line in f:
|
|
for line in f:
|
|
line_arrayu = _remove_empty(line.split(' '))
|
|
line_arrayu = _remove_empty(line.split(' '))
|
|
@@ -140,7 +143,10 @@ def _proc4load(proto,hosts,ports):
|
|
return 0
|
|
return 0
|
|
elif proto == IPPROTO_TCP:
|
|
elif proto == IPPROTO_TCP:
|
|
try:
|
|
try:
|
|
- with open(PROC_TCP4,'r') as f:
|
|
|
|
|
|
+ procv = PROC_TCP4
|
|
|
|
+ if ipvers == 6:
|
|
|
|
+ procv = PROC_TCP6
|
|
|
|
+ with open(procv,'r') as f:
|
|
next(f)
|
|
next(f)
|
|
for line in f:
|
|
for line in f:
|
|
line_arrayt = _remove_empty(line.split(' '))
|
|
line_arrayt = _remove_empty(line.split(' '))
|
|
@@ -159,7 +165,10 @@ def _proc4load(proto,hosts,ports):
|
|
|
|
|
|
elif proto == IPPROTO_ICMP:
|
|
elif proto == IPPROTO_ICMP:
|
|
try:
|
|
try:
|
|
- with open(PROC_ICMP4,'r') as f:
|
|
|
|
|
|
+ procv = PROC_ICMP4
|
|
|
|
+ if ipvers == 6:
|
|
|
|
+ procv = PROC_ICMP6
|
|
|
|
+ with open(procv,'r') as f:
|
|
next(f)
|
|
next(f)
|
|
for line in f:
|
|
for line in f:
|
|
line_arrayi = _remove_empty(line.split(' '))
|
|
line_arrayi = _remove_empty(line.split(' '))
|
|
@@ -191,12 +200,36 @@ def _ip(s):
|
|
return '.'.join(ip)
|
|
return '.'.join(ip)
|
|
|
|
|
|
def _ip6(s):
|
|
def _ip6(s):
|
|
- ip = [s[6:8],s[4:6],s[2:4],s[0:2],s[12:14],s[14:16],s[10:12],s[8:10],s[22:24],s[20:22],s[18:20],s[16:18],s[30:32],s[28:30],s[26:28],s[24:26]]
|
|
|
|
|
|
+ ip = [s[6:8],s[4:6],s[2:4],s[0:2],s[14:16],s[12:14],s[10:12],s[8:10],s[22:24],s[20:22],s[18:20],s[16:18],s[30:32],s[28:30],s[26:28],s[24:26]]
|
|
return ':'.join(ip)
|
|
return ':'.join(ip)
|
|
|
|
|
|
def _ip_hexrev(ip):
|
|
def _ip_hexrev(ip):
|
|
return ''.join([hex(int(x)+256)[3:] for x in ip.split('.')][::-1]).upper()
|
|
return ''.join([hex(int(x)+256)[3:] for x in ip.split('.')][::-1]).upper()
|
|
|
|
|
|
|
|
+# IPv6 /proc/net/tcp6 format from expanded ip-address
|
|
|
|
+def _to_v6_proc(s):
|
|
|
|
+ s = s.replace(":", "")
|
|
|
|
+ ip = [s[6:8],s[4:6],s[2:4],s[0:2],s[14:16],s[12:14],s[10:12],s[8:10],s[22:24],s[20:22],s[18:20],s[16:18],s[30:32],s[28:30],s[26:28],s[24:26]]
|
|
|
|
+ return ''.join(ip).upper()
|
|
|
|
+
|
|
|
|
+def expand_v6(ip):
|
|
|
|
+ ipa = ip.split(':') # liste
|
|
|
|
+
|
|
|
|
+ if '' in ipa:
|
|
|
|
+ if ipa.count('') > 1: # korr ::1 or :::
|
|
|
|
+ for i in range(ipa.count('')-1):
|
|
|
|
+ ipa.remove('')
|
|
|
|
+
|
|
|
|
+ miss = 8 - len(ipa) +1
|
|
|
|
+ for i in range(miss):
|
|
|
|
+ ipa.insert(ipa.index('')+i, '0000')
|
|
|
|
+ ipa.remove('')
|
|
|
|
+
|
|
|
|
+ return ':'.join(["%04x" % x for x in [int(x, 16) for x in ipa]])
|
|
|
|
+ else:
|
|
|
|
+ return ':'.join(["%04x" % x for x in [int(x, 16) for x in ipa]])
|
|
|
|
+
|
|
|
|
+
|
|
def _remove_empty(array):
|
|
def _remove_empty(array):
|
|
return [x for x in array if x != '']
|
|
return [x for x in array if x != '']
|
|
|
|
|
|
@@ -263,7 +296,10 @@ def doPackets(packet):
|
|
c_hash = conn_addr+'=:='+str(conn_port)
|
|
c_hash = conn_addr+'=:='+str(conn_port)
|
|
if not any(x[0] == c_hash for x in conn_cache):
|
|
if not any(x[0] == c_hash for x in conn_cache):
|
|
# get the connection info from packet
|
|
# get the connection info from packet
|
|
- spid,sexe,suid = get_conn_info(packet[0][1].proto, conn_addr, conn_port)
|
|
|
|
|
|
+ if packet[0][1].version == 4:
|
|
|
|
+ spid,sexe,suid = get_conn_info(packet[0][1].proto, conn_addr, conn_port, packet[0][1].version)
|
|
|
|
+ elif packet[0][1].version == 6:
|
|
|
|
+ spid,sexe,suid = get_conn_info(packet[0][1].nh, conn_addr, conn_port, packet[0][1].version)
|
|
if re.match("^[0-9]+$", spid):
|
|
if re.match("^[0-9]+$", spid):
|
|
program = sexe
|
|
program = sexe
|
|
pid = spid
|
|
pid = spid
|
|
@@ -354,15 +390,20 @@ def doPackets(packet):
|
|
o_sport = str(packet[0][2].dport)
|
|
o_sport = str(packet[0][2].dport)
|
|
flags = "["+packet[0].sprintf('%ICMP.type%') + "/" + packet[0].sprintf('%ICMP.code%')+"]"
|
|
flags = "["+packet[0].sprintf('%ICMP.type%') + "/" + packet[0].sprintf('%ICMP.code%')+"]"
|
|
else:
|
|
else:
|
|
- layerukn = packet[0][IP].getlayer(1)
|
|
|
|
- if layerukn is None:
|
|
|
|
- o_proto = "UNKNOWN"
|
|
|
|
- else:
|
|
|
|
- #print("Layer:", xxl1.name)
|
|
|
|
- o_proto = layerukn.name
|
|
|
|
-
|
|
|
|
- #o_proto = "UNKNOWN"
|
|
|
|
|
|
+ layerukn = packet[0][1].getlayer(1)
|
|
|
|
+ if layerukn is None:
|
|
|
|
+ o_proto = "UNKNOWN"
|
|
|
|
+ else:
|
|
|
|
+ #print("Layer:", xxl1.name)
|
|
|
|
+ o_proto = layerukn.name
|
|
|
|
|
|
|
|
+ #o_proto = "UNKNOWN"
|
|
|
|
+
|
|
|
|
+ if packet[0][1].version == 4:
|
|
|
|
+ packlen = str(packet[0][1].len)
|
|
|
|
+ if packet[0][1].version == 6:
|
|
|
|
+ packlen = str(packet[0][1].plen)
|
|
|
|
+
|
|
if o_dir == 1:
|
|
if o_dir == 1:
|
|
if numeric == False:
|
|
if numeric == False:
|
|
#if res_cache.has_key(packet[0][1].dst):
|
|
#if res_cache.has_key(packet[0][1].dst):
|
|
@@ -374,7 +415,7 @@ def doPackets(packet):
|
|
rem_name = packet[0][1].dst
|
|
rem_name = packet[0][1].dst
|
|
|
|
|
|
#return "\033[1m "+str(packet[0].time)+" "+str(program)+"\033[0m" +"/"+ str(pid) + " - " + o_proto + ": " + packet[0][1].src + ":" + o_sport + "\033[1m\033[31m ->>> \033[0m" + rem_name + ":" + o_dport + " " + flags + " Len:" + str(packet[0][1].len) + " : " + o_payload
|
|
#return "\033[1m "+str(packet[0].time)+" "+str(program)+"\033[0m" +"/"+ str(pid) + " - " + o_proto + ": " + packet[0][1].src + ":" + o_sport + "\033[1m\033[31m ->>> \033[0m" + rem_name + ":" + o_dport + " " + flags + " Len:" + str(packet[0][1].len) + " : " + o_payload
|
|
- return "\033[1m"+str(program)+"\033[0m" +"/"+ str(pid) + " - " + o_proto + ": " + packet[0][1].src + ":" + o_sport + "\033[1m\033[31m ->>> \033[0m" + rem_name + ":" + o_dport + " " + flags + " Len:" + str(packet[0][1].len) + " : " + o_payload
|
|
|
|
|
|
+ return "\033[1m"+str(program)+"\033[0m" +"/"+ str(pid) + " - " + o_proto + ": " + packet[0][1].src + ":" + o_sport + "\033[1m\033[31m ->>> \033[0m" + rem_name + ":" + o_dport + " " + flags + " Len:" + packlen + " : " + o_payload
|
|
else:
|
|
else:
|
|
if numeric == False:
|
|
if numeric == False:
|
|
#if res_cache.has_key(packet[0][1].src):
|
|
#if res_cache.has_key(packet[0][1].src):
|
|
@@ -385,7 +426,7 @@ def doPackets(packet):
|
|
else:
|
|
else:
|
|
rem_name = packet[0][1].src
|
|
rem_name = packet[0][1].src
|
|
|
|
|
|
- return "\033[1m"+str(program)+"\033[0m" +"/"+ str(pid) + " - " + o_proto + ": " + packet[0][1].dst + ":" + o_dport + "\033[1m\033[36m <<<- \033[0m" + rem_name + ":" + o_sport + " " + flags + " Len:" + str(packet[0][1].len) + " : " + o_payload
|
|
|
|
|
|
+ return "\033[1m"+str(program)+"\033[0m" +"/"+ str(pid) + " - " + o_proto + ": " + packet[0][1].dst + ":" + o_dport + "\033[1m\033[36m <<<- \033[0m" + rem_name + ":" + o_sport + " " + flags + " Len:" + packlen + " : " + o_payload
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -402,12 +443,16 @@ if not check_root():
|
|
ifaces = subprocess.getoutput("ls /sys/class/net")
|
|
ifaces = subprocess.getoutput("ls /sys/class/net")
|
|
iface_list = ifaces.split('\n')
|
|
iface_list = ifaces.split('\n')
|
|
|
|
|
|
|
|
+rfilter = "ip or ip6"
|
|
print("")
|
|
print("")
|
|
# commandline params
|
|
# commandline params
|
|
-parser = argparse.ArgumentParser(description='sisniff V'+VERSION)
|
|
|
|
|
|
+parser = argparse.ArgumentParser(description='sisniff V'+VERSION+"\n2017-2019 by sigi <https://wiki.zweiernet.ch/wiki/sisniff>",
|
|
|
|
+ formatter_class=argparse.RawDescriptionHelpFormatter)
|
|
parser.add_argument('-i', help="Interface (required)", choices=iface_list, required=True)
|
|
parser.add_argument('-i', help="Interface (required)", choices=iface_list, required=True)
|
|
parser.add_argument('-n', help="Do not resolve IP-Addresses", action="store_true")
|
|
parser.add_argument('-n', help="Do not resolve IP-Addresses", action="store_true")
|
|
parser.add_argument('-p', help='Filter by program name ([not-] negates)', type=str, metavar='program|not-program')
|
|
parser.add_argument('-p', help='Filter by program name ([not-] negates)', type=str, metavar='program|not-program')
|
|
|
|
+parser.add_argument('-4', dest='v4', help="Only IPv4", action="store_true")
|
|
|
|
+parser.add_argument('-6', dest='v6', help="Only IPv6", action="store_true")
|
|
parser.add_argument('-pH', help="Show HTTP Payload", action="store_true")
|
|
parser.add_argument('-pH', help="Show HTTP Payload", action="store_true")
|
|
parser.add_argument('-pHl', help="Show HTTP Payload, long output", action="store_true")
|
|
parser.add_argument('-pHl', help="Show HTTP Payload, long output", action="store_true")
|
|
parser.add_argument('filter', nargs='?', help="Filter (BPF syntax) on top of IP (in dbl-quotes \"...\")", type=str)
|
|
parser.add_argument('filter', nargs='?', help="Filter (BPF syntax) on top of IP (in dbl-quotes \"...\")", type=str)
|
|
@@ -415,6 +460,10 @@ args = parser.parse_args()
|
|
iface = args.i
|
|
iface = args.i
|
|
if args.n:
|
|
if args.n:
|
|
numeric = True
|
|
numeric = True
|
|
|
|
+if args.v4:
|
|
|
|
+ rfilter = "ip"
|
|
|
|
+if args.v6:
|
|
|
|
+ rfilter = "ip6"
|
|
if args.pH:
|
|
if args.pH:
|
|
payloadH = True
|
|
payloadH = True
|
|
if args.pHl:
|
|
if args.pHl:
|
|
@@ -422,16 +471,28 @@ if args.pHl:
|
|
payloadHl = True
|
|
payloadHl = True
|
|
if args.filter:
|
|
if args.filter:
|
|
fillter = " and (" + args.filter + ")"
|
|
fillter = " and (" + args.filter + ")"
|
|
- print("> Applying Filter: \"ip" + fillter + "\"")
|
|
|
|
|
|
+ print("> Applying Filter: \"" + rfilter + fillter + "\"")
|
|
if args.p:
|
|
if args.p:
|
|
filter_prog = args.p
|
|
filter_prog = args.p
|
|
|
|
|
|
|
|
|
|
-# local addresses
|
|
|
|
-MYADDRS = _remove_empty([os.popen('ip addr show '+iface).read().split("inet ")[1].split("/")[0]])
|
|
|
|
-MYADDRS.append('0.0.0.0')
|
|
|
|
-MYADDRS.append('127.0.0.1')
|
|
|
|
-xMYADDRS = [_ip_hexrev(x) for x in MYADDRS]
|
|
|
|
|
|
+# local addresses
|
|
|
|
+if args.v6:
|
|
|
|
+ MYADDRS=[]
|
|
|
|
+ xMYADDRS = []
|
|
|
|
+else:
|
|
|
|
+ MYADDRS = _remove_empty(os.popen("ip addr show " + iface + " | egrep 'inet ' | awk '{{print $2}}' | awk -F'/' '{{print $1}}'").read().split())
|
|
|
|
+ MYADDRS.append('0.0.0.0')
|
|
|
|
+ MYADDRS.append('127.0.0.1')
|
|
|
|
+ xMYADDRS = [_ip_hexrev(x) for x in MYADDRS]
|
|
|
|
+if args.v4:
|
|
|
|
+ MYADDRS6=[]
|
|
|
|
+else:
|
|
|
|
+ MYADDRS6 = _remove_empty(os.popen("ip addr show " + iface + " | egrep 'inet6' | grep -vi fe80 | awk '{{print $2}}' | awk -F'/' '{{print $1}}'").read().split())
|
|
|
|
+ MYADDRS6.append(':::')
|
|
|
|
+ MYADDRS6.append('::1')
|
|
|
|
+ MYADDRS = MYADDRS + MYADDRS6
|
|
|
|
+xMYADDRS = xMYADDRS + [_to_v6_proc(expand_v6(x)) for x in MYADDRS6]
|
|
print("> My IP-Addresses: " + str(MYADDRS))
|
|
print("> My IP-Addresses: " + str(MYADDRS))
|
|
|
|
|
|
# confirmed connections cache (ringboffer)
|
|
# confirmed connections cache (ringboffer)
|
|
@@ -442,12 +503,12 @@ cc_maxlen = 20
|
|
res_cache = {}
|
|
res_cache = {}
|
|
n_try = 3
|
|
n_try = 3
|
|
print("")
|
|
print("")
|
|
-print("Prog/PID mavericks: ?/? = No entry in /proc/net/xxx; -/- = No PID for Inode found; ./. = Inode=0;")
|
|
|
|
|
|
+print("Prog/PID mavericks: \033[1m?/?\033[0m = No entry in /proc/net/xxx; \033[1m-/-\033[0m = No PID for Inode found; \033[1m./.\033[0m = Inode=0;")
|
|
print("")
|
|
print("")
|
|
print("Program/PID: Local addr:port <<->> Remote addr:port [Flags] Len:length : [Payload]")
|
|
print("Program/PID: Local addr:port <<->> Remote addr:port [Flags] Len:length : [Payload]")
|
|
print("-------------------------------------------------------------------------------")
|
|
print("-------------------------------------------------------------------------------")
|
|
|
|
|
|
# sniff, filtering for IP traffic
|
|
# sniff, filtering for IP traffic
|
|
-sniff(filter="ip"+fillter,iface=iface,prn=doPackets, store=0)
|
|
|
|
|
|
+sniff(filter=rfilter+fillter,iface=iface,prn=doPackets, store=0)
|
|
|
|
|
|
## -- oond denn isch schloss
|
|
## -- oond denn isch schloss
|