Support a ``set rad_alive N'' command to enable periodic RADIUS accounting

information being sent to the RADIUS server.

Logging of RADIUS accounting information moves to a ``set log [+-]radius''
level, along with the RADIUS alive info, and the version number is bumped
to 3.2 to reflect this.

Mostly submitted by:	alx@sm.ukrtel.net (back in January)
MFC after:		3 weeks
This commit is contained in:
Brian Somers 2004-07-17 01:07:53 +00:00
parent 8a0f7000e6
commit e715b13bca
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=132273
7 changed files with 190 additions and 42 deletions

View File

@ -142,6 +142,7 @@
#define VAR_IFQUEUE 35
#define VAR_MPPE 36
#define VAR_IPV6CPRETRY 37
#define VAR_RAD_ALIVE 38
/* ``accept|deny|disable|enable'' masks */
#define NEG_HISMASK (1)
@ -165,7 +166,7 @@
#define NEG_MPPE 54
#define NEG_CHAP81 55
const char Version[] = "3.1";
const char Version[] = "3.2";
static int ShowCommand(struct cmdargs const *);
static int TerminalCommand(struct cmdargs const *);
@ -2026,7 +2027,30 @@ SetVariable(struct cmdargs const *arg)
bundle_SetIdleTimer(arg->bundle, timeout, min);
}
break;
#ifndef NORADIUS
case VAR_RAD_ALIVE:
if (arg->argc > arg->argn + 2) {
log_Printf(LogWARN, "Too many RADIUS alive interval values\n");
res = 1;
} else if (arg->argc == arg->argn) {
log_Printf(LogWARN, "Too few RADIUS alive interval values\n");
res = 1;
} else {
arg->bundle->radius.alive.interval = atoi(argp);
if (arg->bundle->radius.alive.interval && !arg->bundle->radius.cfg.file) {
log_Printf(LogWARN, "rad_alive requires radius to be configured\n");
res = 1;
} else if (arg->bundle->ncp.ipcp.fsm.state == ST_OPENED) {
if (arg->bundle->radius.alive.interval)
radius_StartTimer(arg->bundle);
else
radius_StopTimer(&arg->bundle->radius);
}
}
break;
#endif
case VAR_LQRPERIOD:
long_val = atol(argp);
if (long_val < MIN_LQRPERIOD) {
@ -2342,7 +2366,7 @@ static struct cmdtab const SetCommands[] = {
"set lcpretry value [attempts]", (const void *)VAR_LCPRETRY},
{"log", NULL, log_SetLevel, LOCAL_AUTH, "log level",
"set log [local] [+|-]all|async|cbcp|ccp|chat|command|connect|debug|dns|hdlc|"
"id0|ipcp|lcp|lqm|phase|physical|sync|tcp/ip|timer|tun..."},
"id0|ipcp|lcp|lqm|phase|physical|radius|sync|tcp/ip|timer|tun..."},
{"login", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
"login script", "set login chat-script", (const void *) VAR_LOGIN},
{"logout", NULL, SetVariable, LOCAL_AUTH | LOCAL_CX,
@ -2372,6 +2396,9 @@ static struct cmdtab const SetCommands[] = {
#ifndef NORADIUS
{"radius", NULL, SetVariable, LOCAL_AUTH,
"RADIUS Config", "set radius cfgfile", (const void *)VAR_RADIUS},
{"rad_alive", NULL, SetVariable, LOCAL_AUTH,
"Raduis alive interval", "set rad_alive value",
(const void *)VAR_RAD_ALIVE},
#endif
{"reconnect", NULL, datalink_SetReconnect, LOCAL_AUTH | LOCAL_CX,
"Reconnect timeout", "set reconnect value ntries"},

View File

@ -874,9 +874,10 @@ IpcpLayerDown(struct fsm *fp)
radius_Account(&fp->bundle->radius, &fp->bundle->radacct,
fp->bundle->links, RAD_STOP, &ipcp->throughput);
if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid)
system_Select(fp->bundle, fp->bundle->radius.filterid, LINKDOWNFILE,
NULL, NULL);
if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid)
system_Select(fp->bundle, fp->bundle->radius.filterid, LINKDOWNFILE,
NULL, NULL);
radius_StopTimer(&fp->bundle->radius);
#endif
/*
@ -945,6 +946,7 @@ IpcpLayerUp(struct fsm *fp)
if (fp->bundle->radius.cfg.file && fp->bundle->radius.filterid)
system_Select(fp->bundle, fp->bundle->radius.filterid, LINKUPFILE,
NULL, NULL);
radius_StartTimer(fp->bundle);
#endif
/*

View File

@ -60,6 +60,7 @@ static const char *const LogNames[] = {
"LQM",
"Phase",
"Physical",
"Radius",
"Sync",
"TCP/IP",
"Timer",

View File

@ -45,16 +45,17 @@
#define LogLQM (15)
#define LogPHASE (16)
#define LogPHYSICAL (17) /* syslog(LOG_INFO, ....) */
#define LogSYNC (18) /* syslog(LOG_INFO, ....) */
#define LogTCPIP (19)
#define LogTIMER (20) /* syslog(LOG_DEBUG, ....) */
#define LogTUN (21) /* If set, tun%d is output with each message */
#define LogWARN (22) /* Sent to VarTerm else syslog(LOG_WARNING, ) */
#define LogERROR (23) /* syslog(LOG_ERR, ....), + sent to VarTerm */
#define LogALERT (24) /* syslog(LOG_ALERT, ....) */
#define LogRADIUS (18) /* syslog(LOG_INFO, ....) */
#define LogSYNC (19) /* syslog(LOG_INFO, ....) */
#define LogTCPIP (20)
#define LogTIMER (21) /* syslog(LOG_DEBUG, ....) */
#define LogTUN (22) /* If set, tun%d is output with each message */
#define LogWARN (23) /* Sent to VarTerm else syslog(LOG_WARNING, ) */
#define LogERROR (24) /* syslog(LOG_ERR, ....), + sent to VarTerm */
#define LogALERT (25) /* syslog(LOG_ALERT, ....) */
#define LogMAXCONF (21)
#define LogMAX (24)
#define LogMAXCONF (22)
#define LogMAX (25)
struct mbuf;
struct cmdargs;

View File

@ -2335,6 +2335,14 @@ Generate LQR reports.
Phase transition log output.
.It Li Physical
Dump physical level packet in hex.
.It Li Radius
Dump RADIUS information.
RADIUS information resulting from the link coming up or down is logged at
.Dq Phase
level unless
.Dq Radius
logging is enabled.
This log level is most useful for monitoring RADIUS alive information.
.It Li Sync
Dump sync level packet in hex.
.It Li TCP/IP
@ -5479,6 +5487,16 @@ to function.
.Pp
Values received from the RADIUS server may be viewed using
.Dq show bundle .
.It set rad_alive Ar timeout
When RADIUS is configured, setting
.Dq rad_alive
to a non-zero
.Ar timeout
value will tell
.Nm
to sent RADIUS accounting information to the RADIUS server every
.Ar timeout
seconds.
.It set reconnect Ar timeout ntries
Should the line drop unexpectedly (due to loss of CD or LQR
failure), a connection will be re-established after the given

View File

@ -262,7 +262,8 @@ radius_Process(struct radius *r, int got)
switch (got) {
case RAD_ACCESS_ACCEPT:
log_Printf(LogPHASE, "Radius(%s): ACCEPT received\n", stype);
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
"Radius(%s): ACCEPT received\n", stype);
if (!r->cx.auth) {
rad_close(r->cx.rad);
return;
@ -270,7 +271,8 @@ radius_Process(struct radius *r, int got)
break;
case RAD_ACCESS_REJECT:
log_Printf(LogPHASE, "Radius(%s): REJECT received\n", stype);
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
"Radius(%s): REJECT received\n", stype);
if (!r->cx.auth) {
rad_close(r->cx.rad);
return;
@ -279,14 +281,22 @@ radius_Process(struct radius *r, int got)
case RAD_ACCESS_CHALLENGE:
/* we can't deal with this (for now) ! */
log_Printf(LogPHASE, "Radius: CHALLENGE received (can't handle yet)\n");
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
"Radius: CHALLENGE received (can't handle yet)\n");
if (r->cx.auth)
auth_Failure(r->cx.auth);
rad_close(r->cx.rad);
return;
case RAD_ACCOUNTING_RESPONSE:
log_Printf(LogPHASE, "Radius(%s): Accounting response received\n", stype);
/*
* It's probably not ideal to log this at PHASE level as we'll see
* too much stuff going to the log when ``set rad_alive'' is used.
* So we differ from older behaviour (ppp version 3.1 and before)
* and just log accounting responses to LogRADIUS.
*/
log_Printf(LogRADIUS, "Radius(%s): Accounting response received\n",
stype);
if (r->cx.auth)
auth_Failure(r->cx.auth); /* unexpected !!! */
@ -295,7 +305,8 @@ radius_Process(struct radius *r, int got)
return;
case -1:
log_Printf(LogPHASE, "radius(%s): %s\n", stype, rad_strerror(r->cx.rad));
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
"radius(%s): %s\n", stype, rad_strerror(r->cx.rad));
if (r->cx.auth)
auth_Failure(r->cx.auth);
rad_close(r->cx.rad);
@ -318,7 +329,8 @@ radius_Process(struct radius *r, int got)
switch (res) {
case RAD_FRAMED_IP_ADDRESS:
r->ip = rad_cvt_addr(data);
log_Printf(LogPHASE, " IP %s\n", inet_ntoa(r->ip));
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" IP %s\n", inet_ntoa(r->ip));
break;
case RAD_FILTER_ID:
@ -329,22 +341,26 @@ radius_Process(struct radius *r, int got)
rad_close(r->cx.rad);
return;
}
log_Printf(LogPHASE, " Filter \"%s\"\n", r->filterid);
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" Filter \"%s\"\n", r->filterid);
break;
case RAD_SESSION_TIMEOUT:
r->sessiontime = rad_cvt_int(data);
log_Printf(LogPHASE, " Session-Timeout %lu\n", r->sessiontime);
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" Session-Timeout %lu\n", r->sessiontime);
break;
case RAD_FRAMED_IP_NETMASK:
r->mask = rad_cvt_addr(data);
log_Printf(LogPHASE, " Netmask %s\n", inet_ntoa(r->mask));
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" Netmask %s\n", inet_ntoa(r->mask));
break;
case RAD_FRAMED_MTU:
r->mtu = rad_cvt_int(data);
log_Printf(LogPHASE, " MTU %lu\n", r->mtu);
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" MTU %lu\n", r->mtu);
break;
case RAD_FRAMED_ROUTING:
@ -356,7 +372,8 @@ radius_Process(struct radius *r, int got)
case RAD_FRAMED_COMPRESSION:
r->vj = rad_cvt_int(data) == 1 ? 1 : 0;
log_Printf(LogPHASE, " VJ %sabled\n", r->vj ? "en" : "dis");
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" VJ %sabled\n", r->vj ? "en" : "dis");
break;
case RAD_FRAMED_ROUTE:
@ -374,7 +391,8 @@ radius_Process(struct radius *r, int got)
return;
}
log_Printf(LogPHASE, " Route: %s\n", nuke);
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" Route: %s\n", nuke);
bundle = r->cx.auth->physical->dl->bundle;
ip.s_addr = INADDR_ANY;
ncpaddr_setip4(&gw, ip);
@ -424,7 +442,8 @@ radius_Process(struct radius *r, int got)
rad_close(r->cx.rad);
return;
}
log_Printf(LogPHASE, " Reply-Message \"%s\"\n", r->repstr);
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" Reply-Message \"%s\"\n", r->repstr);
break;
#ifndef NOINET6
@ -432,7 +451,8 @@ radius_Process(struct radius *r, int got)
free(r->ipv6prefix);
r->ipv6prefix = rad_cvt_ipv6prefix(data, len);
inet_ntop(AF_INET6, &r->ipv6prefix[2], ipv6addr, sizeof(ipv6addr));
log_Printf(LogPHASE, " IPv6 %s/%d\n", ipv6addr, r->ipv6prefix[1]);
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" IPv6 %s/%d\n", ipv6addr, r->ipv6prefix[1]);
break;
case RAD_FRAMED_IPV6_ROUTE:
@ -450,7 +470,8 @@ radius_Process(struct radius *r, int got)
return;
}
log_Printf(LogPHASE, " IPv6 Route: %s\n", nuke);
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" IPv6 Route: %s\n", nuke);
bundle = r->cx.auth->physical->dl->bundle;
ncpaddr_setip6(&gw, &in6addr_any);
ncprange_set(&dest, &gw, 0);
@ -522,7 +543,8 @@ radius_Process(struct radius *r, int got)
rad_close(r->cx.rad);
return;
}
log_Printf(LogPHASE, " MS-CHAP-Error \"%s\"\n", r->errstr);
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" MS-CHAP-Error \"%s\"\n", r->errstr);
}
break;
@ -549,32 +571,36 @@ radius_Process(struct radius *r, int got)
rad_close(r->cx.rad);
return;
}
log_Printf(LogPHASE, " MS-CHAP2-Success \"%s\"\n",
r->msrepstr);
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" MS-CHAP2-Success \"%s\"\n", r->msrepstr);
}
break;
case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_POLICY:
r->mppe.policy = rad_cvt_int(data);
log_Printf(LogPHASE, " MS-MPPE-Encryption-Policy %s\n",
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" MS-MPPE-Encryption-Policy %s\n",
radius_policyname(r->mppe.policy));
break;
case RAD_MICROSOFT_MS_MPPE_ENCRYPTION_TYPES:
r->mppe.types = rad_cvt_int(data);
log_Printf(LogPHASE, " MS-MPPE-Encryption-Types %s\n",
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" MS-MPPE-Encryption-Types %s\n",
radius_typesname(r->mppe.types));
break;
case RAD_MICROSOFT_MS_MPPE_RECV_KEY:
free(r->mppe.recvkey);
demangle(r, data, len, &r->mppe.recvkey, &r->mppe.recvkeylen);
log_Printf(LogPHASE, " MS-MPPE-Recv-Key ********\n");
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" MS-MPPE-Recv-Key ********\n");
break;
case RAD_MICROSOFT_MS_MPPE_SEND_KEY:
demangle(r, data, len, &r->mppe.sendkey, &r->mppe.sendkeylen);
log_Printf(LogPHASE, " MS-MPPE-Send-Key ********\n");
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
" MS-MPPE-Send-Key ********\n");
break;
#endif
@ -622,7 +648,8 @@ radius_Continue(struct radius *r, int sel)
timer_Stop(&r->cx.timer);
if ((got = rad_continue_send_request(r->cx.rad, sel, &r->cx.fd, &tv)) == 0) {
log_Printf(LogPHASE, "Radius: Request re-sent\n");
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
"Radius: Request re-sent\n");
r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
timer_Start(&r->cx.timer);
return;
@ -821,7 +848,7 @@ radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
struct timeval tv;
int got;
char hostname[MAXHOSTNAMELEN];
char *mac_addr;
char *mac_addr, *what;
#if 0
struct hostent *hp;
struct in_addr hostaddr;
@ -878,6 +905,7 @@ radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
rad_close(r->cx.rad);
return 0;
}
what = "PAP";
break;
case PROTO_CHAP:
@ -890,6 +918,7 @@ radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
rad_close(r->cx.rad);
return 0;
}
what = "CHAP";
break;
#ifndef NODES
@ -909,6 +938,7 @@ radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
RAD_MICROSOFT_MS_CHAP_RESPONSE, &msresp,
sizeof msresp);
what = "MSCHAP";
break;
case 0x81:
@ -930,6 +960,7 @@ radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
rad_put_vendor_attr(r->cx.rad, RAD_VENDOR_MICROSOFT,
RAD_MICROSOFT_MS_CHAP2_RESPONSE, &msresp2,
sizeof msresp2);
what = "MSCHAPv2";
break;
#endif
default:
@ -971,11 +1002,14 @@ radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
radius_put_physical_details(r->cx.rad, authp->physical);
log_Printf(LogRADIUS, "Radius(auth): %s data sent for %s\n", what, name);
r->cx.auth = authp;
if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
radius_Process(r, got);
else {
log_Printf(LogPHASE, "Radius: Request sent\n");
log_Printf(log_IsKept(LogRADIUS) ? LogRADIUS : LogPHASE,
"Radius: Request sent\n");
log_Printf(LogDEBUG, "Using radius_Timeout [%p]\n", radius_Timeout);
r->cx.timer.load = tv.tv_usec / TICKUNIT + tv.tv_sec * SECTICKS;
r->cx.timer.func = radius_Timeout;
@ -1159,8 +1193,8 @@ radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl,
return;
}
if (acct_type == RAD_STOP)
/* Show some statistics */
if (acct_type == RAD_STOP || acct_type == RAD_ALIVE)
/* Show some statistics */
if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn % UINT32_MAX) != 0 ||
rad_put_int(r->cx.rad, RAD_ACCT_INPUT_GIGAWORDS, stats->OctetsIn / UINT32_MAX) != 0 ||
rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 ||
@ -1175,6 +1209,31 @@ radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl,
return;
}
if (log_IsKept(LogPHASE) || log_IsKept(LogRADIUS)) {
char *what;
int level;
switch (acct_type) {
case RAD_START:
what = "START";
level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS;
break;
case RAD_STOP:
what = "STOP";
level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS;
break;
case RAD_ALIVE:
what = "ALIVE";
level = LogRADIUS;
break;
default:
what = "<unknown>";
level = log_IsKept(LogPHASE) ? LogPHASE : LogRADIUS;
break;
}
log_Printf(level, "Radius(acct): %s data sent\n", what);
}
r->cx.auth = NULL; /* Not valid for accounting requests */
if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
radius_Process(r, got);
@ -1222,3 +1281,35 @@ radius_Show(struct radius *r, struct prompt *p)
} else
prompt_Printf(p, " (not authenticated)\n");
}
static void
radius_alive(void *v)
{
struct bundle *bundle = (struct bundle *)v;
timer_Stop(&bundle->radius.alive.timer);
bundle->radius.alive.timer.load = bundle->radius.alive.interval * SECTICKS;
if (bundle->radius.alive.timer.load) {
radius_Account(&bundle->radius, &bundle->radacct,
bundle->links, RAD_ALIVE, &bundle->ncp.ipcp.throughput);
timer_Start(&bundle->radius.alive.timer);
}
}
void
radius_StartTimer(struct bundle *bundle)
{
if (bundle->radius.cfg.file && bundle->radius.alive.interval) {
bundle->radius.alive.timer.func = radius_alive;
bundle->radius.alive.timer.name = "radius alive";
bundle->radius.alive.timer.load = bundle->radius.alive.interval * SECTICKS;
bundle->radius.alive.timer.arg = bundle;
radius_alive(bundle);
}
}
void
radius_StopTimer(struct radius *r)
{
timer_Stop(&r->alive.timer);
}

View File

@ -66,6 +66,10 @@ struct radius {
struct {
char file[PATH_MAX]; /* Radius config file */
} cfg;
struct {
struct pppTimer timer; /* for this long */
int interval;
} alive;
};
struct radacct {
@ -97,6 +101,8 @@ extern void radius_Init(struct radius *);
extern void radius_Destroy(struct radius *);
extern void radius_Show(struct radius *, struct prompt *);
extern void radius_StartTimer(struct bundle *);
extern void radius_StopTimer(struct radius *);
extern int radius_Authenticate(struct radius *, struct authinfo *,
const char *, const char *, int,
const char *, int);
@ -114,5 +120,7 @@ extern void radius_Account(struct radius *, struct radacct *,
#define RAD_STOP 2
#endif
#define RAD_ALIVE 3
/* Get address from NAS pool */
#define RADIUS_INADDR_POOL htonl(0xfffffffe) /* 255.255.255.254 */