#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <sys/types.h>
#include "ntpd.h"
#include "ntp_if.h"
#include "ntp_stdlib.h"
#define INITRESLIST 10
#define INCRESLIST 5
struct restrictlist *restrictlist;
static int restrictcount;
static struct restrictlist *resfree;
static int numresfree;
static u_long res_calls;
static u_long res_found;
static u_long res_not_found;
u_long client_limit;
u_long client_limit_period;
static u_long res_limited_refcnt;
static struct restrictlist resinit[INITRESLIST];
void
init_restrict(void)
{
register int i;
char bp[80];
resfree = 0;
memset((char *)resinit, 0, sizeof resinit);
for (i = 1; i < INITRESLIST; i++) {
resinit[i].next = resfree;
resfree = &resinit[i];
}
numresfree = INITRESLIST-1;
resinit[0].addr = htonl(INADDR_ANY);
resinit[0].mask = 0;
restrictlist = &resinit[0];
restrictcount = 1;
res_calls = 0;
res_found = 0;
res_not_found = 0;
client_limit = 3;
client_limit_period = 3600;
res_limited_refcnt = 0;
sprintf(bp, "client_limit=%ld", client_limit);
set_sys_var(bp, strlen(bp)+1, RO);
sprintf(bp, "client_limit_period=%ld", client_limit_period);
set_sys_var(bp, strlen(bp)+1, RO);
}
int
restrictions(
struct sockaddr_in *srcadr
)
{
register struct restrictlist *rl;
register struct restrictlist *match;
register u_int32 hostaddr;
register int isntpport;
res_calls++;
hostaddr = SRCADR(srcadr);
isntpport = (SRCPORT(srcadr) == NTP_PORT);
if (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr)))
return (int)RES_IGNORE;
match = restrictlist;
for (rl = match->next; rl != 0 && rl->addr <= hostaddr; rl = rl->next)
if ((hostaddr & rl->mask) == rl->addr) {
if ((rl->mflags & RESM_NTPONLY) && !isntpport)
continue;
match = rl;
}
match->count++;
if (match == restrictlist)
res_not_found++;
else
res_found++;
if (match->flags & RES_LIMITED) {
int lcnt;
struct mon_data *md, *this_client;
#ifdef DEBUG
if (debug > 2)
printf("limited clients check: %ld clients, period %ld seconds, net is 0x%lX\n",
client_limit, client_limit_period,
(u_long)netof(hostaddr));
#endif
if (mon_enabled == MON_OFF) {
#ifdef DEBUG
if (debug > 4)
printf("no limit - monitoring is off\n");
#endif
return (int)(match->flags & ~RES_LIMITED);
}
this_client = mon_mru_list.mru_next;
for (md = mon_fifo_list.fifo_next,lcnt = 0;
md != &mon_fifo_list;
md = md->fifo_next) {
if ((current_time - md->lasttime)
> client_limit_period) {
#ifdef DEBUG
if (debug > 5)
printf("checking: %s: ignore: too old: %ld\n",
numtoa(md->rmtadr),
current_time - md->lasttime);
#endif
continue;
}
if (md->mode == MODE_BROADCAST ||
md->mode == MODE_CONTROL ||
md->mode == MODE_PRIVATE) {
#ifdef DEBUG
if (debug > 5)
printf("checking: %s: ignore mode %d\n",
numtoa(md->rmtadr),
md->mode);
#endif
continue;
}
if (netof(md->rmtadr) !=
netof(hostaddr)) {
#ifdef DEBUG
if (debug > 5)
printf("checking: %s: different net 0x%lX\n",
numtoa(md->rmtadr),
(u_long)netof(md->rmtadr));
#endif
continue;
}
lcnt++;
if (lcnt > (int) client_limit ||
md->rmtadr == hostaddr) {
#ifdef DEBUG
if (debug > 5)
printf("considering %s: found host\n",
numtoa(md->rmtadr));
#endif
break;
}
#ifdef DEBUG
else {
if (debug > 5)
printf("considering %s: same net\n",
numtoa(md->rmtadr));
}
#endif
}
#ifdef DEBUG
if (debug > 4)
printf("this one is rank %d in list, limit is %lu: %s\n",
lcnt, client_limit,
(lcnt <= (int) client_limit) ? "ALLOW" : "REJECT");
#endif
if (lcnt <= (int) client_limit) {
this_client->lastdrop = 0;
return (int)(match->flags & ~RES_LIMITED);
} else {
this_client->lastdrop = current_time;
}
}
return (int)match->flags;
}
void
hack_restrict(
int op,
struct sockaddr_in *resaddr,
struct sockaddr_in *resmask,
int mflags,
int flags
)
{
register u_int32 addr;
register u_int32 mask;
register struct restrictlist *rl;
register struct restrictlist *rlprev;
int i;
addr = SRCADR(resaddr);
mask = SRCADR(resmask);
addr &= mask;
if (addr == htonl(INADDR_ANY)) {
rlprev = 0;
rl = restrictlist;
} else {
rlprev = restrictlist;
rl = rlprev->next;
while (rl != 0) {
if (rl->addr > addr) {
rl = 0;
break;
} else if (rl->addr == addr) {
if (rl->mask == mask) {
if ((mflags & RESM_NTPONLY)
== (rl->mflags & RESM_NTPONLY))
break;
if (!(mflags & RESM_NTPONLY)) {
rl = 0;
break;
}
} else if (rl->mask > mask) {
rl = 0;
break;
}
}
rlprev = rl;
rl = rl->next;
}
}
switch (op) {
case RESTRICT_FLAGS:
if (rl == 0) {
if (numresfree == 0) {
rl = (struct restrictlist *) emalloc(
INCRESLIST*sizeof(struct restrictlist));
memset((char *)rl, 0,
INCRESLIST*sizeof(struct restrictlist));
for (i = 0; i < INCRESLIST; i++) {
rl->next = resfree;
resfree = rl;
rl++;
}
numresfree = INCRESLIST;
}
rl = resfree;
resfree = rl->next;
numresfree--;
rl->addr = addr;
rl->mask = mask;
rl->mflags = (u_short)mflags;
rl->next = rlprev->next;
rlprev->next = rl;
restrictcount++;
}
if ((rl->flags ^ (u_short)flags) & RES_LIMITED) {
res_limited_refcnt++;
mon_start(MON_RES);
}
rl->flags |= (u_short)flags;
break;
case RESTRICT_UNFLAG:
if (rl != 0) {
if ((rl->flags ^ (u_short)flags) & RES_LIMITED) {
res_limited_refcnt--;
if (res_limited_refcnt == 0)
mon_stop(MON_RES);
}
rl->flags &= (u_short)~flags;
}
break;
case RESTRICT_REMOVE:
if (rl != 0
&& rl->addr != htonl(INADDR_ANY)
&& !(rl->mflags & RESM_INTERFACE)) {
rlprev->next = rl->next;
restrictcount--;
if (rl->flags & RES_LIMITED) {
res_limited_refcnt--;
if (res_limited_refcnt == 0)
mon_stop(MON_RES);
}
memset((char *)rl, 0, sizeof(struct restrictlist));
rl->next = resfree;
resfree = rl;
numresfree++;
}
break;
default:
break;
}
}