All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dhcpd.c
Go to the documentation of this file.
1 /*
2  * dhcp.c DHCP processing.
3  *
4  * Version: $Id: f239f2f95425f6ce95fc535c185a51bd231f22c0 $
5  *
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.
10  *
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.
15  *
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
19  *
20  * Copyright 2008 The FreeRADIUS server project
21  * Copyright 2008,2011 Alan DeKok <aland@deployingradius.com>
22  */
23 
24 /*
25  * Standard sequence:
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
30  *
31  * Relay sequence:
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
42  *
43  * Note: NACK are broadcasted, rest is unicast, unless client asked
44  * for a broadcast
45  */
46 
47 
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>
54 
55 #ifndef __MINGW32__
56 #include <sys/ioctl.h>
57 #endif
58 
59 /*
60  * Same contents as listen_socket_t.
61  */
62 typedef struct dhcp_socket_t {
64 
65  /*
66  * DHCP-specific additions.
67  */
70  char const *src_interface;
73 
74 static void dhcp_packet_debug(REQUEST *request, RADIUS_PACKET *packet, bool received);
75 
76 #ifdef WITH_UDPFROMTO
77 static int dhcprelay_process_client_request(REQUEST *request)
78 {
79  uint8_t maxhops = 16;
80  VALUE_PAIR *vp, *giaddr;
81  dhcp_socket_t *sock;
82 
83  rad_assert(request->packet->data[0] == 1);
84 
85  /*
86  * Do the forward by ourselves, do not rely on dhcp_socket_send()
87  */
88  request->reply->code = 0;
89 
90  /*
91  * It's invalid to have giaddr=0 AND a relay option
92  */
93  giaddr = fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, 266, TAG_ANY); /* DHCP-Gateway-IP-Address */
94  if (giaddr && (giaddr->vp_ipaddr == htonl(INADDR_ANY)) &&
95  fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, 82, TAG_ANY)) { /* DHCP-Relay-Agent-Information */
96  RDEBUG2("Received packet with giaddr = 0 and containing relay option: Discarding packet");
97  return 1;
98  }
99 
100  /*
101  * RFC 1542 (BOOTP), page 15
102  *
103  * Drop requests if hop-count > 16 or admin specified another value
104  */
105  if ((vp = fr_pair_find_by_num(request->config, DHCP_MAGIC_VENDOR, 271, TAG_ANY))) { /* DHCP-Relay-Max-Hop-Count */
106  maxhops = vp->vp_integer;
107  }
108  vp = fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, 259, TAG_ANY); /* DHCP-Hop-Count */
109  rad_assert(vp != NULL);
110  if (vp->vp_integer > maxhops) {
111  RDEBUG2("Number of hops is greater than %d: not relaying", maxhops);
112  return 1;
113  } else {
114  /* Increment hop count */
115  vp->vp_integer++;
116  }
117 
118  sock = request->listener->data;
119 
120  /*
121  * Forward the request to the next server using the
122  * incoming request as a template.
123  */
124  /* set SRC ipaddr/port to the listener ipaddr/port */
125  request->packet->src_ipaddr.af = AF_INET;
126  request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = sock->lsock.my_ipaddr.ipaddr.ip4addr.s_addr;
127  request->packet->src_port = sock->lsock.my_port;
128 
129  vp = fr_pair_find_by_num(request->config, DHCP_MAGIC_VENDOR, 270, TAG_ANY); /* DHCP-Relay-To-IP-Address */
130  rad_assert(vp != NULL);
131 
132  /* set DEST ipaddr/port to the next server ipaddr/port */
133  request->packet->dst_ipaddr.af = AF_INET;
134  request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
135  request->packet->dst_port = sock->lsock.my_port;
136 
137  /*
138  * Relaying is not proxying, we just forward it on and forget
139  * about it, not sending a response to the DHCP client.
140  */
141  dhcp_packet_debug(request, request->packet, false);
142 
143  if (fr_dhcp_encode(request->packet) < 0) {
144  RERROR("Failed encoding DHCP packet: %s", fr_strerror());
145  return -1;
146  }
147 
148  return fr_dhcp_send_socket(request->packet);
149 }
150 
151 
152 /*
153  * We've seen a reply from a server.
154  * i.e. we're a relay.
155  */
156 static int dhcprelay_process_server_reply(REQUEST *request)
157 {
158  VALUE_PAIR *vp, *giaddr;
159  dhcp_socket_t *sock;
160 
161  rad_assert(request->packet->data[0] == 2);
162 
163  /*
164  * Do the forward by ourselves, do not rely on dhcp_socket_send()
165  */
166  request->reply->code = 0;
167 
168  sock = request->listener->data;
169 
170  /*
171  * Check that packet is for us.
172  */
173  giaddr = fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, 266, TAG_ANY); /* DHCP-Gateway-IP-Address */
174 
175  /* --with-udpfromto is needed just for the following test */
176  if (!giaddr || giaddr->vp_ipaddr != request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr) {
177  RDEBUG2("Packet received from server was not for us (was for 0x%x). Discarding packet",
178  ntohl(request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr));
179  return 1;
180  }
181 
182  /* set SRC ipaddr/port to the listener ipaddr/port */
183  request->packet->src_ipaddr.af = AF_INET;
184  request->packet->src_port = sock->lsock.my_port;
185 
186  /* set DEST ipaddr/port to clientip/68 or broadcast in specific cases */
187  request->packet->dst_ipaddr.af = AF_INET;
188 
189  /*
190  * We're a relay, and send the reply to giaddr.
191  */
192  request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = giaddr->vp_ipaddr;
193  request->reply->dst_port = request->packet->dst_port; /* server port */
194 
195  if ((request->packet->code == PW_DHCP_NAK) ||
196  !sock->src_interface ||
197  ((vp = fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, 262, TAG_ANY)) /* DHCP-Flags */ &&
198  (vp->vp_integer & 0x8000) &&
199  ((vp = fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, 263, TAG_ANY)) /* DHCP-Client-IP-Address */ &&
200  (vp->vp_ipaddr == htonl(INADDR_ANY))))) {
201  /*
202  * RFC 2131, page 23
203  *
204  * Broadcast on
205  * - DHCPNAK
206  * or
207  * - Broadcast flag is set up and ciaddr == NULL
208  */
209  RDEBUG2("Response will be broadcast");
210  request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
211  } else {
212  /*
213  * RFC 2131, page 23
214  *
215  * Unicast to
216  * - ciaddr if present
217  * otherwise to yiaddr
218  */
219  if ((vp = fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, 263, TAG_ANY)) /* DHCP-Client-IP-Address */ &&
220  (vp->vp_ipaddr != htonl(INADDR_ANY))) {
221  request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
222  } else {
223  vp = fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, 264, TAG_ANY); /* DHCP-Your-IP-Address */
224  if (!vp) {
225  REDEBUG("Failed to find IP Address for request");
226  return -1;
227  }
228 
229  RDEBUG2("Response will be unicast to &DHCP-Your-IP-Address");
230  request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
231 
232  /*
233  * When sending a DHCP_OFFER, make sure our ARP table
234  * contains an entry for the client IP address, or else
235  * packet may not be forwarded if it was the first time
236  * the client was requesting an IP address.
237  */
238  if (request->packet->code == PW_DHCP_OFFER) {
240  TAG_ANY); /* DHCP-Client-Hardware-Address */
241  if (hwvp == NULL) {
242  RDEBUG2("DHCP_OFFER packet received with no Client Hardware Address. "
243  "Discarding packet");
244  return 1;
245  }
246  if (fr_dhcp_add_arp_entry(request->packet->sockfd, sock->src_interface, hwvp, vp) < 0) {
247  REDEBUG("Failed adding ARP entry: %s", fr_strerror());
248  return -1;
249  }
250  }
251  }
252  }
253 
254  /*
255  * Our response doesn't go through process.c
256  */
257  dhcp_packet_debug(request, request->packet, false);
258 
259  if (fr_dhcp_encode(request->packet) < 0) {
260  RERROR("Failed encoding DHCP packet: %s", fr_strerror());
261  return -1;
262  }
263 
264  return fr_dhcp_send_socket(request->packet);
265 }
266 #else /* WITH_UDPFROMTO */
268 {
269  WARN("DHCP Relaying requires the server to be configured with UDPFROMTO");
270  return -1;
271 }
272 
274 {
275  WARN("DHCP Relaying requires the server to be configured with UDPFROMTO");
276  return -1;
277 }
278 
279 #endif /* WITH_UDPFROMTO */
280 
281 static const uint32_t attrnums[] = {
282  57, /* DHCP-DHCP-Maximum-Msg-Size */
283  256, /* DHCP-Opcode */
284  257, /* DHCP-Hardware-Type */
285  258, /* DHCP-Hardware-Address-Length */
286  259, /* DHCP-Hop-Count */
287  260, /* DHCP-Transaction-Id */
288  262, /* DHCP-Flags */
289  263, /* DHCP-Client-IP-Address */
290  266, /* DHCP-Gateway-IP-Address */
291  267 /* DHCP-Client-Hardware-Address */
292 };
293 
294 static int dhcp_process(REQUEST *request)
295 {
296  int rcode;
297  unsigned int i;
298  VALUE_PAIR *vp;
299  dhcp_socket_t *sock;
300 
301  /*
302  * If there's a giaddr, save it as the Relay-IP-Address
303  * in the response. That way the later code knows where
304  * to send the reply.
305  */
306  vp = fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, 266, TAG_ANY); /* DHCP-Gateway-IP-Address */
307  if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) {
308  VALUE_PAIR *relay;
309 
310  /* DHCP-Relay-IP-Address */
311  relay = radius_pair_create(request->reply, &request->reply->vps,
312  272, DHCP_MAGIC_VENDOR);
313  if (relay) relay->vp_ipaddr = vp->vp_ipaddr;
314  }
315 
316  vp = fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, 53, TAG_ANY); /* DHCP-Message-Type */
317  if (vp) {
318  fr_dict_enum_t *dv = fr_dict_enum_by_da(NULL, vp->da, vp->vp_integer);
319  RDEBUG("Trying sub-section dhcp %s {...}", dv ? dv->name : "<unknown>");
320  rcode = process_post_auth(vp->vp_integer, request);
321  } else {
322  REDEBUG("Failed to find DHCP-Message-Type in packet!");
323  rcode = RLM_MODULE_FAIL;
324  }
325 
326  vp = fr_pair_find_by_num(request->reply->vps, DHCP_MAGIC_VENDOR, 53, TAG_ANY); /* DHCP-Message-Type */
327  if (vp) {
328  request->reply->code = vp->vp_integer;
329  if ((request->reply->code != 0) &&
330  (request->reply->code < PW_DHCP_OFFSET)) {
331  request->reply->code += PW_DHCP_OFFSET;
332  }
333  }
334  else switch (rcode) {
335  case RLM_MODULE_OK:
336  case RLM_MODULE_UPDATED:
337  if (request->packet->code == PW_DHCP_DISCOVER) {
338  request->reply->code = PW_DHCP_OFFER;
339  break;
340 
341  } else if (request->packet->code == PW_DHCP_REQUEST) {
342  request->reply->code = PW_DHCP_ACK;
343  break;
344  }
345  request->reply->code = PW_DHCP_NAK;
346  break;
347 
348  default:
349  case RLM_MODULE_REJECT:
350  case RLM_MODULE_FAIL:
351  case RLM_MODULE_INVALID:
352  case RLM_MODULE_NOOP:
353  case RLM_MODULE_NOTFOUND:
354  if (request->packet->code == PW_DHCP_DISCOVER) {
355  request->reply->code = 0; /* ignore the packet */
356  } else {
357  request->reply->code = PW_DHCP_NAK;
358  }
359  break;
360 
361  case RLM_MODULE_HANDLED:
362  request->reply->code = 0; /* ignore the packet */
363  break;
364  }
365 
366  /*
367  * TODO: Handle 'output' of RLM_MODULE when acting as a
368  * DHCP relay We may want to not forward packets in
369  * certain circumstances.
370  */
371 
372  /*
373  * Handle requests when acting as a DHCP relay
374  */
375  vp = fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, 256, TAG_ANY); /* DHCP-Opcode */
376  if (!vp) {
377  REDEBUG("Someone deleted the DHCP-Opcode!");
378  return 1;
379  }
380 
381  /* BOOTREPLY received on port 67 (i.e. from a server) */
382  if (vp->vp_integer == 2) {
383  return dhcprelay_process_server_reply(request);
384  }
385 
386  /* Packet from client, and we have DHCP-Relay-To-IP-Address */
387  if (fr_pair_find_by_num(request->config, DHCP_MAGIC_VENDOR, 270, TAG_ANY)) {
388  return dhcprelay_process_client_request(request);
389  }
390 
391  /* else it's a packet from a client, without relaying */
392  rad_assert(vp->vp_integer == 1); /* BOOTREQUEST */
393 
394  sock = request->listener->data;
395 
396  /*
397  * Handle requests when acting as a DHCP server
398  */
399 
400  /*
401  * Releases don't get replies.
402  */
403  if (request->packet->code == PW_DHCP_RELEASE) {
404  request->reply->code = 0;
405  }
406 
407  if (request->reply->code == 0) {
408  return 1;
409  }
410 
411  request->reply->sockfd = request->packet->sockfd;
412 
413  /*
414  * Copy specific fields from packet to reply, if they
415  * don't already exist
416  */
417  for (i = 0; i < sizeof(attrnums) / sizeof(attrnums[0]); i++) {
418  uint32_t attr = attrnums[i];
419 
420  if (fr_pair_find_by_num(request->reply->vps, DHCP_MAGIC_VENDOR, attr, TAG_ANY)) continue;
421 
422  vp = fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, attr, TAG_ANY);
423  if (vp) {
424  fr_pair_add(&request->reply->vps, fr_pair_copy(request->reply, vp));
425  }
426  }
427 
428  vp = fr_pair_find_by_num(request->reply->vps, DHCP_MAGIC_VENDOR, 256, TAG_ANY); /* DHCP-Opcode */
429  rad_assert(vp != NULL);
430  vp->vp_integer = 2; /* BOOTREPLY */
431 
432  /*
433  * Allow NAKs to be delayed for a short period of time.
434  */
435  if (request->reply->code == PW_DHCP_NAK) {
436  vp = fr_pair_find_by_num(request->reply->vps, 0, PW_FREERADIUS_RESPONSE_DELAY, TAG_ANY);
437  if (vp) {
438  if (vp->vp_integer <= 10) {
439  request->response_delay.tv_sec = vp->vp_integer;
440  request->response_delay.tv_usec = 0;
441  } else {
442  request->response_delay.tv_sec = 10;
443  request->response_delay.tv_usec = 0;
444  }
445  } else {
446 #define USEC 1000000
447  vp = fr_pair_find_by_num(request->reply->vps, 0, PW_FREERADIUS_RESPONSE_DELAY_USEC, TAG_ANY);
448  if (vp) {
449  if (vp->vp_integer <= 10 * USEC) {
450  request->response_delay.tv_sec = vp->vp_integer / USEC;
451  request->response_delay.tv_usec = vp->vp_integer % USEC;
452  } else {
453  request->response_delay.tv_sec = 10;
454  request->response_delay.tv_usec = 0;
455  }
456  }
457  }
458  }
459 
460  /*
461  * Prepare the reply packet for sending through dhcp_socket_send()
462  */
463  request->reply->dst_ipaddr.af = AF_INET;
464  request->reply->src_ipaddr.af = AF_INET;
465  request->reply->src_ipaddr.prefix = 32;
466 
467  /*
468  * Packet-Src-IP-Address has highest precedence
469  */
470  vp = fr_pair_find_by_num(request->reply->vps, 0, PW_PACKET_SRC_IP_ADDRESS, TAG_ANY);
471  if (vp) {
472  request->reply->if_index = 0; /* Must be 0, we don't know the outbound if_index */
473  request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
474  /*
475  * The request was unicast (via a relay)
476  */
477  } else if (request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr != htonl(INADDR_BROADCAST) &&
478  request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr != htonl(INADDR_ANY)) {
479  request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr;
480  request->reply->if_index = request->packet->if_index;
481  /*
482  * The listener was bound to an IP address, or we determined
483  * the address automatically, as it was the only address bound
484  * to the interface, and we bound to the interface.
485  */
486  } else if (sock->src_ipaddr.ipaddr.ip4addr.s_addr != htonl(INADDR_ANY)) {
487  request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = sock->src_ipaddr.ipaddr.ip4addr.s_addr;
488 #ifdef WITH_IFINDEX_IPADDR_RESOLUTION
489  /*
490  * We built with udpfromto and have the if_index of the receiving
491  * interface, which we can now resolve to an IP address.
492  */
493  } else if (request->packet->if_index > 0) {
494  fr_ipaddr_t primary;
495 
496  if (fr_ipaddr_from_ifindex(&primary, request->packet->sockfd, request->packet->dst_ipaddr.af,
497  request->packet->if_index) < 0) {
498  REDEBUG("Failed determining src_ipaddr from if_index: %s", fr_strerror());
499  return -1;
500  }
501  request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = primary.ipaddr.ip4addr.s_addr;
502 #endif
503  /*
504  * There's a Server-Identification attribute
505  */
506  } else if ((vp = fr_pair_find_by_num(request->reply->vps, DHCP_MAGIC_VENDOR, 54, TAG_ANY))) {
507  request->reply->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
508  } else {
509  REDEBUG("Unable to determine correct src_ipaddr for response");
510  return -1;
511  }
512  request->reply->dst_port = request->packet->src_port;
513  request->reply->src_port = request->packet->dst_port;
514 
515  /*
516  * Answer to client's nearest DHCP relay.
517  *
518  * Which may be different than the giaddr given in the
519  * packet to the client. i.e. the relay may have a
520  * public IP, but the gateway a private one.
521  */
522  vp = fr_pair_find_by_num(request->reply->vps, DHCP_MAGIC_VENDOR, 272, TAG_ANY); /* DHCP-Relay-IP-Address */
523  if (vp && (vp->vp_ipaddr != ntohl(INADDR_ANY))) {
524  RDEBUG2("Reply will be unicast to giaddr from original packet");
525  request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
526  request->reply->dst_port = request->packet->dst_port;
527 
528  vp = fr_pair_find_by_num(request->reply->vps, 0, PW_PACKET_DST_PORT, TAG_ANY);
529  if (vp) request->reply->dst_port = vp->vp_integer;
530 
531  return 1;
532  }
533 
534  /*
535  * Answer to client's nearest DHCP gateway. In this
536  * case, the client can reach the gateway, as can the
537  * server.
538  *
539  * We also use *our* source port as the destination port.
540  * Gateways are servers, and listen on the server port,
541  * not the client port.
542  */
543  vp = fr_pair_find_by_num(request->reply->vps, DHCP_MAGIC_VENDOR, 266, TAG_ANY); /* DHCP-Gateway-IP-Address */
544  if (vp && (vp->vp_ipaddr != htonl(INADDR_ANY))) {
545  RDEBUG2("Reply will be unicast to giaddr");
546  request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
547  request->reply->dst_port = request->packet->dst_port;
548  return 1;
549  }
550 
551  /*
552  * If it's a NAK, or the broadcast flag was set, ond
553  * there's no client-ip-address, send a broadcast.
554  */
555  if ((request->reply->code == PW_DHCP_NAK) ||
556  ((vp = fr_pair_find_by_num(request->reply->vps, DHCP_MAGIC_VENDOR, 262, TAG_ANY)) && /* DHCP-Flags */
557  (vp->vp_integer & 0x8000) &&
558  ((vp = fr_pair_find_by_num(request->reply->vps, DHCP_MAGIC_VENDOR, 263, TAG_ANY)) && /* DHCP-Client-IP-Address */
559  (vp->vp_ipaddr == htonl(INADDR_ANY))))) {
560  /*
561  * RFC 2131, page 23
562  *
563  * Broadcast on
564  * - DHCPNAK
565  * or
566  * - Broadcast flag is set up and ciaddr == NULL
567  */
568  RDEBUG2("Reply will be broadcast");
569  request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
570  return 1;
571  }
572 
573  /*
574  * RFC 2131, page 23
575  *
576  * Unicast to ciaddr if present, otherwise to yiaddr.
577  */
578  if ((vp = fr_pair_find_by_num(request->reply->vps, DHCP_MAGIC_VENDOR, 263, TAG_ANY)) && /* DHCP-Client-IP-Address */
579  (vp->vp_ipaddr != htonl(INADDR_ANY))) {
580  RDEBUG2("Reply will be sent unicast to &DHCP-Client-IP-Address");
581  request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
582  return 1;
583  }
584 
585  vp = fr_pair_find_by_num(request->reply->vps, DHCP_MAGIC_VENDOR, 264, TAG_ANY); /* DHCP-Your-IP-Address */
586  if (!vp) {
587  RDEBUG2("Failed to find &DHCP-Client-IP-Address or &DHCP-Your-IP-Address for request; "
588  "not responding");
589  /*
590  * There is nowhere to send the response to, so don't bother.
591  */
592  request->reply->code = 0;
593  return -1;
594  }
595 
596 #ifdef SIOCSARP
597  /*
598  * The system is configured to listen for broadcast
599  * packets, which means we'll need to send unicast
600  * replies, to IPs which haven't yet been assigned.
601  * Therefore, we need to update the ARP table.
602  *
603  * However, they haven't specified a interface. So we
604  * can't update the ARP table. And we must send a
605  * broadcast response.
606  */
607  if (sock->lsock.broadcast && !sock->src_interface) {
608  WARN("You MUST set \"interface\" if you have \"broadcast = yes\"");
609  RDEBUG2("Reply will be broadcast as no interface was defined");
610  request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
611  return 1;
612  }
613 
614  RDEBUG2("Reply will be unicast to &DHCP-Your-IP-Address");
615  request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
616 
617  /*
618  * When sending a DHCP_OFFER, make sure our ARP table
619  * contains an entry for the client IP address.
620  * Otherwise the packet may not be sent to the client, as
621  * the OS has no ARP entry for it.
622  *
623  * This is a cute hack to avoid us having to create a raw
624  * socket to send DHCP packets.
625  */
626  if (request->reply->code == PW_DHCP_OFFER) {
627  VALUE_PAIR *hwvp = fr_pair_find_by_num(request->reply->vps, 267, DHCP_MAGIC_VENDOR, TAG_ANY); /* DHCP-Client-Hardware-Address */
628 
629  if (!hwvp) return -1;
630 
631  if (fr_dhcp_add_arp_entry(request->reply->sockfd, sock->src_interface, hwvp, vp) < 0) {
632  REDEBUG("Failed adding arp entry: %s", fr_strerror());
633  return -1;
634  }
635  }
636 #else
637  if (request->packet->src_ipaddr.ipaddr.ip4addr.s_addr != ntohl(INADDR_NONE)) {
638  RDEBUG2("Reply will be unicast to the unicast source IP address");
639  request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = request->packet->src_ipaddr.ipaddr.ip4addr.s_addr;
640  } else {
641  RDEBUG2("Reply will be broadcast as this system does not support ARP updates");
642  request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_BROADCAST);
643  }
644 #endif
645 
646  return 1;
647 }
648 
649 /*
650  * We allow using PCAP, but only if there's no SO_BINDTODEVICE
651  */
652 #ifndef SO_BINDTODEVICE
653 #ifdef HAVE_PCAP_H
654 #define PCAP_RAW_SOCKETS (1)
655 #endif
656 #endif
657 
658 #ifdef PCAP_RAW_SOCKETS
659 /** Build PCAP filter string to pass to libpcap based on listen section
660  * Will be called by init_pcap.
661  *
662  * @param this listen section
663  * @return PCAP filter string
664  */
665 static const char *dhcp_pcap_filter_build(rad_listen_t *this)
666 {
667  dhcp_socket_t *sock = this->data;
668  char *filter;
669 
670  /*
671  * Set the port filter
672  */
673  filter = talloc_strdup(this, "(udp and dst port ");
674  if (sock->lsock.my_port) {
675  filter = talloc_asprintf_append_buffer(filter, "%u)", sock->lsock.my_port);
676  } else {
677  filter = talloc_strdup_append_buffer(filter, "bootps)");
678  }
679 
680  if (!fr_is_inaddr_any(&sock->lsock.my_ipaddr)) {
681  char buffer[INET_ADDRSTRLEN];
682  fr_inet_ntoh(&sock->lsock.my_ipaddr, buffer, sizeof(buffer));
683 
684  if (sock->lsock.broadcast) {
685  filter = talloc_asprintf_append_buffer(filter, " and (dst host %s or dst host 255.255.255.255)",
686  buffer);
687  } else {
688  filter = talloc_asprintf_append_buffer(filter, " and dst host %s", buffer);
689  }
690  }
691 
692  return filter;
693 }
694 #endif
695 
697 {
698  int rcode;
699  dhcp_socket_t *sock = this->data;
700  RADCLIENT *client;
701  CONF_PAIR *cp;
702 
703 #ifdef PCAP_RAW_SOCKETS
704  sock->lsock.pcap_filter_builder = dhcp_pcap_filter_build;
705  sock->lsock.pcap_type = PCAP_INTERFACE_IN_OUT;
706 #endif
707 
708  /*
709  * Set if before parsing, so the user can forcibly turn
710  * it off later.
711  */
712  this->nodup = true;
713 
714  rcode = common_socket_parse(cs, this);
715  if (rcode != 0) return rcode;
716 
717  if (!sock->lsock.interface) WARN("No \"interface\" setting is defined. Only unicast DHCP will work");
718 
719  /*
720  * Undocumented extension for testing without
721  * destroying your network!
722  */
723  sock->suppress_responses = false;
724  cp = cf_pair_find(cs, "suppress_responses");
725  if (cp) {
726  rcode = cf_pair_parse(cs, "suppress_responses", FR_ITEM_POINTER(PW_TYPE_BOOLEAN, &sock->suppress_responses), NULL, T_INVALID);
727  if (rcode < 0) return -1;
728  }
729 
730  cp = cf_pair_find(cs, "src_interface");
731  if (cp) {
732  rcode = cf_pair_parse(cs, "src_interface", FR_ITEM_POINTER(PW_TYPE_STRING, &sock->src_interface), NULL, T_INVALID);
733  if (rcode < 0) return -1;
734  } else {
735  sock->src_interface = sock->lsock.interface;
736  }
737 
738  if (!sock->src_interface && sock->lsock.interface) {
739  sock->src_interface = talloc_typed_strdup(sock, sock->lsock.interface);
740  }
741 
742  /*
743  * Set the source IP address explicitly.
744  */
745  cp = cf_pair_find(cs, "src_ipaddr");
746  if (cp) {
747  memset(&sock->src_ipaddr, 0, sizeof(sock->src_ipaddr));
748  sock->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_NONE);
749  rcode = cf_pair_parse(cs, "src_ipaddr", FR_ITEM_POINTER(PW_TYPE_IPV4_ADDR, &sock->src_ipaddr), NULL, T_INVALID);
750  if (rcode < 0) return -1;
751 
752  sock->src_ipaddr.af = AF_INET;
753  /*
754  * Or by looking up the IP address associated with the
755  * src_interface or interface (if we're binding to INADDR_ANY).
756  */
757  } else {
758  char buffer[INET_ADDRSTRLEN];
759 
760  if (fr_is_inaddr_any(&sock->lsock.my_ipaddr) && sock->src_interface) {
761  if (fr_ipaddr_from_ifname(&sock->src_ipaddr, AF_INET, sock->src_interface) < 0) {
762  WARN("Failed resolving interface %s to IP address: %s", sock->src_interface,
763  fr_strerror());
764  WARN("Will continue, but source address must be set within the DHCP virtual server");
765  goto src_addr_is_bound_addr;
766  }
767  inet_ntop(sock->src_ipaddr.af, &sock->src_ipaddr.ipaddr.ip4addr.s_addr, buffer, sizeof(buffer));
768  rad_assert(sock->src_ipaddr.af == AF_INET);
769  } else {
770  src_addr_is_bound_addr:
771  sock->src_ipaddr = sock->lsock.my_ipaddr;
772  }
773 
774  /*
775  * If src is not INADDR_ANY add a configuration item
776  */
777  if (!fr_is_inaddr_any(&sock->src_ipaddr)) {
778  /*
779  * Magic defaults FTW.
780  *
781  * This lets %{config:} work as expected, if we want to set
782  * DHCP-DHCP-Server-Identifier.
783  */
784  inet_ntop(sock->src_ipaddr.af, &sock->src_ipaddr.ipaddr.ip4addr.s_addr, buffer, sizeof(buffer));
785  DEBUG2("\tsrc_ipaddr = \"%s\"", buffer);
786  cp = cf_pair_alloc(cs, "src_ipaddr", buffer, T_OP_SET, T_BARE_WORD, T_BARE_WORD);
787  if (!cp) return -1;
788  cf_pair_add(cs, cp);
789  }
790  }
791 
792  /*
793  * Initialize the fake client.
794  */
795  client = &sock->dhcp_client;
796  memset(client, 0, sizeof(*client));
797  client->ipaddr.af = AF_INET;
798  client->ipaddr.ipaddr.ip4addr.s_addr = ntohl(INADDR_NONE);
799  client->ipaddr.prefix = 0;
800  client->longname = client->shortname = "dhcp";
801  client->secret = client->shortname;
802  client->nas_type = talloc_typed_strdup(sock, "none");
803 
804  return 0;
805 }
806 
807 
808 /*
809  * Check if an incoming request is "ok"
810  *
811  * It takes packets, not requests. It sees if the packet looks
812  * OK. If so, it does a number of sanity checks on it.
813  */
814 static int dhcp_socket_recv(rad_listen_t *listener)
815 {
816  RADIUS_PACKET *packet;
817  dhcp_socket_t *sock = listener->data;
818  RADCLIENT *client = &sock->dhcp_client;
819 
820 #ifdef __clang_analyzer__
821  rad_assert(client);
822 #endif
823  FR_STATS_INC(auth, total_requests);
825 
826 #ifdef PCAP_RAW_SOCKETS
827  if (sock->lsock.pcap) {
828  packet = fr_dhcp_recv_pcap(sock->lsock.pcap);
829  } else
830 #endif
831  {
832  packet = fr_dhcp_recv_socket(listener->fd);
833  }
834 
835  if (!packet) {
836  FR_STATS_INC(auth, total_malformed_requests);
837  ERROR("%s", fr_strerror());
838  return 0;
839  }
840 
841  if (!request_receive(NULL, listener, packet, &sock->dhcp_client, dhcp_process)) {
842  FR_STATS_INC(auth, total_packets_dropped);
843  fr_radius_free(&packet);
844  return 0;
845  }
846 
847  return 1;
848 }
849 
850 
851 /*
852  * Send an authentication response packet
853  */
854 static int dhcp_socket_send(rad_listen_t *listener, REQUEST *request)
855 {
856  dhcp_socket_t *sock = listener->data;
857 
858  rad_assert(request->listener == listener);
859  rad_assert(listener->send == dhcp_socket_send);
860 
861  if (request->reply->code == 0) return 0; /* don't reply */
862 
863  if (fr_dhcp_encode(request->reply) < 0) {
864  RERROR("Failed encoding DHCP packet: %s", fr_strerror());
865  return -1;
866  }
867 
868  if (sock->suppress_responses) return 0;
869 
870 #ifdef PCAP_RAW_SOCKETS
871  if (sock->lsock.pcap) {
872  /* set ethernet destination address to DHCP-Client-Hardware-Address in request. */
873  uint8_t dhmac[ETHER_HDR_LEN] = { 0 };
874  bool found = false;
875  VALUE_PAIR *vp;
876  if ((vp = fr_pair_find_by_num(request->packet->vps, DHCP_MAGIC_VENDOR, 267, TAG_ANY))) {
877  if (vp->data.length == sizeof(vp->vp_ether)) {
878  memcpy(dhmac, vp->vp_ether, vp->data.length);
879  found = true;
880  }
881  }
882 
883  if (!found) {
884  REDEBUG("&DHCP-Client-Hardware-Address not found in request");
885  return -1;
886  }
887 
888  return fr_dhcp_send_pcap(sock->lsock.pcap, dhmac, request->reply);
889  } else
890 #endif
891  {
892  return fr_dhcp_send_socket(request->reply);
893  }
894 }
895 
896 /*
897  * Debug the packet if requested.
898  */
899 static void dhcp_packet_debug(REQUEST *request, RADIUS_PACKET *packet, bool received)
900 {
901  char src_ipaddr[INET6_ADDRSTRLEN];
902  char dst_ipaddr[INET6_ADDRSTRLEN];
903 #if defined(WITH_UDPFROMTO) && defined(WITH_IFINDEX_NAME_RESOLUTION)
904  char if_name[IFNAMSIZ];
905 #endif
906 
907  if (!packet) return;
908  if (!RDEBUG_ENABLED) return;
909 
910  /*
911  * Client-specific debugging re-prints the input
912  * packet into the client log.
913  *
914  * This really belongs in a utility library
915  */
916  if ((packet->code > PW_DHCP_OFFSET) && (packet->code < PW_DHCP_MAX)) {
917  radlog_request(L_DBG, L_DBG_LVL_1, request, "%s %s Id %08x from %s%s%s:%i to %s%s%s:%i "
918 #if defined(WITH_UDPFROMTO) && defined(WITH_IFINDEX_NAME_RESOLUTION)
919  "%s%s%s"
920 #endif
921  "length %zu",
922  received ? "Received" : "Sent",
924  packet->id,
925  packet->src_ipaddr.af == AF_INET6 ? "[" : "",
926  inet_ntop(packet->src_ipaddr.af,
927  &packet->src_ipaddr.ipaddr,
928  src_ipaddr, sizeof(src_ipaddr)),
929  packet->src_ipaddr.af == AF_INET6 ? "]" : "",
930  packet->src_port,
931  packet->dst_ipaddr.af == AF_INET6 ? "[" : "",
932  inet_ntop(packet->dst_ipaddr.af,
933  &packet->dst_ipaddr.ipaddr,
934  dst_ipaddr, sizeof(dst_ipaddr)),
935  packet->dst_ipaddr.af == AF_INET6 ? "]" : "",
936  packet->dst_port,
937 #if defined(WITH_UDPFROMTO) && defined(WITH_IFINDEX_NAME_RESOLUTION)
938  packet->if_index ? "via " : "",
939  packet->if_index ? fr_ifname_from_ifindex(if_name, packet->if_index) : "",
940  packet->if_index ? " " : "",
941 #endif
942  packet->data_len);
943  } else {
944  radlog_request(L_DBG, L_DBG_LVL_1, request, "%s code %u Id %08x from %s%s%s:%i to %s%s%s:%i "
945 #if defined(WITH_UDPFROMTO) && defined(WITH_IFINDEX_NAME_RESOLUTION)
946  "%s%s%s"
947 #endif
948  "length %zu",
949  received ? "Received" : "Sent",
950  packet->code,
951  packet->id,
952  packet->src_ipaddr.af == AF_INET6 ? "[" : "",
953  inet_ntop(packet->src_ipaddr.af,
954  &packet->src_ipaddr.ipaddr,
955  src_ipaddr, sizeof(src_ipaddr)),
956  packet->src_ipaddr.af == AF_INET6 ? "]" : "",
957  packet->src_port,
958  packet->dst_ipaddr.af == AF_INET6 ? "[" : "",
959  inet_ntop(packet->dst_ipaddr.af,
960  &packet->dst_ipaddr.ipaddr,
961  dst_ipaddr, sizeof(dst_ipaddr)),
962  packet->dst_ipaddr.af == AF_INET6 ? "]" : "",
963  packet->dst_port,
964 #if defined(WITH_UDPFROMTO) && defined(WITH_IFINDEX_NAME_RESOLUTION)
965  packet->if_index ? "via " : "",
966  packet->if_index ? fr_ifname_from_ifindex(if_name, packet->if_index) : "",
967  packet->if_index ? " " : "",
968 #endif
969  packet->data_len);
970  }
971 
972  if (received) {
973  rdebug_pair_list(L_DBG_LVL_2, request, packet->vps, "&request:");
974  } else {
975  rdebug_proto_pair_list(L_DBG_LVL_2, request, packet->vps, "&reply:");
976  }
977 }
978 
979 static int dhcp_socket_encode(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
980 {
981  DEBUG2("NO ENCODE!");
982  return 0;
983 }
984 
985 
986 static int dhcp_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
987 {
988  return fr_dhcp_decode(request->packet);
989 }
990 
992 fr_protocol_t proto_dhcp = {
994  .name = "dhcp",
995  .inst_size = sizeof(dhcp_socket_t),
996  .transports = TRANSPORT_UDP,
997  .tls = false,
998  .parse = dhcp_socket_parse,
999  .open = common_socket_open,
1000  .recv = dhcp_socket_recv,
1001  .send = dhcp_socket_send,
1002  .print = common_socket_print,
1003  .debug = dhcp_packet_debug,
1004  .encode = dhcp_socket_encode,
1005  .decode = dhcp_socket_decode
1006 };
int fr_dhcp_add_arp_entry(int fd, char const *interface, VALUE_PAIR *hwvp, VALUE_PAIR *clvp)
int sockfd
Socket this packet was read from.
Definition: libradius.h:147
struct timeval response_delay
How long to wait before sending Access-Rejects.
Definition: radiusd.h:246
2nd highest priority debug messages (-xx | -X).
Definition: log.h:52
VALUE_PAIR * config
VALUE_PAIR (s) used to set per request parameters for modules and the server core at runtime...
Definition: radiusd.h:227
char const * interface
Definition: listen.h:124
int id
Packet ID (used to link requests/responses).
Definition: libradius.h:154
int cf_pair_parse(CONF_SECTION *cs, char const *name, unsigned int type, void *data, char const *dflt, FR_TOKEN dflt_quote)
Parses a CONF_PAIR into a C data type, with a default value.
Definition: conffile.c:1968
#define RERROR(fmt,...)
Definition: log.h:207
static int dhcprelay_process_server_reply(UNUSED REQUEST *request)
Definition: dhcpd.c:267
Only displayed when debugging is enabled.
Definition: log.h:41
#define FR_STATS_TYPE_INC(_x)
Definition: stats.h:90
bfd_auth_t auth
Definition: proto_bfd.c:209
static int dhcp_process(REQUEST *request)
Definition: dhcpd.c:294
The module is OK, continue.
Definition: radiusd.h:91
char const * nas_type
Type of client (arbitrary).
Definition: clients.h:47
int common_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
Definition: listen.c:1274
uint16_t my_port
Definition: listen.h:122
fr_ipaddr_t src_ipaddr
Src IP address of packet.
Definition: libradius.h:149
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition: inet.h:47
int fr_is_inaddr_any(fr_ipaddr_t *ipaddr)
Determine if an address is the INADDR_ANY address for its address family.
Definition: packet.c:91
rlm_rcode_t process_post_auth(int type, REQUEST *request)
Definition: modules.c:2178
VALUE_PAIR * radius_pair_create(TALLOC_CTX *ctx, VALUE_PAIR **vps, unsigned int attribute, unsigned int vendor)
Create a VALUE_PAIR and add it to a list of VALUE_PAIR s.
Definition: pair.c:704
int fd
Definition: listen.h:77
#define RDEBUG_ENABLED
True if request debug level 1 messages are enabled.
Definition: log.h:237
void cf_pair_add(CONF_SECTION *parent, CONF_PAIR *cp)
Add a configuration pair to a section.
Definition: conffile.c:612
#define UNUSED
Definition: libradius.h:134
#define RLM_MODULE_INIT
Definition: modules.h:86
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition: missing.c:538
char const * secret
Secret PSK.
Definition: clients.h:43
static int dhcp_socket_parse(CONF_SECTION *cs, rad_listen_t *this)
Definition: dhcpd.c:696
fr_stats_t auth
Authentication stats.
Definition: clients.h:59
rad_listen_t * listener
The listener that received the request.
Definition: radiusd.h:218
The module considers the request invalid.
Definition: radiusd.h:93
uint8_t * data
Packet data (body).
Definition: libradius.h:160
rad_listen_send_t send
Definition: listen.h:96
uint16_t dst_port
DST Port of packet.
Definition: libradius.h:152
uint16_t src_port
Src port of packet.
Definition: libradius.h:151
fr_ipaddr_t dst_ipaddr
Dst IP address of packet.
Definition: libradius.h:150
fr_ipaddr_t my_ipaddr
Definition: listen.h:121
#define FR_STATS_INC(_x, _y)
Definition: stats.h:89
CONF_PAIR * cf_pair_find(CONF_SECTION const *, char const *name)
Definition: conffile.c:3478
int af
Address family.
Definition: inet.h:42
#define TRANSPORT_UDP
Definition: protocol.h:62
#define rad_assert(expr)
Definition: rad_assert.h:38
int fr_dhcp_encode(RADIUS_PACKET *packet)
Definition: dhcp.c:1629
Highest priority debug messages (-x).
Definition: log.h:51
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *vp)
Add a VP to the end of the list.
Definition: pair.c:659
#define DEBUG2(fmt,...)
Definition: log.h:176
#define USEC
Immediately reject the request.
Definition: radiusd.h:89
union fr_ipaddr_t::@1 ipaddr
unsigned int code
Packet code (type).
Definition: libradius.h:155
int fr_dhcp_decode(RADIUS_PACKET *packet)
Definition: dhcp.c:1103
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
Definition: clients.h:36
static int dhcprelay_process_client_request(UNUSED REQUEST *request)
Definition: dhcpd.c:273
int common_socket_open(CONF_SECTION *cs, rad_listen_t *this)
Definition: listen.c:1599
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
RADIUS_PACKET * reply
Outgoing response.
Definition: radiusd.h:225
static void dhcp_packet_debug(REQUEST *request, RADIUS_PACKET *packet, bool received)
Definition: dhcpd.c:899
fr_ipaddr_t src_ipaddr
Definition: dhcpd.c:71
A truth value.
Definition: radius.h:56
fr_protocol_t proto_dhcp
Definition: dhcpd.c:992
Configuration AVP similar to a VALUE_PAIR.
Definition: conffile.c:82
Definition: token.h:45
static int dhcp_socket_send(rad_listen_t *listener, REQUEST *request)
Definition: dhcpd.c:854
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
void radlog_request(log_type_t type, log_lvl_t lvl, REQUEST *request, char const *msg,...) CC_HINT(format(printf
char name[1]
Enum name.
Definition: dict.h:97
void rdebug_pair_list(log_lvl_t level, REQUEST *, VALUE_PAIR *, char const *)
Print a list of VALUE_PAIRs.
Definition: pair.c:757
int request_receive(TALLOC_CTX *ctx, rad_listen_t *listener, RADIUS_PACKET *packet, RADCLIENT *client, RAD_REQUEST_FUNP fun)
Definition: process.c:1523
CONF_PAIR * cf_pair_alloc(CONF_SECTION *parent, char const *attr, char const *value, FR_TOKEN op, FR_TOKEN lhs_type, FR_TOKEN rhs_type)
Allocate a CONF_PAIR.
Definition: conffile.c:546
Module succeeded without doing anything.
Definition: radiusd.h:96
int if_index
Index of receiving interface.
Definition: libradius.h:148
Describes a host allowed to send packets to the server.
Definition: clients.h:35
#define RDEBUG2(fmt,...)
Definition: log.h:244
void rdebug_proto_pair_list(log_lvl_t level, REQUEST *, VALUE_PAIR *, char const *)
Print a list of protocol VALUE_PAIRs.
Definition: pair.c:784
uint8_t data[]
Definition: eap_pwd.h:625
size_t length
Length of value data.
Definition: pair.h:87
Module failed, don't reply.
Definition: radiusd.h:90
#define TAG_ANY
Definition: pair.h:191
char const * dhcp_message_types[]
Definition: dhcp.c:140
int fr_dhcp_send_socket(RADIUS_PACKET *packet)
Send DHCP packet using socket.
Definition: dhcp.c:561
void fr_radius_free(RADIUS_PACKET **)
Free a RADIUS_PACKET.
Definition: radius.c:1727
#define FR_ITEM_POINTER(_t, _p)
Definition: conffile.h:176
size_t data_len
Length of packet data.
Definition: libradius.h:161
RADIUS_PACKET * packet
Incoming request.
Definition: radiusd.h:221
static int dhcp_socket_recv(rad_listen_t *listener)
Definition: dhcpd.c:814
#define WARN(fmt,...)
Definition: log.h:144
fr_dict_enum_t * fr_dict_enum_by_da(fr_dict_t *dict, fr_dict_attr_t const *da, int value)
Lookup the structure representing an enum value in a fr_dict_attr_t.
Definition: dict.c:3654
#define REDEBUG(fmt,...)
Definition: log.h:254
#define ETHER_HDR_LEN
Definition: net.h:63
#define INADDR_BROADCAST
Definition: dhcp.c:59
VALUE_PAIR * fr_pair_copy(TALLOC_CTX *ctx, VALUE_PAIR const *vp)
Copy a single valuepair.
Definition: pair.c:129
#define DHCP_MAGIC_VENDOR
Definition: dhcp.h:97
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
int fr_ipaddr_from_ifname(fr_ipaddr_t *out, int af, char const *name)
char const * longname
Client identifier.
Definition: clients.h:40
RADIUS_PACKET * fr_dhcp_recv_socket(int sockfd)
Receive DHCP packet using socket.
Definition: dhcp.c:255
uint64_t magic
Used to validate loaded library.
Definition: protocol.h:40
IPv4/6 prefix.
Definition: inet.h:41
bool suppress_responses
Definition: dhcpd.c:68
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
void * data
Definition: listen.h:103
struct dhcp_socket_t dhcp_socket_t
String of printable characters.
Definition: radius.h:33
RADCLIENT dhcp_client
Definition: dhcpd.c:69
User not found.
Definition: radiusd.h:95
static int dhcp_socket_encode(UNUSED rad_listen_t *listener, UNUSED REQUEST *request)
Definition: dhcpd.c:979
char const * fr_inet_ntoh(fr_ipaddr_t const *src, char *out, size_t outlen)
Perform reverse resolution of an IP address.
Definition: inet.c:226
OK (pairs modified).
Definition: radiusd.h:97
char * talloc_typed_strdup(void const *t, char const *p)
Call talloc strdup, setting the type on the new chunk correctly.
Definition: missing.c:588
32 Bit IPv4 Address.
Definition: radius.h:35
The module handled the request, so stop.
Definition: radiusd.h:92
char const * src_interface
Definition: dhcpd.c:70
#define RDEBUG(fmt,...)
Definition: log.h:243
int common_socket_print(rad_listen_t const *this, char *buffer, size_t bufsize)
Definition: listen.c:1021
#define ERROR(fmt,...)
Definition: log.h:145
fr_uint_t total_requests
Definition: stats.h:40
Value of an enumerated attribute.
Definition: dict.h:94
#define PW_DHCP_OFFSET
Definition: dhcp.h:73
static int dhcp_socket_decode(UNUSED rad_listen_t *listener, REQUEST *request)
Definition: dhcpd.c:986
char const * shortname
Client nickname.
Definition: clients.h:41
static const uint32_t attrnums[]
Definition: dhcpd.c:281
listen_socket_t lsock
Definition: dhcpd.c:63
value_data_t data
Definition: pair.h:133