diff --git a/src/auth/pam.c b/src/auth/pam.c index 27a26218..0d4f663b 100644 --- a/src/auth/pam.c +++ b/src/auth/pam.c @@ -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; diff --git a/src/auth/radius.c b/src/auth/radius.c index e0253d28..a5326cb2 100644 --- a/src/auth/radius.c +++ b/src/auth/radius.c @@ -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) diff --git a/src/auth/radius.h b/src/auth/radius.h index cde2890f..37d61b64 100644 --- a/src/auth/radius.h +++ b/src/auth/radius.h @@ -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]; diff --git a/src/ipc.proto b/src/ipc.proto index 7879bec3..c6788b2b 100644 --- a/src/ipc.proto +++ b/src/ipc.proto @@ -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 diff --git a/src/main-misc.c b/src/main-misc.c index b5f9ac8c..f88ff02d 100644 --- a/src/main-misc.c +++ b/src/main-misc.c @@ -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); diff --git a/src/sec-mod-auth.c b/src/sec-mod-auth.c index b740f247..4421fd2f 100644 --- a/src/sec-mod-auth.c +++ b/src/sec-mod-auth.c @@ -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; diff --git a/src/sec-mod-auth.h b/src/sec-mod-auth.h index f95cf679..9040bee4 100644 --- a/src/sec-mod-auth.h +++ b/src/sec-mod-auth.h @@ -22,6 +22,7 @@ # define AUTH_H #include +#include #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); diff --git a/src/sec-mod.h b/src/sec-mod.h index 45fc2d4d..f87e267b 100644 --- a/src/sec-mod.h +++ b/src/sec-mod.h @@ -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_ */ diff --git a/src/worker-vpn.c b/src/worker-vpn.c index 7fc1c5a8..cee17fec 100644 --- a/src/worker-vpn.c +++ b/src/worker-vpn.c @@ -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; diff --git a/src/worker.h b/src/worker.h index 578eacd4..4dddcc2c 100644 --- a/src/worker.h +++ b/src/worker.h @@ -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;