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: 99524a1c9207b27cfd1cb8dcc8321fdbd92038f6 $
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: 99524a1c9207b27cfd1cb8dcc8321fdbd92038f6 $")
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 = NULL;
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_LIBPCAP
263 if (pcap) {
264 reply = fr_dhcpv4_pcap_recv(pcap);
265# ifdef HAVE_LINUX_IF_PACKET_H
266 } else
267# else
268 }
269# endif
270#endif
271#ifdef HAVE_LINUX_IF_PACKET_H
272 {
273 reply = fr_dhcpv4_raw_packet_recv(lsockfd, p_ll, request, request_list);
274 }
275#elif !defined(HAVE_LIBPCAP)
276# error Need <if/packet.h> or <pcap.h>
277#endif
278 } else {
279 our_timeout = fr_time_delta_wrap(0);
280 }
281
282 if (reply) {
283 nb_reply ++;
284
285 if (fr_debug_lvl > 1) fr_dhcpv4_print_hex(stdout, reply->data, reply->data_len);
286
287 fr_pair_dcursor_init(&cursor, &reply_vps);
288 if (fr_dhcpv4_decode(reply, &reply_vps, reply->data, reply->data_len, &reply->code) < 0) {
289 ERROR("Failed decoding reply");
290 return NULL;
291 }
292
293 if (!found) found = reply;
294
295 if (reply->code == FR_DHCP_OFFER) {
298
299 if (vp1 && vp2) {
300 nb_offer++;
301 offer_list = talloc_realloc(request, offer_list, dc_offer_t, nb_offer);
302 offer_list[nb_offer - 1].server_addr = vp1->vp_ipv4addr;
303 offer_list[nb_offer - 1].offered_addr = vp2->vp_ipv4addr;
304 }
305 }
306 }
307 }
308
309 if (0 == nb_reply) {
310 DEBUG("No valid DHCP reply received");
311 return NULL;
312 }
313
314 /* display offer(s) received */
315 if (nb_offer > 0 ) {
316 int i;
317
318 DEBUG("Received %d DHCP Offer(s):", nb_offer);
319 for (i = 0; i < nb_reply; i++) {
320 char server_addr_buf[INET6_ADDRSTRLEN];
321 char offered_addr_buf[INET6_ADDRSTRLEN];
322
323 DEBUG("IP address: %s offered by DHCP server: %s",
324 inet_ntop(AF_INET, &offer_list[i].offered_addr,
325 offered_addr_buf, sizeof(offered_addr_buf)),
326 inet_ntop(AF_INET, &offer_list[i].server_addr,
327 server_addr_buf, sizeof(server_addr_buf))
328 );
329 }
330 }
331
332 return found;
333}
334#endif /* <if/packet.h> or <pcap.h> */
335
336static int send_with_socket(fr_packet_t **reply, fr_packet_t *request,
337#ifndef HAVE_LINUX_IF_PACKET_H
338 UNUSED
339#endif
340 fr_pair_list_t *request_list)
341{
342 int on = 1;
343
344#ifdef HAVE_LINUX_IF_PACKET_H
345 if (raw_mode) {
346 sockfd = fr_dhcpv4_raw_socket_open(&ll, iface_ind);
347 if (sockfd < 0) {
348 ERROR("Error opening socket");
349 return -1;
350 }
351 } else
352#endif
353 {
354 sockfd = fr_socket_server_udp(&request->socket.inet.src_ipaddr, &request->socket.inet.src_port, NULL, false);
355 if (sockfd < 0) {
356 ERROR("Error opening socket - %s", fr_strerror());
357 return -1;
358 }
359
360 if (fr_socket_bind(sockfd, NULL, &request->socket.inet.src_ipaddr, &request->socket.inet.src_port) < 0) {
361 ERROR("Error binding socket - %s", fr_strerror());
362 return -1;
363 }
364 }
365
366
367 /*
368 * Set option 'receive timeout' on socket.
369 * Note: in case of a timeout, the error will be "Resource temporarily unavailable".
370 */
371 if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO,
372 &fr_time_delta_to_timeval(timeout), sizeof(struct timeval)) == -1) {
373 ERROR("Failed setting socket timeout: %s", fr_syserror(errno));
374 return -1;
375 }
376
377 if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) < 0) {
378 ERROR("Can't set broadcast option: %s", fr_syserror(errno));
379 return -1;
380 }
381 request->socket.fd = sockfd;
382
383#ifdef HAVE_LINUX_IF_PACKET_H
384 if (raw_mode) {
385 if (fr_dhcpv4_raw_packet_send(sockfd, &ll, request, request_list) < 0) {
386 ERROR("Failed sending (fr_dhcpv4_raw_packet_send): %s", fr_syserror(errno));
387 return -1;
388 }
389 if (!reply_expected) return 0;
390
391 *reply = fr_dhcpv4_recv_raw_loop(sockfd, &ll, request, request_list);
392 if (!*reply) {
393 ERROR("Error receiving reply (fr_dhcpv4_recv_raw_loop)");
394 return -1;
395 }
396 } else
397#endif
398 {
399 if (fr_dhcpv4_udp_packet_send(request) < 0) {
400 ERROR("Failed sending: %s", fr_syserror(errno));
401 return -1;
402 }
403 if (!reply_expected) return 0;
404
406 if (!*reply) {
407 if (errno == EAGAIN) {
408 fr_strerror_clear(); /* clear error */
409 ERROR("Timed out waiting for reply");
410 } else {
411 ERROR("Error receiving reply");
412 }
413 return -1;
414 }
415 }
416
417 return 0;
418}
419
420#ifdef HAVE_LIBPCAP
421static int send_with_pcap(fr_packet_t **reply, fr_packet_t *request, fr_pair_list_t *request_list)
422{
423 char ip[16];
424 char pcap_filter[255];
425
426 pcap = fr_pcap_init(NULL, iface, PCAP_INTERFACE_IN_OUT);
427 if (!pcap) {
428 ERROR("Failed creating pcap");
429 return -1;
430 }
431
432 if (fr_pcap_open(pcap) < 0) {
433 ERROR("Failed opening interface");
434 talloc_free(pcap);
435 return -1;
436 }
437
438 fr_inet_ntoh(&request->socket.inet.src_ipaddr, ip, sizeof(ip));
439 snprintf(pcap_filter, sizeof(pcap_filter), "udp and dst port %d", request->socket.inet.src_port);
440
441 if (fr_pcap_apply_filter(pcap, pcap_filter) < 0) {
442 ERROR("Failing setting filter");
443 talloc_free(pcap);
444 return -1;
445 }
446
447 if (fr_dhcpv4_pcap_send(pcap, eth_bcast, request) < 0) {
448 ERROR("Failed sending request");
449 talloc_free(pcap);
450 return -1;
451 }
452
453 if (!reply_expected) return 0;
454
455 *reply = fr_dhcpv4_recv_raw_loop(pcap->fd,
456#ifdef HAVE_LINUX_IF_PACKET_H
457 &ll,
458#endif
459 request, request_list);
460
461 if (!*reply) {
462 ERROR("Error receiving reply");
463 talloc_free(pcap);
464 return -1;
465 }
466
467 talloc_free(pcap);
468 return 0;
469}
470#endif /* HAVE_LIBPCAP */
471
472static void dhcp_packet_debug(fr_packet_t *packet, fr_pair_list_t *list, bool received)
473{
474 char buffer[2048] = "";
475
476 char src_ipaddr[INET6_ADDRSTRLEN];
477 char dst_ipaddr[INET6_ADDRSTRLEN];
478#if defined(WITH_IFINDEX_NAME_RESOLUTION)
479 char if_name[IFNAMSIZ];
480#endif
481 fr_pair_t *vp;
482
483 if (!packet) return;
484
485 /*
486 * Client-specific debugging re-prints the input
487 * packet into the client log.
488 *
489 * This really belongs in a utility library
490 */
491 printf("%s %s Id %08x from %s%s%s:%i to %s%s%s:%i "
492#ifdef WITH_IFINDEX_NAME_RESOLUTION
493 "%s%s%s"
494#endif
495 "length %zu\n",
496 received ? "Received" : "Sending",
497 dhcp_message_types[packet->code],
498 packet->id,
499 packet->socket.inet.src_ipaddr.af == AF_INET6 ? "[" : "",
500 inet_ntop(packet->socket.inet.src_ipaddr.af,
501 &packet->socket.inet.src_ipaddr.addr,
502 src_ipaddr, sizeof(src_ipaddr)),
503 packet->socket.inet.src_ipaddr.af == AF_INET6 ? "]" : "",
504 packet->socket.inet.src_port,
505 packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "[" : "",
506 inet_ntop(packet->socket.inet.dst_ipaddr.af,
507 &packet->socket.inet.dst_ipaddr.addr,
508 dst_ipaddr, sizeof(dst_ipaddr)),
509 packet->socket.inet.dst_ipaddr.af == AF_INET6 ? "]" : "",
510 packet->socket.inet.dst_port,
511#ifdef WITH_IFINDEX_NAME_RESOLUTION
512 packet->socket.inet.ifindex ? "via " : "",
513 packet->socket.inet.ifindex ? fr_ifname_from_ifindex(if_name, packet->socket.inet.ifindex) : "",
514 packet->socket.inet.ifindex ? " " : "",
515#endif
516 packet->data_len);
517
518 for (vp = fr_pair_list_head(list);
519 vp;
520 vp = fr_pair_list_next(list, vp)) {
522
524
525 out = FR_SBUFF_OUT(buffer, sizeof(buffer));
526 (void) fr_pair_print(&out, NULL, vp);
527 printf("\t%s\n", fr_sbuff_start(&out));
528 }
529}
530
531int main(int argc, char **argv)
532{
533
534 static uint16_t server_port = 0;
535 static int packet_code = 0;
538
539 int c;
540 char const *raddb_dir = RADDBDIR;
541 char const *dict_dir = DICTDIR;
542 char const *filename = NULL;
543
544 fr_packet_t *packet = NULL;
545 fr_pair_list_t packet_vps;
546 fr_packet_t *reply = NULL;
547 fr_pair_list_t reply_vps;
548
549 int ret;
550
551 fr_pair_list_init(&packet_vps);
552 fr_pair_list_init(&reply_vps);
553
554 /*
555 * Must be called first, so the handler is called last
556 */
558
559 fr_debug_lvl = 1;
560
561 while ((c = getopt(argc, argv, "d:D:f:hr:t:vxi:")) != -1) switch(c) {
562 case 'D':
563 dict_dir = optarg;
564 break;
565
566 case 'd':
567 raddb_dir = optarg;
568 break;
569
570 case 'f':
571 filename = optarg;
572 break;
573
574 case 'i':
575 iface = optarg;
576 break;
577
578 case 'r':
579 if (!isdigit((uint8_t) *optarg)) usage();
580 retries = atoi(optarg);
581 if ((retries == 0) || (retries > 1000)) usage();
582 break;
583
584 case 't':
585 if (fr_time_delta_from_str(&timeout, optarg, strlen(optarg), FR_TIME_RES_SEC) < 0) usage();
586 break;
587
588 case 'v':
590 fr_exit(EXIT_SUCCESS);
591
592 case 'x':
593 fr_debug_lvl++;
594 break;
595
596 case 'h':
597 default:
598 usage();
599 }
600 argc -= (optind - 1);
601 argv += (optind - 1);
602
603 if (argc < 2) usage();
604
605 if (!fr_dict_global_ctx_init(NULL, true, dict_dir)) {
606 fr_perror("dhcpclient");
607 fr_exit(EXIT_FAILURE);
608 }
609
611 fr_perror("dhcpclient");
612 fr_exit(EXIT_FAILURE);
613 }
614
616 fr_perror("dhcpclient");
617 fr_exit(EXIT_FAILURE);
618 }
619
621 fr_perror("dhcpclient");
622 fr_exit(EXIT_FAILURE);
623 }
624
626
627 fr_strerror_clear(); /* Clear the error buffer */
628
629 /*
630 * Initialise the DHCPv4 library
631 */
632 if (fr_dhcpv4_global_init() < 0) {
633 fr_perror("dhcpclient");
634 fr_exit(EXIT_FAILURE);
635 }
636
637 /*
638 * Resolve hostname.
639 */
640 server_ipaddr.af = AF_INET;
641 if (strcmp(argv[1], "-") != 0) {
643 strlen(argv[1]), AF_UNSPEC, true, true) < 0) {
644 fr_perror("dhcpclient");
645 fr_exit(EXIT_FAILURE);
646 }
648 }
649
650 /*
651 * See what kind of request we want to send.
652 */
653 if (argc >= 3) {
654 if (!isdigit((uint8_t) argv[2][0])) {
656 if (packet_code == -2) {
657 ERROR("Unknown packet type: %s", argv[2]);
658 usage();
659 }
660 } else {
661 packet_code = atoi(argv[2]);
662 }
663 }
664 if (!server_port) server_port = 67;
665
666 /*
667 * set "raw mode" if an interface is specified and if destination
668 * IP address is the broadcast address.
669 */
670 if (iface) {
671 iface_ind = if_nametoindex(iface);
672 if (iface_ind <= 0) {
673 ERROR("Unknown interface: %s", iface);
674 fr_exit(EXIT_FAILURE);
675 }
676
677 if (server_ipaddr.addr.v4.s_addr == 0xFFFFFFFF) {
678 ERROR("Using interface: %s (index: %d) in raw packet mode", iface, iface_ind);
679 raw_mode = true;
680 }
681 }
682
683 if ((request_init(&packet, &packet_vps, filename) < 0) || fr_pair_list_empty(&packet_vps)) {
684 ERROR("Nothing to send");
685 fr_exit(EXIT_FAILURE);
686 }
687
688 /*
689 * Set defaults if they weren't specified via pairs
690 */
691 if (packet->socket.inet.src_port == 0) packet->socket.inet.src_port = server_port + 1;
692 if (packet->socket.inet.dst_port == 0) packet->socket.inet.dst_port = server_port;
693 if (packet->socket.inet.src_ipaddr.af == AF_UNSPEC) packet->socket.inet.src_ipaddr = client_ipaddr;
694 if (packet->socket.inet.dst_ipaddr.af == AF_UNSPEC) packet->socket.inet.dst_ipaddr = server_ipaddr;
695 if (!packet->code) packet->code = packet_code;
696
697 /*
698 * Sanity check.
699 */
700 if (!packet->code) {
701 ERROR("Command was %s, and request did not contain Message-Type nor Packet-Type",
702 (argc >= 3) ? "'auto'" : "unspecified");
703 fr_exit(EXIT_FAILURE);
704 }
705
706 /*
707 * These kind of packets do not get a reply, so don't wait for one.
708 */
709 if ((packet->code == FR_DHCP_RELEASE) || (packet->code == FR_DHCP_DECLINE)) {
710 reply_expected = false;
711 }
712
713 /*
714 * Encode the packet
715 */
716 if (fr_dhcpv4_packet_encode(packet, &packet_vps) < 0) {
717 ERROR("Failed encoding packet");
718 fr_exit(EXIT_FAILURE);
719 }
720
721 /*
722 * Decode the request to produce fr_pair_t's from the headers.
723 */
724 if (fr_debug_lvl) {
725 if (fr_debug_lvl > 1) fr_dhcpv4_print_hex(stdout, packet->data, packet->data_len);
726
727 (void) fr_dhcpv4_decode(packet, &reply_vps, packet->data, packet->data_len, &packet->code);
728 dhcp_packet_debug(packet, &reply_vps, false);
729 fr_pair_list_free(&reply_vps);
730 }
731
732#ifdef HAVE_LIBPCAP
733 if (raw_mode) {
734 ret = send_with_pcap(&reply, packet, &packet_vps);
735 } else
736#endif
737 {
738 ret = send_with_socket(&reply, packet, &packet_vps);
739 }
740
741 if (reply) {
742 if (fr_dhcpv4_decode(reply, &reply_vps, reply->data, reply->data_len, &reply->code) < 0) {
743 ERROR("Failed decoding packet");
744 ret = -1;
745 }
746 dhcp_packet_debug(reply, &reply_vps, true);
747 }
748
750
752 fr_perror("dhcpclient");
753 ret = -1;
754 }
755
756 /*
757 * Ensure our atexit handlers run before any other
758 * atexit handlers registered by third party libraries.
759 */
761
762 return ret < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
763}
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:485
#define NEVER_RETURNS
Should be placed before the function return type.
Definition build.h:315
#define L(_str)
Helper for initialising arrays of string literals.
Definition build.h:209
#define UNUSED
Definition build.h:317
#define NUM_ELEMENTS(_t)
Definition build.h:339
#define fr_exit(_x)
Exit, producing a log message in debug builds.
Definition debug.h:220
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:531
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:472
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 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:336
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:386
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_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:4436
fr_dict_t * fr_dict_unconst(fr_dict_t const *dict)
Coerce to non-const.
Definition dict_util.c:4629
#define fr_dict_autofree(_to_free)
Definition dict.h:870
fr_dict_attr_t const ** out
Where to write a pointer to the resolved fr_dict_attr_t.
Definition dict.h:274
fr_dict_t const ** out
Where to write a pointer to the loaded/resolved fr_dict_t.
Definition dict.h:287
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:4134
#define fr_dict_autoload(_to_load)
Definition dict.h:867
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:273
Specifies a dictionary which must be loaded/loadable for the module to function.
Definition dict.h:286
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:938
int af
Address family.
Definition inet.h:64
union fr_ipaddr_t::@136 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
talloc_free(reap)
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: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:697
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:127
uint8_t eth_bcast[ETH_ADDR_LEN]
Definition base.c:165
int fr_dhcpv4_global_init(void)
Resolve/cache attributes in the DHCP dictionary.
Definition base.c:585
void fr_dhcpv4_global_free(void)
Definition base.c:609
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:656
static int packet_code
static fr_ipaddr_t client_ipaddr
Definition radclient.c:85
static uint16_t server_port
Definition radclient.c:76
static fr_ipaddr_t server_ipaddr
Definition radclient.c:78
#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:865
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:227
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
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
#define PAIR_VERIFY(_x)
Definition pair.h:193
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
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:589
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: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: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:1022