1*9e9fa66aSchristos /* $NetBSD: ntp_restrict.c,v 1.13 2024/10/01 20:59:51 christos Exp $ */ 2abb0f93cSkardel 3abb0f93cSkardel /* 4abb0f93cSkardel * ntp_restrict.c - determine host restrictions 5abb0f93cSkardel */ 6abb0f93cSkardel #ifdef HAVE_CONFIG_H 7abb0f93cSkardel #include <config.h> 8abb0f93cSkardel #endif 9abb0f93cSkardel 10abb0f93cSkardel #include <stdio.h> 11abb0f93cSkardel #include <sys/types.h> 12abb0f93cSkardel 13abb0f93cSkardel #include "ntpd.h" 14abb0f93cSkardel #include "ntp_if.h" 15f003fb54Skardel #include "ntp_lists.h" 16abb0f93cSkardel #include "ntp_stdlib.h" 17f003fb54Skardel #include "ntp_assert.h" 18abb0f93cSkardel 19abb0f93cSkardel /* 20eabc0478Schristos * This code keeps a simple address-and-mask list of addressses we want 21eabc0478Schristos * to place restrictions on (or remove them from). The restrictions are 22eabc0478Schristos * implemented as a set of flags which tell you what matching addresses 23eabc0478Schristos * can't do. The list is sorted retrieve the restrictions most specific 24eabc0478Schristos * to the address. 25abb0f93cSkardel * 26abb0f93cSkardel * This was originally intended to restrict you from sync'ing to your 27abb0f93cSkardel * own broadcasts when you are doing that, by restricting yourself from 28abb0f93cSkardel * your own interfaces. It was also thought it would sometimes be useful 29abb0f93cSkardel * to keep a misbehaving host or two from abusing your primary clock. It 30abb0f93cSkardel * has been expanded, however, to suit the needs of those with more 31abb0f93cSkardel * restrictive access policies. 32abb0f93cSkardel */ 33f003fb54Skardel #define MASK_IPV6_ADDR(dst, src, msk) \ 34abb0f93cSkardel do { \ 35eabc0478Schristos int x; \ 36eabc0478Schristos \ 37eabc0478Schristos for (x = 0; x < (int)COUNTOF((dst)->s6_addr); x++) { \ 38eabc0478Schristos (dst)->s6_addr[x] = (src)->s6_addr[x] \ 39eabc0478Schristos & (msk)->s6_addr[x]; \ 40abb0f93cSkardel } \ 41eabc0478Schristos } while (FALSE) 42abb0f93cSkardel 43abb0f93cSkardel /* 44f003fb54Skardel * We allocate INC_RESLIST{4|6} entries to the free list whenever empty. 45eabc0478Schristos * Auto-tune these to be just less than 1KB (leaving at least 32 bytes 46f003fb54Skardel * for allocator overhead). 47abb0f93cSkardel */ 48*9e9fa66aSchristos #define INC_RESLIST4 ((1024 - 32) / sizeof(struct restrict_4)) 49*9e9fa66aSchristos #define INC_RESLIST6 ((1024 - 32) / sizeof(struct restrict_6)) 50abb0f93cSkardel 51abb0f93cSkardel /* 52abb0f93cSkardel * The restriction list 53abb0f93cSkardel */ 54*9e9fa66aSchristos struct restrict_4 *restrictlist4; 55*9e9fa66aSchristos struct restrict_6 *restrictlist6; 56*9e9fa66aSchristos static size_t restrictcount; /* count in the restrict lists */ 57abb0f93cSkardel 58abb0f93cSkardel /* 59abb0f93cSkardel * The free list and associated counters. Also some uninteresting 60abb0f93cSkardel * stat counters. 61abb0f93cSkardel */ 62*9e9fa66aSchristos static struct restrict_4 *resfree4; /* available entries (free list) */ 63*9e9fa66aSchristos static struct restrict_6 *resfree6; 64abb0f93cSkardel 65abb0f93cSkardel static u_long res_calls; 66abb0f93cSkardel static u_long res_found; 67abb0f93cSkardel static u_long res_not_found; 68abb0f93cSkardel 69abb0f93cSkardel /* 70f003fb54Skardel * Count number of restriction entries referring to RES_LIMITED, to 71f003fb54Skardel * control implicit activation/deactivation of the MRU monlist. 72abb0f93cSkardel */ 73abb0f93cSkardel static u_long res_limited_refcnt; 74abb0f93cSkardel 75abb0f93cSkardel /* 76f003fb54Skardel * Our default entries. 774eea345dSchristos * 784eea345dSchristos * We can make this cleaner with c99 support: see init_restrict(). 79abb0f93cSkardel */ 80*9e9fa66aSchristos static struct restrict_4 restrict_def4; 81*9e9fa66aSchristos static struct restrict_6 restrict_def6; 82f003fb54Skardel 83f003fb54Skardel /* 84f003fb54Skardel * "restrict source ..." enabled knob and restriction bits. 85f003fb54Skardel */ 86f003fb54Skardel static int restrict_source_enabled; 87cdfa2a7eSchristos static u_int32 restrict_source_rflags; 88f003fb54Skardel static u_short restrict_source_mflags; 894eea345dSchristos static short restrict_source_ippeerlimit; 90f003fb54Skardel 91f003fb54Skardel /* 92f003fb54Skardel * private functions 93f003fb54Skardel */ 94*9e9fa66aSchristos static struct restrict_4 * alloc_res4(void); 95*9e9fa66aSchristos static struct restrict_6 * alloc_res6(void); 96*9e9fa66aSchristos static void free_res4(struct restrict_4 *); 97*9e9fa66aSchristos static void free_res6(struct restrict_6 *); 98eabc0478Schristos static inline void inc_res_limited(void); 99eabc0478Schristos static inline void dec_res_limited(void); 100*9e9fa66aSchristos static struct restrict_4 * match_restrict4_addr(u_int32, u_short); 101*9e9fa66aSchristos static struct restrict_6 * match_restrict6_addr(const struct in6_addr *, 102f003fb54Skardel u_short); 103eabc0478Schristos static inline int/*BOOL*/ mflags_sorts_before(u_short, u_short); 104*9e9fa66aSchristos static int/*BOOL*/ res_sorts_before4(struct restrict_4 *, 105*9e9fa66aSchristos struct restrict_4 *); 106*9e9fa66aSchristos static int/*BOOL*/ res_sorts_before6(struct restrict_6 *, 107*9e9fa66aSchristos struct restrict_6 *); 108eabc0478Schristos 109eabc0478Schristos #ifdef DEBUG 110*9e9fa66aSchristos /* dump_restrict() & dump_restricts() are DEBUG-only */ 111eabc0478Schristos 112*9e9fa66aSchristos static void 113*9e9fa66aSchristos dump_restrict(const struct restrict_info *ri, const char *as, const char *ms) 114*9e9fa66aSchristos { 115*9e9fa66aSchristos printf("%s/%s: hits %u ippeerlimit %hd mflags %s rflags %s", 116*9e9fa66aSchristos as, ms, ri->count, ri->ippeerlimit, 117*9e9fa66aSchristos mflags_str(ri->mflags), 118*9e9fa66aSchristos rflags_str(ri->rflags)); 119*9e9fa66aSchristos if (ri->expire > 0) { 120*9e9fa66aSchristos printf(" expire %u\n", ri->expire); 121*9e9fa66aSchristos } else { 122*9e9fa66aSchristos printf("\n"); 123*9e9fa66aSchristos } 124*9e9fa66aSchristos } 1254eea345dSchristos 1264eea345dSchristos /* 127eabc0478Schristos * dump_restrict - spit out a single restriction entry 1284eea345dSchristos */ 1294eea345dSchristos static void 130*9e9fa66aSchristos dump_restrict4( 131*9e9fa66aSchristos struct restrict_4 * res) 1324eea345dSchristos { 1334eea345dSchristos char as[INET6_ADDRSTRLEN]; 1344eea345dSchristos char ms[INET6_ADDRSTRLEN]; 1354eea345dSchristos 136eabc0478Schristos struct in_addr sia, sim; 1374eea345dSchristos 138*9e9fa66aSchristos sia.s_addr = htonl(res->v4.addr); 139*9e9fa66aSchristos sim.s_addr = htonl(res->v4.addr); 1404eea345dSchristos inet_ntop(AF_INET, &sia, as, sizeof as); 1414eea345dSchristos inet_ntop(AF_INET, &sim, ms, sizeof ms); 142*9e9fa66aSchristos 143*9e9fa66aSchristos dump_restrict(&res->ri, as, ms); 1444eea345dSchristos } 145*9e9fa66aSchristos 146*9e9fa66aSchristos static void 147*9e9fa66aSchristos dump_restrict6( 148*9e9fa66aSchristos struct restrict_6 * res) 149*9e9fa66aSchristos { 150*9e9fa66aSchristos char as[INET6_ADDRSTRLEN]; 151*9e9fa66aSchristos char ms[INET6_ADDRSTRLEN]; 152*9e9fa66aSchristos 153*9e9fa66aSchristos inet_ntop(AF_INET6, &res->v6.addr, as, sizeof as); 154*9e9fa66aSchristos inet_ntop(AF_INET6, &res->v6.mask, ms, sizeof ms); 155*9e9fa66aSchristos 156*9e9fa66aSchristos dump_restrict(&res->ri, as, ms); 1574eea345dSchristos } 1584eea345dSchristos 1594eea345dSchristos 1604eea345dSchristos /* 161eabc0478Schristos * dump_restricts - spit out the 'restrict' entries 1624eea345dSchristos */ 1634eea345dSchristos void 1644eea345dSchristos dump_restricts(void) 1654eea345dSchristos { 166*9e9fa66aSchristos struct restrict_4 * res4; 167*9e9fa66aSchristos struct restrict_6 * res6; 1684eea345dSchristos 1694eea345dSchristos /* Spit out the IPv4 list */ 170eabc0478Schristos printf("dump_restricts: restrictlist4: %p\n", restrictlist4); 171*9e9fa66aSchristos for (res4 = restrictlist4; res4 != NULL; res4 = res4->link) { 172*9e9fa66aSchristos dump_restrict4(res4); 1734eea345dSchristos } 1744eea345dSchristos 1754eea345dSchristos /* Spit out the IPv6 list */ 176eabc0478Schristos printf("dump_restricts: restrictlist6: %p\n", restrictlist6); 177*9e9fa66aSchristos for (res6 = restrictlist6; res6 != NULL; res6 = res6->link) { 178*9e9fa66aSchristos dump_restrict6(res6); 1794eea345dSchristos } 180eabc0478Schristos } 181eabc0478Schristos #endif /* DEBUG - dump_restrict() / dump_restricts() */ 1824eea345dSchristos 1834eea345dSchristos 184abb0f93cSkardel /* 185abb0f93cSkardel * init_restrict - initialize the restriction data structures 186abb0f93cSkardel */ 187abb0f93cSkardel void 188abb0f93cSkardel init_restrict(void) 189abb0f93cSkardel { 190abb0f93cSkardel /* 191eabc0478Schristos * The restriction lists end with a default entry with address 192f003fb54Skardel * and mask 0, which will match any entry. The lists are kept 193f003fb54Skardel * sorted by descending address followed by descending mask: 194f003fb54Skardel * 195f003fb54Skardel * address mask 196f003fb54Skardel * 192.168.0.0 255.255.255.0 kod limited noquery nopeer 197f003fb54Skardel * 192.168.0.0 255.255.0.0 kod limited 198f003fb54Skardel * 0.0.0.0 0.0.0.0 kod limited noquery 199f003fb54Skardel * 200f003fb54Skardel * The first entry which matches an address is used. With the 201f003fb54Skardel * example restrictions above, 192.168.0.0/24 matches the first 202f003fb54Skardel * entry, the rest of 192.168.0.0/16 matches the second, and 203f003fb54Skardel * everything else matches the third (default). 204f003fb54Skardel * 205f003fb54Skardel * Note this achieves the same result a little more efficiently 206f003fb54Skardel * than the documented behavior, which is to keep the lists 207f003fb54Skardel * sorted by ascending address followed by ascending mask, with 208f003fb54Skardel * the _last_ matching entry used. 209f003fb54Skardel * 210f003fb54Skardel * An additional wrinkle is we may have multiple entries with 211f003fb54Skardel * the same address and mask but differing match flags (mflags). 212eabc0478Schristos * We want to never talk to ourself, so RES_IGNORE entries for 213eabc0478Schristos * each local address are added by ntp_io.c with a host mask and 214eabc0478Schristos * both RESM_INTERFACE and RESM_NTPONLY set. We sort those 215eabc0478Schristos * entries before entries without those flags to achieve this. 216eabc0478Schristos * The remaining match flag is RESM_SOURCE, used to dynamically 217eabc0478Schristos * set restrictions for each peer based on the prototype set by 218eabc0478Schristos * "restrict source" in the configuration. We want those entries 219eabc0478Schristos * to be considered only when there is not a static host 220eabc0478Schristos * restriction for the address in the configuration, to allow 221eabc0478Schristos * operators to blacklist pool and manycast servers at runtime as 222eabc0478Schristos * desired using ntpq runtime configuration. Such static entries 223eabc0478Schristos * have no RESM_ bits set, so the sort order for mflags is first 224eabc0478Schristos * RESM_INTERFACE, then entries without RESM_SOURCE, finally the 225eabc0478Schristos * remaining. 226abb0f93cSkardel */ 2274eea345dSchristos 228*9e9fa66aSchristos restrict_def4.ri.ippeerlimit = -1; /* Cleaner if we have C99 */ 229*9e9fa66aSchristos restrict_def6.ri.ippeerlimit = -1; /* Cleaner if we have C99 */ 2304eea345dSchristos 231f003fb54Skardel LINK_SLIST(restrictlist4, &restrict_def4, link); 232f003fb54Skardel LINK_SLIST(restrictlist6, &restrict_def6, link); 233abb0f93cSkardel restrictcount = 2; 234f003fb54Skardel } 235f003fb54Skardel 236f003fb54Skardel 237*9e9fa66aSchristos static struct restrict_4 * 238f003fb54Skardel alloc_res4(void) 239f003fb54Skardel { 240f003fb54Skardel const size_t count = INC_RESLIST4; 241*9e9fa66aSchristos struct restrict_4* rl; 242*9e9fa66aSchristos struct restrict_4* res; 243*9e9fa66aSchristos const size_t cb = sizeof(*rl); 2448b8da087Schristos size_t i; 245f003fb54Skardel 246f003fb54Skardel UNLINK_HEAD_SLIST(res, resfree4, link); 247eabc0478Schristos if (res != NULL) { 248f003fb54Skardel return res; 249eabc0478Schristos } 250ccc794f0Schristos rl = eallocarray(count, cb); 251f003fb54Skardel /* link all but the first onto free list */ 252f003fb54Skardel res = (void *)((char *)rl + (count - 1) * cb); 253f003fb54Skardel for (i = count - 1; i > 0; i--) { 254f003fb54Skardel LINK_SLIST(resfree4, res, link); 255f003fb54Skardel res = (void *)((char *)res - cb); 256f003fb54Skardel } 257eabc0478Schristos DEBUG_INSIST(rl == res); 258f003fb54Skardel /* allocate the first */ 259f003fb54Skardel return res; 260f003fb54Skardel } 261f003fb54Skardel 262f003fb54Skardel 263*9e9fa66aSchristos static struct restrict_6 * 264f003fb54Skardel alloc_res6(void) 265f003fb54Skardel { 266f003fb54Skardel const size_t count = INC_RESLIST6; 267*9e9fa66aSchristos struct restrict_6 * rl; 268*9e9fa66aSchristos struct restrict_6 * res; 269*9e9fa66aSchristos const size_t cb = sizeof(*rl); 2708b8da087Schristos size_t i; 271f003fb54Skardel 272f003fb54Skardel UNLINK_HEAD_SLIST(res, resfree6, link); 273eabc0478Schristos if (res != NULL) { 274f003fb54Skardel return res; 275eabc0478Schristos } 276ccc794f0Schristos rl = eallocarray(count, cb); 277f003fb54Skardel /* link all but the first onto free list */ 278f003fb54Skardel res = (void *)((char *)rl + (count - 1) * cb); 279f003fb54Skardel for (i = count - 1; i > 0; i--) { 280f003fb54Skardel LINK_SLIST(resfree6, res, link); 281f003fb54Skardel res = (void *)((char *)res - cb); 282f003fb54Skardel } 283eabc0478Schristos DEBUG_INSIST(rl == res); 284f003fb54Skardel /* allocate the first */ 285f003fb54Skardel return res; 286f003fb54Skardel } 287f003fb54Skardel 288f003fb54Skardel 289f003fb54Skardel static void 290*9e9fa66aSchristos free_res6(struct restrict_6 * res) 291f003fb54Skardel { 292*9e9fa66aSchristos struct restrict_6 * unlinked; 293f003fb54Skardel 294f003fb54Skardel restrictcount--; 295*9e9fa66aSchristos if (RES_LIMITED & res->ri.rflags) { 296f003fb54Skardel dec_res_limited(); 297eabc0478Schristos } 298*9e9fa66aSchristos UNLINK_SLIST(unlinked, restrictlist6, res, link, struct restrict_6); 299eabc0478Schristos INSIST(unlinked == res); 300*9e9fa66aSchristos zero_mem(res, sizeof(*res)); 301*9e9fa66aSchristos LINK_SLIST(resfree6, res, link); 302f003fb54Skardel } 303f003fb54Skardel 304*9e9fa66aSchristos static void 305*9e9fa66aSchristos free_res4(struct restrict_4 * res) 306*9e9fa66aSchristos { 307*9e9fa66aSchristos struct restrict_4 * unlinked; 308*9e9fa66aSchristos 309*9e9fa66aSchristos restrictcount--; 310*9e9fa66aSchristos if (RES_LIMITED & res->ri.rflags) { 311*9e9fa66aSchristos dec_res_limited(); 312*9e9fa66aSchristos } 313*9e9fa66aSchristos UNLINK_SLIST(unlinked, restrictlist4, res, link, struct restrict_4); 314*9e9fa66aSchristos INSIST(unlinked == res); 315*9e9fa66aSchristos zero_mem(res, sizeof(*res)); 316*9e9fa66aSchristos LINK_SLIST(resfree4, res, link); 317*9e9fa66aSchristos } 318f003fb54Skardel 319eabc0478Schristos static inline void 320f003fb54Skardel inc_res_limited(void) 321f003fb54Skardel { 322eabc0478Schristos if (0 == res_limited_refcnt) { 323f003fb54Skardel mon_start(MON_RES); 324eabc0478Schristos } 325f003fb54Skardel res_limited_refcnt++; 326f003fb54Skardel } 327f003fb54Skardel 328f003fb54Skardel 329eabc0478Schristos static inline void 330f003fb54Skardel dec_res_limited(void) 331f003fb54Skardel { 332f003fb54Skardel res_limited_refcnt--; 333eabc0478Schristos if (0 == res_limited_refcnt) { 334f003fb54Skardel mon_stop(MON_RES); 335f003fb54Skardel } 336eabc0478Schristos } 337f003fb54Skardel 338f003fb54Skardel 339*9e9fa66aSchristos static struct restrict_4 * 340f003fb54Skardel match_restrict4_addr( 341f003fb54Skardel u_int32 addr, 342f003fb54Skardel u_short port 343f003fb54Skardel ) 344f003fb54Skardel { 345*9e9fa66aSchristos struct restrict_4 * res; 346*9e9fa66aSchristos struct restrict_4 * next; 347f003fb54Skardel 348f003fb54Skardel for (res = restrictlist4; res != NULL; res = next) { 349f003fb54Skardel next = res->link; 350*9e9fa66aSchristos if (res->ri.expire && res->ri.expire <= current_time) { 351*9e9fa66aSchristos free_res4(res); /* zeroes the contents */ 352eabc0478Schristos } 353*9e9fa66aSchristos if ( res->v4.addr == (addr & res->v4.mask) 354*9e9fa66aSchristos && ( !(RESM_NTPONLY & res->ri.mflags) 3554eea345dSchristos || NTP_PORT == port)) { 356eabc0478Schristos 357f003fb54Skardel break; 358f003fb54Skardel } 3594eea345dSchristos } 360f003fb54Skardel return res; 361f003fb54Skardel } 362f003fb54Skardel 363f003fb54Skardel 364*9e9fa66aSchristos static struct restrict_6 * 365f003fb54Skardel match_restrict6_addr( 366f003fb54Skardel const struct in6_addr * addr, 367f003fb54Skardel u_short port 368f003fb54Skardel ) 369f003fb54Skardel { 370*9e9fa66aSchristos struct restrict_6 * res; 371*9e9fa66aSchristos struct restrict_6 * next; 372f003fb54Skardel struct in6_addr masked; 373f003fb54Skardel 374f003fb54Skardel for (res = restrictlist6; res != NULL; res = next) { 375f003fb54Skardel next = res->link; 376*9e9fa66aSchristos if (res->ri.expire && res->ri.expire <= current_time) { 377*9e9fa66aSchristos free_res6(res); 378eabc0478Schristos } 379*9e9fa66aSchristos MASK_IPV6_ADDR(&masked, addr, &res->v6.mask); 380*9e9fa66aSchristos if (ADDR6_EQ(&masked, &res->v6.addr) 381*9e9fa66aSchristos && ( !(RESM_NTPONLY & res->ri.mflags) 382eabc0478Schristos || NTP_PORT == (int)port)) { 383eabc0478Schristos 384f003fb54Skardel break; 385f003fb54Skardel } 386eabc0478Schristos } 387f003fb54Skardel return res; 388f003fb54Skardel } 389f003fb54Skardel 390abb0f93cSkardel 391abb0f93cSkardel /* 392f003fb54Skardel * match_restrict_entry - find an exact match on a restrict list. 393f003fb54Skardel * 394f003fb54Skardel * Exact match is addr, mask, and mflags all equal. 395f003fb54Skardel * In order to use more common code for IPv4 and IPv6, this routine 396*9e9fa66aSchristos * requires the caller to populate a restrict_[46] with mflags and either 397f003fb54Skardel * the v4 or v6 address and mask as appropriate. Other fields in the 398f003fb54Skardel * input restrict_u are ignored. 399abb0f93cSkardel */ 400*9e9fa66aSchristos static struct restrict_4 * 401*9e9fa66aSchristos match_restrict4_entry( 402*9e9fa66aSchristos const struct restrict_4 * pmatch) 403f003fb54Skardel { 404*9e9fa66aSchristos struct restrict_4 *res; 405f003fb54Skardel 406*9e9fa66aSchristos for (res = restrictlist4; res != NULL; res = res->link) { 407*9e9fa66aSchristos if (res->ri.mflags == pmatch->ri.mflags && 408*9e9fa66aSchristos !memcmp(&res->v4, &pmatch->v4, sizeof(res->v4))) { 409f003fb54Skardel break; 410eabc0478Schristos } 411eabc0478Schristos } 412f003fb54Skardel return res; 413f003fb54Skardel } 414f003fb54Skardel 415*9e9fa66aSchristos static struct restrict_6 * 416*9e9fa66aSchristos match_restrict6_entry( 417*9e9fa66aSchristos const struct restrict_6 * pmatch) 418*9e9fa66aSchristos { 419*9e9fa66aSchristos struct restrict_6 *res; 420*9e9fa66aSchristos 421*9e9fa66aSchristos for (res = restrictlist6; res != NULL; res = res->link) { 422*9e9fa66aSchristos if (res->ri.mflags == pmatch->ri.mflags && 423*9e9fa66aSchristos !memcmp(&res->v6, &pmatch->v6, sizeof(res->v6))) { 424*9e9fa66aSchristos break; 425*9e9fa66aSchristos } 426*9e9fa66aSchristos } 427*9e9fa66aSchristos return res; 428*9e9fa66aSchristos } 429abb0f93cSkardel 430abb0f93cSkardel /* 431eabc0478Schristos * mflags_sorts_before - common mflags sorting code 432eabc0478Schristos * 433eabc0478Schristos * See block comment in init_restrict() above for rationale. 434eabc0478Schristos */ 435eabc0478Schristos static inline int/*BOOL*/ 436eabc0478Schristos mflags_sorts_before( 437eabc0478Schristos u_short m1, 438eabc0478Schristos u_short m2 439eabc0478Schristos ) 440eabc0478Schristos { 441eabc0478Schristos if ( (RESM_INTERFACE & m1) 442eabc0478Schristos && !(RESM_INTERFACE & m2)) { 443eabc0478Schristos return TRUE; 444eabc0478Schristos } else if ( !(RESM_SOURCE & m1) 445eabc0478Schristos && (RESM_SOURCE & m2)) { 446eabc0478Schristos return TRUE; 447eabc0478Schristos } else { 448eabc0478Schristos return FALSE; 449eabc0478Schristos } 450eabc0478Schristos } 451eabc0478Schristos 452eabc0478Schristos 453eabc0478Schristos /* 454eabc0478Schristos * res_sorts_before4 - compare IPv4 restriction entries 455f003fb54Skardel * 456f003fb54Skardel * Returns nonzero if r1 sorts before r2. We sort by descending 457eabc0478Schristos * address, then descending mask, then an intricate mflags sort 458eabc0478Schristos * order explained in a block comment near the top of this file. 459abb0f93cSkardel */ 460eabc0478Schristos static int/*BOOL*/ 461f003fb54Skardel res_sorts_before4( 462*9e9fa66aSchristos struct restrict_4 *r1, 463*9e9fa66aSchristos struct restrict_4 *r2 464f003fb54Skardel ) 465f003fb54Skardel { 466f003fb54Skardel int r1_before_r2; 467f003fb54Skardel 468*9e9fa66aSchristos if (r1->v4.addr > r2->v4.addr) { 469eabc0478Schristos r1_before_r2 = TRUE; 470*9e9fa66aSchristos } else if (r1->v4.addr < r2->v4.addr) { 471eabc0478Schristos r1_before_r2 = FALSE; 472*9e9fa66aSchristos } else if (r1->v4.mask > r2->v4.mask) { 473eabc0478Schristos r1_before_r2 = TRUE; 474*9e9fa66aSchristos } else if (r1->v4.mask < r2->v4.mask) { 475eabc0478Schristos r1_before_r2 = FALSE; 476eabc0478Schristos } else { 477*9e9fa66aSchristos r1_before_r2 = mflags_sorts_before(r1->ri.mflags, r2->ri.mflags); 478eabc0478Schristos } 479f003fb54Skardel 480f003fb54Skardel return r1_before_r2; 481f003fb54Skardel } 482f003fb54Skardel 483f003fb54Skardel 484f003fb54Skardel /* 485eabc0478Schristos * res_sorts_before6 - compare IPv6 restriction entries 486f003fb54Skardel * 487f003fb54Skardel * Returns nonzero if r1 sorts before r2. We sort by descending 488eabc0478Schristos * address, then descending mask, then an intricate mflags sort 489eabc0478Schristos * order explained in a block comment near the top of this file. 490f003fb54Skardel */ 491eabc0478Schristos static int/*BOOL*/ 492f003fb54Skardel res_sorts_before6( 493*9e9fa66aSchristos struct restrict_6* r1, 494*9e9fa66aSchristos struct restrict_6* r2 495f003fb54Skardel ) 496f003fb54Skardel { 497f003fb54Skardel int r1_before_r2; 498f003fb54Skardel int cmp; 499f003fb54Skardel 500*9e9fa66aSchristos cmp = ADDR6_CMP(&r1->v6.addr, &r2->v6.addr); 501eabc0478Schristos if (cmp > 0) { /* r1->addr > r2->addr */ 502eabc0478Schristos r1_before_r2 = TRUE; 503eabc0478Schristos } else if (cmp < 0) { /* r2->addr > r1->addr */ 504eabc0478Schristos r1_before_r2 = FALSE; 505eabc0478Schristos } else { 506*9e9fa66aSchristos cmp = ADDR6_CMP(&r1->v6.mask, &r2->v6.mask); 507eabc0478Schristos if (cmp > 0) { /* r1->mask > r2->mask*/ 508eabc0478Schristos r1_before_r2 = TRUE; 509eabc0478Schristos } else if (cmp < 0) { /* r2->mask > r1->mask */ 510eabc0478Schristos r1_before_r2 = FALSE; 511eabc0478Schristos } else { 512*9e9fa66aSchristos r1_before_r2 = mflags_sorts_before(r1->ri.mflags, 513*9e9fa66aSchristos r2->ri.mflags); 514eabc0478Schristos } 515f003fb54Skardel } 516f003fb54Skardel 517f003fb54Skardel return r1_before_r2; 518abb0f93cSkardel } 519abb0f93cSkardel 520abb0f93cSkardel 521abb0f93cSkardel /* 5224eea345dSchristos * restrictions - return restrictions for this host in *r4a 523abb0f93cSkardel */ 5244eea345dSchristos void 525abb0f93cSkardel restrictions( 5264eea345dSchristos sockaddr_u *srcadr, 5274eea345dSchristos r4addr *r4a 528abb0f93cSkardel ) 529abb0f93cSkardel { 530f003fb54Skardel struct in6_addr *pin6; 5314eea345dSchristos 532eabc0478Schristos DEBUG_REQUIRE(NULL != r4a); 533abb0f93cSkardel 534abb0f93cSkardel res_calls++; 5354eea345dSchristos 536abb0f93cSkardel if (IS_IPV4(srcadr)) { 537*9e9fa66aSchristos struct restrict_4 *match; 538abb0f93cSkardel /* 539abb0f93cSkardel * Ignore any packets with a multicast source address 540abb0f93cSkardel * (this should be done early in the receive process, 541abb0f93cSkardel * not later!) 542abb0f93cSkardel */ 5434eea345dSchristos if (IN_CLASSD(SRCADR(srcadr))) { 544eabc0478Schristos goto multicast; 5454eea345dSchristos } 546abb0f93cSkardel 547f003fb54Skardel match = match_restrict4_addr(SRCADR(srcadr), 548f003fb54Skardel SRCPORT(srcadr)); 549eabc0478Schristos DEBUG_INSIST(match != NULL); 550*9e9fa66aSchristos match->ri.count++; 551f003fb54Skardel /* 552f003fb54Skardel * res_not_found counts only use of the final default 553f003fb54Skardel * entry, not any "restrict default ntpport ...", which 554f003fb54Skardel * would be just before the final default. 555f003fb54Skardel */ 556f003fb54Skardel if (&restrict_def4 == match) 557abb0f93cSkardel res_not_found++; 558abb0f93cSkardel else 559abb0f93cSkardel res_found++; 560*9e9fa66aSchristos r4a->rflags = match->ri.rflags; 561*9e9fa66aSchristos r4a->ippeerlimit = match->ri.ippeerlimit; 562eabc0478Schristos } else { 563*9e9fa66aSchristos struct restrict_6 *match; 564eabc0478Schristos DEBUG_REQUIRE(IS_IPV6(srcadr)); 565abb0f93cSkardel 566f003fb54Skardel pin6 = PSOCK_ADDR6(srcadr); 567abb0f93cSkardel 568abb0f93cSkardel /* 569abb0f93cSkardel * Ignore any packets with a multicast source address 570abb0f93cSkardel * (this should be done early in the receive process, 571abb0f93cSkardel * not later!) 572abb0f93cSkardel */ 573eabc0478Schristos if (IN6_IS_ADDR_MULTICAST(pin6)) { 574eabc0478Schristos goto multicast; 575eabc0478Schristos } 576f003fb54Skardel match = match_restrict6_addr(pin6, SRCPORT(srcadr)); 577eabc0478Schristos DEBUG_INSIST(match != NULL); 578*9e9fa66aSchristos match->ri.count++; 579f003fb54Skardel if (&restrict_def6 == match) 580abb0f93cSkardel res_not_found++; 581abb0f93cSkardel else 582abb0f93cSkardel res_found++; 583*9e9fa66aSchristos r4a->rflags = match->ri.rflags; 584*9e9fa66aSchristos r4a->ippeerlimit = match->ri.ippeerlimit; 585abb0f93cSkardel } 586cdfa2a7eSchristos 5874eea345dSchristos return; 588eabc0478Schristos 589eabc0478Schristos multicast: 590eabc0478Schristos r4a->rflags = RES_IGNORE; 591eabc0478Schristos r4a->ippeerlimit = 0; 5924eea345dSchristos } 5934eea345dSchristos 5944eea345dSchristos 595eabc0478Schristos #ifdef DEBUG 596eabc0478Schristos /* display string for restrict_op */ 5974eea345dSchristos const char * 598eabc0478Schristos resop_str(restrict_op op) 599eabc0478Schristos { 6004eea345dSchristos switch (op) { 6014eea345dSchristos case RESTRICT_FLAGS: return "RESTRICT_FLAGS"; 602eabc0478Schristos case RESTRICT_UNFLAG: return "RESTRICT_UNFLAG"; 6034eea345dSchristos case RESTRICT_REMOVE: return "RESTRICT_REMOVE"; 6044eea345dSchristos case RESTRICT_REMOVEIF: return "RESTRICT_REMOVEIF"; 6054eea345dSchristos } 606eabc0478Schristos DEBUG_INVARIANT(!"bad restrict_op in resop_str"); 607eabc0478Schristos return ""; /* silence not all paths return value warning */ 608abb0f93cSkardel } 609eabc0478Schristos #endif /* DEBUG */ 610abb0f93cSkardel 611abb0f93cSkardel 612abb0f93cSkardel /* 613abb0f93cSkardel * hack_restrict - add/subtract/manipulate entries on the restrict list 614abb0f93cSkardel */ 615eabc0478Schristos int/*BOOL*/ 616abb0f93cSkardel hack_restrict( 6174eea345dSchristos restrict_op op, 618abb0f93cSkardel sockaddr_u * resaddr, 619abb0f93cSkardel sockaddr_u * resmask, 6204eea345dSchristos short ippeerlimit, 621f003fb54Skardel u_short mflags, 6224eea345dSchristos u_short rflags, 623eabc0478Schristos u_int32 expire 624abb0f93cSkardel ) 625abb0f93cSkardel { 626eabc0478Schristos int bump_res_limited = FALSE; 627*9e9fa66aSchristos struct restrict_4 match4, *res4 = NULL; 628*9e9fa66aSchristos struct restrict_6 match6, *res6 = NULL; 629*9e9fa66aSchristos struct restrict_info *ri; 630f003fb54Skardel 631eabc0478Schristos #ifdef DEBUG 632eabc0478Schristos if (debug > 0) { 633eabc0478Schristos printf("hack_restrict: op %s addr %s mask %s", 634eabc0478Schristos resop_str(op), stoa(resaddr), stoa(resmask)); 635eabc0478Schristos if (ippeerlimit >= 0) { 636eabc0478Schristos printf(" ippeerlimit %d", ippeerlimit); 637eabc0478Schristos } 638eabc0478Schristos printf(" mflags %s rflags %s", mflags_str(mflags), 639eabc0478Schristos rflags_str(rflags)); 640eabc0478Schristos if (expire) { 641eabc0478Schristos printf("lifetime %u\n", 642eabc0478Schristos expire - (u_int32)current_time); 643eabc0478Schristos } else { 644eabc0478Schristos printf("\n"); 645eabc0478Schristos } 646eabc0478Schristos } 647eabc0478Schristos #endif 648f003fb54Skardel 649f003fb54Skardel if (NULL == resaddr) { 650eabc0478Schristos DEBUG_REQUIRE(NULL == resmask); 651eabc0478Schristos DEBUG_REQUIRE(RESTRICT_FLAGS == op); 652eabc0478Schristos DEBUG_REQUIRE(RESM_SOURCE & mflags); 6534eea345dSchristos restrict_source_rflags = rflags; 654f003fb54Skardel restrict_source_mflags = mflags; 6554eea345dSchristos restrict_source_ippeerlimit = ippeerlimit; 656eabc0478Schristos restrict_source_enabled = TRUE; 657eabc0478Schristos DPRINTF(1, ("restrict source template saved\n")); 658eabc0478Schristos return TRUE; 659f003fb54Skardel } 660f003fb54Skardel 661af12ab5eSchristos 662abb0f93cSkardel if (IS_IPV4(resaddr)) { 663eabc0478Schristos DEBUG_INVARIANT(IS_IPV4(resmask)); 664abb0f93cSkardel /* 665f003fb54Skardel * Get address and mask in host byte order for easy 666f003fb54Skardel * comparison as u_int32 667abb0f93cSkardel */ 668*9e9fa66aSchristos ZERO(match4); 669*9e9fa66aSchristos match4.v4.addr = SRCADR(resaddr); 670*9e9fa66aSchristos match4.v4.mask = SRCADR(resmask); 671*9e9fa66aSchristos match4.v4.addr &= match4.v4.mask; 672*9e9fa66aSchristos match4.ri.mflags = mflags; 673*9e9fa66aSchristos res4 = match_restrict4_entry(&match4); 674*9e9fa66aSchristos ri = res4 ? &res4->ri : NULL; 675eabc0478Schristos } else { 676eabc0478Schristos DEBUG_INVARIANT(IS_IPV6(resaddr)); 677eabc0478Schristos DEBUG_INVARIANT(IS_IPV6(resmask)); 678f003fb54Skardel /* 679f003fb54Skardel * Get address and mask in network byte order for easy 680f003fb54Skardel * comparison as byte sequences (e.g. memcmp()) 681f003fb54Skardel */ 682*9e9fa66aSchristos ZERO(match6); 683*9e9fa66aSchristos match6.v6.mask = SOCK_ADDR6(resmask); 684*9e9fa66aSchristos MASK_IPV6_ADDR(&match6.v6.addr, PSOCK_ADDR6(resaddr), 685*9e9fa66aSchristos &match6.v6.mask); 686*9e9fa66aSchristos match6.ri.mflags = mflags; 687*9e9fa66aSchristos res6 = match_restrict6_entry(&match6); 688*9e9fa66aSchristos ri = res6 ? &res6->ri : NULL; 689eabc0478Schristos } 690abb0f93cSkardel 691f003fb54Skardel 692f003fb54Skardel switch (op) { 693f003fb54Skardel 694f003fb54Skardel case RESTRICT_FLAGS: 695abb0f93cSkardel /* 696eabc0478Schristos * Here we add bits to the rflags. If we already have 697eabc0478Schristos * this restriction modify it. 698abb0f93cSkardel */ 699*9e9fa66aSchristos if (NULL != ri) { 700eabc0478Schristos if ( (RES_LIMITED & rflags) 701*9e9fa66aSchristos && !(RES_LIMITED & ri->rflags)) { 702eabc0478Schristos 703eabc0478Schristos bump_res_limited = TRUE; 704eabc0478Schristos } 705*9e9fa66aSchristos ri->rflags |= rflags; 706*9e9fa66aSchristos ri->expire = expire; 707eabc0478Schristos } else { 708*9e9fa66aSchristos if (IS_IPV4(resaddr)) { 709*9e9fa66aSchristos match4.ri.rflags = rflags; 710*9e9fa66aSchristos match4.ri.expire = expire; 711*9e9fa66aSchristos match4.ri.ippeerlimit = ippeerlimit; 712*9e9fa66aSchristos res4 = alloc_res4(); 713*9e9fa66aSchristos memcpy(res4, &match4, sizeof(*res4)); 714f003fb54Skardel LINK_SORT_SLIST( 715*9e9fa66aSchristos restrictlist4, res4, 716*9e9fa66aSchristos res_sorts_before4(res4, L_S_S_CUR()), 717*9e9fa66aSchristos link, struct restrict_4); 718*9e9fa66aSchristos } else { 719*9e9fa66aSchristos match6.ri.rflags = rflags; 720*9e9fa66aSchristos match6.ri.expire = expire; 721*9e9fa66aSchristos match6.ri.ippeerlimit = ippeerlimit; 722*9e9fa66aSchristos res6 = alloc_res6(); 723*9e9fa66aSchristos memcpy(res6, &match6, sizeof(*res6)); 724*9e9fa66aSchristos LINK_SORT_SLIST( 725*9e9fa66aSchristos restrictlist6, res6, 726*9e9fa66aSchristos res_sorts_before6(res6, L_S_S_CUR()), 727*9e9fa66aSchristos link, struct restrict_6); 728*9e9fa66aSchristos } 729f003fb54Skardel restrictcount++; 730eabc0478Schristos if (RES_LIMITED & rflags) { 731eabc0478Schristos bump_res_limited = TRUE; 732abb0f93cSkardel } 733eabc0478Schristos } 734eabc0478Schristos if (bump_res_limited) { 735eabc0478Schristos inc_res_limited(); 736eabc0478Schristos } 737eabc0478Schristos return TRUE; 738abb0f93cSkardel 739abb0f93cSkardel case RESTRICT_UNFLAG: 740abb0f93cSkardel /* 7414eea345dSchristos * Remove some bits from the rflags. If we didn't 742abb0f93cSkardel * find this one, just return. 743abb0f93cSkardel */ 744*9e9fa66aSchristos if (NULL == ri) { 745eabc0478Schristos DPRINTF(1, ("No match for %s %s removing rflags %s\n", 746eabc0478Schristos stoa(resaddr), stoa(resmask), 747eabc0478Schristos rflags_str(rflags))); 748eabc0478Schristos return FALSE; 749abb0f93cSkardel } 750*9e9fa66aSchristos if ( (RES_LIMITED & ri->rflags) 751eabc0478Schristos && (RES_LIMITED & rflags)) { 752eabc0478Schristos dec_res_limited(); 753eabc0478Schristos } 754*9e9fa66aSchristos ri->rflags &= ~rflags; 755eabc0478Schristos return TRUE; 756abb0f93cSkardel 757abb0f93cSkardel case RESTRICT_REMOVE: 758abb0f93cSkardel case RESTRICT_REMOVEIF: 759abb0f93cSkardel /* 760abb0f93cSkardel * Remove an entry from the table entirely if we 761abb0f93cSkardel * found one. Don't remove the default entry and 762eabc0478Schristos * don't remove an interface entry unless asked. 763abb0f93cSkardel */ 764*9e9fa66aSchristos if ( ri != NULL 765f003fb54Skardel && ( RESTRICT_REMOVEIF == op 766*9e9fa66aSchristos || !(RESM_INTERFACE & ri->mflags))) { 767*9e9fa66aSchristos if (res4 && res4 != &restrict_def4) { 768*9e9fa66aSchristos free_res4(res4); 769eabc0478Schristos return TRUE; 770abb0f93cSkardel } 771*9e9fa66aSchristos if (res6 && res6 != &restrict_def6) { 772*9e9fa66aSchristos free_res6(res6); 773*9e9fa66aSchristos return TRUE; 774*9e9fa66aSchristos } 775*9e9fa66aSchristos } 776eabc0478Schristos DPRINTF(1, ("No match removing %s %s restriction\n", 777eabc0478Schristos stoa(resaddr), stoa(resmask))); 778eabc0478Schristos return FALSE; 779eabc0478Schristos } 780eabc0478Schristos /* notreached */ 781eabc0478Schristos return FALSE; 782abb0f93cSkardel } 783f003fb54Skardel 7842950cc38Schristos 7852950cc38Schristos /* 7862950cc38Schristos * restrict_source - maintains dynamic "restrict source ..." entries as 7872950cc38Schristos * peers come and go. 7882950cc38Schristos */ 7892950cc38Schristos void 7902950cc38Schristos restrict_source( 7912950cc38Schristos sockaddr_u * addr, 792eabc0478Schristos int farewell, /* TRUE to remove */ 793eabc0478Schristos u_int32 lifetime /* seconds, 0 forever */ 7942950cc38Schristos ) 7952950cc38Schristos { 7962950cc38Schristos sockaddr_u onesmask; 797eabc0478Schristos int/*BOOL*/ success; 7982950cc38Schristos 799eabc0478Schristos if ( !restrict_source_enabled || SOCK_UNSPEC(addr) 800eabc0478Schristos || IS_MCAST(addr) || ISREFCLOCKADR(addr)) { 8012950cc38Schristos return; 802eabc0478Schristos } 8032950cc38Schristos 804af12ab5eSchristos REQUIRE(AF_INET == AF(addr) || AF_INET6 == AF(addr)); 8052950cc38Schristos 8062950cc38Schristos SET_HOSTMASK(&onesmask, AF(addr)); 8072950cc38Schristos if (farewell) { 808eabc0478Schristos success = hack_restrict(RESTRICT_REMOVE, addr, &onesmask, 809eabc0478Schristos 0, RESM_SOURCE, 0, 0); 810eabc0478Schristos if (success) { 811eabc0478Schristos DPRINTF(1, ("%s %s removed", __func__, 8122950cc38Schristos stoa(addr))); 813eabc0478Schristos } else { 814eabc0478Schristos msyslog(LOG_ERR, "%s remove %s failed", 815eabc0478Schristos __func__, stoa(addr)); 8162950cc38Schristos } 817eabc0478Schristos return; 818eabc0478Schristos } 819eabc0478Schristos 820eabc0478Schristos success = hack_restrict(RESTRICT_FLAGS, addr, &onesmask, 821eabc0478Schristos restrict_source_ippeerlimit, 822eabc0478Schristos restrict_source_mflags, 823eabc0478Schristos restrict_source_rflags, 824eabc0478Schristos lifetime > 0 825eabc0478Schristos ? lifetime + current_time 826eabc0478Schristos : 0); 827eabc0478Schristos if (success) { 828eabc0478Schristos DPRINTF(1, ("%s %s add/upd\n", __func__, 829eabc0478Schristos stoa(addr))); 830eabc0478Schristos } else { 831eabc0478Schristos msyslog(LOG_ERR, "%s %s failed", __func__, stoa(addr)); 832eabc0478Schristos } 833eabc0478Schristos } 834eabc0478Schristos 835eabc0478Schristos 836eabc0478Schristos #ifdef DEBUG 837eabc0478Schristos /* Convert restriction RES_ flag bits into a display string */ 838eabc0478Schristos const char * 839eabc0478Schristos rflags_str( 840eabc0478Schristos u_short rflags 841eabc0478Schristos ) 842eabc0478Schristos { 843eabc0478Schristos const size_t sz = LIB_BUFLENGTH; 844eabc0478Schristos char * rfs; 845eabc0478Schristos 846eabc0478Schristos LIB_GETBUF(rfs); 847eabc0478Schristos rfs[0] = '\0'; 848eabc0478Schristos 849eabc0478Schristos if (rflags & RES_FLAKE) { 850eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_FLAKE, rflags); 851eabc0478Schristos append_flagstr(rfs, sz, "flake"); 852eabc0478Schristos } 853eabc0478Schristos 854eabc0478Schristos if (rflags & RES_IGNORE) { 855eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_IGNORE, rflags); 856eabc0478Schristos append_flagstr(rfs, sz, "ignore"); 857eabc0478Schristos } 858eabc0478Schristos 859eabc0478Schristos if (rflags & RES_KOD) { 860eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_KOD, rflags); 861eabc0478Schristos append_flagstr(rfs, sz, "kod"); 862eabc0478Schristos } 863eabc0478Schristos 864eabc0478Schristos if (rflags & RES_MSSNTP) { 865eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_MSSNTP, rflags); 866eabc0478Schristos append_flagstr(rfs, sz, "mssntp"); 867eabc0478Schristos } 868eabc0478Schristos 869eabc0478Schristos if (rflags & RES_LIMITED) { 870eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_LIMITED, rflags); 871eabc0478Schristos append_flagstr(rfs, sz, "limited"); 872eabc0478Schristos } 873eabc0478Schristos 874eabc0478Schristos if (rflags & RES_LPTRAP) { 875eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_LPTRAP, rflags); 876eabc0478Schristos append_flagstr(rfs, sz, "lptrap"); 877eabc0478Schristos } 878eabc0478Schristos 879eabc0478Schristos if (rflags & RES_NOMODIFY) { 880eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_NOMODIFY, rflags); 881eabc0478Schristos append_flagstr(rfs, sz, "nomodify"); 882eabc0478Schristos } 883eabc0478Schristos 884eabc0478Schristos if (rflags & RES_NOMRULIST) { 885eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_NOMRULIST, rflags); 886eabc0478Schristos append_flagstr(rfs, sz, "nomrulist"); 887eabc0478Schristos } 888eabc0478Schristos 889eabc0478Schristos if (rflags & RES_NOEPEER) { 890eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_NOEPEER, rflags); 891eabc0478Schristos append_flagstr(rfs, sz, "noepeer"); 892eabc0478Schristos } 893eabc0478Schristos 894eabc0478Schristos if (rflags & RES_NOPEER) { 895eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_NOPEER, rflags); 896eabc0478Schristos append_flagstr(rfs, sz, "nopeer"); 897eabc0478Schristos } 898eabc0478Schristos 899eabc0478Schristos if (rflags & RES_NOQUERY) { 900eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_NOQUERY, rflags); 901eabc0478Schristos append_flagstr(rfs, sz, "noquery"); 902eabc0478Schristos } 903eabc0478Schristos 904eabc0478Schristos if (rflags & RES_DONTSERVE) { 905eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_DONTSERVE, rflags); 906eabc0478Schristos append_flagstr(rfs, sz, "dontserve"); 907eabc0478Schristos } 908eabc0478Schristos 909eabc0478Schristos if (rflags & RES_NOTRAP) { 910eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_NOTRAP, rflags); 911eabc0478Schristos append_flagstr(rfs, sz, "notrap"); 912eabc0478Schristos } 913eabc0478Schristos 914eabc0478Schristos if (rflags & RES_DONTTRUST) { 915eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_DONTTRUST, rflags); 916eabc0478Schristos append_flagstr(rfs, sz, "notrust"); 917eabc0478Schristos } 918eabc0478Schristos 919eabc0478Schristos if (rflags & RES_SRVRSPFUZ) { 920eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_SRVRSPFUZ, rflags); 921eabc0478Schristos append_flagstr(rfs, sz, "srvrspfuz"); 922eabc0478Schristos } 923eabc0478Schristos 924eabc0478Schristos if (rflags & RES_VERSION) { 925eabc0478Schristos CLEAR_BIT_IF_DEBUG(RES_VERSION, rflags); 926eabc0478Schristos append_flagstr(rfs, sz, "version"); 927eabc0478Schristos } 928eabc0478Schristos 929eabc0478Schristos DEBUG_INVARIANT(!rflags); 930eabc0478Schristos 931eabc0478Schristos if ('\0' == rfs[0]) { 932eabc0478Schristos append_flagstr(rfs, sz, "(none)"); 933eabc0478Schristos } 934eabc0478Schristos 935eabc0478Schristos return rfs; 936eabc0478Schristos } 937eabc0478Schristos 938eabc0478Schristos 939eabc0478Schristos /* Convert restriction match RESM_ flag bits into a display string */ 940eabc0478Schristos const char * 941eabc0478Schristos mflags_str( 942eabc0478Schristos u_short mflags 943eabc0478Schristos ) 944eabc0478Schristos { 945eabc0478Schristos const size_t sz = LIB_BUFLENGTH; 946eabc0478Schristos char * mfs; 947eabc0478Schristos 948eabc0478Schristos LIB_GETBUF(mfs); 949eabc0478Schristos mfs[0] = '\0'; 950eabc0478Schristos 951eabc0478Schristos if (mflags & RESM_NTPONLY) { 952eabc0478Schristos CLEAR_BIT_IF_DEBUG(RESM_NTPONLY, mflags); 953eabc0478Schristos append_flagstr(mfs, sz, "ntponly"); 954eabc0478Schristos } 955eabc0478Schristos 956eabc0478Schristos if (mflags & RESM_SOURCE) { 957eabc0478Schristos CLEAR_BIT_IF_DEBUG(RESM_SOURCE, mflags); 958eabc0478Schristos append_flagstr(mfs, sz, "source"); 959eabc0478Schristos } 960eabc0478Schristos 961eabc0478Schristos if (mflags & RESM_INTERFACE) { 962eabc0478Schristos CLEAR_BIT_IF_DEBUG(RESM_INTERFACE, mflags); 963eabc0478Schristos append_flagstr(mfs, sz, "interface"); 964eabc0478Schristos } 965eabc0478Schristos 966eabc0478Schristos DEBUG_INVARIANT(!mflags); 967eabc0478Schristos 968eabc0478Schristos return mfs; 969eabc0478Schristos } 970eabc0478Schristos #endif /* DEBUG */ 971