static rc_stats_t stats;
static uint16_t server_port = 0;
-static int packet_code = 0;
+static int packet_code = PW_CODE_UNDEFINED;
static fr_ipaddr_t server_ipaddr;
static int resend_count = 1;
static bool done = true;
{
fprintf(stderr, "Usage: radclient [options] server[:port] <command> [<secret>]\n");
- fprintf(stderr, " <command> One of auth, acct, status, coa, or disconnect.\n");
+ fprintf(stderr, " <command> One of auth, acct, status, coa, disconnect or auto.\n");
fprintf(stderr, " -4 Use IPv4 address of server\n");
fprintf(stderr, " -6 Use IPv6 address of server.\n");
fprintf(stderr, " -c <count> Send each packet 'count' times.\n");
}
static const FR_NAME_NUMBER request_types[] = {
- { "auth", PW_CODE_AUTHENTICATION_REQUEST },
+ { "auth", PW_CODE_ACCESS_REQUEST },
{ "challenge", PW_CODE_ACCESS_CHALLENGE },
{ "acct", PW_CODE_ACCOUNTING_REQUEST },
{ "status", PW_CODE_STATUS_SERVER },
return ntohs(svp->s_port);
}
+/*
+ * Set a port from the request type if we don't already have one
+ */
static void radclient_get_port(PW_CODE type, uint16_t *port)
{
switch (type) {
default:
- case PW_CODE_AUTHENTICATION_REQUEST:
+ case PW_CODE_ACCESS_REQUEST:
case PW_CODE_ACCESS_CHALLENGE:
case PW_CODE_STATUS_SERVER:
if (*port == 0) *port = getport("radius");
return;
case PW_CODE_DISCONNECT_REQUEST:
+ if (*port == 0) *port = PW_POD_UDP_PORT;
+ return;
+
case PW_CODE_COA_REQUEST:
if (*port == 0) *port = PW_COA_UDP_PORT;
return;
case PW_CODE_UNDEFINED:
if (*port == 0) *port = 0;
+ return;
}
}
/*
+ * Resolve a port to a request type
+ */
+static PW_CODE radclient_get_code(uint16_t port)
+{
+ if ((port == getport("radius")) || (port == PW_AUTH_UDP_PORT) || (port == PW_AUTH_UDP_PORT_ALT)) {
+ return PW_CODE_ACCESS_REQUEST;
+ }
+ if ((port == getport("radacct")) || (port == PW_ACCT_UDP_PORT) || (port == PW_ACCT_UDP_PORT_ALT)) {
+ return PW_CODE_ACCOUNTING_REQUEST;
+ }
+ if (port == PW_COA_UDP_PORT) return PW_CODE_COA_REQUEST;
+ if (port == PW_POD_UDP_PORT) return PW_CODE_DISCONNECT_REQUEST;
+
+ return PW_CODE_UNDEFINED;
+}
+
+/*
* Initialize a radclient data structure and add it to
* the global linked list.
*/
/*
* Determine where to read the VP's from.
*/
- if (strcmp(files->packets, "-") != 0) {
+ if (strcmp(files->packets, "stdin") != 0) {
packets = fopen(files->packets, "r");
if (!packets) {
ERROR("Error opening %s: %s", files->packets, strerror(errno));
goto error;
}
- request->packet = rad_alloc(request, 1);
+ request->packet = rad_alloc(request, true);
if (!request->packet) {
ERROR("Out of memory");
goto error;
request->packet->code = vp->vp_integer;
break;
+ case PW_RESPONSE_PACKET_TYPE:
+ request->filter_code = vp->vp_integer;
+ break;
+
case PW_PACKET_DST_PORT:
request->packet->dst_port = (vp->vp_integer & 0xffff);
break;
}
} /* loop over the VP's we read in */
- /*
- * Use the default set on the command line
- */
- if (request->packet->code == 0) {
- request->packet->code = packet_code;
- }
+ /*
+ * Use the default set on the command line
+ */
+ if (request->packet->code == PW_CODE_UNDEFINED) request->packet->code = packet_code;
/*
* Default to the filename
*/
- if (!request->name) {
- request->name = request->files->packets;
- }
+ if (!request->name) request->name = request->files->packets;
/*
* Automatically set the response code from the request code
* (if one wasn't already set).
*/
- if (!request->filter_code) {
+ if (request->filter_code == PW_CODE_UNDEFINED) {
switch (request->packet->code) {
- case PW_CODE_AUTHENTICATION_REQUEST:
- request->filter_code = PW_CODE_AUTHENTICATION_ACK;
+ case PW_CODE_ACCESS_REQUEST:
+ request->filter_code = PW_CODE_ACCESS_ACCEPT;
break;
case PW_CODE_ACCOUNTING_REQUEST:
request->filter_code = PW_CODE_DISCONNECT_ACK;
break;
+ case PW_CODE_STATUS_SERVER:
+ switch (radclient_get_code(request->packet->dst_port)) {
+ case PW_CODE_ACCESS_REQUEST:
+ request->filter_code = PW_CODE_ACCESS_ACCEPT;
+ break;
+
+ case PW_CODE_ACCOUNTING_REQUEST:
+ request->filter_code = PW_CODE_ACCOUNTING_RESPONSE;
+ break;
+
+ default:
+ REDEBUG("Can't determine expected response to Status-Server request, specify "
+ "a well known RADIUS port, or add a Response-Packet-Type attribute "
+ "to the request of filter");
+ goto error;
+ }
+ break;
+
+ case PW_CODE_UNDEFINED:
+ REDEBUG("Both Packet-Type and Response-Packet-Type undefined, specify at least one, "
+ "or a well known RADIUS port");
+ goto error;
+
default:
+ REDEBUG("Can't determine expected Response-Packet-Type for Packet-Type %i",
+ request->packet->code);
+ goto error;
+ }
+ /*
+ * Automatically set the request code from the response code
+ * (if one wasn't already set).
+ */
+ } else if (request->packet->code == PW_CODE_UNDEFINED) {
+ switch (request->filter_code) {
+ case PW_CODE_ACCESS_ACCEPT:
+ case PW_CODE_ACCESS_REJECT:
+ request->packet->code = PW_CODE_ACCESS_REQUEST;
+ break;
+
+ case PW_CODE_ACCOUNTING_RESPONSE:
+ request->packet->code = PW_CODE_ACCOUNTING_REQUEST;
break;
+
+ case PW_CODE_DISCONNECT_ACK:
+ case PW_CODE_DISCONNECT_NAK:
+ request->packet->code = PW_CODE_DISCONNECT_REQUEST;
+ break;
+
+ case PW_CODE_COA_ACK:
+ case PW_CODE_COA_NAK:
+ request->packet->code = PW_CODE_COA_REQUEST;
+ break;
+
+ default:
+ REDEBUG("Can't determine expected Packet-Type for Response-Packet-Type %i",
+ request->filter_code);
+ goto error;
}
}
/*
- * Automatically set the dst port if one wasn't already set.
+ * Automatically set the dst port (if one wasn't already set).
*/
if (request->packet->dst_port == 0) {
radclient_get_port(request->packet->code, &request->packet->dst_port);
+ if (request->packet->dst_port == 0) {
+ REDEBUG("Can't determine destination port");
+ goto error;
+ }
}
/*
/*
* Read request(s) from the file.
*/
- if (!radclient_init(files, files)) {
- return -1; /* stop walking */
- }
+ if (!radclient_init(files, files)) return -1; /* stop walking */
return 0;
}
* and ensure that the next packet has a unique
* authentication vector.
*/
- if (request->packet->data) {
- TALLOC_FREE(request->packet->data);
- }
-
+ if (request->packet->data) TALLOC_FREE(request->packet->data);
if (request->reply) rad_free(&request->reply);
}
* Remember when we have to wake up, to re-send the
* request, of we didn't receive a reply.
*/
- if ((sleep_time == -1) || (sleep_time > (int) timeout)) {
- sleep_time = (int) timeout;
- }
+ if ((sleep_time == -1) || (sleep_time > (int) timeout)) sleep_time = (int) timeout;
/*
* Haven't sent the packet yet. Initialize it.
*/
retry:
request->packet->src_ipaddr.af = server_ipaddr.af;
- rcode = fr_packet_list_id_alloc(pl, ipproto,
- &request->packet, NULL);
+ rcode = fr_packet_list_id_alloc(pl, ipproto, &request->packet, NULL);
if (!rcode) {
int mysockfd;
if ((vp = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) {
pairstrcpy(vp, request->password);
-
} else if ((vp = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
bool already_hex = false;
vp->length = 17;
}
} else if (pairfind(request->packet->vps, PW_MS_CHAP_PASSWORD, 0, TAG_ANY) != NULL) {
- mschapv1_encode(request->packet,
- &request->packet->vps,
- request->password);
+ mschapv1_encode(request->packet, &request->packet->vps, request->password);
} else {
DEBUG("WARNING: No password in the request");
}
max_fd = fr_packet_list_fd_set(pl, &set);
if (max_fd < 0) exit(1); /* no sockets to listen on! */
- if (wait_time <= 0) {
- tv.tv_sec = 0;
- } else {
- tv.tv_sec = wait_time;
- }
+ tv.tv_sec = (wait_time <= 0) ? 0 : wait_time;
tv.tv_usec = 0;
/*
* No packet was received.
*/
- if (select(max_fd, &set, NULL, NULL, &tv) <= 0) {
- return 0;
- }
+ if (select(max_fd, &set, NULL, NULL, &tv) <= 0) return 0;
/*
* Look for the packet.
* Increment counters...
*/
switch (request->reply->code) {
- case PW_CODE_AUTHENTICATION_ACK:
+ case PW_CODE_ACCESS_ACCEPT:
case PW_CODE_ACCOUNTING_RESPONSE:
case PW_CODE_COA_ACK:
case PW_CODE_DISCONNECT_ACK:
talloc_set_log_stderr();
- filename_tree = rbtree_create(filename_cmp, NULL, 0);
+ filename_tree = rbtree_create(NULL, filename_cmp, NULL, 0);
if (!filename_tree) {
oom:
ERROR("Out of memory");
case '4':
force_af = AF_INET;
break;
+
case '6':
force_af = AF_INET6;
break;
+
case 'c':
if (!isdigit((int) *optarg))
usage();
resend_count = atoi(optarg);
break;
+
case 'D':
dict_dir = optarg;
break;
+
case 'd':
radius_dir = optarg;
break;
+
case 'f':
{
char const *p;
rbtree_insert(filename_tree, (void *) files);
}
break;
+
case 'F':
print_filename = true;
break;
+
case 'i': /* currently broken */
if (!isdigit((int) *optarg))
usage();
break;
case 'r':
- if (!isdigit((int) *optarg))
- usage();
+ if (!isdigit((int) *optarg)) usage();
retries = atoi(optarg);
if ((retries == 0) || (retries > 1000)) usage();
break;
+
case 's':
do_summary = true;
break;
+
case 'S':
{
char *p;
secret = filesecret;
}
break;
+
case 't':
if (!isdigit((int) *optarg))
usage();
timeout = atof(optarg);
break;
+
case 'v':
DEBUG("%s", radclient_version);
exit(0);
break;
+
case 'x':
fr_debug_flag++;
rc_debug_flag++;
break;
+
case 'h':
default:
usage();
}
fr_strerror(); /* Clear the error buffer */
-
/*
* Get the request type
*/
* Strip port from hostname if needed.
*/
if (portname) server_port = atoi(portname);
+
+ /*
+ * Work backwards from the port to determine the packet type
+ */
+ if (packet_code == PW_CODE_UNDEFINED) packet_code = radclient_get_code(server_port);
}
radclient_get_port(packet_code, &server_port);
rc_file_pair_t *files;
files = talloc_zero(talloc_autofree_context(), rc_file_pair_t);
- files->packets = "-";
+ files->packets = "stdin";
if (!radclient_init(files, files)) {
exit(1);
}