1 /* 2 * ntp_restrict.c - determine host restrictions 3 */ 4 #ifdef HAVE_CONFIG_H 5 #include <config.h> 6 #endif 7 8 #include <stdio.h> 9 #include <sys/types.h> 10 11 #include "ntpd.h" 12 #include "ntp_if.h" 13 #include "ntp_stdlib.h" 14 15 /* 16 * This code keeps a simple address-and-mask list of hosts we want 17 * to place restrictions on (or remove them from). The restrictions 18 * are implemented as a set of flags which tell you what the host 19 * can't do. There is a subroutine entry to return the flags. The 20 * list is kept sorted to reduce the average number of comparisons 21 * and make sure you get the set of restrictions most specific to 22 * the address. 23 * 24 * The algorithm is that, when looking up a host, it is first assumed 25 * that the default set of restrictions will apply. It then searches 26 * down through the list. Whenever it finds a match it adopts the 27 * match's flags instead. When you hit the point where the sorted 28 * address is greater than the target, you return with the last set of 29 * flags you found. Because of the ordering of the list, the most 30 * specific match will provide the final set of flags. 31 * 32 * This was originally intended to restrict you from sync'ing to your 33 * own broadcasts when you are doing that, by restricting yourself from 34 * your own interfaces. It was also thought it would sometimes be useful 35 * to keep a misbehaving host or two from abusing your primary clock. It 36 * has been expanded, however, to suit the needs of those with more 37 * restrictive access policies. 38 */ 39 /* 40 * We will use two lists, one for IPv4 addresses and one for IPv6 41 * addresses. This is not protocol-independant but for now I can't 42 * find a way to respect this. We'll check this later... JFB 07/2001 43 */ 44 #define SET_IPV6_ADDR_MASK(dst, src, msk) \ 45 do { \ 46 int idx; \ 47 for (idx = 0; idx < 16; idx++) { \ 48 (dst)->s6_addr[idx] = \ 49 (u_char) ((src)->s6_addr[idx] & (msk)->s6_addr[idx]); \ 50 } \ 51 } while (0) 52 53 /* 54 * Memory allocation parameters. We allocate INITRESLIST entries 55 * initially, and add INCRESLIST entries to the free list whenever 56 * we run out. 57 */ 58 #define INITRESLIST 10 59 #define INCRESLIST 5 60 61 #define RES_AVG 8. /* interpacket averaging factor */ 62 63 /* 64 * The restriction list 65 */ 66 struct restrictlist *restrictlist; 67 struct restrictlist6 *restrictlist6; 68 static int restrictcount; /* count of entries in the res list */ 69 static int restrictcount6; /* count of entries in the res list 2*/ 70 71 /* 72 * The free list and associated counters. Also some uninteresting 73 * stat counters. 74 */ 75 static struct restrictlist *resfree; 76 static struct restrictlist6 *resfree6; 77 static int numresfree; /* number of structures on free list */ 78 static int numresfree6; /* number of structures on free list 2 */ 79 80 static u_long res_calls; 81 static u_long res_found; 82 static u_long res_not_found; 83 84 /* 85 * Parameters of the RES_LIMITED restriction option. 86 */ 87 u_long res_avg_interval = 5; /* min average interpacket interval */ 88 u_long res_min_interval = 1; /* min interpacket interval */ 89 90 /* 91 * Count number of restriction entries referring to RES_LIMITED controls 92 * activation/deactivation of monitoring (with respect to RES_LIMITED 93 * control) 94 */ 95 static u_long res_limited_refcnt; 96 static u_long res_limited_refcnt6; 97 98 /* 99 * Our initial allocation of lists entries. 100 */ 101 static struct restrictlist resinit[INITRESLIST]; 102 static struct restrictlist6 resinit6[INITRESLIST]; 103 104 /* 105 * init_restrict - initialize the restriction data structures 106 */ 107 void 108 init_restrict(void) 109 { 110 register int i; 111 112 /* 113 * Zero the list and put all but one on the free list 114 */ 115 resfree = 0; 116 memset((char *)resinit, 0, sizeof resinit); 117 resfree6 = 0; 118 memset((char *)resinit6, 0, sizeof resinit6); 119 for (i = 1; i < INITRESLIST; i++) { 120 resinit[i].next = resfree; 121 resinit6[i].next = resfree6; 122 resfree = &resinit[i]; 123 resfree6 = &resinit6[i]; 124 } 125 numresfree = INITRESLIST-1; 126 numresfree6 = INITRESLIST-1; 127 128 /* 129 * Put the remaining item at the head of the list as our default 130 * entry. Everything in here should be zero for now. 131 */ 132 resinit[0].addr = htonl(INADDR_ANY); 133 resinit[0].mask = 0; 134 memset(&resinit6[0].addr6, 0, sizeof(struct in6_addr)); 135 memset(&resinit6[0].mask6, 0, sizeof(struct in6_addr)); 136 restrictlist = &resinit[0]; 137 restrictlist6 = &resinit6[0]; 138 restrictcount = 1; 139 restrictcount = 2; 140 141 /* 142 * fix up stat counters 143 */ 144 res_calls = 0; 145 res_found = 0; 146 res_not_found = 0; 147 148 /* 149 * set default values for RES_LIMIT functionality 150 */ 151 res_limited_refcnt = 0; 152 res_limited_refcnt6 = 0; 153 } 154 155 156 /* 157 * restrictions - return restrictions for this host 158 */ 159 int 160 restrictions( 161 struct sockaddr_storage *srcadr 162 ) 163 { 164 struct restrictlist *rl; 165 struct restrictlist *match = NULL; 166 struct restrictlist6 *rl6; 167 struct restrictlist6 *match6 = NULL; 168 struct in6_addr hostaddr6; 169 struct in6_addr hostservaddr6; 170 u_int32 hostaddr; 171 int flags = 0; 172 int isntpport; 173 174 res_calls++; 175 if (srcadr->ss_family == AF_INET) { 176 /* 177 * We need the host address in host order. Also need to 178 * know whether this is from the ntp port or not. 179 */ 180 hostaddr = SRCADR(srcadr); 181 isntpport = (SRCPORT(srcadr) == NTP_PORT); 182 183 /* 184 * Ignore any packets with a multicast source address 185 * (this should be done early in the receive process, 186 * later!) 187 */ 188 if (IN_CLASSD(SRCADR(srcadr))) 189 return (int)RES_IGNORE; 190 191 /* 192 * Set match to first entry, which is default entry. 193 * Work our way down from there. 194 */ 195 match = restrictlist; 196 for (rl = match->next; rl != 0 && rl->addr <= hostaddr; 197 rl = rl->next) 198 if ((hostaddr & rl->mask) == rl->addr) { 199 if ((rl->mflags & RESM_NTPONLY) && 200 !isntpport) 201 continue; 202 match = rl; 203 } 204 match->count++; 205 if (match == restrictlist) 206 res_not_found++; 207 else 208 res_found++; 209 flags = match->flags; 210 } 211 212 /* IPv6 source address */ 213 if (srcadr->ss_family == AF_INET6) { 214 /* 215 * Need to know whether this is from the ntp port or 216 * not. 217 */ 218 hostaddr6 = GET_INADDR6(*srcadr); 219 isntpport = (ntohs(( 220 (struct sockaddr_in6 *)srcadr)->sin6_port) == 221 NTP_PORT); 222 223 /* 224 * Ignore any packets with a multicast source address 225 * (this should be done early in the receive process, 226 * later!) 227 */ 228 if (IN6_IS_ADDR_MULTICAST(&hostaddr6)) 229 return (int)RES_IGNORE; 230 231 /* 232 * Set match to first entry, which is default entry. 233 * Work our way down from there. 234 */ 235 match6 = restrictlist6; 236 for (rl6 = match6->next; rl6 != 0 && 237 (memcmp(&(rl6->addr6), &hostaddr6, 238 sizeof(hostaddr6)) <= 0); rl6 = rl6->next) { 239 SET_IPV6_ADDR_MASK(&hostservaddr6, &hostaddr6, 240 &rl6->mask6); 241 if (memcmp(&hostservaddr6, &(rl6->addr6), 242 sizeof(hostservaddr6)) == 0) { 243 if ((rl6->mflags & RESM_NTPONLY) && 244 !isntpport) 245 continue; 246 match6 = rl6; 247 } 248 } 249 match6->count++; 250 if (match6 == restrictlist6) 251 res_not_found++; 252 else 253 res_found++; 254 flags = match6->flags; 255 } 256 257 /* 258 * The following implements a generalized call gap facility. 259 * Douse the RES_LIMITED bit only if the interval since the last 260 * packet is greater than res_min_interval and the average is 261 * greater thatn res_avg_interval. 262 */ 263 if (mon_enabled == MON_OFF) { 264 flags &= ~RES_LIMITED; 265 } else { 266 struct mon_data *md; 267 268 /* 269 * At this poin the most recent arrival is first in the 270 * MRU list. Let the first 10 packets in for free until 271 * the average stabilizes. 272 */ 273 md = mon_mru_list.mru_next; 274 if (md->avg_interval == 0) 275 md->avg_interval = md->drop_count; 276 else 277 md->avg_interval += (md->drop_count - 278 md->avg_interval) / RES_AVG; 279 if (md->count < 10 || (md->drop_count > 280 res_min_interval && md->avg_interval > 281 res_avg_interval)) 282 flags &= ~RES_LIMITED; 283 md->drop_count = flags; 284 } 285 return (flags); 286 } 287 288 289 /* 290 * hack_restrict - add/subtract/manipulate entries on the restrict list 291 */ 292 void 293 hack_restrict( 294 int op, 295 struct sockaddr_storage *resaddr, 296 struct sockaddr_storage *resmask, 297 int mflags, 298 int flags 299 ) 300 { 301 register u_int32 addr = 0; 302 register u_int32 mask = 0; 303 struct in6_addr addr6; 304 struct in6_addr mask6; 305 register struct restrictlist *rl = NULL; 306 register struct restrictlist *rlprev = NULL; 307 register struct restrictlist6 *rl6 = NULL; 308 register struct restrictlist6 *rlprev6 = NULL; 309 int i, addr_cmp, mask_cmp; 310 memset(&addr6, 0, sizeof(struct in6_addr)); 311 memset(&mask6, 0, sizeof(struct in6_addr)); 312 313 if (resaddr->ss_family == AF_INET) { 314 /* 315 * Get address and mask in host byte order 316 */ 317 addr = SRCADR(resaddr); 318 mask = SRCADR(resmask); 319 addr &= mask; /* make sure low bits zero */ 320 321 /* 322 * If this is the default address, point at first on 323 * list. Else go searching for it. 324 */ 325 if (addr == 0) { 326 rlprev = 0; 327 rl = restrictlist; 328 } else { 329 rlprev = restrictlist; 330 rl = rlprev->next; 331 while (rl != 0) { 332 if (rl->addr > addr) { 333 rl = 0; 334 break; 335 } else if (rl->addr == addr) { 336 if (rl->mask == mask) { 337 if ((mflags & 338 RESM_NTPONLY) == 339 (rl->mflags & 340 RESM_NTPONLY)) 341 break; 342 343 if (!(mflags & 344 RESM_NTPONLY)) { 345 rl = 0; 346 break; 347 } 348 } else if (rl->mask > mask) { 349 rl = 0; 350 break; 351 } 352 } 353 rlprev = rl; 354 rl = rl->next; 355 } 356 } 357 } 358 359 if (resaddr->ss_family == AF_INET6) { 360 mask6 = GET_INADDR6(*resmask); 361 SET_IPV6_ADDR_MASK(&addr6, 362 &GET_INADDR6(*resaddr), &mask6); 363 if (IN6_IS_ADDR_UNSPECIFIED(&addr6)) { 364 rlprev6 = 0; 365 rl6 = restrictlist6; 366 } else { 367 rlprev6 = restrictlist6; 368 rl6 = rlprev6->next; 369 while (rl6 != 0) { 370 addr_cmp = memcmp(&rl6->addr6, &addr6, 371 sizeof(addr6)); 372 if (addr_cmp > 0) { 373 rl6 = 0; 374 break; 375 } else if (addr_cmp == 0) { 376 mask_cmp = memcmp(&rl6->mask6, 377 &mask6, sizeof(mask6)); 378 if (mask_cmp == 0) { 379 if ((mflags & 380 RESM_NTPONLY) == 381 (rl6->mflags & 382 RESM_NTPONLY)) 383 break; 384 385 if (!(mflags & 386 RESM_NTPONLY)) { 387 rl6 = 0; 388 break; 389 } 390 } else if (mask_cmp > 0) { 391 rl6 = 0; 392 break; 393 } 394 } 395 rlprev6 = rl6; 396 rl6 = rl6->next; 397 } 398 } 399 } 400 401 /* 402 * In case the above wasn't clear :-), either rl now points 403 * at the entry this call refers to, or rl is zero and rlprev 404 * points to the entry prior to where this one should go in 405 * the sort. 406 */ 407 408 /* 409 * Switch based on operation 410 */ 411 if (resaddr->ss_family == AF_INET) { 412 switch (op) { 413 case RESTRICT_FLAGS: 414 /* 415 * Here we add bits to the flags. If this is a 416 * new restriction add it. 417 */ 418 if (rl == 0) { 419 if (numresfree == 0) { 420 rl = (struct restrictlist *) 421 emalloc(INCRESLIST * 422 sizeof(struct 423 restrictlist)); 424 memset((char *)rl, 0, 425 INCRESLIST * sizeof(struct 426 restrictlist)); 427 for (i = 0; i < INCRESLIST; i++) { 428 rl->next = resfree; 429 resfree = rl; 430 rl++; 431 } 432 numresfree = INCRESLIST; 433 } 434 435 rl = resfree; 436 resfree = rl->next; 437 numresfree--; 438 439 rl->addr = addr; 440 rl->mask = mask; 441 rl->mflags = (u_short)mflags; 442 443 rl->next = rlprev->next; 444 rlprev->next = rl; 445 restrictcount++; 446 } 447 if ((rl->flags ^ (u_short)flags) & 448 RES_LIMITED) { 449 res_limited_refcnt++; 450 mon_start(MON_RES); 451 } 452 rl->flags |= (u_short)flags; 453 break; 454 455 case RESTRICT_UNFLAG: 456 /* 457 * Remove some bits from the flags. If we didn't 458 * find this one, just return. 459 */ 460 if (rl != 0) { 461 if ((rl->flags ^ (u_short)flags) & 462 RES_LIMITED) { 463 res_limited_refcnt--; 464 if (res_limited_refcnt == 0) 465 mon_stop(MON_RES); 466 } 467 rl->flags &= (u_short)~flags; 468 } 469 break; 470 471 case RESTRICT_REMOVE: 472 /* 473 * Remove an entry from the table entirely if we 474 * found one. Don't remove the default entry and 475 * don't remove an interface entry. 476 */ 477 if (rl != 0 478 && rl->addr != htonl(INADDR_ANY) 479 && !(rl->mflags & RESM_INTERFACE)) { 480 rlprev->next = rl->next; 481 restrictcount--; 482 if (rl->flags & RES_LIMITED) { 483 res_limited_refcnt--; 484 if (res_limited_refcnt == 0) 485 mon_stop(MON_RES); 486 } 487 memset((char *)rl, 0, 488 sizeof(struct restrictlist)); 489 490 rl->next = resfree; 491 resfree = rl; 492 numresfree++; 493 } 494 break; 495 496 default: 497 break; 498 } 499 } else if (resaddr->ss_family == AF_INET6) { 500 switch (op) { 501 case RESTRICT_FLAGS: 502 /* 503 * Here we add bits to the flags. If this is a 504 * new restriction add it. 505 */ 506 if (rl6 == 0) { 507 if (numresfree6 == 0) { 508 rl6 = (struct 509 restrictlist6 *)emalloc( 510 INCRESLIST * sizeof(struct 511 restrictlist6)); 512 memset((char *)rl6, 0, 513 INCRESLIST * sizeof(struct 514 restrictlist6)); 515 516 for (i = 0; i < INCRESLIST; 517 i++) { 518 rl6->next = resfree6; 519 resfree6 = rl6; 520 rl6++; 521 } 522 numresfree6 = INCRESLIST; 523 } 524 rl6 = resfree6; 525 resfree6 = rl6->next; 526 numresfree6--; 527 rl6->addr6 = addr6; 528 rl6->mask6 = mask6; 529 rl6->mflags = (u_short)mflags; 530 rl6->next = rlprev6->next; 531 rlprev6->next = rl6; 532 restrictcount6++; 533 } 534 if ((rl6->flags ^ (u_short)flags) & 535 RES_LIMITED) { 536 res_limited_refcnt6++; 537 mon_start(MON_RES); 538 } 539 rl6->flags |= (u_short)flags; 540 break; 541 542 case RESTRICT_UNFLAG: 543 /* 544 * Remove some bits from the flags. If we didn't 545 * find this one, just return. 546 */ 547 if (rl6 != 0) { 548 if ((rl6->flags ^ (u_short)flags) & 549 RES_LIMITED) { 550 res_limited_refcnt6--; 551 if (res_limited_refcnt6 == 0) 552 mon_stop(MON_RES); 553 } 554 rl6->flags &= (u_short)~flags; 555 } 556 break; 557 558 case RESTRICT_REMOVE: 559 /* 560 * Remove an entry from the table entirely if we 561 * found one. Don't remove the default entry and 562 * don't remove an interface entry. 563 */ 564 if (rl6 != 0 && 565 !IN6_IS_ADDR_UNSPECIFIED(&rl6->addr6) 566 && !(rl6->mflags & RESM_INTERFACE)) { 567 rlprev6->next = rl6->next; 568 restrictcount6--; 569 if (rl6->flags & RES_LIMITED) { 570 res_limited_refcnt6--; 571 if (res_limited_refcnt6 == 0) 572 mon_stop(MON_RES); 573 } 574 memset((char *)rl6, 0, 575 sizeof(struct restrictlist6)); 576 rl6->next = resfree6; 577 resfree6 = rl6; 578 numresfree6++; 579 } 580 break; 581 582 default: 583 break; 584 } 585 } 586 } 587