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