diff -urNb mpd-3.18.orig/src/link.c mpd-3.18/src/link.c --- mpd-3.18.orig/src/link.c Tue May 4 22:12:28 2004 +++ mpd-3.18/src/link.c Fri May 14 13:43:59 2004 @@ -236,6 +236,7 @@ lnk->conf.retry_timeout = LINK_DEFAULT_RETRY; lnk->bandwidth = LINK_DEFAULT_BANDWIDTH; lnk->latency = LINK_DEFAULT_LATENCY; + lnk->dropUser = 0; Disable(&lnk->conf.options, LINK_CONF_CHAPMD5); Accept(&lnk->conf.options, LINK_CONF_CHAPMD5); diff -urNb mpd-3.18.orig/src/link.h mpd-3.18/src/link.h --- mpd-3.18.orig/src/link.h Tue May 4 22:12:28 2004 +++ mpd-3.18/src/link.h Fri May 14 13:43:59 2004 @@ -95,6 +95,8 @@ u_int64_t runts; /* Too short MP fragments */ u_int64_t dupFragments; /* MP frames with duplicate seq # */ u_int64_t dropFragments; /* MP fragments we had to drop */ + u_int64_t sv_xmitOctets; /* update-limit support */ + u_int64_t sv_recvOctets; /* update-limit support */ }; typedef struct linkstat *LinkStats; @@ -133,6 +135,7 @@ char *downReason; /* Reason for link going down */ int bandwidth; /* Bandwidth in bits per second */ int latency; /* Latency in microseconds */ + int dropUser; /* should we drop connection? */ /* Info gleaned from negotiations */ struct in_range peer_allow; /* Range from /etc/ppp/secrets */ diff -urNb mpd-3.18.orig/src/ngfunc.c mpd-3.18/src/ngfunc.c --- mpd-3.18.orig/src/ngfunc.c Tue May 4 22:12:28 2004 +++ mpd-3.18/src/ngfunc.c Fri May 14 13:43:59 2004 @@ -215,7 +215,7 @@ newPpp = 1; /* Give it a name */ - snprintf(nm.name, sizeof(nm.name), "mpd%d-%s", getpid(), b->name); + snprintf(nm.name, sizeof(nm.name), "mpd-%s", b->name); if (NgSendMsg(b->csock, MPD_HOOK_PPP, NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) { Log(LG_ERR, ("[%s] can't name %s node: %s", diff -urNb mpd-3.18.orig/src/radius.c mpd-3.18/src/radius.c --- mpd-3.18.orig/src/radius.c Tue May 4 22:12:28 2004 +++ mpd-3.18/src/radius.c Fri May 14 13:51:33 2004 @@ -17,6 +17,14 @@ #include #include +#include +#include +#include +#include +#include +#include +#include + /* Global variables */ static int RadiusSetCommand(int ac, char *av[], void *arg); @@ -28,7 +36,8 @@ /* compatibility functions until libradius has these builtin */ static int rad_demangle2(struct rad_handle *, const void *, size_t, u_char *); static int rad_demangle_mppe_key2(struct rad_handle *, const void *, size_t, u_char *, size_t *); - + static int RadiusGetCurrentParams(); + static void FillCallerId(char *, size_t, struct in_addr); /* Set menu options */ @@ -38,7 +47,9 @@ SET_TIMEOUT, SET_RETRIES, SET_CONFIG, - SET_UPDATE + SET_UPDATE, + SET_UPDATE_LIMIT_IN, + SET_UPDATE_LIMIT_OUT }; /* @@ -58,6 +69,10 @@ RadiusSetCommand, NULL, (void *) SET_CONFIG }, { "acct-update ", "set update interval", RadiusSetCommand, NULL, (void *) SET_UPDATE }, + { "update-limit-in ", "set update limit (inbound traffic)", + RadiusSetCommand, NULL, (void *) SET_UPDATE_LIMIT_IN }, + { "update-limit-out ", "set update limit (outbound traffic)", + RadiusSetCommand, NULL, (void *) SET_UPDATE_LIMIT_OUT }, { NULL }, }; @@ -159,6 +174,22 @@ conf->acct_update = val; break; + case SET_UPDATE_LIMIT_IN: + val = atoi(*av); + if (val <= 0) + Log(LG_ERR, ("Update limit (in) must be positive.")); + else + conf->update_limit_in = val; + break; + + case SET_UPDATE_LIMIT_OUT: + val = atoi(*av); + if (val <= 0) + Log(LG_ERR, ("Update limit (out) must be positive.")); + else + conf->update_limit_out = val; + break; + case SET_RETRIES: val = atoi(*av); if (val <= 0) @@ -295,7 +326,7 @@ struct radius *rad = &bund->radius; char host[MAXHOSTNAMELEN]; struct in_addr *peer_ip; - char *peeripname; + char caller_id[256]; u_char *peer_mac; char peermacname[18]; @@ -358,9 +389,9 @@ peer_ip = PptpGetPeerIp(); if (peer_ip != NULL && peer_ip->s_addr != 0) { - peeripname = inet_ntoa(*peer_ip); - if (peeripname != NULL) { - if (rad_put_string(rad->radh, RAD_CALLING_STATION_ID, peeripname) == -1) { + FillCallerId(caller_id, sizeof(caller_id), *peer_ip); + if (caller_id[0]) { + if (rad_put_string(rad->radh, RAD_CALLING_STATION_ID, caller_id) == -1) { Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_put_string(RAD_CALLING_STATION_ID) failed %s", lnk->name, function, rad_strerror(rad->radh))); RadiusClose(); @@ -1035,6 +1066,13 @@ Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MPD_QUEUE: %s", lnk->name, function, acl2)); acls = &(rad->acl_queue); + } else if (res == RAD_MPD_DROP_USER) { + if (rad_cvt_int(data) == RAD_MPD_DROP_USER_YES) + lnk->dropUser++; + else + lnk->dropUser = 0; + Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MPD_DROP_USER: %d", lnk->name, function, lnk->dropUser)); + break; } else { Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping MPD vendor specific attribute: %d ", lnk->name, function, res)); break; @@ -1114,6 +1152,61 @@ return RAD_ACK; } +static int +RadiusGetCurrentParams() +{ + char function[] = "RadiusGetCurrentParams"; + struct radius *rad = &bund->radius; + int res; + size_t len; + const void *data; + u_int32_t vendor; + + while ((res = rad_get_attr(rad->radh, &data, &len)) > 0) { + + switch (res) { + + case RAD_VENDOR_SPECIFIC: + if ((res = rad_get_vendor_attr(&vendor, &data, &len)) == -1) { + Log(LG_RADIUS, ("[%s] RADIUS: %s: rad_get_vendor_attr failed: %s ", lnk->name, function, rad_strerror(rad->radh))); + return RAD_NACK; + } + + switch (vendor) { + + case RAD_VENDOR_MPD: + + switch (res) { + + case RAD_MPD_DROP_USER: + if (rad_cvt_int(data) == RAD_MPD_DROP_USER_YES) + lnk->dropUser++; + else + lnk->dropUser = 0; + Log(LG_RADIUS, ("[%s] RADIUS: %s: RAD_MPD_DROP_USER: %d", lnk->name, function, lnk->dropUser)); + break; + + default: + Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping MPD vendor specific attribute: %d", lnk->name, function, res)); + break; + } /* switch(res) */ + break; + + default: + Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping vendor %d attribute: %d ", lnk->name, function, vendor, res)); + break; + } /* switch(vendor) */ + break; + + default: + Log(LG_RADIUS, ("[%s] RADIUS: %s: Dropping attribute: %d ", lnk->name, function, res)); + break; + } + } + + return RAD_ACK; +} + void RadiusAcctUpdate(void *a) { @@ -1123,7 +1216,10 @@ lnk->name, function)); TimerStop(&lnk->radius.radUpdate); - RadiusAccount(RAD_UPDATE); + lnk->dropUser = 0; /* we MUST clear drop-user every time before checking */ + if (RadiusAccount(RAD_UPDATE) == RAD_ACK) + if (RadiusGetCurrentParams() == RAD_ACK && lnk->dropUser) + BundCloseLinks(); TimerStart(&lnk->radius.radUpdate); } @@ -1134,6 +1230,7 @@ char function[] = "RadiusAccount"; struct radius *rad = &bund->radius; int authentic; + int send_update = 0; /* Should we send acct-update? */ /* if Radius-Auth wasn't used, then copy in authname */ if (!strlen(rad->authname)) @@ -1258,11 +1355,34 @@ } } + if (!(rad->conf.update_limit_in || rad->conf.update_limit_out)) + send_update++; + else { + if (rad->conf.update_limit_in && + lnk->stats.recvOctets - lnk->stats.sv_recvOctets > rad->conf.update_limit_in) + send_update++; + if (rad->conf.update_limit_out && + lnk->stats.xmitOctets - lnk->stats.sv_xmitOctets > rad->conf.update_limit_out) + send_update++; + } + + if (acct_type == RAD_UPDATE && !send_update) { + Log(LG_RADIUS, ("[%s] RADIUS: %s: shouldn't send Interim-Update", + lnk->name, function)); + RadiusClose(); + return RAD_NACK; + } + Log(LG_RADIUS, ("[%s] RADIUS: %s: Sending accounting data (Type: %d)", lnk->name, function, acct_type)); if (RadiusSendRequest() == RAD_NACK) return RAD_NACK; + /* save old statistics (update-limit feature) */ + + lnk->stats.sv_recvOctets = lnk->stats.recvOctets; + lnk->stats.sv_xmitOctets = lnk->stats.xmitOctets; + return RAD_ACK; } @@ -1362,6 +1482,8 @@ printf("\tConfig-file : %s\n", conf->file); printf("\tMe (NAS-IP) : %s\n", inet_ntoa(conf->radius_me)); printf("\tAcct-Interval: %d\n", conf->acct_update); + printf("\tUpdate-Limit-In : %d\n", conf->update_limit_in); + printf("\tUpdate-Limit-Out: %d\n", conf->update_limit_out); if (conf->server != NULL) { @@ -1574,4 +1696,56 @@ memcpy(demangled, P + 1, *len); return 0; +} + +#define ROUNDUP(a) \ + ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long)) + +static void FillCallerId(char * caller_id, size_t len, struct in_addr peer_ip) +{ + int mib[6]; + int needed = 0; + int found = 0; + char * buf, * lim, * next; + struct rt_msghdr *rtm; + struct sockaddr_inarp *sin; + struct sockaddr_dl *sdl; + char ifname[IF_NAMESIZE]; + + mib[0] = CTL_NET; + mib[1] = PF_ROUTE; + mib[2] = 0; + mib[3] = AF_INET; + mib[4] = NET_RT_FLAGS; + mib[5] = RTF_LLINFO; + + memset(caller_id, 0, len); + + if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0) + return; + if (!(buf = (char *) malloc(needed))) + return; + if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) + return; + lim = buf + needed; + + for (next = buf; next < lim; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)next; + sin = (struct sockaddr_inarp *)(rtm + 1); + if (sin->sin_addr.s_addr != peer_ip.s_addr) + continue; + (char *)sdl = (char *)sin + ROUNDUP(sin->sin_len); + if_indextoname(sdl->sdl_index, ifname); + snprintf(caller_id, len - 1, "%s / %s / %s", + inet_ntoa(peer_ip), + ether_ntoa((struct ether_addr *)LLADDR(sdl)), + ifname); + found++; + break; + } + free(buf); + if (!found) + snprintf(caller_id, len - 1, "%s / (unknown) / (unknown)", + inet_ntoa(peer_ip)); + return; } diff -urNb mpd-3.18.orig/src/radius.h mpd-3.18/src/radius.h --- mpd-3.18.orig/src/radius.h Tue May 4 22:12:28 2004 +++ mpd-3.18/src/radius.h Fri May 14 13:49:35 2004 @@ -61,6 +61,11 @@ #define RAD_MPD_PIPE 2 #define RAD_MPD_QUEUE 3 +/* for dropping users */ +#define RAD_MPD_DROP_USER 154 /* Drop-User attribute */ +#define RAD_MPD_DROP_USER_NO 0 /* Drop-User: "No" value */ +#define RAD_MPD_DROP_USER_YES 1 /* Drop-User: "Yes" value */ + /* * FUNCTIONS */ @@ -101,6 +106,10 @@ int radius_timeout; int radius_retries; int acct_update; /* Accounting Update Interval */ + int update_limit_in; /* Send Update only when counters + grow more than "update_limit_xx" + since last update */ + int update_limit_out; struct in_addr radius_me; char file[PATH_MAX]; struct radiusserver_conf *server;