lin
2025-08-21 57113df3a0e2be01232281fad9a5f2c060567981
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#!/usr/bin/python
 
"""
usage:
./dhcp_failed_machines.py /var/log/dhcp.log
 
You can also run it directly on the gzip'd logs.
 
This script basically expects to run from the dhcp machine, as it looks at
/etc/dhcp/dhcpd.conf to be able to do reverse DNS lookups.  It also expects the
dhcp log to be copied to some local file.
 
If you're lucky, there might still be a copy of this script already on the dhcp
server at /tmp/looky.py.
"""
 
import gzip
import itertools
import pprint
import re
import sys
 
lookups = {}
 
with open('/etc/dhcp/dhcpd.conf', 'r') as f:
  for line in f:
    if line.startswith('#'):
      continue
    if line.split() and line.split()[0] == 'host':
      hostconf = list(itertools.takewhile(lambda x: x.strip() != '}', f))
      d = dict([h.strip().split()[-2:] for h in hostconf])
      hostname = d['ddns-hostname'].replace('"', '').replace(';', '')
      lookups[d['fixed-address'].replace(';', '')] = hostname
 
 
offers = {}
offenders = set()
restarts = []
 
rgx = re.compile(
  r'(?P<command>[A-Z]+) (?:from|on|for) (?P<host>\d+.\d+.\d+.\d+)')
server_restart_str = 'Internet Systems Consortium'
 
 
def open_file(f):
  if f.endswith('.gz'):
    return gzip.open(f, 'r')
  else:
    return open(f, 'r')
 
with open_file(sys.argv[1]) as f:
  for line in f:
    if server_restart_str in line:
        restarts.append(line)
        continue
    m = rgx.search(line)
    if m:
      command = m.group('command')
      host = m.group('host')
      if command == 'DHCPOFFER':
        offers[host] = offers.get(host, 0) + 1
        if offers[host] > 2:
          offenders.add(host)
      if command == 'DHCPREQUEST':
        offers[host] = 0
 
if restarts:
    print 'DHCP restarts:\n %s' % ''.join(restarts)
 
def lookup(h):
  return lookups.get(h, h)
 
hosts = sorted([lookup(h) for h in offenders])
if len(sys.argv) == 2:
  pprint.pprint(hosts)
else:
  warning = int(sys.argv[2])
  critical = int(sys.argv[3])
  if len(offenders) > critical:
    print ('DHCP Critical, number of duts with DHCP failure is %d: %s' %
           (len(hosts), ', '.join(hosts)))
    sys.exit(2)
  elif len(offenders) > warning:
    print ('DHCP Warning, number of duts with DHCP failure is %d: %s' %
           (len(hosts), ', '.join(hosts)))
    sys.exit(1)
  else:
    print ('DHCP OK, number of duts with DHCP failure is %d: %s' %
           (len(hosts), ', '.join(hosts)))
    sys.exit(0)