radius: increase the info sent during accounting requests

Based on suggestions by Niels Peen. That adds:
Calling-Station-Id in auth message, and Service-Type,
Framed-Protocol, Framed-IP-Address, Acct-Authentic,
NAS-Port-Type, Acct-Session-Time in acct messages.
This commit is contained in:
Nikos Mavrogiannopoulos
2014-12-14 14:30:53 +01:00
parent 113ae94f13
commit 853f7876cd
10 changed files with 135 additions and 66 deletions

View File

@@ -367,7 +367,7 @@ int pret;
return 0;
}
static void pam_auth_close_session(void* ctx)
static void pam_auth_close_session(void* ctx, stats_st *stats)
{
struct pam_ctx_st * pctx = ctx;
int pret;

View File

@@ -72,6 +72,7 @@ static int radius_auth_init(void **ctx, void *pool, const char *username, const
return ERR_AUTH_FAIL;
snprintf(pctx->username, sizeof(pctx->username), "%s", username);
snprintf(pctx->remote_ip, sizeof(pctx->remote_ip), "%s", ip);
pctx->config = additional;
pctx->pass_msg = pass_msg_first;
@@ -145,6 +146,14 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len)
goto cleanup;
}
if (rc_avpair_add(rh, &send, PW_CALLING_STATION_ID, pctx->remote_ip, -1, 0) == NULL) {
syslog(LOG_ERR,
"%s:%u: user '%s' auth error", __func__, __LINE__,
pctx->username);
ret = ERR_AUTH_FAIL;
goto cleanup;
}
service = PW_AUTHENTICATE_ONLY;
if (rc_avpair_add(rh, &send, PW_SERVICE_TYPE, &service, -1, 0) == NULL) {
syslog(LOG_ERR,
@@ -168,7 +177,6 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len)
} else if (vp->attribute == RAD_GROUP_NAME && vp->type == PW_TYPE_STRING) {
/* Group-Name */
snprintf(pctx->groupname, sizeof(pctx->groupname), "%s", vp->strvalue);
#ifdef PW_FRAMED_IPV6_ADDRESS
} else if (vp->attribute == PW_FRAMED_IPV6_ADDRESS && vp->type == PW_TYPE_IPV6ADDR) {
/* Framed-IPv6-Address */
inet_ntop(AF_INET6, vp->strvalue, pctx->ipv6, sizeof(pctx->ipv6));
@@ -178,7 +186,6 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len)
inet_ntop(AF_INET6, vp->strvalue, pctx->ipv6_dns1, sizeof(pctx->ipv6_dns1));
else
inet_ntop(AF_INET6, vp->strvalue, pctx->ipv6_dns2, sizeof(pctx->ipv6_dns2));
#endif
} else if (vp->attribute == PW_FRAMED_IP_ADDRESS && vp->type == PW_TYPE_IPADDR) {
/* Framed-IP-Address */
ip = htonl(vp->lvalue);
@@ -244,14 +251,100 @@ static void radius_auth_deinit(void *ctx)
talloc_free(pctx);
}
static void append_stats(rc_handle *rh, VALUE_PAIR **send, stats_st *stats)
{
uint32_t uin, uout;
static void radius_auth_session_stats(void* ctx, uint64_t bytes_in, uint64_t bytes_out)
if (stats->uptime) {
uin = stats->uptime;
if (rc_avpair_add(rh, send, PW_ACCT_SESSION_TIME, &uin, -1, 0) == NULL) {
return;
}
}
uin = stats->bytes_in;
uout = stats->bytes_out;
if (rc_avpair_add(rh, send, PW_ACCT_INPUT_OCTETS, &uin, -1, 0) == NULL) {
return;
}
if (rc_avpair_add(rh, send, PW_ACCT_OUTPUT_OCTETS, &uout, -1, 0) == NULL) {
return;
}
uin = stats->bytes_in / 4294967296;
if (rc_avpair_add(rh, send, PW_ACCT_INPUT_GIGAWORDS, &uin, -1, 0) == NULL) {
return;
}
uout = stats->bytes_in / 4294967296;
if (rc_avpair_add(rh, send, PW_ACCT_OUTPUT_GIGAWORDS, &uout, -1, 0) == NULL) {
return;
}
return;
}
static void append_acct_standard(struct radius_ctx_st * pctx, rc_handle *rh,
VALUE_PAIR **send)
{
int i;
if (rc_avpair_add(rh, send, PW_USER_NAME, pctx->username, -1, 0) == NULL) {
return;
}
i = PW_FRAMED;
if (rc_avpair_add(rh, send, PW_SERVICE_TYPE, &i, -1, 0) == NULL) {
return;
}
i = PW_PPP;
if (rc_avpair_add(rh, send, PW_FRAMED_PROTOCOL, &i, -1, 0) == NULL) {
return;
}
if (pctx->ipv4[0] != 0) {
struct in_addr in;
inet_pton(AF_INET, pctx->ipv4, &in);
in.s_addr = ntohl(in.s_addr);
if (rc_avpair_add(rh, send, PW_FRAMED_IP_ADDRESS, &in, sizeof(in), 0) == NULL) {
return;
}
}
if (pctx->ipv6[0] != 0) {
struct in6_addr in;
inet_pton(AF_INET6, pctx->ipv6, &in);
if (rc_avpair_add(rh, send, PW_FRAMED_IPV6_ADDRESS, &in, sizeof(in), 0) == NULL) {
return;
}
}
if (rc_avpair_add(rh, send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) {
return;
}
i = PW_RADIUS;
if (rc_avpair_add(rh, send, PW_ACCT_AUTHENTIC, &i, -1, 0) == NULL) {
return;
}
i = PW_ASYNC;
if (rc_avpair_add(rh, send, PW_NAS_PORT_TYPE, &i, -1, 0) == NULL) {
return;
}
return;
}
static void radius_auth_session_stats(void* ctx, stats_st *stats)
{
struct radius_ctx_st * pctx = ctx;
int ret;
uint32_t status_type;
VALUE_PAIR *send = NULL, *recvd = NULL;
uint32_t uin, uout;
status_type = PW_STATUS_ALIVE;
@@ -262,40 +355,8 @@ uint32_t uin, uout;
goto cleanup;
}
if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
uin = bytes_in;
uout = bytes_out;
if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_OCTETS, &uin, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_OCTETS, &uout, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
uin = bytes_in / 4294967296;
if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_GIGAWORDS, &uin, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
uout = bytes_in / 4294967296;
if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_GIGAWORDS, &uout, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
append_acct_standard(pctx, rh, &send);
append_stats(rh, &send, stats);
ret = rc_aaa(rh, 0, send, &recvd, NULL, 1, PW_ACCOUNTING_REQUEST);
@@ -330,21 +391,13 @@ VALUE_PAIR *send = NULL, *recvd = NULL;
syslog(LOG_DEBUG, "opening session %s with radius", pctx->sid);
if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
append_acct_standard(pctx, rh, &send);
ret = rc_aaa(rh, 0, send, &recvd, NULL, 1, PW_ACCOUNTING_REQUEST);
if (recvd != NULL)
@@ -362,7 +415,7 @@ VALUE_PAIR *send = NULL, *recvd = NULL;
return ret;
}
static void radius_auth_close_session(void* ctx)
static void radius_auth_close_session(void* ctx, stats_st *stats)
{
struct radius_ctx_st * pctx = ctx;
int ret;
@@ -375,14 +428,13 @@ VALUE_PAIR *send = NULL, *recvd = NULL;
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL)
return;
if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) {
goto cleanup;
}
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) {
ret = PW_USER_REQUEST;
if (rc_avpair_add(rh, &send, PW_ACCT_TERMINATE_CAUSE, &ret, -1, 0) == NULL) {
goto cleanup;
}
append_acct_standard(pctx, rh, &send);
append_stats(rh, &send, stats);
ret = rc_aaa(rh, 0, send, &recvd, NULL, 1, PW_ACCOUNTING_REQUEST);
if (recvd != NULL)

View File

@@ -29,6 +29,8 @@ struct radius_ctx_st {
char groupname[MAX_GROUPNAME_SIZE];
char sid[BASE64_LENGTH(SID_SIZE) + 1];
char remote_ip[MAX_IP_STR];
/* variables for configuration */
char ipv4[MAX_IP_STR];
char ipv4_mask[MAX_IP_STR];

View File

@@ -87,6 +87,7 @@ message cli_stats_msg
required uint64 bytes_in = 1;
required uint64 bytes_out = 2;
optional bytes sid = 3; /* only required by sec-mod */
required uint32 uptime = 4; /* sec-mod */
}
/* UDP_FD */
@@ -188,6 +189,7 @@ message cookie
message sec_auth_session_msg
{
required bytes sid = 1;
optional uint32 uptime = 3; /* on close */
}
message sec_auth_session_reply_msg

View File

@@ -195,6 +195,8 @@ int session_cmd(main_server_st * s, struct proc_st *proc, unsigned open)
return -1;
}
ireq.uptime = time(0)-proc->conn_time;
ireq.has_uptime = 1;
ireq.sid.data = proc->sid;
ireq.sid.len = sizeof(proc->sid);

View File

@@ -368,6 +368,9 @@ int handle_sec_auth_session_cmd(int cfd, sec_mod_st * sec, const SecAuthSessionM
}
talloc_free(lpool);
} else {
if (req->has_uptime) {
e->stats.uptime = req->uptime;
}
del_client_entry(sec, e);
}
@@ -395,13 +398,14 @@ int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req)
return -1;
}
e->bytes_in = req->bytes_in;
e->bytes_out = req->bytes_out;
e->stats.bytes_in = req->bytes_in;
e->stats.bytes_out = req->bytes_out;
e->stats.uptime = req->uptime;
if (module == NULL || module->session_stats == NULL)
return 0;
module->session_stats(e->auth_ctx, e->bytes_in, e->bytes_out);
module->session_stats(e->auth_ctx, &e->stats);
return 0;
}
@@ -558,7 +562,7 @@ void sec_auth_user_deinit(sec_mod_st * sec, client_entry_st * e)
seclog(sec, LOG_DEBUG, "auth deinit for user '%s'", e->username);
if (e->auth_ctx != NULL) {
if (e->have_session) {
module->close_session(e->auth_ctx);
module->close_session(e->auth_ctx, &e->stats);
}
module->auth_deinit(e->auth_ctx);
e->auth_ctx = NULL;

View File

@@ -22,6 +22,7 @@
# define AUTH_H
#include <main.h>
#include <sec-mod.h>
#define MAX_AUTH_REQS 8
#define MAX_GROUPS 32
@@ -37,8 +38,8 @@ struct auth_mod_st {
int (*auth_user)(void* ctx, char *groupname, int groupname_size);
int (*open_session)(void *ctx, const void *sid, unsigned sid_size); /* optional, may be null */
void (*session_stats)(void *ctx, uint64_t bytes_in, uint64_t bytes_out); /* optional, may be null */
void (*close_session)(void *ctx); /* optional */
void (*session_stats)(void *ctx, struct stats_st *stats); /* optional, may be null */
void (*close_session)(void *ctx, struct stats_st *stats); /* optional may be null */
void (*auth_deinit)(void* ctx);
void (*group_list)(void *pool, void *additional, char ***groupname, unsigned *groupname_size);

View File

@@ -38,6 +38,11 @@ typedef struct sec_mod_st {
struct config_mod_st *config_module;
} sec_mod_st;
typedef struct stats_st {
uint64_t bytes_in;
uint64_t bytes_out;
time_t uptime;
} stats_st;
typedef struct client_entry_st {
/* A unique session identifier used to distinguish sessions
@@ -50,10 +55,7 @@ typedef struct client_entry_st {
unsigned have_session; /* whether an auth session is initialized */
unsigned tls_auth_ok;
/* these are filled in after the worker process dies, using the
* Cli stats message. */
uint64_t bytes_in;
uint64_t bytes_out;
stats_st stats;
unsigned status; /* PS_AUTH_ */

View File

@@ -713,6 +713,7 @@ void vpn_server(struct worker_st *ws)
"could not disable system calls, kernel might not support seccomp");
}
}
ws->session_start_time = time(0);
oclog(ws, LOG_DEBUG, "accepted connection");
if (ws->remote_addr_len == sizeof(struct sockaddr_in))
@@ -1004,6 +1005,7 @@ int periodic_check(worker_st * ws, unsigned mtu_overhead, time_t now,
if (sd >= 0) {
msg.bytes_in = ws->tun_bytes_in;
msg.bytes_out = ws->tun_bytes_out;
msg.uptime = now - ws->session_start_time;
msg.sid.len = sizeof(ws->sid);
msg.sid.data = ws->sid;
msg.has_sid = 1;

View File

@@ -154,7 +154,9 @@ typedef struct worker_st {
struct sockaddr_storage remote_addr; /* peer's address */
socklen_t remote_addr_len;
int proto; /* AF_INET or AF_INET6 */
time_t session_start_time;
/* for dead peer detection */
time_t last_msg_udp;
time_t last_msg_tcp;