The FreeRADIUS server $Id: 15bac2a4c627c01d1aa2047687b3418955ac7f00 $
Loading...
Searching...
No Matches
dhcpclient.c
Go to the documentation of this file.
1/*
2 * dhcpclient.c DHCP test client.
3 *
4 * Version: $Id: a2b32b227a0031cf87ba6e68aa85d7083583dffb $
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 2000,2006 The FreeRADIUS server project
21 * @copyright 2000 Miquel van Smoorenburg (miquels@cistron.nl)
22 * @copyright 2010 Alan DeKok (aland@freeradius.org)
23 */
24
25RCSID("$Id: a2b32b227a0031cf87ba6e68aa85d7083583dffb $")
26
27#include <freeradius-devel/util/conf.h>
28#include <freeradius-devel/util/syserror.h>
29#include <freeradius-devel/util/atexit.h>
30#include <freeradius-devel/util/pair_legacy.h>
31#include <freeradius-devel/server/packet.h>
32#include <freeradius-devel/dhcpv4/dhcpv4.h>
33
34/*
35 * Logging macros
36 */
37#undef DEBUG
38#define DEBUG(fmt, ...) if (fr_debug_lvl > 0) fprintf(stdout, fmt "\n", ## __VA_ARGS__)
39
40#define ERROR(fmt, ...) fr_perror("dhcpclient: " fmt, ## __VA_ARGS__)
41
42#include <ctype.h>
43
44#ifdef HAVE_GETOPT_H
45# include <getopt.h>
46#endif
47
48#include <assert.h>
49
50#include <net/if.h>
51
52static int retries = 3;
54
55static int sockfd;
56#ifdef HAVE_LIBPCAP
57static fr_pcap_t *pcap = NULL;
58#endif
59
60static char *iface = NULL;
61static int iface_ind = -1;
62
63#ifdef HAVE_LINUX_IF_PACKET_H
64static struct sockaddr_ll ll; /* Socket address structure */
65#endif
66
67static bool raw_mode = false;
68static bool reply_expected = true;
69
70static char const *dhcpclient_version = RADIUSD_VERSION_BUILD("dhcpclient");
71
72/* structure to keep track of offered IP addresses */
77
79static fr_dict_t const *dict_dhcpv4;
80
83 { .out = &dict_freeradius, .proto = "freeradius" },
84 { .out = &dict_dhcpv4, .proto = "dhcpv4" },
86};
87
92
95 { .out = &attr_packet_type, .name = "Packet-Type", .type = FR_TYPE_UINT32, .dict = &dict_dhcpv4 },
96 { .out = &attr_dhcp_message_type, .name = "Message-Type", .type = FR_TYPE_UINT8, .dict = &dict_dhcpv4},
97 { .out = &attr_dhcp_dhcp_server_identifier, .name = "Server-Identifier", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_dhcpv4 },
98 { .out = &attr_dhcp_your_ip_address, .name = "Your-IP-Address", .type = FR_TYPE_IPV4_ADDR, .dict = &dict_dhcpv4 },
100};
101
103 { L("auto"), 0 },
104 { L("decline"), FR_DHCP_DECLINE },
105 { L("discover"), FR_DHCP_DISCOVER },
106 { L("inform"), FR_DHCP_INFORM },
107 { L("lease_query"), FR_DHCP_LEASE_QUERY },
108 { L("release"), FR_DHCP_RELEASE },
109 { L("request"), FR_DHCP_REQUEST }
110};
112
113static NEVER_RETURNS void usage(void)
114{
115 DEBUG("Usage: dhcpclient [options] server[:port] [<command>]");
116 DEBUG("Send a DHCP request with provided RADIUS attrs and output response.");
117
118 DEBUG(" <command> One of: discover, request, decline, release, inform; or: auto.");
119 DEBUG(" -d <directory> Set the directory where the dictionaries are stored (defaults to " CONFDIR ").");
120 DEBUG(" -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").");
121 DEBUG(" -f <file> Read packets from file, not stdin.");
122 DEBUG(" -i <interface> Use this interface to send/receive at packet level on a raw socket.");
123 DEBUG(" -r <retries> On timeout, retry sending the packet 'retries' times.\n");
124 DEBUG(" -t <timeout> Wait 'timeout' seconds for a reply (may be a floating point number).");
125 DEBUG(" -v Show program version information.");
126 DEBUG(" -x Debugging mode.");
127
128 fr_exit(EXIT_SUCCESS);
129}
130
131
132/*
133 * Initialize the request.
134 */
135static int request_init(fr_packet_t **out, fr_pair_list_t *packet_vps, char const *filename)
136{
137 FILE *fp;
138 fr_pair_t *vp;
139 bool filedone = false;
140 fr_packet_t *packet;
141
142 /*
143 * Determine where to read the VP's from.
144 */
145 if (filename) {
146 fp = fopen(filename, "r");
147 if (!fp) {
148 ERROR("Error opening %s: %s", filename, fr_syserror(errno));
149 return -1;
150 }
151 } else {
152 DEBUG("Reading packets from stdin\n");
153 fp = stdin;
154 }
155
156 packet = fr_packet_alloc(NULL, false);
157
158 /*
159 * Read the VP's.
160 */
161 if (fr_pair_list_afrom_file(packet, dict_dhcpv4, packet_vps, fp, &filedone, true) < 0) {
162 fr_perror("dhcpclient");
163 fr_packet_free(&packet);
164 if (fp != stdin) fclose(fp);
165 return -1;
166 }
167
168 /*
169 * Fix / set various options
170 */
171 for (vp = fr_pair_list_head(packet_vps);
172 vp;
173 vp = fr_pair_list_next(packet_vps, vp)) {
174 /*
175 * Allow to set packet type using Message-Type
176 */
177 if (vp->da == attr_dhcp_message_type) {
178 packet->code = vp->vp_uint8;
179
180 /*
181 * Allow it to set the packet type in
182 * the attributes read from the file.
183 * (this takes precedence over the command argument.)
184 */
185 } else if (vp->da == attr_packet_type) {
186 packet->code = vp->vp_uint32;
187
188 } /* switch over the attribute */
189
190 } /* loop over the VP's we read in */
191
192 /*
193 * Fill in the packet header from attributes, and then
194 * re-realize the attributes.
195 */
196 fr_packet_net_from_pairs(packet, packet_vps);
197
198 if (fp != stdin) fclose(fp);
199
200 /*
201 * And we're done.
202 */
203 *out = packet;
204
205 return 0;
206}
207
208
209/*
210 * Loop waiting for DHCP replies until timer expires.
211 * Note that there may be more than one reply: multiple DHCP servers can respond to a broadcast discover.
212 * A real client would pick one of the proposed replies.
213 * We'll just return the first eligible reply, and display the others.
214 */
215#if defined(HAVE_LINUX_IF_PACKET_H) || defined (HAVE_LIBPCAP)
216static fr_packet_t *fr_dhcpv4_recv_raw_loop(int lsockfd,
217#ifdef HAVE_LINUX_IF_PACKET_H
218 struct sockaddr_ll *p_ll,
219#endif
220 fr_packet_t *request,
221#ifndef HAVE_LINUX_IF_PACKET_H
222 UNUSED
223#endif
224 fr_pair_list_t *request_list
225 )
226{
227 fr_time_delta_t our_timeout;
228 fr_packet_t *found = NULL;
229 fr_packet_t *reply = NULL;
230 fr_pair_list_t reply_vps;
231 int nb_reply = 0;
232 int nb_offer = 0;
233 dc_offer_t *offer_list = NULL;
234 fd_set read_fd;
235 int retval;
236 fr_dcursor_t cursor;
237
238 fr_pair_list_init(&reply_vps);
239
240 our_timeout = timeout;
241
242 /* Loop waiting for DHCP replies until timer expires */
243 while (fr_time_delta_ispos(our_timeout)) {
244 if ((!found) || (reply)) { // only debug at start and each time we get a valid DHCP reply on raw socket
245 DEBUG("Waiting for %s DHCP replies for: %.6f",
246 (nb_reply > 0) ? " additional ":" ", fr_time_delta_unwrap(our_timeout) / (double)NSEC);
247 }
248
249 reply = NULL;
250 FD_ZERO(&read_fd);
251 FD_SET(lsockfd, &read_fd);
252 retval = select(lsockfd + 1, &read_fd, NULL, NULL, &fr_time_delta_to_timeval(our_timeout));
253 if (retval < 0) {
254 fr_strerror_printf("Select on DHCP socket failed: %s", fr_syserror(errno));
255 return NULL;
256 }
257
258 if (retval > 0 && FD_ISSET(lsockfd, &read_fd)) {
259 /* There is something to read on our socket */
260
261#ifdef HAVE_LIBPCAP
262 if (pcap) {
263 reply = fr_dhcpv4_pcap_recv(pcap);
264# ifdef HAVE_LINUX_IF_PACKET_H
265 } else
266# else
267 }
268# endif
269#endif
270#ifdef HAVE_LINUX_IF_PACKET_H
271 {
272 reply = fr_dhcpv4_raw_packet_recv(lsockfd, p_ll, request, request_list);
273 }
274#elif !defined(HAVE_LIBPCAP)
275# error Need <if/packet.h> or <pcap.h>
276#endif
277 } else {
278 our_timeout = fr_time_delta_wrap(0);
279 }
280
281 if (reply) {
282 nb_reply ++;
283
284 if (fr_debug_lvl > 1) fr_dhcpv4_print_hex(stdout, reply->data, reply->data_len);
285
286 fr_pair_dcursor_init(&cursor, &reply_vps);
287 if (fr_dhcpv4_decode(reply, &reply_vps, reply->data, reply->data_len, &reply->code) < 0) {
288 ERROR("Failed decoding reply");
289 return NULL;
290 }
291
292 if (!found) found = reply;
293
294 if (reply->code == FR_DHCP_OFFER) {
297
298 if (vp1 && vp2) {
299 nb_offer++;
300 offer_list = talloc_realloc(request, offer_list, dc_offer_t, nb_offer);
301 offer_list[nb_offer - 1].server_addr = vp1->vp_ipv4addr;
302 offer_list[nb_offer - 1].offered_addr = vp2->vp_ipv4addr;
303 }
304 }
305 }
306 }
307
308 if (0 == nb_reply) {
309 DEBUG("No valid DHCP reply received");
310 return NULL;
311 }
312
313 /* display offer(s) received */
314 if (nb_offer > 0 ) {
315 int i;
316
317 DEBUG("Received %d DHCP Offer(s):", nb_offer);
318 for (i = 0; i < nb_offer; i++) {
319 char server_addr_buf[INET6_ADDRSTRLEN];
320 char offered_addr_buf[INET6_ADDRSTRLEN];
321
322 DEBUG("IP address: %s offered by DHCP server: %s",
323 inet_ntop(AF_INET, &offer_list[i].offered_addr,
324 offered_addr_buf, sizeof(offered_addr_buf)),
325 inet_ntop(AF_INET, &offer_list[i].server_addr,
326 server_addr_buf, sizeof(server_addr_buf))
327 );
328 }
329 }
330
331 return found;
332}
333#endif /* <if/packet.h> or <pcap.h> */
334
335static int send_with_socket(fr_packet_t **reply, fr_packet_t *request,
336#ifndef HAVE_LINUX_IF_PACKET_H
337 UNUSED
338#endif
339 fr_pair_list_t *request_list)
340{
341 int on = 1;
342
343#ifdef HAVE_LINUX_IF_PACKET_H
344 if (raw_mode) {
345 sockfd = fr_dhcpv4_raw_socket_open(&ll, iface_ind);
346 if (sockfd < 0) {
347 ERROR("Error opening socket");
348 return -1;
349 }
350 } else
351#endif
352 {
353 sockfd = fr_socket_server_udp(&request->socket.inet.src_ipaddr, &request->socket.inet.src_port, NULL, false);
354 if (sockfd < 0) {
355 ERROR("Error opening socket - %s", fr_strerror());
356 return -1;
357 }
358
359 if (fr_socket_bind(sockfd, NULL, &request->socket.inet.src_ipaddr, &request->socket.inet.src_port) < 0) {
360 ERROR("Error binding socket - %s", fr_strerror());
361 return -1;
362 }
363 }
364
365
366 /*
367 * Set option 'receive timeout' on socket.
368 * Note: in case of a timeout, the error will be "Resource temporarily unavailable".
369 */
370 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,
371 &fr_time_delta_to_timeval(timeout), sizeof(struct timeval)) == -1) {
372 ERROR("Failed setting socket timeout: %s", fr_syserror(errno));
373 return -1;
374 }
375
376 if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
377 ERROR("Can't set broadcast option: %s", fr_syserror(errno));
378 return -1;
379 }
380 request->socket.fd = sockfd;
381
382#ifdef HAVE_LINUX_IF_PACKET_H
383 if (raw_mode) {
384 if (fr_dhcpv4_raw_packet_send(sockfd, &ll, request, request_list) < 0) {
385 ERROR("Failed sending (fr_dhcpv4_raw_packet_send): %s", fr_syserror(errno));
386 return -1;
387 }
388 if (!reply_expected) return 0;
389
390 *reply = fr_dhcpv4_recv_raw_loop(sockfd, &ll, request, request_list);
391 if (!*reply) {
392 ERROR("Error receiving reply (fr_dhcpv4_recv_raw_loop)");
393 return -1;
394 }
395 } else
396#endif
397 {
398 if (fr_dhcpv4_udp_packet_send(request) < 0) {
399 ERROR("Failed sending: %s", fr_syserror(errno));
400 return -1;
401 }
402 if (!reply_expected) return 0;
403
405 if (!*reply) {
406 if (errno == EAGAIN) {
407 fr_strerror_clear(); /* clear error */
408 ERROR("Timed out waiting for reply");
409 } else {
410 ERROR("Error receiving reply");
411 }
412 return -1;
413 }
414 }
415
416 return 0;
417}
418
419#ifdef HAVE_LIBPCAP
420static int send_with_pcap(fr_packet_t **reply, fr_packet_t *request, fr_pair_list_t *request_list)
421{
422 char ip[16];
423 char pcap_filter[255];
424
425 pcap = fr_pcap_init(NULL, iface, PCAP_INTERFACE_IN_OUT);
426 if (!pcap) {
427 ERROR("Failed creating pcap");
428 return -1;
429 }
430
431 if (fr_pcap_open(pcap) < 0) {
432 ERROR("Failed opening interface");
433 talloc_free(pcap);
434 return -1;
435 }
436
437 fr_inet_ntoh(&request->socket.inet.src_ipaddr, ip, sizeof(ip));
438 snprintf(pcap_filter, sizeof(pcap_filter), "udp and dst port %d", request->socket.inet.src_port);
439
440 if (fr_pcap_apply_filter(pcap, pcap_filter) < 0) {
441 ERROR("Failing setting filter");
442 talloc_free(pcap);
443 return -1;
444 }
445
446 if (fr_dhcpv4_pcap_send(pcap, eth_bcast, request) < 0) {
447 ERROR("Failed sending request");
448 talloc_free(pcap);
449 return -1;
450 }
451
452 if (!reply_expected) return 0;
453
454 *reply = fr_dhcpv4_recv_raw_loop(pcap->fd,
455#ifdef HAVE_LINUX_IF_PACKET_H
456 &ll,
457#endif
458 request, request_list);
459
460 if (!*reply) {
461 ERROR("Error receiving reply");
462 talloc_free(pcap);
463 return -1;
464 }
465
466 talloc_free(pcap);
467 return 0;
468}
469#endif /* HAVE_LIBPCAP */
470
471static void dhcp_packet_debug(fr_packet_t *packet, fr_pair_list_t *list, bool received)
472{
473 char buffer[2048] = "";
474
475 char src_ipaddr[INET6_ADDRSTRLEN];
476 char dst_ipaddr[INET6_ADDRSTRLEN];
477#if defined(WITH_IFINDEX_NAME_RESOLUTION)
478 char if_name[IFNAMSIZ];
479#endif
480 fr_pair_t *vp;
481
482 if (!packet) return;
483
484 /*
485 * Client-specific debugging re-prints the input
486 * packet into the client log.
487 *
488 * This really belongs in a utility library
489 */
490 printf("%s %s Id %08x from %s%s%s:%i to %s%s%s:%i "
491#ifdef WITH_IFINDEX_NAME_RESOLUTION
492 "%s%s%s"
493#endif
494 "length %zu\n",
495 received ? "Received" : "Sending",
496 dhcp_message_types[packet->code],
497 packet->id,
498 packet->socket.inet.src_ipaddr.af == AF_INET6 ? "[" : "",
499 inet_ntop(packet->socket.inet.src_ipaddr.af,
500 &packet->socket.inet.src_ipaddr.addr,
501 src_ipaddr, sizeof(src_ipaddr)),
502 packet->socket.inet.src_ipaddr.af == AF_INET6 ? "]" : "",
503 packet->socket.inet.src_port,
504 packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "[" : "",
505 inet_ntop(packet->socket.inet.dst_ipaddr.af,
506 &packet->socket.inet.dst_ipaddr.addr,
507 dst_ipaddr, sizeof(dst_ipaddr)),
508 packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "]" : "",
509 packet->socket.inet.dst_port,
510#ifdef WITH_IFINDEX_NAME_RESOLUTION
511 packet->socket.inet.ifindex ? "via " : "",
512 packet->socket.inet.ifindex ? fr_ifname_from_ifindex(if_name, packet->socket.inet.ifindex) : "",
513 packet->socket.inet.ifindex ? " " : "",
514#endif
515 packet->data_len);
516
517 for (vp = fr_pair_list_head(list);
518 vp;
519 vp = fr_pair_list_next(list, vp)) {
521
523
524 out = FR_SBUFF_OUT(buffer, sizeof(buffer));
525 (void) fr_pair_print(&out, NULL, vp);
526 printf("\t%s\n", fr_sbuff_start(&out));
527 }
528}
529
530int main(int argc, char **argv)
531{
532
533 static uint16_t server_port = 0;
534 static int packet_code = 0;
537
538 int c;
539 char const *confdir = CONFDIR;
540 char const *dict_dir = DICTDIR;
541 char const *filename = NULL;
542
543 fr_packet_t *packet = NULL;
544 fr_pair_list_t packet_vps;
545 fr_packet_t *reply = NULL;
546 fr_pair_list_t reply_vps;
547
548 int ret;
549
550 fr_pair_list_init(&packet_vps);
551 fr_pair_list_init(&reply_vps);
552
553 /*
554 * Must be called first, so the handler is called last
555 */
557
558 fr_debug_lvl = 1;
559
560 while ((c = getopt(argc, argv, "d:D:f:hr:t:vxi:")) != -1) switch(c) {
561 case 'D':
562 dict_dir = optarg;
563 break;
564
565 case 'd':
566 confdir = optarg;
567 break;
568
569 case 'f':
570 filename = optarg;
571 break;
572
573 case 'i':
574 iface = optarg;
575 break;
576
577 case 'r':
578 if (!isdigit((uint8_t) *optarg)) usage();
579 retries = atoi(optarg);
580 if ((retries == 0) || (retries > 1000)) usage();
581 break;
582
583 case 't':
584 if (fr_time_delta_from_str(&timeout, optarg, strlen(optarg), FR_TIME_RES_SEC) < 0) usage();
585 break;
586
587 case 'v':
589 fr_exit(EXIT_SUCCESS);
590
591 case 'x':
592 fr_debug_lvl++;
593 break;
594
595 case 'h':
596 default:
597 usage();
598 }
599 argc -= (optind - 1);
600 argv += (optind - 1);
601
602 if (argc < 2) usage();
603
604 if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) {
605 fr_perror("dhcpclient");
606 fr_exit(EXIT_FAILURE);
607 }
608
610 fr_perror("dhcpclient");
611 fr_exit(EXIT_FAILURE);
612 }
613
615 fr_perror("dhcpclient");
616 fr_exit(EXIT_FAILURE);
617 }
618
620 fr_perror("dhcpclient");
621 fr_exit(EXIT_FAILURE);
622 }
623
625
626 fr_strerror_clear(); /* Clear the error buffer */
627
628 /*
629 * Initialise the DHCPv4 library
630 */
631 if (fr_dhcpv4_global_init() < 0) {
632 fr_perror("dhcpclient");
633 fr_exit(EXIT_FAILURE);
634 }
635
636 /*
637 * Resolve hostname.
638 */
639 server_ipaddr.af = AF_INET;
640 if (strcmp(argv[1], "-") != 0) {
642 strlen(argv[1]), AF_UNSPEC, true, true) < 0) {
643 fr_perror("dhcpclient");
644 fr_exit(EXIT_FAILURE);
645 }
647 }
648
649 /*
650 * See what kind of request we want to send.
651 */
652 if (argc >= 3) {
653 if (!isdigit((uint8_t) argv[2][0])) {
655 if (packet_code == -2) {
656 ERROR("Unknown packet type: %s", argv[2]);
657 usage();
658 }
659 } else {
660 packet_code = atoi(argv[2]);
661 }
662 }
663 if (!server_port) server_port = 67;
664
665 /*
666 * set "raw mode" if an interface is specified and if destination
667 * IP address is the broadcast address.
668 */
669 if (iface) {
670 iface_ind = if_nametoindex(iface);
671 if (iface_ind <= 0) {
672 ERROR("Unknown interface: %s", iface);
673 fr_exit(EXIT_FAILURE);
674 }
675
676 if (server_ipaddr.addr.v4.s_addr == 0xFFFFFFFF) {
677 DEBUG("Using interface: %s (index: %d) in raw packet mode", iface, iface_ind);
678 raw_mode = true;
679 }
680 }
681
682 if ((request_init(&packet, &packet_vps, filename) < 0) || fr_pair_list_empty(&packet_vps)) {
683 ERROR("Nothing to send");
684 fr_exit(EXIT_FAILURE);
685 }
686
687 /*
688 * Set defaults if they weren't specified via pairs
689 */
690 if (packet->socket.inet.src_port == 0) packet->socket.inet.src_port = server_port + 1;
691 if (packet->socket.inet.dst_port == 0) packet->socket.inet.dst_port = server_port;
692 if (packet->socket.inet.src_ipaddr.af == AF_UNSPEC) packet->socket.inet.src_ipaddr = client_ipaddr;
693 if (packet->socket.inet.dst_ipaddr.af == AF_UNSPEC) packet->socket.inet.dst_ipaddr = server_ipaddr;
694 if (!packet->code) packet->code = packet_code;
695
696 /*
697 * Sanity check.
698 */
699 if (!packet->code) {
700 ERROR("Command was %s, and request did not contain Message-Type nor Packet-Type",
701 (argc >= 3) ? "'auto'" : "unspecified");
702 fr_exit(EXIT_FAILURE);
703 }
704
705 /*
706 * These kind of packets do not get a reply, so don't wait for one.
707 */
708 if ((packet->code == FR_DHCP_RELEASE) || (packet->code == FR_DHCP_DECLINE)) {
709 reply_expected = false;
710 }
711
712 /*
713 * Encode the packet
714 */
715 if (fr_dhcpv4_packet_encode(packet, &packet_vps) < 0) {
716 ERROR("Failed encoding packet");
717 fr_exit(EXIT_FAILURE);
718 }
719
720 /*
721 * Decode the request to produce fr_pair_t's from the headers.
722 */
723 if (fr_debug_lvl) {
724 if (fr_debug_lvl > 1) fr_dhcpv4_print_hex(stdout, packet->data, packet->data_len);
725
726 (void) fr_dhcpv4_decode(packet, &reply_vps, packet->data, packet->data_len, &packet->code);
727 dhcp_packet_debug(packet, &reply_vps, false);
728 fr_pair_list_free(&reply_vps);
729 }
730
731#ifdef HAVE_LIBPCAP
732 if (raw_mode) {
733 ret = send_with_pcap(&reply, packet, &packet_vps);
734 } else
735#endif
736 {
737 ret = send_with_socket(&reply, packet, &packet_vps);
738 }
739
740 if (reply) {
741 if (fr_dhcpv4_decode(reply, &reply_vps, reply->data, reply->data_len, &reply->code) < 0) {
742 ERROR("Failed decoding packet");
743 ret = -1;
744 }
745 dhcp_packet_debug(reply, &reply_vps, true);
746 }
747
749
751 fr_perror("dhcpclient");
752 ret = -1;
753 }
754
755 /*
756 * Ensure our atexit handlers run before any other
757 * atexit handlers registered by third party libraries.
758 */
760
761 return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
762}
static int const char char buffer[256]
Definition acutest.h:576
int fr_atexit_global_setup(void)
Setup the atexit handler, should be called at the start of a program's execution.
Definition atexit.c:159
int fr_atexit_global_trigger_all(void)
Cause all global free triggers to fire.
Definition atexit.c:285
#define RCSID(id)
Definition build.h:488
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:316
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:210
#define UNUSED
Definition build.h:318
#define NUM_ELEMENTS(_t)
Definition build.h:340
#define fr_exit(_x)
Exit, producing a log message in debug builds.
Definition debug.h:230
fr_dict_autoload_t dhcpclient_dict[]
Definition dhcpclient.c:82
static fr_dict_attr_t const * attr_packet_type
Definition dhcpclient.c:88
#define ERROR(fmt,...)
Definition dhcpclient.c:40
static fr_table_num_sorted_t const request_types[]
Definition dhcpclient.c:102
int main(int argc, char **argv)
Definition dhcpclient.c:530
static bool reply_expected
Definition dhcpclient.c:68
static fr_dict_t const * dict_freeradius
Definition dhcpclient.c:78
static fr_dict_attr_t const * attr_dhcp_message_type
Definition dhcpclient.c:89
static int iface_ind
Definition dhcpclient.c:61
static size_t request_types_len
Definition dhcpclient.c:111
static fr_dict_t const * dict_dhcpv4
Definition dhcpclient.c:79
static int retries
Definition dhcpclient.c:52
uint32_t server_addr
Definition dhcpclient.c:74
static void dhcp_packet_debug(fr_packet_t *packet, fr_pair_list_t *list, bool received)
Definition dhcpclient.c:471
static fr_dict_attr_t const * attr_dhcp_your_ip_address
Definition dhcpclient.c:91
static bool raw_mode
Definition dhcpclient.c:67
fr_dict_attr_autoload_t dhcpclient_dict_attr[]
Definition dhcpclient.c:94
static int sockfd
Definition dhcpclient.c:55
#define DEBUG(fmt,...)
Definition dhcpclient.c:38
static fr_time_delta_t timeout
Definition dhcpclient.c:53
static fr_dict_attr_t const * attr_dhcp_dhcp_server_identifier
Definition dhcpclient.c:90
static NEVER_RETURNS void usage(void)
Definition dhcpclient.c:113
static int send_with_socket(fr_packet_t **reply, fr_packet_t *request, UNUSED fr_pair_list_t *request_list)
Definition dhcpclient.c:335
static char const * dhcpclient_version
Definition dhcpclient.c:70
uint32_t offered_addr
Definition dhcpclient.c:75
static char * iface
Definition dhcpclient.c:60
int fr_dhcpv4_udp_packet_send(fr_packet_t *packet)
Send DHCP packet using a connectionless UDP socket.
Definition udp.c:41
@ FR_DHCP_REQUEST
Definition dhcpv4.h:47
@ FR_DHCP_DECLINE
Definition dhcpv4.h:48
@ FR_DHCP_OFFER
Definition dhcpv4.h:46
@ FR_DHCP_DISCOVER
Definition dhcpv4.h:45
@ FR_DHCP_LEASE_QUERY
Definition dhcpv4.h:54
@ FR_DHCP_RELEASE
Definition dhcpv4.h:51
@ FR_DHCP_INFORM
Definition dhcpv4.h:52
fr_packet_t * fr_dhcpv4_udp_packet_recv(int sockfd)
Receive DHCP packet using a connectionless UDP socket.
Definition udp.c:74
int fr_dhcpv4_packet_encode(fr_packet_t *packet, fr_pair_list_t *list)
Definition packet.c:390
int fr_dhcpv4_decode(TALLOC_CTX *ctx, fr_pair_list_t *out, uint8_t const *data, size_t data_len, unsigned int *code)
Definition packet.c:119
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition dict_util.c:4903
#define fr_dict_autofree(_to_free)
Definition dict.h:915
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
int fr_dict_read(fr_dict_t *dict, char const *dict_dir, char const *filename))
Read supplementary attribute definitions into an existing dictionary.
int fr_dict_attr_autoload(fr_dict_attr_autoload_t const *to_load)
Process a dict_attr_autoload element to load/verify a dictionary attribute.
Definition dict_util.c:4395
#define fr_dict_autoload(_to_load)
Definition dict.h:912
#define DICT_AUTOLOAD_TERMINATOR
Definition dict.h:311
fr_dict_gctx_t * fr_dict_global_ctx_init(TALLOC_CTX *ctx, bool free_at_exit, char const *dict_dir))
Initialise the global protocol hashes.
Definition dict_util.c:4713
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
talloc_free(hp)
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:356
int fr_inet_pton_port(fr_ipaddr_t *out, uint16_t *port_out, char const *value, ssize_t inlen, int af, bool resolve, bool mask)
Parses IPv4/6 address + port, to fr_ipaddr_t and integer (port)
Definition inet.c:944
int af
Address family.
Definition inet.h:63
union fr_ipaddr_t::@137 addr
IPv4/6 prefix.
int packet_global_init(void)
Initialises the Net.
Definition packet.c:200
void fr_packet_net_from_pairs(fr_packet_t *packet, fr_pair_list_t const *list)
Convert pairs to information in a packet.
Definition packet.c:154
int fr_debug_lvl
Definition log.c:40
fr_packet_t * fr_packet_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new fr_packet_t.
Definition packet.c:38
void fr_packet_free(fr_packet_t **packet_p)
Free a fr_packet_t.
Definition packet.c:89
unsigned short uint16_t
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_UINT8
8 Bit unsigned integer.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
unsigned int uint32_t
unsigned char uint8_t
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition missing.c:447
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
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
Definition pair.c:46
int fr_pair_list_afrom_file(TALLOC_CTX *ctx, fr_dict_t const *dict, fr_pair_list_t *out, FILE *fp, bool *pfiledone, bool allow_exec)
Read valuepairs from the fp up to End-Of-File.
char const * dhcp_message_types[]
Definition base.c:129
uint8_t eth_bcast[ETH_ADDR_LEN]
Definition base.c:167
int fr_dhcpv4_global_init(void)
Resolve/cache attributes in the DHCP dictionary.
Definition base.c:606
void fr_dhcpv4_global_free(void)
Definition base.c:630
void fr_dhcpv4_print_hex(FILE *fp, uint8_t const *packet, size_t packet_len)
Print a raw DHCP packet as hex.
Definition base.c:677
static int packet_code
static fr_ipaddr_t client_ipaddr
Definition radclient.c:84
static uint16_t server_port
Definition radclient.c:75
static fr_ipaddr_t server_ipaddr
Definition radclient.c:77
#define request_init(_ctx, _type, _args)
Definition request.h:321
#define fr_sbuff_start(_sbuff_or_marker)
#define FR_SBUFF_OUT(_start, _len_or_end)
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
Definition snprintf.c:689
int fr_socket_server_udp(fr_ipaddr_t const *src_ipaddr, uint16_t *src_port, char const *port_name, bool async)
Open an IPv4/IPv6 unconnected UDP socket.
Definition socket.c:846
int fr_socket_bind(int sockfd, char const *ifname, fr_ipaddr_t *src_ipaddr, uint16_t *src_port)
Bind a UDP/TCP v4/v6 socket to a given ipaddr src port, and interface.
Definition socket.c:200
fr_pair_t * vp
Stores an attribute, a value and various bits of other data.
Definition pair.h:68
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
Definition pair.h:69
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition syserror.c:243
#define fr_table_value_by_str(_table, _name, _def)
Convert a string to a value using a sorted or ordered table.
Definition table.h:653
An element in a lexicographically sorted array of name to num mappings.
Definition table.h:49
fr_slen_t fr_time_delta_from_str(fr_time_delta_t *out, char const *in, size_t inlen, fr_time_res_t hint)
Create fr_time_delta_t from a string.
Definition time.c:412
static int64_t fr_time_delta_unwrap(fr_time_delta_t time)
Definition time.h:154
#define fr_time_delta_wrap(_time)
Definition time.h:152
#define fr_time_delta_ispos(_a)
Definition time.h:290
#define fr_time_delta_to_timeval(_delta)
Convert a delta to a timeval.
Definition time.h:656
@ FR_TIME_RES_SEC
Definition time.h:50
#define NSEC
Definition time.h:379
A time delta, a difference in time measured in nanoseconds.
Definition time.h:80
static bool filedone
#define FR_DICTIONARY_FILE
Definition conf.h:7
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
uint8_t * data
Packet data (body).
Definition packet.h:63
size_t data_len
Length of packet data.
Definition packet.h:64
ssize_t fr_pair_print(fr_sbuff_t *out, fr_dict_attr_t const *parent, fr_pair_t const *vp))
Print one attribute and value to a string.
Definition pair_print.c:232
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
#define PAIR_VERIFY(_x)
Definition pair.h:204
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
Definition pair_inline.c:69
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
Definition pair.h:604
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
Definition pair_inline.c:42
int af
AF_INET, AF_INET6, or AF_UNIX.
Definition socket.h:75
int fd
File descriptor if this is a live socket.
Definition socket.h:78
char const * fr_strerror(void)
Get the last library error.
Definition strerror.c:553
void fr_perror(char const *fmt,...)
Print the current error to stderr with a prefix.
Definition strerror.c:732
void fr_strerror_clear(void)
Clears all pending messages from the talloc pools.
Definition strerror.c:576
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
Definition strerror.h:64
#define RADIUSD_VERSION_BUILD(_x)
Create a version string for a utility in the suite of FreeRADIUS utilities.
Definition version.h:58
static size_t char ** out
Definition value.h:1030