All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
radeapclient.c
Go to the documentation of this file.
1 /*
2  * radeapclient.c EAP specific radius packet debug tool.
3  *
4  * Version: $Id: 93369c86fc1f08a85b1ad0d6cbb83e6b1bd04346 $
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 RCSID("$Id: 93369c86fc1f08a85b1ad0d6cbb83e6b1bd04346 $")
26 
27 #include <freeradius-devel/libradius.h>
28 
29 #include <ctype.h>
30 #include <assert.h>
31 
32 #if HAVE_GETOPT_H
33 # include <getopt.h>
34 #endif
35 
36 #include <freeradius-devel/conf.h>
37 #include <freeradius-devel/md5.h>
38 
39 #include "eap_types.h"
40 #include "eap_sim.h"
41 
42 #ifdef WITH_TLS
43 # include <freeradius-devel/tls.h>
44 #endif
45 
46 extern int sha1_data_problems;
47 
48 #define USEC 1000000
49 
50 
51 /*
52  * Global variables.
53  */
54 static char const *progname = "radeapclient";
56 
57 char const *radiusd_version = "FreeRADIUS Version " RADIUSD_VERSION_STRING
58 #ifdef RADIUSD_VERSION_COMMIT
59 " (git #" STRINGIFY(RADIUSD_VERSION_COMMIT) ")"
60 #endif
61 ", built on " __DATE__ " at " __TIME__;
62 
63 
64 static uint32_t parallel = 1;
65 static uint32_t rate_limit = 0;
66 static unsigned int retries = 3;
67 static float timeout = 5;
68 static struct timeval tv_timeout;
69 static unsigned int recycle_count = 1;
70 static char const *secret = NULL;
71 static bool do_output = true;
72 static bool do_summary = false;
73 static char filesecret[256];
74 static float progress_interval = 0;
75 static struct timeval tv_progress_interval;
76 static char const *radius_dir = NULL;
77 
78 //TODO: move structures to a header file.
79 
83 
84 /** Structure which contains EAP context, necessary to perform the full EAP transaction.
85  */
86 typedef struct rc_eap_sim_context {
87  struct eapsim_keys keys;
89 
90 typedef struct rc_eap_md5_context {
91  int tried;
93 
94 typedef struct rc_eap_context {
95  int eap_type; //!< contains the EAP-Type
96  char password[256]; //!< copy of User-Password (or CHAP-Password).
97  union {
100  } eap;
102 
103 
104 /** Structure which holds a list of available input vps.
105  */
109  uint32_t size;
110 };
111 
112 /** Structure which holds an input vps entry (read from file or stdin),
113  * and linkage to previous / next entries.
114  */
115 struct rc_input_vps {
116  uint32_t num; //!< The number (within the file) of the input we're reading.
117 
118  VALUE_PAIR *vps_in; //!< the list of attribute/value pairs.
119 
120  rc_input_vps_list_t *list; //!< the list to which this entry belongs (NULL for an unchained entry).
121 
122  uint32_t recycle; //!< number of times this input has been used to start a transaction.
123 
126 };
127 
128 
129 /** Structure which holds a transaction: sent packet, reply received...
130  */
132  uint32_t id; //!< id of transaction (0 for the first one).
133 
134  uint32_t num_packet; //!< number of packets sent for this transaction.
135 
136  struct timeval timestamp; //!< when the transaction is started.
139 
141 
143 
144  uint32_t tries;
145 
146  fr_event_t *event; //!< armed event (if any).
147 
148  char password[256];
149  char const *name; //!< Test name (as specified in the request).
150 };
151 
152 
153 /** Define workflow types (transactions for which we got a response)
154  */
155 typedef enum {
162 } rc_wf_type_t;
163 
164 #define LG_PAD_STATS 20
165 #define LG_PAD_WF_TYPES 25
166 
167 static char const *rc_wf_types[RC_WF_MAX] = {
168  "(All)",
169  "Access-Request - Accept",
170  "CoA-Request - Ack",
171  "EAP Request - Success",
172  "Accounting-Request - Response"
173 };
174 
175 /** Structure which holds per-workflow statistics information
176  */
177 typedef struct rc_wf_stats {
178  uint32_t num;
179  struct timeval tv_rtt_cumul;
180  struct timeval tv_rtt_min;
181  struct timeval tv_rtt_max;
182 } rc_wf_stats_t;
183 
184 /** Structure which holds global statistics information
185  */
186 typedef struct rc_stats {
187  uint32_t nb_started; //!< number of transactions started
188  uint32_t nb_eap; //!< number of EAP transactions started
189  uint32_t nb_success; //!< number of successful transactions
190  uint32_t nb_fail; //!< number of failed transactions
191  uint32_t nb_lost; //!< number of packets to which we received no response
192  uint32_t nb_packets_sent; //!< number of packets sent (including retransmissions)
193  uint32_t nb_packets_retries; //!< number of packets retransmissions
194  uint32_t nb_packets_recv; //!< number of packets received
195 
197 
198 } rc_stats_t;
199 
200 #define STATS_INC(_stat_type) { \
201  stats._stat_type ++; \
202 }
203 
204 
205 static TALLOC_CTX *autofree;
207 static struct timeval tv_start;
208 static struct timeval tv_end;
209 static uint32_t num_input = 0; //!< number of input entries loaded.
210 static uint32_t num_trans = 0; //!< number of transactions initialized.
211 static uint32_t num_started = 0; //!< number of transactions started.
212 static uint32_t num_ongoing = 0; //!< number of ongoing transactions.
213 static uint32_t num_finished = 0; //!< number of finished transactions.
214 
215 static rc_input_vps_list_t rc_vps_list_in; //!< list of available input vps entries.
216 static fr_packet_list_t *pl = NULL; //!< list of outgoing packets.
217 static unsigned int num_sockets = 0; //!< number of allocated sockets.
218 static fr_event_list_t *ev_list = NULL; //!< list of armed events.
219 static char ch_elapsed[12+1];
220 #define ELAPSED rc_print_elapsed(ch_elapsed, 3)
221 
222 static int force_af = AF_UNSPEC;
223 static int ipproto = IPPROTO_UDP;
225 static bool server_addr_init = false;
226 static uint16_t server_port = 0;
228 
229 
230 static int rc_map_eap_methods(RADIUS_PACKET *req);
231 static void rc_unmap_eap_methods(RADIUS_PACKET *rep);
232 static int rc_map_eapsim_types(RADIUS_PACKET *r);
234 
235 static void rc_get_radius_port(PW_CODE type, uint16_t *port);
237 static void rc_evprep_progress_stat(void);
240 static void rc_do_progress_stat(void);
241 static uint32_t rc_get_elapsed(void);
242 static float rc_get_wf_rate(rc_wf_type_t i);
243 
244 
245 
246 /** Display usage and exit.
247  */
248 static void NEVER_RETURNS usage(void)
249 {
250  fprintf(stdout, "Usage: radeapclient [options] server[:port] <command> [<secret>]\n");
251 
252  fprintf(stdout, " <command> One of auth, acct, status, coa, disconnect or auto.\n");
253  fprintf(stdout, " -4 Use IPv4 address of server\n");
254  fprintf(stdout, " -6 Use IPv6 address of server.\n");
255  fprintf(stdout, " -c <count> Send each packet 'count' times.\n");
256  fprintf(stdout, " -d <raddb> Set user dictionary directory (defaults to " RADDBDIR ").\n");
257  fprintf(stdout, " -D <dictdir> Set main dictionary directory (defaults to " DICTDIR ").\n");
258  fprintf(stdout, " -f <file> Read packets from file, not stdin.\n");
259  fprintf(stdout, " -h Print usage help information.\n");
260  fprintf(stdout, " -n <num> Rate limit. Send at most N requests/s.\n");
261  fprintf(stdout, " -o <time> Output progress statistics each 'time' seconds.\n");
262  fprintf(stdout, " -p <num> Send 'num' packets in parallel.\n");
263  fprintf(stdout, " -q Do not print anything out.\n");
264  fprintf(stdout, " -r <retries> If timeout, retry sending the packet 'retries' times.\n");
265  fprintf(stdout, " -s Print out summary statistics information.\n");
266  fprintf(stdout, " -S <file> read secret from file, not command line.\n");
267  fprintf(stdout, " -t <timeout> Wait 'timeout' seconds before retrying (may be a floating point number).\n");
268  fprintf(stdout, " -v Show program version information.\n");
269  fprintf(stdout, " -x Debugging mode.\n");
270 
271  exit(1);
272 }
273 
274 /* This is not called, but is required by libfreeradius-eap.so */
276 {
277  /* We're not the server so we cannot do this */
278  abort();
279 }
280 
282 {
283  /*We're not the server so we cannot do this*/
284  abort();
285 }
286 
287 /** Set the global radius config directory.
288  *
289  * (copied from main/mainconfig.c)
290  */
291 void set_radius_dir(TALLOC_CTX *ctx, char const *path)
292 {
293  if (radius_dir) {
294  char *p;
295 
296  memcpy(&p, &radius_dir, sizeof(p));
297  talloc_free(p);
298  radius_dir = NULL;
299  }
300  if (path) radius_dir = talloc_strdup(ctx, path);
301 }
302 
303 
304 /** Print a elapsed time buffer (SS.uuuuuu).
305  */
306 static char *rc_print_elapsed(char *out, uint8_t decimals)
307 {
308  if (!out || !timerisset(&tv_start)) return NULL;
309 
310  if (decimals > 6) decimals = 6;
311 
312  struct timeval tv_now;
313  struct timeval tv_delta;
314 
315  gettimeofday(&tv_now, NULL);
316  timersub(&tv_now, &tv_start, &tv_delta);
317 
318  uint32_t u_sec = (uint32_t)(tv_delta.tv_sec);
319  sprintf(out, "%d", u_sec);
320 
321  /* assuming tv_usec < USEC */
322  if (decimals) {
323  char buffer[8] = "";
324  sprintf(buffer, ".%06d", (int) tv_delta.tv_usec);
325  strncat(out, buffer, decimals+1); /* (this is always terminated with 0). */
326  }
327 
328  return out;
329 }
330 
331 /** Print a "hexstring" buffer (with optional separator each N octets)
332  */
333 static char *rc_print_hexstr(char *pch_out, const uint8_t *in, int size, int separ_i, char sep)
334 {
335  int i, j = 0;
336 
337  for (i = 0; i < size; i++) {
338  if ((separ_i) && (j == separ_i)) {
339  *pch_out = sep;
340  pch_out += 1;
341  j = 0;
342  }
343  j++;
344  sprintf(pch_out, "%02x", in[i]);
345  pch_out += 2;
346  }
347  *pch_out = '\0';
348  return pch_out;
349 }
350 
351 /** Convert a float to struct timeval.
352  */
353 static void rc_float_to_timeval(struct timeval *tv, float f_val)
354 {
355  tv->tv_sec = (time_t)f_val;
356  uint64_t usec = (uint64_t)(f_val * USEC) - (tv->tv_sec * USEC);
357  tv->tv_usec = usec;
358 }
359 
360 /** Convert a struct timeval to float
361  */
362 static float rc_timeval_to_float(struct timeval *tv)
363 {
364  return ((float)tv->tv_sec + ((float)tv->tv_usec / USEC));
365 }
366 
367 /** Add an allocated rc_input_vps_t entry to the tail of the list.
368  */
370 {
371  if (!list || !entry) return;
372 
373  if (!list->head) {
374  assert(list->tail == NULL);
375  list->head = entry;
376  entry->prev = NULL;
377  } else {
378  assert(list->tail != NULL);
379  assert(list->tail->next == NULL);
380  list->tail->next = entry;
381  entry->prev = list->tail;
382  }
383  list->tail = entry;
384  entry->next = NULL;
385  entry->list = list;
386  list->size ++;
387 }
388 
389 /** Remove a selected rc_input_vps_t entry from its current list.
390  */
392 {
393  if (!entry) return NULL;
394 
395  if (!entry->list) return entry; /* not in a list, nothing to do. Just return the entry. */
396 
397  rc_input_vps_t *prev, *next;
398 
399  prev = entry->prev;
400  next = entry->next;
401 
402  rc_input_vps_list_t *list = entry->list;
403 
404  assert(list->head != NULL); /* entry belongs to a list, so the list can't be empty. */
405  assert(list->tail != NULL); /* same. */
406 
407  if (prev) {
408  assert(list->head != entry); /* if entry has a prev, then entry can't be head. */
409  prev->next = next;
410  }
411  else {
412  assert(list->head == entry); /* if entry has no prev, then entry must be head. */
413  list->head = next;
414  }
415 
416  if (next) {
417  assert(list->tail != entry); /* if entry has a next, then entry can't be tail. */
418  next->prev = prev;
419  }
420  else {
421  assert(list->tail == entry); /* if entry has no next, then entry must be tail. */
422  list->tail = prev;
423  }
424 
425  entry->list = NULL;
426  entry->prev = NULL;
427  entry->next = NULL;
428  list->size --;
429  return entry;
430 }
431 
432 /** Load input entries (list of vps) from a file or stdin, and add them to the list.
433  * They will be used to initiate transactions.
434  */
435 static int rc_load_input(TALLOC_CTX *ctx, char const *filename, rc_input_vps_list_t *list, uint32_t max_entries)
436 {
437  FILE *file_in = NULL;
438  bool file_done = false;
439  rc_input_vps_t *request;
440  char const *input;
441  uint32_t input_num = 0;
442 
443  /* Determine where to read the VP's from. */
444  if (filename && strcmp(filename, "-") != 0) {
445  DEBUG2("Opening input file: %s", filename);
446  file_in = fopen(filename, "r");
447  if (!file_in) {
448  ERROR("Error opening %s: %s", filename, strerror(errno));
449  return 0;
450  }
451  input = filename;
452  } else {
453  DEBUG2("Reading input vps from stdin");
454  file_in = stdin;
455  input = "stdin";
456  }
457 
458  /* Loop over the file (or stdin). */
459  do {
460  input_num ++;
461  MEM(request = talloc_zero(ctx, rc_input_vps_t));
462 
463  if (fr_pair_list_afrom_file(request, &request->vps_in, file_in, &file_done) < 0) {
464  ERROR("Error parsing entry %u from input: %s", input_num, input);
465  talloc_free(request);
466  break;
467  }
468  if (NULL == request->vps_in) {
469  /* Last line might be empty, in this case fr_pair_list_afrom_file will return a NULL vps pointer. Silently ignore this. */
470  talloc_free(request);
471  break;
472  }
473 
474  /* Add that to the list */
475  rc_add_vps_entry(list, request);
476 
477  request->num = list->size;
478 
479  if (max_entries && list->size >= max_entries) {
480  /* Only load what we need. */
481  break;
482  }
483  } while (!file_done);
484 
485  if (file_in != stdin) fclose(file_in);
486 
487  /* And we're done. */
488  num_input += list->size;
489  DEBUG("Read %d element(s) from input: %s", list->size, input);
490  return 1;
491 }
492 
493 /** Perform packet initialization for a transaction.
494  */
496 {
497  if (!trans || !trans->packet) return 0;
498 
499  RADIUS_PACKET *packet = trans->packet;
500  vp_cursor_t cursor;
501  VALUE_PAIR *vp;
502 
503  /*
504  * Process special attributes
505  */
506  for (vp = fr_cursor_init(&cursor, &packet->vps);
507  vp;
508  vp = fr_cursor_next(&cursor)) {
509  /*
510  * Double quoted strings get marked up as xlat expansions,
511  * but we don't support that in request.
512  */
513  if (vp->type == VT_XLAT) {
514  vp->type = VT_DATA;
515  vp->vp_strvalue = vp->xlat;
516  vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
517  }
518 
519  if (!vp->da->vendor) switch (vp->da->attr) {
520  default:
521  break;
522 
523  /*
524  * Allow it to set the packet type in
525  * the attributes read from the file.
526  */
527  case PW_PACKET_TYPE:
528  packet->code = vp->vp_integer;
529  break;
530 
531  case PW_PACKET_DST_PORT:
532  packet->dst_port = (vp->vp_integer & 0xffff);
533  break;
534 
535  case PW_PACKET_DST_IP_ADDRESS:
536  packet->dst_ipaddr.af = AF_INET;
537  packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
538  packet->dst_ipaddr.prefix = 32;
539  break;
540 
541  case PW_PACKET_DST_IPV6_ADDRESS:
542  packet->dst_ipaddr.af = AF_INET6;
543  packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
544  packet->dst_ipaddr.prefix = 128;
545  break;
546 
547  case PW_PACKET_SRC_PORT:
548  if ((vp->vp_integer < 1024) ||
549  (vp->vp_integer > 65535)) {
550  DEBUG("Invalid value '%u' for Packet-Src-Port", vp->vp_integer);
551  } else {
552  packet->src_port = (vp->vp_integer & 0xffff);
553  }
554  break;
555 
556  case PW_PACKET_SRC_IP_ADDRESS:
557  packet->src_ipaddr.af = AF_INET;
558  packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
559  packet->src_ipaddr.prefix = 32;
560  break;
561 
562  case PW_PACKET_SRC_IPV6_ADDRESS:
563  packet->src_ipaddr.af = AF_INET6;
564  packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
565  packet->src_ipaddr.prefix = 128;
566  break;
567 
568  case PW_DIGEST_REALM:
569  case PW_DIGEST_NONCE:
570  case PW_DIGEST_METHOD:
571  case PW_DIGEST_URI:
572  case PW_DIGEST_QOP:
573  case PW_DIGEST_ALGORITHM:
574  case PW_DIGEST_BODY_DIGEST:
575  case PW_DIGEST_CNONCE:
576  case PW_DIGEST_NONCE_COUNT:
577  case PW_DIGEST_USER_NAME:
578  /* overlapping! */
579  {
580  fr_dict_attr_t const *da;
581  uint8_t *p, *q;
582 
583  p = talloc_array(vp, uint8_t, vp->vp_length + 2);
584 
585  memcpy(p + 2, vp->vp_octets, vp->vp_length);
586  p[0] = vp->da->attr - PW_DIGEST_REALM + 1;
587  vp->vp_length += 2;
588  p[1] = vp->vp_length;
589 
591  if (!da) {
592  ERROR("Attribute 'Digest-Attributes' not found by value");
593  exit(1);
594  }
595  vp->da = da;
596 
597  /*
598  * Re-do fr_pair_value_memsteal ourselves,
599  * because we play games with
600  * vp->da, and fr_pair_value_memsteal goes
601  * to GREAT lengths to sanitize
602  * and fix and change and
603  * double-check the various
604  * fields.
605  */
606  memcpy(&q, &vp->vp_octets, sizeof(q));
607  talloc_free(q);
608 
609  vp->vp_octets = talloc_steal(vp, p);
610  vp->type = VT_DATA;
611 
612  VERIFY_VP(vp);
613  }
614  break;
615 
616  /*
617  * Keep a copy of the the password attribute.
618  */
619  case PW_USER_PASSWORD:
620  case PW_CHAP_PASSWORD:
621  case PW_MS_CHAP_PASSWORD:
622  strlcpy(trans->password, vp->vp_strvalue, sizeof(trans->password));
623  break;
624 
625  case PW_RADCLIENT_TEST_NAME:
626  trans->name = vp->vp_strvalue;
627  break;
628  }
629  } /* loop over the VP's we read in */
630 
631  if (packet->dst_port == 0) packet->dst_port = server_port;
632 
633  if (packet->dst_ipaddr.af == AF_UNSPEC) {
634  if (!server_addr_init) {
635  DEBUG("No server was given, and input entry %u did not contain Packet-Dst-IP-Address, ignored.", trans->input_vps->num);
636  return 0;
637  }
638  packet->dst_ipaddr = server_ipaddr;
639  }
640 
641  /* Use the default set on the command line. */
642  if (packet->code == PW_CODE_UNDEFINED) {
643  if (packet_code == PW_CODE_UNDEFINED) {
644  DEBUG("No packet type was given, and input entry %u did not contain Packet-Type, ignored.", trans->input_vps->num);
645  return 0;
646  }
647  packet->code = packet_code;
648  }
649 
650  /* Automatically set the dst port (if one wasn't already set). */
651  if (packet->dst_port == 0) {
652  rc_get_radius_port(packet->code, &packet->dst_port);
653  if (packet->dst_port == 0) {
654  DEBUG("Can't determine destination port for input entry %u, ignored.", trans->input_vps->num);
655  return 0;
656  }
657  }
658 
659  packet->sockfd = -1;
660 
661  /* Done. */
662  return 1;
663 }
664 
665 /** Map EAP methods and build EAP-Message (if EAP is involved).
666  * Also allocate the EAP context.
667  */
669 {
670  if (!trans || !trans->packet) return;
671 
672  RADIUS_PACKET *packet = trans->packet;
673 
674  /* Build EAP-Message (if EAP is involved. Otherwise, do nothing). */
675  int eap_type = rc_map_eap_methods(packet);
676 
677  if (eap_type) {
678  if (!trans->eap_context) {
679  MEM(trans->eap_context = talloc_zero(trans, rc_eap_context_t));
680  STATS_INC(nb_eap);
681  }
682  trans->eap_context->eap_type = eap_type;
683 
684  /*
685  * Keep a copy of the the User-Password or CHAP-Password.
686  * Note: this is not useful for EAP-SIM, but we cannot know what kind
687  * of challenge the server will issue.
688  */
689  VALUE_PAIR *vp;
690  vp = fr_pair_find_by_num(packet->vps, 0, PW_CLEARTEXT_PASSWORD, TAG_ANY);
691  if (!vp) vp = fr_pair_find_by_num(packet->vps, 0, PW_USER_PASSWORD, TAG_ANY);
692  if (!vp) vp = fr_pair_find_by_num(packet->vps, 0, PW_CHAP_PASSWORD, TAG_ANY);
693  if (vp) {
694  strlcpy(trans->eap_context->password, vp->vp_strvalue, sizeof(trans->eap_context->password));
695  }
696  }
697 }
698 
699 /** Grab an element from the input list. Initialize a new transaction context, using this element.
700  */
701 static rc_transaction_t *rc_init_transaction(TALLOC_CTX *ctx)
702 {
703  if (!rc_vps_list_in.head || rc_vps_list_in.size == 0) {
704  /* Empty list, can't create a new transaction. */
705  return NULL;
706  }
707 
708  rc_input_vps_t *vps_entry = rc_vps_list_in.head;
709 
710  rc_yank_vps_entry(vps_entry); /* This cannot fail (we checked the list beforehand.) */
711 
712  /* We grabbed an vps entry, now we can initialize a new transaction. */
714  MEM(trans = talloc_zero(ctx, rc_transaction_t));
715 
716  trans->input_vps = vps_entry;
717  trans->id = num_trans ++;
718 
719  talloc_steal(trans, vps_entry); /* It's ours now. */
720 
721  RADIUS_PACKET *packet;
722  MEM(packet = fr_radius_alloc(trans, 1));
723  trans->packet = packet;
724 
725  /* Fill in the packet value pairs. */
726  packet->vps = fr_pair_list_copy(packet, vps_entry->vps_in);
727 
728  /* Initialize the transaction packet. */
729  if (!rc_init_packet(trans)) {
730  /* Failed... */
731  talloc_free(trans);
732  return NULL;
733  }
734 
735  vps_entry->recycle ++;
736 
737  gettimeofday(&trans->timestamp, NULL);
738 
739  /* Update transactions counters. */
740  num_started ++;
741  num_ongoing ++;
742 
743  STATS_INC(nb_started);
744 
745  return trans;
746 }
747 
748 /** Terminate a transaction.
749  */
751 {
752  if (!trans) return;
753 
754  if (trans->event) fr_event_delete(ev_list, &trans->event);
755  rc_deallocate_id(trans);
756 
757  rc_input_vps_t *vps_entry = trans->input_vps;
758  if (vps_entry->recycle < recycle_count) {
759  /* Not done yet with this input. Put it back into the list of available entries. */
760  talloc_steal(autofree, vps_entry);
761  rc_add_vps_entry(&rc_vps_list_in, vps_entry);
762  trans->input_vps = NULL;
763  }
764 
765  talloc_free(trans);
766 
767  /* Update transactions counters. */
768  num_ongoing --;
769  num_finished ++;
770 
771  DEBUG4("pl: %d, ev: %d, in: %d", fr_packet_list_num_outgoing(pl), fr_event_list_num_elements(ev_list), rc_vps_list_in.size);
772 }
773 
774 
775 static void rc_cleanresp(RADIUS_PACKET *resp)
776 {
777  VALUE_PAIR *vp;
778  vp_cursor_t cursor;
779 
780  /*
781  * maybe should just copy things we care about, or keep
782  * a copy of the original input and start from there again?
783  */
784  fr_pair_delete_by_num(&resp->vps, 0, PW_EAP_MESSAGE, TAG_ANY);
785  fr_pair_delete_by_num(&resp->vps, 0, PW_EAP_TYPE_BASE + PW_EAP_IDENTITY, TAG_ANY);
786 
787  for (vp = fr_cursor_init(&cursor, &resp->vps);
788  vp;
789  vp = fr_cursor_next(&cursor)) {
790  if ((vp->da->attr >= PW_EAP_TYPE_BASE &&
791  vp->da->attr < PW_EAP_TYPE_BASE+256) ||
792  (vp->da->attr >= PW_EAP_SIM_BASE &&
793  vp->da->attr < PW_EAP_SIM_BASE+256))
794  {
795  vp = fr_cursor_remove(&cursor);
796  talloc_free(vp);
797  }
798  }
799 }
800 
801 /** We got an EAP-Request/Sim/Start message in a legal state.
802  *
803  * pick a supported version, put it into the reply, and insert a nonce.
804  */
805 static int rc_process_eap_start(rc_eap_context_t *eap_context,
806  RADIUS_PACKET *req, RADIUS_PACKET *rep)
807 {
808  VALUE_PAIR *vp, *newvp;
809  VALUE_PAIR *anyidreq_vp, *fullauthidreq_vp, *permanentidreq_vp;
810  uint16_t const *versions;
811  uint16_t selectedversion;
812  unsigned int i,versioncount;
813 
814  /* form new response clear of any EAP stuff */
815  rc_cleanresp(rep);
816 
817  if ((vp = fr_pair_find_by_num(req->vps, 0, PW_EAP_SIM_VERSION_LIST, TAG_ANY)) == NULL) {
818  ERROR("illegal start message has no VERSION_LIST");
819  return 0;
820  }
821 
822  versions = (uint16_t const *) vp->vp_strvalue;
823 
824  /* verify that the attribute length is big enough for a length field */
825  if (vp->vp_length < 4)
826  {
827  ERROR("start message has illegal VERSION_LIST. Too short: %u", (unsigned int) vp->vp_length);
828  return 0;
829  }
830 
831  versioncount = ntohs(versions[0])/2;
832  /* verify that the attribute length is big enough for the given number
833  * of versions present.
834  */
835  if ((unsigned)vp->vp_length <= (versioncount*2 + 2))
836  {
837  ERROR("start message is too short. Claimed %d versions does not fit in %u bytes", versioncount, (unsigned int) vp->vp_length);
838  return 0;
839  }
840 
841  /*
842  * record the versionlist for the MK calculation.
843  */
844  eap_context->eap.sim.keys.versionlistlen = versioncount*2;
845  memcpy(eap_context->eap.sim.keys.versionlist, (unsigned char const *)(versions+1),
846  eap_context->eap.sim.keys.versionlistlen);
847 
848  /* walk the version list, and pick the one we support, which
849  * at present, is 1, EAP_SIM_VERSION.
850  */
851  selectedversion=0;
852  for (i=0; i < versioncount; i++)
853  {
854  if (ntohs(versions[i+1]) == EAP_SIM_VERSION)
855  {
856  selectedversion=EAP_SIM_VERSION;
857  break;
858  }
859  }
860  if (selectedversion == 0)
861  {
862  ERROR("eap-sim start message. No compatible version found. We need %d", EAP_SIM_VERSION);
863  for (i=0; i < versioncount; i++)
864  {
865  ERROR("\tfound version %d",
866  ntohs(versions[i+1]));
867  }
868  }
869 
870  /*
871  * now make sure that we have only FULLAUTH_ID_REQ.
872  * I think that it actually might not matter - we can answer in
873  * anyway we like, but it is illegal to have more than one
874  * present.
875  */
876  anyidreq_vp = fr_pair_find_by_num(req->vps, 0, PW_EAP_SIM_ANY_ID_REQ, TAG_ANY);
877  fullauthidreq_vp = fr_pair_find_by_num(req->vps, 0, PW_EAP_SIM_FULLAUTH_ID_REQ, TAG_ANY);
878  permanentidreq_vp = fr_pair_find_by_num(req->vps, 0, PW_EAP_SIM_PERMANENT_ID_REQ, TAG_ANY);
879 
880  if (!fullauthidreq_vp ||
881  anyidreq_vp != NULL ||
882  permanentidreq_vp != NULL) {
883  ERROR("start message has %sanyidreq, %sfullauthid and %spermanentid. Illegal combination.",
884  (anyidreq_vp != NULL ? "a ": "no "),
885  (fullauthidreq_vp != NULL ? "a ": "no "),
886  (permanentidreq_vp != NULL ? "a ": "no "));
887  return 0;
888  }
889 
890  /* okay, we have just any_id_req there, so fill in response */
891 
892  /* mark the subtype as being EAP-SIM/Response/Start */
893  newvp = fr_pair_afrom_num(rep, 0, PW_EAP_SIM_SUBTYPE);
894  newvp->vp_integer = EAPSIM_START;
895  fr_pair_replace(&(rep->vps), newvp);
896 
897  /* insert selected version into response. */
898  {
899  uint16_t no_versions;
900 
901  no_versions = htons(selectedversion);
902 
903  newvp = fr_pair_afrom_num(rep, 0, PW_EAP_SIM_SELECTED_VERSION);
904  fr_pair_value_memcpy(newvp, (uint8_t *) &no_versions, 2);
905  fr_pair_replace(&(rep->vps), newvp);
906 
907  /* record the selected version */
908  memcpy(eap_context->eap.sim.keys.versionselect, &no_versions, 2);
909  }
910 
911  vp = newvp = NULL;
912 
913  {
914  uint32_t nonce[4];
915  uint8_t *p;
916  /*
917  * insert a nonce_mt that we make up.
918  */
919  nonce[0]=fr_rand();
920  nonce[1]=fr_rand();
921  nonce[2]=fr_rand();
922  nonce[3]=fr_rand();
923 
924  newvp = fr_pair_afrom_num(rep, 0, PW_EAP_SIM_NONCE_MT);
925 
926  p = talloc_zero_array(newvp, uint8_t, 18); /* 18 = 16 bytes of nonce + padding */
927  memcpy(&p[2], nonce, 16);
928  fr_pair_value_memsteal(newvp, p);
929 
930  fr_pair_replace(&(rep->vps), newvp);
931 
932  /* also keep a copy of the nonce! */
933  memcpy(eap_context->eap.sim.keys.nonce_mt, nonce, 16);
934  }
935 
936  {
937  uint16_t idlen;
938  uint8_t *p;
939  uint16_t no_idlen;
940 
941  /*
942  * insert the identity here.
943  */
944  vp = fr_pair_find_by_num(rep->vps, 0, PW_USER_NAME, TAG_ANY);
945  if (!vp)
946  {
947  ERROR("eap-sim: We need to have a User-Name attribute!");
948  return 0;
949  }
950  newvp = fr_pair_afrom_num(rep, 0, PW_EAP_SIM_IDENTITY);
951 
952  idlen = strlen(vp->vp_strvalue);
953  p = talloc_zero_array(newvp, uint8_t, idlen + 2);
954  no_idlen = htons(idlen);
955  memcpy(p, &no_idlen, 2);
956  memcpy(p + 2, vp->vp_strvalue, idlen);
957  fr_pair_value_memsteal(newvp, p);
958 
959  fr_pair_replace(&(rep->vps), newvp);
960 
961  /* record it */
962  memcpy(eap_context->eap.sim.keys.identity, vp->vp_strvalue, idlen);
963  eap_context->eap.sim.keys.identitylen = idlen;
964  }
965 
966  return 1;
967 }
968 
969 /** We got an EAP-Request/Sim/Challenge message in a legal state.
970  *
971  * use the RAND challenge to produce the SRES result, and then
972  * use that to generate a new MAC.
973  *
974  * for the moment, we ignore the RANDs, then just plug in the SRES
975  * values.
976  */
978  RADIUS_PACKET *req, RADIUS_PACKET *rep)
979 {
980  VALUE_PAIR *newvp;
981  VALUE_PAIR *mac, *randvp;
982  VALUE_PAIR *sres1, *sres2, *sres3;
983  VALUE_PAIR *Kc1, *Kc2, *Kc3;
984  uint8_t calcmac[EAPSIM_CALCMAC_SIZE];
985 
986  /* look for the AT_MAC and the challenge data */
987  mac = fr_pair_find_by_num(req->vps, 0, PW_EAP_SIM_MAC, TAG_ANY);
988  randvp = fr_pair_find_by_num(req->vps, 0, PW_EAP_SIM_RAND, TAG_ANY);
989  if (!mac || !randvp) {
990  ERROR("Challenge message needs to contain RAND and MAC");
991  return 0;
992  }
993 
994  /*
995  * compare RAND with randX, to verify this is the right response
996  * to this challenge.
997  */
998  {
999  VALUE_PAIR *randcfgvp[3];
1000  uint8_t const *randcfg[3];
1001 
1002  randcfg[0] = &randvp->vp_octets[2];
1003  randcfg[1] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE];
1004  randcfg[2] = &randvp->vp_octets[2+EAPSIM_RAND_SIZE*2];
1005 
1006  randcfgvp[0] = fr_pair_find_by_num(rep->vps, 0, PW_EAP_SIM_RAND1, TAG_ANY);
1007  randcfgvp[1] = fr_pair_find_by_num(rep->vps, 0, PW_EAP_SIM_RAND2, TAG_ANY);
1008  randcfgvp[2] = fr_pair_find_by_num(rep->vps, 0, PW_EAP_SIM_RAND3, TAG_ANY);
1009 
1010  if (!randcfgvp[0] ||
1011  !randcfgvp[1] ||
1012  !randcfgvp[2]) {
1013  ERROR("Need to have RAND 1, 2 and 3 set");
1014  return 0;
1015  }
1016 
1017  if (memcmp(randcfg[0], randcfgvp[0]->vp_octets, EAPSIM_RAND_SIZE) != 0 ||
1018  memcmp(randcfg[1], randcfgvp[1]->vp_octets, EAPSIM_RAND_SIZE) != 0 ||
1019  memcmp(randcfg[2], randcfgvp[2]->vp_octets, EAPSIM_RAND_SIZE) != 0)
1020  {
1021  int rnum;
1022 
1023  ERROR("one of RAND 1, 2, or 3 didn't match");
1024 
1025  char ch_rand[EAPSIM_RAND_SIZE*2 +1 +3] = ""; // +3 for separators.
1026  for (rnum = 0; rnum < 3; rnum++) {
1027  rc_print_hexstr(ch_rand, randcfg[rnum], EAPSIM_RAND_SIZE, 4, '_');
1028  ERROR("Received rand %d: %s", rnum, ch_rand);
1029 
1030  rc_print_hexstr(ch_rand, randcfgvp[rnum]->vp_octets, EAPSIM_RAND_SIZE, 4, '_');
1031  ERROR("Configured rand %d: %s", rnum, ch_rand);
1032  }
1033  return 0;
1034  }
1035  }
1036 
1037  /*
1038  * now dig up the sres values from the response packet,
1039  * which were put there when we read things in.
1040  *
1041  * Really, they should be calculated from the RAND!
1042  *
1043  */
1044  sres1 = fr_pair_find_by_num(rep->vps, 0, PW_EAP_SIM_SRES1, TAG_ANY);
1045  sres2 = fr_pair_find_by_num(rep->vps, 0, PW_EAP_SIM_SRES2, TAG_ANY);
1046  sres3 = fr_pair_find_by_num(rep->vps, 0, PW_EAP_SIM_SRES3, TAG_ANY);
1047 
1048  if (!sres1 ||
1049  !sres2 ||
1050  !sres3) {
1051  ERROR("Need to have SRES 1, 2, and 3 set");
1052  return 0;
1053  }
1054  memcpy(eap_context->eap.sim.keys.sres[0], sres1->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[0]));
1055  memcpy(eap_context->eap.sim.keys.sres[1], sres2->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[1]));
1056  memcpy(eap_context->eap.sim.keys.sres[2], sres3->vp_strvalue, sizeof(eap_context->eap.sim.keys.sres[2]));
1057 
1058  Kc1 = fr_pair_find_by_num(rep->vps, 0, PW_EAP_SIM_KC1, TAG_ANY);
1059  Kc2 = fr_pair_find_by_num(rep->vps, 0, PW_EAP_SIM_KC2, TAG_ANY);
1060  Kc3 = fr_pair_find_by_num(rep->vps, 0, PW_EAP_SIM_KC3, TAG_ANY);
1061 
1062  if (!Kc1 ||
1063  !Kc2 ||
1064  !Kc3) {
1065  ERROR("Need to have Kc 1, 2, and 3 set");
1066  return 0;
1067  }
1068  memcpy(eap_context->eap.sim.keys.Kc[0], Kc1->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[0]));
1069  memcpy(eap_context->eap.sim.keys.Kc[1], Kc2->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[1]));
1070  memcpy(eap_context->eap.sim.keys.Kc[2], Kc3->vp_strvalue, sizeof(eap_context->eap.sim.keys.Kc[2]));
1071 
1072  /* all set, calculate keys */
1073  eapsim_calculate_keys(&eap_context->eap.sim.keys);
1074 
1075  if (rad_debug_lvl) {
1076  eapsim_dump_mk(&eap_context->eap.sim.keys);
1077  }
1078 
1079  /* verify the MAC, now that we have all the keys. */
1080  int rcode_mac = eapsim_checkmac(NULL, req->vps, eap_context->eap.sim.keys.K_aut,
1081  eap_context->eap.sim.keys.nonce_mt, sizeof(eap_context->eap.sim.keys.nonce_mt),
1082  calcmac);
1083 
1084  char ch_calc_mac[EAPSIM_CALCMAC_SIZE*2 +1 +4] = ""; // +4 for separators.
1085  rc_print_hexstr(ch_calc_mac, calcmac, EAPSIM_CALCMAC_SIZE, 4, '_');
1086 
1087  if (rcode_mac) {
1088  DEBUG2("MAC check succeeded (%s)", ch_calc_mac);
1089  }
1090  else {
1091  ERROR("Challenge MAC check failed. Calculated MAC (%s) did not match", ch_calc_mac);
1092  return 0;
1093  }
1094 
1095  /* form new response clear of any EAP stuff */
1096  rc_cleanresp(rep);
1097 
1098  /* mark the subtype as being EAP-SIM/Response/Start */
1099  newvp = fr_pair_afrom_num(rep, 0, PW_EAP_SIM_SUBTYPE);
1100  newvp->vp_integer = EAPSIM_CHALLENGE;
1101  fr_pair_replace(&(rep->vps), newvp);
1102 
1103  {
1104  uint8_t *p;
1105  /*
1106  * fill the SIM_MAC with a field that will in fact get appended
1107  * to the packet before the MAC is calculated
1108  */
1109  newvp = fr_pair_afrom_num(rep, 0, PW_EAP_SIM_MAC);
1110 
1111  p = talloc_zero_array(newvp, uint8_t, EAPSIM_SRES_SIZE*3);
1112  memcpy(p+EAPSIM_SRES_SIZE * 0, sres1->vp_strvalue, EAPSIM_SRES_SIZE);
1113  memcpy(p+EAPSIM_SRES_SIZE * 1, sres2->vp_strvalue, EAPSIM_SRES_SIZE);
1114  memcpy(p+EAPSIM_SRES_SIZE * 2, sres3->vp_strvalue, EAPSIM_SRES_SIZE);
1115  fr_pair_value_memsteal(newvp, p);
1116 
1117  fr_pair_replace(&(rep->vps), newvp);
1118  }
1119 
1120  newvp = fr_pair_afrom_num(rep, 0, PW_EAP_SIM_KEY);
1121  fr_pair_value_memcpy(newvp, eap_context->eap.sim.keys.K_aut, EAPSIM_AUTH_SIZE);
1122 
1123  fr_pair_replace(&(rep->vps), newvp);
1124 
1125  return 1;
1126 }
1127 
1128 /** This runs the EAP-SIM client state machine.
1129  * the *request* is from the server.
1130  * the *reponse* is to the server.
1131  */
1132 static int rc_respond_eap_sim(rc_eap_context_t *eap_context,
1133  RADIUS_PACKET *req, RADIUS_PACKET *resp)
1134 {
1135  enum eapsim_clientstates state, newstate;
1136  enum eapsim_subtype subtype;
1137  VALUE_PAIR *vp, *statevp, *radstate, *eapid;
1138  char statenamebuf[32], subtypenamebuf[32];
1139  int rcode_eap;
1140 
1141  if ((radstate = fr_pair_list_copy_by_num(NULL, req->vps, 0, PW_STATE, TAG_ANY)) == NULL)
1142  {
1143  return 0;
1144  }
1145 
1146  if ((eapid = fr_pair_list_copy_by_num(NULL, req->vps, 0, PW_EAP_ID, TAG_ANY)) == NULL)
1147  {
1148  return 0;
1149  }
1150 
1151  /* first, dig up the state from the request packet, setting
1152  * ourselves to be in EAP-SIM-Start state if there is none.
1153  */
1154 
1155  if ((statevp = fr_pair_find_by_num(resp->vps, 0, PW_EAP_SIM_STATE, TAG_ANY)) == NULL)
1156  {
1157  /* must be initial request */
1158  statevp = fr_pair_afrom_num(resp, 0, PW_EAP_SIM_STATE);
1159  statevp->vp_integer = EAPSIM_CLIENT_INIT;
1160  fr_pair_replace(&(resp->vps), statevp);
1161  }
1162  state = statevp->vp_integer;
1163 
1164  /*
1165  * map the attributes, and authenticate them.
1166  */
1167  rc_unmap_eapsim_types(req);
1168 
1169  if ((vp = fr_pair_find_by_num(req->vps, 0, PW_EAP_SIM_SUBTYPE, TAG_ANY)) == NULL)
1170  {
1171  return 0;
1172  }
1173  subtype = vp->vp_integer;
1174 
1175  /*
1176  * look for the appropriate state, and process incoming message
1177  */
1178  switch (state) {
1179  case EAPSIM_CLIENT_INIT:
1180  switch (subtype) {
1181  case EAPSIM_START:
1182  rcode_eap = rc_process_eap_start(eap_context, req, resp);
1183  break;
1184 
1185  case EAPSIM_CHALLENGE:
1186  case EAPSIM_NOTIFICATION:
1187  case EAPSIM_REAUTH:
1188  default:
1189  ERROR("sim in state '%s' (%d), message '%s' (%d) is illegal. Reply dropped.",
1190  sim_state2name(state, statenamebuf, sizeof(statenamebuf)), state,
1191  sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf)), subtype);
1192  /* invalid state, drop message */
1193  return 0;
1194  }
1195  break;
1196 
1197  case EAPSIM_CLIENT_START:
1198  switch (subtype) {
1199  case EAPSIM_START:
1200  /* NOT SURE ABOUT THIS ONE, retransmit, I guess */
1201  rcode_eap = rc_process_eap_start(eap_context, req, resp);
1202  break;
1203 
1204  case EAPSIM_CHALLENGE:
1205  rcode_eap = rc_process_eap_challenge(eap_context, req, resp);
1206  break;
1207 
1208  default:
1209  ERROR("sim in state %s message %s is illegal. Reply dropped.",
1210  sim_state2name(state, statenamebuf, sizeof(statenamebuf)),
1211  sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf)));
1212  /* invalid state, drop message */
1213  return 0;
1214  }
1215  break;
1216 
1217  default:
1218  ERROR("sim in illegal state '%s' (%d)",
1219  sim_state2name(state, statenamebuf, sizeof(statenamebuf)), state);
1220  return 0;
1221  }
1222 
1223  /* process_eap_* functions return 0 if fail, 1 if success. */
1224  if (!rcode_eap) {
1225  ERROR("EAP process failed, aborting EAP-SIM transaction.");
1226  return 0;
1227  }
1228  newstate = EAPSIM_CLIENT_START; // (1)
1229 
1230  /* copy the eap state object in */
1231  fr_pair_replace(&(resp->vps), eapid);
1232 
1233  /* update state info, and send new packet */
1234  rc_map_eapsim_types(resp);
1235 
1236  /* copy the radius state object in */
1237  fr_pair_replace(&(resp->vps), radstate);
1238 
1239  statevp->vp_integer = newstate;
1240  return 1;
1241 }
1242 
1243 static int rc_respond_eap_md5(rc_eap_context_t *eap_context,
1244  RADIUS_PACKET *req, RADIUS_PACKET *rep)
1245 {
1246  VALUE_PAIR *vp, *id, *state;
1247  size_t valuesize;
1248  uint8_t identifier;
1249  uint8_t const *value;
1250  FR_MD5_CTX context;
1251  uint8_t response[16];
1252 
1253  rc_cleanresp(rep);
1254 
1255  if ((state = fr_pair_list_copy_by_num(NULL, req->vps, 0, PW_STATE, TAG_ANY)) == NULL)
1256  {
1257  ERROR("no state attribute found");
1258  return 0;
1259  }
1260 
1261  if ((id = fr_pair_list_copy_by_num(NULL, req->vps, 0, PW_EAP_ID, TAG_ANY)) == NULL)
1262  {
1263  ERROR("no EAP-ID attribute found");
1264  return 0;
1265  }
1266  identifier = id->vp_integer;
1267 
1268  if ((vp = fr_pair_find_by_num(req->vps, 0, PW_EAP_TYPE_BASE + PW_EAP_MD5, TAG_ANY)) == NULL)
1269  {
1270  ERROR("no EAP-MD5 attribute found");
1271  return 0;
1272  }
1273 
1274  /* got the details of the MD5 challenge */
1275  valuesize = vp->vp_octets[0];
1276  value = &vp->vp_octets[1];
1277 
1278  /* sanitize items */
1279  if (valuesize > vp->vp_length)
1280  {
1281  ERROR("md5 valuesize if too big (%u > %u)",
1282  (unsigned int) valuesize, (unsigned int) vp->vp_length);
1283  return 0;
1284  }
1285 
1286  /* now do the CHAP operation ourself, rather than build the
1287  * buffer. We could also call fr_radius_encode_chap_password, but it wants
1288  * a CHAP-Challenge, which we don't want to bother with.
1289  */
1290  fr_md5_init(&context);
1291  fr_md5_update(&context, &identifier, 1);
1292  fr_md5_update(&context, (uint8_t *) eap_context->password, strlen(eap_context->password));
1293  fr_md5_update(&context, value, valuesize);
1294  fr_md5_final(response, &context);
1295 
1296  {
1297  uint8_t *p;
1298  uint8_t lg_response;
1299 
1300  vp = fr_pair_afrom_num(rep, 0, PW_EAP_TYPE_BASE + PW_EAP_MD5);
1301  vp->vp_length = 17;
1302 
1303  p = talloc_zero_array(vp, uint8_t, 17);
1304  lg_response = 16;
1305  memcpy(p, &lg_response, 1);
1306  memcpy(p + 1, response, 16);
1307  fr_pair_value_memsteal(vp, p);
1308  }
1309  fr_pair_replace(&(rep->vps), vp);
1310 
1311  fr_pair_replace(&(rep->vps), id);
1312 
1313  /* copy the state object in */
1314  fr_pair_replace(&(rep->vps), state);
1315 
1316  return 1;
1317 }
1318 
1319 
1320 /** Allocate a new socket, and add it to the packet list.
1321  */
1322 static void rc_add_socket(fr_ipaddr_t *src_ipaddr, uint16_t src_port, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port)
1323 {
1324  int mysockfd;
1325 
1326  /* Trace what we're doing. */
1327  char src_addr[INET6_ADDRSTRLEN] = "";
1328  char dst_addr[INET6_ADDRSTRLEN] = "";
1329  inet_ntop(AF_INET, &(src_ipaddr->ipaddr.ip4addr.s_addr), src_addr, sizeof(src_addr));
1330  inet_ntop(AF_INET, &(dst_ipaddr->ipaddr.ip4addr.s_addr), dst_addr, sizeof(dst_addr));
1331 
1332  INFO("Adding new socket: src: %s:%d, dst: %s:%d", src_addr, src_port, dst_addr, dst_port);
1333 
1334  mysockfd = fr_socket(src_ipaddr, src_port);
1335  if (mysockfd < 0) {
1336  ERROR("Failed to create new socket: %s", fr_strerror());
1337  exit(1);
1338  }
1339 
1340  if (!fr_packet_list_socket_add(pl, mysockfd, ipproto, dst_ipaddr, dst_port, NULL)) {
1341  ERROR("Failed to add new socket: %s", fr_strerror());
1342  exit(1);
1343  }
1344 
1345  num_sockets ++;
1346  DEBUG("Added new socket: %d (num sockets: %d)", mysockfd, num_sockets);
1347 }
1348 
1349 /** Send one packet for a transaction.
1350  */
1352 {
1353  if (!trans || !packet_p || !*packet_p) return -1;
1354 
1355  assert(pl != NULL);
1356 
1357  RADIUS_PACKET *packet = *packet_p;
1358 
1359  if (packet->id == -1) {
1360  /* Haven't sent the packet yet. Initialize it. */
1361  bool rcode;
1362  int i;
1363 
1364  rc_build_eap_context(trans); /* In case of EAP, build EAP-Message and initialize EAP context. */
1365 
1366  assert(trans->reply == NULL);
1367 
1368  trans->tries = 0;
1369  packet->src_ipaddr.af = server_ipaddr.af;
1370  int nb_sock_add = 0;
1371  while (1) {
1372  /* Allocate a RADIUS packet ID from a suitable socket of the packet list. */
1373  rcode = fr_packet_list_id_alloc(pl, ipproto, packet_p, NULL);
1374 
1375  if (rcode) { /* Got an ID. */
1376  break;
1377  }
1378  if (nb_sock_add >= 1) {
1379  ERROR("Added %d new socket(s), but still could not get an ID (currently: %d outgoing requests).",
1380  nb_sock_add, fr_packet_list_num_outgoing(pl));
1381  exit(1);
1382  }
1383 
1384  /* Could not find a free packet ID. Allocate a new socket, then try again. */
1385  rc_add_socket(&packet->src_ipaddr, packet->src_port, &packet->dst_ipaddr, packet->dst_port);
1386 
1387  nb_sock_add ++;
1388  }
1389 
1390  assert(packet->id != -1);
1391  assert(packet->data == NULL);
1392 
1393  for (i = 0; i < 4; i++) {
1394  ((uint32_t *) packet->vector)[i] = fr_rand();
1395  }
1396  }
1397 
1398  /*
1399  * Send the packet.
1400  */
1401  DEBUG("Transaction: %u, sending packet: %u (id: %u)...", trans->id, trans->num_packet, packet->id);
1402 
1403  gettimeofday(&packet->timestamp, NULL); /* set outgoing packet timestamp. */
1404 
1405  if (fr_radius_send(packet, NULL, secret) < 0) {
1406  ERROR("Failed to send packet (sockfd: %d, id: %d): %s",
1407  packet->sockfd, packet->id, fr_strerror());
1408  }
1409 
1410  STATS_INC(nb_packets_sent);
1411  if (trans->tries) STATS_INC(nb_packets_retries);
1412 
1413  trans->num_packet ++;
1414  trans->tries ++;
1415 
1416  if (fr_debug_lvl > 0) fr_packet_header_print(fr_log_fp, packet, false);
1417  if (fr_debug_lvl > 0) fr_pair_list_fprint(fr_log_fp, packet->vps);
1418 
1419  return 1;
1420 }
1421 
1422 /** Send current packet of a transaction. Arm timeout event.
1423  */
1425 // note: we need a 'RADIUS_PACKET **' for fr_packet_list_id_alloc.
1426 {
1427  if (!trans || !packet_p || !*packet_p) return -1;
1428 
1429  int ret = rc_send_one_packet(trans, packet_p);
1430  if (ret == 1) {
1431  /* Send successful: arm the timeout callback. */
1432  rc_evprep_packet_timeout(trans);
1433  }
1434  return ret;
1435 }
1436 
1437 /** Deallocate RADIUS packet ID.
1438  */
1440 {
1441  if (!trans || !trans->packet ||
1442  (trans->packet->id < 0)) {
1443  return;
1444  }
1445 
1446  RADIUS_PACKET *packet = trans->packet;
1447 
1448  DEBUG2("Deallocating (sockfd: %d, id: %d)", packet->sockfd, packet->id);
1449 
1450  /*
1451  * One more unused RADIUS ID.
1452  */
1453  fr_packet_list_id_free(pl, packet, true);
1454  /* note: "true" means automatically yank, so we must *not* yank ourselves before calling (otherwise, it does nothing)
1455  * so, *don't*: fr_packet_list_yank(pl, request->packet); */
1456 
1457  /* free more stuff to ensure next allocate won't be stuck on a "full" socket. */
1458  packet->id = -1;
1459  packet->sockfd = -1;
1460  packet->src_ipaddr.af = AF_UNSPEC;
1461  packet->src_port = 0;
1462 
1463  /*
1464  * If we've already sent a packet, free up the old one,
1465  * and ensure that the next packet has a unique
1466  * authentication vector.
1467  */
1468  if (packet->data) {
1469  talloc_free(packet->data);
1470  packet->data = NULL;
1471  }
1472 
1473  if (trans->reply) fr_radius_free(&trans->reply);
1474 }
1475 
1476 /** Receive one packet, maybe.
1477  */
1478 static int rc_recv_one_packet(struct timeval *tv_wait_time)
1479 {
1480  fd_set set;
1481  struct timeval tv;
1483  RADIUS_PACKET *reply, **packet_p;
1484  volatile int max_fd;
1485  bool ongoing_trans = false;
1486  char buffer[INET6_ADDRSTRLEN];
1487 
1488  /* Wait for reply, timing out as necessary */
1489  FD_ZERO(&set);
1490 
1491  max_fd = fr_packet_list_fd_set(pl, &set);
1492  if (max_fd < 0) {
1493  /* no sockets to listen on! */
1494  return 0;
1495  }
1496 
1497  if (NULL == tv_wait_time) {
1498  timerclear(&tv);
1499  } else {
1500  tv.tv_sec = tv_wait_time->tv_sec;
1501  tv.tv_usec = tv_wait_time->tv_usec;
1502  }
1503 
1504  if (select(max_fd, &set, NULL, NULL, &tv) <= 0) {
1505  /* No packet was received. */
1506  return 0;
1507  }
1508 
1509  /*
1510  * Receive the reply.
1511  */
1512  reply = fr_packet_list_recv(pl, &set);
1513  if (!reply) {
1514  ERROR("Received bad packet: %s", fr_strerror());
1515  return -1; /* bad packet */
1516  }
1517 
1518  /*
1519  * Look for the packet which matches the reply.
1520  */
1521  reply->src_ipaddr = server_ipaddr;
1522  reply->src_port = server_port;
1523 
1524  /*
1525  * Note: this only works if all packets have the same destination (IP, port).
1526  * We should handle a list of destinations. But we don't. radclient doesn't do it either).
1527  */
1528 
1529  packet_p = fr_packet_list_find_byreply(pl, reply);
1530 
1531  if (!packet_p) {
1532  /* got reply to packet we didn't send.
1533  * (or maybe we sent it, got no response, freed the ID. Then server responds to first request.)
1534  */
1535  DEBUG("No outstanding request was found for reply from %s, port %d (sockfd: %d, id: %d)",
1536  inet_ntop(reply->src_ipaddr.af, &reply->src_ipaddr.ipaddr, buffer, sizeof(buffer)),
1537  reply->src_port, reply->sockfd, reply->id);
1538  fr_radius_free(&reply);
1539  return -1;
1540  }
1541 
1542  STATS_INC(nb_packets_recv);
1543 
1544  trans = fr_packet2myptr(rc_transaction_t, packet, packet_p);
1545 
1546  if (trans->event) fr_event_delete(ev_list, &trans->event);
1547 
1548  /*
1549  * Fails the signature validation: not a valid reply.
1550  */
1551  if (fr_radius_verify(reply, trans->packet, secret) < 0) {
1552  /* shared secret is incorrect.
1553  * (or maybe this is a response to another packet we sent, for which we got no response,
1554  * freed the ID, then reused it. Then server responds to first packet.)
1555  */
1556  DEBUG("Conflicting response authenticator for reply from %s (sockfd: %d, id: %d)",
1557  inet_ntop(reply->src_ipaddr.af, &reply->src_ipaddr.ipaddr, buffer, sizeof(buffer)),
1558  reply->sockfd, reply->id);
1559 
1560  goto packet_done;
1561  }
1562 
1563  /* Set reply destination = packet source. */
1564  reply->dst_ipaddr = trans->packet->src_ipaddr;
1565  reply->dst_port = trans->packet->src_port;
1566 
1567  trans->reply = reply;
1568  reply = NULL;
1569 
1570  if (fr_radius_decode(trans->reply, trans->packet, secret) != 0) {
1571  /* This can fail if packet contains too many attributes. */
1572  DEBUG("Failed decoding reply");
1573  goto packet_done;
1574  }
1575 
1576  gettimeofday(&trans->reply->timestamp, NULL); /* set received packet timestamp. */
1577 
1578  if (trans->eap_context) {
1579  /* Call unmap before packet print (so we can see the decoded EAP stuff). */
1580  rc_unmap_eap_methods(trans->reply);
1581  }
1582 
1583  DEBUG("Transaction: %u, received packet (id: %u).", trans->id, trans->reply->id);
1584 
1585  if (fr_debug_lvl > 0) fr_packet_header_print(fr_log_fp, trans->reply, true);
1586  if (fr_debug_lvl > 0) fr_pair_list_fprint(fr_log_fp, trans->reply->vps);
1587 
1588  if (!trans->eap_context) {
1589  goto packet_done;
1590  }
1591 
1592  /* now look for the code type. */
1593  VALUE_PAIR *vp, *vpnext;
1594  for (vp = trans->reply->vps; vp != NULL; vp = vpnext) {
1595  vpnext = vp->next;
1596 
1597  switch (vp->da->attr) {
1598  default:
1599  break;
1600 
1601  case PW_EAP_TYPE_BASE + PW_EAP_MD5:
1602  if (rc_respond_eap_md5(trans->eap_context, trans->reply, trans->packet) && trans->eap_context->eap.md5.tried < 3)
1603  {
1604  /* answer the challenge from server. */
1605  trans->eap_context->eap.md5.tried ++;
1606  rc_deallocate_id(trans);
1607  rc_send_transaction_packet(trans, &trans->packet);
1608  ongoing_trans = true; // don't free the transaction yet.
1609  }
1610  goto packet_done;
1611 
1612  case PW_EAP_TYPE_BASE + PW_EAP_SIM:
1613  if (rc_respond_eap_sim(trans->eap_context, trans->reply, trans->packet)) {
1614  /* answer the challenge from server. */
1615  rc_deallocate_id(trans);
1616  rc_send_transaction_packet(trans, &trans->packet);
1617  ongoing_trans = true; // don't free the transaction yet.
1618  }
1619  goto packet_done;
1620  }
1621  }
1622 
1623  goto eap_done;
1624 
1625 eap_done:
1626  /* EAP transaction ends here (no more requests from EAP server). */
1627 
1628  /*
1629  * success: if we have EAP-Code = Success, and reply is an Access-Accept.
1630  */
1631  if (trans->reply->code != PW_CODE_ACCESS_ACCEPT) {
1632  DEBUG("EAP transaction finished, but reply is not an Access-Accept");
1633  STATS_INC(nb_fail);
1634  goto packet_done;
1635  }
1636  vp = fr_pair_find_by_num(trans->reply->vps, 0, PW_EAP_CODE, TAG_ANY);
1637  if ( (!vp) || (vp->vp_integer != 3) ) {
1638  DEBUG("EAP transaction finished, but reply does not contain EAP-Code = Success");
1639  STATS_INC(nb_fail);
1640  goto packet_done;
1641  }
1642  STATS_INC(nb_success);
1644 
1645  goto packet_done;
1646 
1647 packet_done:
1648 
1649  if (trans->reply && !trans->eap_context) {
1650  /* Statistics for non-EAP transactions */
1651  switch (trans->reply->code) {
1652  case PW_CODE_ACCESS_ACCEPT:
1653  STATS_INC(nb_success);
1655  break;
1656  case PW_CODE_COA_ACK:
1657  STATS_INC(nb_success);
1659  break;
1661  STATS_INC(nb_success);
1663  break;
1664  case PW_CODE_ACCESS_REJECT:
1665  case PW_CODE_COA_NAK:
1666  STATS_INC(nb_fail);
1667  break;
1668  default:
1669  break;
1670  }
1671  }
1672 
1673  fr_radius_free(&trans->reply);
1674  fr_radius_free(&reply); /* may be NULL */
1675 
1676  if (!ongoing_trans) {
1677  rc_deallocate_id(trans);
1678  rc_finish_transaction(trans);
1679  }
1680 
1681  return 1;
1682 }
1683 
1684 /** Event callback: packet timeout.
1685  */
1686 static void rc_evcb_packet_timeout(void *ctx, UNUSED struct timeval *now)
1687 {
1688  rc_transaction_t *trans = ctx;
1689  if (!trans || !trans->packet) return;
1690 
1691  DEBUG("Timeout for transaction: %d, tries (so far): %d (max: %d)", trans->id, trans->tries, retries);
1692 
1693  if (trans->event) fr_event_delete(ev_list, &trans->event);
1694 
1695  if (trans->tries < retries) {
1696  /* Try again. */
1697  rc_send_transaction_packet(trans, &trans->packet);
1698  } else {
1699  DEBUG("No response for transaction: %d, giving up", trans->id);
1700  rc_finish_transaction(trans);
1701 
1702  STATS_INC(nb_lost);
1703  }
1704 }
1705 
1706 /** Prepare event: packet timeout.
1707  */
1709 {
1710  struct timeval tv_event;
1711  gettimeofday(&tv_event, NULL);
1712  timeradd(&tv_event, &tv_timeout, &tv_event);
1713 
1714  if (!fr_event_insert(ev_list, rc_evcb_packet_timeout, (void *)trans, &tv_event, &trans->event)) {
1715  ERROR("Failed to insert event");
1716  exit(1);
1717  }
1718 }
1719 
1720 /** Event callback: report progress statistics.
1721  */
1722 static void rc_evcb_progress_stat(void UNUSED *ctx, UNUSED struct timeval *now)
1723 {
1724  /* print the progress statistics */
1726 
1727  /* schedule the next */
1729 }
1730 
1731 /** Prepare event: report progress statistics.
1732  */
1733 static void rc_evprep_progress_stat(void)
1734 {
1735  if (!timerisset(&tv_progress_interval)) return;
1736 
1737  struct timeval tv_event;
1738  gettimeofday(&tv_event, NULL);
1739 
1740  timeradd(&tv_event, &tv_progress_interval, &tv_event);
1741 
1742  static fr_event_t *event; /* only one of this kind. */
1743 
1744  if (!fr_event_insert(ev_list, rc_evcb_progress_stat, (void *) NULL, &tv_event, &event)) {
1745  ERROR("Failed to insert event");
1746  exit(1);
1747  }
1748 }
1749 
1750 /** Trigger all armed events for which time is reached.
1751  */
1752 static uint32_t rc_loop_events(void)
1753 {
1754  struct timeval when;
1755  uint32_t nb_processed = 0;
1756 
1757  if (!fr_event_list_num_elements(ev_list)) return 0;
1758 
1759  while (1) {
1760  gettimeofday(&when, NULL);
1761  if (!fr_event_run(ev_list, &when)) {
1762  /* no more. */
1763  break;
1764  }
1765  nb_processed ++;
1766  }
1767  return nb_processed;
1768 }
1769 
1770 /** Receive loop.
1771  * Handle incoming packets, until nothing more is received.
1772  */
1773 static uint32_t rc_loop_recv(void)
1774 {
1775  uint32_t nb_received = 0;
1776  while (rc_recv_one_packet(NULL) > 0) {
1777  nb_received ++;
1778  }
1779  return nb_received;
1780 }
1781 
1782 /** Compute maximum number of new requests that can be started
1783  * while conforming to the specified rate limit.
1784  */
1785 static uint32_t rc_rate_limit(bool *do_limit)
1786 {
1787  uint32_t max_start_new = 0;
1788  *do_limit = false;
1789 
1790  if (rate_limit) {
1791  /* get elapsed time so far */
1792  struct timeval tv_now, tv_elapsed;
1793  gettimeofday(&tv_now, NULL);
1794  timersub(&tv_now, &tv_start, &tv_elapsed);
1795  float elapsed = rc_timeval_to_float(&tv_elapsed);
1796 
1797  if (elapsed > 0) {
1798  *do_limit = true; /* enforce a limit */
1799 
1800  /* project ourselves a small amount of time in the future to perform calculation */
1801  float elapsed_p = elapsed + 0.01;
1802 
1803  /* Compute:
1804  * The maximum number of started requests (according to the rate limit and elapsed time),
1805  * and the maximum number of new requests that can be started according to the rate limit.
1806  */
1807  uint32_t num_start_limit = (float)rate_limit * elapsed_p;
1808  if (num_start_limit > num_started) max_start_new = num_start_limit - num_started;
1809 
1810 //#define DEBUG_RATE_LIMIT 1
1811 #ifdef DEBUG_RATE_LIMIT
1812  if (max_start_new) {
1813  float cur_rate = num_started / elapsed;
1814  float target_rate = (float)(num_started + max_start_new) / elapsed_p;
1815  printf("RATE LIMIT - elapsed: %.3f, started: %d, rate: %.3f, limit: %d, new: %d, target rate: %.6f\n",
1816  elapsed, num_started, cur_rate, num_start_limit, max_start_new, target_rate);
1817  }
1818 #endif
1819  }
1820  }
1821  return max_start_new;
1822 }
1823 
1824 /** Loop starting new transactions, until a limit is reached
1825  * (max parallelism, or no more input available.)
1826  */
1827 static uint32_t rc_loop_start_transactions(void)
1828 {
1829  uint32_t nb_started = 0;
1830  bool do_limit = false;
1831 
1832  uint32_t max_start = rc_rate_limit(&do_limit);
1833 
1834  while (1) {
1835  if (num_ongoing >= parallel) break; /* parallel limit */
1836  if (do_limit && nb_started >= max_start) break; /* rate limit */
1837 
1838  /* Try to initialize a new transaction. */
1840  if (!trans) break;
1841 
1842  nb_started ++;
1843  rc_send_transaction_packet(trans, &trans->packet);
1844  }
1845  return nb_started;
1846 }
1847 
1848 /** Main loop: Handle events. Receive and process responses. Start new transactions.
1849  * Until we're done.
1850  */
1851 static void rc_main_loop(void)
1852 {
1853  while (1) {
1854  /* Handle events. */
1855  rc_loop_events();
1856 
1857  /* Receive and process response until no more are received (don't wait). */
1858  rc_loop_recv();
1859 
1860  /* Start new transactions and send the associated packet. */
1862 
1863  /* Check if we're done. */
1864  if ( (rc_vps_list_in.size == 0)
1865  && (fr_packet_list_num_outgoing(pl) == 0) ) {
1866  break;
1867  }
1868  }
1869  INFO("Main loop: done.");
1870 }
1871 
1872 /** Get port number for a given service name.
1873  */
1874 static uint16_t rc_getport(char const *name)
1875 {
1876  struct servent *svp;
1877 
1878  svp = getservbyname(name, "udp");
1879  if (!svp) return 0;
1880 
1881  return ntohs(svp->s_port);
1882 }
1883 
1884 /** Set a port from the request type if we don't already have one.
1885  */
1886 static void rc_get_radius_port(PW_CODE type, uint16_t *port)
1887 {
1888  switch (type) {
1889  default:
1892  case PW_CODE_STATUS_SERVER:
1893  if (*port == 0) *port = rc_getport("radius");
1894  if (*port == 0) *port = PW_AUTH_UDP_PORT;
1895  return;
1896 
1898  if (*port == 0) *port = rc_getport("radacct");
1899  if (*port == 0) *port = PW_ACCT_UDP_PORT;
1900  return;
1901 
1903  if (*port == 0) *port = PW_POD_UDP_PORT;
1904  return;
1905 
1906  case PW_CODE_COA_REQUEST:
1907  if (*port == 0) *port = PW_COA_UDP_PORT;
1908  return;
1909 
1910  case PW_CODE_UNDEFINED:
1911  if (*port == 0) *port = 0;
1912  return;
1913  }
1914 }
1915 
1916 /** Resolve a port to a request type.
1917  */
1918 static PW_CODE rc_get_code(uint16_t port)
1919 {
1920  /*
1921  * rc_getport returns 0 if the service doesn't exist
1922  * so we need to return early, to avoid incorrect
1923  * codes.
1924  */
1925  if (port == 0) return PW_CODE_UNDEFINED;
1926 
1927  if ((port == rc_getport("radius")) || (port == PW_AUTH_UDP_PORT) || (port == PW_AUTH_UDP_PORT_ALT)) {
1928  return PW_CODE_ACCESS_REQUEST;
1929  }
1930  if ((port == rc_getport("radacct")) || (port == PW_ACCT_UDP_PORT) || (port == PW_ACCT_UDP_PORT_ALT)) {
1932  }
1933  if (port == PW_COA_UDP_PORT) return PW_CODE_COA_REQUEST;
1934  if (port == PW_POD_UDP_PORT) return PW_CODE_DISCONNECT_REQUEST;
1935 
1936  return PW_CODE_UNDEFINED;
1937 }
1938 
1939 /** Resolve server hostname.
1940  */
1941 static void rc_resolve_hostname(char *server_arg)
1942 {
1943  if (force_af == AF_UNSPEC) force_af = AF_INET;
1944  server_ipaddr.af = force_af;
1945  if (strcmp(server_arg, "-") != 0) {
1946  char *p;
1947  char const *hostname = server_arg;
1948  char const *portname = server_arg;
1949  char buffer[256];
1950 
1951  if (*server_arg == '[') { /* IPv6 URL encoded */
1952  p = strchr(server_arg, ']');
1953  if ((size_t) (p - server_arg) >= sizeof(buffer)) {
1954  usage();
1955  }
1956 
1957  memcpy(buffer, server_arg + 1, p - server_arg - 1);
1958  buffer[p - server_arg - 1] = '\0';
1959 
1960  hostname = buffer;
1961  portname = p + 1;
1962 
1963  }
1964  p = strchr(portname, ':');
1965  if (p && (strchr(p + 1, ':') == NULL)) {
1966  *p = '\0';
1967  portname = p + 1;
1968  } else {
1969  portname = NULL;
1970  }
1971 
1972  if (fr_inet_hton(&server_ipaddr, force_af, hostname, false) < 0) {
1973  ERROR("Failed to find IP address for host %s: %s", hostname, strerror(errno));
1974  exit(1);
1975  }
1976  server_addr_init = true;
1977 
1978  /* Strip port from hostname if needed. */
1979  if (portname) server_port = atoi(portname);
1980 
1981  /*
1982  * Work backwards from the port to determine the packet type
1983  */
1984  if (packet_code == PW_CODE_UNDEFINED) packet_code = rc_get_code(server_port);
1985  }
1986  rc_get_radius_port(packet_code, &server_port);
1987 }
1988 
1989 /** Update per-workflow statistics (number of transactions, rtt min, max, and cumulated).
1990  */
1992 {
1993  if (!trans || !trans->packet || !trans->reply) return;
1994  if (!wf_type || wf_type >= RC_WF_MAX) return;
1995 
1996  struct timeval tv_rtt;
1997  timersub(&trans->reply->timestamp, &trans->timestamp, &tv_rtt);
1998  /* The reference timestamp is that of the transaction, because several packets can be involved, e.g. EAP. */
1999 
2000  int i;
2001  for (i=0; i<2; i++) { /* update the specified workflow type, and also "All" (0) */
2002  rc_wf_stats_t *my_stats = &stats.wf_stats[i*wf_type];
2003 
2004  if ((0 == my_stats->num) || (timercmp(&tv_rtt, &my_stats->tv_rtt_min, <))) {
2005  my_stats->tv_rtt_min.tv_sec = tv_rtt.tv_sec;
2006  my_stats->tv_rtt_min.tv_usec = tv_rtt.tv_usec;
2007  }
2008  if ((0 == my_stats->num) || (timercmp(&tv_rtt, &my_stats->tv_rtt_max, >=))) {
2009  my_stats->tv_rtt_max.tv_sec = tv_rtt.tv_sec;
2010  my_stats->tv_rtt_max.tv_usec = tv_rtt.tv_usec;
2011  }
2012 
2013  timeradd(&my_stats->tv_rtt_cumul, &tv_rtt, &my_stats->tv_rtt_cumul);
2014  my_stats->num ++;
2015  }
2016 }
2017 
2018 /** Print per-workflow detailed statistics.
2019  */
2020 static void rc_print_wf_stats(FILE *fp)
2021 {
2022  /* ensure there is something to print */
2023  int i;
2024  int i_start = 0;
2025  int num_stat = 0;
2026  for (i=1; i<RC_WF_MAX; i++) {
2027  if (stats.wf_stats[i].num > 0) num_stat ++;
2028  }
2029  if (num_stat == 0) return;
2030 
2031  fprintf(fp, "*** Statistics (per-workflow):\n");
2032 
2033  if (num_stat == 1) i_start = 1; /* only print "All" if we have more than one (otherwise it's redundant). */
2034 
2035  for (i=i_start; i<RC_WF_MAX; i++) {
2036  rc_wf_stats_t *my_stats = &stats.wf_stats[i];
2037 
2038  if (my_stats->num == 0) continue;
2039 
2040  float avg_rtt = 1000 * rc_timeval_to_float(&my_stats->tv_rtt_cumul) / my_stats->num;
2041  float min_rtt = 1000 * rc_timeval_to_float(&my_stats->tv_rtt_min);
2042  float max_rtt = 1000 * rc_timeval_to_float(&my_stats->tv_rtt_max);
2043 
2044  /* Only print rate if scenario lasted at least a little time. */
2045  if (rc_get_elapsed() < 200) {
2046  fprintf(fp, "\t%-*.*s: nb: %d, RTT (ms): [avg: %.3f, min: %.3f, max: %.3f]\n",
2047  LG_PAD_WF_TYPES, LG_PAD_WF_TYPES, rc_wf_types[i], my_stats->num, avg_rtt, min_rtt, max_rtt);
2048  } else {
2049  fprintf(fp, "\t%-*.*s: nb: %d, RTT (ms): [avg: %.3f, min: %.3f, max: %.3f], rate (avg/s): %.3f\n",
2050  LG_PAD_WF_TYPES, LG_PAD_WF_TYPES, rc_wf_types[i], my_stats->num, avg_rtt, min_rtt, max_rtt,
2051  rc_get_wf_rate(i));
2052  }
2053  }
2054 }
2055 
2056 /** Do summary / statistics (if asked for).
2057  */
2058 static void rc_summary(void)
2059 {
2060  if (!do_summary) return;
2061 
2062  FILE *fp = stdout;
2063 
2064  fprintf(fp, "*** Statistics summary:\n");
2065 
2066  if (stats.nb_started == stats.nb_eap) {
2067  /* Only EAP. */
2068  fprintf(fp, "\t%-*.*s: %u\n", LG_PAD_STATS, LG_PAD_STATS, "EAP transactions", stats.nb_started);
2069  } else if (stats.nb_eap == 0) {
2070  /* No EAP. Label those as "Requests". */
2071  fprintf(fp, "\t%-*.*s: %u\n", LG_PAD_STATS, LG_PAD_STATS, "Requests", stats.nb_started);
2072  } else {
2073  /* Bit of both. */
2074  fprintf(fp, "\t%-*.*s: %u (with EAP: %u)\n", LG_PAD_STATS, LG_PAD_STATS, "Transactions", stats.nb_started, stats.nb_eap);
2075  }
2076 
2077  fprintf(fp, "\t%-*.*s: %u\n", LG_PAD_STATS, LG_PAD_STATS, "Success", stats.nb_success);
2078  fprintf(fp, "\t%-*.*s: %u\n", LG_PAD_STATS, LG_PAD_STATS, "Fail", stats.nb_fail);
2079  fprintf(fp, "\t%-*.*s: %u\n", LG_PAD_STATS, LG_PAD_STATS, "Lost", stats.nb_lost);
2080  fprintf(fp, "\t%-*.*s: %u (retries: %u)\n", LG_PAD_STATS, LG_PAD_STATS, "Packets sent", stats.nb_packets_sent, stats.nb_packets_retries);
2081  fprintf(fp, "\t%-*.*s: %u\n", LG_PAD_STATS, LG_PAD_STATS, "Packets received", stats.nb_packets_recv);
2082 
2083  rc_print_wf_stats(fp);
2084 }
2085 
2086 /** Get elapsed time (in ms).
2087  */
2088 static uint32_t rc_get_elapsed(void)
2089 {
2090  uint32_t u_ms_elapsed;
2091  struct timeval tv_elapsed;
2092 
2093  if (timerisset(&tv_end)) {
2094  timersub(&tv_end, &tv_start, &tv_elapsed);
2095  } else {
2096  struct timeval tv_now;
2097  gettimeofday(&tv_now, NULL);
2098  timersub(&tv_now, &tv_start, &tv_elapsed);
2099  }
2100 
2101  u_ms_elapsed = (tv_elapsed.tv_sec * 1000) + (tv_elapsed.tv_usec/1000);
2102 
2103  return u_ms_elapsed;
2104 }
2105 
2106 /** Compute the started transactions rate /s.
2107  */
2108 static float rc_get_start_rate(void)
2109 {
2110  uint32_t u_ms_elapsed = rc_get_elapsed();
2111 
2112  if (u_ms_elapsed > 0) { /* should always be the case, but just to be sure. */
2113  return (float)(num_started * 1000) / (float)u_ms_elapsed;
2114  }
2115  return 0;
2116 }
2117 
2118 /** Compute the rate /s of a given workflow type.
2119  */
2121 {
2122  rc_wf_stats_t *my_stats = &stats.wf_stats[i];
2123  uint32_t u_ms_elapsed = rc_get_elapsed();
2124 
2125  if (u_ms_elapsed > 0) { // should always be the case, just to be sure.
2126  return (float)(my_stats->num * 1000) / (float)u_ms_elapsed;
2127  }
2128  return 0;
2129 }
2130 
2131 /** Display simple progress statistics.
2132  */
2133 static void rc_do_progress_stat(void)
2134 {
2135  if (!do_output || !progress_interval) return;
2136 
2137  printf("STAT (%s):", ELAPSED);
2138 
2139  printf(" %.2f%%", (100 * (float)num_started / num_input));
2140  printf(", start: %u (on: %u, ok: %u, fail: %u, lost: %u)",
2141  num_started, num_ongoing, stats.nb_success, stats.nb_fail, stats.nb_lost);
2142 
2143  printf(", rate (/s): %.1f", rc_get_start_rate());
2144 
2145  printf("\n");
2146 }
2147 
2148 
2149 
2150 int main(int argc, char **argv)
2151 {
2152  char *p;
2153  int c;
2154  char *filename = NULL;
2155  FILE *fp;
2156  fr_dict_t *dict = NULL;
2157 
2158  static fr_log_t radclient_log = {
2159  .colourise = true,
2160  .fd = STDOUT_FILENO,
2161  .dst = L_DST_STDOUT,
2162  .file = NULL,
2163  };
2164 
2165  /*
2166  * We probably don't want to free the talloc autofree context
2167  * directly, so we'll allocate a new context beneath it, and
2168  * free that before any leak reports.
2169  */
2170  autofree = talloc_init("main");
2171 
2172  fr_debug_lvl = 0;
2173  fr_log_fp = stdout;
2174 
2175  set_radius_dir(autofree, RADIUS_DIR);
2176 
2177  while ((c = getopt(argc, argv, "46c:d:D:f:hn:o:p:qr:sS:t:vxX")) != EOF)
2178  {
2179  switch (c) {
2180  case '4':
2181  force_af = AF_INET;
2182  break;
2183 
2184  case '6':
2185  force_af = AF_INET6;
2186  break;
2187 
2188  case 'c':
2189  if (!isdigit((int) *optarg)) usage();
2190  recycle_count = atoi(optarg);
2191  if (recycle_count == 0) recycle_count = 1;
2192  break;
2193 
2194  case 'd':
2195  set_radius_dir(autofree, optarg);
2196  break;
2197 
2198  case 'D':
2199  main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg);
2200  break;
2201 
2202  case 'f':
2203  filename = optarg;
2204  break;
2205 
2206  case 'n':
2207  rate_limit = atoi(optarg);
2208  if (rate_limit == 0) usage();
2209  break;
2210 
2211  case 'o':
2212  progress_interval = atof(optarg);
2213  if (progress_interval < 0.1) usage();
2214  break;
2215 
2216  case 'p':
2217  parallel = atoi(optarg);
2218  if (parallel == 0) parallel = 1;
2219  if (parallel > 65536) parallel = 65536;
2220  break;
2221 
2222  case 'q':
2223  do_output = false;
2224  break;
2225 
2226  case 'x':
2227  rad_debug_lvl++;
2228  fr_debug_lvl++;
2229  break;
2230 
2231  case 'X':
2232 #if 0
2233  sha1_data_problems = 1; /* for debugging only */
2234 #endif
2235  break;
2236 
2237  case 'r':
2238  if (!isdigit((int) *optarg))
2239  usage();
2240  retries = atoi(optarg);
2241  break;
2242 
2243  case 's':
2244  do_summary = true;
2245  break;
2246 
2247  case 't':
2248  if (!isdigit((int) *optarg))
2249  usage();
2250  timeout = atof(optarg);
2251  break;
2252 
2253  case 'v':
2254  printf("%s: %s\n", progname, radiusd_version);
2255  exit(EXIT_SUCCESS);
2256 
2257  case 'S':
2258  fp = fopen(optarg, "r");
2259  if (!fp) {
2260  ERROR("Error opening %s: %s", optarg, fr_syserror(errno));
2261  exit(1);
2262  }
2263  if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
2264  ERROR("Error reading %s: %s",
2265  optarg, fr_syserror(errno));
2266  exit(1);
2267  }
2268  fclose(fp);
2269 
2270  /* truncate newline */
2271  p = filesecret + strlen(filesecret) - 1;
2272  while ((p >= filesecret) &&
2273  (*p < ' ')) {
2274  *p = '\0';
2275  --p;
2276  }
2277 
2278  if (strlen(filesecret) < 2) {
2279  ERROR("Secret in %s is too short", optarg);
2280  exit(1);
2281  }
2282  secret = filesecret;
2283  break;
2284 
2285  case 'h':
2286  default:
2287  usage();
2288  }
2289  }
2290  argc -= (optind - 1);
2291  argv += (optind - 1);
2292 
2293  if ((argc < 3) ||
2294  ((!secret) && (argc < 4))) {
2295  usage();
2296  }
2297 
2298  /* Initialize logging */
2299  if (!do_output) {
2300  rad_debug_lvl = 0;
2301  fr_debug_lvl = 0;
2302  radclient_log.dst = L_DST_NULL;
2303  radclient_log.fd = 0;
2304  }
2305  radlog_init(&radclient_log, false);
2306 
2307  /* Prepare progress report time. */
2308  rc_float_to_timeval(&tv_progress_interval, progress_interval);
2309 
2310  /* Prepare the timeout. */
2311  rc_float_to_timeval(&tv_timeout, timeout);
2312 
2313  if (!main_config.dictionary_dir) {
2314  main_config.dictionary_dir = DICTDIR;
2315  }
2316 
2317  /*
2318  * Read the distribution dictionaries first, then
2319  * the ones in raddb.
2320  */
2321  DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY);
2322  if (fr_dict_init(autofree, &dict, main_config.dictionary_dir, RADIUS_DICTIONARY, "radius") != 0) {
2323  ERROR("Errors reading dictionary: %s", fr_strerror());
2324  exit(1);
2325  }
2326 
2327  /*
2328  * It's OK if this one doesn't exist.
2329  */
2330  int rcode = fr_dict_read(dict, radius_dir, RADIUS_DICTIONARY);
2331  if (rcode == -1) {
2332  ERROR("Errors reading %s/%s: %s", radius_dir, RADIUS_DICTIONARY, fr_strerror());
2333  exit(1);
2334  }
2335 
2336  /*
2337  * We print this after reading it. That way if
2338  * it doesn't exist, it's OK, and we don't print
2339  * anything.
2340  */
2341  if (rcode == 0) {
2342  DEBUG2("Including dictionary file %s/%s", radius_dir, RADIUS_DICTIONARY);
2343  }
2344 
2345  /*
2346  * Get the request type
2347  */
2348  if (!isdigit((int) argv[2][0])) {
2349  packet_code = fr_str2int(fr_request_types, argv[2], -2);
2350  if (packet_code == -2) {
2351  ERROR("Unrecognised request type \"%s\"", argv[2]);
2352  usage();
2353  }
2354  } else {
2355  packet_code = atoi(argv[2]);
2356  }
2357 
2358  /*
2359  * Resolve hostname.
2360  */
2361  rc_resolve_hostname(argv[1]);
2362 
2363  /*
2364  * Add the secret.
2365  */
2366  if (argv[3]) secret = argv[3];
2367 
2368  /*
2369  * Read input data vp(s) from the file (or stdin).
2370  */
2371  INFO("Loading input data...");
2372  if (!rc_load_input(autofree, filename, &rc_vps_list_in, 0)
2373  || rc_vps_list_in.size == 0) {
2374  ERROR("No valid input. Nothing to send.");
2375  exit(EXIT_FAILURE);
2376  }
2377  INFO("Loaded: %d input element(s).", rc_vps_list_in.size);
2378 
2379  /* Initialize the packets list. */
2380  MEM(pl = fr_packet_list_create(1));
2381 
2382  /* Initialize the events list. */
2383  ev_list = fr_event_list_create(autofree, NULL);
2384  if (!ev_list) {
2385  ERROR("Failed to create event list");
2386  exit(1);
2387  }
2388 
2389  /* Keep track of elapsed time. */
2390  gettimeofday(&tv_start, NULL);
2391 
2392  /* Arm progress statistics */
2394 
2395  /*
2396  * Start main loop.
2397  */
2398  rc_main_loop();
2399 
2400  rc_do_progress_stat(); /* one last time. */
2401  gettimeofday(&tv_end, NULL);
2402 
2403  /*
2404  * Do summary / statistics (if asked for).
2405  */
2406  rc_summary();
2407 
2408  talloc_free(autofree);
2409 
2410  return 0;
2411 }
2412 
2413 
2414 
2415 /** Given a radius request with some attributes in the EAP range, build
2416  * them all into a single EAP-Message body.
2417  *
2418  * If there are multiple eligibles EAP-Type, the first one is picked.
2419  * Function returns 0 if no EAP is involved, or the EAP-Type otherwise.
2420  */
2422 {
2423  VALUE_PAIR *vp, *vpnext;
2424  int id, eapcode;
2425  int eap_method = 0;
2426 
2427  eap_packet_t *pt_ep = talloc_zero(req, eap_packet_t);
2428 
2429  vp = fr_pair_find_by_num(req->vps, 0, PW_EAP_ID, TAG_ANY);
2430  if (!vp) {
2431  id = ((int)getpid() & 0xff);
2432  } else {
2433  id = vp->vp_integer;
2434  }
2435 
2436  vp = fr_pair_find_by_num(req->vps, 0, PW_EAP_CODE, TAG_ANY);
2437  if (!vp) {
2438  eapcode = PW_EAP_REQUEST;
2439  } else {
2440  eapcode = vp->vp_integer;
2441  }
2442 
2443  for (vp = req->vps; vp != NULL; vp = vpnext) {
2444  /* save it in case it changes! */
2445  vpnext = vp->next;
2446 
2447  if (vp->da->attr >= PW_EAP_TYPE_BASE &&
2448  vp->da->attr < PW_EAP_TYPE_BASE+256) {
2449  break;
2450  }
2451  }
2452 
2453  if (!vp) {
2454  return 0;
2455  }
2456 
2457  eap_method = vp->da->attr - PW_EAP_TYPE_BASE;
2458 
2459  switch (eap_method) {
2460  case PW_EAP_IDENTITY:
2461  case PW_EAP_NOTIFICATION:
2462  case PW_EAP_NAK:
2463  case PW_EAP_MD5:
2464  case PW_EAP_OTP:
2465  case PW_EAP_GTC:
2466  case PW_EAP_TLS:
2467  case PW_EAP_LEAP:
2468  case PW_EAP_TTLS:
2469  case PW_EAP_PEAP:
2470  default:
2471  /*
2472  * no known special handling, it is just encoded as an
2473  * EAP-message with the given type.
2474  */
2475 
2476  /* nuke any existing EAP-Messages */
2477  fr_pair_delete_by_num(&req->vps, 0, PW_EAP_MESSAGE, TAG_ANY);
2478 
2479  pt_ep->code = eapcode;
2480  pt_ep->id = id;
2481  pt_ep->type.num = eap_method;
2482  pt_ep->type.length = vp->vp_length;
2483 
2484  pt_ep->type.data = talloc_memdup(vp, vp->vp_octets, vp->vp_length);
2485  talloc_set_type(pt_ep->type.data, uint8_t);
2486 
2487  eap_basic_compose(req, pt_ep);
2488  }
2489 
2490  return eap_method;
2491 }
2492 
2493 /** Given a radius request with an EAP-Message body, decode its specific
2494  * attributes.
2495  */
2497 {
2498  VALUE_PAIR *eap1;
2499  eap_packet_raw_t *e;
2500  int len;
2501  int type;
2502 
2503  if (!rep) return;
2504 
2505  /* find eap message */
2506  e = eap_vp2packet(NULL, rep->vps);
2507  if (!e) {
2508  ERROR("%s", fr_strerror());
2509  return;
2510  }
2511  /* create EAP-ID and EAP-CODE attributes to start */
2512  eap1 = fr_pair_afrom_num(rep, 0, PW_EAP_ID);
2513  eap1->vp_integer = e->id;
2514  fr_pair_add(&(rep->vps), eap1);
2515 
2516  eap1 = fr_pair_afrom_num(rep, 0, PW_EAP_CODE);
2517  eap1->vp_integer = e->code;
2518  fr_pair_add(&(rep->vps), eap1);
2519 
2520  switch (e->code) {
2521  default:
2522  case PW_EAP_SUCCESS:
2523  case PW_EAP_FAILURE:
2524  /* no data */
2525  break;
2526 
2527  case PW_EAP_REQUEST:
2528  case PW_EAP_RESPONSE:
2529  /* there is a type field, which we use to create
2530  * a new attribute */
2531 
2532  /* the length was decode already into the attribute
2533  * length, and was checked already. Network byte
2534  * order, just pull it out using math.
2535  */
2536  len = e->length[0]*256 + e->length[1];
2537 
2538  /* verify the length is big enough to hold type */
2539  if (len < 5)
2540  {
2541  talloc_free(e);
2542  return;
2543  }
2544 
2545  type = e->data[0];
2546 
2547  type += PW_EAP_TYPE_BASE;
2548  len -= 5;
2549 
2550  if (len > MAX_STRING_LEN) {
2551  len = MAX_STRING_LEN;
2552  }
2553 
2554  eap1 = fr_pair_afrom_num(rep, 0, type);
2555  fr_pair_value_memcpy(eap1, e->data + 1, len);
2556 
2557  fr_pair_add(&(rep->vps), eap1);
2558  break;
2559  }
2560 
2561  talloc_free(e);
2562  return;
2563 }
2564 
2566 {
2567  int ret;
2568 
2569  eap_packet_t *pt_ep = talloc_zero(r, eap_packet_t);
2570 
2571  ret = map_eapsim_basictypes(r, pt_ep);
2572 
2573  if (ret != 1) {
2574  return ret;
2575  }
2576 
2577  eap_basic_compose(r, pt_ep);
2578 
2579  return 1;
2580 }
2581 
2583 {
2584  VALUE_PAIR *esvp;
2585  uint8_t *eap_data;
2586  int rcode_unmap;
2587 
2588  esvp = fr_pair_find_by_num(r->vps, 0, PW_EAP_TYPE_BASE + PW_EAP_SIM, TAG_ANY);
2589  if (!esvp) {
2590  ERROR("eap: EAP-Sim attribute not found");
2591  return 0;
2592  }
2593 
2594  eap_data = talloc_memdup(esvp, esvp->vp_octets, esvp->vp_length);
2595  talloc_set_type(eap_data, uint8_t);
2596 
2597  rcode_unmap = unmap_eapsim_basictypes(r, eap_data, esvp->vp_length);
2598 
2599  talloc_free(eap_data);
2600  return rcode_unmap;
2601 }
2602 
static struct timeval tv_end
Definition: radeapclient.c:208
uint8_t id
Definition: eap_types.h:145
VALUE_PAIR has a single value.
Definition: pair.h:101
static fr_event_list_t * ev_list
list of armed events.
Definition: radeapclient.c:218
static void rc_resolve_hostname(char *server_arg)
Resolve server hostname.
static void rc_add_socket(fr_ipaddr_t *src_ipaddr, uint16_t src_port, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port)
Allocate a new socket, and add it to the packet list.
Structure which holds an input vps entry (read from file or stdin), and linkage to previous / next en...
Definition: radeapclient.c:115
int sockfd
Socket this packet was read from.
Definition: libradius.h:147
FILE * fr_log_fp
Definition: radius.c:81
void fr_pair_list_fprint(FILE *, VALUE_PAIR const *vp)
Print a list of attributes and enumv.
Definition: pair.c:2266
uint32_t nb_packets_recv
number of packets received
Definition: radeapclient.c:194
int id
Packet ID (used to link requests/responses).
Definition: libradius.h:154
struct timeval timestamp
When we received the packet.
Definition: libradius.h:159
int fr_radius_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original, char const *secret)
Calculate/check digest, and decode radius attributes.
Definition: radius.c:1485
uint32_t id
id of transaction (0 for the first one).
Definition: radeapclient.c:132
static char ch_elapsed[12+1]
Definition: radeapclient.c:219
static void rc_finish_transaction(rc_transaction_t *trans)
Terminate a transaction.
Definition: radeapclient.c:750
static void rc_float_to_timeval(struct timeval *tv, float f_val)
Convert a float to struct timeval.
Definition: radeapclient.c:353
struct rc_wf_stats rc_wf_stats_t
Structure which holds per-workflow statistics information.
RFC2865 - Access-Challenge.
Definition: radius.h:102
Main server configuration.
Definition: radiusd.h:108
rc_input_vps_t * tail
Definition: radeapclient.c:108
bool fr_packet_list_id_free(fr_packet_list_t *pl, RADIUS_PACKET *request, bool yank)
Definition: packet.c:830
rc_input_vps_t * prev
Definition: radeapclient.c:124
uint32_t nb_eap
number of EAP transactions started
Definition: radeapclient.c:188
static uint32_t num_input
number of input entries loaded.
Definition: radeapclient.c:209
static bool server_addr_init
Definition: radeapclient.c:225
int fr_dict_read(fr_dict_t *dict, char const *dir, char const *filename)
Definition: dict.c:2291
Dictionary attribute.
Definition: dict.h:77
int fr_inet_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
Wrappers for IPv4/IPv6 host to IP address lookup.
Definition: inet.c:127
Structure which holds per-workflow statistics information.
Definition: radeapclient.c:177
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
Definition: pair.c:106
static float rc_get_start_rate(void)
Compute the started transactions rate /s.
uint32_t fr_rand(void)
Return a 32-bit random number.
Definition: radius.c:1621
#define MEM(x)
Definition: radiusd.h:396
static int rc_load_input(TALLOC_CTX *ctx, char const *filename, rc_input_vps_list_t *list, uint32_t max_entries)
Load input entries (list of vps) from a file or stdin, and add them to the list.
Definition: radeapclient.c:435
static char const * radius_dir
Definition: radeapclient.c:76
fr_ipaddr_t src_ipaddr
Src IP address of packet.
Definition: libradius.h:149
#define EAPSIM_AUTH_SIZE
Definition: eap_sim.h:84
RADIUS_PACKET ** fr_packet_list_find_byreply(fr_packet_list_t *pl, RADIUS_PACKET *reply)
Definition: packet.c:514
static int rc_send_transaction_packet(rc_transaction_t *trans, RADIUS_PACKET **packet_p)
Send current packet of a transaction.
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
Definition: inet.h:47
#define INFO(fmt,...)
Definition: log.h:143
static char const * name
static void rc_deallocate_id(rc_transaction_t *trans)
Deallocate RADIUS packet ID.
static void rc_evcb_packet_timeout(void *ctx, UNUSED struct timeval *now)
Event callback: packet timeout.
#define vp_octets
Definition: pair.h:170
#define LG_PAD_WF_TYPES
Definition: radeapclient.c:165
static uint32_t num_started
number of transactions started.
Definition: radeapclient.c:211
static int ipproto
Definition: radeapclient.c:223
#define VERIFY_VP(_x)
Definition: pair.h:44
#define UNUSED
Definition: libradius.h:134
eapsim_clientstates
Definition: eap_sim.h:42
void fr_md5_init(FR_MD5_CTX *ctx)
Initialise a new MD5 context.
Definition: md5.c:84
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
Definition: libradius.h:162
#define PW_AUTH_UDP_PORT_ALT
Definition: radius.h:115
union rc_eap_context::@14 eap
#define USEC
Definition: radeapclient.c:48
uint8_t code
Definition: eap_types.h:144
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
Definition: missing.c:538
eap_packet_raw_t * eap_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps)
Definition: eapcommon.c:297
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
Definition: cursor.c:60
struct timeval tv_rtt_max
Definition: radeapclient.c:181
int fr_radius_send(RADIUS_PACKET *, RADIUS_PACKET const *, char const *secret)
Reply to the request.
Definition: radius.c:506
struct rc_eap_sim_context rc_eap_sim_context_t
Structure which contains EAP context, necessary to perform the full EAP transaction.
rc_input_vps_t * head
Definition: radeapclient.c:107
#define STATS_INC(_stat_type)
Definition: radeapclient.c:200
static char const * hostname(char *buf, size_t buflen, uint32_t ipaddr)
Definition: radwho.c:149
valuepair value must be xlat expanded when it's added to VALUE_PAIR tree.
Definition: pair.h:102
uint8_t * data
Packet data (body).
Definition: libradius.h:160
VALUE_PAIR * fr_pair_list_copy_by_num(TALLOC_CTX *ctx, VALUE_PAIR *from, unsigned int vendor, unsigned int attr, int8_t tag)
Copy matching pairs.
Definition: pair.c:1428
static char filesecret[256]
Definition: radeapclient.c:73
fr_event_list_t * fr_event_list_create(TALLOC_CTX *ctx, fr_event_status_t status)
Definition: event.c:120
struct rc_eap_md5_context rc_eap_md5_context_t
uint16_t dst_port
DST Port of packet.
Definition: libradius.h:152
#define LG_PAD_STATS
Definition: radeapclient.c:164
uint32_t nb_fail
number of failed transactions
Definition: radeapclient.c:190
uint16_t src_port
Src port of packet.
Definition: libradius.h:151
fr_ipaddr_t dst_ipaddr
Dst IP address of packet.
Definition: libradius.h:150
RADIUS_PACKET * reply
Definition: radeapclient.c:138
int fr_debug_lvl
Definition: misc.c:40
eap_type_data_t type
Definition: eap_types.h:136
static uint32_t rc_rate_limit(bool *do_limit)
Compute maximum number of new requests that can be started while conforming to the specified rate lim...
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
Definition: pair.h:144
static char * rc_print_elapsed(char *out, uint8_t decimals)
Print a elapsed time buffer (SS.uuuuuu).
Definition: radeapclient.c:306
uint32_t recycle
number of times this input has been used to start a transaction.
Definition: radeapclient.c:122
struct value_pair * next
Definition: pair.h:116
static void NEVER_RETURNS usage(void)
Display usage and exit.
Definition: radeapclient.c:248
static int force_af
Definition: radeapclient.c:222
static uint32_t rate_limit
Definition: radeapclient.c:65
RFC2866 - Accounting-Response.
Definition: radius.h:96
FR_NAME_NUMBER const fr_request_types[]
Definition: radius.c:52
rc_input_vps_t * input_vps
Definition: radeapclient.c:140
RADIUS_PACKET * packet
Definition: radeapclient.c:137
struct timeval tv_rtt_min
Definition: radeapclient.c:180
void fr_md5_update(FR_MD5_CTX *ctx, uint8_t const *in, size_t inlen) CC_BOUNDED(__string__
static void rc_summary(void)
Do summary / statistics (if asked for).
RFC2865 - Access-Reject.
Definition: radius.h:94
RFC3575/RFC5176 - CoA-Ack (positive)
Definition: radius.h:109
static int rc_send_one_packet(rc_transaction_t *trans, RADIUS_PACKET **packet_p)
Send one packet for a transaction.
int af
Address family.
Definition: inet.h:42
Vendors and attribute names.
Definition: dict.c:61
#define PW_DIGEST_ATTRIBUTES
Definition: radius.h:165
RFC2865 - Access-Request.
Definition: radius.h:92
int fr_str2int(FR_NAME_NUMBER const *table, char const *name, int def)
Definition: token.c:451
eap_type_t num
Definition: eap_types.h:122
static float timeout
Definition: radeapclient.c:67
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Definition: log.c:238
Structure which holds a transaction: sent packet, reply received...
Definition: radeapclient.c:131
uint32_t nb_lost
number of packets to which we received no response
Definition: radeapclient.c:191
#define EAP_SIM_VERSION
Definition: eap_sim.h:31
int unmap_eapsim_basictypes(RADIUS_PACKET *r, uint8_t *attr, unsigned int attrlen)
Definition: eapsimlib.c:284
VALUE_PAIR * fr_pair_list_copy(TALLOC_CTX *ctx, VALUE_PAIR *from)
Copy a pairlist.
Definition: pair.c:1394
int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set)
Definition: packet.c:874
#define PW_COA_UDP_PORT
Definition: radius.h:120
static int rc_respond_eap_md5(rc_eap_context_t *eap_context, RADIUS_PACKET *req, RADIUS_PACKET *rep)
#define DEBUG(fmt,...)
Definition: log.h:175
char const * radiusd_version
Definition: radeapclient.c:57
int fr_radius_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original, char const *secret)
Verify the Request/Response Authenticator (and Message-Authenticator if present) of a packet...
Definition: radius.c:1144
static char * rc_print_hexstr(char *pch_out, const uint8_t *in, int size, int separ_i, char sep)
Print a "hexstring" buffer (with optional separator each N octets)
Definition: radeapclient.c:333
void fr_packet_header_print(FILE *fp, RADIUS_PACKET *packet, bool received)
Definition: packet.c:962
uint8_t id
Definition: eap_types.h:134
eap_method
Definition: eap_types.h:45
Structure to represent packet format of eap on wire
Definition: eap_types.h:143
uint32_t num
The number (within the file) of the input we're reading.
Definition: radeapclient.c:116
int sha1_data_problems
static int rc_recv_one_packet(struct timeval *tv_wait_time)
Receive one packet, maybe.
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *vp)
Add a VP to the end of the list.
Definition: pair.c:659
static bool do_summary
Definition: radeapclient.c:72
static void rc_do_progress_stat(void)
Display simple progress statistics.
#define DEBUG2(fmt,...)
Definition: log.h:176
RFC2866 - Accounting-Request.
Definition: radius.h:95
#define STRINGIFY(x)
Definition: build.h:34
static void rc_wf_stat_update(rc_transaction_t *trans, rc_wf_type_t wf_type)
Update per-workflow statistics (number of transactions, rtt min, max, and cumulated).
RADIUS_PACKET * fr_radius_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new RADIUS_PACKET.
Definition: radius.c:1651
static rc_stats_t stats
Definition: radeapclient.c:206
static rc_input_vps_t * rc_yank_vps_entry(rc_input_vps_t *entry)
Remove a selected rc_input_vps_t entry from its current list.
Definition: radeapclient.c:391
unsigned int attr
Attribute number.
Definition: dict.h:79
static float rc_get_wf_rate(rc_wf_type_t i)
Compute the rate /s of a given workflow type.
static uint32_t num_trans
number of transactions initialized.
Definition: radeapclient.c:210
static void rc_cleanresp(RADIUS_PACKET *resp)
Definition: radeapclient.c:775
union fr_ipaddr_t::@1 ipaddr
static int packet_code
Definition: radeapclient.c:227
RFC3575/RFC5176 - CoA-Nak (not willing to perform)
Definition: radius.h:110
int eapsim_checkmac(TALLOC_CTX *ctx, VALUE_PAIR *rvps, uint8_t key[8], uint8_t *extra, int extralen, uint8_t calcmac[20])
unsigned int code
Packet code (type).
Definition: libradius.h:155
rc_input_vps_list_t * list
the list to which this entry belongs (NULL for an unchained entry).
Definition: radeapclient.c:120
char password[256]
copy of User-Password (or CHAP-Password).
Definition: radeapclient.c:96
struct timeval tv_rtt_cumul
Definition: radeapclient.c:179
static void rc_unmap_eap_methods(RADIUS_PACKET *rep)
Given a radius request with an EAP-Message body, decode its specific attributes.
int map_eapsim_basictypes(RADIUS_PACKET *r, eap_packet_t *ep)
Definition: eapsimlib.c:63
RFC2865 - Access-Accept.
Definition: radius.h:93
static void rc_evprep_progress_stat(void)
Prepare event: report progress statistics.
static unsigned int num_sockets
number of allocated sockets.
Definition: radeapclient.c:217
#define RADIUS_DICTIONARY
Definition: conf.h:7
unsigned int vendor
Vendor that defines this attribute.
Definition: dict.h:78
Definition: log.h:68
static uint32_t num_ongoing
number of ongoing transactions.
Definition: radeapclient.c:212
Stores an attribute, a value and various bits of other data.
Definition: pair.h:112
char const * sim_state2name(enum eapsim_clientstates state, char *buf, int buflen)
Definition: eapsimlib.c:437
static rc_transaction_t * rc_init_transaction(TALLOC_CTX *ctx)
Grab an element from the input list.
Definition: radeapclient.c:701
size_t length
Definition: eap_types.h:123
static void rc_build_eap_context(rc_transaction_t *trans)
Map EAP methods and build EAP-Message (if EAP is involved).
Definition: radeapclient.c:668
static struct timeval tv_progress_interval
Definition: radeapclient.c:75
static struct timeval tv_start
Definition: radeapclient.c:207
char password[256]
Definition: radeapclient.c:148
static PW_CODE rc_get_code(uint16_t port)
Resolve a port to a request type.
#define PW_ACCT_UDP_PORT_ALT
Definition: radius.h:117
uint8_t length[2]
Definition: eap_types.h:146
uint8_t data[1]
Definition: eap_types.h:147
fr_packet_list_t * fr_packet_list_create(int alloc_id)
Definition: packet.c:464
enum rlm_rcodes rlm_rcode_t
Return codes indicating the result of the module call.
int main(int argc, char **argv)
RFC3575/RFC5176 - CoA-Request.
Definition: radius.h:108
void eapsim_dump_mk(struct eapsim_keys *ek)
Definition: eapcrypto.c:103
uint8_t vector[AUTH_VECTOR_LEN]
RADIUS authentication vector.
Definition: libradius.h:157
char const * fr_strerror(void)
Get the last library error.
Definition: log.c:212
static uint32_t num_finished
number of finished transactions.
Definition: radeapclient.c:213
int fr_event_run(fr_event_list_t *el, struct timeval *when)
Definition: event.c:266
int radlog_init(fr_log_t *log, bool daemonize)
Initialise file descriptors based on logging destination.
Definition: log.c:257
static int rc_process_eap_challenge(rc_eap_context_t *eap_context, RADIUS_PACKET *req, RADIUS_PACKET *rep)
We got an EAP-Request/Sim/Challenge message in a legal state.
Definition: radeapclient.c:977
#define DEBUG4(fmt,...)
Definition: log.h:178
static char const * progname
Definition: radeapclient.c:54
void fr_pair_delete_by_num(VALUE_PAIR **head, unsigned int vendor, unsigned int attr, int8_t tag)
Delete matching pairs.
Definition: pair.c:797
static void rc_main_loop(void)
Main loop: Handle events.
uint32_t num
Definition: radeapclient.c:178
Packet code has not been set.
Definition: radius.h:91
static uint32_t rc_get_elapsed(void)
Get elapsed time (in ms).
Structure which holds global statistics information.
Definition: radclient.h:52
unsigned int state
Definition: proto_bfd.c:200
static uint32_t rc_loop_recv(void)
Receive loop.
#define PW_POD_UDP_PORT
Definition: radius.h:118
static bool do_output
Definition: radeapclient.c:71
static void rc_print_wf_stats(FILE *fp)
Print per-workflow detailed statistics.
main_config_t main_config
Main server configuration.
Definition: radeapclient.c:55
static float progress_interval
Definition: radeapclient.c:74
static int rc_map_eapsim_types(RADIUS_PACKET *r)
void fr_pair_value_memsteal(VALUE_PAIR *vp, uint8_t const *src)
Reparent an allocated octet buffer to a VALUE_PAIR.
Definition: pair.c:1933
#define TAG_ANY
Definition: pair.h:191
value_type_t type
Type of pointer in value union.
Definition: pair.h:132
uint32_t nb_packets_sent
number of packets sent (including retransmissions)
Definition: radeapclient.c:192
static int rc_respond_eap_sim(rc_eap_context_t *eap_context, RADIUS_PACKET *req, RADIUS_PACKET *resp)
This runs the EAP-SIM client state machine.
char const * sim_subtype2name(enum eapsim_subtype subtype, char *buf, int buflen)
Definition: eapsimlib.c:459
static rc_input_vps_list_t rc_vps_list_in
list of available input vps entries.
Definition: radeapclient.c:215
int fr_socket(fr_ipaddr_t *ipaddr, uint16_t port)
Definition: packet.c:136
static uint16_t rc_getport(char const *name)
Get port number for a given service name.
bool fr_packet_list_id_alloc(fr_packet_list_t *pl, int proto, RADIUS_PACKET **request_p, void **pctx)
Definition: packet.c:611
log_lvl_t rad_debug_lvl
Global debugging level.
Definition: log.c:49
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
Definition: cursor.c:263
int fr_pair_list_afrom_file(TALLOC_CTX *ctx, VALUE_PAIR **out, FILE *fp, bool *pfiledone)
Definition: pair.c:1333
static uint32_t rc_loop_events(void)
Trigger all armed events for which time is reached.
void fr_radius_free(RADIUS_PACKET **)
Free a RADIUS_PACKET.
Definition: radius.c:1727
fr_event_t * event
armed event (if any).
Definition: radeapclient.c:146
int eap_type
contains the EAP-Type
Definition: radeapclient.c:95
static uint32_t parallel
Definition: radeapclient.c:64
uint32_t nb_success
number of successful transactions
Definition: radeapclient.c:189
uint32_t nb_started
number of transactions started
Definition: radeapclient.c:187
void eapsim_calculate_keys(struct eapsim_keys *ek)
Definition: eapcrypto.c:37
static void rc_evcb_progress_stat(void UNUSED *ctx, UNUSED struct timeval *now)
Event callback: report progress statistics.
rlm_rcode_t process_authorize(UNUSED int type, UNUSED REQUEST *request)
Definition: radeapclient.c:281
#define EAPSIM_SRES_SIZE
Definition: eap_sim.h:79
rc_input_vps_t * next
Definition: radeapclient.c:125
int rad_virtual_server(REQUEST UNUSED *request)
Definition: radeapclient.c:275
char const * dictionary_dir
Where to load dictionaries from.
Definition: radiusd.h:142
#define ELAPSED
Definition: radeapclient.c:220
#define EAPSIM_CALCMAC_SIZE
Definition: eap_sim.h:82
Structure which contains EAP context, necessary to perform the full EAP transaction.
Definition: radeapclient.c:86
#define PW_AUTH_UDP_PORT
Definition: radius.h:114
struct eapsim_keys keys
Definition: radeapclient.c:87
int eap_basic_compose(RADIUS_PACKET *packet, eap_packet_t *reply)
Definition: eapcommon.c:191
static void rc_get_radius_port(PW_CODE type, uint16_t *port)
Set a port from the request type if we don't already have one.
rc_wf_stats_t wf_stats[RC_WF_MAX]
Definition: radeapclient.c:196
uint32_t num_packet
number of packets sent for this transaction.
Definition: radeapclient.c:134
VALUE_PAIR * fr_pair_find_by_num(VALUE_PAIR *head, unsigned int vendor, unsigned int attr, int8_t tag)
Find the pair with the matching attribute.
Definition: pair.c:639
bool fr_packet_list_socket_add(fr_packet_list_t *pl, int sockfd, int proto, fr_ipaddr_t *dst_ipaddr, uint16_t dst_port, void *ctx)
Definition: packet.c:356
Discard log messages.
Definition: log.h:63
static char const * rc_wf_types[RC_WF_MAX]
Definition: radeapclient.c:167
static void rc_evprep_packet_timeout(rc_transaction_t *trans)
Prepare event: packet timeout.
int fr_event_delete(fr_event_list_t *el, fr_event_t **parent)
Definition: event.c:172
VALUE_PAIR * fr_cursor_remove(vp_cursor_t *cursor)
Remove the current pair.
Definition: cursor.c:433
static uint16_t server_port
Definition: radeapclient.c:226
RFC2865/RFC5997 - Status Server (request)
Definition: radius.h:103
rc_wf_type_t
Define workflow types (transactions for which we got a response)
Definition: radeapclient.c:155
void void fr_md5_final(uint8_t out[MD5_DIGEST_LENGTH], FR_MD5_CTX *ctx) CC_BOUNDED(__minbytes__
Structure to hold EAP data.
Definition: eap_types.h:132
uint32_t tries
Definition: radeapclient.c:144
static unsigned int retries
Definition: radeapclient.c:66
size_t strlcpy(char *dst, char const *src, size_t siz)
Definition: strlcpy.c:38
static char const * secret
Definition: radeapclient.c:70
IPv4/6 prefix.
Definition: inet.h:41
static float rc_timeval_to_float(struct timeval *tv)
Convert a struct timeval to float.
Definition: radeapclient.c:362
struct timeval timestamp
when the transaction is started.
Definition: radeapclient.c:136
struct rc_eap_context rc_eap_context_t
PW_CODE
RADIUS packet codes.
Definition: radius.h:90
bool colourise
Prefix log messages with VT100 escape codes to change text colour.
Definition: log.h:69
static fr_packet_list_t * pl
list of outgoing packets.
Definition: radeapclient.c:216
uint32_t fr_packet_list_num_outgoing(fr_packet_list_t *pl)
Definition: packet.c:952
static fr_ipaddr_t server_ipaddr
Definition: radeapclient.c:224
static TALLOC_CTX * autofree
Definition: radeapclient.c:205
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
Definition: pair.h:113
eapsim_subtype
Definition: eap_sim.h:33
rc_eap_context_t * eap_context
Definition: radeapclient.c:142
Structure which holds a list of available input vps.
Definition: radeapclient.c:106
static void rc_add_vps_entry(rc_input_vps_list_t *list, rc_input_vps_t *entry)
Add an allocated rc_input_vps_t entry to the tail of the list.
Definition: radeapclient.c:369
log_dst_t dst
Log destination.
Definition: log.h:72
#define MAX_STRING_LEN
Definition: libradius.h:120
static uint32_t rc_loop_start_transactions(void)
Loop starting new transactions, until a limit is reached (max parallelism, or no more input available...
fr_dict_attr_t const * fr_dict_attr_by_num(fr_dict_t *dict, unsigned int vendor, unsigned int attr)
Lookup a fr_dict_attr_t by its vendor and attribute numbers.
Definition: dict.c:3519
static int rc_map_eap_methods(RADIUS_PACKET *req)
Given a radius request with some attributes in the EAP range, build them all into a single EAP-Messag...
#define NEVER_RETURNS
Definition: libradius.h:133
void fr_pair_replace(VALUE_PAIR **head, VALUE_PAIR *add)
Replace all matching VPs.
Definition: pair.c:696
Log to stdout.
Definition: log.h:58
int fr_event_insert(fr_event_list_t *el, fr_event_callback_t callback, void *ctx, struct timeval *when, fr_event_t **parent)
Definition: event.c:204
#define PW_ACCT_UDP_PORT
Definition: radius.h:116
static int rc_unmap_eapsim_types(RADIUS_PACKET *r)
#define RCSID(id)
Definition: build.h:135
char const * name
Test name (as specified in the request).
Definition: radeapclient.c:149
static int r
Definition: rbmonkey.c:66
char * talloc_typed_strdup(void const *t, char const *p)
Call talloc strdup, setting the type on the new chunk correctly.
Definition: missing.c:588
VALUE_PAIR * vps_in
the list of attribute/value pairs.
Definition: radeapclient.c:118
int fd
File descriptor to write messages to.
Definition: log.h:71
#define EAPSIM_RAND_SIZE
Definition: eap_sim.h:80
static int rc_init_packet(rc_transaction_t *trans)
Perform packet initialization for a transaction.
Definition: radeapclient.c:495
#define ERROR(fmt,...)
Definition: log.h:145
eap_code_t code
Definition: eap_types.h:133
#define RADIUS_DIR
Definition: conf.h:3
RADIUS_PACKET * fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set)
Definition: packet.c:901
#define fr_packet2myptr(TYPE, MEMBER, PTR)
Definition: packet.h:77
void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t len)
Copy data into an "octets" data type.
Definition: pair.c:1905
int fr_dict_init(TALLOC_CTX *ctx, fr_dict_t **out, char const *dir, char const *fn, char const *name)
(re)initialize a protocol dictionary
Definition: dict.c:2148
uint32_t nb_packets_retries
number of packets retransmissions
Definition: radeapclient.c:193
int fr_event_list_num_elements(fr_event_list_t *el)
Definition: event.c:164
static struct timeval tv_timeout
Definition: radeapclient.c:68
void set_radius_dir(TALLOC_CTX *ctx, char const *path)
Set the global radius config directory.
Definition: radeapclient.c:291
struct rc_stats rc_stats_t
Structure which holds global statistics information.
uint8_t * data
Definition: eap_types.h:124
static unsigned int recycle_count
Definition: radeapclient.c:69
static int rc_process_eap_start(rc_eap_context_t *eap_context, RADIUS_PACKET *req, RADIUS_PACKET *rep)
We got an EAP-Request/Sim/Start message in a legal state.
Definition: radeapclient.c:805
RFC3575/RFC5176 - Disconnect-Request.
Definition: radius.h:105
static USES_APPLE_DEPRECATED_API char trans[64]
Definition: rlm_unix.c:58