2 * dhcp.c DHCP processing.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2008 The FreeRADIUS server project
21 * Copyright 2008,2011 Alan DeKok <aland@deployingradius.com>
26 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 DISCOVER
27 * CLIENT_IP : 68 <- DHCP_SERVER_IP : 67 OFFER
28 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 REQUEST
29 * CLIENT_IP : 68 <- DHCP_SERVER_IP : 67 ACK
32 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 DISCOVER
33 * RELAY_IP : 67 -> NEXT_SERVER_IP : 67 DISCOVER
34 * (NEXT_SERVER_IP can be a relay itself)
35 * FIRST_RELAY_IP : 67 <- DHCP_SERVER_IP : 67 OFFER
36 * CLIENT_IP : 68 <- FIRST_RELAY_IP : 67 OFFER
37 * INADDR_ANY : 68 -> INADDR_BROADCAST : 67 REQUEST
38 * RELAY_IP : 67 -> NEXT_SERVER_IP : 67 REQUEST
39 * (NEXT_SERVER_IP can be a relay itself)
40 * FIRST_RELAY_IP : 67 <- DHCP_SERVER_IP : 67 ACK
41 * CLIENT_IP : 68 <- FIRST_RELAY_IP : 67 ACK
43 * Note: NACK are broadcasted, rest is unicast, unless client asked
48 #include <freeradius-devel/radiusd.h>
49 #include <freeradius-devel/modules.h>
50 #include <freeradius-devel/protocol.h>
51 #include <freeradius-devel/process.h>
52 #include <freeradius-devel/dhcp.h>
53 #include <freeradius-devel/rad_assert.h>
56 #include <sys/ioctl.h>
60 * Same contents as listen_socket_t.
62 typedef struct dhcp_socket_t {
63 listen_socket_t lsock;
66 * DHCP-specific additions.
68 bool suppress_responses;
69 RADCLIENT dhcp_client;
70 char const *src_interface;
71 fr_ipaddr_t src_ipaddr;
75 static int dhcprelay_process_client_request(REQUEST *request)
78 VALUE_PAIR *vp, *giaddr;
81 rad_assert(request->packet->data[0] == 1);
84 * Do the forward by ourselves, do not rely on dhcp_socket_send()
86 request->reply->code = 0;
89 * It's invalid to have giaddr=0 AND a relay option
91 giaddr = fr_pair_find_by_num(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
92 if (giaddr && (giaddr->vp_ipaddr == htonl(INADDR_ANY)) &&
93 fr_pair_find_by_num(request->packet->vps, 82, DHCP_MAGIC_VENDOR, TAG_ANY)) { /* DHCP-Relay-Agent-Information */
94 DEBUG("DHCP: Received packet with giaddr = 0 and containing relay option: Discarding packet\n");
99 * RFC 1542 (BOOTP), page 15
101 * Drop requests if hop-count > 16 or admin specified another value
103 if ((vp = fr_pair_find_by_num(request->config, 271, DHCP_MAGIC_VENDOR, TAG_ANY))) { /* DHCP-Relay-Max-Hop-Count */
104 maxhops = vp->vp_integer;
106 vp = fr_pair_find_by_num(request->packet->vps, 259, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Hop-Count */
107 rad_assert(vp != NULL);
108 if (vp->vp_integer > maxhops) {
109 DEBUG("DHCP: Number of hops is greater than %d: not relaying\n", maxhops);
112 /* Increment hop count */
116 sock = request->listener->data;
119 * Forward the request to the next server using the
120 * incoming request as a template.
122 /* set SRC ipaddr/port to the listener ipaddr/port */
123 request->packet->src_ipaddr.af = AF_INET;
124 request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = sock->lsock.my_ipaddr.ipaddr.ip4addr.s_addr;
125 request->packet->src_port = sock->lsock.my_port;
127 vp = fr_pair_find_by_num(request->config, 270, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Relay-To-IP-Address */
128 rad_assert(vp != NULL);
130 /* set DEST ipaddr/port to the next server ipaddr/port */
131 request->packet->dst_ipaddr.af = AF_INET;
132 request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
133 request->packet->dst_port = sock->lsock.my_port;
135 if (fr_dhcp_encode(request->packet) < 0) {
136 DEBUG("dhcprelay_process_client_request: ERROR in fr_dhcp_encode\n");
140 return fr_dhcp_send(request->packet);
145 * We've seen a reply from a server.
146 * i.e. we're a relay.
148 static int dhcprelay_process_server_reply(REQUEST *request)
150 VALUE_PAIR *vp, *giaddr;
153 rad_assert(request->packet->data[0] == 2);
156 * Do the forward by ourselves, do not rely on dhcp_socket_send()
158 request->reply->code = 0;
160 sock = request->listener->data;
163 * Check that packet is for us.
165 giaddr = fr_pair_find_by_num(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
167 /* --with-udpfromto is needed just for the following test */
168 if (!giaddr || giaddr->vp_ipaddr != request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr) {
169 DEBUG("DHCP: Packet received from server was not for us (was for 0x%x). Discarding packet",
170 ntohl(request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr));
174 /* set SRC ipaddr/port to the listener ipaddr/port */
175 request->packet->src_ipaddr.af = AF_INET;
176 request->packet->src_port = sock->lsock.my_port;
178 /* set DEST ipaddr/port to clientip/68 or broadcast in specific cases */
179 request->packet->dst_ipaddr.af = AF_INET;
182 * We're a relay, and send the reply to giaddr.
184 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = giaddr->vp_ipaddr;
185 request->reply->dst_port = request->packet->dst_port; /* server port */
187 if ((request->packet->code == PW_DHCP_NAK) ||
188 !sock->src_interface ||
189 ((vp = fr_pair_find_by_num(request->packet->vps, 262, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Flags */ &&
190 (vp->vp_integer & 0x8000) &&
191 ((vp = fr_pair_find_by_num(request->packet->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Client-IP-Address */ &&
192 (vp->vp_ipaddr == htonl(INADDR_ANY))))) {
199 * - Broadcast flag is set up and ciaddr == NULL
201 RDEBUG("DHCP: response will be broadcast");
202 request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
208 * - ciaddr if present
209 * otherwise to yiaddr
211 if ((vp = fr_pair_find_by_num(request->packet->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) /* DHCP-Client-IP-Address */ &&
212 (vp->vp_ipaddr != htonl(INADDR_ANY))) {
213 request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
215 vp = fr_pair_find_by_num(request->packet->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-Address */
217 DEBUG("DHCP: Failed to find IP Address for request");
221 RDEBUG("DHCP: response will be unicast to your-ip-address");
222 request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
225 * When sending a DHCP_OFFER, make sure our ARP table
226 * contains an entry for the client IP address, or else
227 * packet may not be forwarded if it was the first time
228 * the client was requesting an IP address.
230 if (request->packet->code == PW_DHCP_OFFER) {
231 VALUE_PAIR *hwvp = fr_pair_find_by_num(request->packet->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Client-Hardware-Address */
233 DEBUG("DHCP: DHCP_OFFER packet received with "
234 "no Client Hardware Address. Discarding packet");
237 if (fr_dhcp_add_arp_entry(request->packet->sockfd, sock->src_interface, hwvp, vp) < 0) {
238 DEBUG("%s", fr_strerror());
245 if (fr_dhcp_encode(request->packet) < 0) {
246 DEBUG("dhcprelay_process_server_reply: ERROR in fr_dhcp_encode\n");
250 return fr_dhcp_send(request->packet);
252 #else /* WITH_UDPFROMTO */
253 static int dhcprelay_process_server_reply(UNUSED REQUEST *request)
255 WARN("DHCP Relaying requires the server to be configured with UDPFROMTO");
259 static int dhcprelay_process_client_request(UNUSED REQUEST *request)
261 WARN("DHCP Relaying requires the server to be configured with UDPFROMTO");
265 #endif /* WITH_UDPFROMTO */
267 static const uint32_t attrnums[] = {
268 57, /* DHCP-DHCP-Maximum-Msg-Size */
269 256, /* DHCP-Opcode */
270 257, /* DHCP-Hardware-Type */
271 258, /* DHCP-Hardware-Address-Length */
272 259, /* DHCP-Hop-Count */
273 260, /* DHCP-Transaction-Id */
274 262, /* DHCP-Flags */
275 263, /* DHCP-Client-IP-Address */
276 266, /* DHCP-Gateway-IP-Address */
277 267 /* DHCP-Client-Hardware-Address */
280 static int dhcp_process(REQUEST *request)
288 * If there's a giaddr, save it as the Relay-IP-Address
289 * in the response. That way the later code knows where
292 vp = fr_pair_find_by_num(request->packet->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
293 if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) {
296 /* DHCP-Relay-IP-Address */
297 relay = radius_pair_create(request->reply, &request->reply->vps,
298 272, DHCP_MAGIC_VENDOR);
299 if (relay) relay->vp_ipaddr = vp->vp_ipaddr;
302 vp = fr_pair_find_by_num(request->packet->vps, 53, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Message-Type */
304 DICT_VALUE *dv = dict_valbyattr(53, DHCP_MAGIC_VENDOR, vp->vp_integer);
305 DEBUG("Trying sub-section dhcp %s {...}",
306 dv ? dv->name : "<unknown>");
307 rcode = process_post_auth(vp->vp_integer, request);
309 DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!");
310 rcode = RLM_MODULE_FAIL;
313 vp = fr_pair_find_by_num(request->reply->vps, 53, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Message-Type */
315 request->reply->code = vp->vp_integer;
316 if ((request->reply->code != 0) &&
317 (request->reply->code < PW_DHCP_OFFSET)) {
318 request->reply->code += PW_DHCP_OFFSET;
321 else switch (rcode) {
323 case RLM_MODULE_UPDATED:
324 if (request->packet->code == PW_DHCP_DISCOVER) {
325 request->reply->code = PW_DHCP_OFFER;
328 } else if (request->packet->code == PW_DHCP_REQUEST) {
329 request->reply->code = PW_DHCP_ACK;
332 request->reply->code = PW_DHCP_NAK;
336 case RLM_MODULE_REJECT:
337 case RLM_MODULE_FAIL:
338 case RLM_MODULE_INVALID:
339 case RLM_MODULE_NOOP:
340 case RLM_MODULE_NOTFOUND:
341 if (request->packet->code == PW_DHCP_DISCOVER) {
342 request->reply->code = 0; /* ignore the packet */
344 request->reply->code = PW_DHCP_NAK;
348 case RLM_MODULE_HANDLED:
349 request->reply->code = 0; /* ignore the packet */
354 * TODO: Handle 'output' of RLM_MODULE when acting as a
355 * DHCP relay We may want to not forward packets in
356 * certain circumstances.
360 * Handle requests when acting as a DHCP relay
362 vp = fr_pair_find_by_num(request->packet->vps, 256, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Opcode */
364 RDEBUG("FAILURE: Someone deleted the DHCP-Opcode!");
368 /* BOOTREPLY received on port 67 (i.e. from a server) */
369 if (vp->vp_integer == 2) {
370 return dhcprelay_process_server_reply(request);
373 /* Packet from client, and we have DHCP-Relay-To-IP-Address */
374 if (fr_pair_find_by_num(request->config, 270, DHCP_MAGIC_VENDOR, TAG_ANY)) {
375 return dhcprelay_process_client_request(request);
378 /* else it's a packet from a client, without relaying */
379 rad_assert(vp->vp_integer == 1); /* BOOTREQUEST */
381 sock = request->listener->data;
384 * Handle requests when acting as a DHCP server
388 * Releases don't get replies.
390 if (request->packet->code == PW_DHCP_RELEASE) {
391 request->reply->code = 0;
394 if (request->reply->code == 0) {
398 request->reply->sockfd = request->packet->sockfd;
401 * Copy specific fields from packet to reply, if they
402 * don't already exist
404 for (i = 0; i < sizeof(attrnums) / sizeof(attrnums[0]); i++) {
405 uint32_t attr = attrnums[i];
407 if (fr_pair_find_by_num(request->reply->vps, attr, DHCP_MAGIC_VENDOR, TAG_ANY)) continue;
409 vp = fr_pair_find_by_num(request->packet->vps, attr, DHCP_MAGIC_VENDOR, TAG_ANY);
411 fr_pair_add(&request->reply->vps, fr_pair_copy(request->reply, vp));
415 vp = fr_pair_find_by_num(request->reply->vps, 256, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Opcode */
416 rad_assert(vp != NULL);
417 vp->vp_integer = 2; /* BOOTREPLY */
420 * Allow NAKs to be delayed for a short period of time.
422 if (request->reply->code == PW_DHCP_NAK) {
423 vp = fr_pair_find_by_num(request->reply->vps, PW_FREERADIUS_RESPONSE_DELAY, 0, TAG_ANY);
425 if (vp->vp_integer <= 10) {
426 request->response_delay.tv_sec = vp->vp_integer;
427 request->response_delay.tv_usec = 0;
429 request->response_delay.tv_sec = 10;
430 request->response_delay.tv_usec = 0;
434 vp = fr_pair_find_by_num(request->reply->vps, PW_FREERADIUS_RESPONSE_DELAY_USEC, 0, TAG_ANY);
436 if (vp->vp_integer <= 10 * USEC) {
437 request->response_delay.tv_sec = vp->vp_integer / USEC;
438 request->response_delay.tv_usec = vp->vp_integer % USEC;
440 request->response_delay.tv_sec = 10;
441 request->response_delay.tv_usec = 0;
448 * Prepare the reply packet for sending through dhcp_socket_send()
450 request->reply->dst_ipaddr.af = AF_INET;
451 request->reply->src_ipaddr.af = AF_INET;
452 request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = sock->src_ipaddr.ipaddr.ip4addr.s_addr;
453 request->reply->src_ipaddr.prefix = 32;
456 * They didn't set a proper src_ipaddr, but we want to
457 * send the packet with a source IP. If there's a server
458 * identifier, use it.
460 if (request->reply->src_ipaddr.ipaddr.ip4addr.s_addr == INADDR_ANY) {
461 vp = fr_pair_find_by_num(request->reply->vps, PW_PACKET_SRC_IP_ADDRESS, 0, TAG_ANY);
462 if (!vp) vp = fr_pair_find_by_num(request->reply->vps, 54, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-DHCP-Server-Identifier */
464 request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
468 request->reply->dst_port = request->packet->src_port;
469 request->reply->src_port = request->packet->dst_port;
472 * Answer to client's nearest DHCP relay.
474 * Which may be different than the giaddr given in the
475 * packet to the client. i.e. the relay may have a
476 * public IP, but the gateway a private one.
478 vp = fr_pair_find_by_num(request->reply->vps, 272, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Relay-IP-Address */
479 if (vp && (vp->vp_ipaddr != ntohl(INADDR_ANY))) {
480 RDEBUG("DHCP: Reply will be unicast to giaddr from original packet");
481 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
482 request->reply->dst_port = request->packet->dst_port;
484 vp = fr_pair_find_by_num(request->reply->vps, PW_PACKET_DST_PORT, 0, TAG_ANY);
485 if (vp) request->reply->dst_port = vp->vp_integer;
491 * Answer to client's nearest DHCP gateway. In this
492 * case, the client can reach the gateway, as can the
495 * We also use *our* source port as the destination port.
496 * Gateways are servers, and listen on the server port,
497 * not the client port.
499 vp = fr_pair_find_by_num(request->reply->vps, 266, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Gateway-IP-Address */
500 if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) {
501 RDEBUG("DHCP: Reply will be unicast to giaddr");
502 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
503 request->reply->dst_port = request->packet->dst_port;
508 * If it's a NAK, or the broadcast flag was set, ond
509 * there's no client-ip-address, send a broadcast.
511 if ((request->reply->code == PW_DHCP_NAK) ||
512 ((vp = fr_pair_find_by_num(request->reply->vps, 262, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Flags */
513 (vp->vp_integer & 0x8000) &&
514 ((vp = fr_pair_find_by_num(request->reply->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Client-IP-Address */
515 (vp->vp_ipaddr == htonl(INADDR_ANY))))) {
522 * - Broadcast flag is set up and ciaddr == NULL
524 RDEBUG("DHCP: Reply will be broadcast");
525 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
532 * Unicast to ciaddr if present, otherwise to yiaddr.
534 if ((vp = fr_pair_find_by_num(request->reply->vps, 263, DHCP_MAGIC_VENDOR, TAG_ANY)) && /* DHCP-Client-IP-Address */
535 (vp->vp_ipaddr != htonl(INADDR_ANY))) {
536 RDEBUG("DHCP: Reply will be sent unicast to client-ip-address");
537 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
541 vp = fr_pair_find_by_num(request->reply->vps, 264, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Your-IP-Address */
543 RDEBUG("DHCP: Failed to find DHCP-Client-IP-Address or DHCP-Your-IP-Address for request; "
546 * There is nowhere to send the response to, so don't bother.
548 request->reply->code = 0;
554 * The system is configured to listen for broadcast
555 * packets, which means we'll need to send unicast
556 * replies, to IPs which haven't yet been assigned.
557 * Therefore, we need to update the ARP table.
559 * However, they haven't specified a interface. So we
560 * can't update the ARP table. And we must send a
561 * broadcast response.
563 if (sock->lsock.broadcast && !sock->src_interface) {
564 WARN("You MUST set \"interface\" if you have \"broadcast = yes\"");
565 RDEBUG("DHCP: Reply will be broadcast as no interface was defined");
566 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
570 RDEBUG("DHCP: Reply will be unicast to your-ip-address");
571 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
574 * When sending a DHCP_OFFER, make sure our ARP table
575 * contains an entry for the client IP address.
576 * Otherwise the packet may not be sent to the client, as
577 * the OS has no ARP entry for it.
579 * This is a cute hack to avoid us having to create a raw
580 * socket to send DHCP packets.
582 if (request->reply->code == PW_DHCP_OFFER) {
583 VALUE_PAIR *hwvp = fr_pair_find_by_num(request->reply->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Client-Hardware-Address */
585 if (!hwvp) return -1;
587 if (fr_dhcp_add_arp_entry(request->reply->sockfd, sock->src_interface, hwvp, vp) < 0) {
588 RDEBUG("Failed adding arp entry: %s", fr_strerror());
593 if (request->packet->src_ipaddr.ipaddr.ip4addr.s_addr != ntohl(INADDR_NONE)) {
594 RDEBUG("DHCP: Request will be unicast to the unicast source IP address");
595 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
597 RDEBUG("DHCP: Reply will be broadcast as this system does not support ARP updates");
598 request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
605 static int dhcp_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
607 int rcode, broadcast = 1;
614 * Set if before parsing, so the user can forcibly turn
619 rcode = common_socket_parse(cs, this);
620 if (rcode != 0) return rcode;
622 if (check_config) return 0;
626 if (!sock->lsock.interface) {
627 WARN("No \"interface\" setting is defined. Only unicast DHCP will work");
631 * See whether or not we enable broadcast packets.
633 cp = cf_pair_find(cs, "broadcast");
635 char const *value = cf_pair_value(cp);
636 if (value && (strcmp(value, "no") == 0)) {
642 if (setsockopt(this->fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
643 ERROR("Can't set broadcast option: %s\n",
649 if (setsockopt(this->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
650 ERROR("Can't set re-use addres option: %s\n",
656 * Undocumented extension for testing without
657 * destroying your network!
659 sock->suppress_responses = false;
660 cp = cf_pair_find(cs, "suppress_responses");
662 rcode = cf_item_parse(cs, "suppress_responses", FR_ITEM_POINTER(PW_TYPE_BOOLEAN, &sock->suppress_responses), NULL);
663 if (rcode < 0) return -1;
666 cp = cf_pair_find(cs, "src_interface");
668 rcode = cf_item_parse(cs, "src_interface", FR_ITEM_POINTER(PW_TYPE_STRING, &sock->src_interface), NULL);
669 if (rcode < 0) return -1;
671 sock->src_interface = sock->lsock.interface;
674 if (!sock->src_interface && sock->lsock.interface) {
675 sock->src_interface = talloc_typed_strdup(sock, sock->lsock.interface);
678 cp = cf_pair_find(cs, "src_ipaddr");
680 memset(&sock->src_ipaddr, 0, sizeof(sock->src_ipaddr));
681 sock->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
682 rcode = cf_item_parse(cs, "src_ipaddr", FR_ITEM_POINTER(PW_TYPE_IPV4_ADDR, &sock->src_ipaddr), NULL);
683 if (rcode < 0) return -1;
685 sock->src_ipaddr.af = AF_INET;
687 memcpy(&sock->src_ipaddr, &sock->lsock.my_ipaddr, sizeof(sock->src_ipaddr));
691 * Initialize the fake client.
693 client = &sock->dhcp_client;
694 memset(client, 0, sizeof(*client));
695 client->ipaddr.af = AF_INET;
696 client->ipaddr.ipaddr.ip4addr.s_addr = ntohl(INADDR_NONE);
697 client->ipaddr.prefix = 0;
698 client->longname = client->shortname = "dhcp";
699 client->secret = client->shortname;
700 client->nas_type = talloc_typed_strdup(sock, "none");
707 * Check if an incoming request is "ok"
709 * It takes packets, not requests. It sees if the packet looks
710 * OK. If so, it does a number of sanity checks on it.
712 static int dhcp_socket_recv(rad_listen_t *listener)
714 RADIUS_PACKET *packet;
717 packet = fr_dhcp_recv(listener->fd);
719 ERROR("%s", fr_strerror());
723 sock = listener->data;
724 if (!request_receive(NULL, listener, packet, &sock->dhcp_client, dhcp_process)) {
734 * Send an authentication response packet
736 static int dhcp_socket_send(rad_listen_t *listener, REQUEST *request)
740 rad_assert(request->listener == listener);
741 rad_assert(listener->send == dhcp_socket_send);
743 if (request->reply->code == 0) return 0; /* don't reply */
745 if (fr_dhcp_encode(request->reply) < 0) {
746 DEBUG("dhcp_socket_send: ERROR\n");
750 sock = listener->data;
751 if (sock->suppress_responses) return 0;
753 return fr_dhcp_send(request->reply);
757 static int dhcp_socket_encode(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
759 DEBUG2("NO ENCODE!");
764 static int dhcp_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
766 return fr_dhcp_decode(request->packet);
769 extern fr_protocol_t proto_dhcp;
770 fr_protocol_t proto_dhcp = {
771 .magic = RLM_MODULE_INIT,
773 .inst_size = sizeof(dhcp_socket_t),
774 .parse = dhcp_socket_parse,
775 .recv = dhcp_socket_recv,
776 .send = dhcp_socket_send,
777 .print = common_socket_print,
778 .encode = dhcp_socket_encode,
779 .decode = dhcp_socket_decode