The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
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: 5dadc7ab86a6ac171eefbd27922cbe78162c7ce6 $
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/protocol.h>
29#include <freeradius-devel/server/module_method.h>
30#include <freeradius-devel/util/dict.h>
31#include <freeradius-devel/util/debug.h>
32#include <freeradius-devel/dhcpv4/dhcpv4.h>
33
34static fr_dict_t const *dict_dhcpv4;
35
41
46
49 { .out = &attr_message_type, .name = "Message-Type", .type = FR_TYPE_UINT8, .dict = &dict_dhcpv4},
50 { .out = &attr_yiaddr, .name = "Your-IP-Address", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_dhcpv4},
51 { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_dhcpv4},
52 { .out = &attr_dhcp_option_82, .name = "Relay-Agent-Information", .type = FR_TYPE_TLV, .dict = &dict_dhcpv4 },
54};
55
56/*
57 * Debug the packet if requested.
58 */
59static void dhcpv4_packet_debug(request_t *request, fr_packet_t *packet, fr_pair_list_t *list, bool received)
60{
61#ifdef WITH_IFINDEX_NAME_RESOLUTION
62 char if_name[IFNAMSIZ];
63#endif
64
65 if (!packet) return;
66 if (!RDEBUG_ENABLED) return;
67
68 log_request(L_DBG, L_DBG_LVL_1, request, __FILE__, __LINE__, "%s %s XID %08x from %s%pV%s:%i to %s%pV%s:%i "
69#ifdef WITH_IFINDEX_NAME_RESOLUTION
70 "%s%s%s"
71#endif
72 "",
73 received ? "Received" : "Sending",
74 dhcp_message_types[packet->code],
75 packet->id,
76 packet->socket.inet.src_ipaddr.af == AF_INET6 ? "[" : "",
77 fr_box_ipaddr(packet->socket.inet.src_ipaddr),
78 packet->socket.inet.src_ipaddr.af == AF_INET6 ? "]" : "",
79 packet->socket.inet.src_port,
80 packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "[" : "",
81 fr_box_ipaddr(packet->socket.inet.dst_ipaddr),
82 packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "]" : "",
83 packet->socket.inet.dst_port
84#ifdef WITH_IFINDEX_NAME_RESOLUTION
85 , packet->socket.inet.ifindex ? "via " : "",
86 packet->socket.inet.ifindex ? fr_ifname_from_ifindex(if_name, packet->socket.inet.ifindex) : "",
87 packet->socket.inet.ifindex ? " " : ""
88#endif
89 );
90
91 if (received || request->parent) {
92 log_request_pair_list(L_DBG_LVL_1, request, NULL, list, NULL);
93 } else {
94 log_request_proto_pair_list(L_DBG_LVL_1, request, NULL, list, NULL);
95 }
96}
97
120
124
125#define FR_DHCP_PROCESS_CODE_VALID(_x) (FR_DHCP_PACKET_CODE_VALID(_x) || (_x == FR_DHCP_DO_NOT_RESPOND))
126
127#define PROCESS_PACKET_TYPE fr_dhcpv4_packet_code_t
128#define PROCESS_CODE_MAX FR_DHCP_CODE_MAX
129#define PROCESS_CODE_DO_NOT_RESPOND FR_DHCP_DO_NOT_RESPOND
130#define PROCESS_PACKET_CODE_VALID FR_DHCP_PROCESS_CODE_VALID
131#define PROCESS_INST process_dhcpv4_t
132#define PROCESS_CODE_DYNAMIC_CLIENT FR_DHCP_ACK
133#include <freeradius-devel/server/process.h>
134
135RESUME(check_offer_ack_options)
136{
137 fr_pair_t *vp;
138
139 vp = fr_pair_find_by_da(&request->reply_pairs, NULL, attr_yiaddr);
140 if (!vp) {
141 REDEBUG("%s packet does not have YIADDR. The client will not receive an IP address.",
142 dhcp_message_types[request->reply->code]);
143 }
144
145 /*
146 * RFC3046 says:
147 * DHCP servers claiming to support the Relay Agent Information option
148 * SHALL echo the entire contents of the Relay Agent Information option
149 * in all replies.
150 */
151 vp = fr_pair_find_by_da(&request->request_pairs, NULL, attr_dhcp_option_82);
152 if (vp) {
153 fr_pair_t *reply_vp;
154 int ret;
155 MEM((ret = pair_update_reply(&reply_vp, attr_dhcp_option_82)) >= 0);
156 if ((ret == 0) && (fr_pair_list_num_elements(&vp->vp_group) > 0)) {
157 MEM(fr_pair_list_copy(reply_vp, &reply_vp->vp_group, &vp->vp_group));
158 }
159 }
160
161 return CALL_RESUME(send_generic);
162}
163
164static fr_process_state_t const process_state[] = {
165 [FR_DHCP_DISCOVER] = {
166 .packet_type = {
170
177 },
178 .default_rcode = RLM_MODULE_NOOP,
179 .default_reply = FR_DHCP_DO_NOT_RESPOND,
180 .recv = recv_generic,
181 .resume = resume_recv_generic,
182 .section_offset = PROCESS_CONF_OFFSET(discover),
183 },
184 [FR_DHCP_OFFER] = {
185 .packet_type = {
189
196 },
197 .default_rcode = RLM_MODULE_NOOP,
198 .result_rcode = RLM_MODULE_OK,
199 .default_reply = FR_DHCP_DO_NOT_RESPOND,
200 .send = send_generic,
201 .resume = resume_check_offer_ack_options,
202 .section_offset = PROCESS_CONF_OFFSET(offer),
203 },
204
205 [FR_DHCP_REQUEST] = {
206 .packet_type = {
210
217 },
218 .default_rcode = RLM_MODULE_NOOP,
219 .default_reply = FR_DHCP_DO_NOT_RESPOND,
220 .recv = recv_generic,
221 .resume = resume_recv_generic,
222 .section_offset = PROCESS_CONF_OFFSET(request),
223 },
224
225 [FR_DHCP_DECLINE] = {
226 .packet_type = {
230
237 },
238 .default_rcode = RLM_MODULE_NOOP,
239 .default_reply = FR_DHCP_DO_NOT_RESPOND,
240 .recv = recv_generic,
241 .resume = resume_recv_generic,
242 .section_offset = PROCESS_CONF_OFFSET(decline),
243 },
244
245 [FR_DHCP_ACK] = {
246 .packet_type = {
250
257 },
258 .default_rcode = RLM_MODULE_NOOP,
259 .result_rcode = RLM_MODULE_OK,
260 .default_reply = FR_DHCP_DO_NOT_RESPOND,
261 .send = send_generic,
262 .resume = resume_check_offer_ack_options,
263 .section_offset = PROCESS_CONF_OFFSET(ack),
264 },
265 [FR_DHCP_NAK] = {
266 .packet_type = {
270
277 },
278 .default_rcode = RLM_MODULE_NOOP,
279 .result_rcode = RLM_MODULE_REJECT,
280 .default_reply = FR_DHCP_DO_NOT_RESPOND,
281 .send = send_generic,
282 .resume = resume_send_generic,
283 .section_offset = PROCESS_CONF_OFFSET(nak),
284 },
285
286 [FR_DHCP_INFORM] = {
287 .packet_type = {
291
298 },
299 .default_rcode = RLM_MODULE_NOOP,
300 .default_reply = FR_DHCP_DO_NOT_RESPOND,
301 .recv = recv_generic,
302 .resume = resume_recv_generic,
303 .section_offset = PROCESS_CONF_OFFSET(inform),
304 },
305
306 [FR_DHCP_RELEASE] = { /* releases are not responded to */
307 .packet_type = {
311
318 },
319 .default_rcode = RLM_MODULE_NOOP,
320 .default_reply = FR_DHCP_DO_NOT_RESPOND,
321 .recv = recv_generic,
322 .resume = resume_recv_generic,
323 .section_offset = PROCESS_CONF_OFFSET(release),
324 },
325
327 .packet_type = {
331
338 },
339 .default_rcode = RLM_MODULE_NOOP,
340 .default_reply = FR_DHCP_DO_NOT_RESPOND,
341 .recv = recv_generic,
342 .resume = resume_recv_generic,
343 .section_offset = PROCESS_CONF_OFFSET(lease_query),
344 },
345
347 .packet_type = {
351
358 },
359 .default_rcode = RLM_MODULE_NOOP,
360 .result_rcode = RLM_MODULE_OK,
361 .default_reply = FR_DHCP_DO_NOT_RESPOND,
362 .send = send_generic,
363 .resume = resume_send_generic,
364 .section_offset = PROCESS_CONF_OFFSET(lease_unassigned),
365 },
366
368 .packet_type = {
372
379 },
380 .default_rcode = RLM_MODULE_NOOP,
381 .result_rcode = RLM_MODULE_NOTFOUND,
382 .default_reply = FR_DHCP_DO_NOT_RESPOND,
383 .send = send_generic,
384 .resume = resume_send_generic,
385 .section_offset = PROCESS_CONF_OFFSET(lease_unknown),
386 },
387
389 .packet_type = {
393
400 },
401 .default_rcode = RLM_MODULE_NOOP,
402 .result_rcode = RLM_MODULE_OK,
403 .default_reply = FR_DHCP_DO_NOT_RESPOND,
404 .send = send_generic,
405 .resume = resume_send_generic,
406 .section_offset = PROCESS_CONF_OFFSET(lease_active),
407 },
408
410 .packet_type = {
414
421 },
422 .default_rcode = RLM_MODULE_NOOP,
423 .result_rcode = RLM_MODULE_DISALLOW,
424 .default_reply = FR_DHCP_DO_NOT_RESPOND,
425 .send = send_generic,
426 .resume = resume_send_generic,
427 .section_offset = PROCESS_CONF_OFFSET(do_not_respond),
428 },
429};
430
431static unlang_action_t mod_process(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
432{
433 fr_process_state_t const *state;
434
436
438 fr_assert(PROCESS_PACKET_CODE_VALID(request->packet->code));
439
440 request->component = "dhcpv4";
441 request->module = NULL;
442 fr_assert(request->proto_dict == dict_dhcpv4);
443
444 UPDATE_STATE(packet);
445
446 if (!state->recv) {
447 REDEBUG("Invalid packet type (%u)", request->packet->code);
449 }
450
451 dhcpv4_packet_debug(request, request->packet, &request->request_pairs, true);
452
453 if (unlikely(request_is_dynamic_client(request))) {
454 return new_client(p_result, mctx, request);
455 }
456
457 return state->recv(p_result, mctx, request);
458}
459
461 {
462 .section = SECTION_NAME("recv", "Discover"),
463 .actions = &mod_actions_postauth,
464
465 .methods = (const section_name_t *[]) {
467 NULL
468 },
469 .offset = PROCESS_CONF_OFFSET(discover),
470 },
471 {
472 .section = SECTION_NAME("send", "Offer"),
473 .actions = &mod_actions_postauth,
474 .offset = PROCESS_CONF_OFFSET(offer),
475 },
476 {
477 .section = SECTION_NAME("recv", "Request"),
479
480 .methods = (const section_name_t *[]) {
482 NULL
483 },
484 .offset = PROCESS_CONF_OFFSET(request),
485 },
486
487 {
488 .section = SECTION_NAME("send", "Ack"),
489 .actions = &mod_actions_postauth,
490 .offset = PROCESS_CONF_OFFSET(ack),
491 },
492 {
493 .section = SECTION_NAME("send", "NAK"),
495 .offset = PROCESS_CONF_OFFSET(nak),
496 },
497 {
498 .section = SECTION_NAME("recv", "Decline"),
500
501 .methods = (const section_name_t *[]) {
503 NULL
504 },
505 .offset = PROCESS_CONF_OFFSET(decline),
506 },
507
508 {
509 .section = SECTION_NAME("recv", "Release"),
510 .actions = &mod_actions_postauth,
511
512 .methods = (const section_name_t *[]) {
514 NULL
515 },
516 .offset = PROCESS_CONF_OFFSET(release),
517 },
518 {
519 .section = SECTION_NAME("recv", "Inform"),
520 .actions = &mod_actions_postauth,
521 .offset = PROCESS_CONF_OFFSET(inform),
522 },
523
524 {
525 .section = SECTION_NAME("recv", "Lease-Query"),
527 .offset = PROCESS_CONF_OFFSET(lease_query),
528 },
529 {
530 .section = SECTION_NAME("send", "Lease-Unassigned"),
532 .offset = PROCESS_CONF_OFFSET(lease_unassigned),
533 },
534 {
535 .section = SECTION_NAME("send", "Lease-Unknown"),
537 .offset = PROCESS_CONF_OFFSET(lease_unknown),
538 },
539 {
540 .section = SECTION_NAME("send", "Lease-Active"),
542 .offset = PROCESS_CONF_OFFSET(lease_active),
543 },
544
545 {
546 .section = SECTION_NAME("send", "Do-Not-Respond"),
548 .offset = PROCESS_CONF_OFFSET(do_not_respond),
549 },
550
551 DYNAMIC_CLIENT_SECTIONS,
552
554};
555
556
559 .common = {
560 .magic = MODULE_MAGIC_INIT,
561 .name = "dhcpv4",
563 MODULE_RCTX(process_rctx_t)
564 },
565 .process = mod_process,
566 .compile_list = compile_list,
567 .dict = &dict_dhcpv4,
568 .packet_type = &attr_packet_type
569};
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:383
A section grouping multiple CONF_PAIR.
Definition cf_priv.h:101
#define MEM(x)
Definition debug.h:36
@ 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:294
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:307
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:313
Specifies an attribute which must be present for the module to function.
Definition dict.h:293
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:306
#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:93
void log_request_proto_pair_list(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_list_t const *vps, char const *prefix)
Print a list of protocol fr_pair_ts.
Definition log.c:844
void log_request(fr_log_type_t type, fr_log_lvl_t lvl, request_t *request, char const *file, int line, char const *fmt,...)
Marshal variadic log arguments into a va_list and pass to normal logging functions.
Definition log.c:610
void log_request_pair_list(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_list_t const *vps, char const *prefix)
Print a fr_pair_list_t.
Definition log.c:820
@ L_DBG_LVL_1
Highest priority debug messages (-x).
Definition log.h:70
@ L_DBG
Only displayed when debugging is enabled.
Definition log.h:59
@ 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:93
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:2327
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:704
static unlang_action_t mod_process(unlang_result_t *p_result, module_ctx_t const *mctx, request_t *request)
Definition base.c:188
static const virtual_server_compile_t compile_list[]
Definition base.c:214
static fr_process_state_t const process_state[]
Definition base.c:69
#define PROCESS_PACKET_CODE_VALID
Definition base.c:65
CONF_SECTION * request
Definition base.c:103
CONF_SECTION * lease_query
Definition base.c:110
CONF_SECTION * ack
Definition base.c:105
CONF_SECTION * offer
Definition base.c:102
CONF_SECTION * lease_unassigned
Definition base.c:111
static void dhcpv4_packet_debug(request_t *request, fr_packet_t *packet, fr_pair_list_t *list, bool received)
Definition base.c:59
CONF_SECTION * do_not_respond
Definition base.c:114
CONF_SECTION * nak
Definition base.c:106
fr_process_module_t process_dhcpv4
Definition base.c:558
static fr_dict_attr_t const * attr_yiaddr
Definition base.c:43
CONF_SECTION * force_renew
Definition base.c:109
CONF_SECTION * decline
Definition base.c:104
CONF_SECTION * new_client
Definition base.c:116
fr_dict_attr_autoload_t process_dhcpv4_dict_attr[]
Definition base.c:48
static fr_dict_t const * dict_dhcpv4
Definition base.c:34
static fr_dict_attr_t const * attr_dhcp_option_82
Definition base.c:45
fr_dict_autoload_t process_dhcpv4_dict[]
Definition base.c:37
CONF_SECTION * add_client
Definition base.c:117
CONF_SECTION * inform
Definition base.c:108
CONF_SECTION * lease_active
Definition base.c:113
process_dhcpv4_sections_t sections
Definition base.c:122
CONF_SECTION * release
Definition base.c:107
CONF_SECTION * discover
Definition base.c:101
CONF_SECTION * deny_client
Definition base.c:118
CONF_SECTION * lease_unknown
Definition base.c:112
static fr_dict_attr_t const * attr_message_type
Definition base.c:42
#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:38
#define REDEBUG(fmt,...)
#define RDEBUG_ENABLED()
#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:188
#define SECTION_NAME(_name1, _name2)
Define a section name consisting of a verb and a noun.
Definition section.h:40
Section name identifier.
Definition section.h:44
void * data
Module's instance data.
Definition module.h:291
#define MODULE_RCTX(_ctype)
Definition module.h:257
#define MODULE_INST(_ctype)
Definition module.h:255
#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:245
unsigned int code
Packet code (type).
Definition packet.h:61
fr_socket_t socket
This packet was received on.
Definition packet.h:57
int id
Packet ID (used to link requests/responses).
Definition packet.h:60
size_t fr_pair_list_num_elements(fr_pair_list_t const *list)
Get the length of a list of fr_pair_t.
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition socket.h:78
#define fr_box_ipaddr(_val)
Definition value.h:317
section_name_t const * section
Identifier for the section.
#define COMPILE_TERMINATOR
Processing sections which are allowed in this virtual server.