1*110c1584Sclaudio /* $OpenBSD: util.c,v 1.83 2024/03/20 09:35:46 claudio 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 352ffcd4e0Sclaudio const char * 362ffcd4e0Sclaudio log_addr(const struct bgpd_addr *addr) 372ffcd4e0Sclaudio { 38290f96faSdenis static char buf[74]; 3945350f87Sclaudio struct sockaddr *sa; 405624d029Sclaudio socklen_t len; 412ffcd4e0Sclaudio 4245350f87Sclaudio sa = addr2sa(addr, 0, &len); 4315d8de66Sclaudio switch (addr->aid) { 4415d8de66Sclaudio case AID_INET: 4515d8de66Sclaudio case AID_INET6: 4645350f87Sclaudio return log_sockaddr(sa, len); 4715d8de66Sclaudio case AID_VPN_IPv4: 48290f96faSdenis case AID_VPN_IPv6: 493038d3d1Sclaudio snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->rd), 5045350f87Sclaudio log_sockaddr(sa, len)); 51290f96faSdenis return (buf); 5215d8de66Sclaudio } 5315d8de66Sclaudio return ("???"); 542ffcd4e0Sclaudio } 552ffcd4e0Sclaudio 562ffcd4e0Sclaudio const char * 572ffcd4e0Sclaudio log_in6addr(const struct in6_addr *addr) 582ffcd4e0Sclaudio { 592ffcd4e0Sclaudio struct sockaddr_in6 sa_in6; 602ffcd4e0Sclaudio 61eafe309eSclaudio memset(&sa_in6, 0, sizeof(sa_in6)); 622ffcd4e0Sclaudio sa_in6.sin6_family = AF_INET6; 632ffcd4e0Sclaudio memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr)); 642ffcd4e0Sclaudio 65be6ced5eSclaudio #ifdef __KAME__ 662ffcd4e0Sclaudio /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */ 67bdec2ffaStb if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) || 68bdec2ffaStb IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr) || 694ff2dba3Sclaudio IN6_IS_ADDR_MC_NODELOCAL(&sa_in6.sin6_addr)) && 70bdec2ffaStb sa_in6.sin6_scope_id == 0) { 7139386878Sclaudio uint16_t tmp16; 722ffcd4e0Sclaudio memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16)); 732ffcd4e0Sclaudio sa_in6.sin6_scope_id = ntohs(tmp16); 742ffcd4e0Sclaudio sa_in6.sin6_addr.s6_addr[2] = 0; 752ffcd4e0Sclaudio sa_in6.sin6_addr.s6_addr[3] = 0; 762ffcd4e0Sclaudio } 77be6ced5eSclaudio #endif 782ffcd4e0Sclaudio 79255fe563Sclaudio return (log_sockaddr((struct sockaddr *)&sa_in6, sizeof(sa_in6))); 802ffcd4e0Sclaudio } 812ffcd4e0Sclaudio 822ffcd4e0Sclaudio const char * 83255fe563Sclaudio log_sockaddr(struct sockaddr *sa, socklen_t len) 842ffcd4e0Sclaudio { 852ffcd4e0Sclaudio static char buf[NI_MAXHOST]; 862ffcd4e0Sclaudio 8745350f87Sclaudio if (sa == NULL || getnameinfo(sa, len, buf, sizeof(buf), NULL, 0, 882ffcd4e0Sclaudio NI_NUMERICHOST)) 892ffcd4e0Sclaudio return ("(unknown)"); 902ffcd4e0Sclaudio else 912ffcd4e0Sclaudio return (buf); 922ffcd4e0Sclaudio } 932ffcd4e0Sclaudio 940c88bf70Sclaudio const char * 9539386878Sclaudio log_as(uint32_t as) 960c88bf70Sclaudio { 9706bcde9cSphessler static char buf[11]; /* "4294967294\0" */ 980c88bf70Sclaudio 99515e489cSderaadt if (snprintf(buf, sizeof(buf), "%u", as) < 0) 1000c88bf70Sclaudio return ("?"); 10106bcde9cSphessler 1020c88bf70Sclaudio return (buf); 1030c88bf70Sclaudio } 1040c88bf70Sclaudio 105256b680eSclaudio const char * 10639386878Sclaudio log_rd(uint64_t rd) 107256b680eSclaudio { 108256b680eSclaudio static char buf[32]; 109256b680eSclaudio struct in_addr addr; 11039386878Sclaudio uint32_t u32; 11139386878Sclaudio uint16_t u16; 112256b680eSclaudio 113f4c0eb52Sclaudio rd = be64toh(rd); 114256b680eSclaudio switch (rd >> 48) { 115bf8e2920Sclaudio case EXT_COMMUNITY_TRANS_TWO_AS: 116256b680eSclaudio u32 = rd & 0xffffffff; 117256b680eSclaudio u16 = (rd >> 32) & 0xffff; 11832ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32); 119256b680eSclaudio break; 120bf8e2920Sclaudio case EXT_COMMUNITY_TRANS_FOUR_AS: 121256b680eSclaudio u32 = (rd >> 16) & 0xffffffff; 122256b680eSclaudio u16 = rd & 0xffff; 12332ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16); 124256b680eSclaudio break; 125bf8e2920Sclaudio case EXT_COMMUNITY_TRANS_IPV4: 126256b680eSclaudio u32 = (rd >> 16) & 0xffffffff; 127256b680eSclaudio u16 = rd & 0xffff; 128256b680eSclaudio addr.s_addr = htonl(u32); 12932ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16); 130256b680eSclaudio break; 131256b680eSclaudio default: 132ec5cb450Sclaudio snprintf(buf, sizeof(buf), "rd #%016llx", 133ec5cb450Sclaudio (unsigned long long)rd); 134ec5cb450Sclaudio break; 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 1666290e740Sclaudio static const char * 1676290e740Sclaudio log_expires(time_t expires) 1686290e740Sclaudio { 1696290e740Sclaudio static char buf[32]; 1706290e740Sclaudio 1716290e740Sclaudio buf[0] = '\0'; 1726290e740Sclaudio if (expires != 0) 1736290e740Sclaudio snprintf(buf, sizeof(buf), " expires %lld", (long long)expires); 1746290e740Sclaudio return buf; 1756290e740Sclaudio } 1766290e740Sclaudio 1776290e740Sclaudio const char * 1786290e740Sclaudio log_roa(struct roa *roa) 1796290e740Sclaudio { 1806290e740Sclaudio static char buf[256]; 1816290e740Sclaudio char maxbuf[32]; 1822fd9f52dSmiod #if defined(__GNUC__) && __GNUC__ < 4 1832fd9f52dSmiod struct bgpd_addr addr = { .aid = roa->aid }; 1842fd9f52dSmiod addr.v6 = roa->prefix.inet6; 1852fd9f52dSmiod #else 1862fd9f52dSmiod struct bgpd_addr addr = { .aid = roa->aid, .v6 = roa->prefix.inet6 }; 1872fd9f52dSmiod #endif 1886290e740Sclaudio 1896290e740Sclaudio maxbuf[0] = '\0'; 1906290e740Sclaudio if (roa->prefixlen != roa->maxlen) 1916290e740Sclaudio snprintf(maxbuf, sizeof(maxbuf), " maxlen %u", roa->maxlen); 1926290e740Sclaudio snprintf(buf, sizeof(buf), "%s/%u%s source-as %u%s", log_addr(&addr), 1936290e740Sclaudio roa->prefixlen, maxbuf, roa->asnum, log_expires(roa->expires)); 1946290e740Sclaudio return buf; 1956290e740Sclaudio } 1966290e740Sclaudio 1976290e740Sclaudio const char * 1986290e740Sclaudio log_aspa(struct aspa_set *aspa) 1996290e740Sclaudio { 2006290e740Sclaudio static char errbuf[256]; 2016290e740Sclaudio static char *buf; 2026290e740Sclaudio static size_t len; 2036290e740Sclaudio char asbuf[16]; 2046290e740Sclaudio size_t needed; 2056290e740Sclaudio uint32_t i; 2066290e740Sclaudio 2076290e740Sclaudio /* include enough space for header and trailer */ 2086290e740Sclaudio if ((uint64_t)aspa->num > (SIZE_MAX / sizeof(asbuf) - 72)) 2096290e740Sclaudio goto fail; 2106290e740Sclaudio needed = aspa->num * sizeof(asbuf) + 72; 2116290e740Sclaudio if (needed > len) { 2126290e740Sclaudio char *nbuf; 2136290e740Sclaudio 2146290e740Sclaudio if ((nbuf = realloc(buf, needed)) == NULL) 2156290e740Sclaudio goto fail; 2166290e740Sclaudio len = needed; 2176290e740Sclaudio buf = nbuf; 2186290e740Sclaudio } 2196290e740Sclaudio 2206290e740Sclaudio snprintf(buf, len, "customer-as %s%s provider-as { ", 2216290e740Sclaudio log_as(aspa->as), log_expires(aspa->expires)); 2226290e740Sclaudio 2236290e740Sclaudio for (i = 0; i < aspa->num; i++) { 2246290e740Sclaudio snprintf(asbuf, sizeof(asbuf), "%s ", log_as(aspa->tas[i])); 2256290e740Sclaudio if (strlcat(buf, asbuf, len) >= len) 2266290e740Sclaudio goto fail; 2276290e740Sclaudio } 2286290e740Sclaudio if (strlcat(buf, "}", len) >= len) 2296290e740Sclaudio goto fail; 2306290e740Sclaudio return buf; 2316290e740Sclaudio 2326290e740Sclaudio fail: 2336290e740Sclaudio free(buf); 2346290e740Sclaudio buf = NULL; 2356290e740Sclaudio len = 0; 2366290e740Sclaudio snprintf(errbuf, sizeof(errbuf), "customer-as %s%s provider-as { ... }", 2376290e740Sclaudio log_as(aspa->as), log_expires(aspa->expires)); 2386290e740Sclaudio return errbuf; 2396290e740Sclaudio } 2406290e740Sclaudio 2410561b344Sphessler const char * 24204349dffSclaudio log_aspath_error(int error) 24304349dffSclaudio { 24404349dffSclaudio static char buf[20]; 24504349dffSclaudio 24604349dffSclaudio switch (error) { 24704349dffSclaudio case AS_ERR_LEN: 24804349dffSclaudio return "inconsitent lenght"; 24904349dffSclaudio case AS_ERR_TYPE: 25004349dffSclaudio return "unknown segment type"; 25104349dffSclaudio case AS_ERR_BAD: 25204349dffSclaudio return "invalid encoding"; 25304349dffSclaudio case AS_ERR_SOFT: 25404349dffSclaudio return "soft failure"; 25504349dffSclaudio default: 25604349dffSclaudio snprintf(buf, sizeof(buf), "unknown %d", error); 25704349dffSclaudio return buf; 25804349dffSclaudio } 25904349dffSclaudio } 26004349dffSclaudio 26104349dffSclaudio const char * 262bd9df44eSclaudio log_rtr_error(enum rtr_error err) 263bd9df44eSclaudio { 264bd9df44eSclaudio static char buf[20]; 265bd9df44eSclaudio 266bd9df44eSclaudio switch (err) { 267bd9df44eSclaudio case NO_ERROR: 268bd9df44eSclaudio return "No Error"; 269bd9df44eSclaudio case CORRUPT_DATA: 270bd9df44eSclaudio return "Corrupt Data"; 271bd9df44eSclaudio case INTERNAL_ERROR: 272bd9df44eSclaudio return "Internal Error"; 273bd9df44eSclaudio case NO_DATA_AVAILABLE: 274bd9df44eSclaudio return "No Data Available"; 275bd9df44eSclaudio case INVALID_REQUEST: 276bd9df44eSclaudio return "Invalid Request"; 277bd9df44eSclaudio case UNSUPP_PROTOCOL_VERS: 278bd9df44eSclaudio return "Unsupported Protocol Version"; 279bd9df44eSclaudio case UNSUPP_PDU_TYPE: 280bd9df44eSclaudio return "Unsupported PDU Type"; 281bd9df44eSclaudio case UNK_REC_WDRAWL: 282f4123069Smbuhl return "Withdrawal of Unknown Record"; 283bd9df44eSclaudio case DUP_REC_RECV: 284bd9df44eSclaudio return "Duplicate Announcement Received"; 285bd9df44eSclaudio case UNEXP_PROTOCOL_VERS: 286bd9df44eSclaudio return "Unexpected Protocol Version"; 287bd9df44eSclaudio default: 288bd9df44eSclaudio snprintf(buf, sizeof(buf), "unknown %u", err); 289bd9df44eSclaudio return buf; 290bd9df44eSclaudio } 291bd9df44eSclaudio } 292bd9df44eSclaudio 293bd9df44eSclaudio const char * 294c0c94bccSclaudio log_policy(enum role role) 295202e5273Stb { 296202e5273Stb switch (role) { 297c0c94bccSclaudio case ROLE_PROVIDER: 298202e5273Stb return "provider"; 299c0c94bccSclaudio case ROLE_RS: 300202e5273Stb return "rs"; 301c0c94bccSclaudio case ROLE_RS_CLIENT: 302202e5273Stb return "rs-client"; 303c0c94bccSclaudio case ROLE_CUSTOMER: 304202e5273Stb return "customer"; 305c0c94bccSclaudio case ROLE_PEER: 306202e5273Stb return "peer"; 307202e5273Stb default: 308202e5273Stb return "unknown"; 309202e5273Stb } 310202e5273Stb } 311202e5273Stb 31204349dffSclaudio static const char * 31339386878Sclaudio aspath_delim(uint8_t seg_type, int closing) 3141e590dcfSclaudio { 3151e590dcfSclaudio static char db[8]; 3161e590dcfSclaudio 3171e590dcfSclaudio switch (seg_type) { 3181e590dcfSclaudio case AS_SET: 3191e590dcfSclaudio if (!closing) 3201e590dcfSclaudio return ("{ "); 3211e590dcfSclaudio else 3221e590dcfSclaudio return (" }"); 3231e590dcfSclaudio case AS_SEQUENCE: 3241e590dcfSclaudio return (""); 3251e590dcfSclaudio case AS_CONFED_SEQUENCE: 3261e590dcfSclaudio if (!closing) 3271e590dcfSclaudio return ("( "); 3281e590dcfSclaudio else 3291e590dcfSclaudio return (" )"); 3301e590dcfSclaudio case AS_CONFED_SET: 3311e590dcfSclaudio if (!closing) 3321e590dcfSclaudio return ("[ "); 3331e590dcfSclaudio else 3341e590dcfSclaudio return (" ]"); 3351e590dcfSclaudio default: 3361e590dcfSclaudio if (!closing) 3371e590dcfSclaudio snprintf(db, sizeof(db), "!%u ", seg_type); 3381e590dcfSclaudio else 3391e590dcfSclaudio snprintf(db, sizeof(db), " !%u", seg_type); 3401e590dcfSclaudio return (db); 3411e590dcfSclaudio } 3421e590dcfSclaudio } 3431e590dcfSclaudio 34404349dffSclaudio static int 34504349dffSclaudio aspath_snprint(char *buf, size_t size, struct ibuf *in) 3462ffcd4e0Sclaudio { 3472ffcd4e0Sclaudio #define UPDATE() \ 3482ffcd4e0Sclaudio do { \ 34904349dffSclaudio if (r < 0 || (unsigned int)r >= size) \ 3502ffcd4e0Sclaudio return (-1); \ 3512ffcd4e0Sclaudio size -= r; \ 3522ffcd4e0Sclaudio buf += r; \ 3532ffcd4e0Sclaudio } while (0) 35404349dffSclaudio 35504349dffSclaudio struct ibuf data; 35604349dffSclaudio uint32_t as; 35704349dffSclaudio int r, n = 0; 35839386878Sclaudio uint8_t i, seg_type, seg_len; 3592ffcd4e0Sclaudio 36004349dffSclaudio ibuf_from_ibuf(&data, in); 36104349dffSclaudio while (ibuf_size(&data) > 0) { 36204349dffSclaudio if (ibuf_get_n8(&data, &seg_type) == -1 || 36304349dffSclaudio ibuf_get_n8(&data, &seg_len) == -1 || 36404349dffSclaudio seg_len == 0) 36504349dffSclaudio return (-1); 3662ffcd4e0Sclaudio 36704349dffSclaudio r = snprintf(buf, size, "%s%s", n++ != 0 ? " " : "", 3681e590dcfSclaudio aspath_delim(seg_type, 0)); 3692ffcd4e0Sclaudio UPDATE(); 3702ffcd4e0Sclaudio 3712ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) { 37204349dffSclaudio if (ibuf_get_n32(&data, &as) == -1) 37304349dffSclaudio return -1; 37404349dffSclaudio 37504349dffSclaudio r = snprintf(buf, size, "%s", log_as(as)); 3762ffcd4e0Sclaudio UPDATE(); 3772ffcd4e0Sclaudio if (i + 1 < seg_len) { 3782ffcd4e0Sclaudio r = snprintf(buf, size, " "); 3792ffcd4e0Sclaudio UPDATE(); 3802ffcd4e0Sclaudio } 3812ffcd4e0Sclaudio } 3821e590dcfSclaudio r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1)); 3832ffcd4e0Sclaudio UPDATE(); 3842ffcd4e0Sclaudio } 38555e49665Sclaudio /* ensure that we have a valid C-string especially for empty as path */ 3862ffcd4e0Sclaudio *buf = '\0'; 38704349dffSclaudio return (0); 3882ffcd4e0Sclaudio #undef UPDATE 3892ffcd4e0Sclaudio } 3902ffcd4e0Sclaudio 39104349dffSclaudio static ssize_t 39204349dffSclaudio aspath_strsize(struct ibuf *in) 3932ffcd4e0Sclaudio { 39404349dffSclaudio struct ibuf buf; 39504349dffSclaudio ssize_t total_size = 0; 39639386878Sclaudio uint32_t as; 39739386878Sclaudio uint8_t i, seg_type, seg_len; 3982ffcd4e0Sclaudio 39904349dffSclaudio ibuf_from_ibuf(&buf, in); 40004349dffSclaudio while (ibuf_size(&buf) > 0) { 40104349dffSclaudio if (ibuf_get_n8(&buf, &seg_type) == -1 || 40204349dffSclaudio ibuf_get_n8(&buf, &seg_len) == -1 || 40304349dffSclaudio seg_len == 0) 40404349dffSclaudio return (-1); 4052ffcd4e0Sclaudio 4062ffcd4e0Sclaudio if (total_size != 0) 4072ffcd4e0Sclaudio total_size += 1; 40804349dffSclaudio total_size += strlen(aspath_delim(seg_type, 0)); 4092ffcd4e0Sclaudio 4102ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) { 41104349dffSclaudio if (ibuf_get_n32(&buf, &as) == -1) 41204349dffSclaudio return (-1); 4130c88bf70Sclaudio 4148db4f5d2Sclaudio do { 4158db4f5d2Sclaudio total_size++; 4168db4f5d2Sclaudio } while ((as = as / 10) != 0); 41704349dffSclaudio } 41804349dffSclaudio total_size += seg_len - 1; 4192ffcd4e0Sclaudio 42004349dffSclaudio total_size += strlen(aspath_delim(seg_type, 1)); 42104349dffSclaudio } 42204349dffSclaudio return (total_size + 1); 4232ffcd4e0Sclaudio } 4242ffcd4e0Sclaudio 42504349dffSclaudio int 42604349dffSclaudio aspath_asprint(char **ret, struct ibuf *data) 42704349dffSclaudio { 42804349dffSclaudio ssize_t slen; 42904349dffSclaudio 43004349dffSclaudio if ((slen = aspath_strsize(data)) == -1) { 43104349dffSclaudio *ret = NULL; 43204349dffSclaudio errno = EINVAL; 43304349dffSclaudio return (-1); 4342ffcd4e0Sclaudio } 43504349dffSclaudio 43604349dffSclaudio *ret = malloc(slen); 43704349dffSclaudio if (*ret == NULL) 43804349dffSclaudio return (-1); 43904349dffSclaudio 44004349dffSclaudio if (aspath_snprint(*ret, slen, data) == -1) { 44104349dffSclaudio free(*ret); 44204349dffSclaudio *ret = NULL; 44304349dffSclaudio errno = EINVAL; 44404349dffSclaudio return (-1); 44504349dffSclaudio } 44604349dffSclaudio 44704349dffSclaudio return (0); 4482ffcd4e0Sclaudio } 4492ffcd4e0Sclaudio 4502ffcd4e0Sclaudio /* 4512ffcd4e0Sclaudio * Extract the asnum out of the as segment at the specified position. 4522ffcd4e0Sclaudio * Direct access is not possible because of non-aligned reads. 453506f72cfSclaudio * Only works on verified 4-byte AS paths. 4542ffcd4e0Sclaudio */ 45539386878Sclaudio uint32_t 4562ffcd4e0Sclaudio aspath_extract(const void *seg, int pos) 4572ffcd4e0Sclaudio { 4582ffcd4e0Sclaudio const u_char *ptr = seg; 45939386878Sclaudio uint32_t as; 4602ffcd4e0Sclaudio 461506f72cfSclaudio /* minimal pos check, return 0 since that is an invalid ASN */ 462506f72cfSclaudio if (pos < 0 || pos >= ptr[1]) 463506f72cfSclaudio return (0); 46439386878Sclaudio ptr += 2 + sizeof(uint32_t) * pos; 46539386878Sclaudio memcpy(&as, ptr, sizeof(uint32_t)); 4660c88bf70Sclaudio return (ntohl(as)); 4672ffcd4e0Sclaudio } 46821a825c9Sclaudio 469de5c2eedSclaudio /* 47029328a94Sclaudio * Verify that the aspath is correctly encoded. 47129328a94Sclaudio */ 47229328a94Sclaudio int 47304349dffSclaudio aspath_verify(struct ibuf *in, int as4byte, int noset) 47429328a94Sclaudio { 47504349dffSclaudio struct ibuf buf; 47604349dffSclaudio int pos, error = 0; 47739386878Sclaudio uint8_t seg_len, seg_type; 47829328a94Sclaudio 47904349dffSclaudio ibuf_from_ibuf(&buf, in); 48004349dffSclaudio if (ibuf_size(&buf) & 1) { 48129328a94Sclaudio /* odd length aspath are invalid */ 48204349dffSclaudio error = AS_ERR_BAD; 48304349dffSclaudio goto done; 48404349dffSclaudio } 48529328a94Sclaudio 48604349dffSclaudio while (ibuf_size(&buf) > 0) { 48704349dffSclaudio if (ibuf_get_n8(&buf, &seg_type) == -1 || 48804349dffSclaudio ibuf_get_n8(&buf, &seg_len) == -1) { 48904349dffSclaudio error = AS_ERR_LEN; 49004349dffSclaudio goto done; 49104349dffSclaudio } 49229328a94Sclaudio 49304349dffSclaudio if (seg_len == 0) { 494d04df938Sclaudio /* empty aspath segments are not allowed */ 49504349dffSclaudio error = AS_ERR_BAD; 49604349dffSclaudio goto done; 49704349dffSclaudio } 498d04df938Sclaudio 49929328a94Sclaudio /* 50029328a94Sclaudio * BGP confederations should not show up but consider them 50129328a94Sclaudio * as a soft error which invalidates the path but keeps the 50229328a94Sclaudio * bgp session running. 50329328a94Sclaudio */ 50429328a94Sclaudio if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET) 50529328a94Sclaudio error = AS_ERR_SOFT; 506aa528464Sclaudio /* 507aa528464Sclaudio * If AS_SET filtering (RFC6472) is on, error out on AS_SET 508aa528464Sclaudio * as well. 509aa528464Sclaudio */ 510aa528464Sclaudio if (noset && seg_type == AS_SET) 511aa528464Sclaudio error = AS_ERR_SOFT; 51229328a94Sclaudio if (seg_type != AS_SET && seg_type != AS_SEQUENCE && 51304349dffSclaudio seg_type != AS_CONFED_SEQUENCE && 51404349dffSclaudio seg_type != AS_CONFED_SET) { 51504349dffSclaudio error = AS_ERR_TYPE; 51604349dffSclaudio goto done; 51704349dffSclaudio } 51829328a94Sclaudio 51929328a94Sclaudio /* RFC 7607 - AS 0 is considered malformed */ 52029328a94Sclaudio for (pos = 0; pos < seg_len; pos++) { 52139386878Sclaudio uint32_t as; 52229328a94Sclaudio 52304349dffSclaudio if (as4byte) { 52404349dffSclaudio if (ibuf_get_n32(&buf, &as) == -1) { 52504349dffSclaudio error = AS_ERR_LEN; 52604349dffSclaudio goto done; 52704349dffSclaudio } 52804349dffSclaudio } else { 52904349dffSclaudio uint16_t tmp; 53004349dffSclaudio if (ibuf_get_n16(&buf, &tmp) == -1) { 53104349dffSclaudio error = AS_ERR_LEN; 53204349dffSclaudio goto done; 53304349dffSclaudio } 53404349dffSclaudio as = tmp; 53504349dffSclaudio } 53629328a94Sclaudio if (as == 0) 53756a9a1b8Sclaudio error = AS_ERR_SOFT; 53829328a94Sclaudio } 53929328a94Sclaudio } 54004349dffSclaudio 54104349dffSclaudio done: 54229328a94Sclaudio return (error); /* aspath is valid but probably not loop free */ 54329328a94Sclaudio } 54429328a94Sclaudio 54529328a94Sclaudio /* 54629328a94Sclaudio * convert a 2 byte aspath to a 4 byte one. 54729328a94Sclaudio */ 54804349dffSclaudio struct ibuf * 54904349dffSclaudio aspath_inflate(struct ibuf *in) 55029328a94Sclaudio { 55104349dffSclaudio struct ibuf *out; 55204349dffSclaudio uint16_t short_as; 55304349dffSclaudio uint8_t seg_type, seg_len; 55429328a94Sclaudio 5554ac10ff8Sclaudio /* 5564ac10ff8Sclaudio * Allocate enough space for the worst case. 5574ac10ff8Sclaudio * XXX add 1 byte for the empty ASPATH case since we can't 5584ac10ff8Sclaudio * allocate an ibuf of 0 length. 5594ac10ff8Sclaudio */ 5604ac10ff8Sclaudio if ((out = ibuf_open(ibuf_size(in) * 2 + 1)) == NULL) 56129328a94Sclaudio return (NULL); 56229328a94Sclaudio 56329328a94Sclaudio /* then copy the aspath */ 56404349dffSclaudio while (ibuf_size(in) > 0) { 56504349dffSclaudio if (ibuf_get_n8(in, &seg_type) == -1 || 56604349dffSclaudio ibuf_get_n8(in, &seg_len) == -1 || 56704349dffSclaudio seg_len == 0) 56804349dffSclaudio goto fail; 56904349dffSclaudio if (ibuf_add_n8(out, seg_type) == -1 || 57004349dffSclaudio ibuf_add_n8(out, seg_len) == -1) 57104349dffSclaudio goto fail; 57204349dffSclaudio 57329328a94Sclaudio for (; seg_len > 0; seg_len--) { 57404349dffSclaudio if (ibuf_get_n16(in, &short_as) == -1) 57504349dffSclaudio goto fail; 57604349dffSclaudio if (ibuf_add_n32(out, short_as) == -1) 57704349dffSclaudio goto fail; 57829328a94Sclaudio } 57929328a94Sclaudio } 58029328a94Sclaudio 58104349dffSclaudio return (out); 58204349dffSclaudio 58304349dffSclaudio fail: 58404349dffSclaudio ibuf_free(out); 58504349dffSclaudio return (NULL); 58629328a94Sclaudio } 58729328a94Sclaudio 5885c4d2233Sclaudio static const u_char addrmask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 5895c4d2233Sclaudio 0xf8, 0xfc, 0xfe, 0xff }; 5905c4d2233Sclaudio 5916d3e8673Sclaudio /* NLRI functions to extract prefixes from the NLRI blobs */ 5920f144400Sclaudio int 5930f144400Sclaudio extract_prefix(const u_char *p, int len, void *va, uint8_t pfxlen, uint8_t max) 5946d3e8673Sclaudio { 5956d3e8673Sclaudio u_char *a = va; 5963f0f322fSclaudio int plen; 5976d3e8673Sclaudio 5983f0f322fSclaudio plen = PREFIX_SIZE(pfxlen) - 1; 5993f0f322fSclaudio if (len < plen || max < plen) 6003f0f322fSclaudio return -1; 6013f0f322fSclaudio 6023f0f322fSclaudio while (pfxlen > 0) { 6036d3e8673Sclaudio if (pfxlen < 8) { 6043f0f322fSclaudio *a++ = *p++ & addrmask[pfxlen]; 6056d3e8673Sclaudio break; 6066d3e8673Sclaudio } else { 6073f0f322fSclaudio *a++ = *p++; 6086d3e8673Sclaudio pfxlen -= 8; 6096d3e8673Sclaudio } 6106d3e8673Sclaudio } 6116d3e8673Sclaudio return (plen); 6126d3e8673Sclaudio } 6136d3e8673Sclaudio 6145c4d2233Sclaudio static int 6155c4d2233Sclaudio extract_prefix_buf(struct ibuf *buf, void *va, uint8_t pfxlen, uint8_t max) 6166d3e8673Sclaudio { 6175c4d2233Sclaudio u_char *a = va; 6185c4d2233Sclaudio unsigned int plen; 6195c4d2233Sclaudio uint8_t tmp; 6205c4d2233Sclaudio 6215c4d2233Sclaudio plen = PREFIX_SIZE(pfxlen) - 1; 6225c4d2233Sclaudio if (ibuf_size(buf) < plen || max < plen) 6235c4d2233Sclaudio return -1; 6245c4d2233Sclaudio 6255c4d2233Sclaudio while (pfxlen > 0) { 6265c4d2233Sclaudio if (ibuf_get_n8(buf, &tmp) == -1) 6275c4d2233Sclaudio return -1; 6285c4d2233Sclaudio 6295c4d2233Sclaudio if (pfxlen < 8) { 6305c4d2233Sclaudio *a++ = tmp & addrmask[pfxlen]; 6315c4d2233Sclaudio break; 6325c4d2233Sclaudio } else { 6335c4d2233Sclaudio *a++ = tmp; 6345c4d2233Sclaudio pfxlen -= 8; 6355c4d2233Sclaudio } 6365c4d2233Sclaudio } 6375c4d2233Sclaudio return (0); 6385c4d2233Sclaudio } 6395c4d2233Sclaudio 6405c4d2233Sclaudio int 6415c4d2233Sclaudio nlri_get_prefix(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen) 6425c4d2233Sclaudio { 64339386878Sclaudio uint8_t pfxlen; 6446d3e8673Sclaudio 6455c4d2233Sclaudio if (ibuf_get_n8(buf, &pfxlen) == -1) 6466d3e8673Sclaudio return (-1); 6475c4d2233Sclaudio if (pfxlen > 32) 6485c4d2233Sclaudio return (-1); 6496d3e8673Sclaudio 650eafe309eSclaudio memset(prefix, 0, sizeof(struct bgpd_addr)); 6516d3e8673Sclaudio prefix->aid = AID_INET; 6525c4d2233Sclaudio 6535c4d2233Sclaudio if (extract_prefix_buf(buf, &prefix->v4, pfxlen, 6545c4d2233Sclaudio sizeof(prefix->v4)) == -1) 6555c4d2233Sclaudio return (-1); 6565c4d2233Sclaudio 6576d3e8673Sclaudio *prefixlen = pfxlen; 6585c4d2233Sclaudio return (0); 6596d3e8673Sclaudio } 6606d3e8673Sclaudio 6616d3e8673Sclaudio int 6625c4d2233Sclaudio nlri_get_prefix6(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen) 6636d3e8673Sclaudio { 66439386878Sclaudio uint8_t pfxlen; 6656d3e8673Sclaudio 6665c4d2233Sclaudio if (ibuf_get_n8(buf, &pfxlen) == -1) 6676d3e8673Sclaudio return (-1); 6685c4d2233Sclaudio if (pfxlen > 128) 6695c4d2233Sclaudio return (-1); 6706d3e8673Sclaudio 671eafe309eSclaudio memset(prefix, 0, sizeof(struct bgpd_addr)); 6726d3e8673Sclaudio prefix->aid = AID_INET6; 6735c4d2233Sclaudio 6745c4d2233Sclaudio if (extract_prefix_buf(buf, &prefix->v6, pfxlen, 6755c4d2233Sclaudio sizeof(prefix->v6)) == -1) 6765c4d2233Sclaudio return (-1); 6775c4d2233Sclaudio 6786d3e8673Sclaudio *prefixlen = pfxlen; 6795c4d2233Sclaudio return (0); 6806d3e8673Sclaudio } 6816d3e8673Sclaudio 6826d3e8673Sclaudio int 6835c4d2233Sclaudio nlri_get_vpn4(struct ibuf *buf, struct bgpd_addr *prefix, 68439386878Sclaudio uint8_t *prefixlen, int withdraw) 6856d3e8673Sclaudio { 6865c4d2233Sclaudio int done = 0; 68739386878Sclaudio uint8_t pfxlen; 6886d3e8673Sclaudio 6895c4d2233Sclaudio if (ibuf_get_n8(buf, &pfxlen) == -1) 6906d3e8673Sclaudio return (-1); 6916d3e8673Sclaudio 692eafe309eSclaudio memset(prefix, 0, sizeof(struct bgpd_addr)); 6935c4d2233Sclaudio prefix->aid = AID_VPN_IPv4; 6946d3e8673Sclaudio 6956d3e8673Sclaudio /* label stack */ 6966d3e8673Sclaudio do { 6975c4d2233Sclaudio if (prefix->labellen + 3U > sizeof(prefix->labelstack) || 6985c4d2233Sclaudio pfxlen < 3 * 8) 6996d3e8673Sclaudio return (-1); 7006d3e8673Sclaudio if (withdraw) { 7016d3e8673Sclaudio /* on withdraw ignore the labelstack all together */ 7025c4d2233Sclaudio if (ibuf_skip(buf, 3) == -1) 7035c4d2233Sclaudio return (-1); 7046d3e8673Sclaudio pfxlen -= 3 * 8; 7056d3e8673Sclaudio break; 7066d3e8673Sclaudio } 7075c4d2233Sclaudio if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) == 7085c4d2233Sclaudio -1) 7095c4d2233Sclaudio return -1; 7105c4d2233Sclaudio if (prefix->labelstack[prefix->labellen + 2] & 7116d3e8673Sclaudio BGP_MPLS_BOS) 7126d3e8673Sclaudio done = 1; 7135c4d2233Sclaudio prefix->labellen += 3; 7146d3e8673Sclaudio pfxlen -= 3 * 8; 7156d3e8673Sclaudio } while (!done); 7166d3e8673Sclaudio 7176d3e8673Sclaudio /* RD */ 7185c4d2233Sclaudio if (pfxlen < sizeof(uint64_t) * 8 || 7195c4d2233Sclaudio ibuf_get_h64(buf, &prefix->rd) == -1) 7206d3e8673Sclaudio return (-1); 72139386878Sclaudio pfxlen -= sizeof(uint64_t) * 8; 7226d3e8673Sclaudio 7236d3e8673Sclaudio /* prefix */ 7246d3e8673Sclaudio if (pfxlen > 32) 7256d3e8673Sclaudio return (-1); 7265c4d2233Sclaudio if (extract_prefix_buf(buf, &prefix->v4, pfxlen, 7275c4d2233Sclaudio sizeof(prefix->v4)) == -1) 7286d3e8673Sclaudio return (-1); 7296d3e8673Sclaudio 7305c4d2233Sclaudio *prefixlen = pfxlen; 7315c4d2233Sclaudio return (0); 7326d3e8673Sclaudio } 7336d3e8673Sclaudio 734290f96faSdenis int 7355c4d2233Sclaudio nlri_get_vpn6(struct ibuf *buf, struct bgpd_addr *prefix, 73639386878Sclaudio uint8_t *prefixlen, int withdraw) 737290f96faSdenis { 7385c4d2233Sclaudio int done = 0; 73939386878Sclaudio uint8_t pfxlen; 740290f96faSdenis 7415c4d2233Sclaudio if (ibuf_get_n8(buf, &pfxlen) == -1) 742290f96faSdenis return (-1); 743290f96faSdenis 744290f96faSdenis memset(prefix, 0, sizeof(struct bgpd_addr)); 7455c4d2233Sclaudio prefix->aid = AID_VPN_IPv6; 746290f96faSdenis 747290f96faSdenis /* label stack */ 748290f96faSdenis do { 7495c4d2233Sclaudio if (prefix->labellen + 3U > sizeof(prefix->labelstack) || 7505c4d2233Sclaudio pfxlen < 3 * 8) 751290f96faSdenis return (-1); 752290f96faSdenis if (withdraw) { 753290f96faSdenis /* on withdraw ignore the labelstack all together */ 7545c4d2233Sclaudio if (ibuf_skip(buf, 3) == -1) 7555c4d2233Sclaudio return (-1); 756290f96faSdenis pfxlen -= 3 * 8; 757290f96faSdenis break; 758290f96faSdenis } 759290f96faSdenis 7605c4d2233Sclaudio if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) == 7615c4d2233Sclaudio -1) 7625c4d2233Sclaudio return (-1); 7635c4d2233Sclaudio if (prefix->labelstack[prefix->labellen + 2] & 764290f96faSdenis BGP_MPLS_BOS) 765290f96faSdenis done = 1; 7665c4d2233Sclaudio prefix->labellen += 3; 767290f96faSdenis pfxlen -= 3 * 8; 768290f96faSdenis } while (!done); 769290f96faSdenis 770290f96faSdenis /* RD */ 7715c4d2233Sclaudio if (pfxlen < sizeof(uint64_t) * 8 || 7725c4d2233Sclaudio ibuf_get_h64(buf, &prefix->rd) == -1) 773290f96faSdenis return (-1); 77439386878Sclaudio pfxlen -= sizeof(uint64_t) * 8; 775290f96faSdenis 776290f96faSdenis /* prefix */ 777290f96faSdenis if (pfxlen > 128) 778290f96faSdenis return (-1); 7795c4d2233Sclaudio if (extract_prefix_buf(buf, &prefix->v6, pfxlen, 7805c4d2233Sclaudio sizeof(prefix->v6)) == -1) 781290f96faSdenis return (-1); 782290f96faSdenis 7835c4d2233Sclaudio *prefixlen = pfxlen; 7845c4d2233Sclaudio return (0); 785290f96faSdenis } 786290f96faSdenis 787fa3a38bbSclaudio static in_addr_t 788fa3a38bbSclaudio prefixlen2mask(uint8_t prefixlen) 789fa3a38bbSclaudio { 790fa3a38bbSclaudio if (prefixlen == 0) 791fa3a38bbSclaudio return (0); 792290f96faSdenis 793fa3a38bbSclaudio return (0xffffffff << (32 - prefixlen)); 794fa3a38bbSclaudio } 795290f96faSdenis 79629328a94Sclaudio /* 797de5c2eedSclaudio * This function will have undefined behaviour if the passed in prefixlen is 798290f96faSdenis * too large for the respective bgpd_addr address family. 799de5c2eedSclaudio */ 800fafbb788Sclaudio int 801fafbb788Sclaudio prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, 802fafbb788Sclaudio int prefixlen) 803fafbb788Sclaudio { 804fafbb788Sclaudio in_addr_t mask, aa, ba; 805fafbb788Sclaudio int i; 80639386878Sclaudio uint8_t m; 807fafbb788Sclaudio 808fafbb788Sclaudio if (a->aid != b->aid) 809fafbb788Sclaudio return (a->aid - b->aid); 810fafbb788Sclaudio 811fafbb788Sclaudio switch (a->aid) { 8123038d3d1Sclaudio case AID_VPN_IPv4: 8133038d3d1Sclaudio if (be64toh(a->rd) > be64toh(b->rd)) 8143038d3d1Sclaudio return (1); 8153038d3d1Sclaudio if (be64toh(a->rd) < be64toh(b->rd)) 8163038d3d1Sclaudio return (-1); 8173038d3d1Sclaudio /* FALLTHROUGH */ 818fafbb788Sclaudio case AID_INET: 8197da59fecSclaudio if (prefixlen == 0) 8207da59fecSclaudio return (0); 821fafbb788Sclaudio if (prefixlen > 32) 822de5c2eedSclaudio return (-1); 823fafbb788Sclaudio mask = htonl(prefixlen2mask(prefixlen)); 824fafbb788Sclaudio aa = ntohl(a->v4.s_addr & mask); 825fafbb788Sclaudio ba = ntohl(b->v4.s_addr & mask); 8263038d3d1Sclaudio if (aa > ba) 8273038d3d1Sclaudio return (1); 8283038d3d1Sclaudio if (aa < ba) 8293038d3d1Sclaudio return (-1); 8303038d3d1Sclaudio break; 8313038d3d1Sclaudio case AID_VPN_IPv6: 8323038d3d1Sclaudio if (be64toh(a->rd) > be64toh(b->rd)) 8333038d3d1Sclaudio return (1); 8343038d3d1Sclaudio if (be64toh(a->rd) < be64toh(b->rd)) 8353038d3d1Sclaudio return (-1); 8363038d3d1Sclaudio /* FALLTHROUGH */ 837fafbb788Sclaudio case AID_INET6: 8387da59fecSclaudio if (prefixlen == 0) 8397da59fecSclaudio return (0); 840fafbb788Sclaudio if (prefixlen > 128) 841de5c2eedSclaudio return (-1); 842fafbb788Sclaudio for (i = 0; i < prefixlen / 8; i++) 843fafbb788Sclaudio if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 844fafbb788Sclaudio return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 845fafbb788Sclaudio i = prefixlen % 8; 846fafbb788Sclaudio if (i) { 847fafbb788Sclaudio m = 0xff00 >> i; 848fafbb788Sclaudio if ((a->v6.s6_addr[prefixlen / 8] & m) != 849fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m)) 850fafbb788Sclaudio return ((a->v6.s6_addr[prefixlen / 8] & m) - 851fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m)); 852fafbb788Sclaudio } 8533038d3d1Sclaudio break; 8543038d3d1Sclaudio default: 8553038d3d1Sclaudio return (-1); 8563038d3d1Sclaudio } 8573038d3d1Sclaudio 8583038d3d1Sclaudio if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) { 8593038d3d1Sclaudio if (a->labellen > b->labellen) 8603038d3d1Sclaudio return (1); 8613038d3d1Sclaudio if (a->labellen < b->labellen) 8623038d3d1Sclaudio return (-1); 8633038d3d1Sclaudio return (memcmp(a->labelstack, b->labelstack, a->labellen)); 8643038d3d1Sclaudio } 865fafbb788Sclaudio return (0); 8663038d3d1Sclaudio 867fafbb788Sclaudio } 868fafbb788Sclaudio 86921a825c9Sclaudio void 8702b5c88feSclaudio inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen) 8712b5c88feSclaudio { 8722b5c88feSclaudio struct in_addr mask; 8732b5c88feSclaudio 8742b5c88feSclaudio mask.s_addr = htonl(prefixlen2mask(prefixlen)); 8752b5c88feSclaudio dest->s_addr = src->s_addr & mask.s_addr; 8762b5c88feSclaudio } 8772b5c88feSclaudio 8782b5c88feSclaudio void 87921a825c9Sclaudio inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 88021a825c9Sclaudio { 88121a825c9Sclaudio struct in6_addr mask; 88221a825c9Sclaudio int i; 88321a825c9Sclaudio 884eafe309eSclaudio memset(&mask, 0, sizeof(mask)); 88521a825c9Sclaudio for (i = 0; i < prefixlen / 8; i++) 88621a825c9Sclaudio mask.s6_addr[i] = 0xff; 88721a825c9Sclaudio i = prefixlen % 8; 88821a825c9Sclaudio if (i) 88921a825c9Sclaudio mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 89021a825c9Sclaudio 89121a825c9Sclaudio for (i = 0; i < 16; i++) 89221a825c9Sclaudio dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 89321a825c9Sclaudio } 894d6c2e4e8Sclaudio 89513bcf54fSclaudio void 89613bcf54fSclaudio applymask(struct bgpd_addr *dest, const struct bgpd_addr *src, int prefixlen) 89713bcf54fSclaudio { 89813bcf54fSclaudio *dest = *src; 89913bcf54fSclaudio switch (src->aid) { 90013bcf54fSclaudio case AID_INET: 90113bcf54fSclaudio case AID_VPN_IPv4: 90213bcf54fSclaudio inet4applymask(&dest->v4, &src->v4, prefixlen); 90313bcf54fSclaudio break; 90413bcf54fSclaudio case AID_INET6: 90513bcf54fSclaudio case AID_VPN_IPv6: 90613bcf54fSclaudio inet6applymask(&dest->v6, &src->v6, prefixlen); 90713bcf54fSclaudio break; 90813bcf54fSclaudio } 90913bcf54fSclaudio } 91013bcf54fSclaudio 911d6c2e4e8Sclaudio /* address family translation functions */ 912d6c2e4e8Sclaudio const struct aid aid_vals[AID_MAX] = AID_VALS; 913d6c2e4e8Sclaudio 91486729c90Sclaudio const char * 91539386878Sclaudio aid2str(uint8_t aid) 91686729c90Sclaudio { 91786729c90Sclaudio if (aid < AID_MAX) 91886729c90Sclaudio return (aid_vals[aid].name); 91986729c90Sclaudio return ("unknown AID"); 92086729c90Sclaudio } 92186729c90Sclaudio 922d6c2e4e8Sclaudio int 92339386878Sclaudio aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi) 924d6c2e4e8Sclaudio { 925*110c1584Sclaudio if (aid != AID_UNSPEC && aid < AID_MAX) { 926d6c2e4e8Sclaudio *afi = aid_vals[aid].afi; 927d6c2e4e8Sclaudio *safi = aid_vals[aid].safi; 928d6c2e4e8Sclaudio return (0); 929d6c2e4e8Sclaudio } 930d6c2e4e8Sclaudio return (-1); 931d6c2e4e8Sclaudio } 932d6c2e4e8Sclaudio 933d6c2e4e8Sclaudio int 93439386878Sclaudio afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid) 935d6c2e4e8Sclaudio { 93639386878Sclaudio uint8_t i; 937d6c2e4e8Sclaudio 938*110c1584Sclaudio for (i = AID_MIN; i < AID_MAX; i++) 939d6c2e4e8Sclaudio if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) { 940d6c2e4e8Sclaudio *aid = i; 941d6c2e4e8Sclaudio return (0); 942d6c2e4e8Sclaudio } 943d6c2e4e8Sclaudio 944d6c2e4e8Sclaudio return (-1); 945d6c2e4e8Sclaudio } 946d6c2e4e8Sclaudio 947d6c2e4e8Sclaudio sa_family_t 94839386878Sclaudio aid2af(uint8_t aid) 949d6c2e4e8Sclaudio { 950d6c2e4e8Sclaudio if (aid < AID_MAX) 951d6c2e4e8Sclaudio return (aid_vals[aid].af); 952d6c2e4e8Sclaudio return (AF_UNSPEC); 953d6c2e4e8Sclaudio } 954d6c2e4e8Sclaudio 955d6c2e4e8Sclaudio int 95639386878Sclaudio af2aid(sa_family_t af, uint8_t safi, uint8_t *aid) 957d6c2e4e8Sclaudio { 95839386878Sclaudio uint8_t i; 959d6c2e4e8Sclaudio 960d6c2e4e8Sclaudio if (safi == 0) /* default to unicast subclass */ 961d6c2e4e8Sclaudio safi = SAFI_UNICAST; 962d6c2e4e8Sclaudio 963*110c1584Sclaudio for (i = AID_UNSPEC; i < AID_MAX; i++) 964d6c2e4e8Sclaudio if (aid_vals[i].af == af && aid_vals[i].safi == safi) { 965d6c2e4e8Sclaudio *aid = i; 966d6c2e4e8Sclaudio return (0); 967d6c2e4e8Sclaudio } 968d6c2e4e8Sclaudio 969d6c2e4e8Sclaudio return (-1); 970d6c2e4e8Sclaudio } 971d6c2e4e8Sclaudio 97245350f87Sclaudio /* 97345350f87Sclaudio * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses 97445350f87Sclaudio * the included label stack is ignored and needs to be handled by the caller. 97545350f87Sclaudio */ 976d6c2e4e8Sclaudio struct sockaddr * 97739386878Sclaudio addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len) 978d6c2e4e8Sclaudio { 979d6c2e4e8Sclaudio static struct sockaddr_storage ss; 980d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; 981d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; 982d6c2e4e8Sclaudio 9834886db4cSclaudio if (addr == NULL || addr->aid == AID_UNSPEC) 9844886db4cSclaudio return (NULL); 98545350f87Sclaudio 986eafe309eSclaudio memset(&ss, 0, sizeof(ss)); 987d6c2e4e8Sclaudio switch (addr->aid) { 988d6c2e4e8Sclaudio case AID_INET: 9893038d3d1Sclaudio case AID_VPN_IPv4: 990d6c2e4e8Sclaudio sa_in->sin_family = AF_INET; 991d6c2e4e8Sclaudio sa_in->sin_addr.s_addr = addr->v4.s_addr; 992d6c2e4e8Sclaudio sa_in->sin_port = htons(port); 993255fe563Sclaudio *len = sizeof(struct sockaddr_in); 994d6c2e4e8Sclaudio break; 995d6c2e4e8Sclaudio case AID_INET6: 99645350f87Sclaudio case AID_VPN_IPv6: 99745350f87Sclaudio sa_in6->sin6_family = AF_INET6; 9983038d3d1Sclaudio memcpy(&sa_in6->sin6_addr, &addr->v6, 99945350f87Sclaudio sizeof(sa_in6->sin6_addr)); 100045350f87Sclaudio sa_in6->sin6_port = htons(port); 100145350f87Sclaudio sa_in6->sin6_scope_id = addr->scope_id; 100245350f87Sclaudio *len = sizeof(struct sockaddr_in6); 100345350f87Sclaudio break; 100441c1c374Sclaudio case AID_FLOWSPECv4: 100541c1c374Sclaudio case AID_FLOWSPECv6: 100641c1c374Sclaudio return (NULL); 1007d6c2e4e8Sclaudio } 1008d6c2e4e8Sclaudio 1009d6c2e4e8Sclaudio return ((struct sockaddr *)&ss); 1010d6c2e4e8Sclaudio } 1011d6c2e4e8Sclaudio 1012d6c2e4e8Sclaudio void 101339386878Sclaudio sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port) 1014d6c2e4e8Sclaudio { 1015d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 1016d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 1017d6c2e4e8Sclaudio 1018eafe309eSclaudio memset(addr, 0, sizeof(*addr)); 1019d6c2e4e8Sclaudio switch (sa->sa_family) { 1020d6c2e4e8Sclaudio case AF_INET: 1021d6c2e4e8Sclaudio addr->aid = AID_INET; 1022d6c2e4e8Sclaudio memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4)); 1023a27d9e33Sclaudio if (port) 1024a27d9e33Sclaudio *port = ntohs(sa_in->sin_port); 1025d6c2e4e8Sclaudio break; 1026d6c2e4e8Sclaudio case AF_INET6: 1027d6c2e4e8Sclaudio addr->aid = AID_INET6; 1028be6ced5eSclaudio #ifdef __KAME__ 1029be6ced5eSclaudio /* 1030be6ced5eSclaudio * XXX thanks, KAME, for this ugliness... 1031be6ced5eSclaudio * adopted from route/show.c 1032be6ced5eSclaudio */ 10335177244fSclaudio if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) || 10345177244fSclaudio IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr) || 10354ff2dba3Sclaudio IN6_IS_ADDR_MC_NODELOCAL(&sa_in6->sin6_addr)) && 10365177244fSclaudio sa_in6->sin6_scope_id == 0) { 1037be6ced5eSclaudio uint16_t tmp16; 1038be6ced5eSclaudio memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2], 1039be6ced5eSclaudio sizeof(tmp16)); 1040be6ced5eSclaudio sa_in6->sin6_scope_id = ntohs(tmp16); 1041be6ced5eSclaudio sa_in6->sin6_addr.s6_addr[2] = 0; 1042be6ced5eSclaudio sa_in6->sin6_addr.s6_addr[3] = 0; 1043be6ced5eSclaudio } 1044be6ced5eSclaudio #endif 10455177244fSclaudio memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6)); 1046d6c2e4e8Sclaudio addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */ 1047a27d9e33Sclaudio if (port) 1048a27d9e33Sclaudio *port = ntohs(sa_in6->sin6_port); 1049d6c2e4e8Sclaudio break; 1050d6c2e4e8Sclaudio } 1051d6c2e4e8Sclaudio } 10526e8089a5Sclaudio 10536e8089a5Sclaudio const char * 1054bc757ddaSclaudio get_baudrate(unsigned long long baudrate, char *unit) 10556e8089a5Sclaudio { 10566e8089a5Sclaudio static char bbuf[16]; 10573eaf1285Sclaudio const unsigned long long kilo = 1000; 10583eaf1285Sclaudio const unsigned long long mega = 1000ULL * kilo; 10593eaf1285Sclaudio const unsigned long long giga = 1000ULL * mega; 10606e8089a5Sclaudio 10613eaf1285Sclaudio if (baudrate > giga) 10626e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu G%s", 10633eaf1285Sclaudio baudrate / giga, unit); 10643eaf1285Sclaudio else if (baudrate > mega) 10656e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu M%s", 10663eaf1285Sclaudio baudrate / mega, unit); 10673eaf1285Sclaudio else if (baudrate > kilo) 10686e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu K%s", 10693eaf1285Sclaudio baudrate / kilo, unit); 10706e8089a5Sclaudio else 10716e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu %s", 10726e8089a5Sclaudio baudrate, unit); 10736e8089a5Sclaudio 10746e8089a5Sclaudio return (bbuf); 10756e8089a5Sclaudio } 1076