24 RCSID(
"$Id: 8b2e2c35e84cebd7a7d9715e3db784e05f60600a $")
26 #include <freeradius-devel/radiusd.h>
27 #include <freeradius-devel/modules.h>
28 #include <freeradius-devel/detail.h>
29 #include <freeradius-devel/process.h>
30 #include <freeradius-devel/rad_assert.h>
32 #ifdef HAVE_SYS_STAT_H
44 #define USEC (1000000)
66 #ifdef WITH_DETAIL_THREAD
83 RDEBUG(
"detail (%s): No response to request. Will retry in %d seconds",
92 gettimeofday(&now, NULL);
137 data->
srtt += rtt >> 3;
155 RDEBUG3(
"detail (%s): Received response for request %d. Will read the next packet in %d seconds",
164 #ifdef WITH_DETAIL_THREAD
165 if (write(data->child_pipe[1], &c, 1) < 0) {
188 data->delay_time =
USEC;
205 data->work_fd = open(data->filename_work, O_RDWR);
211 if ((data->work_fd < 0) && (errno != ENOENT)) {
212 ERROR(
"Failed opening detail file %s: %s",
220 if (data->work_fd < 0) {
227 char const *filename;
230 DEBUG2(
"detail (%s): Polling for detail file", data->name);
232 memset(&files, 0,
sizeof(files));
233 if (glob(data->filename, 0, NULL, &files) != 0) {
245 for (i = 0; i < files.gl_pathc; i++) {
246 if (stat(files.gl_pathv[i], &st) < 0)
continue;
248 if ((i == 0) || (st.st_ctime < chtime)) {
249 chtime = st.st_ctime;
254 if (found < 0)
goto noop;
259 filename = files.gl_pathv[found];
261 DEBUG(
"detail (%s): Renaming %s -> %s", data->name, filename, data->filename_work);
262 if (rename(filename, data->filename_work) < 0) {
263 ERROR(
"detail (%s): Failed renaming %s to %s: %s",
264 data->name, filename, data->filename_work,
fr_syserror(errno));
273 data->work_fd = open(data->filename_work, O_RDWR);
274 if (data->work_fd < 0) {
275 ERROR(
"detail (%s): Failed opening %s: %s",
276 data->name, data->filename_work,
fr_syserror(errno));
287 data->client_ip.af = AF_UNSPEC;
289 data->offset = data->last_offset = data->timestamp_offset = 0;
292 data->done_entry =
false;
313 #ifndef WITH_DETAIL_THREAD
326 if (data->
signal)
return 0;
329 if (!packet)
return -1;
344 switch (packet->
code) {
383 rcode = read(data->master_pipe[0], &packet,
sizeof(packet));
384 if (rcode <= 0)
return rcode;
399 switch (packet->
code) {
419 if (write(data->child_pipe[1], &c, 1) < 0) {
420 ERROR(
"detail (%s): Failed writing ack to reader thread: %s", data->
name,
434 char key[256], op[8], value[1024];
441 switch (data->
state) {
490 ERROR(
"detail (%s): FATAL: Failed to re-open detail file: %s",
518 if (fstat(data->
work_fd, &buf) < 0) {
519 ERROR(
"detail (%s): Failed to stat detail file: %s",
524 if (((off_t) ftell(data->
fp)) == buf.st_size) {
533 if (feof(data->
fp)) {
537 if (data->
fp) fclose(data->
fp);
544 INFO(
"detail (%s): Finished reading \"one shot\" detail file - Exiting", data->
name);
562 if (data->
fp && !feof(data->
fp))
break;
580 DEBUG(
"detail (%s): No response to detail request. Retrying", data->
name);
601 WARN(
"detail (%s): Failed seeking to timestamp offset: %s",
603 }
else if (fwrite(
"\tDone", 1, 5, data->
fp) < 5) {
604 WARN(
"detail (%s): Failed marking request as done: %s",
606 }
else if (fflush(data->
fp) != 0) {
607 WARN(
"detail (%s): Failed flushing marked detail file to disk: %s",
611 if (fseek(data->
fp, data->
offset, SEEK_SET) < 0) {
612 WARN(
"detail (%s): Failed seeking to next detail request: %s",
627 while (fgets(buffer,
sizeof(buffer), data->
fp)) {
636 if (!strchr(buffer,
'\n')) {
646 (buffer[0] ==
'\n')) {
659 if (sscanf(buffer,
"%*s %*s %*d %*d:%*d:%*d %d", &y)) {
671 if (sscanf(buffer,
"%255s %7s %1023s", key, op, value) != 3) {
672 WARN(
"detail (%s): Skipping badly formatted line %s", data->
name, buffer);
679 if (!strchr(op,
'='))
continue;
684 if (!
strcasecmp(key,
"Request-Authenticator"))
continue;
696 ERROR(
"detail (%s): Failed parsing Client-IP-Address", data->
name);
715 vp->vp_date = (uint32_t) data->
timestamp;
772 ERROR(
"detail (%s): Truncated record: treating it as EOF for detail file %s",
794 ERROR(
"detail (%s): FATAL: Failed allocating memory for detail", data->
name);
798 memset(packet, 0,
sizeof(*packet));
812 if (vp) packet->
code = vp->vp_integer;
834 &vp->vp_ipv6addr,
sizeof(vp->vp_ipv6addr));
849 &vp->vp_ipv6addr,
sizeof(vp->vp_ipv6addr));
862 packet->
dst_ipaddr.
ipaddr.ip4addr.s_addr = htonl((INADDR_LOOPBACK & ~0xffffff) | ((data->
counter >> 24) & 0xff));
890 vp->vp_integer += time(NULL) - data->
timestamp;
903 vp->vp_integer = data->
tries;
918 #ifdef WITH_DETAIL_THREAD
926 close(data->child_pipe[0]);
927 close(data->child_pipe[1]);
928 data->child_pipe[0] = -1;
933 pthread_kill(data->pthread_id, SIGTERM);
938 ret = read(data->master_pipe[0], &arg,
sizeof(arg));
940 ERROR(
"detail (%s): Reader thread exited without informing the master: %s",
942 }
else if (ret !=
sizeof(arg)) {
943 ERROR(
"detail (%s): Invalid thread pointer received from reader thread during exit",
945 ERROR(
"detail (%s): Expected %zu bytes, got %zi bytes", data->
name,
sizeof(arg), ret);
948 close(data->master_pipe[0]);
949 close(data->master_pipe[1]);
951 if (arg) pthread_join(data->pthread_id, &arg);
955 if (data->
fp != NULL) {
965 return snprintf(buffer, bufsize,
"%s",
969 return snprintf(buffer, bufsize,
"detail file %s as server %s",
985 delay += (
USEC * 3) / 4;
988 DEBUG2(
"detail (%s): Detail listener state %s waiting %d.%06d sec",
1001 #ifdef WITH_DETAIL_THREAD
1013 DEBUG2(
"detail (%s): Detail listener state %s signalled %d waiting %d.%06d sec",
1029 #ifdef WITH_DETAIL_THREAD
1039 #ifdef WITH_DETAIL_THREAD
1040 static void *detail_handler_thread(
void *arg)
1056 if (data->child_pipe[0] < 0) {
1058 if (write(data->master_pipe[1], &packet,
sizeof(packet)) < 0) {
1059 ERROR(
"detail (%s): Failed writing exit status to master: %s",
1072 if (write(data->master_pipe[1], &packet,
sizeof(packet)) < 0) {
1073 ERROR(
"detail (%s): Failed passing detail packet pointer to master: %s",
1077 if (read(data->child_pipe[0], &c, 1) < 0) {
1078 ERROR(
"detail (%s): Failed getting detail packet ack from master: %s",
1131 this->synchronous =
false;
1134 cf_log_err_cs(cs,
"No detail file specified in listen section");
1156 if ((strchr(data->
filename,
'*') != NULL) ||
1157 (strchr(data->
filename,
'[') != NULL)) {
1161 WARN(
"detail (%s): File \"%s\" appears to use file globbing, but it is not supported on this system",
1165 p = strrchr(buffer, FR_DIR_SEP);
1175 if ((strchr(buffer,
'*') != NULL) ||
1176 (strchr(buffer,
'[') != NULL)) {
1177 cf_log_err_cs(cs,
"Wildcard directories are not supported");
1181 strlcat(buffer,
"detail.work",
1182 sizeof(buffer) - strlen(buffer));
1201 memset(client, 0,
sizeof(*client));
1207 client->
nas_type = talloc_strdup(data,
"none");
1212 #ifdef WITH_DETAIL_THREAD
1225 if (pipe(data->master_pipe) < 0) {
1230 if (pipe(data->child_pipe) < 0) {
1235 pthread_create(&data->pthread_id, NULL, detail_handler_thread,
this);
1237 this->fd = data->master_pipe[0];
void fr_pair_list_free(VALUE_PAIR **)
Free memory used by a valuepair list.
VALUE_PAIR has a single value.
int sockfd
Socket this packet was read from.
int id
Packet ID (used to link requests/responses).
struct timeval timestamp
When we received the packet.
int detail_print(rad_listen_t const *this, char *buffer, size_t bufsize)
char const * nas_type
Type of client (arbitrary).
int fr_inet_hton(fr_ipaddr_t *out, int af, char const *hostname, bool fallback)
Wrappers for IPv4/IPv6 host to IP address lookup.
int rad_accounting(REQUEST *)
VALUE_PAIR * fr_pair_afrom_num(TALLOC_CTX *ctx, unsigned int vendor, unsigned int attr)
Create a new valuepair.
uint32_t fr_rand(void)
Return a 32-bit random number.
fr_ipaddr_t src_ipaddr
Src IP address of packet.
uint8_t prefix
Prefix length - Between 0-32 for IPv4 and 0-128 for IPv6.
static FR_NAME_NUMBER state_names[]
VALUE_PAIR * vps
Result of decoding the packet into VALUE_PAIRs.
#define CONF_PARSER_TERMINATOR
char const * secret
Secret PSK.
VALUE_PAIR * fr_cursor_init(vp_cursor_t *cursor, VALUE_PAIR *const *node)
Setup a cursor to iterate over attribute pairs.
PUBLIC int snprintf(char *string, size_t length, char *format, va_alist)
rad_listen_t * listener
The listener that received the request.
#define PW_TYPE_DEPRECATED
If a matching CONF_PAIR is found, error out with a deprecated message.
#define FR_INTEGER_BOUND_CHECK(_name, _var, _op, _bound)
unsigned int number
Monotonically increasing request number. Reset on server restart.
uint16_t dst_port
DST Port of packet.
uint16_t src_port
Src port of packet.
fr_ipaddr_t dst_ipaddr
Dst IP address of packet.
Defines a CONF_PAIR to C data type mapping.
Abstraction to allow iterating over different configurations of VALUE_PAIRs.
void detail_free(rad_listen_t *this)
int detail_decode(UNUSED rad_listen_t *this, UNUSED REQUEST *request)
int detail_parse(CONF_SECTION *cs, rad_listen_t *this)
char const * fr_syserror(int num)
Guaranteed to be thread-safe version of strerror.
VALUE_PAIR * fr_pair_list_copy(TALLOC_CTX *ctx, VALUE_PAIR *from)
Copy a pairlist.
int rad_coa_recv(REQUEST *request)
int(* RAD_REQUEST_FUNP)(REQUEST *)
void fr_cursor_merge(vp_cursor_t *cursor, VALUE_PAIR *vp)
Merges multiple VALUE_PAIR into the cursor.
void fr_cursor_insert(vp_cursor_t *cursor, VALUE_PAIR *vp)
Insert a single VALUE_PAIR at the end of the list.
void fr_pair_add(VALUE_PAIR **head, VALUE_PAIR *vp)
Add a VP to the end of the list.
RFC2866 - Accounting-Request.
RADIUS_PACKET * fr_radius_alloc(TALLOC_CTX *ctx, bool new_vector)
Allocate a new RADIUS_PACKET.
int cf_section_parse(CONF_SECTION *, void *base, CONF_PARSER const *variables)
Parse a configuration section into user-supplied variables.
int detail_socket_open(UNUSED CONF_SECTION *cs, UNUSED rad_listen_t *this)
static RADIUS_PACKET * detail_poll(rad_listen_t *listener)
union fr_ipaddr_t::@1 ipaddr
unsigned int code
Packet code (type).
fr_ipaddr_t ipaddr
IPv4/IPv6 address of the host.
int detail_encode(UNUSED rad_listen_t *this, UNUSED REQUEST *request)
Stores an attribute, a value and various bits of other data.
RADIUS_PACKET * reply
Outgoing response.
void void cf_log_err_cs(CONF_SECTION const *cs, char const *fmt,...) CC_HINT(format(printf
struct timeval last_packet
bool track
Do we track progress through the file?
RFC3575/RFC5176 - CoA-Request.
static int detail_delay(listen_detail_t *data)
int strcasecmp(char *s1, char *s2)
int request_receive(TALLOC_CTX *ctx, rad_listen_t *listener, RADIUS_PACKET *packet, RADCLIENT *client, RAD_REQUEST_FUNP fun)
Describes a host allowed to send packets to the server.
value_type_t type
Type of pointer in value union.
char const * filename_work
#define PW_TYPE_FILE_OUTPUT
File matching value must exist, and must be writeable.
#define FR_CONF_OFFSET(_n, _t, _s, _f)
VALUE_PAIR * fr_cursor_next(vp_cursor_t *cursor)
Advanced the cursor to the next VALUE_PAIR.
void fr_radius_free(RADIUS_PACKET **)
Free a RADIUS_PACKET.
void radius_signal_self(int flag)
int detail_send(rad_listen_t *listener, REQUEST *request)
RADIUS_PACKET * packet
Incoming request.
char const * name
Identifier used in log messages.
int detail_recv(rad_listen_t *listener)
static const CONF_PARSER detail_config[]
#define PW_TYPE_REQUIRED
Error out if no matching CONF_PAIR is found, and no dflt value is set.
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.
char const * longname
Client identifier.
size_t strlcpy(char *dst, char const *src, size_t siz)
bool done_entry
Are we done reading this entry?
char const * fr_int2str(FR_NAME_NUMBER const *table, int number, char const *def)
int rad_lockfd_nonblock(int fd, int lock_len)
static int detail_open(rad_listen_t *this)
FR_TOKEN fr_pair_list_afrom_str(TALLOC_CTX *ctx, char const *buffer, VALUE_PAIR **head)
Read one line of attribute/value pairs into a list.
char const * cf_section_name2(CONF_SECTION const *cs)
char const * shortname
Client nickname.
#define DEBUG_ENABLED2
True if global debug level 1-2 messages are enabled.
RFC3575/RFC5176 - Disconnect-Request.
size_t strlcat(char *dst, char const *src, size_t siz)