--- a/pvl/syslog/dhcp.py Fri Jan 25 22:02:55 2013 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,191 +0,0 @@
-"""
- Parse ISC dhcpd messages in syslog.
-"""
-
-import re
-
-class DHCPSyslogFilter (object) :
- """
- Parse SyslogMessages from SyslogParser for ISC dhcp semantics.
- """
-
- ## various message types sent/recieved by dhcpd
- # from server/dhcp.c
- TYPE_NAMES = (
- "DHCPDISCOVER",
- "DHCPOFFER",
- "DHCPREQUEST",
- "DHCPDECLINE",
- "DHCPACK",
- "DHCPNAK",
- "DHCPRELEASE",
- "DHCPINFORM",
- "type 9",
- "DHCPLEASEQUERY",
- "DHCPLEASEUNASSIGNED",
- "DHCPLEASEUNKNOWN",
- "DHCPLEASEACTIVE"
- )
-
- # message-parsing regexp..
- RECV_MESSAGE_RE = (
- # dhcpdiscover/ack_lease: info/error
- # hwaddr: <no identifier>
- # hostname: Hostname Unsuitable for Printing
- # error:
- # peer holds all free leases
- # network %s: no free leases
- re.compile(r'(?P<type>DHCPDISCOVER) from (?P<hwaddr>.+?)( \((?P<hostname>.+?)\))? via (?P<gateway>.+?)(: (?P<error>.+?))?$'),
-
- # dhcprequest
- # error:
- # wrong network.
- # ignored (not authoritative).
- # ignored (unknown subnet).
- # lease %s unavailable.
- # unknown lease %s.
- re.compile(r'(?P<type>DHCPREQUEST) for (?P<lease>.+?)( \((?P<server>.+?)\))? from (?P<hwaddr>.+?)( \((?P<hostname>.+?)\))? via (?P<gateway>.+?)(: (?P<error>.+?))?$'),
-
- # dhcprelease
- re.compile(r'(?P<type>DHCPRELEASE) of (?P<lease>.+?) from (?P<hwaddr>.+?)( \((?P<hostname>.+?)\))? via (?P<gateway>.+?) \((?P<found>.+?)\)$'),
-
- # dhcpdecline
- # status:
- # abandoned
- # not found
- # ignored
- re.compile(r'(?P<type>DHCPDECLINE) of (?P<lease>.+?) from (?P<hwaddr>.+?)( \((?P<hostname>.+?)\))? via (?P<gateway>.+?): (?P<status>.+?)$'),
-
- # dhcpinform
- # error:
- # ignored (null source address).
- # unknown subnet for relay address %s
- # unknown subnet for %s address %s
- # not authoritative for subnet %s
- re.compile(r'(?P<type>DHCPINFORM) from (?P<lease>.+?) via (?P<gateway>.+?)(: (?P<error>.+?))?$'),
-
- # dhcpleasequery
- re.compile(r'(?P<type>DHCPLEASEQUERY) from (?P<server>.+?)( for (?P<key_type>IP|client-id|MAC address) (?P<key>.+?))?(: (?P<error>.+?))?$'),
-
- # dhcp: generic/unknown packet
- re.compile(r'(?P<type>\w+) from (?P<hwaddr>.+?) via (?P<gateway>.+?): (?P<error>.+?)$'),
- )
-
- SEND_MESSAGE_RE = (
- # dhcp_reply
- re.compile(r'(?P<type>DHCPACK|DHCPOFFER|BOOTREPLY) on (?P<lease>.+?) to (?P<hwaddr>.+?)( \((?P<hostname>.+?)\))? via (?P<gateway>.+?)$'),
-
- # dhcpinform
- # hwaddr: <no client hardware address>
- re.compile(r'(?P<type>DHCPACK) to (?P<lease>.+?) \((?P<hwaddr>.+?)\) via (?P<gateway>.+?)$'),
-
- # nak_lease
- re.compile(r'(?P<type>DHCPNAK) on (?P<lease>.+?) to (?P<hwaddr>.+?) via (?P<gateway>.+?)$'),
-
- # dhcpleasequery
- re.compile(r'(?P<type>DHCPLEASEUNKNOWN|DHCPLEASEACTIVE|DHCPLEASEUNASSIGNED) to (?P<lease>.+?) for (?P<key_type>IP|client-id|MAC address) (?P<key>.+?) \((?P<count>\d+) associated IPs\)$'),
- )
-
- MESSAGE_ERROR_RE = (
- ('peer-all-free-leases', re.compile('peer holds all free leases')),
- ('no-free-leases', re.compile(r'network (?P<network>.+?): no free leases')),
- ('wrong-network', re.compile(r'wrong network')),
- ('ignored-not-auth', re.compile(r'ignored \(not authoritative\)')),
- ('ignored-unknown-subnet', re.compile(r'ignored \(unknown subnet\)')),
- ('lease-unavailable', re.compile(r'lease (?P<lease>.+?) unavailable')),
- ('lease-unknown', re.compile(r'unknown lease (?P<lease>.+?).$')),
- )
-
- ERROR_RE = (
- # find_lease
- ('duplicate-uid-lease',
- re.compile(r'uid lease (?P<client>.+?) for client (?P<hwaddr>.+?) is duplicate on (?P<shared_network>.+?)$')),
-
- # dhcprelease
- ('dhcprelease-requested-address',
- re.compile(r'DHCPRELEASE from (?P<hwaddr>.+?) specified requested-address.')),
-
- # ???
- ('unexpected-icmp-echo-reply',
- re.compile(r'unexpected ICMP Echo Reply from (?P<client>.+?)$')),
-
- ('host-unknown',
- re.compile(r'(?P<host>.+?): host unknown.')),
- )
-
- IGNORE_RE = (
- re.compile(r'Wrote (?P<count>\d+) (?P<what>.+?) to leases file.'),
- )
-
- def parse (self, line) :
- """
- Match line against our regexps, returning a
-
- {
- tag: send/recv/error,
- type: ...,
- [error]: ...,
- ...
- }
-
- dict if matched
-
- Returns False if the message is ignored, or None if the no regexp matched.
- """
-
- for tag, re_list in (
- ('recv', self.RECV_MESSAGE_RE),
- ('send', self.SEND_MESSAGE_RE),
- ) :
- for re in re_list :
- # test
- match = re.match(line)
-
- if match :
- data = match.groupdict()
- data['tag'] = tag
-
- return data
-
- # error?
- for type, re in self.ERROR_RE:
- match = re.match(line)
-
- if match :
- data = match.groupdict()
- data['tag'] = 'error'
- data['type'] = type
-
- return data
-
- # ignore
- for re in self.IGNORE_RE :
- if re.match(line) :
- # ignore
- return False
-
- # unknown
- return None
-
- def parse_error (self, error) :
- """
- Match given error status from send/recv against known types, returning a type name or None.
- """
-
- for type, re in self.MESSAGE_ERROR_RE :
- match = re.match(error)
-
- if match :
- return type
-
- # nope
- return None
-
-if __name__ == '__main__' :
- import logging
-
- logging.basicConfig()
-
- import doctest
- doctest.testmod()
-