summaryrefslogtreecommitdiffstats
path: root/usr.sbin/ppp
diff options
context:
space:
mode:
authorbrian <brian@FreeBSD.org>2000-08-28 22:44:54 +0000
committerbrian <brian@FreeBSD.org>2000-08-28 22:44:54 +0000
commitcb1cdc90fa757e0475f2fa90070cd79541400475 (patch)
tree1920267811fb05c150fd456a8121562e12dc48c9 /usr.sbin/ppp
parentf47bf1f4e6a3f541e2923ccc99ff4e21f9b60094 (diff)
downloadFreeBSD-src-cb1cdc90fa757e0475f2fa90070cd79541400475.zip
FreeBSD-src-cb1cdc90fa757e0475f2fa90070cd79541400475.tar.gz
Support radius accounting, and add a packet count to throughput
statistics as a side effect. Submitted by: Marcin Cieslak <saper@system.pl> with some tweaks to RAD_ACCT_SESSION_ID and RAD_ACCT_MULTI_SESSION_ID generation by me.
Diffstat (limited to 'usr.sbin/ppp')
-rw-r--r--usr.sbin/ppp/bundle.c1
-rw-r--r--usr.sbin/ppp/bundle.h1
-rw-r--r--usr.sbin/ppp/ipcp.c11
-rw-r--r--usr.sbin/ppp/radius.c165
-rw-r--r--usr.sbin/ppp/radius.h19
-rw-r--r--usr.sbin/ppp/throughput.c12
-rw-r--r--usr.sbin/ppp/throughput.h2
7 files changed, 206 insertions, 5 deletions
diff --git a/usr.sbin/ppp/bundle.c b/usr.sbin/ppp/bundle.c
index e6f8787..3ca0f81 100644
--- a/usr.sbin/ppp/bundle.c
+++ b/usr.sbin/ppp/bundle.c
@@ -902,6 +902,7 @@ bundle_Destroy(struct bundle *bundle)
#ifndef NORADIUS
/* Tell the radius server the bad news */
+ log_Printf(LogDEBUG, "Radius: Destroy called from bundle_Destroy\n");
radius_Destroy(&bundle->radius);
#endif
diff --git a/usr.sbin/ppp/bundle.h b/usr.sbin/ppp/bundle.h
index 3bc6034..9ea2971 100644
--- a/usr.sbin/ppp/bundle.h
+++ b/usr.sbin/ppp/bundle.h
@@ -136,6 +136,7 @@ struct bundle {
#ifndef NORADIUS
struct radius radius; /* Info retrieved from radius server */
+ struct radacct radacct;
#endif
};
diff --git a/usr.sbin/ppp/ipcp.c b/usr.sbin/ppp/ipcp.c
index fc05447..1f5b2f1 100644
--- a/usr.sbin/ppp/ipcp.c
+++ b/usr.sbin/ppp/ipcp.c
@@ -957,6 +957,12 @@ IpcpLayerDown(struct fsm *fp)
s = "Interface configuration error !";
log_Printf(LogIPCP, "%s: LayerDown: %s\n", fp->link->name, s);
+#ifndef NORADIUS
+ radius_Account(&fp->bundle->radius, &fp->bundle->radacct,
+ fp->bundle->links, RAD_STOP, &ipcp->peer_ip, &ipcp->ifmask,
+ &ipcp->throughput);
+#endif
+
/*
* XXX this stuff should really live in the FSM. Our config should
* associate executable sections in files with events.
@@ -1009,6 +1015,11 @@ IpcpLayerUp(struct fsm *fp)
if (!ipcp_InterfaceUp(ipcp))
return 0;
+#ifndef NORADIUS
+ radius_Account(&fp->bundle->radius, &fp->bundle->radacct, fp->bundle->links,
+ RAD_START, &ipcp->peer_ip, &ipcp->ifmask, &ipcp->throughput);
+#endif
+
/*
* XXX this stuff should really live in the FSM. Our config should
* associate executable sections in files with events.
diff --git a/usr.sbin/ppp/radius.c b/usr.sbin/ppp/radius.c
index c868a67..f247043 100644
--- a/usr.sbin/ppp/radius.c
+++ b/usr.sbin/ppp/radius.c
@@ -117,6 +117,12 @@ radius_Process(struct radius *r, int got)
rad_close(r->cx.rad);
return;
+ case RAD_ACCOUNTING_RESPONSE:
+ log_Printf(LogPHASE, "Radius: Accounting response received\n");
+ /* No further processing for accounting requests, please */
+ rad_close(r->cx.rad);
+ return;
+
case -1:
log_Printf(LogPHASE, "radius: %s\n", rad_strerror(r->cx.rad));
auth_Failure(r->cx.auth);
@@ -325,6 +331,7 @@ radius_Init(struct radius *r)
r->desc.Read = radius_Read;
r->desc.Write = radius_Write;
memset(&r->cx.timer, '\0', sizeof r->cx.timer);
+ log_Printf(LogDEBUG, "Radius: radius_Init\n");
}
/*
@@ -334,6 +341,7 @@ void
radius_Destroy(struct radius *r)
{
r->valid = 0;
+ log_Printf(LogDEBUG, "Radius: radius_Destroy\n");
timer_Stop(&r->cx.timer);
route_DeleteAll(&r->routes);
if (r->cx.fd != -1) {
@@ -368,8 +376,8 @@ radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
radius_Destroy(r);
- if ((r->cx.rad = rad_open()) == NULL) {
- log_Printf(LogERROR, "rad_open: %s\n", strerror(errno));
+ if ((r->cx.rad = rad_auth_open()) == NULL) {
+ log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
return;
}
@@ -462,6 +470,159 @@ radius_Authenticate(struct radius *r, struct authinfo *authp, const char *name,
}
/*
+ * Send an accounting request to the RADIUS server
+ */
+void
+radius_Account(struct radius *r, struct radacct *ac, struct datalink *dl,
+ int acct_type, struct in_addr *peer_ip, struct in_addr *netmask,
+ struct pppThroughput *stats)
+{
+ struct ttyent *ttyp;
+ struct timeval tv;
+ int got, slot;
+ char hostname[MAXHOSTNAMELEN];
+ struct hostent *hp;
+ struct in_addr hostaddr;
+
+ if (!*r->cfg.file)
+ return;
+
+ if (r->cx.fd != -1)
+ /*
+ * We assume that our name/key/challenge is the same as last time,
+ * and just continue to wait for the RADIUS server(s).
+ */
+ return;
+
+ radius_Destroy(r);
+
+ if ((r->cx.rad = rad_auth_open()) == NULL) {
+ log_Printf(LogERROR, "rad_auth_open: %s\n", strerror(errno));
+ return;
+ }
+
+ if (rad_config(r->cx.rad, r->cfg.file) != 0) {
+ log_Printf(LogERROR, "rad_config: %s\n", rad_strerror(r->cx.rad));
+ rad_close(r->cx.rad);
+ return;
+ }
+
+ if (rad_create_request(r->cx.rad, RAD_ACCOUNTING_REQUEST) != 0) {
+ log_Printf(LogERROR, "rad_create_request: %s\n", rad_strerror(r->cx.rad));
+ rad_close(r->cx.rad);
+ return;
+ }
+
+ /* Grab some accounting data and initialize structure */
+ if (acct_type == RAD_START) {
+ ac->rad_parent = r;
+ /* Fetch username from datalink */
+ strncpy(ac->user_name, dl->peer.authname, sizeof ac->user_name);
+ ac->user_name[AUTHLEN-1] = '\0';
+
+ ac->authentic = 2; /* Assume RADIUS verified auth data */
+
+ /* Generate a session ID */
+ snprintf(ac->session_id, sizeof ac->session_id, "%s%d-%s%lu",
+ dl->bundle->cfg.auth.name, (int)getpid(),
+ dl->peer.authname, (unsigned long)stats->uptime);
+
+ /* And grab our MP socket name */
+ snprintf(ac->multi_session_id, sizeof ac->multi_session_id, "%s",
+ dl->bundle->ncp.mp.active ?
+ dl->bundle->ncp.mp.server.socket.sun_path : "");
+
+ /* Fetch IP, netmask from IPCP */
+ memcpy(&ac->ip, peer_ip, sizeof(ac->ip));
+ memcpy(&ac->mask, netmask, sizeof(ac->mask));
+ };
+
+ if (rad_put_string(r->cx.rad, RAD_USER_NAME, ac->user_name) != 0 ||
+ rad_put_int(r->cx.rad, RAD_SERVICE_TYPE, RAD_FRAMED) != 0 ||
+ rad_put_int(r->cx.rad, RAD_FRAMED_PROTOCOL, RAD_PPP) != 0 ||
+ rad_put_addr(r->cx.rad, RAD_FRAMED_IP_ADDRESS, ac->ip) != 0 ||
+ rad_put_addr(r->cx.rad, RAD_FRAMED_IP_NETMASK, ac->mask) != 0) {
+ log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
+ rad_close(r->cx.rad);
+ return;
+ }
+
+ if (gethostname(hostname, sizeof hostname) != 0)
+ log_Printf(LogERROR, "rad_put: gethostname(): %s\n", strerror(errno));
+ else {
+ if ((hp = gethostbyname(hostname)) != NULL) {
+ hostaddr.s_addr = *(u_long *)hp->h_addr;
+ if (rad_put_addr(r->cx.rad, RAD_NAS_IP_ADDRESS, hostaddr) != 0) {
+ log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
+ rad_strerror(r->cx.rad));
+ rad_close(r->cx.rad);
+ return;
+ }
+ }
+ if (rad_put_string(r->cx.rad, RAD_NAS_IDENTIFIER, hostname) != 0) {
+ log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
+ rad_strerror(r->cx.rad));
+ rad_close(r->cx.rad);
+ return;
+ }
+ }
+
+ if (dl->physical->handler &&
+ dl->physical->handler->type == TTY_DEVICE) {
+ setttyent();
+ for (slot = 1; (ttyp = getttyent()); ++slot)
+ if (!strcmp(ttyp->ty_name, dl->physical->name.base)) {
+ if(rad_put_int(r->cx.rad, RAD_NAS_PORT, slot) != 0) {
+ log_Printf(LogERROR, "rad_put: rad_put_string: %s\n",
+ rad_strerror(r->cx.rad));
+ rad_close(r->cx.rad);
+ endttyent();
+ return;
+ }
+ break;
+ }
+ endttyent();
+ }
+
+ if (rad_put_int(r->cx.rad, RAD_ACCT_STATUS_TYPE, acct_type) != 0 ||
+ rad_put_string(r->cx.rad, RAD_ACCT_SESSION_ID, ac->session_id) != 0 ||
+ rad_put_string(r->cx.rad, RAD_ACCT_MULTI_SESSION_ID,
+ ac->multi_session_id) != 0 ||
+ rad_put_int(r->cx.rad, RAD_ACCT_DELAY_TIME, 0) != 0) {
+/* XXX ACCT_DELAY_TIME should be increased each time a packet is waiting */
+ log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
+ rad_close(r->cx.rad);
+ return;
+ }
+
+ if (acct_type == RAD_STOP)
+ /* Show some statistics */
+ if (rad_put_int(r->cx.rad, RAD_ACCT_INPUT_OCTETS, stats->OctetsIn) != 0 ||
+ rad_put_int(r->cx.rad, RAD_ACCT_INPUT_PACKETS, stats->PacketsIn) != 0 ||
+ rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_OCTETS, stats->OctetsOut) != 0 ||
+ rad_put_int(r->cx.rad, RAD_ACCT_OUTPUT_PACKETS, stats->PacketsOut)
+ != 0 ||
+ rad_put_int(r->cx.rad, RAD_ACCT_SESSION_TIME, throughput_uptime(stats))
+ != 0) {
+ log_Printf(LogERROR, "rad_put: %s\n", rad_strerror(r->cx.rad));
+ rad_close(r->cx.rad);
+ return;
+ }
+
+ if ((got = rad_init_send_request(r->cx.rad, &r->cx.fd, &tv)))
+ radius_Process(r, got);
+ else {
+ 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;
+ r->cx.timer.name = "radius";
+ r->cx.timer.arg = r;
+ r->cx.auth = NULL; /* Not valid for accounting requests */
+ timer_Start(&r->cx.timer);
+ }
+}
+
+/*
* How do things look at the moment ?
*/
void
diff --git a/usr.sbin/ppp/radius.h b/usr.sbin/ppp/radius.h
index f9fdf3b..393b1d2 100644
--- a/usr.sbin/ppp/radius.h
+++ b/usr.sbin/ppp/radius.h
@@ -45,6 +45,16 @@ struct radius {
} cfg;
};
+struct radacct {
+ struct radius *rad_parent; /* "Parent" struct radius stored in bundle */
+ char user_name[AUTHLEN]; /* Session User-Name */
+ char session_id[256]; /* Unique session ID */
+ char multi_session_id[51]; /* Unique MP session ID */
+ int authentic; /* How the session has been authenticated */
+ struct in_addr ip;
+ struct in_addr mask;
+};
+
#define descriptor2radius(d) \
((d)->type == RADIUS_DESCRIPTOR ? (struct radius *)(d) : NULL)
@@ -56,3 +66,12 @@ extern void radius_Destroy(struct radius *);
extern void radius_Show(struct radius *, struct prompt *);
extern void radius_Authenticate(struct radius *, struct authinfo *,
const char *, const char *, const char *);
+extern void radius_Account(struct radius *, struct radacct *,
+ struct datalink *, int, struct in_addr *,
+ struct in_addr *, struct pppThroughput *);
+
+/* An (int) parameter to radius_Account, from radlib.h */
+#if !defined(RAD_START)
+#define RAD_START 1
+#define RAD_STOP 2
+#endif
diff --git a/usr.sbin/ppp/throughput.c b/usr.sbin/ppp/throughput.c
index 798878f..51c1a54 100644
--- a/usr.sbin/ppp/throughput.c
+++ b/usr.sbin/ppp/throughput.c
@@ -44,7 +44,7 @@
void
throughput_init(struct pppThroughput *t, int period)
{
- t->OctetsIn = t->OctetsOut = 0;
+ t->OctetsIn = t->OctetsOut = t->PacketsIn = t->PacketsOut = 0;
t->SamplePeriod = period;
t->in.SampleOctets = (long long *)
calloc(period, sizeof *t->in.SampleOctets);
@@ -111,6 +111,8 @@ throughput_disp(struct pppThroughput *t, struct prompt *prompt)
divisor = secs_up ? secs_up : 1;
prompt_Printf(prompt, "%llu octets in, %llu octets out\n",
t->OctetsIn, t->OctetsOut);
+ prompt_Printf(prompt, "%llu packets in, %llu packets out\n",
+ t->PacketsIn, t->PacketsOut);
if (t->rolling) {
prompt_Printf(prompt, " overall %6qu bytes/sec\n",
(t->OctetsIn + t->OctetsOut) / divisor);
@@ -137,8 +139,10 @@ throughput_log(struct pppThroughput *t, int level, const char *title)
if (title == NULL)
title = "";
log_Printf(level, "%s%sConnect time: %d secs: %llu octets in, %llu octets"
- " out\n", title, *title ? ": " : "", secs_up, t->OctetsIn,
- t->OctetsOut);
+ " out\n", title, *title ? ": " : "", secs_up, t->OctetsIn,
+ t->OctetsOut);
+ log_Printf(level, "%s%s: %llu packets in, %llu packets out\n",
+ title, *title ? ": " : "", t->PacketsIn, t->PacketsOut);
if (secs_up == 0)
secs_up = 1;
if (t->rolling)
@@ -235,12 +239,14 @@ void
throughput_addin(struct pppThroughput *t, long long n)
{
t->OctetsIn += n;
+ t->PacketsIn++;
}
void
throughput_addout(struct pppThroughput *t, long long n)
{
t->OctetsOut += n;
+ t->PacketsOut++;
}
void
diff --git a/usr.sbin/ppp/throughput.h b/usr.sbin/ppp/throughput.h
index 9dd1648..21e5450 100644
--- a/usr.sbin/ppp/throughput.h
+++ b/usr.sbin/ppp/throughput.h
@@ -37,6 +37,8 @@ struct pppThroughput {
time_t uptime, downtime;
unsigned long long OctetsIn;
unsigned long long OctetsOut;
+ unsigned long long PacketsIn;
+ unsigned long long PacketsOut;
int SamplePeriod;
struct {
unsigned long long *SampleOctets;
OpenPOWER on IntegriCloud