25 RCSID(
"$Id: 93369c86fc1f08a85b1ad0d6cbb83e6b1bd04346 $")
27 #include <freeradius-devel/libradius.h>
36 #include <freeradius-devel/conf.h>
37 #include <freeradius-devel/md5.h>
43 # include <freeradius-devel/tls.h>
58 #ifdef RADIUSD_VERSION_COMMIT
59 " (git #" STRINGIFY(RADIUSD_VERSION_COMMIT)
")"
61 ", built on " __DATE__
" at " __TIME__;
164 #define LG_PAD_STATS 20
165 #define LG_PAD_WF_TYPES 25
169 "Access-Request - Accept",
171 "EAP Request - Success",
172 "Accounting-Request - Response"
200 #define STATS_INC(_stat_type) { \
201 stats._stat_type ++; \
220 #define ELAPSED rc_print_elapsed(ch_elapsed, 3)
250 fprintf(stdout,
"Usage: radeapclient [options] server[:port] <command> [<secret>]\n");
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");
296 memcpy(&p, &radius_dir,
sizeof(p));
300 if (path) radius_dir = talloc_strdup(ctx, path);
308 if (!out || !timerisset(&
tv_start))
return NULL;
310 if (decimals > 6) decimals = 6;
312 struct timeval tv_now;
313 struct timeval tv_delta;
315 gettimeofday(&tv_now, NULL);
316 timersub(&tv_now, &
tv_start, &tv_delta);
318 uint32_t u_sec = (uint32_t)(tv_delta.tv_sec);
319 sprintf(out,
"%d", u_sec);
324 sprintf(buffer,
".%06d", (
int) tv_delta.tv_usec);
325 strncat(out, buffer, decimals+1);
333 static char *
rc_print_hexstr(
char *pch_out,
const uint8_t *in,
int size,
int separ_i,
char sep)
337 for (i = 0; i < size; i++) {
338 if ((separ_i) && (j == separ_i)) {
344 sprintf(pch_out,
"%02x", in[i]);
355 tv->tv_sec = (time_t)f_val;
356 uint64_t usec = (uint64_t)(f_val *
USEC) - (tv->tv_sec *
USEC);
364 return ((
float)tv->tv_sec + ((
float)tv->tv_usec /
USEC));
371 if (!list || !entry)
return;
374 assert(list->
tail == NULL);
378 assert(list->
tail != NULL);
393 if (!entry)
return NULL;
395 if (!entry->
list)
return entry;
404 assert(list->
head != NULL);
405 assert(list->
tail != NULL);
408 assert(list->
head != entry);
412 assert(list->
head == entry);
417 assert(list->
tail != entry);
421 assert(list->
tail == entry);
437 FILE *file_in = NULL;
438 bool file_done =
false;
441 uint32_t input_num = 0;
444 if (filename && strcmp(filename,
"-") != 0) {
445 DEBUG2(
"Opening input file: %s", filename);
446 file_in = fopen(filename,
"r");
448 ERROR(
"Error opening %s: %s", filename, strerror(errno));
453 DEBUG2(
"Reading input vps from stdin");
464 ERROR(
"Error parsing entry %u from input: %s", input_num, input);
465 talloc_free(request);
468 if (NULL == request->
vps_in) {
470 talloc_free(request);
479 if (max_entries && list->
size >= max_entries) {
483 }
while (!file_done);
485 if (file_in != stdin) fclose(file_in);
488 num_input += list->
size;
489 DEBUG(
"Read %d element(s) from input: %s", list->
size, input);
497 if (!trans || !trans->
packet)
return 0;
515 vp->vp_strvalue = vp->xlat;
516 vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
528 packet->
code = vp->vp_integer;
531 case PW_PACKET_DST_PORT:
532 packet->
dst_port = (vp->vp_integer & 0xffff);
535 case PW_PACKET_DST_IP_ADDRESS:
541 case PW_PACKET_DST_IPV6_ADDRESS:
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);
552 packet->
src_port = (vp->vp_integer & 0xffff);
556 case PW_PACKET_SRC_IP_ADDRESS:
562 case PW_PACKET_SRC_IPV6_ADDRESS:
568 case PW_DIGEST_REALM:
569 case PW_DIGEST_NONCE:
570 case PW_DIGEST_METHOD:
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:
583 p = talloc_array(vp, uint8_t, vp->vp_length + 2);
585 memcpy(p + 2, vp->vp_octets, vp->vp_length);
586 p[0] = vp->
da->
attr - PW_DIGEST_REALM + 1;
588 p[1] = vp->vp_length;
592 ERROR(
"Attribute 'Digest-Attributes' not found by value");
606 memcpy(&q, &vp->vp_octets,
sizeof(q));
609 vp->vp_octets = talloc_steal(vp, p);
619 case PW_USER_PASSWORD:
620 case PW_CHAP_PASSWORD:
621 case PW_MS_CHAP_PASSWORD:
625 case PW_RADCLIENT_TEST_NAME:
626 trans->
name = vp->vp_strvalue;
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);
644 DEBUG(
"No packet type was given, and input entry %u did not contain Packet-Type, ignored.", trans->
input_vps->
num);
654 DEBUG(
"Can't determine destination port for input entry %u, ignored.", trans->
input_vps->
num);
670 if (!trans || !trans->
packet)
return;
703 if (!rc_vps_list_in.
head || rc_vps_list_in.
size == 0) {
717 trans->
id = num_trans ++;
719 talloc_steal(trans, vps_entry);
758 if (vps_entry->
recycle < recycle_count) {
760 talloc_steal(autofree, vps_entry);
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))
809 VALUE_PAIR *anyidreq_vp, *fullauthidreq_vp, *permanentidreq_vp;
810 uint16_t
const *versions;
811 uint16_t selectedversion;
812 unsigned int i,versioncount;
818 ERROR(
"illegal start message has no VERSION_LIST");
822 versions = (uint16_t
const *) vp->vp_strvalue;
825 if (vp->vp_length < 4)
827 ERROR(
"start message has illegal VERSION_LIST. Too short: %u", (
unsigned int) vp->vp_length);
831 versioncount = ntohs(versions[0])/2;
835 if ((
unsigned)vp->vp_length <= (versioncount*2 + 2))
837 ERROR(
"start message is too short. Claimed %d versions does not fit in %u bytes", versioncount, (
unsigned int) vp->vp_length);
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);
852 for (i=0; i < versioncount; i++)
860 if (selectedversion == 0)
863 for (i=0; i < versioncount; i++)
865 ERROR(
"\tfound version %d",
866 ntohs(versions[i+1]));
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 "));
899 uint16_t no_versions;
901 no_versions = htons(selectedversion);
908 memcpy(eap_context->
eap.sim.keys.versionselect, &no_versions, 2);
926 p = talloc_zero_array(newvp, uint8_t, 18);
927 memcpy(&p[2], nonce, 16);
933 memcpy(eap_context->
eap.sim.keys.nonce_mt, nonce, 16);
947 ERROR(
"eap-sim: We need to have a User-Name attribute!");
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);
962 memcpy(eap_context->
eap.sim.keys.identity, vp->vp_strvalue, idlen);
963 eap_context->
eap.sim.keys.identitylen = idlen;
989 if (!mac || !randvp) {
990 ERROR(
"Challenge message needs to contain RAND and MAC");
1000 uint8_t
const *randcfg[3];
1002 randcfg[0] = &randvp->vp_octets[2];
1010 if (!randcfgvp[0] ||
1013 ERROR(
"Need to have RAND 1, 2 and 3 set");
1023 ERROR(
"one of RAND 1, 2, or 3 didn't match");
1026 for (rnum = 0; rnum < 3; rnum++) {
1028 ERROR(
"Received rand %d: %s", rnum, ch_rand);
1031 ERROR(
"Configured rand %d: %s", rnum, ch_rand);
1051 ERROR(
"Need to have SRES 1, 2, and 3 set");
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]));
1065 ERROR(
"Need to have Kc 1, 2, and 3 set");
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]));
1081 eap_context->
eap.sim.keys.nonce_mt,
sizeof(eap_context->
eap.sim.keys.nonce_mt),
1088 DEBUG2(
"MAC check succeeded (%s)", ch_calc_mac);
1091 ERROR(
"Challenge MAC check failed. Calculated MAC (%s) did not match", ch_calc_mac);
1138 char statenamebuf[32], subtypenamebuf[32];
1162 state = statevp->vp_integer;
1173 subtype = vp->vp_integer;
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);
1209 ERROR(
"sim in state %s message %s is illegal. Reply dropped.",
1218 ERROR(
"sim in illegal state '%s' (%d)",
1219 sim_state2name(state, statenamebuf,
sizeof(statenamebuf)), state);
1225 ERROR(
"EAP process failed, aborting EAP-SIM transaction.");
1239 statevp->vp_integer = newstate;
1249 uint8_t
const *value;
1251 uint8_t response[16];
1257 ERROR(
"no state attribute found");
1263 ERROR(
"no EAP-ID attribute found");
1266 identifier =
id->vp_integer;
1270 ERROR(
"no EAP-MD5 attribute found");
1275 valuesize = vp->vp_octets[0];
1276 value = &vp->vp_octets[1];
1279 if (valuesize > vp->vp_length)
1281 ERROR(
"md5 valuesize if too big (%u > %u)",
1282 (
unsigned int) valuesize, (
unsigned int) vp->vp_length);
1298 uint8_t lg_response;
1303 p = talloc_zero_array(vp, uint8_t, 17);
1305 memcpy(p, &lg_response, 1);
1306 memcpy(p + 1, response, 16);
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));
1332 INFO(
"Adding new socket: src: %s:%d, dst: %s:%d", src_addr, src_port, dst_addr, dst_port);
1334 mysockfd =
fr_socket(src_ipaddr, src_port);
1346 DEBUG(
"Added new socket: %d (num sockets: %d)", mysockfd, num_sockets);
1353 if (!trans || !packet_p || !*packet_p)
return -1;
1359 if (packet->
id == -1) {
1366 assert(trans->
reply == NULL);
1370 int nb_sock_add = 0;
1378 if (nb_sock_add >= 1) {
1379 ERROR(
"Added %d new socket(s), but still could not get an ID (currently: %d outgoing requests).",
1390 assert(packet->
id != -1);
1391 assert(packet->
data == NULL);
1393 for (i = 0; i < 4; i++) {
1401 DEBUG(
"Transaction: %u, sending packet: %u (id: %u)...", trans->
id, trans->
num_packet, packet->
id);
1406 ERROR(
"Failed to send packet (sockfd: %d, id: %d): %s",
1427 if (!trans || !packet_p || !*packet_p)
return -1;
1441 if (!trans || !trans->
packet ||
1448 DEBUG2(
"Deallocating (sockfd: %d, id: %d)", packet->
sockfd, packet->
id);
1469 talloc_free(packet->
data);
1470 packet->
data = NULL;
1484 volatile int max_fd;
1485 bool ongoing_trans =
false;
1486 char buffer[INET6_ADDRSTRLEN];
1497 if (NULL == tv_wait_time) {
1500 tv.tv_sec = tv_wait_time->tv_sec;
1501 tv.tv_usec = tv_wait_time->tv_usec;
1504 if (select(max_fd, &set, NULL, NULL, &tv) <= 0) {
1535 DEBUG(
"No outstanding request was found for reply from %s, port %d (sockfd: %d, id: %d)",
1556 DEBUG(
"Conflicting response authenticator for reply from %s (sockfd: %d, id: %d)",
1564 reply->
dst_ipaddr = trans->packet->src_ipaddr;
1565 reply->
dst_port = trans->packet->src_port;
1567 trans->reply = reply;
1572 DEBUG(
"Failed decoding reply");
1576 gettimeofday(&trans->reply->timestamp, NULL);
1578 if (trans->eap_context) {
1583 DEBUG(
"Transaction: %u, received packet (id: %u).", trans->id, trans->reply->id);
1588 if (!trans->eap_context) {
1594 for (vp = trans->reply->vps; vp != NULL; vp = vpnext) {
1602 if (
rc_respond_eap_md5(trans->eap_context, trans->reply, trans->packet) && trans->eap_context->eap.md5.tried < 3)
1605 trans->eap_context->eap.md5.tried ++;
1608 ongoing_trans =
true;
1617 ongoing_trans =
true;
1632 DEBUG(
"EAP transaction finished, but reply is not an Access-Accept");
1637 if ( (!vp) || (vp->vp_integer != 3) ) {
1638 DEBUG(
"EAP transaction finished, but reply does not contain EAP-Code = Success");
1649 if (trans->reply && !trans->eap_context) {
1651 switch (trans->reply->code) {
1676 if (!ongoing_trans) {
1689 if (!trans || !trans->
packet)
return;
1691 DEBUG(
"Timeout for transaction: %d, tries (so far): %d (max: %d)", trans->
id, trans->
tries, retries);
1695 if (trans->
tries < retries) {
1699 DEBUG(
"No response for transaction: %d, giving up", trans->
id);
1710 struct timeval tv_event;
1711 gettimeofday(&tv_event, NULL);
1715 ERROR(
"Failed to insert event");
1737 struct timeval tv_event;
1738 gettimeofday(&tv_event, NULL);
1745 ERROR(
"Failed to insert event");
1754 struct timeval when;
1755 uint32_t nb_processed = 0;
1760 gettimeofday(&when, NULL);
1767 return nb_processed;
1775 uint32_t nb_received = 0;
1787 uint32_t max_start_new = 0;
1792 struct timeval tv_now, tv_elapsed;
1793 gettimeofday(&tv_now, NULL);
1794 timersub(&tv_now, &
tv_start, &tv_elapsed);
1801 float elapsed_p = elapsed + 0.01;
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;
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);
1821 return max_start_new;
1829 uint32_t nb_started = 0;
1830 bool do_limit =
false;
1835 if (num_ongoing >= parallel)
break;
1836 if (do_limit && nb_started >= max_start)
break;
1864 if ( (rc_vps_list_in.
size == 0)
1869 INFO(
"Main loop: done.");
1876 struct servent *svp;
1878 svp = getservbyname(name,
"udp");
1881 return ntohs(svp->s_port);
1893 if (*port == 0) *port =
rc_getport(
"radius");
1898 if (*port == 0) *port =
rc_getport(
"radacct");
1911 if (*port == 0) *port = 0;
1943 if (force_af == AF_UNSPEC) force_af = AF_INET;
1945 if (strcmp(server_arg,
"-") != 0) {
1948 char const *portname = server_arg;
1951 if (*server_arg ==
'[') {
1952 p = strchr(server_arg,
']');
1953 if ((
size_t) (p - server_arg) >=
sizeof(buffer)) {
1957 memcpy(buffer, server_arg + 1, p - server_arg - 1);
1958 buffer[p - server_arg - 1] =
'\0';
1964 p = strchr(portname,
':');
1965 if (p && (strchr(p + 1,
':') == NULL)) {
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));
1976 server_addr_init =
true;
1979 if (portname) server_port = atoi(portname);
1993 if (!trans || !trans->
packet || !trans->
reply)
return;
1994 if (!wf_type || wf_type >=
RC_WF_MAX)
return;
1996 struct timeval tv_rtt;
2001 for (i=0; i<2; i++) {
2004 if ((0 == my_stats->
num) || (timercmp(&tv_rtt, &my_stats->
tv_rtt_min, <))) {
2006 my_stats->
tv_rtt_min.tv_usec = tv_rtt.tv_usec;
2008 if ((0 == my_stats->
num) || (timercmp(&tv_rtt, &my_stats->
tv_rtt_max, >=))) {
2010 my_stats->
tv_rtt_max.tv_usec = tv_rtt.tv_usec;
2029 if (num_stat == 0)
return;
2031 fprintf(fp,
"*** Statistics (per-workflow):\n");
2033 if (num_stat == 1) i_start = 1;
2038 if (my_stats->
num == 0)
continue;
2046 fprintf(fp,
"\t%-*.*s: nb: %d, RTT (ms): [avg: %.3f, min: %.3f, max: %.3f]\n",
2049 fprintf(fp,
"\t%-*.*s: nb: %d, RTT (ms): [avg: %.3f, min: %.3f, max: %.3f], rate (avg/s): %.3f\n",
2060 if (!do_summary)
return;
2064 fprintf(fp,
"*** Statistics summary:\n");
2069 }
else if (stats.
nb_eap == 0) {
2090 uint32_t u_ms_elapsed;
2091 struct timeval tv_elapsed;
2093 if (timerisset(&
tv_end)) {
2096 struct timeval tv_now;
2097 gettimeofday(&tv_now, NULL);
2098 timersub(&tv_now, &
tv_start, &tv_elapsed);
2101 u_ms_elapsed = (tv_elapsed.tv_sec * 1000) + (tv_elapsed.tv_usec/1000);
2103 return u_ms_elapsed;
2112 if (u_ms_elapsed > 0) {
2113 return (
float)(num_started * 1000) / (
float)u_ms_elapsed;
2125 if (u_ms_elapsed > 0) {
2126 return (
float)(my_stats->
num * 1000) / (
float)u_ms_elapsed;
2135 if (!do_output || !progress_interval)
return;
2137 printf(
"STAT (%s):",
ELAPSED);
2139 printf(
" %.2f%%", (100 * (
float)num_started / num_input));
2140 printf(
", start: %u (on: %u, ok: %u, fail: %u, lost: %u)",
2154 char *filename = NULL;
2160 .fd = STDOUT_FILENO,
2170 autofree = talloc_init(
"main");
2177 while ((c = getopt(argc, argv,
"46c:d:D:f:hn:o:p:qr:sS:t:vxX")) != EOF)
2185 force_af = AF_INET6;
2189 if (!isdigit((
int) *optarg))
usage();
2190 recycle_count = atoi(optarg);
2191 if (recycle_count == 0) recycle_count = 1;
2207 rate_limit = atoi(optarg);
2208 if (rate_limit == 0)
usage();
2212 progress_interval = atof(optarg);
2213 if (progress_interval < 0.1)
usage();
2217 parallel = atoi(optarg);
2218 if (parallel == 0) parallel = 1;
2219 if (parallel > 65536) parallel = 65536;
2233 sha1_data_problems = 1;
2238 if (!isdigit((
int) *optarg))
2240 retries = atoi(optarg);
2248 if (!isdigit((
int) *optarg))
2250 timeout = atof(optarg);
2254 printf(
"%s: %s\n", progname, radiusd_version);
2258 fp = fopen(optarg,
"r");
2263 if (fgets(filesecret,
sizeof(filesecret), fp) == NULL) {
2264 ERROR(
"Error reading %s: %s",
2271 p = filesecret + strlen(filesecret) - 1;
2272 while ((p >= filesecret) &&
2278 if (strlen(filesecret) < 2) {
2279 ERROR(
"Secret in %s is too short", optarg);
2290 argc -= (optind - 1);
2291 argv += (optind - 1);
2294 ((!
secret) && (argc < 4))) {
2303 radclient_log.
fd = 0;
2348 if (!isdigit((
int) argv[2][0])) {
2350 if (packet_code == -2) {
2351 ERROR(
"Unrecognised request type \"%s\"", argv[2]);
2355 packet_code = atoi(argv[2]);
2366 if (argv[3]) secret = argv[3];
2371 INFO(
"Loading input data...");
2373 || rc_vps_list_in.
size == 0) {
2374 ERROR(
"No valid input. Nothing to send.");
2377 INFO(
"Loaded: %d input element(s).", rc_vps_list_in.
size);
2385 ERROR(
"Failed to create event list");
2401 gettimeofday(&
tv_end, NULL);
2408 talloc_free(autofree);
2431 id = ((int)getpid() & 0xff);
2433 id = vp->vp_integer;
2440 eapcode = vp->vp_integer;
2443 for (vp = req->
vps; vp != NULL; vp = vpnext) {
2447 if (vp->
da->
attr >= PW_EAP_TYPE_BASE &&
2448 vp->
da->
attr < PW_EAP_TYPE_BASE+256) {
2457 eap_method = vp->
da->
attr - PW_EAP_TYPE_BASE;
2459 switch (eap_method) {
2479 pt_ep->
code = eapcode;
2484 pt_ep->
type.
data = talloc_memdup(vp, vp->vp_octets, vp->vp_length);
2485 talloc_set_type(pt_ep->
type.
data, uint8_t);
2513 eap1->vp_integer = e->
id;
2517 eap1->vp_integer = e->
code;
2547 type += PW_EAP_TYPE_BASE;
2590 ERROR(
"eap: EAP-Sim attribute not found");
2594 eap_data = talloc_memdup(esvp, esvp->vp_octets, esvp->vp_length);
2595 talloc_set_type(eap_data, uint8_t);
2599 talloc_free(eap_data);
static struct timeval tv_end
VALUE_PAIR has a single value.
static fr_event_list_t * ev_list
list of armed events.
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.
int sockfd
Socket this packet was read from.
void fr_pair_list_fprint(FILE *, VALUE_PAIR const *vp)
Print a list of attributes and enumv.
uint32_t nb_packets_recv
number of packets received
int id
Packet ID (used to link requests/responses).
struct timeval timestamp
When we received the packet.
int fr_radius_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original, char const *secret)
Calculate/check digest, and decode radius attributes.
uint32_t id
id of transaction (0 for the first one).
static char ch_elapsed[12+1]
static void rc_finish_transaction(rc_transaction_t *trans)
Terminate a transaction.
static void rc_float_to_timeval(struct timeval *tv, float f_val)
Convert a float to struct timeval.
struct rc_wf_stats rc_wf_stats_t
Structure which holds per-workflow statistics information.
RFC2865 - Access-Challenge.
Main server configuration.
bool fr_packet_list_id_free(fr_packet_list_t *pl, RADIUS_PACKET *request, bool yank)
uint32_t nb_eap
number of EAP transactions started
static uint32_t num_input
number of input entries loaded.
static bool server_addr_init
int fr_dict_read(fr_dict_t *dict, char const *dir, char const *filename)
int fr_inet_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
Wrappers for IPv4/IPv6 host to IP address lookup.
Structure which holds per-workflow statistics information.
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
static float rc_get_start_rate(void)
Compute the started transactions rate /s.
uint32_t fr_rand(void)
Return a 32-bit random number.
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.
static char const * radius_dir
fr_ipaddr_t src_ipaddr
Src IP address of packet.
RADIUS_PACKET ** fr_packet_list_find_byreply(fr_packet_list_t *pl, RADIUS_PACKET *reply)
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.
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.
static uint32_t num_started
number of transactions started.
void fr_md5_init(FR_MD5_CTX *ctx)
Initialise a new MD5 context.
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
#define PW_AUTH_UDP_PORT_ALT
union rc_eap_context::@14 eap
char const * inet_ntop(int af, void const *src, char *dst, size_t cnt)
eap_packet_raw_t * eap_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps)
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
struct timeval tv_rtt_max
int fr_radius_send(RADIUS_PACKET *, RADIUS_PACKET const *, char const *secret)
Reply to the request.
struct rc_eap_sim_context rc_eap_sim_context_t
Structure which contains EAP context, necessary to perform the full EAP transaction.
#define STATS_INC(_stat_type)
static char const * hostname(char *buf, size_t buflen, uint32_t ipaddr)
valuepair value must be xlat expanded when it's added to VALUE_PAIR tree.
uint8_t * data
Packet data (body).
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.
static char filesecret[256]
fr_event_list_t * fr_event_list_create(TALLOC_CTX *ctx, fr_event_status_t status)
struct rc_eap_md5_context rc_eap_md5_context_t
uint16_t dst_port
DST Port of packet.
uint32_t nb_fail
number of failed transactions
uint16_t src_port
Src port of packet.
fr_ipaddr_t dst_ipaddr
Dst IP address of packet.
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.
static char * rc_print_elapsed(char *out, uint8_t decimals)
Print a elapsed time buffer (SS.uuuuuu).
uint32_t recycle
number of times this input has been used to start a transaction.
static void NEVER_RETURNS usage(void)
Display usage and exit.
static uint32_t rate_limit
RFC2866 - Accounting-Response.
FR_NAME_NUMBER const fr_request_types[]
rc_input_vps_t * input_vps
struct timeval tv_rtt_min
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).
RFC3575/RFC5176 - CoA-Ack (positive)
static int rc_send_one_packet(rc_transaction_t *trans, RADIUS_PACKET **packet_p)
Send one packet for a transaction.
Vendors and attribute names.
#define PW_DIGEST_ATTRIBUTES
RFC2865 - Access-Request.
int fr_str2int(FR_NAME_NUMBER const *table, char const *name, int def)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
Structure which holds a transaction: sent packet, reply received...
uint32_t nb_lost
number of packets to which we received no response
int unmap_eapsim_basictypes(RADIUS_PACKET *r, uint8_t *attr, unsigned int attrlen)
VALUE_PAIR * fr_pair_list_copy(TALLOC_CTX *ctx, VALUE_PAIR *from)
Copy a pairlist.
int fr_packet_list_fd_set(fr_packet_list_t *pl, fd_set *set)
static int rc_respond_eap_md5(rc_eap_context_t *eap_context, RADIUS_PACKET *req, RADIUS_PACKET *rep)
char const * radiusd_version
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...
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)
void fr_packet_header_print(FILE *fp, RADIUS_PACKET *packet, bool received)
Structure to represent packet format of eap on wire
uint32_t num
The number (within the file) of the input we're reading.
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.
static void rc_do_progress_stat(void)
Display simple progress statistics.
RFC2866 - Accounting-Request.
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.
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.
unsigned int attr
Attribute number.
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.
static void rc_cleanresp(RADIUS_PACKET *resp)
union fr_ipaddr_t::@1 ipaddr
RFC3575/RFC5176 - CoA-Nak (not willing to perform)
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).
rc_input_vps_list_t * list
the list to which this entry belongs (NULL for an unchained entry).
char password[256]
copy of User-Password (or CHAP-Password).
struct timeval tv_rtt_cumul
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)
static void rc_evprep_progress_stat(void)
Prepare event: report progress statistics.
static unsigned int num_sockets
number of allocated sockets.
#define RADIUS_DICTIONARY
unsigned int vendor
Vendor that defines this attribute.
static uint32_t num_ongoing
number of ongoing transactions.
Stores an attribute, a value and various bits of other data.
char const * sim_state2name(enum eapsim_clientstates state, char *buf, int buflen)
static rc_transaction_t * rc_init_transaction(TALLOC_CTX *ctx)
Grab an element from the input list.
static void rc_build_eap_context(rc_transaction_t *trans)
Map EAP methods and build EAP-Message (if EAP is involved).
static struct timeval tv_progress_interval
static struct timeval tv_start
static PW_CODE rc_get_code(uint16_t port)
Resolve a port to a request type.
#define PW_ACCT_UDP_PORT_ALT
fr_packet_list_t * fr_packet_list_create(int alloc_id)
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.
void eapsim_dump_mk(struct eapsim_keys *ek)
uint8_t vector[AUTH_VECTOR_LEN]
RADIUS authentication vector.
char const * fr_strerror(void)
Get the last library error.
static uint32_t num_finished
number of finished transactions.
int fr_event_run(fr_event_list_t *el, struct timeval *when)
int radlog_init(fr_log_t *log, bool daemonize)
Initialise file descriptors based on logging destination.
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.
static char const * progname
void fr_pair_delete_by_num(VALUE_PAIR **head, unsigned int vendor, unsigned int attr, int8_t tag)
Delete matching pairs.
static void rc_main_loop(void)
Main loop: Handle events.
Packet code has not been set.
static uint32_t rc_get_elapsed(void)
Get elapsed time (in ms).
Structure which holds global statistics information.
static uint32_t rc_loop_recv(void)
Receive loop.
static void rc_print_wf_stats(FILE *fp)
Print per-workflow detailed statistics.
main_config_t main_config
Main server configuration.
static float progress_interval
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.
value_type_t type
Type of pointer in value union.
uint32_t nb_packets_sent
number of packets sent (including retransmissions)
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)
static rc_input_vps_list_t rc_vps_list_in
list of available input vps entries.
int fr_socket(fr_ipaddr_t *ipaddr, uint16_t port)
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)
log_lvl_t rad_debug_lvl
Global debugging level.
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
int fr_pair_list_afrom_file(TALLOC_CTX *ctx, VALUE_PAIR **out, FILE *fp, bool *pfiledone)
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.
fr_event_t * event
armed event (if any).
int eap_type
contains the EAP-Type
uint32_t nb_success
number of successful transactions
uint32_t nb_started
number of transactions started
void eapsim_calculate_keys(struct eapsim_keys *ek)
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)
int rad_virtual_server(REQUEST UNUSED *request)
char const * dictionary_dir
Where to load dictionaries from.
#define EAPSIM_CALCMAC_SIZE
Structure which contains EAP context, necessary to perform the full EAP transaction.
int eap_basic_compose(RADIUS_PACKET *packet, eap_packet_t *reply)
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]
uint32_t num_packet
number of packets sent for this transaction.
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.
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)
static char const * rc_wf_types[RC_WF_MAX]
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)
VALUE_PAIR * fr_cursor_remove(vp_cursor_t *cursor)
Remove the current pair.
static uint16_t server_port
RFC2865/RFC5997 - Status Server (request)
rc_wf_type_t
Define workflow types (transactions for which we got a response)
void void fr_md5_final(uint8_t out[MD5_DIGEST_LENGTH], FR_MD5_CTX *ctx) CC_BOUNDED(__minbytes__
Structure to hold EAP data.
static unsigned int retries
size_t strlcpy(char *dst, char const *src, size_t siz)
static char const * secret
static float rc_timeval_to_float(struct timeval *tv)
Convert a struct timeval to float.
struct timeval timestamp
when the transaction is started.
struct rc_eap_context rc_eap_context_t
PW_CODE
RADIUS packet codes.
bool colourise
Prefix log messages with VT100 escape codes to change text colour.
static fr_packet_list_t * pl
list of outgoing packets.
uint32_t fr_packet_list_num_outgoing(fr_packet_list_t *pl)
static fr_ipaddr_t server_ipaddr
static TALLOC_CTX * autofree
fr_dict_attr_t const * da
Dictionary attribute defines the attribute.
rc_eap_context_t * eap_context
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.
log_dst_t dst
Log destination.
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.
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...
void fr_pair_replace(VALUE_PAIR **head, VALUE_PAIR *add)
Replace all matching VPs.
int fr_event_insert(fr_event_list_t *el, fr_event_callback_t callback, void *ctx, struct timeval *when, fr_event_t **parent)
static int rc_unmap_eapsim_types(RADIUS_PACKET *r)
char const * name
Test name (as specified in the request).
char * talloc_typed_strdup(void const *t, char const *p)
Call talloc strdup, setting the type on the new chunk correctly.
VALUE_PAIR * vps_in
the list of attribute/value pairs.
int fd
File descriptor to write messages to.
static int rc_init_packet(rc_transaction_t *trans)
Perform packet initialization for a transaction.
RADIUS_PACKET * fr_packet_list_recv(fr_packet_list_t *pl, fd_set *set)
#define fr_packet2myptr(TYPE, MEMBER, PTR)
void fr_pair_value_memcpy(VALUE_PAIR *vp, uint8_t const *src, size_t len)
Copy data into an "octets" data type.
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
uint32_t nb_packets_retries
number of packets retransmissions
int fr_event_list_num_elements(fr_event_list_t *el)
static struct timeval tv_timeout
void set_radius_dir(TALLOC_CTX *ctx, char const *path)
Set the global radius config directory.
struct rc_stats rc_stats_t
Structure which holds global statistics information.
static unsigned int recycle_count
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.
RFC3575/RFC5176 - Disconnect-Request.
static USES_APPLE_DEPRECATED_API char trans[64]