154359Sroberto/* 2132451Sroberto * ntp_restrict.c - determine host restrictions 354359Sroberto */ 454359Sroberto#ifdef HAVE_CONFIG_H 554359Sroberto#include <config.h> 654359Sroberto#endif 754359Sroberto 854359Sroberto#include <stdio.h> 954359Sroberto#include <sys/types.h> 1054359Sroberto 1154359Sroberto#include "ntpd.h" 1254359Sroberto#include "ntp_if.h" 13290001Sglebius#include "ntp_lists.h" 1454359Sroberto#include "ntp_stdlib.h" 15290001Sglebius#include "ntp_assert.h" 1654359Sroberto 1754359Sroberto/* 1854359Sroberto * This code keeps a simple address-and-mask list of hosts we want 19132451Sroberto * to place restrictions on (or remove them from). The restrictions 2054359Sroberto * are implemented as a set of flags which tell you what the host 21132451Sroberto * can't do. There is a subroutine entry to return the flags. The 2254359Sroberto * list is kept sorted to reduce the average number of comparisons 2354359Sroberto * and make sure you get the set of restrictions most specific to 2454359Sroberto * the address. 2554359Sroberto * 2654359Sroberto * The algorithm is that, when looking up a host, it is first assumed 27132451Sroberto * that the default set of restrictions will apply. It then searches 28132451Sroberto * down through the list. Whenever it finds a match it adopts the 29132451Sroberto * match's flags instead. When you hit the point where the sorted 30132451Sroberto * address is greater than the target, you return with the last set of 31132451Sroberto * flags you found. Because of the ordering of the list, the most 32132451Sroberto * specific match will provide the final set of flags. 3354359Sroberto * 3454359Sroberto * This was originally intended to restrict you from sync'ing to your 35132451Sroberto * own broadcasts when you are doing that, by restricting yourself from 36132451Sroberto * your own interfaces. It was also thought it would sometimes be useful 37132451Sroberto * to keep a misbehaving host or two from abusing your primary clock. It 38132451Sroberto * has been expanded, however, to suit the needs of those with more 39132451Sroberto * restrictive access policies. 4054359Sroberto */ 41132451Sroberto/* 42132451Sroberto * We will use two lists, one for IPv4 addresses and one for IPv6 43132451Sroberto * addresses. This is not protocol-independant but for now I can't 44132451Sroberto * find a way to respect this. We'll check this later... JFB 07/2001 45132451Sroberto */ 46290001Sglebius#define MASK_IPV6_ADDR(dst, src, msk) \ 47290001Sglebius do { \ 48290001Sglebius int idx; \ 49290001Sglebius for (idx = 0; idx < (int)COUNTOF((dst)->s6_addr); idx++) { \ 50290001Sglebius (dst)->s6_addr[idx] = (src)->s6_addr[idx] \ 51290001Sglebius & (msk)->s6_addr[idx]; \ 52290001Sglebius } \ 53132451Sroberto } while (0) 5454359Sroberto 5554359Sroberto/* 56290001Sglebius * We allocate INC_RESLIST{4|6} entries to the free list whenever empty. 57290001Sglebius * Auto-tune these to be just less than 1KB (leaving at least 16 bytes 58290001Sglebius * for allocator overhead). 5954359Sroberto */ 60290001Sglebius#define INC_RESLIST4 ((1024 - 16) / V4_SIZEOF_RESTRICT_U) 61290001Sglebius#define INC_RESLIST6 ((1024 - 16) / V6_SIZEOF_RESTRICT_U) 6254359Sroberto 6354359Sroberto/* 6454359Sroberto * The restriction list 6554359Sroberto */ 66290001Sglebiusrestrict_u *restrictlist4; 67290001Sglebiusrestrict_u *restrictlist6; 68290001Sglebiusstatic int restrictcount; /* count in the restrict lists */ 6954359Sroberto 7054359Sroberto/* 7154359Sroberto * The free list and associated counters. Also some uninteresting 7254359Sroberto * stat counters. 7354359Sroberto */ 74290001Sglebiusstatic restrict_u *resfree4; /* available entries (free list) */ 75290001Sglebiusstatic restrict_u *resfree6; 7654359Sroberto 77290001Sglebiusstatic u_long res_calls; 78290001Sglebiusstatic u_long res_found; 79290001Sglebiusstatic u_long res_not_found; 8054359Sroberto 8154359Sroberto/* 82290001Sglebius * Count number of restriction entries referring to RES_LIMITED, to 83290001Sglebius * control implicit activation/deactivation of the MRU monlist. 8454359Sroberto */ 85290001Sglebiusstatic u_long res_limited_refcnt; 86132451Sroberto 8754359Sroberto/* 88290001Sglebius * Our default entries. 8954359Sroberto */ 90290001Sglebiusstatic restrict_u restrict_def4; 91290001Sglebiusstatic restrict_u restrict_def6; 9254359Sroberto 9354359Sroberto/* 94290001Sglebius * "restrict source ..." enabled knob and restriction bits. 9554359Sroberto */ 96290001Sglebiusstatic int restrict_source_enabled; 97290001Sglebiusstatic u_short restrict_source_flags; 98290001Sglebiusstatic u_short restrict_source_mflags; 9954359Sroberto 10054359Sroberto/* 101290001Sglebius * private functions 102290001Sglebius */ 103290001Sglebiusstatic restrict_u * alloc_res4(void); 104290001Sglebiusstatic restrict_u * alloc_res6(void); 105290001Sglebiusstatic void free_res(restrict_u *, int); 106290001Sglebiusstatic void inc_res_limited(void); 107290001Sglebiusstatic void dec_res_limited(void); 108290001Sglebiusstatic restrict_u * match_restrict4_addr(u_int32, u_short); 109290001Sglebiusstatic restrict_u * match_restrict6_addr(const struct in6_addr *, 110290001Sglebius u_short); 111290001Sglebiusstatic restrict_u * match_restrict_entry(const restrict_u *, int); 112290001Sglebiusstatic int res_sorts_before4(restrict_u *, restrict_u *); 113290001Sglebiusstatic int res_sorts_before6(restrict_u *, restrict_u *); 114290001Sglebius 115290001Sglebius 116290001Sglebius/* 11754359Sroberto * init_restrict - initialize the restriction data structures 11854359Sroberto */ 11954359Srobertovoid 12054359Srobertoinit_restrict(void) 12154359Sroberto{ 12254359Sroberto /* 123290001Sglebius * The restriction lists begin with a default entry with address 124290001Sglebius * and mask 0, which will match any entry. The lists are kept 125290001Sglebius * sorted by descending address followed by descending mask: 126290001Sglebius * 127290001Sglebius * address mask 128290001Sglebius * 192.168.0.0 255.255.255.0 kod limited noquery nopeer 129290001Sglebius * 192.168.0.0 255.255.0.0 kod limited 130290001Sglebius * 0.0.0.0 0.0.0.0 kod limited noquery 131290001Sglebius * 132290001Sglebius * The first entry which matches an address is used. With the 133290001Sglebius * example restrictions above, 192.168.0.0/24 matches the first 134290001Sglebius * entry, the rest of 192.168.0.0/16 matches the second, and 135290001Sglebius * everything else matches the third (default). 136290001Sglebius * 137290001Sglebius * Note this achieves the same result a little more efficiently 138290001Sglebius * than the documented behavior, which is to keep the lists 139290001Sglebius * sorted by ascending address followed by ascending mask, with 140290001Sglebius * the _last_ matching entry used. 141290001Sglebius * 142290001Sglebius * An additional wrinkle is we may have multiple entries with 143290001Sglebius * the same address and mask but differing match flags (mflags). 144290001Sglebius * At present there is only one, RESM_NTPONLY. Entries with 145290001Sglebius * RESM_NTPONLY are sorted earlier so they take precedence over 146290001Sglebius * any otherwise similar entry without. Again, this is the same 147290001Sglebius * behavior as but reversed implementation compared to the docs. 148290001Sglebius * 14954359Sroberto */ 150290001Sglebius LINK_SLIST(restrictlist4, &restrict_def4, link); 151290001Sglebius LINK_SLIST(restrictlist6, &restrict_def6, link); 152290001Sglebius restrictcount = 2; 153290001Sglebius} 154290001Sglebius 155290001Sglebius 156290001Sglebiusstatic restrict_u * 157290001Sglebiusalloc_res4(void) 158290001Sglebius{ 159290001Sglebius const size_t cb = V4_SIZEOF_RESTRICT_U; 160290001Sglebius const size_t count = INC_RESLIST4; 161290001Sglebius restrict_u * rl; 162290001Sglebius restrict_u * res; 163293896Sglebius size_t i; 164290001Sglebius 165290001Sglebius UNLINK_HEAD_SLIST(res, resfree4, link); 166290001Sglebius if (res != NULL) 167290001Sglebius return res; 168290001Sglebius 169290001Sglebius rl = emalloc_zero(count * cb); 170290001Sglebius /* link all but the first onto free list */ 171290001Sglebius res = (void *)((char *)rl + (count - 1) * cb); 172290001Sglebius for (i = count - 1; i > 0; i--) { 173290001Sglebius LINK_SLIST(resfree4, res, link); 174290001Sglebius res = (void *)((char *)res - cb); 17554359Sroberto } 176290001Sglebius INSIST(rl == res); 177290001Sglebius /* allocate the first */ 178290001Sglebius return res; 179290001Sglebius} 18054359Sroberto 18154359Sroberto 182290001Sglebiusstatic restrict_u * 183290001Sglebiusalloc_res6(void) 184290001Sglebius{ 185290001Sglebius const size_t cb = V6_SIZEOF_RESTRICT_U; 186290001Sglebius const size_t count = INC_RESLIST6; 187290001Sglebius restrict_u * rl; 188290001Sglebius restrict_u * res; 189293896Sglebius size_t i; 19054359Sroberto 191290001Sglebius UNLINK_HEAD_SLIST(res, resfree6, link); 192290001Sglebius if (res != NULL) 193290001Sglebius return res; 194290001Sglebius 195290001Sglebius rl = emalloc_zero(count * cb); 196290001Sglebius /* link all but the first onto free list */ 197290001Sglebius res = (void *)((char *)rl + (count - 1) * cb); 198290001Sglebius for (i = count - 1; i > 0; i--) { 199290001Sglebius LINK_SLIST(resfree6, res, link); 200290001Sglebius res = (void *)((char *)res - cb); 201290001Sglebius } 202290001Sglebius INSIST(rl == res); 203290001Sglebius /* allocate the first */ 204290001Sglebius return res; 20554359Sroberto} 20654359Sroberto 20754359Sroberto 208290001Sglebiusstatic void 209290001Sglebiusfree_res( 210290001Sglebius restrict_u * res, 211290001Sglebius int v6 212290001Sglebius ) 213290001Sglebius{ 214290001Sglebius restrict_u ** plisthead; 215290001Sglebius restrict_u * unlinked; 216290001Sglebius 217290001Sglebius restrictcount--; 218290001Sglebius if (RES_LIMITED & res->flags) 219290001Sglebius dec_res_limited(); 220290001Sglebius 221290001Sglebius if (v6) 222290001Sglebius plisthead = &restrictlist6; 223290001Sglebius else 224290001Sglebius plisthead = &restrictlist4; 225290001Sglebius UNLINK_SLIST(unlinked, *plisthead, res, link, restrict_u); 226290001Sglebius INSIST(unlinked == res); 227290001Sglebius 228290001Sglebius if (v6) { 229290001Sglebius zero_mem(res, V6_SIZEOF_RESTRICT_U); 230290001Sglebius plisthead = &resfree6; 231290001Sglebius } else { 232290001Sglebius zero_mem(res, V4_SIZEOF_RESTRICT_U); 233290001Sglebius plisthead = &resfree4; 234290001Sglebius } 235290001Sglebius LINK_SLIST(*plisthead, res, link); 236290001Sglebius} 237290001Sglebius 238290001Sglebius 239290001Sglebiusstatic void 240290001Sglebiusinc_res_limited(void) 241290001Sglebius{ 242290001Sglebius if (!res_limited_refcnt) 243290001Sglebius mon_start(MON_RES); 244290001Sglebius res_limited_refcnt++; 245290001Sglebius} 246290001Sglebius 247290001Sglebius 248290001Sglebiusstatic void 249290001Sglebiusdec_res_limited(void) 250290001Sglebius{ 251290001Sglebius res_limited_refcnt--; 252290001Sglebius if (!res_limited_refcnt) 253290001Sglebius mon_stop(MON_RES); 254290001Sglebius} 255290001Sglebius 256290001Sglebius 257290001Sglebiusstatic restrict_u * 258290001Sglebiusmatch_restrict4_addr( 259290001Sglebius u_int32 addr, 260290001Sglebius u_short port 261290001Sglebius ) 262290001Sglebius{ 263290001Sglebius const int v6 = 0; 264290001Sglebius restrict_u * res; 265290001Sglebius restrict_u * next; 266290001Sglebius 267290001Sglebius for (res = restrictlist4; res != NULL; res = next) { 268290001Sglebius next = res->link; 269290001Sglebius if (res->expire && 270290001Sglebius res->expire <= current_time) 271290001Sglebius free_res(res, v6); 272290001Sglebius if (res->u.v4.addr == (addr & res->u.v4.mask) 273290001Sglebius && (!(RESM_NTPONLY & res->mflags) 274290001Sglebius || NTP_PORT == port)) 275290001Sglebius break; 276290001Sglebius } 277290001Sglebius return res; 278290001Sglebius} 279290001Sglebius 280290001Sglebius 281290001Sglebiusstatic restrict_u * 282290001Sglebiusmatch_restrict6_addr( 283290001Sglebius const struct in6_addr * addr, 284290001Sglebius u_short port 285290001Sglebius ) 286290001Sglebius{ 287290001Sglebius const int v6 = 1; 288290001Sglebius restrict_u * res; 289290001Sglebius restrict_u * next; 290290001Sglebius struct in6_addr masked; 291290001Sglebius 292290001Sglebius for (res = restrictlist6; res != NULL; res = next) { 293290001Sglebius next = res->link; 294290001Sglebius INSIST(next != res); 295290001Sglebius if (res->expire && 296290001Sglebius res->expire <= current_time) 297290001Sglebius free_res(res, v6); 298290001Sglebius MASK_IPV6_ADDR(&masked, addr, &res->u.v6.mask); 299290001Sglebius if (ADDR6_EQ(&masked, &res->u.v6.addr) 300290001Sglebius && (!(RESM_NTPONLY & res->mflags) 301290001Sglebius || NTP_PORT == (int)port)) 302290001Sglebius break; 303290001Sglebius } 304290001Sglebius return res; 305290001Sglebius} 306290001Sglebius 307290001Sglebius 30854359Sroberto/* 309290001Sglebius * match_restrict_entry - find an exact match on a restrict list. 310290001Sglebius * 311290001Sglebius * Exact match is addr, mask, and mflags all equal. 312290001Sglebius * In order to use more common code for IPv4 and IPv6, this routine 313290001Sglebius * requires the caller to populate a restrict_u with mflags and either 314290001Sglebius * the v4 or v6 address and mask as appropriate. Other fields in the 315290001Sglebius * input restrict_u are ignored. 316290001Sglebius */ 317290001Sglebiusstatic restrict_u * 318290001Sglebiusmatch_restrict_entry( 319290001Sglebius const restrict_u * pmatch, 320290001Sglebius int v6 321290001Sglebius ) 322290001Sglebius{ 323290001Sglebius restrict_u *res; 324290001Sglebius restrict_u *rlist; 325290001Sglebius size_t cb; 326290001Sglebius 327290001Sglebius if (v6) { 328290001Sglebius rlist = restrictlist6; 329290001Sglebius cb = sizeof(pmatch->u.v6); 330290001Sglebius } else { 331290001Sglebius rlist = restrictlist4; 332290001Sglebius cb = sizeof(pmatch->u.v4); 333290001Sglebius } 334290001Sglebius 335290001Sglebius for (res = rlist; res != NULL; res = res->link) 336290001Sglebius if (res->mflags == pmatch->mflags && 337290001Sglebius !memcmp(&res->u, &pmatch->u, cb)) 338290001Sglebius break; 339290001Sglebius return res; 340290001Sglebius} 341290001Sglebius 342290001Sglebius 343290001Sglebius/* 344290001Sglebius * res_sorts_before4 - compare two restrict4 entries 345290001Sglebius * 346290001Sglebius * Returns nonzero if r1 sorts before r2. We sort by descending 347290001Sglebius * address, then descending mask, then descending mflags, so sorting 348290001Sglebius * before means having a higher value. 349290001Sglebius */ 350290001Sglebiusstatic int 351290001Sglebiusres_sorts_before4( 352290001Sglebius restrict_u *r1, 353290001Sglebius restrict_u *r2 354290001Sglebius ) 355290001Sglebius{ 356290001Sglebius int r1_before_r2; 357290001Sglebius 358290001Sglebius if (r1->u.v4.addr > r2->u.v4.addr) 359290001Sglebius r1_before_r2 = 1; 360290001Sglebius else if (r1->u.v4.addr < r2->u.v4.addr) 361290001Sglebius r1_before_r2 = 0; 362290001Sglebius else if (r1->u.v4.mask > r2->u.v4.mask) 363290001Sglebius r1_before_r2 = 1; 364290001Sglebius else if (r1->u.v4.mask < r2->u.v4.mask) 365290001Sglebius r1_before_r2 = 0; 366290001Sglebius else if (r1->mflags > r2->mflags) 367290001Sglebius r1_before_r2 = 1; 368290001Sglebius else 369290001Sglebius r1_before_r2 = 0; 370290001Sglebius 371290001Sglebius return r1_before_r2; 372290001Sglebius} 373290001Sglebius 374290001Sglebius 375290001Sglebius/* 376290001Sglebius * res_sorts_before6 - compare two restrict6 entries 377290001Sglebius * 378290001Sglebius * Returns nonzero if r1 sorts before r2. We sort by descending 379290001Sglebius * address, then descending mask, then descending mflags, so sorting 380290001Sglebius * before means having a higher value. 381290001Sglebius */ 382290001Sglebiusstatic int 383290001Sglebiusres_sorts_before6( 384290001Sglebius restrict_u *r1, 385290001Sglebius restrict_u *r2 386290001Sglebius ) 387290001Sglebius{ 388290001Sglebius int r1_before_r2; 389290001Sglebius int cmp; 390290001Sglebius 391290001Sglebius cmp = ADDR6_CMP(&r1->u.v6.addr, &r2->u.v6.addr); 392290001Sglebius if (cmp > 0) /* r1->addr > r2->addr */ 393290001Sglebius r1_before_r2 = 1; 394290001Sglebius else if (cmp < 0) /* r2->addr > r1->addr */ 395290001Sglebius r1_before_r2 = 0; 396290001Sglebius else { 397290001Sglebius cmp = ADDR6_CMP(&r1->u.v6.mask, &r2->u.v6.mask); 398290001Sglebius if (cmp > 0) /* r1->mask > r2->mask*/ 399290001Sglebius r1_before_r2 = 1; 400290001Sglebius else if (cmp < 0) /* r2->mask > r1->mask */ 401290001Sglebius r1_before_r2 = 0; 402290001Sglebius else if (r1->mflags > r2->mflags) 403290001Sglebius r1_before_r2 = 1; 404290001Sglebius else 405290001Sglebius r1_before_r2 = 0; 406290001Sglebius } 407290001Sglebius 408290001Sglebius return r1_before_r2; 409290001Sglebius} 410290001Sglebius 411290001Sglebius 412290001Sglebius/* 41354359Sroberto * restrictions - return restrictions for this host 41454359Sroberto */ 415290001Sglebiusu_short 41654359Srobertorestrictions( 417290001Sglebius sockaddr_u *srcadr 41854359Sroberto ) 41954359Sroberto{ 420290001Sglebius restrict_u *match; 421290001Sglebius struct in6_addr *pin6; 422290001Sglebius u_short flags; 42354359Sroberto 42454359Sroberto res_calls++; 425290001Sglebius flags = 0; 426290001Sglebius /* IPv4 source address */ 427290001Sglebius if (IS_IPV4(srcadr)) { 428132451Sroberto /* 429132451Sroberto * Ignore any packets with a multicast source address 430132451Sroberto * (this should be done early in the receive process, 431290001Sglebius * not later!) 432132451Sroberto */ 433132451Sroberto if (IN_CLASSD(SRCADR(srcadr))) 434132451Sroberto return (int)RES_IGNORE; 43554359Sroberto 436290001Sglebius match = match_restrict4_addr(SRCADR(srcadr), 437290001Sglebius SRCPORT(srcadr)); 438290001Sglebius 439290001Sglebius INSIST(match != NULL); 440290001Sglebius 441290001Sglebius match->count++; 442132451Sroberto /* 443290001Sglebius * res_not_found counts only use of the final default 444290001Sglebius * entry, not any "restrict default ntpport ...", which 445290001Sglebius * would be just before the final default. 446132451Sroberto */ 447290001Sglebius if (&restrict_def4 == match) 448132451Sroberto res_not_found++; 449132451Sroberto else 450132451Sroberto res_found++; 451132451Sroberto flags = match->flags; 452132451Sroberto } 45354359Sroberto 454132451Sroberto /* IPv6 source address */ 455290001Sglebius if (IS_IPV6(srcadr)) { 456290001Sglebius pin6 = PSOCK_ADDR6(srcadr); 45754359Sroberto 458132451Sroberto /* 459132451Sroberto * Ignore any packets with a multicast source address 460132451Sroberto * (this should be done early in the receive process, 461290001Sglebius * not later!) 462132451Sroberto */ 463290001Sglebius if (IN6_IS_ADDR_MULTICAST(pin6)) 464132451Sroberto return (int)RES_IGNORE; 46554359Sroberto 466290001Sglebius match = match_restrict6_addr(pin6, SRCPORT(srcadr)); 467290001Sglebius INSIST(match != NULL); 468290001Sglebius match->count++; 469290001Sglebius if (&restrict_def6 == match) 470132451Sroberto res_not_found++; 471132451Sroberto else 472132451Sroberto res_found++; 473290001Sglebius flags = match->flags; 47454359Sroberto } 475132451Sroberto return (flags); 47654359Sroberto} 47754359Sroberto 47854359Sroberto 47954359Sroberto/* 48054359Sroberto * hack_restrict - add/subtract/manipulate entries on the restrict list 48154359Sroberto */ 48254359Srobertovoid 48354359Srobertohack_restrict( 484290001Sglebius int op, 485290001Sglebius sockaddr_u * resaddr, 486290001Sglebius sockaddr_u * resmask, 487290001Sglebius u_short mflags, 488290001Sglebius u_short flags, 489290001Sglebius u_long expire 49054359Sroberto ) 49154359Sroberto{ 492290001Sglebius int v6; 493290001Sglebius restrict_u match; 494290001Sglebius restrict_u * res; 495290001Sglebius restrict_u ** plisthead; 49654359Sroberto 497290001Sglebius DPRINTF(1, ("restrict: op %d addr %s mask %s mflags %08x flags %08x\n", 498290001Sglebius op, stoa(resaddr), stoa(resmask), mflags, flags)); 499290001Sglebius 500290001Sglebius if (NULL == resaddr) { 501290001Sglebius REQUIRE(NULL == resmask); 502290001Sglebius REQUIRE(RESTRICT_FLAGS == op); 503290001Sglebius restrict_source_flags = flags; 504290001Sglebius restrict_source_mflags = mflags; 505290001Sglebius restrict_source_enabled = 1; 506290001Sglebius return; 507290001Sglebius } 508290001Sglebius 509290001Sglebius ZERO(match); 510290001Sglebius 511290001Sglebius#if 0 512290001Sglebius /* silence VC9 potentially uninit warnings */ 513290001Sglebius // HMS: let's use a compiler-specific "enable" for this. 514290001Sglebius res = NULL; 515290001Sglebius v6 = 0; 516290001Sglebius#endif 517290001Sglebius 518290001Sglebius if (IS_IPV4(resaddr)) { 519290001Sglebius v6 = 0; 520132451Sroberto /* 521290001Sglebius * Get address and mask in host byte order for easy 522290001Sglebius * comparison as u_int32 523132451Sroberto */ 524290001Sglebius match.u.v4.addr = SRCADR(resaddr); 525290001Sglebius match.u.v4.mask = SRCADR(resmask); 526290001Sglebius match.u.v4.addr &= match.u.v4.mask; 52754359Sroberto 528290001Sglebius } else if (IS_IPV6(resaddr)) { 529290001Sglebius v6 = 1; 530132451Sroberto /* 531290001Sglebius * Get address and mask in network byte order for easy 532290001Sglebius * comparison as byte sequences (e.g. memcmp()) 533132451Sroberto */ 534290001Sglebius match.u.v6.mask = SOCK_ADDR6(resmask); 535290001Sglebius MASK_IPV6_ADDR(&match.u.v6.addr, PSOCK_ADDR6(resaddr), 536290001Sglebius &match.u.v6.mask); 537132451Sroberto 538290001Sglebius } else /* not IPv4 nor IPv6 */ 539290001Sglebius REQUIRE(0); 540132451Sroberto 541290001Sglebius match.flags = flags; 542290001Sglebius match.mflags = mflags; 543290001Sglebius match.expire = expire; 544290001Sglebius res = match_restrict_entry(&match, v6); 545132451Sroberto 546290001Sglebius switch (op) { 547290001Sglebius 548290001Sglebius case RESTRICT_FLAGS: 549290001Sglebius /* 550290001Sglebius * Here we add bits to the flags. If this is a 551290001Sglebius * new restriction add it. 552290001Sglebius */ 553290001Sglebius if (NULL == res) { 554290001Sglebius if (v6) { 555290001Sglebius res = alloc_res6(); 556290001Sglebius memcpy(res, &match, 557290001Sglebius V6_SIZEOF_RESTRICT_U); 558290001Sglebius plisthead = &restrictlist6; 559290001Sglebius } else { 560290001Sglebius res = alloc_res4(); 561290001Sglebius memcpy(res, &match, 562290001Sglebius V4_SIZEOF_RESTRICT_U); 563290001Sglebius plisthead = &restrictlist4; 56454359Sroberto } 565290001Sglebius LINK_SORT_SLIST( 566290001Sglebius *plisthead, res, 567290001Sglebius (v6) 568290001Sglebius ? res_sorts_before6(res, L_S_S_CUR()) 569290001Sglebius : res_sorts_before4(res, L_S_S_CUR()), 570290001Sglebius link, restrict_u); 571290001Sglebius restrictcount++; 572290001Sglebius if (RES_LIMITED & flags) 573290001Sglebius inc_res_limited(); 574290001Sglebius } else { 575290001Sglebius if ((RES_LIMITED & flags) && 576290001Sglebius !(RES_LIMITED & res->flags)) 577290001Sglebius inc_res_limited(); 578290001Sglebius res->flags |= flags; 57954359Sroberto } 580290001Sglebius break; 581132451Sroberto 582290001Sglebius case RESTRICT_UNFLAG: 583290001Sglebius /* 584290001Sglebius * Remove some bits from the flags. If we didn't 585290001Sglebius * find this one, just return. 586290001Sglebius */ 587290001Sglebius if (res != NULL) { 588290001Sglebius if ((RES_LIMITED & res->flags) 589290001Sglebius && (RES_LIMITED & flags)) 590290001Sglebius dec_res_limited(); 591290001Sglebius res->flags &= ~flags; 592290001Sglebius } 593290001Sglebius break; 59454359Sroberto 595290001Sglebius case RESTRICT_REMOVE: 596290001Sglebius case RESTRICT_REMOVEIF: 597290001Sglebius /* 598290001Sglebius * Remove an entry from the table entirely if we 599290001Sglebius * found one. Don't remove the default entry and 600290001Sglebius * don't remove an interface entry. 601290001Sglebius */ 602290001Sglebius if (res != NULL 603290001Sglebius && (RESTRICT_REMOVEIF == op 604290001Sglebius || !(RESM_INTERFACE & res->mflags)) 605290001Sglebius && res != &restrict_def4 606290001Sglebius && res != &restrict_def6) 607290001Sglebius free_res(res, v6); 608290001Sglebius break; 60954359Sroberto 610290001Sglebius default: /* unknown op */ 611290001Sglebius INSIST(0); 612290001Sglebius break; 613290001Sglebius } 61454359Sroberto 615290001Sglebius} 61654359Sroberto 617132451Sroberto 618290001Sglebius/* 619290001Sglebius * restrict_source - maintains dynamic "restrict source ..." entries as 620290001Sglebius * peers come and go. 621290001Sglebius */ 622290001Sglebiusvoid 623290001Sglebiusrestrict_source( 624290001Sglebius sockaddr_u * addr, 625290001Sglebius int farewell, /* 0 to add, 1 to remove */ 626290001Sglebius u_long expire /* 0 is infinite, valid until */ 627290001Sglebius ) 628290001Sglebius{ 629290001Sglebius sockaddr_u onesmask; 630290001Sglebius restrict_u * res; 631290001Sglebius int found_specific; 632132451Sroberto 633290001Sglebius if (!restrict_source_enabled || SOCK_UNSPEC(addr) || 634290001Sglebius IS_MCAST(addr) || ISREFCLOCKADR(addr)) 635290001Sglebius return; 636132451Sroberto 637290001Sglebius REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr)); 638132451Sroberto 639290001Sglebius SET_HOSTMASK(&onesmask, AF(addr)); 640290001Sglebius if (farewell) { 641290001Sglebius hack_restrict(RESTRICT_REMOVE, addr, &onesmask, 642290001Sglebius 0, 0, 0); 643290001Sglebius DPRINTF(1, ("restrict_source: %s removed", stoa(addr))); 644290001Sglebius return; 645290001Sglebius } 64654359Sroberto 647290001Sglebius /* 648290001Sglebius * If there is a specific entry for this address, hands 649290001Sglebius * off, as it is condidered more specific than "restrict 650290001Sglebius * server ...". 651290001Sglebius * However, if the specific entry found is a fleeting one 652290001Sglebius * added by pool_xmit() before soliciting, replace it 653290001Sglebius * immediately regardless of the expire value to make way 654290001Sglebius * for the more persistent entry. 655290001Sglebius */ 656290001Sglebius if (IS_IPV4(addr)) { 657290001Sglebius res = match_restrict4_addr(SRCADR(addr), SRCPORT(addr)); 658290001Sglebius INSIST(res != NULL); 659290001Sglebius found_specific = (SRCADR(&onesmask) == res->u.v4.mask); 660290001Sglebius } else { 661290001Sglebius res = match_restrict6_addr(&SOCK_ADDR6(addr), 662290001Sglebius SRCPORT(addr)); 663290001Sglebius INSIST(res != NULL); 664290001Sglebius found_specific = ADDR6_EQ(&res->u.v6.mask, 665290001Sglebius &SOCK_ADDR6(&onesmask)); 666290001Sglebius } 667290001Sglebius if (!expire && found_specific && res->expire) { 668290001Sglebius found_specific = 0; 669290001Sglebius free_res(res, IS_IPV6(addr)); 670290001Sglebius } 671290001Sglebius if (found_specific) 672290001Sglebius return; 673132451Sroberto 674290001Sglebius hack_restrict(RESTRICT_FLAGS, addr, &onesmask, 675290001Sglebius restrict_source_mflags, restrict_source_flags, 676290001Sglebius expire); 677290001Sglebius DPRINTF(1, ("restrict_source: %s host restriction added\n", 678290001Sglebius stoa(addr))); 67954359Sroberto} 680