From 113bf37609ad62578f2bc783886a7b3a0da48d25 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sven=20M=C3=A4der?= <maeder@phys.ethz.ch>
Date: Fri, 14 Dec 2018 13:47:05 +0100
Subject: [PATCH] Add slaptail

---
 bin/slaptail.py | 142 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 142 insertions(+)
 create mode 100755 bin/slaptail.py

diff --git a/bin/slaptail.py b/bin/slaptail.py
new file mode 100755
index 0000000..6a774d3
--- /dev/null
+++ b/bin/slaptail.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python3
+
+import sys
+import time
+import subprocess
+import select
+import re
+import argparse
+
+update_every = 0.001
+log_path = '/var/log/'
+log_file = 'slapd'
+log_file_path = log_path + log_file
+rgx = dict()
+connections = dict()
+rgx['conn'] = re.compile(r'conn=(?P<conn>[0-9]+) .*?=.*? (?P<closed>closed)?')
+
+
+def sleep(start_time):
+    """After hard work, take a nap"""
+    current_time = time.perf_counter()
+    elapsed_time = current_time - start_time
+    sleep_time = update_every - elapsed_time
+
+    if sleep_time > 0:
+        time.sleep(sleep_time)
+
+
+def parse(line):
+    """Parse line and print"""
+    connect = rgx['connect'].search(line)
+
+    if(connect):
+        ip = connect.group('ip')
+        port = connect.group('port')
+        connection_id = connect.group('conn')
+
+        if connection_id not in connections:
+            connections[connection_id] = ip, port
+
+        print(len(connections), ip, port, line, end='')
+
+    else:
+        conn = rgx['conn'].search(line)
+
+        if(conn):
+            connection_id = conn.group('conn')
+
+            if connection_id in connections:
+                ip, port = connections[connection_id]
+
+                print(len(connections), ip, port, line, end='')
+
+                if conn.group('closed'):
+                    del connections[connection_id]
+
+
+def tail_input(fin):
+    """Open input file in tail mode"""
+    poll = select.poll()
+    poll.register(fin.stdout)
+
+    try:
+        while True:
+            start_time = time.perf_counter()
+
+            if poll.poll(1):
+                line = fin.stdout.readline().decode('utf-8')
+
+                parse(line)
+
+            sleep(start_time)
+
+    except KeyboardInterrupt:
+        sys.stdout.flush()
+        pass
+
+
+def read_input(fin):
+    """Read from input file"""
+    try:
+        for line in fin:
+            parse(line)
+    except KeyboardInterrupt:
+        sys.stdout.flush()
+        pass
+
+
+def main():
+    """Open file in non blocking mode and parse it"""
+    parser = argparse.ArgumentParser(
+        add_help=False,
+        description='Parse from file or stdin'
+    )
+    parser.add_argument(
+        '-f', '--follow',
+        dest='follow', action='store_const', const=True,
+        help='Output appended data as the file grows'
+    )
+    parser.add_argument(
+        'pattern',
+        type=str,
+        help='Regex pattern'
+    )
+    parser.add_argument(
+        'file',
+        nargs='?', type=str,
+        help='File to open'
+    )
+    parser.add_argument(
+        '-h', '--help',
+        action='help',
+        help='Show this help message and exit'
+    )
+    arg = vars(parser.parse_args())
+
+    rgx['connect'] = re.compile(''.join([r'conn=(?P<conn>[0-9]+).+?ACCEPT from IP=(?P<ip>',
+                                arg['pattern'], r'):[0-9]+ \(IP=0\.0\.0\.0:(?P<port>[0-9]+)\)']))
+
+    if arg['follow']:
+        if arg['file']:
+            path = arg['file']
+        else:
+            path = log_file_path
+
+        fin = subprocess.Popen(['tail', '-F', path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        tail_input(fin)
+
+    else:
+        if arg['file']:
+            with open(arg['file'], 'r') as fin:
+                read_input(fin)
+        else:
+            fin = sys.stdin
+            read_input(fin)
+
+    sys.exit(0)
+
+
+if __name__ == '__main__':
+    main()
+    sys.exit(0)
-- 
GitLab