mirror of
https://gitlab.com/openconnect/ocserv.git
synced 2026-02-10 00:37:00 +08:00
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:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user