summaryrefslogtreecommitdiffstats
path: root/raddb/policy.d/dhcp
blob: 1752acbd1545eafcc9adfee0b50d7a4de2067677 (plain)
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
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
#  Assign common DHCP reply packet options
dhcp_common {
	#  The contents here are invented.  Change them!
	update reply {
		&DHCP-Domain-Name-Server = 127.0.0.1
		&DHCP-Domain-Name-Server += 127.0.0.2
		&DHCP-Subnet-Mask = 255.255.255.0
		&DHCP-Router-Address = 192.0.2.1
		&DHCP-Broadcast-Address = 192.0.2.255
		&DHCP-IP-Address-Lease-Time = 7200
		&DHCP-DHCP-Server-Identifier = &control:DHCP-DHCP-Server-Identifier
	}
}

#  Lookup DHCP group based options.  This policy allows  for membership
#  of multiple groups so can cover the ISC concepts of "group" and "class"
#  To use this enable the "dhcp_files" module
#dhcp_group_options {
#	foreach &request:DHCP-Group-Name {
#		dhcp_set_group_options
#	}
#}

#  Policy to override DHCP-Network-Subnet
#
#  Some networks have a "shared-network" or "multinet" configuration (as
#  defined by some other DHCP servers) in which multiple IP subnets may
#  co-exist in a single Layer 2 network (or VLAN).
#
#  In enterprise environments this is often for the purpose of providing loose
#  segregation between classes of devices such as local network-attached
#  storage or IP telephony. There are valid reasons why each of the subnets is
#  not seperately VLANed, such as to enable the use of ICMP redirects to avoid
#  hairpinning of cross-subnet traffic via a gateway.
#
#  In ISP environments this is a common configuration for edge networks whose
#  access is provided by DOCSIS cable modems that share a VLAN with the devices
#  they provide a service to but are seperately addressed.
#
#  Where it is necessary to force the selection of a particular subnet for a
#  device, multiple pools must be configured for each subnet and referenced
#  with unique identifiers in the *network-specific* section of
#  mods-config/files/dhcp.
#
#  By default DHCP-Network-Subnet is populated such that it normally
#  refers to the Layer 2 network from which the DHCP query originates - we
#  cannot know the intended subnet for the device without additional input to
#  the policy.
#
#  Override DHCP-Network-Subnet to be an address within the desired
#  network to force selection of a particular address pool and/or network
#  parameters.
#
#  Note: If each subnet within a network is equally valid for the DHCP requests
#  originating from that network then you do not need to call this policy,
#  rather look at the examples concerning dhcp_subnet in
#  mods-config/files/dhcp instead, which use a single pool containing addresses
#  from all subnets then set the correct subnet-specific options based on the
#  randomly assigned IP address.
#
#dhcp_override_network {
#	if (&DHCP-Vendor-Class-Identifier && &DHCP-Vendor-Class-Identifier == "SIP100")
#		update request {
#			DHCP-Network-Subnet := 10.10.0.0
#		}
#	}
#}


#  Policy that calls the files instance of the same name after first making
#  DHCP-Network-Subnet specific to the allocated IP address of the client.
#dhcp_subnet {
#	update {
#		&DHCP-Network-Subnet := "%{%{reply:DHCP-Your-IP-Address}:-%{DHCP-Client-IP-Address}}"
#	}
#
#	# Call the dhcp_subnet instance of the files module
#	dhcp_subnet
#}

#  Assign compatibility data to request for sqlippool for DHCP Request
dhcp_sqlippool_request {

	#
	#  During initial address selection (DORA) the REQUEST is broadcast and
	#  requested-ip must be provided. We revoke any active offers for addresses
	#  not matching the requested-ip, i.e. those made by other servers when
	#  processing the DISCOVER.
	#
	#  If there is only a single server then this optimisation can be disabled.
	#
	if (&DHCP-Requested-IP-Address) {
		update request {
			&Acct-Status-Type := Start
		}
		dhcp_sqlippool.accounting
	}

	#  Extend an existing offer or active lease
	update request {
		&Acct-Status-Type := Alive
	}
	dhcp_sqlippool.accounting {
		notfound = return
	}

	update reply {
		&DHCP-Your-IP-Address := "%{%{DHCP-Requested-IP-Address}:-%{DHCP-Client-IP-Address}}"
	}

}

#  Assign compatibility data to request for sqlippool for DHCP Release
dhcp_sqlippool_release {

	#  Do some minor hacks to the request so that it looks
	#  like a RADIUS Accounting Stop request to the SQL IP Pool module.
	update request {
		&Acct-Status-Type = Stop
	}

	#  Call the actual module in accounting context
	dhcp_sqlippool.accounting

}

#  Assign compatibility data to request for sqlippool for DHCP Decline
dhcp_sqlippool_decline {

	#  Do a minor hack to the request so that it looks
	#  like a RADIUS Accounting Off request to the SQL IP Pool module.
	update request {
		&Acct-Status-Type = Accounting-Off
	}

	#  Call the actual module in accounting context
	dhcp_sqlippool.accounting

}

#  Example policy for fetching option data from SQL
dhcp_policy_sql {

	#
	#  Network-specific options
	#

	#
	#  We want to lookup the Layer 2 network specific DHCP options to
	#  include in the reply. For this we need a stable identifier for the
	#  network from which the request is originating (based on
	#  DHCP-Network-Subnet) which can be used as the lookup key
	#  (DHCP-SQL-Option-Identifier) for the network options.
	#
	#  Here we fabricate an example for the purpose of placing all
	#  configuration elements into SQL. We use a PostgreSQL query that
	#  returns the network identifier in the row containing the smallest
	#  enclosing CIDR, which assumes a schema such as the following:
	#
	#    CREATE TABLE fr_network_to_identifier (network CIDR, network_id TEXT)
	#
	#  Note: An rlm_files based lookup of the network_identifier (as per
	#  the examples in the dhcp virtual server) may be preferable to an ad
	#  hoc SQL query assuming that the network topology does not change
	#  frequently.
	#
#	update control {
#		&control:Tmp-String-0 := "%{dhcp_sql:SELECT network_id \
#		    FROM fr_network_to_identifier \
#		    WHERE '%{DHCP-Network-Subnet}'::inet << network \
#		    ORDER BY MASKLEN(network) DESC LIMIT 1;}"
#	}

	#
	#  Use the network identifer to lookup the options specific to the
	#  originating network, using "network" context.  Common network
	#  settings can be placed into a group and shared, with individual
	#  networks mapped to one or more option groups.
	#
	#    - Place network-specific options in the dhcpreply table with
	#      "context = 'network'".
	#    - Add "Fall-Through := Yes" to the network options in the dhcpreply
	#      table to trigger group lookups for the network, which are
	#      disabled by default.
	#    - Place "identifier = <network_id>, groupname = <group>,
	#      priority = <priority>, context = 'network'" in the dhcpgroup
	#      table to map a network to a shared set of network options.
	#    - Place group-specific options in the dhcpgroupreply table with
	#      "context = 'network'".
	#
	#  Note: In "shared-network" or "multinet" topologies you can instead
	#  just set all of the network options once in the subnet-specific
	#  options (after obtaining an IP address), below.
	#
#	update control {
#		&DHCP-SQL-Option-Context := "network"
#		&DHCP-SQL-Option-Identifier := &control:Tmp-String-0
#	}
#	dhcp_sql.authorize


	#
	#  Allocate IPs from the DHCP pool in SQL.
	#
	#  Here we simply reuse the network_id (obtained previously) as the
	#  Pool-Name.
	#
#	update control {
#		&Pool-Name := &control:Tmp-String-0
#	}
#	dhcp_sqlippool


	#
	#  Subnet-specific options
	#

	#
	#  In "shared-network" or "multinet" topologies (in which a Layer 2
	#  network has a single pool that contains addresses from multiple
	#  subnets) it is necessary to set subnet-specific options based on the
	#  address that has just been allocated.
	#
	#  Again, for this we need to derive a stable identifier for the subnet
	#  to which the IP address we are issuing belongs that will serve as a
	#  lookup key for the network options.
	#
	#  Continuing our previous example, we can use a PostgreSQL query to
	#  find the subnet identifer in the row with the closest enclosing
	#  CIDR, which assumes a schema such as the following:
	#
	#      CREATE TABLE fr_subnet_to_identifier (subnet CIDR, subnet_id TEXT)
	#
	#  Note: An rlm_files based lookup of the subnet_identifier (as per the
	#  examples in the dhcp virtual server) is preferable to an ad hoc SQL
	#  query assuming that the network topology does not change frequently.
	#
#	update control {
#		&control:Tmp-String-0 := "%{dhcp_sql:SELECT subnet_id \
#		    FROM fr_subnet_to_identifier \
#		    WHERE '%{reply:DHCP-Your-IP-Address}'::inet << subnet \
#		    ORDER BY MASKLEN(subnet) DESC LIMIT 1;}"
#	}

	#
	#  Use the subnet identifer to lookup the options specific to the
	#  subnet for the IP we are allocating, using "subnet" context.  Common
	#  subnet settings can be placed into a group and shared, with
	#  individual subnets mapped to one or more option groups.
	#
	#    - Place subnet-specific options in the dhcpreply table with
	#      "context = 'subnet'".
	#    - Add "Fall-Through := Yes" to the subnet options in the dhcpreply
	#      table to trigger group lookups for the subnet, which are
	#      disabled by default.
	#    - Place "identifier = <subnet_id>, groupname = <group>,
	#      priority = <priority>, context = 'subnet'" in the dhcpgroup
	#      table to map a subnet to a shared set of subnet options.
	#    - Place group-specific options in the dhcpgroupreply table with
	#      "context = 'subnet'".
	#
#	update control {
#		&DHCP-SQL-Option-Context := "subnet"
#		&DHCP-SQL-Option-Identifier := &control:Tmp-String-0
#	}
#	dhcp_sql.authorize


	#
	#  Host-specific and group-specific options
	#

	#  "Groups" conventionally differentiate devices based on manual
	#  groupings using a device-specific identifier such as the MAC
	#  address.
	#
	#    - Place host-specific options in the dhcpreply table with
	#      "context = 'group'".
	#    - Add "Fall-Through := Yes" to the device options in the dhcpreply
	#      table to trigger group lookups, which are disabled by default.
	#    - Place "identifier = <MAC-Address>, groupname = <group>,
	#      priority = <priority>, context='group'" in the dhcpgroup table
	#      to map a device to its groups.
	#    - Place group-specific options in the dhcpgroupreply table with
	#      "context = 'group'".
	#
#	update control {
#		&DHCP-SQL-Option-Context := "group"
#		&DHCP-SQL-Option-Identifier := &request:DHCP-Client-Hardware-Address
#	}
#	dhcp_sql.authorize


	#
	#  Class/subclass-specific options
	#

	#
	#  "Classes" conventionally differentiate devices based on all or part
	#  of one or more DHCP request options, or any combination of
	#  information that is available in the request or has already looked
	#  up from some datastore.
	#
	#  Create multiple instances of the following block, one for each
	#  class. Differentiate between classes by setting
	#  DHCP-SQL-Option-Context uniquely.
	#
	#    - Place "subclass"-specific options (i.e. each member of a class)
	#      in the dhcpreply table with "context = <class-name>".
	#    - For class-level options common to every member of a class,
	#      either:
	#        - Duplicate the options for each member of the subclass.
	#      or:
	#        - Add "Fall-Through := Yes" to each members options to trigger
	#          group lookups, which are disabled by default.
	#        - Map each member of the class to a group in the dhcpgroup
	#          table with context = '<class-name>';
	#        - Create the corresponding class in the dhcpgroupreply table
	#          with "context = '<class-name>'".
	#
#	update control {
#		&DHCP-SQL-Option-Context := "class-vci-substring"
#		&DHCP-SQL-Option-Identifier := "%{substring %{request:DHCP-Vendor-Class-Identifier} 5 4}"
#	}
#	dhcp_sql.authorize

}