Make "-c" work
[freeradius.git] / src / main / radclient.c
1 /*
2  * radclient.c  General radius packet debug tool.
3  *
4  * Version:     $Id$
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 2000  Alan DeKok <aland@ox.org>
23  */
24
25 #include <freeradius-devel/ident.h>
26 RCSID("$Id$")
27
28 #include <freeradius-devel/libradius.h>
29 #include <freeradius-devel/conf.h>
30 #include <freeradius-devel/radpaths.h>
31
32 #include <ctype.h>
33
34 #ifdef HAVE_GETOPT_H
35 #       include <getopt.h>
36 #endif
37
38 #include <assert.h>
39
40 static int retries = 10;
41 static float timeout = 3;
42 static const char *secret = NULL;
43 static int do_output = 1;
44 static int totalapp = 0;
45 static int totaldeny = 0;
46 static int totallost = 0;
47
48 static int server_port = 0;
49 static int packet_code = 0;
50 static lrad_ipaddr_t server_ipaddr;
51 static int resend_count = 1;
52 static int done = 1;
53 static int print_filename = 0;
54
55 static lrad_ipaddr_t client_ipaddr;
56 static int client_port = 0;
57
58 static int sockfd;
59 static int last_used_id = -1;
60
61 static rbtree_t *filename_tree = NULL;
62 static lrad_packet_list_t *pl = NULL;
63
64 static int sleep_time = -1;
65
66 typedef struct radclient_t {
67         struct          radclient_t *prev;
68         struct          radclient_t *next;
69
70         const char      *filename;
71         int             packet_number; /* in the file */
72         char            password[256];
73         time_t          timestamp;
74         RADIUS_PACKET   *request;
75         RADIUS_PACKET   *reply;
76         int             resend;
77         int             tries;
78         int             done;
79 } radclient_t;
80
81 static radclient_t *radclient_head = NULL;
82 static radclient_t *radclient_tail = NULL;
83
84
85 static void NEVER_RETURNS usage(void)
86 {
87         fprintf(stderr, "Usage: radclient [options] server[:port] <command> [<secret>]\n");
88
89         fprintf(stderr, "  <command>    One of auth, acct, status, coa, or disconnect.\n");
90         fprintf(stderr, "  -c count    Send each packet 'count' times.\n");
91         fprintf(stderr, "  -d raddb    Set dictionary directory.\n");
92         fprintf(stderr, "  -f file     Read packets from file, not stdin.\n");
93         fprintf(stderr, "  -i id       Set request id to 'id'.  Values may be 0..255\n");
94         fprintf(stderr, "  -n num      Send N requests/s\n");
95         fprintf(stderr, "  -p num      Send 'num' packets from a file in parallel.\n");
96         fprintf(stderr, "  -q          Do not print anything out.\n");
97         fprintf(stderr, "  -r retries  If timeout, retry sending the packet 'retries' times.\n");
98         fprintf(stderr, "  -s          Print out summary information of auth results.\n");
99         fprintf(stderr, "  -S file     read secret from file, not command line.\n");
100         fprintf(stderr, "  -t timeout  Wait 'timeout' seconds before retrying (may be a floating point number).\n");
101         fprintf(stderr, "  -v          Show program version information.\n");
102         fprintf(stderr, "  -x          Debugging mode.\n");
103         fprintf(stderr, "  -4          Use IPv4 address of server\n");
104         fprintf(stderr, "  -6          Use IPv6 address of server.\n");
105
106         exit(1);
107 }
108
109 /*
110  *      Free a radclient struct, which may (or may not)
111  *      already be in the list.
112  */
113 static void radclient_free(radclient_t *radclient)
114 {
115         radclient_t *prev, *next;
116
117         if (radclient->request) rad_free(&radclient->request);
118         if (radclient->reply) rad_free(&radclient->reply);
119
120         prev = radclient->prev;
121         next = radclient->next;
122
123         if (prev) {
124                 assert(radclient_head != radclient);
125                 prev->next = next;
126         } else if (radclient_head) {
127                 assert(radclient_head == radclient);
128                 radclient_head = next;
129         }
130
131         if (next) {
132                 assert(radclient_tail != radclient);
133                 next->prev = prev;
134         } else if (radclient_tail) {
135                 assert(radclient_tail == radclient);
136                 radclient_tail = prev;
137         }
138
139         free(radclient);
140 }
141
142 /*
143  *      Initialize a radclient data structure
144  */
145 static radclient_t *radclient_init(const char *filename)
146 {
147         FILE *fp;
148         VALUE_PAIR *vp;
149         radclient_t *start, *radclient, *prev = NULL;
150         int filedone = 0;
151         int packet_number = 1;
152
153         start = NULL;
154         assert(filename != NULL);
155
156         /*
157          *      Determine where to read the VP's from.
158          */
159         if (strcmp(filename, "-") != 0) {
160                 fp = fopen(filename, "r");
161                 if (!fp) {
162                         fprintf(stderr, "radclient: Error opening %s: %s\n",
163                                 filename, strerror(errno));
164                         return NULL;
165                 }
166         } else {
167                 fp = stdin;
168         }
169
170         /*
171          *      Loop until the file is done.
172          */
173         do {
174                 /*
175                  *      Allocate it.
176                  */
177                 radclient = malloc(sizeof(*radclient));
178                 if (!radclient) {
179                         perror("radclient: X");
180                         return NULL; /* memory leak "start" */
181                 }
182                 memset(radclient, 0, sizeof(*radclient));
183
184                 radclient->request = rad_alloc(1);
185                 if (!radclient->request) {
186                         librad_perror("radclient: Y");
187                         radclient_free(radclient);
188                         return NULL; /* memory leak "start" */
189                 }
190
191                 radclient->filename = filename;
192                 radclient->request->id = -1; /* allocate when sending */
193                 radclient->packet_number = packet_number++;
194
195                 /*
196                  *      Read the VP's.
197                  */
198                 radclient->request->vps = readvp2(fp, &filedone, "radclient:");
199                 if (!radclient->request->vps) {
200                         radclient_free(radclient);
201                         return start; /* done: return the list */
202                 }
203
204                 /*
205                  *      Keep a copy of the the User-Password attribute.
206                  */
207                 if ((vp = pairfind(radclient->request->vps, PW_USER_PASSWORD)) != NULL) {
208                         strlcpy(radclient->password, vp->vp_strvalue,
209                                 sizeof(radclient->password));
210                         /*
211                          *      Otherwise keep a copy of the CHAP-Password attribute.
212                          */
213                 } else if ((vp = pairfind(radclient->request->vps, PW_CHAP_PASSWORD)) != NULL) {
214                         strlcpy(radclient->password, vp->vp_strvalue,
215                                 sizeof(radclient->password));
216                 } else {
217                         radclient->password[0] = '\0';
218                 }
219
220                 /*
221                  *  Fix up Digest-Attributes issues
222                  */
223                 for (vp = radclient->request->vps; vp != NULL; vp = vp->next) {
224                         switch (vp->attribute) {
225                         default:
226                                 break;
227
228                                 /*
229                                  *      Allow it to set the packet type in
230                                  *      the attributes read from the file.
231                                  */
232                         case PW_PACKET_TYPE:
233                                 radclient->request->code = vp->vp_integer;
234                                 break;
235
236                         case PW_PACKET_DST_PORT:
237                                 radclient->request->dst_port = (vp->vp_integer & 0xffff);
238                                 break;
239
240                         case PW_PACKET_DST_IP_ADDRESS:
241                                 radclient->request->dst_ipaddr.af = AF_INET;
242                                 radclient->request->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
243                                 break;
244
245                         case PW_PACKET_DST_IPV6_ADDRESS:
246                                 radclient->request->dst_ipaddr.af = AF_INET6;
247                                 radclient->request->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
248                                 break;
249
250                         case PW_PACKET_SRC_PORT:
251                                 radclient->request->src_port = (vp->vp_integer & 0xffff);
252                                 break;
253
254                         case PW_PACKET_SRC_IP_ADDRESS:
255                                 radclient->request->src_ipaddr.af = AF_INET;
256                                 radclient->request->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
257                                 break;
258
259                         case PW_PACKET_SRC_IPV6_ADDRESS:
260                                 radclient->request->src_ipaddr.af = AF_INET6;
261                                 radclient->request->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
262                                 break;
263
264                         case PW_DIGEST_REALM:
265                         case PW_DIGEST_NONCE:
266                         case PW_DIGEST_METHOD:
267                         case PW_DIGEST_URI:
268                         case PW_DIGEST_QOP:
269                         case PW_DIGEST_ALGORITHM:
270                         case PW_DIGEST_BODY_DIGEST:
271                         case PW_DIGEST_CNONCE:
272                         case PW_DIGEST_NONCE_COUNT:
273                         case PW_DIGEST_USER_NAME:
274                                 /* overlapping! */
275                                 memmove(&vp->vp_octets[2], &vp->vp_octets[0],
276                                         vp->length);
277                                 vp->vp_octets[0] = vp->attribute - PW_DIGEST_REALM + 1;
278                                 vp->length += 2;
279                                 vp->vp_octets[1] = vp->length;
280                                 vp->attribute = PW_DIGEST_ATTRIBUTES;
281                                 break;
282                         }
283                 } /* loop over the VP's we read in */
284
285                 if (!start) {
286                         start = radclient;
287                         prev = start;
288                 } else {
289                         prev->next = radclient;
290                         radclient->prev = prev;
291                         prev = radclient;
292                 }
293         } while (!filedone); /* loop until the file is done. */
294
295         if (fp != stdin) fclose(fp);
296
297         /*
298          *      And we're done.
299          */
300         return start;
301 }
302
303
304 /*
305  *      Sanity check each argument.
306  */
307 static int radclient_sane(radclient_t *radclient)
308 {
309         if (radclient->request->dst_port == 0) {
310                 radclient->request->dst_port = server_port;
311         }
312         if (radclient->request->dst_ipaddr.af == AF_UNSPEC) {
313                 if (server_ipaddr.af == AF_UNSPEC) {
314                         fprintf(stderr, "radclient: No server was given, but request %d in file %s did not contain Packet-Dst-IP-Address\n",
315                                 radclient->packet_number, radclient->filename);
316                         return -1;
317                 }
318                 radclient->request->dst_ipaddr = server_ipaddr;
319         }
320         if (radclient->request->code == 0) {
321                 if (packet_code == -1) {
322                         fprintf(stderr, "radclient: Request was \"auto\", but request %d in file %s did not contain Packet-Type\n",
323                                 radclient->packet_number, radclient->filename);
324                         return -1;
325                 }
326
327                 radclient->request->code = packet_code;
328         }
329         radclient->request->sockfd = -1;
330
331         return 0;
332 }
333
334
335 /*
336  *      For request handline.
337  */
338 static int filename_cmp(const void *one, const void *two)
339 {
340         return strcmp((const char *) one, (const char *) two);
341 }
342
343 static int filename_walk(void *context, void *data)
344 {
345         const char      *filename = data;
346         radclient_t     *radclient;
347
348         context = context;      /* -Wunused */
349
350         /*
351          *      Initialize the request we're about
352          *      to send.
353          */
354         radclient = radclient_init(filename);
355         if (!radclient) {
356                 exit(1);
357         }
358
359         if (!radclient_head) {
360                 assert(radclient_tail == NULL);
361                 radclient_head = radclient;
362         } else {
363                 assert(radclient_tail->next == NULL);
364                 radclient_tail->next = radclient;
365                 radclient->prev = radclient_tail;
366         }
367
368         /*
369          *      We may have had a list of "radclient" structures
370          *      returned to us.
371          */
372         while (radclient->next) radclient = radclient->next;
373         radclient_tail = radclient;
374
375         return 0;
376 }
377
378
379 /*
380  *      Deallocate packet ID, etc.
381  */
382 static void deallocate_id(radclient_t *radclient)
383 {
384         if (!radclient || !radclient->request ||
385             (radclient->request->id < 0)) {
386                 return;
387         }
388
389         /*
390          *      One more unused RADIUS ID.
391          */
392         lrad_packet_list_id_free(pl, radclient->request);
393         radclient->request->id = -1;
394
395         /*
396          *      If we've already sent a packet, free up the old one,
397          *      and ensure that the next packet has a unique
398          *      authentication vector.
399          */
400         if (radclient->request->data) {
401                 free(radclient->request->data);
402                 radclient->request->data = NULL;
403         }
404
405         if (radclient->reply) rad_free(&radclient->reply);
406 }
407
408
409 static void print_hex(RADIUS_PACKET *packet)
410 {
411         int i;
412
413         if (!packet->data) return;
414
415         printf("  Code:\t\t%u\n", packet->data[0]);
416         printf("  Id:\t\t%u\n", packet->data[1]);
417         printf("  Length:\t%u\n", ((packet->data[2] << 8) |
418                                    (packet->data[3])));
419         printf("  Vector:\t");
420         for (i = 4; i < 20; i++) {
421                 printf("%02x", packet->data[i]);
422         }
423         printf("\n");
424         
425         if (packet->data_len > 20) {
426                 int total;
427                 const uint8_t *ptr;
428                 printf("  Data:");
429
430                 total = packet->data_len - 20;
431                 ptr = packet->data + 20;
432
433                 while (total > 0) {
434                         int attrlen;
435
436                         printf("\t\t");
437                         if (total < 2) { /* too short */
438                                 printf("%02x\n", *ptr);
439                                 break;
440                         }
441
442                         if (ptr[1] > total) { /* too long */
443                                 for (i = 0; i < total; i++) {
444                                         printf("%02x ", ptr[i]);
445                                 }
446                                 break;
447                         }
448
449                         printf("%02x  %02x  ", ptr[0], ptr[1]);
450                         attrlen = ptr[1] - 2;
451                         ptr += 2;
452                         total -= 2;
453
454                         for (i = 0; i < attrlen; i++) {
455                                 if ((i > 0) && ((i & 0x0f) == 0x00))
456                                         printf("\t\t\t");
457                                 printf("%02x ", ptr[i]);
458                                 if ((i & 0x0f) == 0x0f) printf("\n");
459                         }
460
461                         if ((attrlen & 0x0f) != 0x00) printf("\n");
462
463                         ptr += attrlen;
464                         total -= attrlen;
465                 }
466         }
467         fflush(stdout);
468 }
469
470 /*
471  *      Send one packet.
472  */
473 static int send_one_packet(radclient_t *radclient)
474 {
475         assert(radclient->done == 0);
476
477         /*
478          *      Remember when we have to wake up, to re-send the
479          *      request, of we didn't receive a response.
480          */
481         if ((sleep_time == -1) ||
482             (sleep_time > (int) timeout)) {
483                 sleep_time = (int) timeout;
484         }
485
486         /*
487          *      Haven't sent the packet yet.  Initialize it.
488          */
489         if (radclient->request->id == -1) {
490                 int i, rcode;
491
492                 assert(radclient->reply == NULL);
493
494                 /*
495                  *      Didn't find a free packet ID, we're not done,
496                  *      we don't sleep, and we stop trying to process
497                  *      this packet.
498                  */
499         retry:
500                 rcode = lrad_packet_list_id_alloc(pl, radclient->request);
501                 if (rcode < 0) {
502                         int mysockfd;
503
504                         mysockfd = lrad_socket(&client_ipaddr, 0);
505                         if (!mysockfd) {
506                                 fprintf(stderr, "radclient: Can't open new socket\n");
507                                 exit(1);
508                         }
509                         if (!lrad_packet_list_socket_add(pl, mysockfd)) {
510                                 fprintf(stderr, "radclient: Can't add new socket\n");
511                                 exit(1);
512                         }
513                         goto retry;
514                 }
515
516                 if (rcode == 0) {
517                         done = 0;
518                         sleep_time = 0;
519                         return 0;
520                 }
521
522                 assert(radclient->request->id != -1);
523                 assert(radclient->request->data == NULL);
524
525                 for (i = 0; i < 4; i++) {
526                         *((uint32_t *) radclient->request->vector) = lrad_rand();
527                 }
528
529                 /*
530                  *      Update the password, so it can be encrypted with the
531                  *      new authentication vector.
532                  */
533                 if (radclient->password[0] != '\0') {
534                         VALUE_PAIR *vp;
535
536                         if ((vp = pairfind(radclient->request->vps, PW_USER_PASSWORD)) != NULL) {
537                                 strlcpy(vp->vp_strvalue, radclient->password,
538                                         sizeof(vp->vp_strvalue));
539                                 vp->length = strlen(vp->vp_strvalue);
540
541                         } else if ((vp = pairfind(radclient->request->vps, PW_CHAP_PASSWORD)) != NULL) {
542                           /*
543                            *    FIXME: AND there's no CHAP-Challenge,
544                            *           AND vp->length != 17
545                            *           AND rad_chap_encode() != vp->vp_octets
546                            */
547                                 strlcpy(vp->vp_strvalue, radclient->password,
548                                         sizeof(vp->vp_strvalue));
549                                 vp->length = strlen(vp->vp_strvalue);
550
551                                 rad_chap_encode(radclient->request,
552                                                 vp->vp_octets,
553                                                 radclient->request->id, vp);
554                                 vp->length = 17;
555                         }
556                 }
557
558                 radclient->timestamp = time(NULL);
559                 radclient->tries = 1;
560                 radclient->resend++;
561
562                 /*
563                  *      Duplicate found.  Serious error!
564                  */
565                 if (!lrad_packet_list_insert(pl, &radclient->request)) {
566                         assert(0 == 1);
567                 }
568                 
569
570         } else {                /* radclient->request->id >= 0 */
571                 time_t now = time(NULL);
572
573                 /*
574                  *      FIXME: Accounting packets are never retried!
575                  *      The Acct-Delay-Time attribute is updated to
576                  *      reflect the delay, and the packet is re-sent
577                  *      from scratch!
578                  */
579
580                 /*
581                  *      Not time for a retry, do so.
582                  */
583                 if ((now - radclient->timestamp) < timeout) {
584                         /*
585                          *      When we walk over the tree sending
586                          *      packets, we update the minimum time
587                          *      required to sleep.
588                          */
589                         if ((sleep_time == -1) ||
590                             (sleep_time > (now - radclient->timestamp))) {
591                                 sleep_time = now - radclient->timestamp;
592                         }
593                         return 0;
594                 }
595
596                 /*
597                  *      We're not trying later, maybe the packet is done.
598                  */
599                 if (radclient->tries == retries) {
600                         assert(radclient->request->id >= 0);
601                         
602                         /*
603                          *      Delete the request from the tree of
604                          *      outstanding requests.
605                          */
606                         lrad_packet_list_yank(pl, radclient->request);
607
608                         fprintf(stderr, "radclient: no response from server for ID %d socket %d\n", radclient->request->id, radclient->request->sockfd);
609                         deallocate_id(radclient);
610                         
611                         /*
612                          *      Normally we mark it "done" when we've received
613                          *      the response, but this is a special case.
614                          */
615                         if (radclient->resend == resend_count) {
616                                 radclient->done = 1;
617                         }
618                         totallost++;
619                         return -1;
620                 }
621
622                 /*
623                  *      We are trying later.
624                  */
625                 radclient->timestamp = now;
626                 radclient->tries++;
627         }
628
629
630         /*
631          *      Send the packet.
632          */
633         if (rad_send(radclient->request, NULL, secret) < 0) {
634                 fprintf(stderr, "radclient: Failed to send packet for ID %d: %s\n",
635                         radclient->request->id, librad_errstr);
636         }
637
638         if (librad_debug > 2) print_hex(radclient->request);
639
640         return 0;
641 }
642
643 /*
644  *      Receive one packet, maybe.
645  */
646 static int recv_one_packet(int wait_time)
647 {
648         fd_set          set;
649         struct timeval  tv;
650         radclient_t     *radclient;
651         RADIUS_PACKET   *reply, **request_p;
652         volatile int max_fd;
653
654         /* And wait for reply, timing out as necessary */
655         FD_ZERO(&set);
656
657         max_fd = lrad_packet_list_fd_set(pl, &set);
658         if (max_fd < 0) exit(1); /* no sockets to listen on! */
659
660         if (wait_time <= 0) {
661                 tv.tv_sec = 0;
662         } else {
663                 tv.tv_sec = wait_time;
664         }
665         tv.tv_usec = 0;
666
667         /*
668          *      No packet was received.
669          */
670         if (select(max_fd, &set, NULL, NULL, &tv) <= 0) {
671                 return 0;
672         }
673
674         /*
675          *      Look for the packet.
676          */
677         reply = lrad_packet_list_recv(pl, &set);
678         if (!reply) {
679                 fprintf(stderr, "radclient: received bad packet: %s\n",
680                         librad_errstr);
681                 return -1;      /* bad packet */
682         }
683
684         if (librad_debug > 2) print_hex(reply);
685
686         request_p = lrad_packet_list_find_byreply(pl, reply);
687         if (!request_p) {
688                 fprintf(stderr, "radclient: received response to request we did not send. (id=%d socket %d)\n", reply->id, reply->sockfd);
689                 rad_free(&reply);
690                 return -1;      /* got reply to packet we didn't send */
691         }
692         radclient = lrad_packet2myptr(radclient_t, request, request_p);
693
694         /*
695          *      Fails the signature validation: not a real reply.
696          *      FIXME: Silently drop it and listen for another packet.
697          */
698         if (rad_verify(reply, radclient->request, secret) < 0) {
699                 librad_perror("rad_verify");
700                 totallost++;
701                 goto packet_done; /* shared secret is incorrect */
702         }
703
704         lrad_packet_list_yank(pl, radclient->request);
705         if (print_filename) printf("%s:%d %d\n",
706                                    radclient->filename,
707                                    radclient->packet_number,
708                                    reply->code);
709         deallocate_id(radclient);
710         radclient->reply = reply;
711
712         /*
713          *      If this fails, we're out of memory.
714          */
715         if (rad_decode(reply, radclient->request, secret) != 0) {
716                 librad_perror("rad_decode");
717                 totallost++;
718                 goto packet_done;
719         }
720
721         /* libradius debug already prints out the value pairs for us */
722         if (!librad_debug && do_output) {
723                 printf("Received response ID %d, code %d, length = %d\n",
724                        reply->id, reply->code, reply->data_len);
725                 vp_printlist(stdout, reply->vps);
726         }
727         if (reply->code != PW_AUTHENTICATION_REJECT) {
728                 totalapp++;
729         } else {
730                 totaldeny++;
731         }
732
733 packet_done:
734         /*
735          *      Once we've sent the packet as many times as requested,
736          *      mark it done.
737          */
738         if ((radclient->done) ||
739             (radclient->resend == resend_count)) {
740                 assert(lrad_packet_list_find(pl, radclient->request) == NULL);
741                 radclient->done = 1;
742         }
743         rad_free(&radclient->reply);
744
745         return 0;
746 }
747
748
749 static int getport(const char *name)
750 {
751         struct  servent         *svp;
752
753         svp = getservbyname (name, "udp");
754         if (!svp) {
755                 return 0;
756         }
757
758         return ntohs(svp->s_port);
759 }
760
761 int main(int argc, char **argv)
762 {
763         char *p;
764         int c;
765         const char *radius_dir = RADDBDIR;
766         char filesecret[256];
767         FILE *fp;
768         int do_summary = 0;
769         int persec = 0;
770         int parallel = 1;
771         radclient_t     *this;
772         int force_af = AF_UNSPEC;
773
774         librad_debug = 0;
775
776         filename_tree = rbtree_create(filename_cmp, NULL, 0);
777         if (!filename_tree) {
778                 fprintf(stderr, "radclient: Out of memory\n");
779                 exit(1);
780         }
781
782         while ((c = getopt(argc, argv, "46c:d:f:Fhi:n:p:qr:sS:t:vx")) != EOF) switch(c) {
783                 case '4':
784                         force_af = AF_INET;
785                         break;
786                 case '6':
787                         force_af = AF_INET6;
788                         break;
789                 case 'c':
790                         if (!isdigit((int) *optarg))
791                                 usage();
792                         resend_count = atoi(optarg);
793                         break;
794                 case 'd':
795                         radius_dir = optarg;
796                         break;
797                 case 'f':
798                         rbtree_insert(filename_tree, optarg);
799                         break;
800                 case 'F':
801                         print_filename = 1;
802                         break;
803                 case 'i':       /* currently broken */
804                         if (!isdigit((int) *optarg))
805                                 usage();
806                         last_used_id = atoi(optarg);
807                         if ((last_used_id < 0) || (last_used_id > 255)) {
808                                 usage();
809                         }
810                         break;
811
812                 case 'n':
813                         persec = atoi(optarg);
814                         if (persec <= 0) usage();
815                         break;
816
817                         /*
818                          *      Note that sending MANY requests in
819                          *      parallel can over-run the kernel
820                          *      queues, and Linux will happily discard
821                          *      packets.  So even if the server responds,
822                          *      the client may not see the response.
823                          */
824                 case 'p':
825                         parallel = atoi(optarg);
826                         if (parallel <= 0) usage();
827                         break;
828
829                 case 'q':
830                         do_output = 0;
831                         break;
832                 case 'r':
833                         if (!isdigit((int) *optarg))
834                                 usage();
835                         retries = atoi(optarg);
836                         if ((retries == 0) || (retries > 1000)) usage();
837                         break;
838                 case 's':
839                         do_summary = 1;
840                         break;
841                case 'S':
842                        fp = fopen(optarg, "r");
843                        if (!fp) {
844                                fprintf(stderr, "radclient: Error opening %s: %s\n",
845                                        optarg, strerror(errno));
846                                exit(1);
847                        }
848                        if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
849                                fprintf(stderr, "radclient: Error reading %s: %s\n",
850                                        optarg, strerror(errno));
851                                exit(1);
852                        }
853                        fclose(fp);
854
855                        /* truncate newline */
856                        p = filesecret + strlen(filesecret) - 1;
857                        while ((p >= filesecret) &&
858                               (*p < ' ')) {
859                                *p = '\0';
860                                --p;
861                        }
862
863                        if (strlen(filesecret) < 2) {
864                                fprintf(stderr, "radclient: Secret in %s is too short\n", optarg);
865                                exit(1);
866                        }
867                        secret = filesecret;
868                        break;
869                 case 't':
870                         if (!isdigit((int) *optarg))
871                                 usage();
872                         timeout = atof(optarg);
873                         break;
874                 case 'v':
875                         printf("radclient: $Id$ built on " __DATE__ " at " __TIME__ "\n");
876                         exit(0);
877                         break;
878                 case 'x':
879                         librad_debug++;
880                         break;
881                 case 'h':
882                 default:
883                         usage();
884                         break;
885         }
886         argc -= (optind - 1);
887         argv += (optind - 1);
888
889         if ((argc < 3)  ||
890             ((secret == NULL) && (argc < 4))) {
891                 usage();
892         }
893
894         if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
895                 librad_perror("radclient");
896                 return 1;
897         }
898
899         /*
900          *      Resolve hostname.
901          */
902         server_ipaddr.af = force_af;
903         if (strcmp(argv[1], "-") != 0) {
904                 const char *hostname = argv[1];
905                 const char *portname = argv[1];
906                 char buffer[256];
907
908                 if (*argv[1] == '[') { /* IPv6 URL encoded */
909                         p = strchr(argv[1], ']');
910                         if ((p - argv[1]) >= sizeof(buffer)) {
911                                 usage();
912                         }
913                         
914                         memcpy(buffer, argv[1] + 1, p - argv[1] - 1);
915                         buffer[p - argv[1] - 1] = '\0';
916
917                         hostname = buffer;
918                         portname = p + 1;
919
920                 }
921                 p = strchr(portname, ':');
922                 if (p && (strchr(p + 1, ':') == NULL)) {
923                         *p = '\0';
924                         portname = p + 1;
925                 } else {
926                         portname = NULL;
927                 }
928
929                 if (ip_hton(hostname, force_af, &server_ipaddr) < 0) {
930                         fprintf(stderr, "radclient: Failed to find IP address for host %s: %s\n", hostname, strerror(errno));
931                         exit(1);
932                 }
933
934                 /*
935                  *      Strip port from hostname if needed.
936                  */
937                 if (portname) server_port = atoi(portname);
938         }
939
940         /*
941          *      See what kind of request we want to send.
942          */
943         if (strcmp(argv[2], "auth") == 0) {
944                 if (server_port == 0) server_port = getport("radius");
945                 if (server_port == 0) server_port = PW_AUTH_UDP_PORT;
946                 packet_code = PW_AUTHENTICATION_REQUEST;
947
948         } else if (strcmp(argv[2], "challenge") == 0) {
949                 if (server_port == 0) server_port = getport("radius");
950                 if (server_port == 0) server_port = PW_AUTH_UDP_PORT;
951                 packet_code = PW_ACCESS_CHALLENGE;
952
953         } else if (strcmp(argv[2], "acct") == 0) {
954                 if (server_port == 0) server_port = getport("radacct");
955                 if (server_port == 0) server_port = PW_ACCT_UDP_PORT;
956                 packet_code = PW_ACCOUNTING_REQUEST;
957                 do_summary = 0;
958
959         } else if (strcmp(argv[2], "status") == 0) {
960                 if (server_port == 0) server_port = getport("radius");
961                 if (server_port == 0) server_port = PW_AUTH_UDP_PORT;
962                 packet_code = PW_STATUS_SERVER;
963
964         } else if (strcmp(argv[2], "disconnect") == 0) {
965                 if (server_port == 0) server_port = PW_POD_UDP_PORT;
966                 packet_code = PW_DISCONNECT_REQUEST;
967
968         } else if (strcmp(argv[2], "coa") == 0) {
969                 if (server_port == 0) server_port = PW_POD_UDP_PORT;
970                 packet_code = PW_COA_REQUEST;
971
972         } else if (strcmp(argv[2], "auto") == 0) {
973                 packet_code = -1;
974
975         } else if (isdigit((int) argv[2][0])) {
976                 if (server_port == 0) server_port = getport("radius");
977                 if (server_port == 0) server_port = PW_AUTH_UDP_PORT;
978                 packet_code = atoi(argv[2]);
979         } else {
980                 usage();
981         }
982
983         /*
984          *      Add the secret.
985          */
986         if (argv[3]) secret = argv[3];
987
988         /*
989          *      If no '-f' is specified, we're reading from stdin.
990          */
991         if (rbtree_num_elements(filename_tree) == 0) {
992                 rbtree_insert(filename_tree, "-");
993         }
994
995         /*
996          *      Walk over the list of filenames, creating the requests.
997          */
998         if (rbtree_walk(filename_tree, InOrder, filename_walk, NULL) != 0) {
999                 exit(1);
1000         }
1001
1002         /*
1003          *      No packets read.  Die.
1004          */
1005         if (!radclient_head) {
1006                 fprintf(stderr, "radclient: Nothing to send.\n");
1007                 exit(1);
1008         }
1009
1010         /*
1011          *      Bind to the first specified IP address and port.
1012          *      This means we ignore later ones.
1013          */
1014         if (radclient_head->request->src_ipaddr.af == AF_UNSPEC) {
1015                 memset(&client_ipaddr, 0, sizeof(client_ipaddr));
1016                 client_ipaddr.af = server_ipaddr.af;
1017                 client_port = 0;
1018         } else {
1019                 client_ipaddr = radclient_head->request->src_ipaddr;
1020                 client_port = radclient_head->request->src_port;
1021         }
1022         sockfd = lrad_socket(&client_ipaddr, client_port);
1023         if (sockfd < 0) {
1024                 fprintf(stderr, "radclient: socket: %s\n", librad_errstr);
1025                 exit(1);
1026         }
1027
1028         pl = lrad_packet_list_create(1);
1029         if (!pl) {
1030                 fprintf(stderr, "radclient: Out of memory\n");
1031                 exit(1);
1032         }
1033
1034         if (!lrad_packet_list_socket_add(pl, sockfd)) {
1035                 fprintf(stderr, "radclient: Out of memory\n");
1036                 exit(1);
1037         }
1038
1039         /*
1040          *      Walk over the list of packets, sanity checking
1041          *      everything.
1042          */
1043         for (this = radclient_head; this != NULL; this = this->next) {
1044                 this->request->src_ipaddr = client_ipaddr;
1045                 this->request->src_port = client_port;
1046                 if (radclient_sane(this) != 0) {
1047                         exit(1);
1048                 }
1049         }
1050
1051         /*
1052          *      Walk over the packets to send, until
1053          *      we're all done.
1054          *
1055          *      FIXME: This currently busy-loops until it receives
1056          *      all of the packets.  It should really have some sort of
1057          *      send packet, get time to wait, select for time, etc.
1058          *      loop.
1059          */
1060         do {
1061                 int n = parallel;
1062                 radclient_t *next;
1063                 const char *filename = NULL;
1064
1065                 done = 1;
1066                 sleep_time = -1;
1067
1068                 /*
1069                  *      Walk over the packets, sending them.
1070                  */
1071
1072                 for (this = radclient_head; this != NULL; this = next) {
1073                         next = this->next;
1074
1075                         /*
1076                          *      If there's a packet to receive,
1077                          *      receive it, but don't wait for a
1078                          *      packet.
1079                          */
1080                         recv_one_packet(0);
1081
1082                         /*
1083                          *      This packet is done.  Delete it.
1084                          */
1085                         if (this->done) {
1086                                 radclient_free(this);
1087                                 continue;
1088                         }
1089
1090                         /*
1091                          *      Packets from multiple '-f' are sent
1092                          *      in parallel.
1093                          *
1094                          *      Packets from one file are sent in
1095                          *      series, unless '-p' is specified, in
1096                          *      which case N packets from each file
1097                          *      are sent in parallel.
1098                          */
1099                         if (this->filename != filename) {
1100                                 filename = this->filename;
1101                                 n = parallel;
1102                         }
1103
1104                         if (n > 0) {
1105                                 n--;
1106
1107                                 /*
1108                                  *      Send the current packet.
1109                                  */
1110                                 send_one_packet(this);
1111
1112                                 /*
1113                                  *      Wait a little before sending
1114                                  *      the next packet, if told to.
1115                                  */
1116                                 if (persec) {
1117                                         struct timeval tv;
1118
1119                                         /*
1120                                          *      Don't sleep elsewhere.
1121                                          */
1122                                         sleep_time = 0;
1123
1124                                         if (persec == 1) {
1125                                                 tv.tv_sec = 1;
1126                                                 tv.tv_usec = 0;
1127                                         } else {
1128                                                 tv.tv_sec = 0;
1129                                                 tv.tv_usec = 1000000/persec;
1130                                         }
1131                                         
1132                                         /*
1133                                          *      Sleep for milliseconds,
1134                                          *      portably.
1135                                          *
1136                                          *      If we get an error or
1137                                          *      a signal, treat it like
1138                                          *      a normal timeout.
1139                                          */
1140                                         select(0, NULL, NULL, NULL, &tv);
1141                                 }
1142
1143                                 /*
1144                                  *      If we haven't sent this packet
1145                                  *      often enough, we're not done,
1146                                  *      and we shouldn't sleep.
1147                                  */
1148                                 if (this->resend < resend_count) {
1149                                         done = 0;
1150                                         sleep_time = 0;
1151                                 }
1152                         } else { /* haven't sent this packet, we're not done */
1153                                 assert(this->done == 0);
1154                                 assert(this->reply == NULL);
1155                                 done = 0;
1156                         }
1157                 }
1158
1159                 /*
1160                  *      Still have outstanding requests.
1161                  */
1162                 if (lrad_packet_list_num_elements(pl) > 0) {
1163                         done = 0;
1164                 } else {
1165                         sleep_time = 0;
1166                 }
1167
1168                 /*
1169                  *      Nothing to do until we receive a request, so
1170                  *      sleep until then.  Once we receive one packet,
1171                  *      we go back, and walk through the whole list again,
1172                  *      sending more packets (if necessary), and updating
1173                  *      the sleep time.
1174                  */
1175                 if (!done && (sleep_time > 0)) {
1176                         recv_one_packet(sleep_time);
1177                 }
1178         } while (!done);
1179
1180         rbtree_free(filename_tree);
1181         lrad_packet_list_free(pl);
1182         dict_free();
1183
1184         if (do_summary) {
1185                 printf("\n\t   Total approved auths:  %d\n", totalapp);
1186                 printf("\t     Total denied auths:  %d\n", totaldeny);
1187                 printf("\t       Total lost auths:  %d\n", totallost);
1188         }
1189
1190         return 0;
1191 }