diff -urNb pppd-radius.orig/options.c pppd-radius/options.c --- pppd-radius.orig/options.c Wed Jul 16 14:53:46 2003 +++ pppd-radius/options.c Wed Dec 10 19:39:28 2003 @@ -103,6 +103,7 @@ #ifdef RADIUS int useradius = 0; /* Use RADIUS for checking PAP */ u_int32_t nas_ip = 0; /* NAS IP addresss */ +int acct_update = 300; /* send Interim-Update every 5 minutes */ #endif int lcp_echo_interval = 0; /* Interval between LCP echo-requests */ int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */ @@ -200,6 +201,7 @@ #ifdef RADIUS static int setdoradius __P((char **)); static int setnasip __P((char **)); +static int setacctupdate __P((char **)); #endif static int setusehostname __P((char **)); static int setnoipdflt __P((char **)); @@ -358,6 +360,7 @@ #ifdef RADIUS {"radius", 0, setdoradius}, /* Use RADIUS for UPAP */ {"nas_ip", 1, setnasip}, /* NAS IP address */ + {"acct_update", 1, setacctupdate}, /* Interim-Update interval (seconds) */ #endif {"noipdefault", 0, setnoipdflt}, /* Don't use name for default IP adrs */ {"lcp-echo-failure", 1, setlcpechofails}, /* consecutive echo failures */ @@ -2055,6 +2058,22 @@ useradius = 1; inet_aton(*argv, (struct in_addr *)&nas_ip); return 1; +} + +static int +setacctupdate(argv) + char **argv; +{ + int value; + + if (!int_option(*argv, &value)) + return 0; + if (value < 0) { + option_error("acct_update time must be positive"); + return 0; + } + acct_update = value; + return 1; } #endif diff -urNb pppd-radius.orig/pppd.h pppd-radius/pppd.h --- pppd-radius.orig/pppd.h Wed Jul 16 14:54:07 2003 +++ pppd-radius/pppd.h Mon Dec 15 17:13:43 2003 @@ -99,6 +99,7 @@ #ifdef RADIUS extern int useradius; /* Use RADIUS for checking PAP */ extern u_int32_t nas_ip; /* NAS IP address */ +extern int acct_update; /* Interim-Update interval */ #endif extern int lcp_echo_interval; /* Interval between LCP echo-requests */ extern int lcp_echo_fails; /* Tolerance to unanswered echo-requests */ @@ -177,6 +178,13 @@ /* Table of pointers to supported protocols */ extern struct protent *protocols[]; +#ifdef RADIUS +struct pppd_stats { + unsigned int bytes_in; + unsigned int bytes_out; +}; +#endif + /* * Prototypes. */ @@ -307,6 +315,10 @@ #ifdef PPP_FILTER int set_filters __P((struct bpf_program *pass, struct bpf_program *active)); /* Set filter programs in kernel */ +#endif +#ifdef RADIUS +int get_ppp_stats __P((int, struct pppd_stats *)); + /* Return link statistics */ #endif /* Procedures exported from options.c */ diff -urNb pppd-radius.orig/radius.c pppd-radius/radius.c --- pppd-radius.orig/radius.c Wed Jul 23 17:53:27 2003 +++ pppd-radius/radius.c Tue Dec 16 12:17:08 2003 @@ -13,6 +13,7 @@ #include #include +#include "pppd.h" #include "radius.h" #include "fsm.h" #include "ipcp.h" @@ -24,11 +25,11 @@ static char rad_user[256], rad_tty[256], rad_session_id[17]; static char rad_called_id[64], rad_calling_id[64]; + int rad_login(char *user, char *port, char *pwd, u_int32_t remote) { char *p; size_t len; int rad_ret; /* RADIUS return code */ -// struct tm *tm; struct utmp utmp; struct rad_handle * rad; struct stat st; @@ -115,6 +116,8 @@ while ((rad_ret = rad_get_attr(rad, (const void **) &p, &len)) && rad_ret != -1) { if (rad_ret == RAD_FRAMED_IP_ADDRESS) { remote = htonl(rad_cvt_int(p)); + } else if (rad_ret == RAD_SESSION_TIMEOUT) { + maxconnect = rad_cvt_int(p); } } @@ -127,7 +130,7 @@ /* Create Session-ID */ /* FIXME: try to md5(nas_ip, stime, pid) */ - sprintf(rad_session_id, "%08X%08X", stime, getpid()); + sprintf(rad_session_id, "%08X", getpid()); /* RADIUS accounting */ @@ -172,6 +175,10 @@ rad_close(rad); /* RADIUS ACCT request finished successfully */ + /* setup acct_update timer */ + if (acct_update) + TIMEOUT(rad_alive_timeout, NULL, acct_update); + bzero(&utmp, sizeof(utmp)); time(&utmp.ut_time); strncpy(utmp.ut_name, rad_user, sizeof(utmp.ut_name)); @@ -194,6 +201,19 @@ time_t etime = time((time_t *) NULL); extern u_int32_t nas_ip; ipcp_options *ho = &ipcp_hisoptions[0]; /* it's safe cause NUM_PPP == 1 */ + struct pppd_stats link_stats; + int dummy = 0; + + /* Stop Alive timer */ + + UNTIMEOUT(rad_alive_timeout, NULL); + + /* Get some statistics */ + + memset(&link_stats, 0, sizeof(link_stats)); + + if (!get_ppp_stats(dummy, &link_stats)) + syslog(LOG_ERR, "get_ppp_stats() failed"); /* RADIUS accounting */ @@ -225,6 +245,8 @@ rad_put_string(rad, RAD_CALLING_STATION_ID, rad_calling_id) || rad_put_string(rad, RAD_CALLED_STATION_ID, rad_called_id) || rad_put_string(rad, RAD_ACCT_SESSION_ID, rad_session_id) || + rad_put_int(rad, RAD_ACCT_INPUT_OCTETS, link_stats.bytes_in) || + rad_put_int(rad, RAD_ACCT_OUTPUT_OCTETS, link_stats.bytes_out) || rad_put_int(rad, RAD_ACCT_STATUS_TYPE, RAD_STOP)) { syslog(LOG_ERR, "rad_put_XXX: %s", rad_strerror(rad)); rad_close(rad); @@ -245,4 +267,75 @@ logout(rad_tty); /* wipe out utmp log entry */ rad_logged_in = 0; +} + +void rad_acct_update() { + struct rad_handle * rad; + int rad_ret; /* RADIUS return code */ + extern time_t stime; + time_t now = time((time_t *) NULL); /* current time */ + extern u_int32_t nas_ip; + ipcp_options *ho = &ipcp_hisoptions[0]; /* it's safe cause NUM_PPP == 1 */ + struct pppd_stats link_stats; + int dummy = 0; + + /* First, get some statistics */ + + memset(&link_stats, 0, sizeof(link_stats)); + + if (!get_ppp_stats(dummy, &link_stats)) + syslog(LOG_ERR, "get_ppp_stats() failed"); + + /* RADIUS accounting */ + + if (!(rad = rad_acct_open())) { + syslog(LOG_ERR, "rad_acct_open: %d", errno); + return; + } + + if (rad_config(rad, NULL)) { + syslog(LOG_ERR, "rad_config: %s", rad_strerror(rad)); + rad_close(rad); + return; + } + + if (rad_create_request(rad, RAD_ACCOUNTING_REQUEST)) { + syslog(LOG_ERR, "rad_create_request(acct): %s", rad_strerror(rad)); + rad_close(rad); + return; + } + + if (rad_put_int(rad, RAD_NAS_IP_ADDRESS, ntohl(nas_ip)) || + rad_put_int(rad, RAD_NAS_PORT_TYPE, RAD_ASYNC) || + rad_put_int(rad, RAD_NAS_PORT, rad_port) || + rad_put_string(rad, RAD_USER_NAME, rad_user) || + rad_put_int(rad, RAD_SERVICE_TYPE, RAD_FRAMED) || + rad_put_int(rad, RAD_FRAMED_PROTOCOL, RAD_PPP) || + rad_put_int(rad, RAD_FRAMED_IP_ADDRESS, ntohl(inet_addr(rad_ipaddr))) || + rad_put_int(rad, RAD_ACCT_SESSION_TIME, now - stime) || + rad_put_string(rad, RAD_CALLING_STATION_ID, rad_calling_id) || + rad_put_string(rad, RAD_CALLED_STATION_ID, rad_called_id) || + rad_put_string(rad, RAD_ACCT_SESSION_ID, rad_session_id) || + rad_put_int(rad, RAD_ACCT_INPUT_OCTETS, link_stats.bytes_in) || + rad_put_int(rad, RAD_ACCT_OUTPUT_OCTETS, link_stats.bytes_out) || + rad_put_int(rad, RAD_ACCT_STATUS_TYPE, RAD_ALIVE)) { + syslog(LOG_ERR, "rad_put_XXX: %s", rad_strerror(rad)); + rad_close(rad); + return; + } + + if ((rad_ret = rad_send_request(rad)) == -1) { + syslog(LOG_ERR, "rad_send_request(acct): %s", rad_strerror(rad)); + rad_close(rad); + return; + } + + rad_close(rad); /* RADIUS ACCT request finished successfully */ +} + +void rad_alive_timeout() +{ + rad_acct_update(); + if (acct_update) + TIMEOUT(rad_alive_timeout, NULL, acct_update); } diff -urNb pppd-radius.orig/radius.h pppd-radius/radius.h --- pppd-radius.orig/radius.h Tue Jul 15 17:01:12 2003 +++ pppd-radius/radius.h Wed Dec 10 19:40:03 2003 @@ -3,10 +3,15 @@ #include +#ifndef RAD_ALIVE +#define RAD_ALIVE 3 /* Interim-Update accounting type */ +#endif + extern int rad_logged_in; extern char rad_ipaddr[64]; int rad_login(char *, char *, char *, u_int32_t); void rad_logout(); +void rad_alive_timeout(); #endif /* RADIUS_H */ diff -urNb pppd-radius.orig/sys-bsd.c pppd-radius/sys-bsd.c --- pppd-radius.orig/sys-bsd.c Mon Nov 04 19:02:46 2002 +++ pppd-radius/sys-bsd.c Mon Dec 15 17:20:19 2003 @@ -1590,3 +1590,52 @@ lock_file = NULL; } } + +#ifdef RADIUS +/* my own replacement for strlcpy(3) */ + +size_t +xstrlcpy(char *dst, const char *src, size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++); + } + return (s - src - 1); /* count does not include NUL */ +} + +/* + * get_ppp_stats - return statistics for the link. + */ +int +get_ppp_stats(u, stats) + int u; + struct pppd_stats *stats; +{ + struct ifpppstatsreq req; + + memset (&req, 0, sizeof (req)); + xstrlcpy(req.ifr_name, ifname, sizeof(req.ifr_name)); + if (ioctl(sockfd, SIOCGPPPSTATS, &req) < 0) + return 0; + stats->bytes_in = req.stats.p.ppp_ibytes; + stats->bytes_out = req.stats.p.ppp_obytes; + return 1; +} +#endif