fwaechter
fwaechter

Reputation: 905

Parse a dhcpd.lease File with Bash

I Try to parse my dhcpd.lease File with Basel. A typical entry looks like this:

lease 192.168.20.4 {
    starts 6 2009/06/27 00:40:00;
    ends 6 2009/06/27 12:40:00;
    hardware ethernet 00:00:00:00:00:00;
    uid 00:00:00:00:00:00;
    client-hostname "examle-workstation1";
}

All information i get is the MAC and what i want ist the IP and the client-hostname. But maybe, there is no client-hostname. The entry looks like this:

lease 192.168.20.5 {
    starts 6 2009/06/27 00:40:00;
    ends 6 2009/06/27 12:40:00;
    hardware ethernet 00:00:00:00:00:00;
}

My first idea was to grep the lease attribute, the hardware ethernet attribute and the uid attribute and putt it all on one line. And then parse it.

But my problem is, i have a big file with many entries allocated in many files. The tree looks like this:

dhcpd-leases
-- 192.168.20.0
-- 192.168.30.0
-- 192.168.40.0
[...]

And all what i get ist the MACs parsed from another files in to a list. So i start with this list and want to grep the Attributes ip, mac with my MAC:

for ENTRY in $MACLIST
do
    VAR$(cat "dhcpd-leases/10.148.$NETWORK.2/dhcpd.leases" | grep -E "$MAC|lease|client-hostname")
    echo $VAR
done

But it because of the many entrys in the $VAR and the files im unable to Parse it out right.

Can somenone help?

Best regards Peter

Upvotes: 4

Views: 20077

Answers (5)

bigmac
bigmac

Reputation: 27

I like awk, but I like it less when the program gets big.

So I found another way of parsing the leases file, finding first a unix command chain that converts the file into a two columns format, the ip adress in the first column, the mac address in the second:

egrep -o 'lease.*{|ethernet.*;' dhcpd.leases | awk '{print $2}' | xargs -n 2 | cut -d ';' -f 1

with a simple awk command you can then get the ip address from the mac address. Following here is the full command built as a shell function:

function f_mac_to_ip {

parseResult=$(egrep -o 'lease.*{|ethernet.*;' /var/lib/dhcp/db/dhcpd.leases | awk '{print $2}' | xargs -n 2 | cut -d ';' -f 1  | grep $1 | awk '{print $1}')
    echo "$parseResult"
}

I don't know much about the leases format. If ever there can be entries without an "ethernet" field, the above parsing wouldn't work.

Upvotes: 1

Topper Harley
Topper Harley

Reputation: 12384

Not necessarily better than @ghostdog74, but here's a script to convert to json:

#!/usr/bin/awk -f

# Start with array creation
BEGIN {
    printf "[";
}

# New lease: start object 
/^lease/ {
    # If that ip is unknown, create a new JSON object
    if (!known[$2]) {
        # if this object is not the first, print a comma
        if (!notFirst) {
            notFirst=1;
        } else {
            printf ",";
        }

        # create a new JSON object with the first key being the IP (column 2)
        printf "{\"ip\":\"%s\"", $2; known[$2]=1;

        # print subsequent lines, see below
        p=1;
    }
}

# If printing is enabled print line as a JSON key/value pair
p && /^  / {
    # Print key (first word)
    printf ",\"%s\":", $1;

    # Clean up the rest of the line: trim whitespace and trailing ;, remove " and escape \
    $1="";
    gsub(/\\/, "\\\\", $0);
    gsub(/"/, "", $0);
    gsub(/^[\t ]*/, "", $0);
    gsub(/;$/, "", $0);
    printf "\"%s\"", $0;
}

# End of lease: close JSON object and disable printing
/^\}$/ {
    if (p) {
        printf "}"
    }
    p=0
}

# Close the JSON array
END {
    print "]";
}

Result:

$ /opt/dhcpd.leases_to_json.awk /var/lib/dhcp/dhcpd.leases | jq .
[
  {
    "ip": "10.7.37.10",
    "starts": "3 2019/08/28 22:24:26",
    "ends": "3 2019/08/28 22:34:26",
    "cltt": "3 2019/08/28 22:25:32",
    "binding": "state active",
    "next": "binding state free",
    "rewind": "binding state free",
    "hardware": "ethernet xx:xx:xx:xx:xx:xx",
    "client-hostname": "zzzzzzz"
  },
  {
    "ip": "10.7.37.11",
    "starts": "3 2019/08/28 22:26:10",
    "ends": "3 2019/08/28 22:36:10",
    "cltt": "3 2019/08/28 22:26:10",
    "binding": "state active",
    "next": "binding state free",
    "rewind": "binding state free",
    "hardware": "ethernet xx:xx:xx:xx:xx:xx",
    "uid": "\\001pv\\377\\001\\005~",
    "client-hostname": "xxxx"
  }
]

Upvotes: 0

t0mm13b
t0mm13b

Reputation: 34592

If you are trying to get the MAC's and IP's, it would be better to use the arp -s command instead of looking at the DHCP lease file.

Upvotes: 1

Beau
Beau

Reputation: 11378

Text::DHCPLeases would also do exactly what you need, without reinventing the wheel. :)

Upvotes: 0

ghostdog74
ghostdog74

Reputation: 343067

assuming your maclist file look like this (just one entry for example)

$ cat maclist
00:00:00:00:00:01

and your lease file like this

$ cat file
lease 192.168.20.4 {
    starts 6 2009/06/27 00:40:00;
    ends 6 2009/06/27 12:40:00;
    hardware ethernet 00:00:00:00:00:00;
    uid 00:00:00:00:00:00;
    client-hostname "examle-workstation1";
}

lease 192.168.20.5 {
    starts 6 2009/06/27 00:40:00;
    ends 6 2009/06/27 12:40:00;
    hardware ethernet 00:00:00:00:00:00;
}

lease 192.168.20.6 {
    starts 6 2009/06/27 00:40:00;
    ends 6 2009/06/27 12:40:00;
    hardware ethernet 00:00:00:00:00:01;
    uid 00:00:00:00:00:01;
    client-hostname "examle-workstation2";
}


lease 192.168.20.7 {
    starts 6 2009/06/27 00:40:00;
    ends 6 2009/06/27 12:40:00;
    hardware ethernet 01:00:00:00:00:00;
}

you can try this

awk 'BEGIN{
    while( (getline line < "maclist") > 0){
        mac[line]
    }
    RS="}"
    FS="\n"
}
/lease/{
    for(i=1;i<=NF;i++){
        gsub(";","",$i)
        if ($i ~ /lease/) {
            m=split($i, IP," ")
            ip=IP[2]
        }
        if( $i ~ /hardware/ ){
            m=split($i, hw," ")
            ether=hw[3]
        }
        if ( $i ~ /client-hostname/){
            m=split($i,ch, " ")
            hostname=ch[2]
        }
        if ( $i ~ /uid/){
            m=split($i,ui, " ")
            uid=ui[2]
        }
    }
    if ( ether in mac ){
        print "ip: "ip " hostname: "hostname " ether: "ether " uid: "uid
    }
} ' file

output

$ ./shell.sh
hostname: "examle-workstation2" ether: 00:00:00:00:00:01 uid: 00:00:00:00:00:01

Upvotes: 5

Related Questions