egrep, sed oder awk, um die Anzahl der aktiven DHCP-Leases zu ermitteln?

egrep, sed oder awk, um die Anzahl der aktiven DHCP-Leases zu ermitteln?

Nehmen wir an, ich habe die folgende Datei dhcpd.leases:

# The format of this file is documented in the dhcpd.leases(5) manual page.
# This lease file was written by isc-dhcp-4.3.6-P1

# authoring-byte-order entry is generated, DO NOT DELETE
authoring-byte-order little-endian;

lease 10.1.1.108 {
  ...
  starts 3 2020/03/04 08:23:54;
  ends 3 2020/03/04 13:49:03;
  tstp 3 2020/03/04 13:49:03;
  cltt 3 2020/03/04 08:23:54;
  binding state free;
  ...
}
lease 10.1.1.109 {
  ...
  starts 3 2020/03/04 13:43:00;
  ends 3 2020/03/04 13:49:44;
  tstp 3 2020/03/04 13:49:44;
  cltt 3 2020/03/04 13:43:00;
  binding state free;
  ...
}
lease 10.1.2.100 {
  ...
  starts 6 2020/03/28 12:49:45;
  ends 0 2020/03/29 12:49:45;
  tstp 0 2020/03/29 12:49:45;
  cltt 6 2020/03/28 12:49:45;
  binding state active;
  ...
lease 10.1.1.104 {
  ...
  starts 6 2020/03/28 18:53:45;
  ends 0 2020/03/29 18:53:45;
  tstp 0 2020/03/29 18:53:45;
  cltt 6 2020/03/28 18:53:45;
  binding state active;
  ...
}

Ich möchte die Anzahl der aktiven DHCP-Leases für jedes Subnetz extrahieren, in diesem Beispiel etwa so:

10.1.1.0/24: 1
10.1.2.0/24: 1

Nun, ich habe hier zahlreiche Fragen zur Datei dhcpd.leases gesehen, aber die meisten Antworten beziehen sich auf die Ausgabe der Mac-Adresse für jede IP, was hier nicht das ist, wonach ich suche. Das Problem mit den Befehlen, die ich ausprobiert habe, ist, dass ich nicht herausfinden kann, wie ich die inaktiven Leases vollständig ausschließen kann, nicht herausfinden kann, wie ich die Subnetze aufteile, und nicht herausfinden kann, welches Tool ich dafür wirklich verwenden sollte.

Jede Hilfe wäre willkommen.

Hier sind einige Sachen, die ich ausprobiert habe. Ich habe keine Ahnung, ob ich auf dem richtigen Weg bin. Ich habe stundenlang mit diesen Befehlen herumgespielt ...

egrep "lease|active|\}" /var/dhcpd/var/db/dhcpd.leases
sed -e '/lease/,/active/!d' /var/dhcpd/var/db/dhcpd.leases
awk 'BEGIN{FS="\n"; RS="}";} {print $2}' /var/dhcpd/var/db/dhcpd.leases

Tut jedoch nicht wirklich das, was ich möchte.

Hinweis: Ich verwende pfSense (FreeBSD).

Antwort1

Also gut, nach weiteren Recherchen habe ich beschlossen, dieses Python-Skript für meine Zwecke anzupassen: https://askubuntu.com/questions/219609/wie-zeige-ich-aktive-dhcp-leases/553387#553387

Außerdem ist meine Netzwerktopologie hier bekannt, festgelegt und ändert sich nicht, sodass die kleine Mathematik, die ich am Ende mache, dies berücksichtigt, aber Sie können es leicht nach Bedarf ändern. Und schließlich, da all dies letztendlich für ein Checkmk-Überwachungsdiagrammskript war, wird die Ausgabe so präsentiert, wie Checkmk sie zum Parsen benötigt. Wie auch immer, ohne weitere Umschweife, hier ist sie:

#!/usr/bin/python
import datetime, bisect

def left(s, amount):
    return s[:amount]

def right(s, amount):
    return s[-amount:]

def mid(s, offset, amount):
    return s[offset:offset+amount]

def parse_timestamp(raw_str):
        tokens = raw_str.split()

        if len(tokens) == 1:
                if tokens[0].lower() == 'never':
                        return 'never';
                else:
                        raise Exception('Parse error in timestamp')
        elif len(tokens) == 3:
                return datetime.datetime.strptime(' '.join(tokens[1:]),'%Y/%m/%d %H:%M:%S')
        else:
                raise Exception('Parse error in timestamp')

def timestamp_is_ge(t1, t2):
        if t1 == 'never':
                return True
        elif t2 == 'never':
                return False
        else:
                return t1 >= t2

def timestamp_is_lt(t1, t2):
        if t1 == 'never':
                return False
        elif t2 == 'never':
                return t1 != 'never'
        else:
                return t1 < t2

def timestamp_is_between(t, tstart, tend):
        return timestamp_is_ge(t, tstart) and timestamp_is_lt(t, tend)

def parse_hardware(raw_str):
        tokens = raw_str.split()

        if len(tokens) == 2:
                return tokens[1]
        else:
                raise Exception('Parse error in hardware')

def strip_endquotes(raw_str):
        return raw_str.strip('"')

def identity(raw_str):
        return raw_str

def parse_binding_state(raw_str):
        tokens = raw_str.split()

        if len(tokens) == 2:
                return tokens[1]
        else:
                raise Exception('Parse error in binding state')

def parse_next_binding_state(raw_str):
        tokens = raw_str.split()

        if len(tokens) == 3:
                return tokens[2]
        else:
                raise Exception('Parse error in next binding state')

def parse_rewind_binding_state(raw_str):
        tokens = raw_str.split()

        if len(tokens) == 3:
                return tokens[2]
        else:
                raise Exception('Parse error in next binding state')

def parse_leases_file(leases_file):
        valid_keys = {
                'starts':               parse_timestamp,
                'ends':                 parse_timestamp,
                'tstp':                 parse_timestamp,
                'tsfp':                 parse_timestamp,
                'atsfp':                parse_timestamp,
                'cltt':                 parse_timestamp,
                'hardware':             parse_hardware,
                'binding':              parse_binding_state,
                'next':                 parse_next_binding_state,
                'rewind':               parse_rewind_binding_state,
                'uid':                  strip_endquotes,
                'client-hostname':      strip_endquotes,
                'option':               identity,
                'set':                  identity,
                'on':                   identity,
                'abandoned':            None,
                'bootp':                None,
                'reserved':             None,
                }

        leases_db = {}
        lease_rec = {}
        in_lease = False
        in_failover = False

        for line in leases_file:
                if line.lstrip().startswith('#'):
                        continue

                tokens = line.split()

                if len(tokens) == 0:
                        continue

                key = tokens[0].lower()

                if key == 'lease':
                        if not in_lease:
                                ip_address = tokens[1]
                                lease_rec = {'ip_address' : ip_address}
                                in_lease = True
                        else:
                                raise Exception('Parse error in leases file')

                elif key == 'failover':
                        in_failover = True
                elif key == '}':
                        if in_lease:
                                for k in valid_keys:
                                        if callable(valid_keys[k]):
                                                lease_rec[k] = lease_rec.get(k, '')
                                        else:
                                                lease_rec[k] = False

                                ip_address = lease_rec['ip_address']

                                if ip_address in leases_db:
                                        leases_db[ip_address].insert(0, lease_rec)
                                else:
                                        leases_db[ip_address] = [lease_rec]

                                lease_rec = {}
                                in_lease = False
                        elif in_failover:
                                in_failover = False
                                continue
                        else:
                                raise Exception('Parse error in leases file')
                elif key in valid_keys:
                        if in_lease:
                                value = line[(line.index(key) + len(key)):]
                                value = value.strip().rstrip(';').rstrip()

                                if callable(valid_keys[key]):
                                        lease_rec[key] = valid_keys[key](value)
                                else:
                                        lease_rec[key] = True
                        else:
                                raise Exception('Parse error in leases file')
                else:
                        if in_lease:
                                raise Exception('Parse error in leases file')
        if in_lease:
                raise Exception('Parse error in leases file')
        return leases_db

def round_timedelta(tdelta):
        return datetime.timedelta(tdelta.days,
                tdelta.seconds + (0 if tdelta.microseconds < 500000 else 1))

def timestamp_now():
        n = datetime.datetime.utcnow()
        return datetime.datetime(n.year, n.month, n.day, n.hour, n.minute,
                n.second + (0 if n.microsecond < 500000 else 1))

def lease_is_active(lease_rec, as_of_ts):
        return timestamp_is_between(as_of_ts, lease_rec['starts'],
                lease_rec['ends'])

def ipv4_to_int(ipv4_addr):
        parts = ipv4_addr.split('.')
        return (int(parts[0]) << 24) + (int(parts[1]) << 16) + \
                (int(parts[2]) << 8) + int(parts[3])

def select_active_leases(leases_db, as_of_ts):
        retarray = []
        sortedarray = []

        for ip_address in leases_db:
                lease_rec = leases_db[ip_address][0]

                if lease_is_active(lease_rec, as_of_ts):
                        ip_as_int = ipv4_to_int(ip_address)
                        insertpos = bisect.bisect(sortedarray, ip_as_int)
                        sortedarray.insert(insertpos, ip_as_int)
                        retarray.insert(insertpos, lease_rec)
        return retarray

myfile = open('/var/dhcpd/var/db/dhcpd.leases', 'r')
leases = parse_leases_file(myfile)
myfile.close()

now = timestamp_now()
report_dataset = select_active_leases(leases, now)
lan_leases = sum(map(lambda x : left(x['ip_address'],7)=='10.1.1.', report_dataset))
wlan_leases = sum(map(lambda x : left(x['ip_address'],8)=='10.20.1.', report_dataset))
wlan_guest_leases = sum(map(lambda x : left(x['ip_address'],8)=='10.20.2.', report_dataset))
wlan_appliance_leases = sum(map(lambda x : left(x['ip_address'],8)=='10.20.3.', report_dataset))

print('0 dhcp_leases lan_leases=' + str(lan_leases) + '|wlan_leases=' + str(wlan_leases) + '|wlan_guest_leases=' + str(wlan_guest_leases) + '|wlan_appliance_leases=' + str(wlan_appliance_leases) + ' ' + str(lan_leases) + ' LAN lease(s), ' + str(wlan_leases) + ' WLAN lease(s), ' + str(wlan_guest_leases) + ' WLAN_GUEST lease(s), ' + str(wlan_appliance_leases) + ' WLAN_APPLIANCE lease(s)')

verwandte Informationen