Skip to content

Instantly share code, notes, and snippets.

@mjuenema
Last active November 14, 2020 19:37
Show Gist options
  • Save mjuenema/a60bb45734be12bd3e95a31536aa0acf to your computer and use it in GitHub Desktop.
Save mjuenema/a60bb45734be12bd3e95a31536aa0acf to your computer and use it in GitHub Desktop.

Syslog server in Python

Very basic Syslog server in Python that accepts messages in RFC3164 and RFC5424 format. This has only been tested with Rsyslog on Linux and Cisco IOS syslog. Other implementations may send mesages in slightly different format than the two regular expressions at the top of the script will match. In particular there are apparently many implementations that deviate from strict RFC3164.

from __future__ import print_function
import re
import socket
import arrow

RFC_3164 = re.compile('<(?P<pri>\d+)>\s*(?P<timestamp>\S{3}\s\d{2}\s+\d{2}:\d{2}:\d{2})\s+(?P<host>\S+)\s+(?P<tag>[^\[\s\:]+)\[*(?P<procid>\d*)\]*:*\s+(?P<msg>.*)')
RFC_5424 = re.compile('<(?P<pri>\d+)>(?P<version>\d+)\s+(?P<timestamp>\S+)\s+(?P<host>\S+)\s+(?P<tag>\S+)\s+(?P<procid>\S+)\s+(?P<msgid>\S+)\s+-\s+(?P<msg>.*)')
CISCO_IOS = re.compile('<(?P<pri>\d+)>\d*:\s*\.*(?P<timestamp>\S{3}\s\d{2}\s+\d{2}:\d{2}:\d{2}\.\d{3}):\s+(?P<tag>\S+)\s+(?P<msg>.*)')

RFC_3164_TIMEFMT = 'MMM DD HH:mm:ss'
RFC_5424_TIMEFMT = None
CISCO_IOS_TIMEFMT = 'MMM DD HH:mm:ss.SSS'


sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('', 514))

SEVERITY = {0: 'emergency',
            1: 'alert',
            2: 'critical',
            3: 'error',
            4: 'warning',
            5: 'notice',
            6: 'info',
            7: 'debug'}

FACILITY = {0: 'kernel',
            1: 'user',
            2: 'mail',
            3: 'daemon',
            4: 'auth',
            5: 'syslog',
            6: 'lpr',
            7: 'news',
            8: 'uucp',
            9: 'cron',
            10: 'authpriv',
            11: 'ftp',
            12: 'ntp',
            13: 'security',
            14: 'console',
            15: 'solaris-cron',
            16: 'local0',
            17: 'local1',
            18: 'local2',
            19: 'local3',
            20: 'local4',
            21: 'local5',
            22: 'local6',
            23: 'local7'}

while True:

    data, addr = sock.recvfrom(1500)
    NOW = arrow.now()
    srcip,sport = addr

    m = None
    for regex,timefmt in ( (RFC_3164,RFC_3164_TIMEFMT),
                           (RFC_5424, RFC_5424_TIMEFMT),
                           (CISCO_IOS, CISCO_IOS_TIMEFMT) ):
        m = regex.search(data)
        if m:
            break

    if not m:
        raise ValueError(data)

    groups = m.groupdict()
    pri = int(groups.get('pri', 0))
    facility = int(pri/8)
    severity = pri - (facility * 8)
    facility_name = FACILITY.get(facility, None)
    severity_name = SEVERITY.get(severity, None)

    version = int(groups.get('version', 0))
    timestamp = groups.get('timestamp', None)
    host = groups.get('host', srcip)
    tag = groups.get('tag', None)
    procid = groups.get('procid', None)
    msgid = groups.get('msgid', None)
    msg = groups.get('msg', None)

    if timefmt:
        timestamp = arrow.get(timestamp, timefmt).replace(year=NOW.year)
    else:
        timestamp = arrow.get(timestamp)

    # Correct timezone
    if timestamp.hour == NOW.hour and timestamp.minute == NOW.minute:
        timestamp = timestamp.replace(tzinfo=NOW.tzinfo)
    else:
        timestamp = timestamp.to(NOW.tzinfo)


    print(facility_name, severity_name, version, timestamp, host, tag, procid, msgid, msg)
    ```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment