1*f4123069Smbuhl /* $OpenBSD: util.c,v 1.72 2022/11/07 11:33:24 mbuhl 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> 2348bae517Sclaudio #include <endian.h> 2429328a94Sclaudio #include <errno.h> 252ffcd4e0Sclaudio #include <netdb.h> 262ffcd4e0Sclaudio #include <stdlib.h> 272ffcd4e0Sclaudio #include <stdio.h> 282ffcd4e0Sclaudio #include <string.h> 290561b344Sphessler #include <vis.h> 302ffcd4e0Sclaudio 312ffcd4e0Sclaudio #include "bgpd.h" 322ffcd4e0Sclaudio #include "rde.h" 335e3f6f95Sbenno #include "log.h" 342ffcd4e0Sclaudio 3539386878Sclaudio const char *aspath_delim(uint8_t, int); 361e590dcfSclaudio 372ffcd4e0Sclaudio const char * 382ffcd4e0Sclaudio log_addr(const struct bgpd_addr *addr) 392ffcd4e0Sclaudio { 40290f96faSdenis static char buf[74]; 4145350f87Sclaudio struct sockaddr *sa; 425624d029Sclaudio socklen_t len; 432ffcd4e0Sclaudio 4445350f87Sclaudio sa = addr2sa(addr, 0, &len); 4515d8de66Sclaudio switch (addr->aid) { 4615d8de66Sclaudio case AID_INET: 4715d8de66Sclaudio case AID_INET6: 4845350f87Sclaudio return log_sockaddr(sa, len); 4915d8de66Sclaudio case AID_VPN_IPv4: 50290f96faSdenis case AID_VPN_IPv6: 513038d3d1Sclaudio snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->rd), 5245350f87Sclaudio log_sockaddr(sa, len)); 53290f96faSdenis return (buf); 5415d8de66Sclaudio } 5515d8de66Sclaudio return ("???"); 562ffcd4e0Sclaudio } 572ffcd4e0Sclaudio 582ffcd4e0Sclaudio const char * 592ffcd4e0Sclaudio log_in6addr(const struct in6_addr *addr) 602ffcd4e0Sclaudio { 612ffcd4e0Sclaudio struct sockaddr_in6 sa_in6; 622ffcd4e0Sclaudio 63eafe309eSclaudio memset(&sa_in6, 0, sizeof(sa_in6)); 642ffcd4e0Sclaudio sa_in6.sin6_family = AF_INET6; 652ffcd4e0Sclaudio memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr)); 662ffcd4e0Sclaudio 67be6ced5eSclaudio #ifdef __KAME__ 682ffcd4e0Sclaudio /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */ 69bdec2ffaStb if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) || 70bdec2ffaStb IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr) || 714ff2dba3Sclaudio IN6_IS_ADDR_MC_NODELOCAL(&sa_in6.sin6_addr)) && 72bdec2ffaStb sa_in6.sin6_scope_id == 0) { 7339386878Sclaudio uint16_t tmp16; 742ffcd4e0Sclaudio memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16)); 752ffcd4e0Sclaudio sa_in6.sin6_scope_id = ntohs(tmp16); 762ffcd4e0Sclaudio sa_in6.sin6_addr.s6_addr[2] = 0; 772ffcd4e0Sclaudio sa_in6.sin6_addr.s6_addr[3] = 0; 782ffcd4e0Sclaudio } 79be6ced5eSclaudio #endif 802ffcd4e0Sclaudio 81255fe563Sclaudio return (log_sockaddr((struct sockaddr *)&sa_in6, sizeof(sa_in6))); 822ffcd4e0Sclaudio } 832ffcd4e0Sclaudio 842ffcd4e0Sclaudio const char * 85255fe563Sclaudio log_sockaddr(struct sockaddr *sa, socklen_t len) 862ffcd4e0Sclaudio { 872ffcd4e0Sclaudio static char buf[NI_MAXHOST]; 882ffcd4e0Sclaudio 8945350f87Sclaudio if (sa == NULL || getnameinfo(sa, len, buf, sizeof(buf), NULL, 0, 902ffcd4e0Sclaudio NI_NUMERICHOST)) 912ffcd4e0Sclaudio return ("(unknown)"); 922ffcd4e0Sclaudio else 932ffcd4e0Sclaudio return (buf); 942ffcd4e0Sclaudio } 952ffcd4e0Sclaudio 960c88bf70Sclaudio const char * 9739386878Sclaudio log_as(uint32_t as) 980c88bf70Sclaudio { 9906bcde9cSphessler static char buf[11]; /* "4294967294\0" */ 1000c88bf70Sclaudio 101515e489cSderaadt if (snprintf(buf, sizeof(buf), "%u", as) < 0) 1020c88bf70Sclaudio return ("?"); 10306bcde9cSphessler 1040c88bf70Sclaudio return (buf); 1050c88bf70Sclaudio } 1060c88bf70Sclaudio 107256b680eSclaudio const char * 10839386878Sclaudio log_rd(uint64_t rd) 109256b680eSclaudio { 110256b680eSclaudio static char buf[32]; 111256b680eSclaudio struct in_addr addr; 11239386878Sclaudio uint32_t u32; 11339386878Sclaudio uint16_t u16; 114256b680eSclaudio 115f4c0eb52Sclaudio rd = be64toh(rd); 116256b680eSclaudio switch (rd >> 48) { 117bf8e2920Sclaudio case EXT_COMMUNITY_TRANS_TWO_AS: 118256b680eSclaudio u32 = rd & 0xffffffff; 119256b680eSclaudio u16 = (rd >> 32) & 0xffff; 12032ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32); 121256b680eSclaudio break; 122bf8e2920Sclaudio case EXT_COMMUNITY_TRANS_FOUR_AS: 123256b680eSclaudio u32 = (rd >> 16) & 0xffffffff; 124256b680eSclaudio u16 = rd & 0xffff; 12532ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16); 126256b680eSclaudio break; 127bf8e2920Sclaudio case EXT_COMMUNITY_TRANS_IPV4: 128256b680eSclaudio u32 = (rd >> 16) & 0xffffffff; 129256b680eSclaudio u16 = rd & 0xffff; 130256b680eSclaudio addr.s_addr = htonl(u32); 13132ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16); 132256b680eSclaudio break; 133256b680eSclaudio default: 134256b680eSclaudio return ("rd ?"); 135256b680eSclaudio } 136256b680eSclaudio return (buf); 137256b680eSclaudio } 138256b680eSclaudio 139bf8e2920Sclaudio const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES; 140bf8e2920Sclaudio 141256b680eSclaudio /* NOTE: this function does not check if the type/subtype combo is 142536f41e5Sclaudio * actually valid. */ 143536f41e5Sclaudio const char * 144f8162053Sclaudio log_ext_subtype(int type, uint8_t subtype) 145536f41e5Sclaudio { 146536f41e5Sclaudio static char etype[6]; 147bf8e2920Sclaudio const struct ext_comm_pairs *cp; 148536f41e5Sclaudio 149bf8e2920Sclaudio for (cp = iana_ext_comms; cp->subname != NULL; cp++) { 1500e6216fdSclaudio if ((type == cp->type || type == -1) && subtype == cp->subtype) 151bf8e2920Sclaudio return (cp->subname); 152bf8e2920Sclaudio } 153d6340f7aSderaadt snprintf(etype, sizeof(etype), "[%u]", subtype); 154536f41e5Sclaudio return (etype); 155536f41e5Sclaudio } 156536f41e5Sclaudio 1571e590dcfSclaudio const char * 158a78f83ceSderaadt log_reason(const char *communication) { 159a78f83ceSderaadt static char buf[(REASON_LEN - 1) * 4 + 1]; 1600561b344Sphessler 1610561b344Sphessler strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL); 1620561b344Sphessler 1630561b344Sphessler return buf; 1640561b344Sphessler } 1650561b344Sphessler 1660561b344Sphessler const char * 167bd9df44eSclaudio log_rtr_error(enum rtr_error err) 168bd9df44eSclaudio { 169bd9df44eSclaudio static char buf[20]; 170bd9df44eSclaudio 171bd9df44eSclaudio switch (err) { 172bd9df44eSclaudio case NO_ERROR: 173bd9df44eSclaudio return "No Error"; 174bd9df44eSclaudio case CORRUPT_DATA: 175bd9df44eSclaudio return "Corrupt Data"; 176bd9df44eSclaudio case INTERNAL_ERROR: 177bd9df44eSclaudio return "Internal Error"; 178bd9df44eSclaudio case NO_DATA_AVAILABLE: 179bd9df44eSclaudio return "No Data Available"; 180bd9df44eSclaudio case INVALID_REQUEST: 181bd9df44eSclaudio return "Invalid Request"; 182bd9df44eSclaudio case UNSUPP_PROTOCOL_VERS: 183bd9df44eSclaudio return "Unsupported Protocol Version"; 184bd9df44eSclaudio case UNSUPP_PDU_TYPE: 185bd9df44eSclaudio return "Unsupported PDU Type"; 186bd9df44eSclaudio case UNK_REC_WDRAWL: 187*f4123069Smbuhl return "Withdrawal of Unknown Record"; 188bd9df44eSclaudio case DUP_REC_RECV: 189bd9df44eSclaudio return "Duplicate Announcement Received"; 190bd9df44eSclaudio case UNEXP_PROTOCOL_VERS: 191bd9df44eSclaudio return "Unexpected Protocol Version"; 192bd9df44eSclaudio default: 193bd9df44eSclaudio snprintf(buf, sizeof(buf), "unknown %u", err); 194bd9df44eSclaudio return buf; 195bd9df44eSclaudio } 196bd9df44eSclaudio } 197bd9df44eSclaudio 198bd9df44eSclaudio const char * 199202e5273Stb log_policy(uint8_t role) 200202e5273Stb { 201202e5273Stb switch (role) { 202202e5273Stb case CAPA_ROLE_PROVIDER: 203202e5273Stb return "provider"; 204202e5273Stb case CAPA_ROLE_RS: 205202e5273Stb return "rs"; 206202e5273Stb case CAPA_ROLE_RS_CLIENT: 207202e5273Stb return "rs-client"; 208202e5273Stb case CAPA_ROLE_CUSTOMER: 209202e5273Stb return "customer"; 210202e5273Stb case CAPA_ROLE_PEER: 211202e5273Stb return "peer"; 212202e5273Stb default: 213202e5273Stb return "unknown"; 214202e5273Stb } 215202e5273Stb } 216202e5273Stb 217202e5273Stb const char * 21839386878Sclaudio aspath_delim(uint8_t seg_type, int closing) 2191e590dcfSclaudio { 2201e590dcfSclaudio static char db[8]; 2211e590dcfSclaudio 2221e590dcfSclaudio switch (seg_type) { 2231e590dcfSclaudio case AS_SET: 2241e590dcfSclaudio if (!closing) 2251e590dcfSclaudio return ("{ "); 2261e590dcfSclaudio else 2271e590dcfSclaudio return (" }"); 2281e590dcfSclaudio case AS_SEQUENCE: 2291e590dcfSclaudio return (""); 2301e590dcfSclaudio case AS_CONFED_SEQUENCE: 2311e590dcfSclaudio if (!closing) 2321e590dcfSclaudio return ("( "); 2331e590dcfSclaudio else 2341e590dcfSclaudio return (" )"); 2351e590dcfSclaudio case AS_CONFED_SET: 2361e590dcfSclaudio if (!closing) 2371e590dcfSclaudio return ("[ "); 2381e590dcfSclaudio else 2391e590dcfSclaudio return (" ]"); 2401e590dcfSclaudio default: 2411e590dcfSclaudio if (!closing) 2421e590dcfSclaudio snprintf(db, sizeof(db), "!%u ", seg_type); 2431e590dcfSclaudio else 2441e590dcfSclaudio snprintf(db, sizeof(db), " !%u", seg_type); 2451e590dcfSclaudio return (db); 2461e590dcfSclaudio } 2471e590dcfSclaudio } 2481e590dcfSclaudio 2492ffcd4e0Sclaudio int 25039386878Sclaudio aspath_snprint(char *buf, size_t size, void *data, uint16_t len) 2512ffcd4e0Sclaudio { 2522ffcd4e0Sclaudio #define UPDATE() \ 2532ffcd4e0Sclaudio do { \ 254515e489cSderaadt if (r < 0) \ 2552ffcd4e0Sclaudio return (-1); \ 2562ffcd4e0Sclaudio total_size += r; \ 2572ffcd4e0Sclaudio if ((unsigned int)r < size) { \ 2582ffcd4e0Sclaudio size -= r; \ 2592ffcd4e0Sclaudio buf += r; \ 2602ffcd4e0Sclaudio } else { \ 2612ffcd4e0Sclaudio buf += size; \ 2622ffcd4e0Sclaudio size = 0; \ 2632ffcd4e0Sclaudio } \ 2642ffcd4e0Sclaudio } while (0) 26539386878Sclaudio uint8_t *seg; 2662ffcd4e0Sclaudio int r, total_size; 26739386878Sclaudio uint16_t seg_size; 26839386878Sclaudio uint8_t i, seg_type, seg_len; 2692ffcd4e0Sclaudio 2702ffcd4e0Sclaudio total_size = 0; 2712ffcd4e0Sclaudio seg = data; 2722ffcd4e0Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 2732ffcd4e0Sclaudio seg_type = seg[0]; 2742ffcd4e0Sclaudio seg_len = seg[1]; 27539386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 2762ffcd4e0Sclaudio 2771e590dcfSclaudio r = snprintf(buf, size, "%s%s", 2781e590dcfSclaudio total_size != 0 ? " " : "", 2791e590dcfSclaudio aspath_delim(seg_type, 0)); 2802ffcd4e0Sclaudio UPDATE(); 2812ffcd4e0Sclaudio 2822ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) { 2830c88bf70Sclaudio r = snprintf(buf, size, "%s", 2840c88bf70Sclaudio log_as(aspath_extract(seg, i))); 2852ffcd4e0Sclaudio UPDATE(); 2862ffcd4e0Sclaudio if (i + 1 < seg_len) { 2872ffcd4e0Sclaudio r = snprintf(buf, size, " "); 2882ffcd4e0Sclaudio UPDATE(); 2892ffcd4e0Sclaudio } 2902ffcd4e0Sclaudio } 2911e590dcfSclaudio r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1)); 2922ffcd4e0Sclaudio UPDATE(); 2932ffcd4e0Sclaudio } 29455e49665Sclaudio /* ensure that we have a valid C-string especially for empty as path */ 2952ffcd4e0Sclaudio if (size > 0) 2962ffcd4e0Sclaudio *buf = '\0'; 2972ffcd4e0Sclaudio 2982ffcd4e0Sclaudio return (total_size); 2992ffcd4e0Sclaudio #undef UPDATE 3002ffcd4e0Sclaudio } 3012ffcd4e0Sclaudio 3022ffcd4e0Sclaudio int 30339386878Sclaudio aspath_asprint(char **ret, void *data, uint16_t len) 3042ffcd4e0Sclaudio { 3052ffcd4e0Sclaudio size_t slen; 3062ffcd4e0Sclaudio int plen; 3072ffcd4e0Sclaudio 3082ffcd4e0Sclaudio slen = aspath_strlen(data, len) + 1; 3092ffcd4e0Sclaudio *ret = malloc(slen); 3102ffcd4e0Sclaudio if (*ret == NULL) 3112ffcd4e0Sclaudio return (-1); 3122ffcd4e0Sclaudio 3132ffcd4e0Sclaudio plen = aspath_snprint(*ret, slen, data, len); 3142ffcd4e0Sclaudio if (plen == -1) { 3152ffcd4e0Sclaudio free(*ret); 3162ffcd4e0Sclaudio *ret = NULL; 3172ffcd4e0Sclaudio return (-1); 3182ffcd4e0Sclaudio } 3192ffcd4e0Sclaudio 3202ffcd4e0Sclaudio return (0); 3212ffcd4e0Sclaudio } 3222ffcd4e0Sclaudio 3232ffcd4e0Sclaudio size_t 32439386878Sclaudio aspath_strlen(void *data, uint16_t len) 3252ffcd4e0Sclaudio { 32639386878Sclaudio uint8_t *seg; 3272ffcd4e0Sclaudio int total_size; 32839386878Sclaudio uint32_t as; 32939386878Sclaudio uint16_t seg_size; 33039386878Sclaudio uint8_t i, seg_type, seg_len; 3312ffcd4e0Sclaudio 3322ffcd4e0Sclaudio total_size = 0; 3332ffcd4e0Sclaudio seg = data; 3342ffcd4e0Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 3352ffcd4e0Sclaudio seg_type = seg[0]; 3362ffcd4e0Sclaudio seg_len = seg[1]; 33739386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 3382ffcd4e0Sclaudio 3392ffcd4e0Sclaudio if (seg_type == AS_SET) 3402ffcd4e0Sclaudio if (total_size != 0) 3412ffcd4e0Sclaudio total_size += 3; 3422ffcd4e0Sclaudio else 3432ffcd4e0Sclaudio total_size += 2; 3442ffcd4e0Sclaudio else if (total_size != 0) 3452ffcd4e0Sclaudio total_size += 1; 3462ffcd4e0Sclaudio 3472ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) { 3482ffcd4e0Sclaudio as = aspath_extract(seg, i); 3490c88bf70Sclaudio 3508db4f5d2Sclaudio do { 3518db4f5d2Sclaudio total_size++; 3528db4f5d2Sclaudio } while ((as = as / 10) != 0); 3532ffcd4e0Sclaudio 3542ffcd4e0Sclaudio if (i + 1 < seg_len) 3552ffcd4e0Sclaudio total_size += 1; 3562ffcd4e0Sclaudio } 3572ffcd4e0Sclaudio 3582ffcd4e0Sclaudio if (seg_type == AS_SET) 3592ffcd4e0Sclaudio total_size += 2; 3602ffcd4e0Sclaudio } 3612ffcd4e0Sclaudio return (total_size); 3622ffcd4e0Sclaudio } 3632ffcd4e0Sclaudio 3642ffcd4e0Sclaudio /* 3652ffcd4e0Sclaudio * Extract the asnum out of the as segment at the specified position. 3662ffcd4e0Sclaudio * Direct access is not possible because of non-aligned reads. 367506f72cfSclaudio * Only works on verified 4-byte AS paths. 3682ffcd4e0Sclaudio */ 36939386878Sclaudio uint32_t 3702ffcd4e0Sclaudio aspath_extract(const void *seg, int pos) 3712ffcd4e0Sclaudio { 3722ffcd4e0Sclaudio const u_char *ptr = seg; 37339386878Sclaudio uint32_t as; 3742ffcd4e0Sclaudio 375506f72cfSclaudio /* minimal pos check, return 0 since that is an invalid ASN */ 376506f72cfSclaudio if (pos < 0 || pos >= ptr[1]) 377506f72cfSclaudio return (0); 37839386878Sclaudio ptr += 2 + sizeof(uint32_t) * pos; 37939386878Sclaudio memcpy(&as, ptr, sizeof(uint32_t)); 3800c88bf70Sclaudio return (ntohl(as)); 3812ffcd4e0Sclaudio } 38221a825c9Sclaudio 383de5c2eedSclaudio /* 38429328a94Sclaudio * Verify that the aspath is correctly encoded. 38529328a94Sclaudio */ 38629328a94Sclaudio int 38739386878Sclaudio aspath_verify(void *data, uint16_t len, int as4byte, int noset) 38829328a94Sclaudio { 38939386878Sclaudio uint8_t *seg = data; 39039386878Sclaudio uint16_t seg_size, as_size = 2; 39139386878Sclaudio uint8_t seg_len, seg_type; 39229328a94Sclaudio int error = 0; 39329328a94Sclaudio 39429328a94Sclaudio if (len & 1) 39529328a94Sclaudio /* odd length aspath are invalid */ 39629328a94Sclaudio return (AS_ERR_BAD); 39729328a94Sclaudio 39829328a94Sclaudio if (as4byte) 39929328a94Sclaudio as_size = 4; 40029328a94Sclaudio 40129328a94Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 40239386878Sclaudio const uint8_t *ptr; 40329328a94Sclaudio int pos; 40429328a94Sclaudio 40529328a94Sclaudio if (len < 2) /* header length check */ 40629328a94Sclaudio return (AS_ERR_BAD); 40729328a94Sclaudio seg_type = seg[0]; 40829328a94Sclaudio seg_len = seg[1]; 40929328a94Sclaudio 410d04df938Sclaudio if (seg_len == 0) 411d04df938Sclaudio /* empty aspath segments are not allowed */ 412d04df938Sclaudio return (AS_ERR_BAD); 413d04df938Sclaudio 41429328a94Sclaudio /* 41529328a94Sclaudio * BGP confederations should not show up but consider them 41629328a94Sclaudio * as a soft error which invalidates the path but keeps the 41729328a94Sclaudio * bgp session running. 41829328a94Sclaudio */ 41929328a94Sclaudio if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET) 42029328a94Sclaudio error = AS_ERR_SOFT; 421aa528464Sclaudio /* 422aa528464Sclaudio * If AS_SET filtering (RFC6472) is on, error out on AS_SET 423aa528464Sclaudio * as well. 424aa528464Sclaudio */ 425aa528464Sclaudio if (noset && seg_type == AS_SET) 426aa528464Sclaudio error = AS_ERR_SOFT; 42729328a94Sclaudio if (seg_type != AS_SET && seg_type != AS_SEQUENCE && 42829328a94Sclaudio seg_type != AS_CONFED_SEQUENCE && seg_type != AS_CONFED_SET) 42929328a94Sclaudio return (AS_ERR_TYPE); 43029328a94Sclaudio 43129328a94Sclaudio seg_size = 2 + as_size * seg_len; 43229328a94Sclaudio 43329328a94Sclaudio if (seg_size > len) 43429328a94Sclaudio return (AS_ERR_LEN); 43529328a94Sclaudio 43629328a94Sclaudio /* RFC 7607 - AS 0 is considered malformed */ 43729328a94Sclaudio ptr = seg + 2; 43829328a94Sclaudio for (pos = 0; pos < seg_len; pos++) { 43939386878Sclaudio uint32_t as; 44029328a94Sclaudio 44129328a94Sclaudio memcpy(&as, ptr, as_size); 44229328a94Sclaudio if (as == 0) 44356a9a1b8Sclaudio error = AS_ERR_SOFT; 44451491708Sclaudio ptr += as_size; 44529328a94Sclaudio } 44629328a94Sclaudio } 44729328a94Sclaudio return (error); /* aspath is valid but probably not loop free */ 44829328a94Sclaudio } 44929328a94Sclaudio 45029328a94Sclaudio /* 45129328a94Sclaudio * convert a 2 byte aspath to a 4 byte one. 45229328a94Sclaudio */ 45329328a94Sclaudio u_char * 45439386878Sclaudio aspath_inflate(void *data, uint16_t len, uint16_t *newlen) 45529328a94Sclaudio { 45639386878Sclaudio uint8_t *seg, *nseg, *ndata; 45739386878Sclaudio uint16_t seg_size, olen, nlen; 45839386878Sclaudio uint8_t seg_len; 45929328a94Sclaudio 46029328a94Sclaudio /* first calculate the length of the aspath */ 46129328a94Sclaudio seg = data; 46229328a94Sclaudio nlen = 0; 46329328a94Sclaudio for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) { 46429328a94Sclaudio seg_len = seg[1]; 46539386878Sclaudio seg_size = 2 + sizeof(uint16_t) * seg_len; 46639386878Sclaudio nlen += 2 + sizeof(uint32_t) * seg_len; 46729328a94Sclaudio 46829328a94Sclaudio if (seg_size > olen) { 46929328a94Sclaudio errno = ERANGE; 47029328a94Sclaudio return (NULL); 47129328a94Sclaudio } 47229328a94Sclaudio } 47329328a94Sclaudio 47429328a94Sclaudio *newlen = nlen; 47529328a94Sclaudio if ((ndata = malloc(nlen)) == NULL) 47629328a94Sclaudio return (NULL); 47729328a94Sclaudio 47829328a94Sclaudio /* then copy the aspath */ 47929328a94Sclaudio seg = data; 48029328a94Sclaudio for (nseg = ndata; nseg < ndata + nlen; ) { 48129328a94Sclaudio *nseg++ = *seg++; 48229328a94Sclaudio *nseg++ = seg_len = *seg++; 48329328a94Sclaudio for (; seg_len > 0; seg_len--) { 48429328a94Sclaudio *nseg++ = 0; 48529328a94Sclaudio *nseg++ = 0; 48629328a94Sclaudio *nseg++ = *seg++; 48729328a94Sclaudio *nseg++ = *seg++; 48829328a94Sclaudio } 48929328a94Sclaudio } 49029328a94Sclaudio 49129328a94Sclaudio return (ndata); 49229328a94Sclaudio } 49329328a94Sclaudio 4946d3e8673Sclaudio /* NLRI functions to extract prefixes from the NLRI blobs */ 4956d3e8673Sclaudio static int 49639386878Sclaudio extract_prefix(u_char *p, uint16_t len, void *va, 49739386878Sclaudio uint8_t pfxlen, uint8_t max) 4986d3e8673Sclaudio { 4996d3e8673Sclaudio static u_char addrmask[] = { 5006d3e8673Sclaudio 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 5016d3e8673Sclaudio u_char *a = va; 5026d3e8673Sclaudio int i; 50339386878Sclaudio uint16_t plen = 0; 5046d3e8673Sclaudio 5056d3e8673Sclaudio for (i = 0; pfxlen && i < max; i++) { 5066d3e8673Sclaudio if (len <= plen) 5076d3e8673Sclaudio return (-1); 5086d3e8673Sclaudio if (pfxlen < 8) { 5096d3e8673Sclaudio a[i] = *p++ & addrmask[pfxlen]; 5106d3e8673Sclaudio plen++; 5116d3e8673Sclaudio break; 5126d3e8673Sclaudio } else { 5136d3e8673Sclaudio a[i] = *p++; 5146d3e8673Sclaudio plen++; 5156d3e8673Sclaudio pfxlen -= 8; 5166d3e8673Sclaudio } 5176d3e8673Sclaudio } 5186d3e8673Sclaudio return (plen); 5196d3e8673Sclaudio } 5206d3e8673Sclaudio 5216d3e8673Sclaudio int 52239386878Sclaudio nlri_get_prefix(u_char *p, uint16_t len, struct bgpd_addr *prefix, 52339386878Sclaudio uint8_t *prefixlen) 5246d3e8673Sclaudio { 5256d3e8673Sclaudio int plen; 52639386878Sclaudio uint8_t pfxlen; 5276d3e8673Sclaudio 5286d3e8673Sclaudio if (len < 1) 5296d3e8673Sclaudio return (-1); 5306d3e8673Sclaudio 5316d3e8673Sclaudio pfxlen = *p++; 5326d3e8673Sclaudio len--; 5336d3e8673Sclaudio 534eafe309eSclaudio memset(prefix, 0, sizeof(struct bgpd_addr)); 5356d3e8673Sclaudio prefix->aid = AID_INET; 5366d3e8673Sclaudio *prefixlen = pfxlen; 5376d3e8673Sclaudio 5386d3e8673Sclaudio if (pfxlen > 32) 5396d3e8673Sclaudio return (-1); 5406d3e8673Sclaudio if ((plen = extract_prefix(p, len, &prefix->v4, pfxlen, 5416d3e8673Sclaudio sizeof(prefix->v4))) == -1) 5426d3e8673Sclaudio return (-1); 5436d3e8673Sclaudio 5446d3e8673Sclaudio return (plen + 1); /* pfxlen needs to be added */ 5456d3e8673Sclaudio } 5466d3e8673Sclaudio 5476d3e8673Sclaudio int 54839386878Sclaudio nlri_get_prefix6(u_char *p, uint16_t len, struct bgpd_addr *prefix, 54939386878Sclaudio uint8_t *prefixlen) 5506d3e8673Sclaudio { 5516d3e8673Sclaudio int plen; 55239386878Sclaudio uint8_t pfxlen; 5536d3e8673Sclaudio 5546d3e8673Sclaudio if (len < 1) 5556d3e8673Sclaudio return (-1); 5566d3e8673Sclaudio 5576d3e8673Sclaudio pfxlen = *p++; 5586d3e8673Sclaudio len--; 5596d3e8673Sclaudio 560eafe309eSclaudio memset(prefix, 0, sizeof(struct bgpd_addr)); 5616d3e8673Sclaudio prefix->aid = AID_INET6; 5626d3e8673Sclaudio *prefixlen = pfxlen; 5636d3e8673Sclaudio 5646d3e8673Sclaudio if (pfxlen > 128) 5656d3e8673Sclaudio return (-1); 5666d3e8673Sclaudio if ((plen = extract_prefix(p, len, &prefix->v6, pfxlen, 5676d3e8673Sclaudio sizeof(prefix->v6))) == -1) 5686d3e8673Sclaudio return (-1); 5696d3e8673Sclaudio 5706d3e8673Sclaudio return (plen + 1); /* pfxlen needs to be added */ 5716d3e8673Sclaudio } 5726d3e8673Sclaudio 5736d3e8673Sclaudio int 57439386878Sclaudio nlri_get_vpn4(u_char *p, uint16_t len, struct bgpd_addr *prefix, 57539386878Sclaudio uint8_t *prefixlen, int withdraw) 5766d3e8673Sclaudio { 5776d3e8673Sclaudio int rv, done = 0; 57839386878Sclaudio uint16_t plen; 57939386878Sclaudio uint8_t pfxlen; 5806d3e8673Sclaudio 5816d3e8673Sclaudio if (len < 1) 5826d3e8673Sclaudio return (-1); 5836d3e8673Sclaudio 5846d3e8673Sclaudio memcpy(&pfxlen, p, 1); 5856d3e8673Sclaudio p += 1; 5866d3e8673Sclaudio plen = 1; 5876d3e8673Sclaudio 588eafe309eSclaudio memset(prefix, 0, sizeof(struct bgpd_addr)); 5896d3e8673Sclaudio 5906d3e8673Sclaudio /* label stack */ 5916d3e8673Sclaudio do { 5926d3e8673Sclaudio if (len - plen < 3 || pfxlen < 3 * 8) 5936d3e8673Sclaudio return (-1); 5943038d3d1Sclaudio if (prefix->labellen + 3U > 5953038d3d1Sclaudio sizeof(prefix->labelstack)) 5966d3e8673Sclaudio return (-1); 5976d3e8673Sclaudio if (withdraw) { 5986d3e8673Sclaudio /* on withdraw ignore the labelstack all together */ 5996d3e8673Sclaudio plen += 3; 6006d3e8673Sclaudio pfxlen -= 3 * 8; 6016d3e8673Sclaudio break; 6026d3e8673Sclaudio } 6033038d3d1Sclaudio prefix->labelstack[prefix->labellen++] = *p++; 6043038d3d1Sclaudio prefix->labelstack[prefix->labellen++] = *p++; 6053038d3d1Sclaudio prefix->labelstack[prefix->labellen] = *p++; 6063038d3d1Sclaudio if (prefix->labelstack[prefix->labellen] & 6076d3e8673Sclaudio BGP_MPLS_BOS) 6086d3e8673Sclaudio done = 1; 6093038d3d1Sclaudio prefix->labellen++; 6106d3e8673Sclaudio plen += 3; 6116d3e8673Sclaudio pfxlen -= 3 * 8; 6126d3e8673Sclaudio } while (!done); 6136d3e8673Sclaudio 6146d3e8673Sclaudio /* RD */ 61539386878Sclaudio if (len - plen < (int)sizeof(uint64_t) || 61639386878Sclaudio pfxlen < sizeof(uint64_t) * 8) 6176d3e8673Sclaudio return (-1); 61839386878Sclaudio memcpy(&prefix->rd, p, sizeof(uint64_t)); 61939386878Sclaudio pfxlen -= sizeof(uint64_t) * 8; 62039386878Sclaudio p += sizeof(uint64_t); 62139386878Sclaudio plen += sizeof(uint64_t); 6226d3e8673Sclaudio 6236d3e8673Sclaudio /* prefix */ 6246d3e8673Sclaudio prefix->aid = AID_VPN_IPv4; 6256d3e8673Sclaudio *prefixlen = pfxlen; 6266d3e8673Sclaudio 6276d3e8673Sclaudio if (pfxlen > 32) 6286d3e8673Sclaudio return (-1); 6293038d3d1Sclaudio if ((rv = extract_prefix(p, len, &prefix->v4, 6303038d3d1Sclaudio pfxlen, sizeof(prefix->v4))) == -1) 6316d3e8673Sclaudio return (-1); 6326d3e8673Sclaudio 6336d3e8673Sclaudio return (plen + rv); 6346d3e8673Sclaudio } 6356d3e8673Sclaudio 636290f96faSdenis int 63739386878Sclaudio nlri_get_vpn6(u_char *p, uint16_t len, struct bgpd_addr *prefix, 63839386878Sclaudio uint8_t *prefixlen, int withdraw) 639290f96faSdenis { 640290f96faSdenis int rv, done = 0; 64139386878Sclaudio uint16_t plen; 64239386878Sclaudio uint8_t pfxlen; 643290f96faSdenis 644290f96faSdenis if (len < 1) 645290f96faSdenis return (-1); 646290f96faSdenis 647290f96faSdenis memcpy(&pfxlen, p, 1); 648290f96faSdenis p += 1; 649290f96faSdenis plen = 1; 650290f96faSdenis 651290f96faSdenis memset(prefix, 0, sizeof(struct bgpd_addr)); 652290f96faSdenis 653290f96faSdenis /* label stack */ 654290f96faSdenis do { 655290f96faSdenis if (len - plen < 3 || pfxlen < 3 * 8) 656290f96faSdenis return (-1); 6573038d3d1Sclaudio if (prefix->labellen + 3U > 6583038d3d1Sclaudio sizeof(prefix->labelstack)) 659290f96faSdenis return (-1); 660290f96faSdenis if (withdraw) { 661290f96faSdenis /* on withdraw ignore the labelstack all together */ 662290f96faSdenis plen += 3; 663290f96faSdenis pfxlen -= 3 * 8; 664290f96faSdenis break; 665290f96faSdenis } 666290f96faSdenis 6673038d3d1Sclaudio prefix->labelstack[prefix->labellen++] = *p++; 6683038d3d1Sclaudio prefix->labelstack[prefix->labellen++] = *p++; 6693038d3d1Sclaudio prefix->labelstack[prefix->labellen] = *p++; 6703038d3d1Sclaudio if (prefix->labelstack[prefix->labellen] & 671290f96faSdenis BGP_MPLS_BOS) 672290f96faSdenis done = 1; 6733038d3d1Sclaudio prefix->labellen++; 674290f96faSdenis plen += 3; 675290f96faSdenis pfxlen -= 3 * 8; 676290f96faSdenis } while (!done); 677290f96faSdenis 678290f96faSdenis /* RD */ 67939386878Sclaudio if (len - plen < (int)sizeof(uint64_t) || 68039386878Sclaudio pfxlen < sizeof(uint64_t) * 8) 681290f96faSdenis return (-1); 682290f96faSdenis 68339386878Sclaudio memcpy(&prefix->rd, p, sizeof(uint64_t)); 68439386878Sclaudio pfxlen -= sizeof(uint64_t) * 8; 68539386878Sclaudio p += sizeof(uint64_t); 68639386878Sclaudio plen += sizeof(uint64_t); 687290f96faSdenis 688290f96faSdenis /* prefix */ 689290f96faSdenis prefix->aid = AID_VPN_IPv6; 690290f96faSdenis *prefixlen = pfxlen; 691290f96faSdenis 692290f96faSdenis if (pfxlen > 128) 693290f96faSdenis return (-1); 694290f96faSdenis 6953038d3d1Sclaudio if ((rv = extract_prefix(p, len, &prefix->v6, 6963038d3d1Sclaudio pfxlen, sizeof(prefix->v6))) == -1) 697290f96faSdenis return (-1); 698290f96faSdenis 699290f96faSdenis return (plen + rv); 700290f96faSdenis } 701290f96faSdenis 702fa3a38bbSclaudio static in_addr_t 703fa3a38bbSclaudio prefixlen2mask(uint8_t prefixlen) 704fa3a38bbSclaudio { 705fa3a38bbSclaudio if (prefixlen == 0) 706fa3a38bbSclaudio return (0); 707290f96faSdenis 708fa3a38bbSclaudio return (0xffffffff << (32 - prefixlen)); 709fa3a38bbSclaudio } 710290f96faSdenis 71129328a94Sclaudio /* 712de5c2eedSclaudio * This function will have undefined behaviour if the passed in prefixlen is 713290f96faSdenis * too large for the respective bgpd_addr address family. 714de5c2eedSclaudio */ 715fafbb788Sclaudio int 716fafbb788Sclaudio prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, 717fafbb788Sclaudio int prefixlen) 718fafbb788Sclaudio { 719fafbb788Sclaudio in_addr_t mask, aa, ba; 720fafbb788Sclaudio int i; 72139386878Sclaudio uint8_t m; 722fafbb788Sclaudio 723fafbb788Sclaudio if (a->aid != b->aid) 724fafbb788Sclaudio return (a->aid - b->aid); 725fafbb788Sclaudio 726fafbb788Sclaudio switch (a->aid) { 7273038d3d1Sclaudio case AID_VPN_IPv4: 7283038d3d1Sclaudio if (be64toh(a->rd) > be64toh(b->rd)) 7293038d3d1Sclaudio return (1); 7303038d3d1Sclaudio if (be64toh(a->rd) < be64toh(b->rd)) 7313038d3d1Sclaudio return (-1); 7323038d3d1Sclaudio /* FALLTHROUGH */ 733fafbb788Sclaudio case AID_INET: 7347da59fecSclaudio if (prefixlen == 0) 7357da59fecSclaudio return (0); 736fafbb788Sclaudio if (prefixlen > 32) 737de5c2eedSclaudio return (-1); 738fafbb788Sclaudio mask = htonl(prefixlen2mask(prefixlen)); 739fafbb788Sclaudio aa = ntohl(a->v4.s_addr & mask); 740fafbb788Sclaudio ba = ntohl(b->v4.s_addr & mask); 7413038d3d1Sclaudio if (aa > ba) 7423038d3d1Sclaudio return (1); 7433038d3d1Sclaudio if (aa < ba) 7443038d3d1Sclaudio return (-1); 7453038d3d1Sclaudio break; 7463038d3d1Sclaudio case AID_VPN_IPv6: 7473038d3d1Sclaudio if (be64toh(a->rd) > be64toh(b->rd)) 7483038d3d1Sclaudio return (1); 7493038d3d1Sclaudio if (be64toh(a->rd) < be64toh(b->rd)) 7503038d3d1Sclaudio return (-1); 7513038d3d1Sclaudio /* FALLTHROUGH */ 752fafbb788Sclaudio case AID_INET6: 7537da59fecSclaudio if (prefixlen == 0) 7547da59fecSclaudio return (0); 755fafbb788Sclaudio if (prefixlen > 128) 756de5c2eedSclaudio return (-1); 757fafbb788Sclaudio for (i = 0; i < prefixlen / 8; i++) 758fafbb788Sclaudio if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 759fafbb788Sclaudio return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 760fafbb788Sclaudio i = prefixlen % 8; 761fafbb788Sclaudio if (i) { 762fafbb788Sclaudio m = 0xff00 >> i; 763fafbb788Sclaudio if ((a->v6.s6_addr[prefixlen / 8] & m) != 764fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m)) 765fafbb788Sclaudio return ((a->v6.s6_addr[prefixlen / 8] & m) - 766fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m)); 767fafbb788Sclaudio } 7683038d3d1Sclaudio break; 7693038d3d1Sclaudio default: 7703038d3d1Sclaudio return (-1); 7713038d3d1Sclaudio } 7723038d3d1Sclaudio 7733038d3d1Sclaudio if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) { 7743038d3d1Sclaudio if (a->labellen > b->labellen) 7753038d3d1Sclaudio return (1); 7763038d3d1Sclaudio if (a->labellen < b->labellen) 7773038d3d1Sclaudio return (-1); 7783038d3d1Sclaudio return (memcmp(a->labelstack, b->labelstack, a->labellen)); 7793038d3d1Sclaudio } 780fafbb788Sclaudio return (0); 7813038d3d1Sclaudio 782fafbb788Sclaudio } 783fafbb788Sclaudio 78421a825c9Sclaudio void 7852b5c88feSclaudio inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen) 7862b5c88feSclaudio { 7872b5c88feSclaudio struct in_addr mask; 7882b5c88feSclaudio 7892b5c88feSclaudio mask.s_addr = htonl(prefixlen2mask(prefixlen)); 7902b5c88feSclaudio dest->s_addr = src->s_addr & mask.s_addr; 7912b5c88feSclaudio } 7922b5c88feSclaudio 7932b5c88feSclaudio void 79421a825c9Sclaudio inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 79521a825c9Sclaudio { 79621a825c9Sclaudio struct in6_addr mask; 79721a825c9Sclaudio int i; 79821a825c9Sclaudio 799eafe309eSclaudio memset(&mask, 0, sizeof(mask)); 80021a825c9Sclaudio for (i = 0; i < prefixlen / 8; i++) 80121a825c9Sclaudio mask.s6_addr[i] = 0xff; 80221a825c9Sclaudio i = prefixlen % 8; 80321a825c9Sclaudio if (i) 80421a825c9Sclaudio mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 80521a825c9Sclaudio 80621a825c9Sclaudio for (i = 0; i < 16; i++) 80721a825c9Sclaudio dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 80821a825c9Sclaudio } 809d6c2e4e8Sclaudio 81013bcf54fSclaudio void 81113bcf54fSclaudio applymask(struct bgpd_addr *dest, const struct bgpd_addr *src, int prefixlen) 81213bcf54fSclaudio { 81313bcf54fSclaudio *dest = *src; 81413bcf54fSclaudio switch (src->aid) { 81513bcf54fSclaudio case AID_INET: 81613bcf54fSclaudio case AID_VPN_IPv4: 81713bcf54fSclaudio inet4applymask(&dest->v4, &src->v4, prefixlen); 81813bcf54fSclaudio break; 81913bcf54fSclaudio case AID_INET6: 82013bcf54fSclaudio case AID_VPN_IPv6: 82113bcf54fSclaudio inet6applymask(&dest->v6, &src->v6, prefixlen); 82213bcf54fSclaudio break; 82313bcf54fSclaudio } 82413bcf54fSclaudio } 82513bcf54fSclaudio 826d6c2e4e8Sclaudio /* address family translation functions */ 827d6c2e4e8Sclaudio const struct aid aid_vals[AID_MAX] = AID_VALS; 828d6c2e4e8Sclaudio 82986729c90Sclaudio const char * 83039386878Sclaudio aid2str(uint8_t aid) 83186729c90Sclaudio { 83286729c90Sclaudio if (aid < AID_MAX) 83386729c90Sclaudio return (aid_vals[aid].name); 83486729c90Sclaudio return ("unknown AID"); 83586729c90Sclaudio } 83686729c90Sclaudio 837d6c2e4e8Sclaudio int 83839386878Sclaudio aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi) 839d6c2e4e8Sclaudio { 840d6c2e4e8Sclaudio if (aid < AID_MAX) { 841d6c2e4e8Sclaudio *afi = aid_vals[aid].afi; 842d6c2e4e8Sclaudio *safi = aid_vals[aid].safi; 843d6c2e4e8Sclaudio return (0); 844d6c2e4e8Sclaudio } 845d6c2e4e8Sclaudio return (-1); 846d6c2e4e8Sclaudio } 847d6c2e4e8Sclaudio 848d6c2e4e8Sclaudio int 84939386878Sclaudio afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid) 850d6c2e4e8Sclaudio { 85139386878Sclaudio uint8_t i; 852d6c2e4e8Sclaudio 853d6c2e4e8Sclaudio for (i = 0; i < AID_MAX; i++) 854d6c2e4e8Sclaudio if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) { 855d6c2e4e8Sclaudio *aid = i; 856d6c2e4e8Sclaudio return (0); 857d6c2e4e8Sclaudio } 858d6c2e4e8Sclaudio 859d6c2e4e8Sclaudio return (-1); 860d6c2e4e8Sclaudio } 861d6c2e4e8Sclaudio 862d6c2e4e8Sclaudio sa_family_t 86339386878Sclaudio aid2af(uint8_t aid) 864d6c2e4e8Sclaudio { 865d6c2e4e8Sclaudio if (aid < AID_MAX) 866d6c2e4e8Sclaudio return (aid_vals[aid].af); 867d6c2e4e8Sclaudio return (AF_UNSPEC); 868d6c2e4e8Sclaudio } 869d6c2e4e8Sclaudio 870d6c2e4e8Sclaudio int 87139386878Sclaudio af2aid(sa_family_t af, uint8_t safi, uint8_t *aid) 872d6c2e4e8Sclaudio { 87339386878Sclaudio uint8_t i; 874d6c2e4e8Sclaudio 875d6c2e4e8Sclaudio if (safi == 0) /* default to unicast subclass */ 876d6c2e4e8Sclaudio safi = SAFI_UNICAST; 877d6c2e4e8Sclaudio 878d6c2e4e8Sclaudio for (i = 0; i < AID_MAX; i++) 879d6c2e4e8Sclaudio if (aid_vals[i].af == af && aid_vals[i].safi == safi) { 880d6c2e4e8Sclaudio *aid = i; 881d6c2e4e8Sclaudio return (0); 882d6c2e4e8Sclaudio } 883d6c2e4e8Sclaudio 884d6c2e4e8Sclaudio return (-1); 885d6c2e4e8Sclaudio } 886d6c2e4e8Sclaudio 88745350f87Sclaudio /* 88845350f87Sclaudio * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses 88945350f87Sclaudio * the included label stack is ignored and needs to be handled by the caller. 89045350f87Sclaudio */ 891d6c2e4e8Sclaudio struct sockaddr * 89239386878Sclaudio addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len) 893d6c2e4e8Sclaudio { 894d6c2e4e8Sclaudio static struct sockaddr_storage ss; 895d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; 896d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; 897d6c2e4e8Sclaudio 8984886db4cSclaudio if (addr == NULL || addr->aid == AID_UNSPEC) 8994886db4cSclaudio return (NULL); 90045350f87Sclaudio 901eafe309eSclaudio memset(&ss, 0, sizeof(ss)); 902d6c2e4e8Sclaudio switch (addr->aid) { 903d6c2e4e8Sclaudio case AID_INET: 9043038d3d1Sclaudio case AID_VPN_IPv4: 905d6c2e4e8Sclaudio sa_in->sin_family = AF_INET; 906d6c2e4e8Sclaudio sa_in->sin_addr.s_addr = addr->v4.s_addr; 907d6c2e4e8Sclaudio sa_in->sin_port = htons(port); 908255fe563Sclaudio *len = sizeof(struct sockaddr_in); 909d6c2e4e8Sclaudio break; 910d6c2e4e8Sclaudio case AID_INET6: 91145350f87Sclaudio case AID_VPN_IPv6: 91245350f87Sclaudio sa_in6->sin6_family = AF_INET6; 9133038d3d1Sclaudio memcpy(&sa_in6->sin6_addr, &addr->v6, 91445350f87Sclaudio sizeof(sa_in6->sin6_addr)); 91545350f87Sclaudio sa_in6->sin6_port = htons(port); 91645350f87Sclaudio sa_in6->sin6_scope_id = addr->scope_id; 91745350f87Sclaudio *len = sizeof(struct sockaddr_in6); 91845350f87Sclaudio break; 919d6c2e4e8Sclaudio } 920d6c2e4e8Sclaudio 921d6c2e4e8Sclaudio return ((struct sockaddr *)&ss); 922d6c2e4e8Sclaudio } 923d6c2e4e8Sclaudio 924d6c2e4e8Sclaudio void 92539386878Sclaudio sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port) 926d6c2e4e8Sclaudio { 927d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 928d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 929d6c2e4e8Sclaudio 930eafe309eSclaudio memset(addr, 0, sizeof(*addr)); 931d6c2e4e8Sclaudio switch (sa->sa_family) { 932d6c2e4e8Sclaudio case AF_INET: 933d6c2e4e8Sclaudio addr->aid = AID_INET; 934d6c2e4e8Sclaudio memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4)); 935a27d9e33Sclaudio if (port) 936a27d9e33Sclaudio *port = ntohs(sa_in->sin_port); 937d6c2e4e8Sclaudio break; 938d6c2e4e8Sclaudio case AF_INET6: 939d6c2e4e8Sclaudio addr->aid = AID_INET6; 940be6ced5eSclaudio #ifdef __KAME__ 941be6ced5eSclaudio /* 942be6ced5eSclaudio * XXX thanks, KAME, for this ugliness... 943be6ced5eSclaudio * adopted from route/show.c 944be6ced5eSclaudio */ 9455177244fSclaudio if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) || 9465177244fSclaudio IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr) || 9474ff2dba3Sclaudio IN6_IS_ADDR_MC_NODELOCAL(&sa_in6->sin6_addr)) && 9485177244fSclaudio sa_in6->sin6_scope_id == 0) { 949be6ced5eSclaudio uint16_t tmp16; 950be6ced5eSclaudio memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2], 951be6ced5eSclaudio sizeof(tmp16)); 952be6ced5eSclaudio sa_in6->sin6_scope_id = ntohs(tmp16); 953be6ced5eSclaudio sa_in6->sin6_addr.s6_addr[2] = 0; 954be6ced5eSclaudio sa_in6->sin6_addr.s6_addr[3] = 0; 955be6ced5eSclaudio } 956be6ced5eSclaudio #endif 9575177244fSclaudio memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6)); 958d6c2e4e8Sclaudio addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */ 959a27d9e33Sclaudio if (port) 960a27d9e33Sclaudio *port = ntohs(sa_in6->sin6_port); 961d6c2e4e8Sclaudio break; 962d6c2e4e8Sclaudio } 963d6c2e4e8Sclaudio } 9646e8089a5Sclaudio 9656e8089a5Sclaudio const char * 966bc757ddaSclaudio get_baudrate(unsigned long long baudrate, char *unit) 9676e8089a5Sclaudio { 9686e8089a5Sclaudio static char bbuf[16]; 9693eaf1285Sclaudio const unsigned long long kilo = 1000; 9703eaf1285Sclaudio const unsigned long long mega = 1000ULL * kilo; 9713eaf1285Sclaudio const unsigned long long giga = 1000ULL * mega; 9726e8089a5Sclaudio 9733eaf1285Sclaudio if (baudrate > giga) 9746e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu G%s", 9753eaf1285Sclaudio baudrate / giga, unit); 9763eaf1285Sclaudio else if (baudrate > mega) 9776e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu M%s", 9783eaf1285Sclaudio baudrate / mega, unit); 9793eaf1285Sclaudio else if (baudrate > kilo) 9806e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu K%s", 9813eaf1285Sclaudio baudrate / kilo, unit); 9826e8089a5Sclaudio else 9836e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu %s", 9846e8089a5Sclaudio baudrate, unit); 9856e8089a5Sclaudio 9866e8089a5Sclaudio return (bbuf); 9876e8089a5Sclaudio } 988