/
dhcp-logger.py
executable file
·135 lines (98 loc) · 3.8 KB
/
dhcp-logger.py
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#!/usr/bin/python3
# dhcp-logger.py - called from dnsmasq --dhcp-script=dhcp-logger.py
"""
man dnsmasq
--dhcp-script=<path>
Whenever a new DHCP lease is created, or an old one destroyed,
or a TFTP file transfer completes, the executable specified by
this option is run. <path> must be an absolute pathname, no
PATH search occurs. The arguments to the process are "add",
"old" or "del", the MAC address of the host (or DUID for IPv6) ,
the IP address, and the hostname, if known. "add" means a lease
has been created, "del" means it has been destroyed, "old" is a
notification of an existing lease when dnsmasq starts or a
change to MAC address or hostname of an existing lease (also,
lease length or expiry and client-id, if leasefile-ro is set).
If the MAC address is from a network type other than ethernet,
it will have the network type prepended, eg
"06-01:23:45:67:89:ab" for token ring. The process is run as
root (assuming that dnsmasq was originally run as root) even if
dnsmasq is configured to change UID to an unprivileged user.
The environment is inherited from the invoker of dnsmasq, with
some or all of the following variables added
If the client provides a hostname, DNSMASQ_SUPPLIED_HOSTNAME
dhcp-host=mac,ip,hostname
/etc/dnsmasq.d/, which is included in my dnsmasq conf:
dnsmasq ... --conf-dir=/etc/dnsmasq.d
See --dhcp-hostsdir for a way of getting new host entries read
automatically.
Primary key in leases database is IP, to "add" happens when IP address
is new, "old" for existing IP address, but other data changes.
and where the hostname comes from (client or server)
either, if both available, server overrides.
"""
# DNSMASQ_VENDOR_CLASS
import argparse
import datetime
import json
import os
def add_to_file(filename, line):
with open(filename,'a') as f:
f.write(line+'\n')
def log_me(args):
d = {}
d['timestamp'] = datetime.datetime.now().isoformat()
d['action'] = args.action
d['mac']=args.mac
d['ip']=args.ip
d['hostname']=args.hostname
d['vendor_class'] = os.getenv('DNSMASQ_VENDOR_CLASS', "no vc")
d['client_id'] = os.getenv('DNSMASQ_CLIENT_ID', "no cid")
d['tags'] = os.getenv('DNSMASQ_TAGS', "no tags")
d['mud'] = os.getenv('DNSMASQ_MUD_URL', "no mud")
d['requested_options'] = os.getenv('DNSMASQ_REQUESTED_OPTIONS', "no ra")
line = json.dumps(d)
add_to_file(args.filename, line)
def debug(args):
with open('/tmp/foo','a') as f:
f.write(args.__repr__())
f.write('\n')
f.write(os.getenv('DNSMASQ_SUPPLIED_HOSTNAME', "oh no!"))
f.write('\n')
f.write(os.getenv('DNSMASQ_VENDOR_CLASS', "oh noze!"))
f.write('\n')
def get_args():
"""
The arguments to the process are
action: one of ["add", "old", "del"],
MAC address of the host (or DUID for IPv6) ,
IP address,
hostname, if known.
"""
parser = argparse.ArgumentParser(
description="""called from dnsmasq""")
parser.add_argument('action',
help='What the server is doing.')
parser.add_argument('mac',
help='MAC address of the host.')
parser.add_argument('ip',
help='ip addresst.')
parser.add_argument('hostname',
nargs='?',
default=None)
parser.add_argument('--filename',
default="/var/log/dnsmasq/vc.jsons",
help='File to save mac/hostnames (overide for testing)')
parser.add_argument('--debug',
default=False,
help="append 'rawr' data to /tmp/foo")
args = parser.parse_args()
return args
def main():
args = get_args()
if args.debug:
debug(args)
if args.action in ["add", "old",]:
log_me(args)
if __name__ == "__main__":
main()