Sisniff: Unterschied zwischen den Versionen

Aus Si:Wiki von Siegrist SystemLösungen - Informatik und Rezepte
Wechseln zu: Navigation, Suche
K
K
 
(22 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
 
{{DISPLAYTITLE:sisniff}}
 
{{DISPLAYTITLE:sisniff}}
Ein Netzwerk-Sniffer der für jedes Packet nebst Adresse und Port die lokal verbundene Anwendung und deren PID ermittelt und anzeigt.<br />
+
Ein Netzwerk-Sniffer der für jedes Packet nebst Adresse und Port die '''lokal verbundene Anwendung und deren PID''' ermittelt und anzeigt.<br />
Es wird TCP und UDP unterstützt.<br />
+
Zusätzlich kann ein Filter definiert und die Requests/Responses von HTTP Verbindungen angezeigt werden.<br />
+
''sisniff'' versucht, zu jedem Packet der Netzwerkschnittstelle die dazugehörigen Anwendung zu ermitteln.<br />
 +
Sinnvoll vor allem in einer Desktop Umgebung<br />
  
 +
Es wird TCP, UDP und ICMP unterstützt, für IPv4 und IPv6.<br />
 +
Der Sniffer akzeptiert Filter wie sie bei tcpdump üblich sind.<br />
 +
 +
Bei HTTP Verbindungen kann ausserdem ein Teil der Payload angezeigt werden.
 +
 +
[[Datei:Terminal_059.png|400px|thumb|right|sisniff Image]]
 +
  
[[Datei:Terminal_059.png|400px|thumb|right|sisniff Image]]
 
 
Die Option <code>-h</code> gibt eine Argumenteübersicht und listet die verfügbaren Interfaces auf.
 
Die Option <code>-h</code> gibt eine Argumenteübersicht und listet die verfügbaren Interfaces auf.
 
<small><pre>
 
<small><pre>
# ./sisniff.py -h
+
# ./sisniff -h
usage: sisniff.py [-h] -i {eth0,lo,tun0,wlan0} [-n] [-pH] [filter]
+
usage: sisniff [-h] -i {eth0,lo,wlan0} [-n] [-P] [-p program|not-program] [-4] [-6] [-H] [-Hl] [filter]
 +
 
 +
sisniff V1.5
 +
2017-2023 by sigi <https://wiki.zweiernet.ch/wiki/sisniff>
  
 
positional arguments:
 
positional arguments:
Zeile 16: Zeile 26:
 
optional arguments:
 
optional arguments:
 
   -h, --help            show this help message and exit
 
   -h, --help            show this help message and exit
   -i {eth0,lo,tun0,wlan0}
+
   -i {eth0,lo,wlan0}   Interface
                        Interface (mandatory)
+
 
   -n                    Do not resolve IP-Addresses
 
   -n                    Do not resolve IP-Addresses
   -pH                   Show HTTP Payload
+
   -P                    Don't put interface into promiscuous mode
 +
  -p program|not-program
 +
                        Filter by program name (accepts * pattern) ([not-] negates)
 +
  -4                    Only IPv4
 +
  -6                    Only IPv6
 +
  -H                    Show HTTP Payload
 +
  -Hl                   Show HTTP Payload, long output
 
</pre></small>
 
</pre></small>
Download der aktuellen Version: [https://www.zweiernet.ch/download/sisniff-0.7.tar.gz sisniff-0.7.tar.gz]<br />
+
<br /><p>
  
 +
;Downloads der aktuellen Version:
 +
: Download mit wget: <code>wget https://git.zweiernet.ch/sigi/sisniff/raw/master/sisniff</code><br />
 +
: gzipped: https://git.zweiernet.ch/sigi/sisniff/archive/master.tar.gz<br>
 +
: Git Projektseite: https://git.zweiernet.ch/sigi/sisniff<br />
 +
<br />
 +
<br />
  
 +
{{IBox|i|
 +
Da <code>sisniff</code> auf der Scapy <code>sniff()</code>-Funktion aufsetzt, wird Scapy > 2.x benötigt:
 +
:Unter Debian/Ubuntu: <code>apt-get install scapy</code>
 +
:pip/pip3: <code>pip install scapy</code>
 +
:Andere: http://www.secdev.org/projects/scapy/
 +
}}
 +
<br />
  
Python2 Code of sisniff.py:
+
Beispiele:
 +
<small><pre>
 +
# sisniff "port not ssh"
 +
# sisniff -p *vpn*
 +
# sisniff -i wlan0 -p not-thunderbird-bin -4 "host not www.zweiernet.ch"
 +
# sisniff -i eth0 -p firefox -Hl "port 80"
 +
</pre></small>
 +
<br />
 +
 
 +
Python Code:
  
<syntaxhighlight lang="python">
+
<small><syntaxhighlight lang="python">
#!/usr/bin/python2
+
#!/usr/bin/env python3
  
# (c) 2017 by Siegrist(SystemLoesungen) <PSS@ZweierNet.ch>
+
# (c) 2017-2022 by Siegrist(SystemLoesungen) <PSS@ZweierNet.ch>
 +
#
 +
# All Rights reserved.
 +
# This program is free software; you can redistribute it and/or
 +
# modify it under the terms of the GNU General Public License as
 +
# published by the Free Software Foundation.
 +
#
 +
# This program is distributed in the hope that it will be useful,
 +
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 +
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +
# GNU General Public License for more details.
 +
#
  
 
from scapy.all import *
 
from scapy.all import *
Zeile 41: Zeile 89:
 
import fcntl
 
import fcntl
 
import struct
 
import struct
import commands
 
 
import argparse
 
import argparse
 +
#if sys.version_info.major == 2:
 +
#    import commands as subprocess
 +
#elif sys.version_info.major == 3:
 +
#    import subprocess
 +
 +
def _to_str(inp):
 +
    if sys.version_info.major == 2:
 +
        return inp
 +
    else:
 +
        return "".join( chr(x) for x in inp)
 +
   
  
VERSION = "0.7"
+
VERSION = "1.4"
  
 
PROC_TCP4 = "/proc/net/tcp"
 
PROC_TCP4 = "/proc/net/tcp"
 
PROC_UDP4 = "/proc/net/udp"
 
PROC_UDP4 = "/proc/net/udp"
 +
PROC_ICMP4 = "/proc/net/icmp"
 
PROC_TCP6 = "/proc/net/tcp6"
 
PROC_TCP6 = "/proc/net/tcp6"
 
PROC_UDP6 = "/proc/net/udp6"
 
PROC_UDP6 = "/proc/net/udp6"
 
PROC_PACKET = "/proc/net/packet"
 
PROC_PACKET = "/proc/net/packet"
  
 +
# Services
 
TSERV = dict((TCP_SERVICES[k], k) for k in TCP_SERVICES.keys())
 
TSERV = dict((TCP_SERVICES[k], k) for k in TCP_SERVICES.keys())
 
USERV = dict((UDP_SERVICES[k], k) for k in UDP_SERVICES.keys())
 
USERV = dict((UDP_SERVICES[k], k) for k in UDP_SERVICES.keys())
  
 +
# IP Protocol Numbers (dec)
 +
IPPROTO_ICMP = 1
 +
IPPROTO_TCP = 6
 +
IPROTOP_IGP = 9
 +
IPPROTO_UDP = 17
 +
 +
nostate = set(['04','05','06''07','08','09','0C','0D'])
 
tcp_payload_hdrs = ['GET|POST|HTTP|HEAD|PUT|PATCH|DELETE|TRACE|OPTIONS|CONNECT']
 
tcp_payload_hdrs = ['GET|POST|HTTP|HEAD|PUT|PATCH|DELETE|TRACE|OPTIONS|CONNECT']
 
numeric = False
 
numeric = False
 
payloadH = False
 
payloadH = 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
     line_array = _proc4load(proto,hosts,ports)
+
   
   
+
     line_array = _proc4load(proto,hosts,ports,ipvers)
 +
   
 
     if line_array == 0:
 
     if line_array == 0:
 
         return ['?','?','?']
 
         return ['?','?','?']
Zeile 73: Zeile 142:
 
         uid = line_array[7]
 
         uid = line_array[7]
 
     '''
 
     '''
     uid = 0
+
       
 +
     inode = str(line_array[9])
 +
    if inode == "0":
 +
        return ['.','.','.']
 
      
 
      
     inode = line_array[9]                # Need the inode to get process pid.
+
     pid = _get_pid_of_inode(inode)          # try get a pid
    if inode == 0:
+
        return ['?','-','?']
+
 
      
 
      
    pid = _get_pid_of_inode(inode)
 
    if pid == "NoPid":
 
        return ["NoPid", "NoExe", uid]
 
 
      
 
      
 +
    if pid == "NoPid":
 +
        #print(">>>>>>>>>>>NoPID:" + str(hosts) +" "+ str(ports) + "//" + str(line_array))
 +
        return ['-', '-', uid]
 +
 
     try:                                            # try read the process name.
 
     try:                                            # try read the process name.
 
         exe = os.readlink('/proc/'+pid+'/exe').split('/')[-1]
 
         exe = os.readlink('/proc/'+pid+'/exe').split('/')[-1]
Zeile 88: Zeile 159:
 
         exe = None
 
         exe = None
 
      
 
      
     #print str(lhost) +" "+ str(lport) +" "+ inode +" "+ pid
+
     #print(str(lhost) +" "+ str(lport) +" "+ inode +" "+ pid)
 
     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
+
     ---- 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_ESTABLISHED = 1,
TCP_SYN_SENT,
+
    TCP_SYN_SENT,
TCP_SYN_RECV,
+
    TCP_SYN_RECV,
TCP_FIN_WAIT1,
+
    TCP_FIN_WAIT1,
TCP_FIN_WAIT2,
+
    TCP_FIN_WAIT2,
TCP_TIME_WAIT,
+
    TCP_TIME_WAIT,
TCP_CLOSE,
+
    TCP_CLOSE,
TCP_CLOSE_WAIT,
+
    TCP_CLOSE_WAIT,
TCP_LAST_ACK,
+
    TCP_LAST_ACK,
TCP_LISTEN,
+
    TCP_LISTEN,
TCP_CLOSING, /* Now a valid state */
+
    TCP_CLOSING,   /* Now a valid state */
TCP_NEW_SYN_RECV,
+
    TCP_NEW_SYN_RECV,
  
TCP_MAX_STATES /* Leave at the end! */
+
    TCP_MAX_STATES /* Leave at the end! */
 
     };
 
     };
 
     ----------
 
     ----------
 
     '''
 
     '''
     content = []
+
      
     if proto == 6:
+
    #xhosts = _ip_hexrev(hosts)
 +
    xports = _dec2hex(ports)
 +
   
 +
     if proto == IPPROTO_UDP:
 
         try:
 
         try:
             with open(PROC_TCP4,'r') as f:
+
            procv = PROC_UDP4
                 content = f.readlines()
+
            if ipvers == 6:
                 f.close()
+
                procv = PROC_UDP6
                content.pop(0)
+
             with open(procv,'r') as f:              
 +
                 next(f)
 +
                 for line in f:
 +
                    line_arrayu = _remove_empty(line.split(' '))
 +
                    l_xhost,l_xport = line_arrayu[1].split(':')
 +
                    if l_xhost not in xMYADDRS:
 +
                        continue
 +
                    if l_xport == xports:
 +
                        return line_arrayu
 +
                       
 +
                return 0
 
         except:
 
         except:
             print "open proc_tcp4 error"
+
             print("open proc_udp4 error")
 
             return 0
 
             return 0
     if proto == 17:
+
     elif proto == IPPROTO_TCP:
 
         try:
 
         try:
             with open(PROC_UDP4,'r') as f:
+
            procv = PROC_TCP4
                 content = f.readlines()
+
            if ipvers == 6:
                 f.close()
+
                procv = PROC_TCP6
                content.pop(0)
+
             with open(procv,'r') as f:
 +
                 next(f)
 +
                 for line in f:
 +
                    line_arrayt = _remove_empty(line.split(' '))
 +
                    if line_arrayt[3] in nostate:        # not some TCP state
 +
                        continue
 +
                    l_xhost,l_xport = line_arrayt[1].split(':')
 +
                    if l_xhost not in xMYADDRS:
 +
                        continue
 +
                    if l_xport == xports:
 +
                        return line_arrayt
 +
                       
 +
                return 0
 
         except:
 
         except:
             print "open proc_udp4 error"
+
             print("open proc_tcp error")
 +
            return 0
 +
   
 +
    elif proto == IPPROTO_ICMP:
 +
        try:
 +
            procv = PROC_ICMP4
 +
            if ipvers == 6:
 +
                procv = PROC_ICMP6
 +
            with open(procv,'r') as f:
 +
                next(f)
 +
                for line in f:
 +
                    line_arrayi = _remove_empty(line.split(' '))
 +
                    l_xhost,l_xport = line_arrayi[1].split(':')
 +
                    if l_xhost not in xMYADDRS:
 +
                        continue
 +
                    if l_xport == xports:
 +
                        return line_arrayi
 +
                       
 +
                return 0
 +
        except:
 +
            print("open proc_icmp4 error")
 
             return 0
 
             return 0
 
      
 
      
    for line in content:    # src
 
        line_array = _remove_empty(line.split(' '))
 
        if line_array[3] in ['04','05','06''07','08','09','0C','0D']:        # not some state
 
            continue
 
        l_host,l_port = _convert_ipv4_port(line_array[1])
 
        # alt if l_host == '127.0.0.1' or l_host not in MYADDRS:
 
        if l_host not in MYADDRS:
 
            continue
 
       
 
        if str(l_port) == str(ports):
 
            #print l_host+" "+str(l_port)+" // "+host+" "+str(port)
 
            return line_array
 
    #print "no entry in procfile found!"
 
 
     return 0
 
     return 0
  
Zeile 152: Zeile 255:
 
     host,port = array.split(':')
 
     host,port = array.split(':')
 
     return _ip(host),_hex2dec(port)
 
     return _ip(host),_hex2dec(port)
 
+
       
 
def _hex2dec(s):
 
def _hex2dec(s):
 
     return str(int(s,16))
 
     return str(int(s,16))
  
 +
def _dec2hex(p):
 +
    return hex(int(p)).split('x')[-1].upper()
 +
   
 
def _ip(s):
 
def _ip(s):
 
     ip = [(_hex2dec(s[6:8])),(_hex2dec(s[4:6])),(_hex2dec(s[2:4])),(_hex2dec(s[0:2]))]
 
     ip = [(_hex2dec(s[6:8])),(_hex2dec(s[4:6])),(_hex2dec(s[2:4])),(_hex2dec(s[0:2]))]
Zeile 161: Zeile 267:
  
 
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]]
    #print '66666:', ':'.join(ip), s
+
 
     return ':'.join(ip)
 
     return ':'.join(ip)
 +
 +
def _ip_hexrev(ip):
 +
    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 != '']
  
 
def _get_pid_of_inode(inode):
 
def _get_pid_of_inode(inode):
     for item in glob.glob('/proc/[0-9]*/fd/[0-9]*'):
+
    s_term = r'^socket\:\['+ inode +r'\]$'
 +
     for item in glob.iglob('/proc/[0-9]*/fd/[0-9]*'):
 
         try:
 
         try:
             if re.search(inode,os.readlink(item)):
+
             if re.match(s_term,os.readlink(item)):
 
                 return item.split('/')[2]
 
                 return item.split('/')[2]
 
         except:
 
         except:
Zeile 202: Zeile 335:
 
     pid = "-"     
 
     pid = "-"     
 
     uid = "-"     
 
     uid = "-"     
     o_proto = str(packet[0][1].proto)
+
     o_proto = ""
 
     o_dport = "none"
 
     o_dport = "none"
 
     o_sport = "none"
 
     o_sport = "none"
Zeile 210: Zeile 343:
 
     if packet[0][1].src in MYADDRS:
 
     if packet[0][1].src in MYADDRS:
 
         conn_addr = packet[0][1].src
 
         conn_addr = packet[0][1].src
         if packet.haslayer(TCP) or packet.haslayer(UDP):
+
         if packet.haslayer(TCP) or packet.haslayer(UDP) or packet.haslayer(ICMP):
             conn_port = packet[0][2].sport
+
             try:
 +
                conn_port = packet[0][2].sport
 +
            except:
 +
                conn_port = 99999
 
         o_dir = 1
 
         o_dir = 1
 
     else:
 
     else:
 
         conn_addr = packet[0][1].dst
 
         conn_addr = packet[0][1].dst
         if packet.haslayer(TCP) or packet.haslayer(UDP):
+
         if packet.haslayer(TCP) or packet.haslayer(UDP) or packet.haslayer(ICMP):
             conn_port = packet[0][2].dport
+
             try:
 +
                conn_port = packet[0][2].dport
 +
            except:
 +
                conn_port = 99999
 
         o_dir = 0
 
         o_dir = 0
 
      
 
      
     if packet.haslayer(TCP) or packet.haslayer(UDP):
+
     if packet.haslayer(TCP) or packet.haslayer(UDP) or packet.haslayer(ICMP):        # grrr, no info in /proc/net/icmp so far. or packet.haslayer(ICMP):
 
         # logemol casch  
 
         # logemol casch  
         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)
             if re.match("^[0-9]+$", spid):
+
            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):
 
                 program = sexe
 
                 program = sexe
 
                 pid = spid
 
                 pid = spid
Zeile 232: Zeile 373:
 
                  
 
                  
 
                 # update cache
 
                 # update cache
                 if len(conn_cache) > cc_maxlen:
+
                 if len(conn_cache) >= cc_maxlen:
 
                     conn_cache.pop(0)
 
                     conn_cache.pop(0)
 
                 conn_cache.append([c_hash,program,pid])
 
                 conn_cache.append([c_hash,program,pid])
                #print conn_cache
 
 
             else:
 
             else:
                 program = "-"
+
                 program = sexe
                 pid = "-"
+
                 pid = spid
                 uid = "-"
+
                 uid = suid
 
         else:
 
         else:
 
             # me honds fom casch
 
             # me honds fom casch
Zeile 249: Zeile 389:
 
             renew = conn_cache.pop(indx)
 
             renew = conn_cache.pop(indx)
 
             conn_cache.append(renew)
 
             conn_cache.append(renew)
 +
   
 +
    try:
 +
        filter_prog
 +
    except:
 +
        pass
 +
    else:
 +
        if filter_prog.startswith('not-'):
 +
            filter_progn = filter_prog[4:]
 +
            if filter_progn.startswith('*') and filter_progn.endswith('*') and re.search(filter_progn[1:-1], program):
 +
                return
 +
            elif filter_progn.startswith('*') and not filter_progn.endswith('*') and re.search(filter_progn[1:]+'$', program):
 +
            return
 +
            elif not filter_progn.startswith('*') and filter_progn.endswith('*') and re.match('^'+filter_progn[:-1], program):
 +
            return
 +
            elif not filter_progn.startswith('*') and not filter_progn.endswith('*') and re.match('^'+filter_progn+'$', program):
 +
                return
 +
        else:
 +
            if filter_prog.startswith('*') and filter_prog.endswith('*') and not re.search(filter_prog[1:-1], program):
 +
                return
 +
            elif filter_prog.startswith('*') and not filter_prog.endswith('*') and not re.search(filter_prog[1:]+'$', program):
 +
            return
 +
            elif not filter_prog.startswith('*') and filter_prog.endswith('*') and not re.match('^'+filter_prog[:-1], program):
 +
            return
 +
            elif not filter_prog.startswith('*') and not filter_prog.endswith('*') and not re.match('^'+filter_prog+'$', program):
 +
                return
 
          
 
          
 
      
 
      
 
     o_payload = ""
 
     o_payload = ""
 +
   
 
     if packet.haslayer(UDP):
 
     if packet.haslayer(UDP):
 
         o_proto = "UDP"
 
         o_proto = "UDP"
Zeile 263: Zeile 429:
 
             o_sport = str(packet[0][2].sport)
 
             o_sport = str(packet[0][2].sport)
 
         flags = ""
 
         flags = ""
         #o_payload = packet[0].sprintf('%10s,UDP.payload%')
+
         #o_payload = _to_str(packet[0].sprintf('%10s,UDP.payload%'))
     if packet.haslayer(TCP):
+
     elif packet.haslayer(TCP):
 
         o_proto = "TCP"
 
         o_proto = "TCP"
 
         try:
 
         try:
Zeile 277: Zeile 443:
 
         if payloadH == True:
 
         if payloadH == True:
 
             if packet.haslayer(Raw):
 
             if packet.haslayer(Raw):
                 tpld = packet[0].sprintf('%TCP.payload%')
+
                 #tpld = packet[0].sprintf('%TCP.payload%')
                 if re.match("^GET|POST|HTTP|HEAD|PUT|PATCH|DELETE|TRACE|OPTIONS|CONNECT.*", tpld[0:8]):
+
                tpld = _to_str(packet[0][TCP].load)
                     request_line, gaga = tpld.split('\r\n', 1)
+
                tpldhead = tpld[0:8]
                    o_payload = str(request_line)
+
                #print("tpld:" + tpldhead)
 +
                 if re.match(r'GET|POST|HTTP|HEAD|PUT|PATCH|DELETE|TRACE|OPTIONS|CONNECT.*', tpldhead):
 +
                     if payloadHl == True:
 +
                        o_payload = str(tpld)
 +
                    else:
 +
                        request_line, gaga = tpld.split('\r\n', 1)
 +
                        o_payload = str(request_line)
 
                     #o_payload = tpld[0:20]
 
                     #o_payload = tpld[0:20]
 +
    elif packet.haslayer(ICMP):
 +
        o_proto = "ICMP"
 +
        if conn_port == 99999:
 +
            o_dport = "-"
 +
            o_sport = "-"
 +
        else:
 +
            try:
 +
                o_dport = "\033[1m"+USERV[packet[0][2].sport]+"\033[0m"
 +
            except:
 +
                o_dport = str(packet[0][2].sport)
 +
            try:
 +
                o_sport = "\033[1m"+USERV[packet[0][2].dport]+"\033[0m"
 +
            except:
 +
                o_sport = str(packet[0][2].dport)
 +
        flags = "["+packet[0].sprintf('%ICMP.type%') + "/" + packet[0].sprintf('%ICMP.code%')+"]"
 +
    else:
 +
        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):
 +
            if packet[0][1].dst in res_cache:
 
                 rem_name = res_cache[packet[0][1].dst]
 
                 rem_name = res_cache[packet[0][1].dst]
 
             else:
 
             else:
Zeile 291: Zeile 493:
 
         else:
 
         else:
 
             rem_name = packet[0][1].dst
 
             rem_name = packet[0][1].dst
           
+
 
         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(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:" + 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):
 +
            if packet[0][1].src in res_cache:
 
                 rem_name = res_cache[packet[0][1].src]
 
                 rem_name = res_cache[packet[0][1].src]
 
             else:
 
             else:
Zeile 302: Zeile 506:
 
             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
  
  
Zeile 313: Zeile 517:
 
     conf.sniff_promisc=0
 
     conf.sniff_promisc=0
 
     conf.sniff_promisc=0
 
     conf.sniff_promisc=0
     print conf
+
     sys.exit()
    #sys.exit()
+
  
 
# get the interfaces
 
# get the interfaces
ifaces = commands.getoutput("ls /sys/class/net")
+
#ifaces = subprocess.getoutput("ls /sys/class/net")
iface_list = ifaces.split('\n')
+
#iface_list = ifaces.split('\n')
 +
iface_list = get_if_list()
 +
iface = conf.route.route("0.0.0.0")[0]
  
print
+
rfilter = "ip or ip6"
 +
print("")
 
# commandline params
 
# commandline params
parser = argparse.ArgumentParser(description='sisniff V'+VERSION)
+
parser = argparse.ArgumentParser(description='sisniff V'+VERSION+"\n2017-2022 by sigi <https://wiki.zweiernet.ch/wiki/sisniff>",
parser.add_argument('-i', help="Interface (mandatory)", choices=iface_list, required=True)
+
                                  formatter_class=argparse.RawDescriptionHelpFormatter)
 +
parser.add_argument('-i', help="Interface", choices=iface_list)
 
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('-pH', help="Show HTTP Payload", action="store_true")
+
parser.add_argument('-p', help='Filter by program name (accepts * for matching) ([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('-H', help="Show HTTP Payload", action="store_true")
 +
parser.add_argument('-Hl', 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)
 
args = parser.parse_args()
 
args = parser.parse_args()
iface = args.i
+
if args.i:
 +
iface = args.i
 
if args.n:
 
if args.n:
 
     numeric = True
 
     numeric = True
if args.pH:
+
if args.v4:
 +
rfilter = "ip"
 +
if args.v6:
 +
rfilter = "ip6"
 +
if args.H:
 
     payloadH = True
 
     payloadH = True
 +
if args.Hl:
 +
    payloadH = True
 +
    payloadHl = True
 
if args.filter:
 
if args.filter:
 
     fillter = " and (" + args.filter + ")"
 
     fillter = " and (" + args.filter + ")"
     print "> Applying Filter: \"ip" + fillter + "\""  
+
     print("\033[1m> Applying Filter: \"" + rfilter + fillter + "\"\033[0m")
 +
if args.p:
 +
    filter_prog = args.p
 +
   
  
# local addresses  
+
# local addresses
MYADDRS = _remove_empty(commands.getoutput("hostname -I").split(' '))
+
if args.v6:
MYADDRS.append('0.0.0.0')
+
MYADDRS=[]
MYADDRS.append('127.0.0.1')
+
xMYADDRS = []
print "> My IP-Addresses: " + str(MYADDRS)
+
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("> Listening on: " + iface)
  
 
# confirmed connections cache (ringboffer)
 
# confirmed connections cache (ringboffer)
Zeile 350: Zeile 586:
 
res_cache = {}
 
res_cache = {}
 
n_try = 3
 
n_try = 3
 
+
print("")
print
+
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 "Program/PID: Local addr:port <<->> Remote addr:port [Flags] Len:length : [Payload]"
+
print("")
print "-------------------------------------------------------------------------------"
+
print("Program/PID: Local addr:port <<->> Remote addr:port [Flags] Len:length : [Payload]")
 +
print("----------------------------------------------------------------------------------")
  
 
# sniff, filtering for IP traffic
 
# sniff, filtering for IP traffic
sniff(filter="ip"+fillter,iface=iface,prn=doPackets)
+
try:
 +
    sniff(filter=rfilter+fillter,iface=iface,prn=doPackets, store=0)
 +
except Exception as e:
 +
    print("\n \033[1mError: " + str(e) + "\033[0m \n")
 +
 
  
 
## -- oond denn isch schloss
 
## -- oond denn isch schloss
  
  
</syntaxhighlight>
+
</syntaxhighlight></small>

Aktuelle Version vom 30. Oktober 2023, 16:20 Uhr

Ein Netzwerk-Sniffer der für jedes Packet nebst Adresse und Port die lokal verbundene Anwendung und deren PID ermittelt und anzeigt.

sisniff versucht, zu jedem Packet der Netzwerkschnittstelle die dazugehörigen Anwendung zu ermitteln.
Sinnvoll vor allem in einer Desktop Umgebung

Es wird TCP, UDP und ICMP unterstützt, für IPv4 und IPv6.
Der Sniffer akzeptiert Filter wie sie bei tcpdump üblich sind.

Bei HTTP Verbindungen kann ausserdem ein Teil der Payload angezeigt werden.

sisniff Image


Die Option -h gibt eine Argumenteübersicht und listet die verfügbaren Interfaces auf.

# ./sisniff -h
usage: sisniff [-h] -i {eth0,lo,wlan0} [-n] [-P] [-p program|not-program] [-4] [-6] [-H] [-Hl] [filter]

sisniff V1.5
2017-2023 by sigi <https://wiki.zweiernet.ch/wiki/sisniff>

positional arguments:
  filter                Filter (BPF syntax) on top of IP (in dbl-quotes "...")

optional arguments:
  -h, --help            show this help message and exit
  -i {eth0,lo,wlan0}    Interface
  -n                    Do not resolve IP-Addresses
  -P                    Don't put interface into promiscuous mode
  -p program|not-program
                        Filter by program name (accepts * pattern) ([not-] negates)
  -4                    Only IPv4
  -6                    Only IPv6
  -H                    Show HTTP Payload
  -Hl                   Show HTTP Payload, long output

Downloads der aktuellen Version
Download mit wget: wget https://git.zweiernet.ch/sigi/sisniff/raw/master/sisniff
gzipped: https://git.zweiernet.ch/sigi/sisniff/archive/master.tar.gz
Git Projektseite: https://git.zweiernet.ch/sigi/sisniff


i

Da sisniff auf der Scapy sniff()-Funktion aufsetzt, wird Scapy > 2.x benötigt:

Unter Debian/Ubuntu: apt-get install scapy
pip/pip3: pip install scapy
Andere: http://www.secdev.org/projects/scapy/


Beispiele:

# sisniff "port not ssh"
# sisniff -p *vpn*
# sisniff -i wlan0 -p not-thunderbird-bin -4 "host not www.zweiernet.ch"
# sisniff -i eth0 -p firefox -Hl "port 80"


Python Code:

#!/usr/bin/env python3
 
# (c) 2017-2022 by Siegrist(SystemLoesungen) <PSS@ZweierNet.ch>
#
# All Rights reserved.
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
 
from scapy.all import *
import pwd
import os
import re
import glob
import sys
import string
import fcntl
import struct
import argparse
#if sys.version_info.major == 2:
#    import commands as subprocess
#elif sys.version_info.major == 3:
#    import subprocess
 
def _to_str(inp):
    if sys.version_info.major == 2:
        return inp
    else:
        return "".join( chr(x) for x in inp)
 
 
VERSION = "1.4"
 
PROC_TCP4 = "/proc/net/tcp"
PROC_UDP4 = "/proc/net/udp"
PROC_ICMP4 = "/proc/net/icmp"
PROC_TCP6 = "/proc/net/tcp6"
PROC_UDP6 = "/proc/net/udp6"
PROC_PACKET = "/proc/net/packet"
 
# Services
TSERV = dict((TCP_SERVICES[k], k) for k in TCP_SERVICES.keys())
USERV = dict((UDP_SERVICES[k], k) for k in UDP_SERVICES.keys())
 
# IP Protocol Numbers (dec)
IPPROTO_ICMP = 1
IPPROTO_TCP = 6
IPROTOP_IGP = 9
IPPROTO_UDP = 17
 
nostate = set(['04','05','06''07','08','09','0C','0D'])
tcp_payload_hdrs = ['GET|POST|HTTP|HEAD|PUT|PATCH|DELETE|TRACE|OPTIONS|CONNECT']
numeric = False
payloadH = False
payloadHl = False
fillter = ""
 
def get_conn_info(proto,hosts,ports,ipvers):
    ''' returns: pid, exe, uid '''
    uid = 0
 
    line_array = _proc4load(proto,hosts,ports,ipvers)
 
    if line_array == 0:
        return ['?','?','?']
    '''    
    try:
        uid = pwd.getpwuid(int(line_array[7]))[0]       # Get user from UID.
    except:
        uid = line_array[7]
    '''
 
    inode = str(line_array[9])
    if inode == "0":
        return ['.','.','.']
 
    pid = _get_pid_of_inode(inode)          # try get a pid
 
 
    if pid == "NoPid":
        #print(">>>>>>>>>>>NoPID:" + str(hosts) +" "+ str(ports) + "//" + str(line_array))
        return ['-', '-', uid]
 
    try:                                            # try read the process name.
        exe = os.readlink('/proc/'+pid+'/exe').split('/')[-1]
    except:
        exe = None
 
    #print(str(lhost) +" "+ str(lport) +" "+ inode +" "+ pid)
    return [pid, exe, uid]
 
 
def _proc4load(proto,hosts,ports,ipvers):
    ''' 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 states from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/include/net/tcp_states.h?id=HEAD
    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! */
    };
    ----------
    '''
 
    #xhosts = _ip_hexrev(hosts)
    xports = _dec2hex(ports)
 
    if proto == IPPROTO_UDP:
        try:
            procv = PROC_UDP4
            if ipvers == 6:
                procv = PROC_UDP6
            with open(procv,'r') as f:               
                next(f)
                for line in f:
                    line_arrayu = _remove_empty(line.split(' '))
                    l_xhost,l_xport = line_arrayu[1].split(':')
                    if l_xhost not in xMYADDRS:
                        continue
                    if l_xport == xports:
                        return line_arrayu
 
                return 0
        except:
            print("open proc_udp4 error")
            return 0
    elif proto == IPPROTO_TCP:
        try:
            procv = PROC_TCP4
            if ipvers == 6:
                procv = PROC_TCP6
            with open(procv,'r') as f:
                next(f)
                for line in f:
                    line_arrayt = _remove_empty(line.split(' '))
                    if line_arrayt[3] in nostate:        # not some TCP state
                        continue
                    l_xhost,l_xport = line_arrayt[1].split(':')
                    if l_xhost not in xMYADDRS:
                        continue
                    if l_xport == xports:
                        return line_arrayt
 
                return 0
        except:
            print("open proc_tcp error")
            return 0
 
    elif proto == IPPROTO_ICMP:
        try:
            procv = PROC_ICMP4
            if ipvers == 6:
                procv = PROC_ICMP6
            with open(procv,'r') as f:
                next(f)
                for line in f:
                    line_arrayi = _remove_empty(line.split(' '))
                    l_xhost,l_xport = line_arrayi[1].split(':')
                    if l_xhost not in xMYADDRS:
                        continue
                    if l_xport == xports:
                        return line_arrayi
 
                return 0
        except:
            print("open proc_icmp4 error")
            return 0
 
    return 0
 
def _convert_ipv4_port(array):
    host,port = array.split(':')
    return _ip(host),_hex2dec(port)
 
def _hex2dec(s):
    return str(int(s,16))
 
def _dec2hex(p):
    return hex(int(p)).split('x')[-1].upper()
 
def _ip(s):
    ip = [(_hex2dec(s[6:8])),(_hex2dec(s[4:6])),(_hex2dec(s[2:4])),(_hex2dec(s[0:2]))]
    return '.'.join(ip)
 
def _ip6(s):
    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)
 
def _ip_hexrev(ip):
    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):
    return [x for x in array if x != '']
 
def _get_pid_of_inode(inode):
    s_term = r'^socket\:\['+ inode +r'\]$'
    for item in glob.iglob('/proc/[0-9]*/fd/[0-9]*'):
        try:
            if re.match(s_term,os.readlink(item)):
                return item.split('/')[2]
        except:
            pass
    return "NoPid"
 
def _resolve_ip(host):
    """
    resolve ip und update dictionary res_cache {'ip': 'name'}.
    If resolution for a ip failed, 'name' is n_try ... 0.
    """
    try:
        hname = socket.gethostbyaddr(host)[0]
        res_cache[host] = str(hname)
        return str(hname)
    except:
        res_cache[host] = str(host)
        return str(host)
 
def check_root():
   if os.getuid() == 0:
       return True
   else:
       return False
 
## Define our Custom Action function
def doPackets(packet):
 
    program = "-"
    pid = "-"    
    uid = "-"    
    o_proto = ""
    o_dport = "none"
    o_sport = "none"
    flags = ""
 
    # only local addresses
    if packet[0][1].src in MYADDRS:
        conn_addr = packet[0][1].src
        if packet.haslayer(TCP) or packet.haslayer(UDP) or packet.haslayer(ICMP):
            try:
                conn_port = packet[0][2].sport
            except:
                conn_port = 99999
        o_dir = 1
    else:
        conn_addr = packet[0][1].dst
        if packet.haslayer(TCP) or packet.haslayer(UDP) or packet.haslayer(ICMP):
            try:
                conn_port = packet[0][2].dport
            except:
                conn_port = 99999
        o_dir = 0
 
    if packet.haslayer(TCP) or packet.haslayer(UDP) or packet.haslayer(ICMP):        # grrr, no info in /proc/net/icmp so far. or packet.haslayer(ICMP):
        # logemol casch 
        c_hash = conn_addr+'=:='+str(conn_port)
        if not any(x[0] == c_hash for x in conn_cache):
            # get the connection info from packet
            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):
                program = sexe
                pid = spid
                uid = suid
 
                # update cache
                if len(conn_cache) >= cc_maxlen:
                    conn_cache.pop(0)
                conn_cache.append([c_hash,program,pid])
            else:
                program = sexe
                pid = spid
                uid = suid
        else:
            # me honds fom casch
            indx = [x[0] for x in conn_cache].index(c_hash)
            program = conn_cache[indx][1]
            pid = conn_cache[indx][2]
            uid = 0
            # cache aktualisieren
            renew = conn_cache.pop(indx)
            conn_cache.append(renew)
 
    try:
        filter_prog
    except:
        pass
    else:
        if filter_prog.startswith('not-'):
            filter_progn = filter_prog[4:]
            if filter_progn.startswith('*') and filter_progn.endswith('*') and re.search(filter_progn[1:-1], program):
                return
            elif filter_progn.startswith('*') and not filter_progn.endswith('*') and re.search(filter_progn[1:]+'$', program):
        	    return
            elif not filter_progn.startswith('*') and filter_progn.endswith('*') and re.match('^'+filter_progn[:-1], program):
        	    return
            elif not filter_progn.startswith('*') and not filter_progn.endswith('*') and re.match('^'+filter_progn+'$', program):
                return
        else:
            if filter_prog.startswith('*') and filter_prog.endswith('*') and not re.search(filter_prog[1:-1], program):
                return
            elif filter_prog.startswith('*') and not filter_prog.endswith('*') and not re.search(filter_prog[1:]+'$', program):
        	    return
            elif not filter_prog.startswith('*') and filter_prog.endswith('*') and not re.match('^'+filter_prog[:-1], program):
        	    return
            elif not filter_prog.startswith('*') and not filter_prog.endswith('*') and not re.match('^'+filter_prog+'$', program):
                return
 
 
    o_payload = ""
 
    if packet.haslayer(UDP):
        o_proto = "UDP"
        try:
            o_dport = "\033[1m"+USERV[packet[0][2].dport]+"\033[0m"
        except:
            o_dport = str(packet[0][2].dport)
        try:
            o_sport = "\033[1m"+USERV[packet[0][2].sport]+"\033[0m"
        except:
            o_sport = str(packet[0][2].sport)
        flags = ""
        #o_payload = _to_str(packet[0].sprintf('%10s,UDP.payload%'))
    elif packet.haslayer(TCP):
        o_proto = "TCP"
        try:
            o_dport = "\033[1m"+TSERV[packet[0][2].dport]+"\033[0m"
        except:
            o_dport = str(packet[0][2].dport)
        try:
            o_sport = "\033[1m"+TSERV[packet[0][2].sport]+"\033[0m"
        except:
            o_sport = str(packet[0][2].sport)
        flags = packet[0].sprintf('%3s,TCP.flags%')
        if payloadH == True:
            if packet.haslayer(Raw):
                #tpld = packet[0].sprintf('%TCP.payload%')
                tpld = _to_str(packet[0][TCP].load)
                tpldhead = tpld[0:8]
                #print("tpld:" + tpldhead)
                if re.match(r'GET|POST|HTTP|HEAD|PUT|PATCH|DELETE|TRACE|OPTIONS|CONNECT.*', tpldhead):
                    if payloadHl == True:
                        o_payload = str(tpld)
                    else:
                        request_line, gaga = tpld.split('\r\n', 1)
                        o_payload = str(request_line)
                    #o_payload = tpld[0:20]
    elif packet.haslayer(ICMP):
        o_proto = "ICMP"
        if conn_port == 99999:
            o_dport = "-"
            o_sport = "-"
        else:
            try:
                o_dport = "\033[1m"+USERV[packet[0][2].sport]+"\033[0m"
            except:
                o_dport = str(packet[0][2].sport)
            try:
                o_sport = "\033[1m"+USERV[packet[0][2].dport]+"\033[0m"
            except:
                o_sport = str(packet[0][2].dport)
        flags = "["+packet[0].sprintf('%ICMP.type%') + "/" + packet[0].sprintf('%ICMP.code%')+"]"
    else:
        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 numeric == False:
            #if res_cache.has_key(packet[0][1].dst):
            if packet[0][1].dst in res_cache:
                rem_name = res_cache[packet[0][1].dst]
            else:
                rem_name = _resolve_ip(packet[0][1].dst)
        else:
            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(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:
        if numeric == False:
            #if res_cache.has_key(packet[0][1].src):
            if packet[0][1].src in res_cache:
                rem_name = res_cache[packet[0][1].src]
            else:
                rem_name = _resolve_ip(packet[0][1].src)
        else:
            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:" + packlen + " : " + o_payload
 
 
 
## -- Ond denn s'Hooptprogramm
 
# root check
if not check_root():
    print("This program needs root privileges !\nThats because of reading the /proc filesystem and using libpcap functions.\nSo I give up\n")
    conf.sniff_promisc=0
    conf.sniff_promisc=0
    sys.exit()
 
# get the interfaces
#ifaces = subprocess.getoutput("ls /sys/class/net")
#iface_list = ifaces.split('\n')
iface_list = get_if_list()
iface = conf.route.route("0.0.0.0")[0]
 
rfilter = "ip or ip6"
print("")
# commandline params
parser = argparse.ArgumentParser(description='sisniff V'+VERSION+"\n2017-2022 by sigi <https://wiki.zweiernet.ch/wiki/sisniff>",
                                   formatter_class=argparse.RawDescriptionHelpFormatter)
parser.add_argument('-i', help="Interface", choices=iface_list)
parser.add_argument('-n', help="Do not resolve IP-Addresses", action="store_true")
parser.add_argument('-p', help='Filter by program name (accepts * for matching) ([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('-H', help="Show HTTP Payload", action="store_true")
parser.add_argument('-Hl', 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)
args = parser.parse_args()
if args.i:
	iface = args.i
if args.n:
    numeric = True
if args.v4:
	rfilter = "ip"
if args.v6:
	rfilter = "ip6"
if args.H:
    payloadH = True
if args.Hl:
    payloadH = True
    payloadHl = True
if args.filter:
    fillter = " and (" + args.filter + ")"
    print("\033[1m> Applying Filter: \"" + rfilter + fillter + "\"\033[0m") 
if args.p:
    filter_prog = args.p
 
 
# 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("> Listening on: " + iface)
 
# confirmed connections cache (ringboffer)
conn_cache = []
cc_maxlen = 20
 
# resolver cache
res_cache = {}
n_try = 3
print("")
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("Program/PID: Local addr:port <<->> Remote addr:port [Flags] Len:length : [Payload]")
print("----------------------------------------------------------------------------------")
 
# sniff, filtering for IP traffic
try:
    sniff(filter=rfilter+fillter,iface=iface,prn=doPackets, store=0)
except Exception as e:
    print("\n \033[1mError: " + str(e) + "\033[0m \n")
 
 
## -- oond denn isch schloss