The FreeRADIUS server $Id: f3670dba8951ca10eb4948feb3dc3db9423a334f $
Loading...
Searching...
No Matches
base.c
Go to the documentation of this file.
1/*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
15 */
16
17/**
18 * $Id: 22636b3d03044ab5c72d65f90ee1b2fa9870e8a1 $
19 * @file src/process/dhcpv4/base.c
20 * @brief Base DORA, etc. DHCPV4 processing.
21 *
22 * @copyright 2018 The Freeradius server project.
23 * @copyright 2018 Alan DeKok (aland@deployingradius.com)
24 */
25#define LOG_PREFIX "process_dhcpv4"
26
27#include <freeradius-devel/io/application.h>
28#include <freeradius-devel/server/module_method.h>
29#include <freeradius-devel/util/dict.h>
30#include <freeradius-devel/util/debug.h>
31#include <freeradius-devel/dhcpv4/dhcpv4.h>
32
33static fr_dict_t const *dict_dhcpv4;
34
40
45
48 { .out = &attr_message_type, .name = "Message-Type", .type = FR_TYPE_UINT8, .dict = &dict_dhcpv4},
49 { .out = &attr_yiaddr, .name = "Your-IP-Address", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_dhcpv4},
50 { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_dhcpv4},
51 { .out = &attr_dhcp_option_82, .name = "Relay-Agent-Information", .type = FR_TYPE_TLV, .dict = &dict_dhcpv4 },
53};
54
77
81
82#define FR_DHCP_PROCESS_CODE_VALID(_x) (FR_DHCP_PACKET_CODE_VALID(_x) || (_x == FR_DHCP_DO_NOT_RESPOND))
83
84#define PROCESS_PACKET_TYPE fr_dhcpv4_packet_code_t
85#define PROCESS_CODE_MAX FR_DHCP_CODE_MAX
86#define PROCESS_CODE_DO_NOT_RESPOND FR_DHCP_DO_NOT_RESPOND
87#define PROCESS_PACKET_CODE_VALID FR_DHCP_PROCESS_CODE_VALID
88#define PROCESS_INST process_dhcpv4_t
89#define PROCESS_CODE_DYNAMIC_CLIENT FR_DHCP_ACK
90#include <freeradius-devel/server/process.h>
91
92RESUME(check_offer_ack_options)
93{
95
96 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_yiaddr);
97 if (!vp) {
98 REDEBUG("%s packet does not have YIADDR. The client will not receive an IP address.",
99 dhcp_message_types[request->reply->code]);
100 }
101
102 /*
103 * RFC3046 says:
104 * DHCP servers claiming to support the Relay Agent Information option
105 * SHALL echo the entire contents of the Relay Agent Information option
106 * in all replies.
107 */
108 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_dhcp_option_82);
109 if (vp) {
110 fr_pair_t *reply_vp;
111 int ret;
112 MEM((ret = pair_update_reply(&reply_vp, attr_dhcp_option_82)) >= 0);
113 if ((ret == 0) && (fr_pair_list_num_elements(&vp->vp_group) > 0)) {
114 MEM(fr_pair_list_copy(reply_vp, &reply_vp->vp_group, &vp->vp_group) >= 0);
115 }
116 }
117
118 return CALL_RESUME(send_generic);
119}
120
121static fr_process_state_t const process_state[] = {
122 [FR_DHCP_DISCOVER] = {
123 .packet_type = {
127
134 },
135 .default_rcode = RLM_MODULE_NOOP,
136 .default_reply = FR_DHCP_DO_NOT_RESPOND,
137 .recv = recv_generic,
138 .resume = resume_recv_generic,
139 .section_offset = PROCESS_CONF_OFFSET(discover),
140 },
141 [FR_DHCP_OFFER] = {
142 .packet_type = {
146
153 },
154 .default_rcode = RLM_MODULE_NOOP,
155 .result_rcode = RLM_MODULE_OK,
156 .default_reply = FR_DHCP_DO_NOT_RESPOND,
157 .send = send_generic,
158 .resume = resume_check_offer_ack_options,
159 .section_offset = PROCESS_CONF_OFFSET(offer),
160 },
161
162 [FR_DHCP_REQUEST] = {
163 .packet_type = {
167
174 },
175 .default_rcode = RLM_MODULE_NOOP,
176 .default_reply = FR_DHCP_DO_NOT_RESPOND,
177 .recv = recv_generic,
178 .resume = resume_recv_generic,
179 .section_offset = PROCESS_CONF_OFFSET(request),
180 },
181
182 [FR_DHCP_DECLINE] = {
183 .packet_type = {
187
194 },
195 .default_rcode = RLM_MODULE_NOOP,
196 .default_reply = FR_DHCP_DO_NOT_RESPOND,
197 .recv = recv_generic,
198 .resume = resume_recv_generic,
199 .section_offset = PROCESS_CONF_OFFSET(decline),
200 },
201
202 [FR_DHCP_ACK] = {
203 .packet_type = {
207
214 },
215 .default_rcode = RLM_MODULE_NOOP,
216 .result_rcode = RLM_MODULE_OK,
217 .default_reply = FR_DHCP_DO_NOT_RESPOND,
218 .send = send_generic,
219 .resume = resume_check_offer_ack_options,
220 .section_offset = PROCESS_CONF_OFFSET(ack),
221 },
222 [FR_DHCP_NAK] = {
223 .packet_type = {
227
234 },
235 .default_rcode = RLM_MODULE_NOOP,
236 .result_rcode = RLM_MODULE_REJECT,
237 .default_reply = FR_DHCP_DO_NOT_RESPOND,
238 .send = send_generic,
239 .resume = resume_send_generic,
240 .section_offset = PROCESS_CONF_OFFSET(nak),
241 },
242
243 [FR_DHCP_INFORM] = {
244 .packet_type = {
248
255 },
256 .default_rcode = RLM_MODULE_NOOP,
257 .default_reply = FR_DHCP_DO_NOT_RESPOND,
258 .recv = recv_generic,
259 .resume = resume_recv_generic,
260 .section_offset = PROCESS_CONF_OFFSET(inform),
261 },
262
263 [FR_DHCP_RELEASE] = { /* releases are not responded to */
264 .packet_type = {
268
275 },
276 .default_rcode = RLM_MODULE_NOOP,
277 .default_reply = FR_DHCP_DO_NOT_RESPOND,
278 .recv = recv_generic,
279 .resume = resume_recv_generic,
280 .section_offset = PROCESS_CONF_OFFSET(release),
281 },
282
284 .packet_type = {
288
295 },
296 .default_rcode = RLM_MODULE_NOOP,
297 .default_reply = FR_DHCP_DO_NOT_RESPOND,
298 .recv = recv_generic,
299 .resume = resume_recv_generic,
300 .section_offset = PROCESS_CONF_OFFSET(lease_query),
301 },
302
304 .packet_type = {
308
315 },
316 .default_rcode = RLM_MODULE_NOOP,
317 .result_rcode = RLM_MODULE_OK,
318 .default_reply = FR_DHCP_DO_NOT_RESPOND,
319 .send = send_generic,
320 .resume = resume_send_generic,
321 .section_offset = PROCESS_CONF_OFFSET(lease_unassigned),
322 },
323
325 .packet_type = {
329
336 },
337 .default_rcode = RLM_MODULE_NOOP,
338 .result_rcode = RLM_MODULE_NOTFOUND,
339 .default_reply = FR_DHCP_DO_NOT_RESPOND,
340 .send = send_generic,
341 .resume = resume_send_generic,
342 .section_offset = PROCESS_CONF_OFFSET(lease_unknown),
343 },
344
346 .packet_type = {
350
357 },
358 .default_rcode = RLM_MODULE_NOOP,
359 .result_rcode = RLM_MODULE_OK,
360 .default_reply = FR_DHCP_DO_NOT_RESPOND,
361 .send = send_generic,
362 .resume = resume_send_generic,
363 .section_offset = PROCESS_CONF_OFFSET(lease_active),
364 },
365
367 .packet_type = {
371
378 },
379 .default_rcode = RLM_MODULE_NOOP,
380 .result_rcode = RLM_MODULE_DISALLOW,
381 .default_reply = FR_DHCP_DO_NOT_RESPOND,
382 .send = send_generic,
383 .resume = resume_send_generic,
384 .section_offset = PROCESS_CONF_OFFSET(do_not_respond),
385 },
386};
387
388static unlang_action_t mod_process(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
389{
390 fr_process_state_t const *state;
391
393
395 fr_assert(PROCESS_PACKET_CODE_VALID(request->packet->code));
396
397 request->component = "dhcpv4";
398 request->module = NULL;
399 fr_assert(request->proto_dict == dict_dhcpv4);
400
401 UPDATE_STATE(packet);
402
403 if (!state->recv) {
404 REDEBUG("Invalid packet type (%u)", request->packet->code);
406 }
407
408 if (unlikely(request_is_dynamic_client(request))) {
409 return new_client(p_result, mctx, request);
410 }
411
412 return state->recv(p_result, mctx, request);
413}
414
416 {
417 .section = SECTION_NAME("recv", "Discover"),
418 .actions = &mod_actions_postauth,
419
420 .methods = (const section_name_t *[]) {
422 NULL
423 },
424 .offset = PROCESS_CONF_OFFSET(discover),
425 },
426 {
427 .section = SECTION_NAME("send", "Offer"),
428 .actions = &mod_actions_postauth,
429 .offset = PROCESS_CONF_OFFSET(offer),
430 },
431 {
432 .section = SECTION_NAME("recv", "Request"),
434
435 .methods = (const section_name_t *[]) {
437 NULL
438 },
439 .offset = PROCESS_CONF_OFFSET(request),
440 },
441
442 {
443 .section = SECTION_NAME("send", "Ack"),
444 .actions = &mod_actions_postauth,
445 .offset = PROCESS_CONF_OFFSET(ack),
446 },
447 {
448 .section = SECTION_NAME("send", "NAK"),
450 .offset = PROCESS_CONF_OFFSET(nak),
451 },
452 {
453 .section = SECTION_NAME("recv", "Decline"),
455
456 .methods = (const section_name_t *[]) {
458 NULL
459 },
460 .offset = PROCESS_CONF_OFFSET(decline),
461 },
462
463 {
464 .section = SECTION_NAME("recv", "Release"),
465 .actions = &mod_actions_postauth,
466
467 .methods = (const section_name_t *[]) {
469 NULL
470 },
471 .offset = PROCESS_CONF_OFFSET(release),
472 },
473 {
474 .section = SECTION_NAME("recv", "Inform"),
475 .actions = &mod_actions_postauth,
476 .offset = PROCESS_CONF_OFFSET(inform),
477 },
478
479 {
480 .section = SECTION_NAME("recv", "Lease-Query"),
482 .offset = PROCESS_CONF_OFFSET(lease_query),
483 },
484 {
485 .section = SECTION_NAME("send", "Lease-Unassigned"),
487 .offset = PROCESS_CONF_OFFSET(lease_unassigned),
488 },
489 {
490 .section = SECTION_NAME("send", "Lease-Unknown"),
492 .offset = PROCESS_CONF_OFFSET(lease_unknown),
493 },
494 {
495 .section = SECTION_NAME("send", "Lease-Active"),
497 .offset = PROCESS_CONF_OFFSET(lease_active),
498 },
499
500 {
501 .section = SECTION_NAME("send", "Do-Not-Respond"),
503 .offset = PROCESS_CONF_OFFSET(do_not_respond),
504 },
505
506 DYNAMIC_CLIENT_SECTIONS,
507
509};
510
511
514 .common = {
515 .magic = MODULE_MAGIC_INIT,
516 .name = "dhcpv4",
518 MODULE_RCTX(process_rctx_t)
519 },
520 .process = mod_process,
521 .compile_list = compile_list,
522 .dict = &dict_dhcpv4,
523 .packet_type = &attr_packet_type
524};
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
Definition action.h:35
#define unlikely(_x)
Definition build.h:455
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:106
#define MEM(x)
Definition debug.h:38
@ FR_DHCP_REQUEST
Definition dhcpv4.h:47
@ FR_DHCP_LEASE_UNASSIGNED
Definition dhcpv4.h:55
@ FR_DHCP_DECLINE
Definition dhcpv4.h:48
@ FR_DHCP_OFFER
Definition dhcpv4.h:46
@ FR_DHCP_DISCOVER
Definition dhcpv4.h:45
@ FR_DHCP_LEASE_ACTIVE
Definition dhcpv4.h:57
@ FR_DHCP_LEASE_UNKNOWN
Definition dhcpv4.h:56
@ FR_DHCP_LEASE_QUERY
Definition dhcpv4.h:54
@ FR_DHCP_NAK
Definition dhcpv4.h:50
@ FR_DHCP_RELEASE
Definition dhcpv4.h:51
@ FR_DHCP_DO_NOT_RESPOND
Definition dhcpv4.h:61
@ FR_DHCP_INFORM
Definition dhcpv4.h:52
@ FR_DHCP_ACK
Definition dhcpv4.h:49
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:292
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:305
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
Specifies an attribute which must be present for the module to function.
Definition dict.h:291
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:304
#define MODULE_MAGIC_INIT
Stop people using different module/library/server versions together.
Definition dl_module.h:63
fr_dict_attr_t const * attr_packet_type
Definition base.c:91
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
unlang_mod_actions_t const mod_actions_postauth
Definition mod_action.c:92
unlang_mod_action_t actions[RLM_MODULE_NUMCODES]
Definition mod_action.h:69
module_instance_t const * mi
Instance of the module being instantiated.
Definition module_ctx.h:42
Temporary structure to hold arguments for module calls.
Definition module_ctx.h:41
section_name_t module_method_ippool_mark
section_name_t module_method_ippool_extend
section_name_t module_method_ippool_release
section_name_t module_method_ippool_allocate
int fr_pair_list_copy(TALLOC_CTX *ctx, fr_pair_list_t *to, fr_pair_list_t const *from)
Duplicate a list of pairs.
Definition pair.c:2326
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
Definition pair.c:707
static unlang_action_t mod_process(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition base.c:168
static const virtual_server_compile_t compile_list[]
Definition base.c:192
static fr_process_state_t const process_state[]
Definition base.c:68
#define PROCESS_PACKET_CODE_VALID
Definition base.c:64
CONF_SECTION * request
Definition base.c:60
CONF_SECTION * lease_query
Definition base.c:67
CONF_SECTION * ack
Definition base.c:62
CONF_SECTION * offer
Definition base.c:59
CONF_SECTION * lease_unassigned
Definition base.c:68
CONF_SECTION * do_not_respond
Definition base.c:71
CONF_SECTION * nak
Definition base.c:63
fr_process_module_t process_dhcpv4
Definition base.c:513
static fr_dict_attr_t const * attr_yiaddr
Definition base.c:42
CONF_SECTION * force_renew
Definition base.c:66
CONF_SECTION * decline
Definition base.c:61
CONF_SECTION * new_client
Definition base.c:73
fr_dict_attr_autoload_t process_dhcpv4_dict_attr[]
Definition base.c:47
static fr_dict_t const * dict_dhcpv4
Definition base.c:33
static fr_dict_attr_t const * attr_dhcp_option_82
Definition base.c:44
fr_dict_autoload_t process_dhcpv4_dict[]
Definition base.c:36
CONF_SECTION * add_client
Definition base.c:74
CONF_SECTION * inform
Definition base.c:65
CONF_SECTION * lease_active
Definition base.c:70
process_dhcpv4_sections_t sections
Definition base.c:79
CONF_SECTION * release
Definition base.c:64
CONF_SECTION * discover
Definition base.c:58
CONF_SECTION * deny_client
Definition base.c:75
CONF_SECTION * lease_unknown
Definition base.c:69
static fr_dict_attr_t const * attr_message_type
Definition base.c:41
#define PROCESS_TRACE
Trace each state function as it's entered.
Definition process.h:55
#define PROCESS_CONF_OFFSET(_x)
Definition process.h:79
module_t common
Common fields for all loadable modules.
Common public symbol definition for all process modules.
char const * dhcp_message_types[]
Definition base.c:129
#define fr_assert(_expr)
Definition rad_assert.h:37
#define REDEBUG(fmt,...)
#define RETURN_UNLANG_FAIL
Definition rcode.h:63
@ RLM_MODULE_INVALID
The module considers the request invalid.
Definition rcode.h:51
@ RLM_MODULE_OK
The module is OK, continue.
Definition rcode.h:49
@ RLM_MODULE_FAIL
Module failed, don't reply.
Definition rcode.h:48
@ RLM_MODULE_DISALLOW
Reject the request (user is locked out).
Definition rcode.h:52
@ RLM_MODULE_REJECT
Immediately reject the request.
Definition rcode.h:47
@ RLM_MODULE_TIMEOUT
Module (or section) timed out.
Definition rcode.h:56
@ RLM_MODULE_NOTFOUND
User not found.
Definition rcode.h:53
@ RLM_MODULE_UPDATED
OK (pairs modified).
Definition rcode.h:55
@ RLM_MODULE_NOOP
Module succeeded without doing anything.
Definition rcode.h:54
#define request_is_dynamic_client(_x)
Definition request.h:189
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:39
Section name identifier.
Definition section.h:43
void * data
Module's instance data.
Definition module.h:293
#define MODULE_RCTX(_ctype)
Definition module.h:259
#define MODULE_INST(_ctype)
Definition module.h:257
#define pair_update_reply(_attr, _da)
Return or allocate a fr_pair_t in the reply list.
Definition pair.h:129
#define RESUME(_x)
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
#define talloc_get_type_abort_const
Definition talloc.h:117
void * state
Definition testlib.c:46
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
section_name_t const * section
Identifier for the section.
#define COMPILE_TERMINATOR
Processing sections which are allowed in this virtual server.