-
Notifications
You must be signed in to change notification settings - Fork 1
/
fakedhcpv6d.lua
163 lines (144 loc) · 4.95 KB
/
fakedhcpv6d.lua
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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#!/usr/bin/env lua
-- -*-lua-*-
--
-- $Id: fakedhcpv6d.lua $
--
-- Author: Markus Stenberg <markus [email protected]>
--
-- Copyright (c) 2013 cisco Systems, Inc.
--
-- Created: Thu Feb 21 11:47:15 2013 mstenber
-- Last modified: Wed Sep 25 11:19:40 2013 mstenber
-- Edit time: 74 min
--
-- This is very, very minimal fake DHCPv6 PD server; what it does, is
-- provide a canned reply to stateful DHCPv6 request flows, and
-- ignores anything else (information requests, relayed messages)
require 'mcastjoiner'
require 'dhcpv6_codec'
require 'scb'
require 'ssloop'
require 'dns_db'
require 'mst_cliargs'
local dhcpv6_message = dhcpv6_codec.dhcpv6_message
local loop = ssloop.loop()
local args = mst_cliargs.parse{
options={
{name='dns', desc='IPv6 DNS server', max=10, default={}},
{name='search', desc='IPv6 search path', max=10, default={}},
{name='join', desc='interface to join multicast group on', min=1, max=10},
{name='port', desc='specify port to use',
default=tostring(dhcpv6_const.SERVER_PORT)},
{name='pref', desc='set preferred lifetime', default='123'},
{name='valid', desc='set valid lifetime', default='234'},
{value='prefix', desc='IPv6 prefix to provide to PD requests (static) with = used as separator for class (if any)', max=10, default={}},
}
}
local port = tonumber(args.port)
local o, err = scb.new_udp_socket{ip='*',
port=port,
callback=true,
v6only=true,
}
mst.a(o, 'unable to create scb udp socket', err)
mst.d(' created socket on port', port)
local s = o.s
local _mcj = mcastjoiner.mcj
local j = _mcj:new{mcast6=dhcpv6_const.ALL_RELAY_AGENTS_AND_SERVERS_ADDRESS,
mcasts=s,
}
local joinset = mst.array_to_table(args.join)
mst.d(' calling set_if_joined_set', joinset)
j:set_if_joined_set(joinset)
-- parse the arguments
local prefix2class = {}
for i, pa in ipairs(args.prefix)
do
local pref, class = unpack(mst.string_split(pa, '=', 2))
mst.a(type(pref) == 'string')
prefix2class[pref] = class or false
end
function o.callback(data, src, srcport)
mst.d('got callback', #data, src, srcport, mst.string_to_hex(data))
-- handle address
local l = mst.string_split(src, '%')
if #l ~= 2
then
mst.d('weird source address - global?', src)
return
end
local addr, ifname = unpack(l)
-- handle payload
local o, err = dhcpv6_message:decode(data)
mst.a(o, 'decode error', err)
mst.d('decoded', o)
if o.type >= dhcpv6_const.MT_REPLY
then
mst.d('got weird message, ignoring it', o)
return
end
-- What do we need to do?
local o2 = {--type
type=(o.type == dhcpv6_const.MT_SOLICIT
and dhcpv6_const.MT_ADVERTISE -- only to solicits
or dhcpv6_const.MT_REPLY -- otherwise
),
-- transaction id
xid=o.xid,
-- server id
[1] = {option=dhcpv6_const.O_SERVERID,
data="0001000118b4e92e4e65b47f205e"},
}
for i, v in ipairs(o)
do
if v.option == dhcpv6_const.O_CLIENTID
then
-- - copy O_CLIENTID
table.insert(o2, v)
elseif v.option == dhcpv6_const.O_IA_PD
then
local pref = tonumber(args.pref) or v.t1
mst.a(pref, 'invalid preference value')
local valid = tonumber(args.valid) or v.t2
mst.a(valid, 'invalid valid value')
local v2 = {option=v.option,
iaid=v.iaid,
t1=pref / 2,
t2=pref}
-- produce IA_PD with IAPREFIXes
table.insert(o2, v2)
for prefix, class in pairs(prefix2class)
do
local v3 = {option=dhcpv6_const.O_IAPREFIX,
preferred=pref,
valid=valid,
prefix=prefix}
table.insert(v2, v3)
-- add class option to IAPREFIX also if necessary
if class
then
class = tonumber(class)
mst.a(class, 'invalid class - not a number')
table.insert(v3, {option=dhcpv6_const.O_PREFIX_CLASS, value=class})
end
mst.execute_to_string('ip -6 route delete ' .. prefix .. ' 2>/dev/null')
mst.execute_to_string(string.format('ip -6 route add %s dev %s via %s', prefix, ifname, addr))
end
end
end
-- add DNS parameters if any
for i, v in ipairs(args.dns)
do
table.insert(o2, {option=dhcpv6_const.O_DNS_RNS, [1]=v})
end
for i, v in ipairs(args.search)
do
local search = dns_db.name2ll(v)
table.insert(o2, {option=dhcpv6_const.O_DOMAIN_SEARCH, [1]=search})
end
mst.d('sending reply', o2)
local d = dhcpv6_message:encode(o2)
s:sendto(d, src, srcport)
end
mst.d('entering event loop')
loop:loop()