#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 SET_IPV6_ADDR_MASK(dst, src, msk) \
do { \
int idx; \
for (idx = 0; idx < 16; idx++) { \
(dst)->s6_addr[idx] = \
(u_char) ((src)->s6_addr[idx] & (msk)->s6_addr[idx]); \
} \
} while (0)
#define INITRESLIST 10
#define INCRESLIST 5
struct restrictlist *restrictlist;
struct restrictlist6 *restrictlist6;
static int restrictcount;
static int restrictcount6;
static struct restrictlist *resfree;
static struct restrictlist6 *resfree6;
static int numresfree;
static int numresfree6;
static u_long res_calls;
static u_long res_found;
static u_long res_not_found;
static u_long res_limited_refcnt;
static u_long res_limited_refcnt6;
static struct restrictlist resinit[INITRESLIST];
static struct restrictlist6 resinit6[INITRESLIST];
void
init_restrict(void)
{
register int i;
resfree = 0;
memset((char *)resinit, 0, sizeof resinit);
resfree6 = 0;
memset((char *)resinit6, 0, sizeof resinit6);
for (i = 1; i < INITRESLIST; i++) {
resinit[i].next = resfree;
resinit6[i].next = resfree6;
resfree = &resinit[i];
resfree6 = &resinit6[i];
}
numresfree = INITRESLIST-1;
numresfree6 = INITRESLIST-1;
resinit[0].addr = htonl(INADDR_ANY);
resinit[0].mask = 0;
memset(&resinit6[0].addr6, 0, sizeof(struct in6_addr));
memset(&resinit6[0].mask6, 0, sizeof(struct in6_addr));
restrictlist = &resinit[0];
restrictlist6 = &resinit6[0];
restrictcount = 1;
restrictcount = 2;
res_calls = 0;
res_found = 0;
res_not_found = 0;
res_limited_refcnt = 0;
res_limited_refcnt6 = 0;
}
int
restrictions(
sockaddr_u *srcadr
)
{
struct restrictlist *rl;
struct restrictlist *match = NULL;
struct restrictlist6 *rl6;
struct restrictlist6 *match6 = NULL;
struct in6_addr hostaddr6;
struct in6_addr hostservaddr6;
u_int32 hostaddr;
int flags = 0;
int isntpport;
res_calls++;
if (IS_IPV4(srcadr)) {
hostaddr = SRCADR(srcadr);
isntpport = (NTP_PORT == SRCPORT(srcadr));
if (IN_CLASSD(SRCADR(srcadr)))
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++;
flags = match->flags;
}
if (IS_IPV6(srcadr)) {
hostaddr6 = SOCK_ADDR6(srcadr);
isntpport = (NTP_PORT == SRCPORT(srcadr));
if (IN6_IS_ADDR_MULTICAST(&hostaddr6))
return (int)RES_IGNORE;
match6 = restrictlist6;
for (rl6 = match6->next; rl6 != 0 &&
(memcmp(&(rl6->addr6), &hostaddr6,
sizeof(hostaddr6)) <= 0); rl6 = rl6->next) {
SET_IPV6_ADDR_MASK(&hostservaddr6, &hostaddr6,
&rl6->mask6);
if (memcmp(&hostservaddr6, &(rl6->addr6),
sizeof(hostservaddr6)) == 0) {
if ((rl6->mflags & RESM_NTPONLY) &&
!isntpport)
continue;
match6 = rl6;
}
}
match6->count++;
if (match6 == restrictlist6)
res_not_found++;
else
res_found++;
flags = match6->flags;
}
return (flags);
}
void
hack_restrict(
int op,
sockaddr_u *resaddr,
sockaddr_u *resmask,
int mflags,
int flags
)
{
register u_int32 addr = 0;
register u_int32 mask = 0;
struct in6_addr addr6;
struct in6_addr mask6;
register struct restrictlist *rl = NULL;
register struct restrictlist *rlprev = NULL;
register struct restrictlist6 *rl6 = NULL;
register struct restrictlist6 *rlprev6 = NULL;
int i, addr_cmp, mask_cmp;
memset(&addr6, 0, sizeof(struct in6_addr));
memset(&mask6, 0, sizeof(struct in6_addr));
if (IS_IPV4(resaddr)) {
DPRINTF(1, ("restrict: addr %08x mask %08x mflags %08x flags %08x\n",
SRCADR(resaddr), SRCADR(resmask), mflags, flags));
addr = SRCADR(resaddr);
mask = SRCADR(resmask);
addr &= mask;
if (addr == 0) {
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;
}
}
}
if (IS_IPV6(resaddr)) {
mask6 = SOCK_ADDR6(resmask);
SET_IPV6_ADDR_MASK(&addr6,
PSOCK_ADDR6(resaddr), &mask6);
if (IN6_IS_ADDR_UNSPECIFIED(&addr6)) {
rlprev6 = NULL;
rl6 = restrictlist6;
} else {
rlprev6 = restrictlist6;
rl6 = rlprev6->next;
while (rl6 != 0) {
addr_cmp = memcmp(&rl6->addr6, &addr6,
sizeof(addr6));
if (addr_cmp > 0) {
rl6 = 0;
break;
} else if (addr_cmp == 0) {
mask_cmp = memcmp(&rl6->mask6,
&mask6, sizeof(mask6));
if (mask_cmp == 0) {
if ((mflags &
RESM_NTPONLY) ==
(rl6->mflags &
RESM_NTPONLY))
break;
if (!(mflags &
RESM_NTPONLY)) {
rl6 = 0;
break;
}
} else if (mask_cmp > 0) {
rl6 = 0;
break;
}
}
rlprev6 = rl6;
rl6 = rl6->next;
}
}
}
if (IS_IPV4(resaddr)) {
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;
if (rlprev == NULL) {
rl->next = restrictlist;
restrictlist = rl;
} else {
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:
case RESTRICT_REMOVEIF:
if (rl != 0
&& rl->addr != htonl(INADDR_ANY)
&& !(rl->mflags & RESM_INTERFACE && op !=
RESTRICT_REMOVEIF)) {
if (rlprev != NULL) {
rlprev->next = rl->next;
} else {
restrictlist = 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;
}
} else if (IS_IPV6(resaddr)) {
switch (op) {
case RESTRICT_FLAGS:
if (rl6 == 0) {
if (numresfree6 == 0) {
rl6 = (struct
restrictlist6 *)emalloc(
INCRESLIST * sizeof(struct
restrictlist6));
memset((char *)rl6, 0,
INCRESLIST * sizeof(struct
restrictlist6));
for (i = 0; i < INCRESLIST;
i++) {
rl6->next = resfree6;
resfree6 = rl6;
rl6++;
}
numresfree6 = INCRESLIST;
}
rl6 = resfree6;
resfree6 = rl6->next;
numresfree6--;
rl6->addr6 = addr6;
rl6->mask6 = mask6;
rl6->mflags = (u_short)mflags;
if (rlprev6 != NULL) {
rl6->next = rlprev6->next;
rlprev6->next = rl6;
} else {
rl6->next = restrictlist6;
restrictlist6 = rl6;
}
restrictcount6++;
}
if ((rl6->flags ^ (u_short)flags) &
RES_LIMITED) {
res_limited_refcnt6++;
mon_start(MON_RES);
}
rl6->flags |= (u_short)flags;
break;
case RESTRICT_UNFLAG:
if (rl6 != 0) {
if ((rl6->flags ^ (u_short)flags) &
RES_LIMITED) {
res_limited_refcnt6--;
if (res_limited_refcnt6 == 0)
mon_stop(MON_RES);
}
rl6->flags &= (u_short)~flags;
}
break;
case RESTRICT_REMOVE:
case RESTRICT_REMOVEIF:
if (rl6 != 0 &&
!IN6_IS_ADDR_UNSPECIFIED(&rl6->addr6)
&& !(rl6->mflags & RESM_INTERFACE && op !=
RESTRICT_REMOVEIF)) {
if (rlprev6 != NULL) {
rlprev6->next = rl6->next;
} else {
restrictlist6 = rl6->next;
}
restrictcount6--;
if (rl6->flags & RES_LIMITED) {
res_limited_refcnt6--;
if (res_limited_refcnt6 == 0)
mon_stop(MON_RES);
}
memset((char *)rl6, 0,
sizeof(struct restrictlist6));
rl6->next = resfree6;
resfree6 = rl6;
numresfree6++;
}
break;
default:
break;
}
}
}