1*e3db1f63Sclaudio /* $OpenBSD: util.c,v 1.92 2025/01/27 15:22:11 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 { 859ad78aa8Sclaudio static char buf[4][NI_MAXHOST]; 869ad78aa8Sclaudio static int bufidx; 872ffcd4e0Sclaudio 889ad78aa8Sclaudio bufidx = (bufidx + 1) % 4; 899ad78aa8Sclaudio if (sa == NULL || getnameinfo(sa, len, buf[bufidx], sizeof(buf[0]), 909ad78aa8Sclaudio NULL, 0, NI_NUMERICHOST)) 912ffcd4e0Sclaudio return ("(unknown)"); 922ffcd4e0Sclaudio else 939ad78aa8Sclaudio return (buf[bufidx]); 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: 134ec5cb450Sclaudio snprintf(buf, sizeof(buf), "rd #%016llx", 135ec5cb450Sclaudio (unsigned long long)rd); 136ec5cb450Sclaudio break; 137256b680eSclaudio } 138256b680eSclaudio return (buf); 139256b680eSclaudio } 140256b680eSclaudio 141bf8e2920Sclaudio const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES; 142bf8e2920Sclaudio 143256b680eSclaudio /* NOTE: this function does not check if the type/subtype combo is 144536f41e5Sclaudio * actually valid. */ 145536f41e5Sclaudio const char * 146f8162053Sclaudio log_ext_subtype(int type, uint8_t subtype) 147536f41e5Sclaudio { 148477ac4f1Sclaudio static char etype[16]; 149bf8e2920Sclaudio const struct ext_comm_pairs *cp; 150536f41e5Sclaudio 151bf8e2920Sclaudio for (cp = iana_ext_comms; cp->subname != NULL; cp++) { 1520e6216fdSclaudio if ((type == cp->type || type == -1) && subtype == cp->subtype) 153bf8e2920Sclaudio return (cp->subname); 154bf8e2920Sclaudio } 155477ac4f1Sclaudio if (type == -1) 156477ac4f1Sclaudio return ("???"); 157477ac4f1Sclaudio snprintf(etype, sizeof(etype), "[%hhx:%hhx]", (uint8_t)type, subtype); 158536f41e5Sclaudio return (etype); 159536f41e5Sclaudio } 160536f41e5Sclaudio 1611e590dcfSclaudio const char * 162a78f83ceSderaadt log_reason(const char *communication) { 163a78f83ceSderaadt static char buf[(REASON_LEN - 1) * 4 + 1]; 1640561b344Sphessler 1650561b344Sphessler strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL); 1660561b344Sphessler 1670561b344Sphessler return buf; 1680561b344Sphessler } 1690561b344Sphessler 1706290e740Sclaudio static const char * 1716290e740Sclaudio log_expires(time_t expires) 1726290e740Sclaudio { 1736290e740Sclaudio static char buf[32]; 1746290e740Sclaudio 1756290e740Sclaudio buf[0] = '\0'; 1766290e740Sclaudio if (expires != 0) 1776290e740Sclaudio snprintf(buf, sizeof(buf), " expires %lld", (long long)expires); 1786290e740Sclaudio return buf; 1796290e740Sclaudio } 1806290e740Sclaudio 1816290e740Sclaudio const char * 1826290e740Sclaudio log_roa(struct roa *roa) 1836290e740Sclaudio { 1846290e740Sclaudio static char buf[256]; 1856290e740Sclaudio char maxbuf[32]; 1862fd9f52dSmiod #if defined(__GNUC__) && __GNUC__ < 4 1872fd9f52dSmiod struct bgpd_addr addr = { .aid = roa->aid }; 1882fd9f52dSmiod addr.v6 = roa->prefix.inet6; 1892fd9f52dSmiod #else 1902fd9f52dSmiod struct bgpd_addr addr = { .aid = roa->aid, .v6 = roa->prefix.inet6 }; 1912fd9f52dSmiod #endif 1926290e740Sclaudio 1936290e740Sclaudio maxbuf[0] = '\0'; 1946290e740Sclaudio if (roa->prefixlen != roa->maxlen) 1956290e740Sclaudio snprintf(maxbuf, sizeof(maxbuf), " maxlen %u", roa->maxlen); 1966290e740Sclaudio snprintf(buf, sizeof(buf), "%s/%u%s source-as %u%s", log_addr(&addr), 1976290e740Sclaudio roa->prefixlen, maxbuf, roa->asnum, log_expires(roa->expires)); 1986290e740Sclaudio return buf; 1996290e740Sclaudio } 2006290e740Sclaudio 2016290e740Sclaudio const char * 2026290e740Sclaudio log_aspa(struct aspa_set *aspa) 2036290e740Sclaudio { 2046290e740Sclaudio static char errbuf[256]; 2056290e740Sclaudio static char *buf; 2066290e740Sclaudio static size_t len; 2076290e740Sclaudio char asbuf[16]; 2086290e740Sclaudio size_t needed; 2096290e740Sclaudio uint32_t i; 2106290e740Sclaudio 2116290e740Sclaudio /* include enough space for header and trailer */ 2126290e740Sclaudio if ((uint64_t)aspa->num > (SIZE_MAX / sizeof(asbuf) - 72)) 2136290e740Sclaudio goto fail; 2146290e740Sclaudio needed = aspa->num * sizeof(asbuf) + 72; 2156290e740Sclaudio if (needed > len) { 2166290e740Sclaudio char *nbuf; 2176290e740Sclaudio 2186290e740Sclaudio if ((nbuf = realloc(buf, needed)) == NULL) 2196290e740Sclaudio goto fail; 2206290e740Sclaudio len = needed; 2216290e740Sclaudio buf = nbuf; 2226290e740Sclaudio } 2236290e740Sclaudio 2246290e740Sclaudio snprintf(buf, len, "customer-as %s%s provider-as { ", 2256290e740Sclaudio log_as(aspa->as), log_expires(aspa->expires)); 2266290e740Sclaudio 2276290e740Sclaudio for (i = 0; i < aspa->num; i++) { 2286290e740Sclaudio snprintf(asbuf, sizeof(asbuf), "%s ", log_as(aspa->tas[i])); 2296290e740Sclaudio if (strlcat(buf, asbuf, len) >= len) 2306290e740Sclaudio goto fail; 2316290e740Sclaudio } 2326290e740Sclaudio if (strlcat(buf, "}", len) >= len) 2336290e740Sclaudio goto fail; 2346290e740Sclaudio return buf; 2356290e740Sclaudio 2366290e740Sclaudio fail: 2376290e740Sclaudio free(buf); 2386290e740Sclaudio buf = NULL; 2396290e740Sclaudio len = 0; 2406290e740Sclaudio snprintf(errbuf, sizeof(errbuf), "customer-as %s%s provider-as { ... }", 2416290e740Sclaudio log_as(aspa->as), log_expires(aspa->expires)); 2426290e740Sclaudio return errbuf; 2436290e740Sclaudio } 2446290e740Sclaudio 2450561b344Sphessler const char * 24604349dffSclaudio log_aspath_error(int error) 24704349dffSclaudio { 24804349dffSclaudio static char buf[20]; 24904349dffSclaudio 25004349dffSclaudio switch (error) { 25104349dffSclaudio case AS_ERR_LEN: 2529a8ba155Sjob return "inconsistent length"; 25304349dffSclaudio case AS_ERR_TYPE: 25404349dffSclaudio return "unknown segment type"; 25504349dffSclaudio case AS_ERR_BAD: 25604349dffSclaudio return "invalid encoding"; 25704349dffSclaudio case AS_ERR_SOFT: 25804349dffSclaudio return "soft failure"; 25904349dffSclaudio default: 26004349dffSclaudio snprintf(buf, sizeof(buf), "unknown %d", error); 26104349dffSclaudio return buf; 26204349dffSclaudio } 26304349dffSclaudio } 26404349dffSclaudio 26504349dffSclaudio const char * 266bd9df44eSclaudio log_rtr_error(enum rtr_error err) 267bd9df44eSclaudio { 268bd9df44eSclaudio static char buf[20]; 269bd9df44eSclaudio 270bd9df44eSclaudio switch (err) { 271bd9df44eSclaudio case NO_ERROR: 272bd9df44eSclaudio return "No Error"; 273bd9df44eSclaudio case CORRUPT_DATA: 274bd9df44eSclaudio return "Corrupt Data"; 275bd9df44eSclaudio case INTERNAL_ERROR: 276bd9df44eSclaudio return "Internal Error"; 277bd9df44eSclaudio case NO_DATA_AVAILABLE: 278bd9df44eSclaudio return "No Data Available"; 279bd9df44eSclaudio case INVALID_REQUEST: 280bd9df44eSclaudio return "Invalid Request"; 281bd9df44eSclaudio case UNSUPP_PROTOCOL_VERS: 282bd9df44eSclaudio return "Unsupported Protocol Version"; 283bd9df44eSclaudio case UNSUPP_PDU_TYPE: 284bd9df44eSclaudio return "Unsupported PDU Type"; 285bd9df44eSclaudio case UNK_REC_WDRAWL: 286f4123069Smbuhl return "Withdrawal of Unknown Record"; 287bd9df44eSclaudio case DUP_REC_RECV: 288bd9df44eSclaudio return "Duplicate Announcement Received"; 289bd9df44eSclaudio case UNEXP_PROTOCOL_VERS: 290bd9df44eSclaudio return "Unexpected Protocol Version"; 291bd9df44eSclaudio default: 292bd9df44eSclaudio snprintf(buf, sizeof(buf), "unknown %u", err); 293bd9df44eSclaudio return buf; 294bd9df44eSclaudio } 295bd9df44eSclaudio } 296bd9df44eSclaudio 297bd9df44eSclaudio const char * 298c0c94bccSclaudio log_policy(enum role role) 299202e5273Stb { 300202e5273Stb switch (role) { 301c0c94bccSclaudio case ROLE_PROVIDER: 302202e5273Stb return "provider"; 303c0c94bccSclaudio case ROLE_RS: 304202e5273Stb return "rs"; 305c0c94bccSclaudio case ROLE_RS_CLIENT: 306202e5273Stb return "rs-client"; 307c0c94bccSclaudio case ROLE_CUSTOMER: 308202e5273Stb return "customer"; 309c0c94bccSclaudio case ROLE_PEER: 310202e5273Stb return "peer"; 311202e5273Stb default: 312202e5273Stb return "unknown"; 313202e5273Stb } 314202e5273Stb } 315202e5273Stb 316beb044e9Sclaudio const char * 317beb044e9Sclaudio log_capability(uint8_t capa) 318beb044e9Sclaudio { 319beb044e9Sclaudio static char buf[20]; 320beb044e9Sclaudio 321beb044e9Sclaudio switch (capa) { 322beb044e9Sclaudio case CAPA_MP: 323beb044e9Sclaudio return "Multiprotocol Extensions"; 324beb044e9Sclaudio case CAPA_REFRESH: 325beb044e9Sclaudio return "Route Refresh"; 326000b2be6Sclaudio case CAPA_EXT_NEXTHOP: 327000b2be6Sclaudio return "Extended Nexhop Encoding"; 32844f660feSclaudio case CAPA_EXT_MSG: 32944f660feSclaudio return "Extended Message"; 330beb044e9Sclaudio case CAPA_ROLE: 331beb044e9Sclaudio return "BGP Role"; 332beb044e9Sclaudio case CAPA_RESTART: 333beb044e9Sclaudio return "Graceful Restart"; 334beb044e9Sclaudio case CAPA_AS4BYTE: 335beb044e9Sclaudio return "4-octet AS number"; 336beb044e9Sclaudio case CAPA_ADD_PATH: 337beb044e9Sclaudio return "ADD-PATH"; 338beb044e9Sclaudio case CAPA_ENHANCED_RR: 339beb044e9Sclaudio return "Enhanced Route Refresh"; 340beb044e9Sclaudio default: 341beb044e9Sclaudio snprintf(buf, sizeof(buf), "unknown %u", capa); 342beb044e9Sclaudio return buf; 343beb044e9Sclaudio } 344beb044e9Sclaudio } 345beb044e9Sclaudio 34604349dffSclaudio static const char * 34739386878Sclaudio aspath_delim(uint8_t seg_type, int closing) 3481e590dcfSclaudio { 3491e590dcfSclaudio static char db[8]; 3501e590dcfSclaudio 3511e590dcfSclaudio switch (seg_type) { 3521e590dcfSclaudio case AS_SET: 3531e590dcfSclaudio if (!closing) 3541e590dcfSclaudio return ("{ "); 3551e590dcfSclaudio else 3561e590dcfSclaudio return (" }"); 3571e590dcfSclaudio case AS_SEQUENCE: 3581e590dcfSclaudio return (""); 3591e590dcfSclaudio case AS_CONFED_SEQUENCE: 3601e590dcfSclaudio if (!closing) 3611e590dcfSclaudio return ("( "); 3621e590dcfSclaudio else 3631e590dcfSclaudio return (" )"); 3641e590dcfSclaudio case AS_CONFED_SET: 3651e590dcfSclaudio if (!closing) 3661e590dcfSclaudio return ("[ "); 3671e590dcfSclaudio else 3681e590dcfSclaudio return (" ]"); 3691e590dcfSclaudio default: 3701e590dcfSclaudio if (!closing) 3711e590dcfSclaudio snprintf(db, sizeof(db), "!%u ", seg_type); 3721e590dcfSclaudio else 3731e590dcfSclaudio snprintf(db, sizeof(db), " !%u", seg_type); 3741e590dcfSclaudio return (db); 3751e590dcfSclaudio } 3761e590dcfSclaudio } 3771e590dcfSclaudio 37804349dffSclaudio static int 37904349dffSclaudio aspath_snprint(char *buf, size_t size, struct ibuf *in) 3802ffcd4e0Sclaudio { 3812ffcd4e0Sclaudio #define UPDATE() \ 3822ffcd4e0Sclaudio do { \ 38304349dffSclaudio if (r < 0 || (unsigned int)r >= size) \ 3842ffcd4e0Sclaudio return (-1); \ 3852ffcd4e0Sclaudio size -= r; \ 3862ffcd4e0Sclaudio buf += r; \ 3872ffcd4e0Sclaudio } while (0) 38804349dffSclaudio 38904349dffSclaudio struct ibuf data; 39004349dffSclaudio uint32_t as; 39104349dffSclaudio int r, n = 0; 39239386878Sclaudio uint8_t i, seg_type, seg_len; 3932ffcd4e0Sclaudio 39404349dffSclaudio ibuf_from_ibuf(&data, in); 39504349dffSclaudio while (ibuf_size(&data) > 0) { 39604349dffSclaudio if (ibuf_get_n8(&data, &seg_type) == -1 || 39704349dffSclaudio ibuf_get_n8(&data, &seg_len) == -1 || 39804349dffSclaudio seg_len == 0) 39904349dffSclaudio return (-1); 4002ffcd4e0Sclaudio 40104349dffSclaudio r = snprintf(buf, size, "%s%s", n++ != 0 ? " " : "", 4021e590dcfSclaudio aspath_delim(seg_type, 0)); 4032ffcd4e0Sclaudio UPDATE(); 4042ffcd4e0Sclaudio 4052ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) { 40604349dffSclaudio if (ibuf_get_n32(&data, &as) == -1) 40704349dffSclaudio return -1; 40804349dffSclaudio 40904349dffSclaudio r = snprintf(buf, size, "%s", log_as(as)); 4102ffcd4e0Sclaudio UPDATE(); 4112ffcd4e0Sclaudio if (i + 1 < seg_len) { 4122ffcd4e0Sclaudio r = snprintf(buf, size, " "); 4132ffcd4e0Sclaudio UPDATE(); 4142ffcd4e0Sclaudio } 4152ffcd4e0Sclaudio } 4161e590dcfSclaudio r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1)); 4172ffcd4e0Sclaudio UPDATE(); 4182ffcd4e0Sclaudio } 41955e49665Sclaudio /* ensure that we have a valid C-string especially for empty as path */ 4202ffcd4e0Sclaudio *buf = '\0'; 42104349dffSclaudio return (0); 4222ffcd4e0Sclaudio #undef UPDATE 4232ffcd4e0Sclaudio } 4242ffcd4e0Sclaudio 42504349dffSclaudio static ssize_t 42604349dffSclaudio aspath_strsize(struct ibuf *in) 4272ffcd4e0Sclaudio { 42804349dffSclaudio struct ibuf buf; 42904349dffSclaudio ssize_t total_size = 0; 43039386878Sclaudio uint32_t as; 43139386878Sclaudio uint8_t i, seg_type, seg_len; 4322ffcd4e0Sclaudio 43304349dffSclaudio ibuf_from_ibuf(&buf, in); 43404349dffSclaudio while (ibuf_size(&buf) > 0) { 43504349dffSclaudio if (ibuf_get_n8(&buf, &seg_type) == -1 || 43604349dffSclaudio ibuf_get_n8(&buf, &seg_len) == -1 || 43704349dffSclaudio seg_len == 0) 43804349dffSclaudio return (-1); 4392ffcd4e0Sclaudio 4402ffcd4e0Sclaudio if (total_size != 0) 4412ffcd4e0Sclaudio total_size += 1; 44204349dffSclaudio total_size += strlen(aspath_delim(seg_type, 0)); 4432ffcd4e0Sclaudio 4442ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) { 44504349dffSclaudio if (ibuf_get_n32(&buf, &as) == -1) 44604349dffSclaudio return (-1); 4470c88bf70Sclaudio 4488db4f5d2Sclaudio do { 4498db4f5d2Sclaudio total_size++; 4508db4f5d2Sclaudio } while ((as = as / 10) != 0); 45104349dffSclaudio } 45204349dffSclaudio total_size += seg_len - 1; 4532ffcd4e0Sclaudio 45404349dffSclaudio total_size += strlen(aspath_delim(seg_type, 1)); 45504349dffSclaudio } 45604349dffSclaudio return (total_size + 1); 4572ffcd4e0Sclaudio } 4582ffcd4e0Sclaudio 45904349dffSclaudio int 46004349dffSclaudio aspath_asprint(char **ret, struct ibuf *data) 46104349dffSclaudio { 46204349dffSclaudio ssize_t slen; 46304349dffSclaudio 46404349dffSclaudio if ((slen = aspath_strsize(data)) == -1) { 46504349dffSclaudio *ret = NULL; 46604349dffSclaudio errno = EINVAL; 46704349dffSclaudio return (-1); 4682ffcd4e0Sclaudio } 46904349dffSclaudio 47004349dffSclaudio *ret = malloc(slen); 47104349dffSclaudio if (*ret == NULL) 47204349dffSclaudio return (-1); 47304349dffSclaudio 47404349dffSclaudio if (aspath_snprint(*ret, slen, data) == -1) { 47504349dffSclaudio free(*ret); 47604349dffSclaudio *ret = NULL; 47704349dffSclaudio errno = EINVAL; 47804349dffSclaudio return (-1); 47904349dffSclaudio } 48004349dffSclaudio 48104349dffSclaudio return (0); 4822ffcd4e0Sclaudio } 4832ffcd4e0Sclaudio 4842ffcd4e0Sclaudio /* 4852ffcd4e0Sclaudio * Extract the asnum out of the as segment at the specified position. 4862ffcd4e0Sclaudio * Direct access is not possible because of non-aligned reads. 487506f72cfSclaudio * Only works on verified 4-byte AS paths. 4882ffcd4e0Sclaudio */ 48939386878Sclaudio uint32_t 4902ffcd4e0Sclaudio aspath_extract(const void *seg, int pos) 4912ffcd4e0Sclaudio { 4922ffcd4e0Sclaudio const u_char *ptr = seg; 49339386878Sclaudio uint32_t as; 4942ffcd4e0Sclaudio 495506f72cfSclaudio /* minimal pos check, return 0 since that is an invalid ASN */ 496506f72cfSclaudio if (pos < 0 || pos >= ptr[1]) 497506f72cfSclaudio return (0); 49839386878Sclaudio ptr += 2 + sizeof(uint32_t) * pos; 49939386878Sclaudio memcpy(&as, ptr, sizeof(uint32_t)); 5000c88bf70Sclaudio return (ntohl(as)); 5012ffcd4e0Sclaudio } 50221a825c9Sclaudio 503de5c2eedSclaudio /* 50429328a94Sclaudio * Verify that the aspath is correctly encoded. 50529328a94Sclaudio */ 50629328a94Sclaudio int 507*e3db1f63Sclaudio aspath_verify(struct ibuf *in, int as4byte, int permit_set) 50829328a94Sclaudio { 50904349dffSclaudio struct ibuf buf; 51004349dffSclaudio int pos, error = 0; 51139386878Sclaudio uint8_t seg_len, seg_type; 51229328a94Sclaudio 51304349dffSclaudio ibuf_from_ibuf(&buf, in); 51404349dffSclaudio if (ibuf_size(&buf) & 1) { 51529328a94Sclaudio /* odd length aspath are invalid */ 51604349dffSclaudio error = AS_ERR_BAD; 51704349dffSclaudio goto done; 51804349dffSclaudio } 51929328a94Sclaudio 52004349dffSclaudio while (ibuf_size(&buf) > 0) { 52104349dffSclaudio if (ibuf_get_n8(&buf, &seg_type) == -1 || 52204349dffSclaudio ibuf_get_n8(&buf, &seg_len) == -1) { 52304349dffSclaudio error = AS_ERR_LEN; 52404349dffSclaudio goto done; 52504349dffSclaudio } 52629328a94Sclaudio 52704349dffSclaudio if (seg_len == 0) { 528d04df938Sclaudio /* empty aspath segments are not allowed */ 52904349dffSclaudio error = AS_ERR_BAD; 53004349dffSclaudio goto done; 53104349dffSclaudio } 532d04df938Sclaudio 53329328a94Sclaudio /* 53429328a94Sclaudio * BGP confederations should not show up but consider them 53529328a94Sclaudio * as a soft error which invalidates the path but keeps the 53629328a94Sclaudio * bgp session running. 53729328a94Sclaudio */ 53829328a94Sclaudio if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET) 53929328a94Sclaudio error = AS_ERR_SOFT; 540aa528464Sclaudio /* 541aa528464Sclaudio * If AS_SET filtering (RFC6472) is on, error out on AS_SET 542aa528464Sclaudio * as well. 543aa528464Sclaudio */ 544*e3db1f63Sclaudio if (!permit_set && seg_type == AS_SET) 545aa528464Sclaudio error = AS_ERR_SOFT; 54629328a94Sclaudio if (seg_type != AS_SET && seg_type != AS_SEQUENCE && 54704349dffSclaudio seg_type != AS_CONFED_SEQUENCE && 54804349dffSclaudio seg_type != AS_CONFED_SET) { 54904349dffSclaudio error = AS_ERR_TYPE; 55004349dffSclaudio goto done; 55104349dffSclaudio } 55229328a94Sclaudio 55329328a94Sclaudio /* RFC 7607 - AS 0 is considered malformed */ 55429328a94Sclaudio for (pos = 0; pos < seg_len; pos++) { 55539386878Sclaudio uint32_t as; 55629328a94Sclaudio 55704349dffSclaudio if (as4byte) { 55804349dffSclaudio if (ibuf_get_n32(&buf, &as) == -1) { 55904349dffSclaudio error = AS_ERR_LEN; 56004349dffSclaudio goto done; 56104349dffSclaudio } 56204349dffSclaudio } else { 56304349dffSclaudio uint16_t tmp; 56404349dffSclaudio if (ibuf_get_n16(&buf, &tmp) == -1) { 56504349dffSclaudio error = AS_ERR_LEN; 56604349dffSclaudio goto done; 56704349dffSclaudio } 56804349dffSclaudio as = tmp; 56904349dffSclaudio } 57029328a94Sclaudio if (as == 0) 57156a9a1b8Sclaudio error = AS_ERR_SOFT; 57229328a94Sclaudio } 57329328a94Sclaudio } 57404349dffSclaudio 57504349dffSclaudio done: 57629328a94Sclaudio return (error); /* aspath is valid but probably not loop free */ 57729328a94Sclaudio } 57829328a94Sclaudio 57929328a94Sclaudio /* 58029328a94Sclaudio * convert a 2 byte aspath to a 4 byte one. 58129328a94Sclaudio */ 58204349dffSclaudio struct ibuf * 58304349dffSclaudio aspath_inflate(struct ibuf *in) 58429328a94Sclaudio { 58504349dffSclaudio struct ibuf *out; 58604349dffSclaudio uint16_t short_as; 58704349dffSclaudio uint8_t seg_type, seg_len; 58829328a94Sclaudio 5894ac10ff8Sclaudio /* 5904ac10ff8Sclaudio * Allocate enough space for the worst case. 5914ac10ff8Sclaudio * XXX add 1 byte for the empty ASPATH case since we can't 5924ac10ff8Sclaudio * allocate an ibuf of 0 length. 5934ac10ff8Sclaudio */ 5944ac10ff8Sclaudio if ((out = ibuf_open(ibuf_size(in) * 2 + 1)) == NULL) 59529328a94Sclaudio return (NULL); 59629328a94Sclaudio 59729328a94Sclaudio /* then copy the aspath */ 59804349dffSclaudio while (ibuf_size(in) > 0) { 59904349dffSclaudio if (ibuf_get_n8(in, &seg_type) == -1 || 60004349dffSclaudio ibuf_get_n8(in, &seg_len) == -1 || 60104349dffSclaudio seg_len == 0) 60204349dffSclaudio goto fail; 60304349dffSclaudio if (ibuf_add_n8(out, seg_type) == -1 || 60404349dffSclaudio ibuf_add_n8(out, seg_len) == -1) 60504349dffSclaudio goto fail; 60604349dffSclaudio 60729328a94Sclaudio for (; seg_len > 0; seg_len--) { 60804349dffSclaudio if (ibuf_get_n16(in, &short_as) == -1) 60904349dffSclaudio goto fail; 61004349dffSclaudio if (ibuf_add_n32(out, short_as) == -1) 61104349dffSclaudio goto fail; 61229328a94Sclaudio } 61329328a94Sclaudio } 61429328a94Sclaudio 61504349dffSclaudio return (out); 61604349dffSclaudio 61704349dffSclaudio fail: 61804349dffSclaudio ibuf_free(out); 61904349dffSclaudio return (NULL); 62029328a94Sclaudio } 62129328a94Sclaudio 6225c4d2233Sclaudio static const u_char addrmask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 6235c4d2233Sclaudio 0xf8, 0xfc, 0xfe, 0xff }; 6245c4d2233Sclaudio 6256d3e8673Sclaudio /* NLRI functions to extract prefixes from the NLRI blobs */ 6260f144400Sclaudio int 6270f144400Sclaudio extract_prefix(const u_char *p, int len, void *va, uint8_t pfxlen, uint8_t max) 6286d3e8673Sclaudio { 6296d3e8673Sclaudio u_char *a = va; 6303f0f322fSclaudio int plen; 6316d3e8673Sclaudio 6323f0f322fSclaudio plen = PREFIX_SIZE(pfxlen) - 1; 6333f0f322fSclaudio if (len < plen || max < plen) 6343f0f322fSclaudio return -1; 6353f0f322fSclaudio 6363f0f322fSclaudio while (pfxlen > 0) { 6376d3e8673Sclaudio if (pfxlen < 8) { 6383f0f322fSclaudio *a++ = *p++ & addrmask[pfxlen]; 6396d3e8673Sclaudio break; 6406d3e8673Sclaudio } else { 6413f0f322fSclaudio *a++ = *p++; 6426d3e8673Sclaudio pfxlen -= 8; 6436d3e8673Sclaudio } 6446d3e8673Sclaudio } 6456d3e8673Sclaudio return (plen); 6466d3e8673Sclaudio } 6476d3e8673Sclaudio 6485c4d2233Sclaudio static int 6495c4d2233Sclaudio extract_prefix_buf(struct ibuf *buf, void *va, uint8_t pfxlen, uint8_t max) 6506d3e8673Sclaudio { 6515c4d2233Sclaudio u_char *a = va; 6525c4d2233Sclaudio unsigned int plen; 6535c4d2233Sclaudio uint8_t tmp; 6545c4d2233Sclaudio 6555c4d2233Sclaudio plen = PREFIX_SIZE(pfxlen) - 1; 6565c4d2233Sclaudio if (ibuf_size(buf) < plen || max < plen) 6575c4d2233Sclaudio return -1; 6585c4d2233Sclaudio 6595c4d2233Sclaudio while (pfxlen > 0) { 6605c4d2233Sclaudio if (ibuf_get_n8(buf, &tmp) == -1) 6615c4d2233Sclaudio return -1; 6625c4d2233Sclaudio 6635c4d2233Sclaudio if (pfxlen < 8) { 6645c4d2233Sclaudio *a++ = tmp & addrmask[pfxlen]; 6655c4d2233Sclaudio break; 6665c4d2233Sclaudio } else { 6675c4d2233Sclaudio *a++ = tmp; 6685c4d2233Sclaudio pfxlen -= 8; 6695c4d2233Sclaudio } 6705c4d2233Sclaudio } 6715c4d2233Sclaudio return (0); 6725c4d2233Sclaudio } 6735c4d2233Sclaudio 6745c4d2233Sclaudio int 6755c4d2233Sclaudio nlri_get_prefix(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen) 6765c4d2233Sclaudio { 67739386878Sclaudio uint8_t pfxlen; 6786d3e8673Sclaudio 6795c4d2233Sclaudio if (ibuf_get_n8(buf, &pfxlen) == -1) 6806d3e8673Sclaudio return (-1); 6815c4d2233Sclaudio if (pfxlen > 32) 6825c4d2233Sclaudio return (-1); 6836d3e8673Sclaudio 684eafe309eSclaudio memset(prefix, 0, sizeof(struct bgpd_addr)); 6856d3e8673Sclaudio prefix->aid = AID_INET; 6865c4d2233Sclaudio 6875c4d2233Sclaudio if (extract_prefix_buf(buf, &prefix->v4, pfxlen, 6885c4d2233Sclaudio sizeof(prefix->v4)) == -1) 6895c4d2233Sclaudio return (-1); 6905c4d2233Sclaudio 6916d3e8673Sclaudio *prefixlen = pfxlen; 6925c4d2233Sclaudio return (0); 6936d3e8673Sclaudio } 6946d3e8673Sclaudio 6956d3e8673Sclaudio int 6965c4d2233Sclaudio nlri_get_prefix6(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen) 6976d3e8673Sclaudio { 69839386878Sclaudio uint8_t pfxlen; 6996d3e8673Sclaudio 7005c4d2233Sclaudio if (ibuf_get_n8(buf, &pfxlen) == -1) 7016d3e8673Sclaudio return (-1); 7025c4d2233Sclaudio if (pfxlen > 128) 7035c4d2233Sclaudio return (-1); 7046d3e8673Sclaudio 705eafe309eSclaudio memset(prefix, 0, sizeof(struct bgpd_addr)); 7066d3e8673Sclaudio prefix->aid = AID_INET6; 7075c4d2233Sclaudio 7085c4d2233Sclaudio if (extract_prefix_buf(buf, &prefix->v6, pfxlen, 7095c4d2233Sclaudio sizeof(prefix->v6)) == -1) 7105c4d2233Sclaudio return (-1); 7115c4d2233Sclaudio 7126d3e8673Sclaudio *prefixlen = pfxlen; 7135c4d2233Sclaudio return (0); 7146d3e8673Sclaudio } 7156d3e8673Sclaudio 7166d3e8673Sclaudio int 7175c4d2233Sclaudio nlri_get_vpn4(struct ibuf *buf, struct bgpd_addr *prefix, 71839386878Sclaudio uint8_t *prefixlen, int withdraw) 7196d3e8673Sclaudio { 7205c4d2233Sclaudio int done = 0; 72139386878Sclaudio uint8_t pfxlen; 7226d3e8673Sclaudio 7235c4d2233Sclaudio if (ibuf_get_n8(buf, &pfxlen) == -1) 7246d3e8673Sclaudio return (-1); 7256d3e8673Sclaudio 726eafe309eSclaudio memset(prefix, 0, sizeof(struct bgpd_addr)); 7275c4d2233Sclaudio prefix->aid = AID_VPN_IPv4; 7286d3e8673Sclaudio 7296d3e8673Sclaudio /* label stack */ 7306d3e8673Sclaudio do { 7315c4d2233Sclaudio if (prefix->labellen + 3U > sizeof(prefix->labelstack) || 7325c4d2233Sclaudio pfxlen < 3 * 8) 7336d3e8673Sclaudio return (-1); 7346d3e8673Sclaudio if (withdraw) { 7356d3e8673Sclaudio /* on withdraw ignore the labelstack all together */ 7365c4d2233Sclaudio if (ibuf_skip(buf, 3) == -1) 7375c4d2233Sclaudio return (-1); 7386d3e8673Sclaudio pfxlen -= 3 * 8; 7396d3e8673Sclaudio break; 7406d3e8673Sclaudio } 7415c4d2233Sclaudio if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) == 7425c4d2233Sclaudio -1) 7435c4d2233Sclaudio return -1; 7445c4d2233Sclaudio if (prefix->labelstack[prefix->labellen + 2] & 7456d3e8673Sclaudio BGP_MPLS_BOS) 7466d3e8673Sclaudio done = 1; 7475c4d2233Sclaudio prefix->labellen += 3; 7486d3e8673Sclaudio pfxlen -= 3 * 8; 7496d3e8673Sclaudio } while (!done); 7506d3e8673Sclaudio 7516d3e8673Sclaudio /* RD */ 7525c4d2233Sclaudio if (pfxlen < sizeof(uint64_t) * 8 || 7535c4d2233Sclaudio ibuf_get_h64(buf, &prefix->rd) == -1) 7546d3e8673Sclaudio return (-1); 75539386878Sclaudio pfxlen -= sizeof(uint64_t) * 8; 7566d3e8673Sclaudio 7576d3e8673Sclaudio /* prefix */ 7586d3e8673Sclaudio if (pfxlen > 32) 7596d3e8673Sclaudio return (-1); 7605c4d2233Sclaudio if (extract_prefix_buf(buf, &prefix->v4, pfxlen, 7615c4d2233Sclaudio sizeof(prefix->v4)) == -1) 7626d3e8673Sclaudio return (-1); 7636d3e8673Sclaudio 7645c4d2233Sclaudio *prefixlen = pfxlen; 7655c4d2233Sclaudio return (0); 7666d3e8673Sclaudio } 7676d3e8673Sclaudio 768290f96faSdenis int 7695c4d2233Sclaudio nlri_get_vpn6(struct ibuf *buf, struct bgpd_addr *prefix, 77039386878Sclaudio uint8_t *prefixlen, int withdraw) 771290f96faSdenis { 7725c4d2233Sclaudio int done = 0; 77339386878Sclaudio uint8_t pfxlen; 774290f96faSdenis 7755c4d2233Sclaudio if (ibuf_get_n8(buf, &pfxlen) == -1) 776290f96faSdenis return (-1); 777290f96faSdenis 778290f96faSdenis memset(prefix, 0, sizeof(struct bgpd_addr)); 7795c4d2233Sclaudio prefix->aid = AID_VPN_IPv6; 780290f96faSdenis 781290f96faSdenis /* label stack */ 782290f96faSdenis do { 7835c4d2233Sclaudio if (prefix->labellen + 3U > sizeof(prefix->labelstack) || 7845c4d2233Sclaudio pfxlen < 3 * 8) 785290f96faSdenis return (-1); 786290f96faSdenis if (withdraw) { 787290f96faSdenis /* on withdraw ignore the labelstack all together */ 7885c4d2233Sclaudio if (ibuf_skip(buf, 3) == -1) 7895c4d2233Sclaudio return (-1); 790290f96faSdenis pfxlen -= 3 * 8; 791290f96faSdenis break; 792290f96faSdenis } 793290f96faSdenis 7945c4d2233Sclaudio if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) == 7955c4d2233Sclaudio -1) 7965c4d2233Sclaudio return (-1); 7975c4d2233Sclaudio if (prefix->labelstack[prefix->labellen + 2] & 798290f96faSdenis BGP_MPLS_BOS) 799290f96faSdenis done = 1; 8005c4d2233Sclaudio prefix->labellen += 3; 801290f96faSdenis pfxlen -= 3 * 8; 802290f96faSdenis } while (!done); 803290f96faSdenis 804290f96faSdenis /* RD */ 8055c4d2233Sclaudio if (pfxlen < sizeof(uint64_t) * 8 || 8065c4d2233Sclaudio ibuf_get_h64(buf, &prefix->rd) == -1) 807290f96faSdenis return (-1); 80839386878Sclaudio pfxlen -= sizeof(uint64_t) * 8; 809290f96faSdenis 810290f96faSdenis /* prefix */ 811290f96faSdenis if (pfxlen > 128) 812290f96faSdenis return (-1); 8135c4d2233Sclaudio if (extract_prefix_buf(buf, &prefix->v6, pfxlen, 8145c4d2233Sclaudio sizeof(prefix->v6)) == -1) 815290f96faSdenis return (-1); 816290f96faSdenis 8175c4d2233Sclaudio *prefixlen = pfxlen; 8185c4d2233Sclaudio return (0); 819290f96faSdenis } 820290f96faSdenis 821fa3a38bbSclaudio static in_addr_t 822fa3a38bbSclaudio prefixlen2mask(uint8_t prefixlen) 823fa3a38bbSclaudio { 824fa3a38bbSclaudio if (prefixlen == 0) 825fa3a38bbSclaudio return (0); 826290f96faSdenis 827fa3a38bbSclaudio return (0xffffffff << (32 - prefixlen)); 828fa3a38bbSclaudio } 829290f96faSdenis 83029328a94Sclaudio /* 831de5c2eedSclaudio * This function will have undefined behaviour if the passed in prefixlen is 832290f96faSdenis * too large for the respective bgpd_addr address family. 833de5c2eedSclaudio */ 834fafbb788Sclaudio int 835fafbb788Sclaudio prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, 836fafbb788Sclaudio int prefixlen) 837fafbb788Sclaudio { 838fafbb788Sclaudio in_addr_t mask, aa, ba; 839fafbb788Sclaudio int i; 84039386878Sclaudio uint8_t m; 841fafbb788Sclaudio 842fafbb788Sclaudio if (a->aid != b->aid) 843fafbb788Sclaudio return (a->aid - b->aid); 844fafbb788Sclaudio 845fafbb788Sclaudio switch (a->aid) { 8463038d3d1Sclaudio case AID_VPN_IPv4: 8473038d3d1Sclaudio if (be64toh(a->rd) > be64toh(b->rd)) 8483038d3d1Sclaudio return (1); 8493038d3d1Sclaudio if (be64toh(a->rd) < be64toh(b->rd)) 8503038d3d1Sclaudio return (-1); 8513038d3d1Sclaudio /* FALLTHROUGH */ 852fafbb788Sclaudio case AID_INET: 8537da59fecSclaudio if (prefixlen == 0) 8547da59fecSclaudio return (0); 855fafbb788Sclaudio if (prefixlen > 32) 856de5c2eedSclaudio return (-1); 857fafbb788Sclaudio mask = htonl(prefixlen2mask(prefixlen)); 858fafbb788Sclaudio aa = ntohl(a->v4.s_addr & mask); 859fafbb788Sclaudio ba = ntohl(b->v4.s_addr & mask); 8603038d3d1Sclaudio if (aa > ba) 8613038d3d1Sclaudio return (1); 8623038d3d1Sclaudio if (aa < ba) 8633038d3d1Sclaudio return (-1); 8643038d3d1Sclaudio break; 8653038d3d1Sclaudio case AID_VPN_IPv6: 8663038d3d1Sclaudio if (be64toh(a->rd) > be64toh(b->rd)) 8673038d3d1Sclaudio return (1); 8683038d3d1Sclaudio if (be64toh(a->rd) < be64toh(b->rd)) 8693038d3d1Sclaudio return (-1); 8703038d3d1Sclaudio /* FALLTHROUGH */ 871fafbb788Sclaudio case AID_INET6: 8727da59fecSclaudio if (prefixlen == 0) 8737da59fecSclaudio return (0); 874fafbb788Sclaudio if (prefixlen > 128) 875de5c2eedSclaudio return (-1); 876fafbb788Sclaudio for (i = 0; i < prefixlen / 8; i++) 877fafbb788Sclaudio if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 878fafbb788Sclaudio return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 879fafbb788Sclaudio i = prefixlen % 8; 880fafbb788Sclaudio if (i) { 881fafbb788Sclaudio m = 0xff00 >> i; 882fafbb788Sclaudio if ((a->v6.s6_addr[prefixlen / 8] & m) != 883fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m)) 884fafbb788Sclaudio return ((a->v6.s6_addr[prefixlen / 8] & m) - 885fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m)); 886fafbb788Sclaudio } 8873038d3d1Sclaudio break; 8883038d3d1Sclaudio default: 8893038d3d1Sclaudio return (-1); 8903038d3d1Sclaudio } 8913038d3d1Sclaudio 8923038d3d1Sclaudio if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) { 8933038d3d1Sclaudio if (a->labellen > b->labellen) 8943038d3d1Sclaudio return (1); 8953038d3d1Sclaudio if (a->labellen < b->labellen) 8963038d3d1Sclaudio return (-1); 8973038d3d1Sclaudio return (memcmp(a->labelstack, b->labelstack, a->labellen)); 8983038d3d1Sclaudio } 899fafbb788Sclaudio return (0); 9003038d3d1Sclaudio 901fafbb788Sclaudio } 902fafbb788Sclaudio 90321a825c9Sclaudio void 9042b5c88feSclaudio inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen) 9052b5c88feSclaudio { 9062b5c88feSclaudio struct in_addr mask; 9072b5c88feSclaudio 9082b5c88feSclaudio mask.s_addr = htonl(prefixlen2mask(prefixlen)); 9092b5c88feSclaudio dest->s_addr = src->s_addr & mask.s_addr; 9102b5c88feSclaudio } 9112b5c88feSclaudio 9122b5c88feSclaudio void 91321a825c9Sclaudio inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 91421a825c9Sclaudio { 91521a825c9Sclaudio struct in6_addr mask; 91621a825c9Sclaudio int i; 91721a825c9Sclaudio 918eafe309eSclaudio memset(&mask, 0, sizeof(mask)); 91921a825c9Sclaudio for (i = 0; i < prefixlen / 8; i++) 92021a825c9Sclaudio mask.s6_addr[i] = 0xff; 92121a825c9Sclaudio i = prefixlen % 8; 92221a825c9Sclaudio if (i) 92321a825c9Sclaudio mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 92421a825c9Sclaudio 92521a825c9Sclaudio for (i = 0; i < 16; i++) 92621a825c9Sclaudio dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 92721a825c9Sclaudio } 928d6c2e4e8Sclaudio 92913bcf54fSclaudio void 93013bcf54fSclaudio applymask(struct bgpd_addr *dest, const struct bgpd_addr *src, int prefixlen) 93113bcf54fSclaudio { 93213bcf54fSclaudio *dest = *src; 93313bcf54fSclaudio switch (src->aid) { 93413bcf54fSclaudio case AID_INET: 93513bcf54fSclaudio case AID_VPN_IPv4: 93613bcf54fSclaudio inet4applymask(&dest->v4, &src->v4, prefixlen); 93713bcf54fSclaudio break; 93813bcf54fSclaudio case AID_INET6: 93913bcf54fSclaudio case AID_VPN_IPv6: 94013bcf54fSclaudio inet6applymask(&dest->v6, &src->v6, prefixlen); 94113bcf54fSclaudio break; 94213bcf54fSclaudio } 94313bcf54fSclaudio } 94413bcf54fSclaudio 945d6c2e4e8Sclaudio /* address family translation functions */ 946d6c2e4e8Sclaudio const struct aid aid_vals[AID_MAX] = AID_VALS; 947d6c2e4e8Sclaudio 94886729c90Sclaudio const char * 94939386878Sclaudio aid2str(uint8_t aid) 95086729c90Sclaudio { 95186729c90Sclaudio if (aid < AID_MAX) 95286729c90Sclaudio return (aid_vals[aid].name); 95386729c90Sclaudio return ("unknown AID"); 95486729c90Sclaudio } 95586729c90Sclaudio 956d6c2e4e8Sclaudio int 95739386878Sclaudio aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi) 958d6c2e4e8Sclaudio { 959110c1584Sclaudio if (aid != AID_UNSPEC && aid < AID_MAX) { 960d6c2e4e8Sclaudio *afi = aid_vals[aid].afi; 961d6c2e4e8Sclaudio *safi = aid_vals[aid].safi; 962d6c2e4e8Sclaudio return (0); 963d6c2e4e8Sclaudio } 964d6c2e4e8Sclaudio return (-1); 965d6c2e4e8Sclaudio } 966d6c2e4e8Sclaudio 967d6c2e4e8Sclaudio int 96839386878Sclaudio afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid) 969d6c2e4e8Sclaudio { 97039386878Sclaudio uint8_t i; 971d6c2e4e8Sclaudio 972110c1584Sclaudio for (i = AID_MIN; i < AID_MAX; i++) 973d6c2e4e8Sclaudio if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) { 974d6c2e4e8Sclaudio *aid = i; 975d6c2e4e8Sclaudio return (0); 976d6c2e4e8Sclaudio } 977d6c2e4e8Sclaudio 978d6c2e4e8Sclaudio return (-1); 979d6c2e4e8Sclaudio } 980d6c2e4e8Sclaudio 981d6c2e4e8Sclaudio sa_family_t 98239386878Sclaudio aid2af(uint8_t aid) 983d6c2e4e8Sclaudio { 984d6c2e4e8Sclaudio if (aid < AID_MAX) 985d6c2e4e8Sclaudio return (aid_vals[aid].af); 986d6c2e4e8Sclaudio return (AF_UNSPEC); 987d6c2e4e8Sclaudio } 988d6c2e4e8Sclaudio 989d6c2e4e8Sclaudio int 99039386878Sclaudio af2aid(sa_family_t af, uint8_t safi, uint8_t *aid) 991d6c2e4e8Sclaudio { 99239386878Sclaudio uint8_t i; 993d6c2e4e8Sclaudio 994d6c2e4e8Sclaudio if (safi == 0) /* default to unicast subclass */ 995d6c2e4e8Sclaudio safi = SAFI_UNICAST; 996d6c2e4e8Sclaudio 997110c1584Sclaudio for (i = AID_UNSPEC; i < AID_MAX; i++) 998d6c2e4e8Sclaudio if (aid_vals[i].af == af && aid_vals[i].safi == safi) { 999d6c2e4e8Sclaudio *aid = i; 1000d6c2e4e8Sclaudio return (0); 1001d6c2e4e8Sclaudio } 1002d6c2e4e8Sclaudio 1003d6c2e4e8Sclaudio return (-1); 1004d6c2e4e8Sclaudio } 1005d6c2e4e8Sclaudio 100645350f87Sclaudio /* 100745350f87Sclaudio * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses 100845350f87Sclaudio * the included label stack is ignored and needs to be handled by the caller. 100945350f87Sclaudio */ 1010d6c2e4e8Sclaudio struct sockaddr * 101139386878Sclaudio addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len) 1012d6c2e4e8Sclaudio { 1013d6c2e4e8Sclaudio static struct sockaddr_storage ss; 1014d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; 1015d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; 1016d6c2e4e8Sclaudio 10174886db4cSclaudio if (addr == NULL || addr->aid == AID_UNSPEC) 10184886db4cSclaudio return (NULL); 101945350f87Sclaudio 1020eafe309eSclaudio memset(&ss, 0, sizeof(ss)); 1021d6c2e4e8Sclaudio switch (addr->aid) { 1022d6c2e4e8Sclaudio case AID_INET: 10233038d3d1Sclaudio case AID_VPN_IPv4: 1024d6c2e4e8Sclaudio sa_in->sin_family = AF_INET; 1025d6c2e4e8Sclaudio sa_in->sin_addr.s_addr = addr->v4.s_addr; 1026d6c2e4e8Sclaudio sa_in->sin_port = htons(port); 1027255fe563Sclaudio *len = sizeof(struct sockaddr_in); 1028d6c2e4e8Sclaudio break; 1029d6c2e4e8Sclaudio case AID_INET6: 103045350f87Sclaudio case AID_VPN_IPv6: 103145350f87Sclaudio sa_in6->sin6_family = AF_INET6; 10323038d3d1Sclaudio memcpy(&sa_in6->sin6_addr, &addr->v6, 103345350f87Sclaudio sizeof(sa_in6->sin6_addr)); 103445350f87Sclaudio sa_in6->sin6_port = htons(port); 103545350f87Sclaudio sa_in6->sin6_scope_id = addr->scope_id; 103645350f87Sclaudio *len = sizeof(struct sockaddr_in6); 103745350f87Sclaudio break; 103841c1c374Sclaudio case AID_FLOWSPECv4: 103941c1c374Sclaudio case AID_FLOWSPECv6: 104041c1c374Sclaudio return (NULL); 1041d6c2e4e8Sclaudio } 1042d6c2e4e8Sclaudio 1043d6c2e4e8Sclaudio return ((struct sockaddr *)&ss); 1044d6c2e4e8Sclaudio } 1045d6c2e4e8Sclaudio 1046d6c2e4e8Sclaudio void 104739386878Sclaudio sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port) 1048d6c2e4e8Sclaudio { 1049d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 1050d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 1051d6c2e4e8Sclaudio 1052eafe309eSclaudio memset(addr, 0, sizeof(*addr)); 1053d6c2e4e8Sclaudio switch (sa->sa_family) { 1054d6c2e4e8Sclaudio case AF_INET: 1055d6c2e4e8Sclaudio addr->aid = AID_INET; 1056d6c2e4e8Sclaudio memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4)); 1057a27d9e33Sclaudio if (port) 1058a27d9e33Sclaudio *port = ntohs(sa_in->sin_port); 1059d6c2e4e8Sclaudio break; 1060d6c2e4e8Sclaudio case AF_INET6: 1061d6c2e4e8Sclaudio addr->aid = AID_INET6; 1062be6ced5eSclaudio #ifdef __KAME__ 1063be6ced5eSclaudio /* 1064be6ced5eSclaudio * XXX thanks, KAME, for this ugliness... 1065be6ced5eSclaudio * adopted from route/show.c 1066be6ced5eSclaudio */ 10675177244fSclaudio if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) || 10685177244fSclaudio IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr) || 10694ff2dba3Sclaudio IN6_IS_ADDR_MC_NODELOCAL(&sa_in6->sin6_addr)) && 10705177244fSclaudio sa_in6->sin6_scope_id == 0) { 1071be6ced5eSclaudio uint16_t tmp16; 1072be6ced5eSclaudio memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2], 1073be6ced5eSclaudio sizeof(tmp16)); 1074be6ced5eSclaudio sa_in6->sin6_scope_id = ntohs(tmp16); 1075be6ced5eSclaudio sa_in6->sin6_addr.s6_addr[2] = 0; 1076be6ced5eSclaudio sa_in6->sin6_addr.s6_addr[3] = 0; 1077be6ced5eSclaudio } 1078be6ced5eSclaudio #endif 10795177244fSclaudio memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6)); 1080d6c2e4e8Sclaudio addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */ 1081a27d9e33Sclaudio if (port) 1082a27d9e33Sclaudio *port = ntohs(sa_in6->sin6_port); 1083d6c2e4e8Sclaudio break; 1084d6c2e4e8Sclaudio } 1085d6c2e4e8Sclaudio } 10866e8089a5Sclaudio 10876e8089a5Sclaudio const char * 1088bc757ddaSclaudio get_baudrate(unsigned long long baudrate, char *unit) 10896e8089a5Sclaudio { 10906e8089a5Sclaudio static char bbuf[16]; 10913eaf1285Sclaudio const unsigned long long kilo = 1000; 10923eaf1285Sclaudio const unsigned long long mega = 1000ULL * kilo; 10933eaf1285Sclaudio const unsigned long long giga = 1000ULL * mega; 10946e8089a5Sclaudio 10953eaf1285Sclaudio if (baudrate > giga) 10966e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu G%s", 10973eaf1285Sclaudio baudrate / giga, unit); 10983eaf1285Sclaudio else if (baudrate > mega) 10996e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu M%s", 11003eaf1285Sclaudio baudrate / mega, unit); 11013eaf1285Sclaudio else if (baudrate > kilo) 11026e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu K%s", 11033eaf1285Sclaudio baudrate / kilo, unit); 11046e8089a5Sclaudio else 11056e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu %s", 11066e8089a5Sclaudio baudrate, unit); 11076e8089a5Sclaudio 11086e8089a5Sclaudio return (bbuf); 11096e8089a5Sclaudio } 1110