2 * radclient.c General radius packet debug tool.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 * Copyright 2000,2006,2014 The FreeRADIUS server project
21 * Copyright 2000 Miquel van Smoorenburg <miquels@cistron.nl>
22 * Copyright 2000 Alan DeKok <aland@ox.org>
27 #include <freeradius-devel/radclient.h>
28 #include <freeradius-devel/radpaths.h>
29 #include <freeradius-devel/conf.h>
38 typedef struct REQUEST REQUEST; /* to shut up warnings about mschap.h */
43 static int retries = 3;
44 static float timeout = 5;
45 static char const *secret = NULL;
46 static bool do_output = true;
48 static rc_stats_t stats;
50 static uint16_t server_port = 0;
51 static int packet_code = 0;
52 static fr_ipaddr_t server_ipaddr;
53 static int resend_count = 1;
54 static bool done = true;
55 static bool print_filename = false;
57 static fr_ipaddr_t client_ipaddr;
58 static uint16_t client_port = 0;
61 static int last_used_id = -1;
64 char const *proto = NULL;
66 static int ipproto = IPPROTO_UDP;
68 static rbtree_t *filename_tree = NULL;
69 static fr_packet_list_t *pl = NULL;
71 static int sleep_time = -1;
73 static rc_request_t *request_head = NULL;
74 static rc_request_t *rc_request_tail = NULL;
76 static int rc_debug_flag;
78 char const *radclient_version = "radclient version " RADIUSD_VERSION_STRING
79 #ifdef RADIUSD_VERSION_COMMIT
80 " (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
82 ", built on " __DATE__ " at " __TIME__;
84 static void NEVER_RETURNS usage(void)
86 fprintf(stderr, "Usage: radclient [options] server[:port] <command> [<secret>]\n");
88 fprintf(stderr, " <command> One of auth, acct, status, coa, or disconnect.\n");
89 fprintf(stderr, " -4 Use IPv4 address of server\n");
90 fprintf(stderr, " -6 Use IPv6 address of server.\n");
91 fprintf(stderr, " -c <count> Send each packet 'count' times.\n");
92 fprintf(stderr, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
93 fprintf(stderr, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
94 fprintf(stderr, " -f <file>[:<file>] Read packets from file, not stdin.\n");
95 fprintf(stderr, " If a second file is provided, it will be used to verify responses\n");
96 fprintf(stderr, " -F Print the file name, packet number and reply code.\n");
97 fprintf(stderr, " -h Print usage help information.\n");
98 fprintf(stderr, " -i <id> Set request id to 'id'. Values may be 0..255\n");
99 fprintf(stderr, " -n <num> Send N requests/s\n");
100 fprintf(stderr, " -p <num> Send 'num' packets from a file in parallel.\n");
101 fprintf(stderr, " -q Do not print anything out.\n");
102 fprintf(stderr, " -r <retries> If timeout, retry sending the packet 'retries' times.\n");
103 fprintf(stderr, " -s Print out summary information of auth results.\n");
104 fprintf(stderr, " -S <file> read secret from file, not command line.\n");
105 fprintf(stderr, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating point number).\n");
106 fprintf(stderr, " -v Show program version information.\n");
107 fprintf(stderr, " -x Debugging mode.\n");
110 fprintf(stderr, " -P <proto> Use proto (tcp or udp) for transport.\n");
116 static const FR_NAME_NUMBER request_types[] = {
117 { "auth", PW_CODE_AUTHENTICATION_REQUEST },
118 { "challenge", PW_CODE_ACCESS_CHALLENGE },
119 { "acct", PW_CODE_ACCOUNTING_REQUEST },
120 { "status", PW_CODE_STATUS_SERVER },
121 { "disconnect", PW_CODE_DISCONNECT_REQUEST },
122 { "coa", PW_CODE_COA_REQUEST },
123 { "auto", PW_CODE_UNDEFINED },
129 * Free a radclient struct, which may (or may not)
130 * already be in the list.
132 static int _rc_request_free(rc_request_t *request)
134 rc_request_t *prev, *next;
136 prev = request->prev;
137 next = request->next;
140 assert(request_head != request);
142 } else if (request_head) {
143 assert(request_head == request);
148 assert(rc_request_tail != request);
150 } else if (rc_request_tail) {
151 assert(rc_request_tail == request);
152 rc_request_tail = prev;
158 static int mschapv1_encode(RADIUS_PACKET *packet, VALUE_PAIR **request,
159 char const *password)
163 VALUE_PAIR *challenge, *reply;
166 challenge = paircreate(packet, PW_MSCHAP_CHALLENGE, VENDORPEC_MICROSOFT);
171 pairadd(request, challenge);
172 challenge->length = 8;
173 challenge->vp_octets = p = talloc_array(challenge, uint8_t, challenge->length);
174 for (i = 0; i < challenge->length; i++) {
178 reply = paircreate(packet, PW_MSCHAP_RESPONSE, VENDORPEC_MICROSOFT);
183 pairadd(request, reply);
185 reply->vp_octets = p = talloc_array(reply, uint8_t, reply->length);
186 memset(p, 0, reply->length);
188 p[1] = 0x01; /* NT hash */
190 if (mschap_ntpwdhash(nthash, password) < 0) {
194 smbdes_mschap(nthash, challenge->vp_octets, p + 26);
199 static int getport(char const *name)
203 svp = getservbyname(name, "udp");
208 return ntohs(svp->s_port);
211 static void radclient_get_port(PW_CODE type, uint16_t *port)
215 case PW_CODE_AUTHENTICATION_REQUEST:
216 case PW_CODE_ACCESS_CHALLENGE:
217 case PW_CODE_STATUS_SERVER:
218 if (*port == 0) *port = getport("radius");
219 if (*port == 0) *port = PW_AUTH_UDP_PORT;
222 case PW_CODE_ACCOUNTING_REQUEST:
223 if (*port == 0) *port = getport("radacct");
224 if (*port == 0) *port = PW_ACCT_UDP_PORT;
227 case PW_CODE_DISCONNECT_REQUEST:
228 case PW_CODE_COA_REQUEST:
229 if (*port == 0) *port = PW_COA_UDP_PORT;
232 case PW_CODE_UNDEFINED:
233 if (*port == 0) *port = 0;
238 * Initialize a radclient data structure and add it to
239 * the global linked list.
241 static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
243 FILE *packets, *filters = NULL;
247 rc_request_t *request;
248 bool packets_done = false;
251 assert(files->packets != NULL);
254 * Determine where to read the VP's from.
256 if (strcmp(files->packets, "stdin") != 0) {
257 packets = fopen(files->packets, "r");
259 ERROR("Error opening %s: %s", files->packets, strerror(errno));
264 * Read in the pairs representing the expected response.
266 if (files->filters) {
267 filters = fopen(files->filters, "r");
269 ERROR("Error opening %s: %s", files->filters, strerror(errno));
280 * Loop until the file is done.
286 request = talloc_zero(ctx, rc_request_t);
288 ERROR("Out of memory");
292 request->packet = rad_alloc(request, 1);
293 if (!request->packet) {
294 ERROR("Out of memory");
299 request->packet->src_ipaddr = client_ipaddr;
300 request->packet->src_port = client_port;
301 request->packet->dst_ipaddr = server_ipaddr;
302 request->packet->dst_port = server_port;
303 request->packet->proto = ipproto;
306 request->files = files;
307 request->packet->id = -1; /* allocate when sending */
308 request->num = num++;
311 * Read the request VP's.
313 if (readvp2(&request->packet->vps, request->packet, packets, &packets_done) < 0) {
314 REDEBUG("Error parsing \"%s\"", files->packets);
321 if (!request->packet->vps) {
322 talloc_free(request);
327 * Read in filter VP's.
332 if (readvp2(&request->filter, request, filters, &filters_done) < 0) {
333 REDEBUG("Error parsing \"%s\"", files->filters);
337 if (filters_done && !packets_done) {
338 REDEBUG("Differing number of packets/filters in %s:%s "
339 "(too many requests))", files->packets, files->filters);
343 if (!filters_done && packets_done) {
344 REDEBUG("Differing number of packets/filters in %s:%s "
345 "(too many filters))", files->packets, files->filters);
350 * xlat expansions aren't supported here
352 for (vp = fr_cursor_init(&cursor, &request->filter);
354 vp = fr_cursor_next(&cursor)) {
355 if (vp->type == VT_XLAT) {
357 vp->vp_strvalue = vp->value.xlat;
358 vp->length = talloc_array_length(vp->vp_strvalue) - 1;
361 if (vp->da->vendor == 0 ) switch (vp->da->attr) {
362 case PW_RESPONSE_PACKET_TYPE:
364 fr_cursor_remove(&cursor); /* so we don't break the filter */
365 request->filter_code = vp->vp_integer;
374 * This allows efficient list comparisons later
376 pairsort(&request->filter, attrtagcmp);
379 request->password[0] = '\0';
381 * Process special attributes
383 for (vp = fr_cursor_init(&cursor, &request->packet->vps);
385 vp = fr_cursor_next(&cursor)) {
387 * Double quoted strings get marked up as xlat expansions,
388 * but we don't support that in request.
390 if (vp->type == VT_XLAT) {
392 vp->vp_strvalue = vp->value.xlat;
393 vp->length = talloc_array_length(vp->vp_strvalue) - 1;
396 if (!vp->da->vendor) switch (vp->da->attr) {
401 * Allow it to set the packet type in
402 * the attributes read from the file.
405 request->packet->code = vp->vp_integer;
408 case PW_PACKET_DST_PORT:
409 request->packet->dst_port = (vp->vp_integer & 0xffff);
412 case PW_PACKET_DST_IP_ADDRESS:
413 request->packet->dst_ipaddr.af = AF_INET;
414 request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
417 case PW_PACKET_DST_IPV6_ADDRESS:
418 request->packet->dst_ipaddr.af = AF_INET6;
419 request->packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
422 case PW_PACKET_SRC_PORT:
423 request->packet->src_port = (vp->vp_integer & 0xffff);
426 case PW_PACKET_SRC_IP_ADDRESS:
427 request->packet->src_ipaddr.af = AF_INET;
428 request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
431 case PW_PACKET_SRC_IPV6_ADDRESS:
432 request->packet->src_ipaddr.af = AF_INET6;
433 request->packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
436 case PW_DIGEST_REALM:
437 case PW_DIGEST_NONCE:
438 case PW_DIGEST_METHOD:
441 case PW_DIGEST_ALGORITHM:
442 case PW_DIGEST_BODY_DIGEST:
443 case PW_DIGEST_CNONCE:
444 case PW_DIGEST_NONCE_COUNT:
445 case PW_DIGEST_USER_NAME:
451 p = talloc_array(vp, uint8_t, vp->length + 2);
453 memcpy(p + 2, vp->vp_octets, vp->length);
454 p[0] = vp->da->attr - PW_DIGEST_REALM + 1;
458 da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0);
460 ERROR("Out of memory");
466 * Re-do pairmemsteal ourselves,
467 * because we play games with
468 * vp->da, and pairmemsteal goes
469 * to GREAT lengths to sanitize
470 * and fix and change and
471 * double-check the various
474 memcpy(&q, &vp->vp_octets, sizeof(q));
477 vp->vp_octets = talloc_steal(vp, p);
485 * Keep a copy of the the password attribute.
487 case PW_USER_PASSWORD:
488 case PW_CHAP_PASSWORD:
489 case PW_MS_CHAP_PASSWORD:
490 strlcpy(request->password, vp->vp_strvalue, sizeof(request->password));
493 case PW_RADCLIENT_TEST_NAME:
494 request->name = vp->vp_strvalue;
497 } /* loop over the VP's we read in */
500 * Use the default set on the command line
502 if (request->packet->code == 0) {
503 request->packet->code = packet_code;
507 * Default to the filename
509 if (!request->name) {
510 request->name = request->files->packets;
514 * Automatically set the response code from the request code
515 * (if one wasn't already set).
517 if (!request->filter_code) {
518 switch (request->packet->code) {
519 case PW_CODE_AUTHENTICATION_REQUEST:
520 request->filter_code = PW_CODE_AUTHENTICATION_ACK;
523 case PW_CODE_ACCOUNTING_REQUEST:
524 request->filter_code = PW_CODE_ACCOUNTING_RESPONSE;
527 case PW_CODE_COA_REQUEST:
528 request->filter_code = PW_CODE_COA_ACK;
531 case PW_CODE_DISCONNECT_REQUEST:
532 request->filter_code = PW_CODE_DISCONNECT_ACK;
541 * Automatically set the dst port if one wasn't already set.
543 if (request->packet->dst_port == 0) {
544 radclient_get_port(request->packet->code, &request->packet->dst_port);
548 * Add it to the tail of the list.
551 assert(rc_request_tail == NULL);
552 request_head = request;
553 request->prev = NULL;
555 assert(rc_request_tail->next == NULL);
556 rc_request_tail->next = request;
557 request->prev = rc_request_tail;
559 rc_request_tail = request;
560 request->next = NULL;
563 * Set the destructor so it removes itself from the
564 * request list when freed. We don't set this until
565 * the packet is actually in the list, else we trigger
566 * the asserts in the free callback.
568 talloc_set_destructor(request, _rc_request_free);
569 } while (!packets_done); /* loop until the file is done. */
571 if (packets != stdin) fclose(packets);
572 if (filters) fclose(filters);
580 talloc_free(request);
582 if (packets != stdin) fclose(packets);
583 if (filters) fclose(filters);
590 * Sanity check each argument.
592 static int radclient_sane(rc_request_t *request)
594 if (request->packet->dst_port == 0) {
595 request->packet->dst_port = server_port;
597 if (request->packet->dst_ipaddr.af == AF_UNSPEC) {
598 if (server_ipaddr.af == AF_UNSPEC) {
599 ERROR("No server was given, and request %" PRIu64 " in file %s did not contain "
600 "Packet-Dst-IP-Address", request->num, request->files->packets);
603 request->packet->dst_ipaddr = server_ipaddr;
605 if (request->packet->code == 0) {
606 if (packet_code == -1) {
607 ERROR("Request was \"auto\", and request %" PRIu64 " in file %s did not contain Packet-Type",
608 request->num, request->files->packets);
611 request->packet->code = packet_code;
613 request->packet->sockfd = -1;
620 * For request handling.
622 static int filename_cmp(void const *one, void const *two)
626 rc_file_pair_t const *a = one;
627 rc_file_pair_t const *b = two;
629 cmp = strcmp(a->packets, b->packets);
630 if (cmp != 0) return cmp;
632 return strcmp(a->filters, b->filters);
635 static int filename_walk(UNUSED void *context, void *data)
637 rc_file_pair_t *files = data;
640 * Read request(s) from the file.
642 if (!radclient_init(files, files)) {
643 return -1; /* stop walking */
651 * Deallocate packet ID, etc.
653 static void deallocate_id(rc_request_t *request)
655 if (!request || !request->packet ||
656 (request->packet->id < 0)) {
661 * One more unused RADIUS ID.
663 fr_packet_list_id_free(pl, request->packet, true);
666 * If we've already sent a packet, free up the old one,
667 * and ensure that the next packet has a unique
668 * authentication vector.
670 if (request->packet->data) {
671 TALLOC_FREE(request->packet->data);
674 if (request->reply) rad_free(&request->reply);
680 static int send_one_packet(rc_request_t *request)
682 assert(request->done == false);
685 * Remember when we have to wake up, to re-send the
686 * request, of we didn't receive a reply.
688 if ((sleep_time == -1) || (sleep_time > (int) timeout)) {
689 sleep_time = (int) timeout;
693 * Haven't sent the packet yet. Initialize it.
695 if (request->packet->id == -1) {
699 assert(request->reply == NULL);
702 * Didn't find a free packet ID, we're not done,
703 * we don't sleep, and we stop trying to process
707 request->packet->src_ipaddr.af = server_ipaddr.af;
708 rcode = fr_packet_list_id_alloc(pl, ipproto,
709 &request->packet, NULL);
715 mysockfd = fr_tcp_client_socket(NULL,
716 &request->packet->dst_ipaddr,
717 request->packet->dst_port);
720 mysockfd = fr_socket(&client_ipaddr, 0);
722 ERROR("Failed opening socket");
725 if (!fr_packet_list_socket_add(pl, mysockfd, ipproto,
726 &request->packet->dst_ipaddr,
727 request->packet->dst_port, NULL)) {
728 ERROR("Can't add new socket");
734 assert(request->packet->id != -1);
735 assert(request->packet->data == NULL);
737 for (i = 0; i < 4; i++) {
738 ((uint32_t *) request->packet->vector)[i] = fr_rand();
742 * Update the password, so it can be encrypted with the
743 * new authentication vector.
745 if (request->password[0] != '\0') {
748 if ((vp = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) {
749 pairstrcpy(vp, request->password);
751 } else if ((vp = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
752 bool already_hex = false;
755 * If it's 17 octets, it *might* be already encoded.
756 * Or, it might just be a 17-character password (maybe UTF-8)
757 * Check it for non-printable characters. The odds of ALL
758 * of the characters being 32..255 is (1-7/8)^17, or (1/8)^17,
759 * or 1/(2^51), which is pretty much zero.
761 if (vp->length == 17) {
762 for (i = 0; i < 17; i++) {
763 if (vp->vp_octets[i] < 32) {
771 * Allow the user to specify ASCII or hex CHAP-Password
777 len = len2 = strlen(request->password);
778 if (len2 < 17) len2 = 17;
780 p = talloc_zero_array(vp, uint8_t, len2);
782 memcpy(p, request->password, len);
784 rad_chap_encode(request->packet,
786 fr_rand() & 0xff, vp);
790 } else if (pairfind(request->packet->vps, PW_MS_CHAP_PASSWORD, 0, TAG_ANY) != NULL) {
791 mschapv1_encode(request->packet,
792 &request->packet->vps,
795 DEBUG("WARNING: No password in the request");
799 request->timestamp = time(NULL);
807 if (client_port == 0) {
808 client_ipaddr = request->packet->src_ipaddr;
809 client_port = request->packet->src_port;
813 } else { /* request->packet->id >= 0 */
814 time_t now = time(NULL);
817 * FIXME: Accounting packets are never retried!
818 * The Acct-Delay-Time attribute is updated to
819 * reflect the delay, and the packet is re-sent
824 * Not time for a retry, do so.
826 if ((now - request->timestamp) < timeout) {
828 * When we walk over the tree sending
829 * packets, we update the minimum time
832 if ((sleep_time == -1) ||
833 (sleep_time > (now - request->timestamp))) {
834 sleep_time = now - request->timestamp;
840 * We're not trying later, maybe the packet is done.
842 if (request->tries == retries) {
843 assert(request->packet->id >= 0);
846 * Delete the request from the tree of
847 * outstanding requests.
849 fr_packet_list_yank(pl, request->packet);
851 REDEBUG("No reply from server for ID %d socket %d",
852 request->packet->id, request->packet->sockfd);
853 deallocate_id(request);
856 * Normally we mark it "done" when we've received
857 * the reply, but this is a special case.
859 if (request->resend == resend_count) {
860 request->done = true;
867 * We are trying later.
869 request->timestamp = now;
876 if (rad_send(request->packet, NULL, secret) < 0) {
877 REDEBUG("Failed to send packet for ID %d", request->packet->id);
884 * Receive one packet, maybe.
886 static int recv_one_packet(int wait_time)
890 rc_request_t *request;
891 RADIUS_PACKET *reply, **packet_p;
894 /* And wait for reply, timing out as necessary */
897 max_fd = fr_packet_list_fd_set(pl, &set);
898 if (max_fd < 0) exit(1); /* no sockets to listen on! */
900 if (wait_time <= 0) {
903 tv.tv_sec = wait_time;
908 * No packet was received.
910 if (select(max_fd, &set, NULL, NULL, &tv) <= 0) {
915 * Look for the packet.
917 reply = fr_packet_list_recv(pl, &set);
919 ERROR("Received bad packet");
922 * If the packet is bad, we close the socket.
923 * I'm not sure how to do that now, so we just
928 return -1; /* bad packet */
932 * udpfromto issues. We may have bound to "*",
933 * and we want to find the replies that are sent to
936 * This only works if were not using any of the
937 * Packet-* attributes, or running with 'auto'.
939 reply->dst_ipaddr = client_ipaddr;
940 reply->dst_port = client_port;
942 if (server_port > 0) {
943 reply->src_ipaddr = server_ipaddr;
944 reply->src_port = server_port;
948 packet_p = fr_packet_list_find_byreply(pl, reply);
950 ERROR("Received reply to request we did not send. (id=%d socket %d)",
951 reply->id, reply->sockfd);
953 return -1; /* got reply to packet we didn't send */
955 request = fr_packet2myptr(rc_request_t, packet, packet_p);
958 * Fails the signature validation: not a real reply.
959 * FIXME: Silently drop it and listen for another packet.
961 if (rad_verify(reply, request->packet, secret) < 0) {
962 REDEBUG("Reply verification failed");
964 goto packet_done; /* shared secret is incorrect */
967 if (print_filename) {
968 RDEBUG("%s response code %d", request->files->packets, reply->code);
971 deallocate_id(request);
972 request->reply = reply;
976 * If this fails, we're out of memory.
978 if (rad_decode(request->reply, request->packet, secret) != 0) {
979 REDEBUG("Reply decode failed");
985 * Increment counters...
987 switch (request->reply->code) {
988 case PW_CODE_AUTHENTICATION_ACK:
989 case PW_CODE_ACCOUNTING_RESPONSE:
990 case PW_CODE_COA_ACK:
991 case PW_CODE_DISCONNECT_ACK:
995 case PW_CODE_ACCESS_CHALLENGE:
1003 * If we had an expected response code, check to see if the
1004 * packet matched that.
1006 if (request->reply->code != request->filter_code) {
1007 if (is_radius_code(request->reply->code)) {
1008 REDEBUG("%s: Expected %s got %s", request->name, fr_packet_codes[request->filter_code],
1009 fr_packet_codes[request->reply->code]);
1011 REDEBUG("%s: Expected %u got %i", request->name, request->filter_code,
1012 request->reply->code);
1016 * Check if the contents of the packet matched the filter
1018 } else if (!request->filter) {
1021 VALUE_PAIR const *failed[2];
1023 pairsort(&request->reply->vps, attrtagcmp);
1024 if (pairvalidate(failed, request->filter, request->reply->vps)) {
1025 RDEBUG("%s: Response passed filter", request->name);
1028 pairvalidate_debug(request, failed);
1029 REDEBUG("%s: Response for failed filter", request->name);
1034 if (request->resend == resend_count) {
1035 request->done = true;
1039 rad_free(&request->reply);
1040 rad_free(&reply); /* may be NULL */
1045 int main(int argc, char **argv)
1048 char const *radius_dir = RADDBDIR;
1049 char const *dict_dir = DICTDIR;
1050 char filesecret[256];
1052 int do_summary = false;
1056 int force_af = AF_UNSPEC;
1059 * It's easier having two sets of flags to set the
1060 * verbosity of library calls and the verbosity of
1068 if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
1069 fr_perror("radclient");
1074 talloc_set_log_stderr();
1076 filename_tree = rbtree_create(filename_cmp, NULL, 0);
1077 if (!filename_tree) {
1079 ERROR("Out of memory");
1083 while ((c = getopt(argc, argv, "46c:d:D:f:Fhi:n:p:qr:sS:t:vx"
1087 )) != EOF) switch(c) {
1092 force_af = AF_INET6;
1095 if (!isdigit((int) *optarg))
1097 resend_count = atoi(optarg);
1103 radius_dir = optarg;
1108 rc_file_pair_t *files;
1110 files = talloc(talloc_autofree_context(), rc_file_pair_t);
1111 if (!files) goto oom;
1113 p = strchr(optarg, ':');
1115 files->packets = talloc_strndup(files, optarg, p - optarg);
1116 if (!files->packets) goto oom;
1117 files->filters = p + 1;
1119 files->packets = optarg;
1120 files->filters = NULL;
1122 rbtree_insert(filename_tree, (void *) files);
1126 print_filename = true;
1128 case 'i': /* currently broken */
1129 if (!isdigit((int) *optarg))
1131 last_used_id = atoi(optarg);
1132 if ((last_used_id < 0) || (last_used_id > 255)) {
1138 persec = atoi(optarg);
1139 if (persec <= 0) usage();
1143 * Note that sending MANY requests in
1144 * parallel can over-run the kernel
1145 * queues, and Linux will happily discard
1146 * packets. So even if the server responds,
1147 * the client may not see the reply.
1150 parallel = atoi(optarg);
1151 if (parallel <= 0) usage();
1157 if (strcmp(proto, "tcp") != 0) {
1158 if (strcmp(proto, "udp") == 0) {
1164 ipproto = IPPROTO_TCP;
1172 fr_log_fp = NULL; /* no output from you, either! */
1176 if (!isdigit((int) *optarg))
1178 retries = atoi(optarg);
1179 if ((retries == 0) || (retries > 1000)) usage();
1187 fp = fopen(optarg, "r");
1189 ERROR("Error opening %s: %s", optarg, fr_syserror(errno));
1192 if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
1193 ERROR("Error reading %s: %s", optarg, fr_syserror(errno));
1198 /* truncate newline */
1199 p = filesecret + strlen(filesecret) - 1;
1200 while ((p >= filesecret) &&
1206 if (strlen(filesecret) < 2) {
1207 ERROR("Secret in %s is too short", optarg);
1210 secret = filesecret;
1214 if (!isdigit((int) *optarg))
1216 timeout = atof(optarg);
1219 DEBUG("%s", radclient_version);
1231 argc -= (optind - 1);
1232 argv += (optind - 1);
1234 if ((argc < 3) || ((secret == NULL) && (argc < 4))) {
1235 ERROR("Insufficient arguments");
1239 * Mismatch between the binary and the libraries it depends on
1241 if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
1242 fr_perror("radclient");
1246 if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) {
1247 fr_perror("radclient");
1251 if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) {
1252 fr_perror("radclient");
1255 fr_strerror(); /* Clear the error buffer */
1259 * Get the request type
1261 if (!isdigit((int) argv[2][0])) {
1262 packet_code = fr_str2int(request_types, argv[2], -2);
1263 if (packet_code == -2) {
1264 ERROR("Unrecognised request type \"%s\"", argv[2]);
1268 packet_code = atoi(argv[2]);
1274 if (force_af == AF_UNSPEC) force_af = AF_INET;
1275 server_ipaddr.af = force_af;
1276 if (strcmp(argv[1], "-") != 0) {
1278 char const *hostname = argv[1];
1279 char const *portname = argv[1];
1282 if (*argv[1] == '[') { /* IPv6 URL encoded */
1283 p = strchr(argv[1], ']');
1284 if ((size_t) (p - argv[1]) >= sizeof(buffer)) {
1288 memcpy(buffer, argv[1] + 1, p - argv[1] - 1);
1289 buffer[p - argv[1] - 1] = '\0';
1295 p = strchr(portname, ':');
1296 if (p && (strchr(p + 1, ':') == NULL)) {
1303 if (ip_hton(&server_ipaddr, force_af, hostname, false) < 0) {
1304 ERROR("Failed to find IP address for host %s: %s", hostname, strerror(errno));
1309 * Strip port from hostname if needed.
1311 if (portname) server_port = atoi(portname);
1314 radclient_get_port(packet_code, &server_port);
1319 if (argv[3]) secret = argv[3];
1322 * If no '-f' is specified, we're reading from stdin.
1324 if (rbtree_num_elements(filename_tree) == 0) {
1325 rc_file_pair_t *files;
1327 files = talloc_zero(talloc_autofree_context(), rc_file_pair_t);
1328 files->packets = "stdin";
1329 if (!radclient_init(files, files)) {
1335 * Walk over the list of filenames, creating the requests.
1337 if (rbtree_walk(filename_tree, RBTREE_IN_ORDER, filename_walk, NULL) != 0) {
1338 ERROR("Failed parsing input files");
1343 * No packets read. Die.
1345 if (!request_head) {
1346 ERROR("Nothing to send");
1351 * Bind to the first specified IP address and port.
1352 * This means we ignore later ones.
1354 if (request_head->packet->src_ipaddr.af == AF_UNSPEC) {
1355 memset(&client_ipaddr, 0, sizeof(client_ipaddr));
1356 client_ipaddr.af = server_ipaddr.af;
1359 client_ipaddr = request_head->packet->src_ipaddr;
1360 client_port = request_head->packet->src_port;
1364 sockfd = fr_tcp_client_socket(NULL, &server_ipaddr, server_port);
1367 sockfd = fr_socket(&client_ipaddr, client_port);
1369 ERROR("Error opening socket");
1373 pl = fr_packet_list_create(1);
1375 ERROR("Out of memory");
1379 if (!fr_packet_list_socket_add(pl, sockfd, ipproto, &server_ipaddr,
1380 server_port, NULL)) {
1381 ERROR("Out of memory");
1386 * Walk over the list of packets, sanity checking
1389 for (this = request_head; this != NULL; this = this->next) {
1390 this->packet->src_ipaddr = client_ipaddr;
1391 this->packet->src_port = client_port;
1392 if (radclient_sane(this) != 0) {
1398 * Walk over the packets to send, until
1401 * FIXME: This currently busy-loops until it receives
1402 * all of the packets. It should really have some sort of
1403 * send packet, get time to wait, select for time, etc.
1409 char const *filename = NULL;
1415 * Walk over the packets, sending them.
1418 for (this = request_head; this != NULL; this = next) {
1422 * If there's a packet to receive,
1423 * receive it, but don't wait for a
1429 * This packet is done. Delete it.
1437 * Packets from multiple '-f' are sent
1440 * Packets from one file are sent in
1441 * series, unless '-p' is specified, in
1442 * which case N packets from each file
1443 * are sent in parallel.
1445 if (this->files->packets != filename) {
1446 filename = this->files->packets;
1454 * Send the current packet.
1456 send_one_packet(this);
1459 * Wait a little before sending
1460 * the next packet, if told to.
1466 * Don't sleep elsewhere.
1475 tv.tv_usec = 1000000/persec;
1479 * Sleep for milliseconds,
1482 * If we get an error or
1483 * a signal, treat it like
1486 select(0, NULL, NULL, NULL, &tv);
1490 * If we haven't sent this packet
1491 * often enough, we're not done,
1492 * and we shouldn't sleep.
1494 if (this->resend < resend_count) {
1498 } else { /* haven't sent this packet, we're not done */
1499 assert(this->done == false);
1500 assert(this->reply == NULL);
1506 * Still have outstanding requests.
1508 if (fr_packet_list_num_elements(pl) > 0) {
1515 * Nothing to do until we receive a request, so
1516 * sleep until then. Once we receive one packet,
1517 * we go back, and walk through the whole list again,
1518 * sending more packets (if necessary), and updating
1521 if (!done && (sleep_time > 0)) {
1522 recv_one_packet(sleep_time);
1526 rbtree_free(filename_tree);
1527 fr_packet_list_free(pl);
1528 while (request_head) TALLOC_FREE(request_head);
1532 DEBUG("Packet summary:\n"
1533 "\tAccepted : %" PRIu64 "\n"
1534 "\tRejected : %" PRIu64 "\n"
1535 "\tLost : %" PRIu64 "\n"
1536 "\tPassed filter : %" PRIu64 "\n"
1537 "\tFailed filter : %" PRIu64,
1546 if ((stats.lost > 0) || (stats.failed > 0)) {