1*368f0e94Sbenno /* $OpenBSD: util.c,v 1.21 2016/06/03 17:36:37 benno Exp $ */ 22ffcd4e0Sclaudio 32ffcd4e0Sclaudio /* 42ffcd4e0Sclaudio * Copyright (c) 2006 Claudio Jeker <claudio@openbsd.org> 52ffcd4e0Sclaudio * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org> 62ffcd4e0Sclaudio * 72ffcd4e0Sclaudio * Permission to use, copy, modify, and distribute this software for any 82ffcd4e0Sclaudio * purpose with or without fee is hereby granted, provided that the above 92ffcd4e0Sclaudio * copyright notice and this permission notice appear in all copies. 102ffcd4e0Sclaudio * 112ffcd4e0Sclaudio * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 122ffcd4e0Sclaudio * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 132ffcd4e0Sclaudio * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 142ffcd4e0Sclaudio * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 152ffcd4e0Sclaudio * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 162ffcd4e0Sclaudio * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 172ffcd4e0Sclaudio * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 182ffcd4e0Sclaudio */ 192ffcd4e0Sclaudio #include <sys/types.h> 202ffcd4e0Sclaudio #include <sys/socket.h> 212ffcd4e0Sclaudio #include <netinet/in.h> 222ffcd4e0Sclaudio #include <arpa/inet.h> 232ffcd4e0Sclaudio #include <netdb.h> 242ffcd4e0Sclaudio #include <stdlib.h> 252ffcd4e0Sclaudio #include <stdio.h> 262ffcd4e0Sclaudio #include <string.h> 272ffcd4e0Sclaudio 282ffcd4e0Sclaudio #include "bgpd.h" 292ffcd4e0Sclaudio #include "rde.h" 302ffcd4e0Sclaudio 311e590dcfSclaudio const char *aspath_delim(u_int8_t, int); 321e590dcfSclaudio 332ffcd4e0Sclaudio const char * 342ffcd4e0Sclaudio log_addr(const struct bgpd_addr *addr) 352ffcd4e0Sclaudio { 362ffcd4e0Sclaudio static char buf[48]; 37256b680eSclaudio char tbuf[16]; 382ffcd4e0Sclaudio 3915d8de66Sclaudio switch (addr->aid) { 4015d8de66Sclaudio case AID_INET: 4115d8de66Sclaudio case AID_INET6: 4215d8de66Sclaudio if (inet_ntop(aid2af(addr->aid), &addr->ba, buf, 4315d8de66Sclaudio sizeof(buf)) == NULL) 442ffcd4e0Sclaudio return ("?"); 452ffcd4e0Sclaudio return (buf); 4615d8de66Sclaudio case AID_VPN_IPv4: 47256b680eSclaudio if (inet_ntop(AF_INET, &addr->vpn4.addr, tbuf, 48256b680eSclaudio sizeof(tbuf)) == NULL) 4915d8de66Sclaudio return ("?"); 50256b680eSclaudio snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd), 51256b680eSclaudio tbuf); 5215d8de66Sclaudio return (buf); 5315d8de66Sclaudio } 5415d8de66Sclaudio return ("???"); 552ffcd4e0Sclaudio } 562ffcd4e0Sclaudio 572ffcd4e0Sclaudio const char * 582ffcd4e0Sclaudio log_in6addr(const struct in6_addr *addr) 592ffcd4e0Sclaudio { 602ffcd4e0Sclaudio struct sockaddr_in6 sa_in6; 612ffcd4e0Sclaudio u_int16_t tmp16; 622ffcd4e0Sclaudio 632ffcd4e0Sclaudio bzero(&sa_in6, sizeof(sa_in6)); 642ffcd4e0Sclaudio sa_in6.sin6_len = sizeof(sa_in6); 652ffcd4e0Sclaudio sa_in6.sin6_family = AF_INET6; 662ffcd4e0Sclaudio memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr)); 672ffcd4e0Sclaudio 682ffcd4e0Sclaudio /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */ 692ffcd4e0Sclaudio if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) || 702ffcd4e0Sclaudio IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) { 712ffcd4e0Sclaudio memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16)); 722ffcd4e0Sclaudio sa_in6.sin6_scope_id = ntohs(tmp16); 732ffcd4e0Sclaudio sa_in6.sin6_addr.s6_addr[2] = 0; 742ffcd4e0Sclaudio sa_in6.sin6_addr.s6_addr[3] = 0; 752ffcd4e0Sclaudio } 762ffcd4e0Sclaudio 772ffcd4e0Sclaudio return (log_sockaddr((struct sockaddr *)&sa_in6)); 782ffcd4e0Sclaudio } 792ffcd4e0Sclaudio 802ffcd4e0Sclaudio const char * 812ffcd4e0Sclaudio log_sockaddr(struct sockaddr *sa) 822ffcd4e0Sclaudio { 832ffcd4e0Sclaudio static char buf[NI_MAXHOST]; 842ffcd4e0Sclaudio 852ffcd4e0Sclaudio if (getnameinfo(sa, sa->sa_len, buf, sizeof(buf), NULL, 0, 862ffcd4e0Sclaudio NI_NUMERICHOST)) 872ffcd4e0Sclaudio return ("(unknown)"); 882ffcd4e0Sclaudio else 892ffcd4e0Sclaudio return (buf); 902ffcd4e0Sclaudio } 912ffcd4e0Sclaudio 920c88bf70Sclaudio const char * 930c88bf70Sclaudio log_as(u_int32_t as) 940c88bf70Sclaudio { 9506bcde9cSphessler static char buf[11]; /* "4294967294\0" */ 960c88bf70Sclaudio 970c88bf70Sclaudio if (snprintf(buf, sizeof(buf), "%u", as) == -1) 980c88bf70Sclaudio return ("?"); 9906bcde9cSphessler 1000c88bf70Sclaudio return (buf); 1010c88bf70Sclaudio } 1020c88bf70Sclaudio 103256b680eSclaudio const char * 104256b680eSclaudio log_rd(u_int64_t rd) 105256b680eSclaudio { 106256b680eSclaudio static char buf[32]; 107256b680eSclaudio struct in_addr addr; 108256b680eSclaudio u_int32_t u32; 109256b680eSclaudio u_int16_t u16; 110256b680eSclaudio 111256b680eSclaudio rd = betoh64(rd); 112256b680eSclaudio switch (rd >> 48) { 113256b680eSclaudio case EXT_COMMUNITY_TWO_AS: 114256b680eSclaudio u32 = rd & 0xffffffff; 115256b680eSclaudio u16 = (rd >> 32) & 0xffff; 11632ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32); 117256b680eSclaudio break; 118256b680eSclaudio case EXT_COMMUNITY_FOUR_AS: 119256b680eSclaudio u32 = (rd >> 16) & 0xffffffff; 120256b680eSclaudio u16 = rd & 0xffff; 12132ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16); 122256b680eSclaudio break; 123256b680eSclaudio case EXT_COMMUNITY_IPV4: 124256b680eSclaudio u32 = (rd >> 16) & 0xffffffff; 125256b680eSclaudio u16 = rd & 0xffff; 126256b680eSclaudio addr.s_addr = htonl(u32); 12732ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16); 128256b680eSclaudio break; 129256b680eSclaudio default: 130256b680eSclaudio return ("rd ?"); 131256b680eSclaudio } 132256b680eSclaudio return (buf); 133256b680eSclaudio } 134256b680eSclaudio 135256b680eSclaudio /* NOTE: this function does not check if the type/subtype combo is 136536f41e5Sclaudio * actually valid. */ 137536f41e5Sclaudio const char * 138536f41e5Sclaudio log_ext_subtype(u_int8_t subtype) 139536f41e5Sclaudio { 140536f41e5Sclaudio static char etype[6]; 141536f41e5Sclaudio 142536f41e5Sclaudio switch (subtype) { 143536f41e5Sclaudio case EXT_COMMUNITY_ROUTE_TGT: 144536f41e5Sclaudio return ("rt"); /* route target */ 145e85ee6aeSsthen case EXT_COMMUNITY_ROUTE_ORIG: 146536f41e5Sclaudio return ("soo"); /* source of origin */ 147536f41e5Sclaudio case EXT_COMMUNITY_OSPF_DOM_ID: 148536f41e5Sclaudio return ("odi"); /* ospf domain id */ 149536f41e5Sclaudio case EXT_COMMUNITY_OSPF_RTR_TYPE: 150536f41e5Sclaudio return ("ort"); /* ospf route type */ 151536f41e5Sclaudio case EXT_COMMUNITY_OSPF_RTR_ID: 152536f41e5Sclaudio return ("ori"); /* ospf router id */ 153536f41e5Sclaudio case EXT_COMMUNITY_BGP_COLLECT: 154536f41e5Sclaudio return ("bdc"); /* bgp data collection */ 155536f41e5Sclaudio default: 156d6340f7aSderaadt snprintf(etype, sizeof(etype), "[%u]", subtype); 157536f41e5Sclaudio return (etype); 158536f41e5Sclaudio } 159536f41e5Sclaudio } 160536f41e5Sclaudio 1611e590dcfSclaudio const char * 1621e590dcfSclaudio aspath_delim(u_int8_t seg_type, int closing) 1631e590dcfSclaudio { 1641e590dcfSclaudio static char db[8]; 1651e590dcfSclaudio 1661e590dcfSclaudio switch (seg_type) { 1671e590dcfSclaudio case AS_SET: 1681e590dcfSclaudio if (!closing) 1691e590dcfSclaudio return ("{ "); 1701e590dcfSclaudio else 1711e590dcfSclaudio return (" }"); 1721e590dcfSclaudio case AS_SEQUENCE: 1731e590dcfSclaudio return (""); 1741e590dcfSclaudio case AS_CONFED_SEQUENCE: 1751e590dcfSclaudio if (!closing) 1761e590dcfSclaudio return ("( "); 1771e590dcfSclaudio else 1781e590dcfSclaudio return (" )"); 1791e590dcfSclaudio case AS_CONFED_SET: 1801e590dcfSclaudio if (!closing) 1811e590dcfSclaudio return ("[ "); 1821e590dcfSclaudio else 1831e590dcfSclaudio return (" ]"); 1841e590dcfSclaudio default: 1851e590dcfSclaudio if (!closing) 1861e590dcfSclaudio snprintf(db, sizeof(db), "!%u ", seg_type); 1871e590dcfSclaudio else 1881e590dcfSclaudio snprintf(db, sizeof(db), " !%u", seg_type); 1891e590dcfSclaudio return (db); 1901e590dcfSclaudio } 1911e590dcfSclaudio } 1921e590dcfSclaudio 1932ffcd4e0Sclaudio int 1942ffcd4e0Sclaudio aspath_snprint(char *buf, size_t size, void *data, u_int16_t len) 1952ffcd4e0Sclaudio { 1962ffcd4e0Sclaudio #define UPDATE() \ 1972ffcd4e0Sclaudio do { \ 1982ffcd4e0Sclaudio if (r == -1) \ 1992ffcd4e0Sclaudio return (-1); \ 2002ffcd4e0Sclaudio total_size += r; \ 2012ffcd4e0Sclaudio if ((unsigned int)r < size) { \ 2022ffcd4e0Sclaudio size -= r; \ 2032ffcd4e0Sclaudio buf += r; \ 2042ffcd4e0Sclaudio } else { \ 2052ffcd4e0Sclaudio buf += size; \ 2062ffcd4e0Sclaudio size = 0; \ 2072ffcd4e0Sclaudio } \ 2082ffcd4e0Sclaudio } while (0) 2092ffcd4e0Sclaudio u_int8_t *seg; 2102ffcd4e0Sclaudio int r, total_size; 2112ffcd4e0Sclaudio u_int16_t seg_size; 2122ffcd4e0Sclaudio u_int8_t i, seg_type, seg_len; 2132ffcd4e0Sclaudio 2142ffcd4e0Sclaudio total_size = 0; 2152ffcd4e0Sclaudio seg = data; 2162ffcd4e0Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 2172ffcd4e0Sclaudio seg_type = seg[0]; 2182ffcd4e0Sclaudio seg_len = seg[1]; 2190c88bf70Sclaudio seg_size = 2 + sizeof(u_int32_t) * seg_len; 2202ffcd4e0Sclaudio 2211e590dcfSclaudio r = snprintf(buf, size, "%s%s", 2221e590dcfSclaudio total_size != 0 ? " " : "", 2231e590dcfSclaudio aspath_delim(seg_type, 0)); 2242ffcd4e0Sclaudio UPDATE(); 2252ffcd4e0Sclaudio 2262ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) { 2270c88bf70Sclaudio r = snprintf(buf, size, "%s", 2280c88bf70Sclaudio log_as(aspath_extract(seg, i))); 2292ffcd4e0Sclaudio UPDATE(); 2302ffcd4e0Sclaudio if (i + 1 < seg_len) { 2312ffcd4e0Sclaudio r = snprintf(buf, size, " "); 2322ffcd4e0Sclaudio UPDATE(); 2332ffcd4e0Sclaudio } 2342ffcd4e0Sclaudio } 2351e590dcfSclaudio r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1)); 2362ffcd4e0Sclaudio UPDATE(); 2372ffcd4e0Sclaudio } 23855e49665Sclaudio /* ensure that we have a valid C-string especially for empty as path */ 2392ffcd4e0Sclaudio if (size > 0) 2402ffcd4e0Sclaudio *buf = '\0'; 2412ffcd4e0Sclaudio 2422ffcd4e0Sclaudio return (total_size); 2432ffcd4e0Sclaudio #undef UPDATE 2442ffcd4e0Sclaudio } 2452ffcd4e0Sclaudio 2462ffcd4e0Sclaudio int 2472ffcd4e0Sclaudio aspath_asprint(char **ret, void *data, u_int16_t len) 2482ffcd4e0Sclaudio { 2492ffcd4e0Sclaudio size_t slen; 2502ffcd4e0Sclaudio int plen; 2512ffcd4e0Sclaudio 2522ffcd4e0Sclaudio slen = aspath_strlen(data, len) + 1; 2532ffcd4e0Sclaudio *ret = malloc(slen); 2542ffcd4e0Sclaudio if (*ret == NULL) 2552ffcd4e0Sclaudio return (-1); 2562ffcd4e0Sclaudio 2572ffcd4e0Sclaudio plen = aspath_snprint(*ret, slen, data, len); 2582ffcd4e0Sclaudio if (plen == -1) { 2592ffcd4e0Sclaudio free(*ret); 2602ffcd4e0Sclaudio *ret = NULL; 2612ffcd4e0Sclaudio return (-1); 2622ffcd4e0Sclaudio } 2632ffcd4e0Sclaudio 2642ffcd4e0Sclaudio return (0); 2652ffcd4e0Sclaudio } 2662ffcd4e0Sclaudio 2672ffcd4e0Sclaudio size_t 2682ffcd4e0Sclaudio aspath_strlen(void *data, u_int16_t len) 2692ffcd4e0Sclaudio { 2702ffcd4e0Sclaudio u_int8_t *seg; 2712ffcd4e0Sclaudio int total_size; 2720c88bf70Sclaudio u_int32_t as; 2730c88bf70Sclaudio u_int16_t seg_size; 2742ffcd4e0Sclaudio u_int8_t i, seg_type, seg_len; 2752ffcd4e0Sclaudio 2762ffcd4e0Sclaudio total_size = 0; 2772ffcd4e0Sclaudio seg = data; 2782ffcd4e0Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 2792ffcd4e0Sclaudio seg_type = seg[0]; 2802ffcd4e0Sclaudio seg_len = seg[1]; 2810c88bf70Sclaudio seg_size = 2 + sizeof(u_int32_t) * seg_len; 2822ffcd4e0Sclaudio 2832ffcd4e0Sclaudio if (seg_type == AS_SET) 2842ffcd4e0Sclaudio if (total_size != 0) 2852ffcd4e0Sclaudio total_size += 3; 2862ffcd4e0Sclaudio else 2872ffcd4e0Sclaudio total_size += 2; 2882ffcd4e0Sclaudio else if (total_size != 0) 2892ffcd4e0Sclaudio total_size += 1; 2902ffcd4e0Sclaudio 2912ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) { 2922ffcd4e0Sclaudio as = aspath_extract(seg, i); 2930c88bf70Sclaudio 2948db4f5d2Sclaudio do { 2958db4f5d2Sclaudio total_size++; 2968db4f5d2Sclaudio } while ((as = as / 10) != 0); 2972ffcd4e0Sclaudio 2982ffcd4e0Sclaudio if (i + 1 < seg_len) 2992ffcd4e0Sclaudio total_size += 1; 3002ffcd4e0Sclaudio } 3012ffcd4e0Sclaudio 3022ffcd4e0Sclaudio if (seg_type == AS_SET) 3032ffcd4e0Sclaudio total_size += 2; 3042ffcd4e0Sclaudio } 3052ffcd4e0Sclaudio return (total_size); 3062ffcd4e0Sclaudio } 3072ffcd4e0Sclaudio 308fafbb788Sclaudio /* we need to be able to search more than one as */ 309fafbb788Sclaudio int 310*368f0e94Sbenno aspath_match(void *data, u_int16_t len, struct filter_as *f, u_int32_t match) 311fafbb788Sclaudio { 312fafbb788Sclaudio u_int8_t *seg; 313fafbb788Sclaudio int final; 314fafbb788Sclaudio u_int16_t seg_size; 315de50ed92Sclaudio u_int8_t i, seg_len; 316*368f0e94Sbenno u_int32_t as; 317fafbb788Sclaudio 318*368f0e94Sbenno if (f->type == AS_EMPTY) { 319fafbb788Sclaudio if (len == 0) 320fafbb788Sclaudio return (1); 321fafbb788Sclaudio else 322fafbb788Sclaudio return (0); 323fafbb788Sclaudio } 324fafbb788Sclaudio 325fafbb788Sclaudio seg = data; 326fafbb788Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 327fafbb788Sclaudio seg_len = seg[1]; 328fafbb788Sclaudio seg_size = 2 + sizeof(u_int32_t) * seg_len; 329fafbb788Sclaudio 330fafbb788Sclaudio final = (len == seg_size); 331fafbb788Sclaudio 332fafbb788Sclaudio /* just check the first (leftmost) AS */ 333*368f0e94Sbenno if (f->type == AS_PEER) { 334*368f0e94Sbenno as = aspath_extract(seg, 0); 335*368f0e94Sbenno if (as_compare(f->op, as, match, f->as_min, f->as_max)) 336fafbb788Sclaudio return (1); 337fafbb788Sclaudio else 338fafbb788Sclaudio return (0); 339fafbb788Sclaudio } 340fafbb788Sclaudio /* just check the final (rightmost) AS */ 341*368f0e94Sbenno if (f->type == AS_SOURCE) { 342fafbb788Sclaudio /* not yet in the final segment */ 343fafbb788Sclaudio if (!final) 344fafbb788Sclaudio continue; 345*368f0e94Sbenno as = aspath_extract(seg, seg_len - 1); 346*368f0e94Sbenno if (as_compare(f->op, as, match, f->as_min, f->as_max)) 347fafbb788Sclaudio return (1); 348fafbb788Sclaudio else 349fafbb788Sclaudio return (0); 350fafbb788Sclaudio } 351fafbb788Sclaudio /* AS_TRANSIT or AS_ALL */ 352fafbb788Sclaudio for (i = 0; i < seg_len; i++) { 353fafbb788Sclaudio /* 354fafbb788Sclaudio * the source (rightmost) AS is excluded from 355fafbb788Sclaudio * AS_TRANSIT matches. 356fafbb788Sclaudio */ 357*368f0e94Sbenno if (final && i == seg_len - 1 && f->type == AS_TRANSIT) 358fafbb788Sclaudio return (0); 359*368f0e94Sbenno as = aspath_extract(seg, i); 360*368f0e94Sbenno if (as_compare(f->op, as, match, f->as_min, f->as_max)) 361fafbb788Sclaudio return (1); 362fafbb788Sclaudio } 363fafbb788Sclaudio } 364*368f0e94Sbenno return (0); 365fafbb788Sclaudio } 366*368f0e94Sbenno 367*368f0e94Sbenno int 368*368f0e94Sbenno as_compare(u_int8_t op, u_int32_t as, u_int32_t match, u_int32_t as_min, 369*368f0e94Sbenno u_int32_t as_max) 370*368f0e94Sbenno { 371*368f0e94Sbenno if ((op == OP_NONE || op == OP_EQ) && as == match) 372*368f0e94Sbenno return (1); 373*368f0e94Sbenno else if (op == OP_NE && as != match) 374*368f0e94Sbenno return (1); 375*368f0e94Sbenno else if (op == OP_RANGE && as >= as_min && as <= as_max) 376*368f0e94Sbenno return (1); 377*368f0e94Sbenno else if (op == OP_XRANGE && as > as_min && as < as_max) 378*368f0e94Sbenno return (1); 379fafbb788Sclaudio return (0); 380fafbb788Sclaudio } 381fafbb788Sclaudio 3822ffcd4e0Sclaudio /* 3832ffcd4e0Sclaudio * Extract the asnum out of the as segment at the specified position. 3842ffcd4e0Sclaudio * Direct access is not possible because of non-aligned reads. 385c5508ee4Sclaudio * ATTENTION: no bounds checks are done. 3862ffcd4e0Sclaudio */ 3870c88bf70Sclaudio u_int32_t 3882ffcd4e0Sclaudio aspath_extract(const void *seg, int pos) 3892ffcd4e0Sclaudio { 3902ffcd4e0Sclaudio const u_char *ptr = seg; 3910c88bf70Sclaudio u_int32_t as; 3922ffcd4e0Sclaudio 3930c88bf70Sclaudio ptr += 2 + sizeof(u_int32_t) * pos; 3940c88bf70Sclaudio memcpy(&as, ptr, sizeof(u_int32_t)); 3950c88bf70Sclaudio return (ntohl(as)); 3962ffcd4e0Sclaudio } 39721a825c9Sclaudio 398fafbb788Sclaudio int 399fafbb788Sclaudio prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, 400fafbb788Sclaudio int prefixlen) 401fafbb788Sclaudio { 402fafbb788Sclaudio in_addr_t mask, aa, ba; 403fafbb788Sclaudio int i; 404fafbb788Sclaudio u_int8_t m; 405fafbb788Sclaudio 406fafbb788Sclaudio if (a->aid != b->aid) 407fafbb788Sclaudio return (a->aid - b->aid); 408fafbb788Sclaudio 409fafbb788Sclaudio switch (a->aid) { 410fafbb788Sclaudio case AID_INET: 4117da59fecSclaudio if (prefixlen == 0) 4127da59fecSclaudio return (0); 413fafbb788Sclaudio if (prefixlen > 32) 414fafbb788Sclaudio fatalx("prefix_cmp: bad IPv4 prefixlen"); 415fafbb788Sclaudio mask = htonl(prefixlen2mask(prefixlen)); 416fafbb788Sclaudio aa = ntohl(a->v4.s_addr & mask); 417fafbb788Sclaudio ba = ntohl(b->v4.s_addr & mask); 418fafbb788Sclaudio if (aa != ba) 419fafbb788Sclaudio return (aa - ba); 420fafbb788Sclaudio return (0); 421fafbb788Sclaudio case AID_INET6: 4227da59fecSclaudio if (prefixlen == 0) 4237da59fecSclaudio return (0); 424fafbb788Sclaudio if (prefixlen > 128) 425fafbb788Sclaudio fatalx("prefix_cmp: bad IPv6 prefixlen"); 426fafbb788Sclaudio for (i = 0; i < prefixlen / 8; i++) 427fafbb788Sclaudio if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 428fafbb788Sclaudio return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 429fafbb788Sclaudio i = prefixlen % 8; 430fafbb788Sclaudio if (i) { 431fafbb788Sclaudio m = 0xff00 >> i; 432fafbb788Sclaudio if ((a->v6.s6_addr[prefixlen / 8] & m) != 433fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m)) 434fafbb788Sclaudio return ((a->v6.s6_addr[prefixlen / 8] & m) - 435fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m)); 436fafbb788Sclaudio } 437fafbb788Sclaudio return (0); 438fafbb788Sclaudio case AID_VPN_IPv4: 439fafbb788Sclaudio if (prefixlen > 32) 440fafbb788Sclaudio fatalx("prefix_cmp: bad IPv4 VPN prefixlen"); 441fafbb788Sclaudio if (betoh64(a->vpn4.rd) > betoh64(b->vpn4.rd)) 442fafbb788Sclaudio return (1); 443fafbb788Sclaudio if (betoh64(a->vpn4.rd) < betoh64(b->vpn4.rd)) 444fafbb788Sclaudio return (-1); 445fafbb788Sclaudio mask = htonl(prefixlen2mask(prefixlen)); 446fafbb788Sclaudio aa = ntohl(a->vpn4.addr.s_addr & mask); 447fafbb788Sclaudio ba = ntohl(b->vpn4.addr.s_addr & mask); 448fafbb788Sclaudio if (aa != ba) 449fafbb788Sclaudio return (aa - ba); 450fafbb788Sclaudio if (a->vpn4.labellen > b->vpn4.labellen) 451fafbb788Sclaudio return (1); 452fafbb788Sclaudio if (a->vpn4.labellen < b->vpn4.labellen) 453fafbb788Sclaudio return (-1); 454fafbb788Sclaudio return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack, 455fafbb788Sclaudio a->vpn4.labellen)); 456fafbb788Sclaudio default: 457fafbb788Sclaudio fatalx("prefix_cmp: unknown af"); 458fafbb788Sclaudio } 459fafbb788Sclaudio return (-1); 460fafbb788Sclaudio } 461fafbb788Sclaudio 46221a825c9Sclaudio in_addr_t 46321a825c9Sclaudio prefixlen2mask(u_int8_t prefixlen) 46421a825c9Sclaudio { 46521a825c9Sclaudio if (prefixlen == 0) 46621a825c9Sclaudio return (0); 46721a825c9Sclaudio 46821a825c9Sclaudio return (0xffffffff << (32 - prefixlen)); 46921a825c9Sclaudio } 47021a825c9Sclaudio 47121a825c9Sclaudio void 47221a825c9Sclaudio inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 47321a825c9Sclaudio { 47421a825c9Sclaudio struct in6_addr mask; 47521a825c9Sclaudio int i; 47621a825c9Sclaudio 47721a825c9Sclaudio bzero(&mask, sizeof(mask)); 47821a825c9Sclaudio for (i = 0; i < prefixlen / 8; i++) 47921a825c9Sclaudio mask.s6_addr[i] = 0xff; 48021a825c9Sclaudio i = prefixlen % 8; 48121a825c9Sclaudio if (i) 48221a825c9Sclaudio mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 48321a825c9Sclaudio 48421a825c9Sclaudio for (i = 0; i < 16; i++) 48521a825c9Sclaudio dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 48621a825c9Sclaudio } 487d6c2e4e8Sclaudio 488d6c2e4e8Sclaudio /* address family translation functions */ 489d6c2e4e8Sclaudio const struct aid aid_vals[AID_MAX] = AID_VALS; 490d6c2e4e8Sclaudio 49186729c90Sclaudio const char * 49286729c90Sclaudio aid2str(u_int8_t aid) 49386729c90Sclaudio { 49486729c90Sclaudio if (aid < AID_MAX) 49586729c90Sclaudio return (aid_vals[aid].name); 49686729c90Sclaudio return ("unknown AID"); 49786729c90Sclaudio } 49886729c90Sclaudio 499d6c2e4e8Sclaudio int 500d6c2e4e8Sclaudio aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi) 501d6c2e4e8Sclaudio { 502d6c2e4e8Sclaudio if (aid < AID_MAX) { 503d6c2e4e8Sclaudio *afi = aid_vals[aid].afi; 504d6c2e4e8Sclaudio *safi = aid_vals[aid].safi; 505d6c2e4e8Sclaudio return (0); 506d6c2e4e8Sclaudio } 507d6c2e4e8Sclaudio return (-1); 508d6c2e4e8Sclaudio } 509d6c2e4e8Sclaudio 510d6c2e4e8Sclaudio int 511d6c2e4e8Sclaudio afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid) 512d6c2e4e8Sclaudio { 513d6c2e4e8Sclaudio u_int8_t i; 514d6c2e4e8Sclaudio 515d6c2e4e8Sclaudio for (i = 0; i < AID_MAX; i++) 516d6c2e4e8Sclaudio if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) { 517d6c2e4e8Sclaudio *aid = i; 518d6c2e4e8Sclaudio return (0); 519d6c2e4e8Sclaudio } 520d6c2e4e8Sclaudio 521d6c2e4e8Sclaudio return (-1); 522d6c2e4e8Sclaudio } 523d6c2e4e8Sclaudio 524d6c2e4e8Sclaudio sa_family_t 525d6c2e4e8Sclaudio aid2af(u_int8_t aid) 526d6c2e4e8Sclaudio { 527d6c2e4e8Sclaudio if (aid < AID_MAX) 528d6c2e4e8Sclaudio return (aid_vals[aid].af); 529d6c2e4e8Sclaudio return (AF_UNSPEC); 530d6c2e4e8Sclaudio } 531d6c2e4e8Sclaudio 532d6c2e4e8Sclaudio int 533d6c2e4e8Sclaudio af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid) 534d6c2e4e8Sclaudio { 535d6c2e4e8Sclaudio u_int8_t i; 536d6c2e4e8Sclaudio 537d6c2e4e8Sclaudio if (safi == 0) /* default to unicast subclass */ 538d6c2e4e8Sclaudio safi = SAFI_UNICAST; 539d6c2e4e8Sclaudio 540d6c2e4e8Sclaudio for (i = 0; i < AID_MAX; i++) 541d6c2e4e8Sclaudio if (aid_vals[i].af == af && aid_vals[i].safi == safi) { 542d6c2e4e8Sclaudio *aid = i; 543d6c2e4e8Sclaudio return (0); 544d6c2e4e8Sclaudio } 545d6c2e4e8Sclaudio 546d6c2e4e8Sclaudio return (-1); 547d6c2e4e8Sclaudio } 548d6c2e4e8Sclaudio 549d6c2e4e8Sclaudio struct sockaddr * 550d6c2e4e8Sclaudio addr2sa(struct bgpd_addr *addr, u_int16_t port) 551d6c2e4e8Sclaudio { 552d6c2e4e8Sclaudio static struct sockaddr_storage ss; 553d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; 554d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; 555d6c2e4e8Sclaudio 556d6c2e4e8Sclaudio if (addr->aid == AID_UNSPEC) 557d6c2e4e8Sclaudio return (NULL); 558d6c2e4e8Sclaudio 559d6c2e4e8Sclaudio bzero(&ss, sizeof(ss)); 560d6c2e4e8Sclaudio switch (addr->aid) { 561d6c2e4e8Sclaudio case AID_INET: 562d6c2e4e8Sclaudio sa_in->sin_family = AF_INET; 563d6c2e4e8Sclaudio sa_in->sin_len = sizeof(struct sockaddr_in); 564d6c2e4e8Sclaudio sa_in->sin_addr.s_addr = addr->v4.s_addr; 565d6c2e4e8Sclaudio sa_in->sin_port = htons(port); 566d6c2e4e8Sclaudio break; 567d6c2e4e8Sclaudio case AID_INET6: 568d6c2e4e8Sclaudio sa_in6->sin6_family = AF_INET6; 569d6c2e4e8Sclaudio sa_in6->sin6_len = sizeof(struct sockaddr_in6); 570d6c2e4e8Sclaudio memcpy(&sa_in6->sin6_addr, &addr->v6, 571d6c2e4e8Sclaudio sizeof(sa_in6->sin6_addr)); 572d6c2e4e8Sclaudio sa_in6->sin6_port = htons(port); 573d6c2e4e8Sclaudio sa_in6->sin6_scope_id = addr->scope_id; 574d6c2e4e8Sclaudio break; 575d6c2e4e8Sclaudio } 576d6c2e4e8Sclaudio 577d6c2e4e8Sclaudio return ((struct sockaddr *)&ss); 578d6c2e4e8Sclaudio } 579d6c2e4e8Sclaudio 580d6c2e4e8Sclaudio void 581d6c2e4e8Sclaudio sa2addr(struct sockaddr *sa, struct bgpd_addr *addr) 582d6c2e4e8Sclaudio { 583d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 584d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 585d6c2e4e8Sclaudio 586d6c2e4e8Sclaudio bzero(addr, sizeof(*addr)); 587d6c2e4e8Sclaudio switch (sa->sa_family) { 588d6c2e4e8Sclaudio case AF_INET: 589d6c2e4e8Sclaudio addr->aid = AID_INET; 590d6c2e4e8Sclaudio memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4)); 591d6c2e4e8Sclaudio break; 592d6c2e4e8Sclaudio case AF_INET6: 593d6c2e4e8Sclaudio addr->aid = AID_INET6; 594d6c2e4e8Sclaudio memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6)); 595d6c2e4e8Sclaudio addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */ 596d6c2e4e8Sclaudio break; 597d6c2e4e8Sclaudio } 598d6c2e4e8Sclaudio } 599