1*4886db4cSclaudio /* $OpenBSD: util.c,v 1.58 2021/01/05 10:00:28 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 351e590dcfSclaudio const char *aspath_delim(u_int8_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: 50256b680eSclaudio snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn4.rd), 5145350f87Sclaudio log_sockaddr(sa, len)); 5215d8de66Sclaudio return (buf); 53290f96faSdenis case AID_VPN_IPv6: 54290f96faSdenis snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->vpn6.rd), 5545350f87Sclaudio log_sockaddr(sa, len)); 56290f96faSdenis return (buf); 5715d8de66Sclaudio } 5815d8de66Sclaudio return ("???"); 592ffcd4e0Sclaudio } 602ffcd4e0Sclaudio 612ffcd4e0Sclaudio const char * 622ffcd4e0Sclaudio log_in6addr(const struct in6_addr *addr) 632ffcd4e0Sclaudio { 642ffcd4e0Sclaudio struct sockaddr_in6 sa_in6; 652ffcd4e0Sclaudio 662ffcd4e0Sclaudio bzero(&sa_in6, sizeof(sa_in6)); 672ffcd4e0Sclaudio sa_in6.sin6_family = AF_INET6; 682ffcd4e0Sclaudio memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr)); 692ffcd4e0Sclaudio 70be6ced5eSclaudio #ifdef __KAME__ 712ffcd4e0Sclaudio /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */ 722ffcd4e0Sclaudio if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) || 732ffcd4e0Sclaudio IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) { 74a5df8d9bSclaudio u_int16_t tmp16; 752ffcd4e0Sclaudio memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16)); 762ffcd4e0Sclaudio sa_in6.sin6_scope_id = ntohs(tmp16); 772ffcd4e0Sclaudio sa_in6.sin6_addr.s6_addr[2] = 0; 782ffcd4e0Sclaudio sa_in6.sin6_addr.s6_addr[3] = 0; 792ffcd4e0Sclaudio } 80be6ced5eSclaudio #endif 812ffcd4e0Sclaudio 82255fe563Sclaudio return (log_sockaddr((struct sockaddr *)&sa_in6, sizeof(sa_in6))); 832ffcd4e0Sclaudio } 842ffcd4e0Sclaudio 852ffcd4e0Sclaudio const char * 86255fe563Sclaudio log_sockaddr(struct sockaddr *sa, socklen_t len) 872ffcd4e0Sclaudio { 882ffcd4e0Sclaudio static char buf[NI_MAXHOST]; 892ffcd4e0Sclaudio 9045350f87Sclaudio if (sa == NULL || getnameinfo(sa, len, buf, sizeof(buf), NULL, 0, 912ffcd4e0Sclaudio NI_NUMERICHOST)) 922ffcd4e0Sclaudio return ("(unknown)"); 932ffcd4e0Sclaudio else 942ffcd4e0Sclaudio return (buf); 952ffcd4e0Sclaudio } 962ffcd4e0Sclaudio 970c88bf70Sclaudio const char * 980c88bf70Sclaudio log_as(u_int32_t as) 990c88bf70Sclaudio { 10006bcde9cSphessler static char buf[11]; /* "4294967294\0" */ 1010c88bf70Sclaudio 102515e489cSderaadt if (snprintf(buf, sizeof(buf), "%u", as) < 0) 1030c88bf70Sclaudio return ("?"); 10406bcde9cSphessler 1050c88bf70Sclaudio return (buf); 1060c88bf70Sclaudio } 1070c88bf70Sclaudio 108256b680eSclaudio const char * 109256b680eSclaudio log_rd(u_int64_t rd) 110256b680eSclaudio { 111256b680eSclaudio static char buf[32]; 112256b680eSclaudio struct in_addr addr; 113256b680eSclaudio u_int32_t u32; 114256b680eSclaudio u_int16_t u16; 115256b680eSclaudio 116f4c0eb52Sclaudio rd = be64toh(rd); 117256b680eSclaudio switch (rd >> 48) { 118bf8e2920Sclaudio case EXT_COMMUNITY_TRANS_TWO_AS: 119256b680eSclaudio u32 = rd & 0xffffffff; 120256b680eSclaudio u16 = (rd >> 32) & 0xffff; 12132ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32); 122256b680eSclaudio break; 123bf8e2920Sclaudio case EXT_COMMUNITY_TRANS_FOUR_AS: 124256b680eSclaudio u32 = (rd >> 16) & 0xffffffff; 125256b680eSclaudio u16 = rd & 0xffff; 12632ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16); 127256b680eSclaudio break; 128bf8e2920Sclaudio case EXT_COMMUNITY_TRANS_IPV4: 129256b680eSclaudio u32 = (rd >> 16) & 0xffffffff; 130256b680eSclaudio u16 = rd & 0xffff; 131256b680eSclaudio addr.s_addr = htonl(u32); 13232ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16); 133256b680eSclaudio break; 134256b680eSclaudio default: 135256b680eSclaudio return ("rd ?"); 136256b680eSclaudio } 137256b680eSclaudio return (buf); 138256b680eSclaudio } 139256b680eSclaudio 140bf8e2920Sclaudio const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES; 141bf8e2920Sclaudio 142256b680eSclaudio /* NOTE: this function does not check if the type/subtype combo is 143536f41e5Sclaudio * actually valid. */ 144536f41e5Sclaudio const char * 1450e6216fdSclaudio log_ext_subtype(short type, u_int8_t subtype) 146536f41e5Sclaudio { 147536f41e5Sclaudio static char etype[6]; 148bf8e2920Sclaudio const struct ext_comm_pairs *cp; 149536f41e5Sclaudio 150bf8e2920Sclaudio for (cp = iana_ext_comms; cp->subname != NULL; cp++) { 1510e6216fdSclaudio if ((type == cp->type || type == -1) && subtype == cp->subtype) 152bf8e2920Sclaudio return (cp->subname); 153bf8e2920Sclaudio } 154d6340f7aSderaadt snprintf(etype, sizeof(etype), "[%u]", subtype); 155536f41e5Sclaudio return (etype); 156536f41e5Sclaudio } 157536f41e5Sclaudio 1581e590dcfSclaudio const char * 159a78f83ceSderaadt log_reason(const char *communication) { 160a78f83ceSderaadt static char buf[(REASON_LEN - 1) * 4 + 1]; 1610561b344Sphessler 1620561b344Sphessler strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL); 1630561b344Sphessler 1640561b344Sphessler return buf; 1650561b344Sphessler } 1660561b344Sphessler 1670561b344Sphessler const char * 1681e590dcfSclaudio aspath_delim(u_int8_t seg_type, int closing) 1691e590dcfSclaudio { 1701e590dcfSclaudio static char db[8]; 1711e590dcfSclaudio 1721e590dcfSclaudio switch (seg_type) { 1731e590dcfSclaudio case AS_SET: 1741e590dcfSclaudio if (!closing) 1751e590dcfSclaudio return ("{ "); 1761e590dcfSclaudio else 1771e590dcfSclaudio return (" }"); 1781e590dcfSclaudio case AS_SEQUENCE: 1791e590dcfSclaudio return (""); 1801e590dcfSclaudio case AS_CONFED_SEQUENCE: 1811e590dcfSclaudio if (!closing) 1821e590dcfSclaudio return ("( "); 1831e590dcfSclaudio else 1841e590dcfSclaudio return (" )"); 1851e590dcfSclaudio case AS_CONFED_SET: 1861e590dcfSclaudio if (!closing) 1871e590dcfSclaudio return ("[ "); 1881e590dcfSclaudio else 1891e590dcfSclaudio return (" ]"); 1901e590dcfSclaudio default: 1911e590dcfSclaudio if (!closing) 1921e590dcfSclaudio snprintf(db, sizeof(db), "!%u ", seg_type); 1931e590dcfSclaudio else 1941e590dcfSclaudio snprintf(db, sizeof(db), " !%u", seg_type); 1951e590dcfSclaudio return (db); 1961e590dcfSclaudio } 1971e590dcfSclaudio } 1981e590dcfSclaudio 1992ffcd4e0Sclaudio int 2002ffcd4e0Sclaudio aspath_snprint(char *buf, size_t size, void *data, u_int16_t len) 2012ffcd4e0Sclaudio { 2022ffcd4e0Sclaudio #define UPDATE() \ 2032ffcd4e0Sclaudio do { \ 204515e489cSderaadt if (r < 0) \ 2052ffcd4e0Sclaudio return (-1); \ 2062ffcd4e0Sclaudio total_size += r; \ 2072ffcd4e0Sclaudio if ((unsigned int)r < size) { \ 2082ffcd4e0Sclaudio size -= r; \ 2092ffcd4e0Sclaudio buf += r; \ 2102ffcd4e0Sclaudio } else { \ 2112ffcd4e0Sclaudio buf += size; \ 2122ffcd4e0Sclaudio size = 0; \ 2132ffcd4e0Sclaudio } \ 2142ffcd4e0Sclaudio } while (0) 2152ffcd4e0Sclaudio u_int8_t *seg; 2162ffcd4e0Sclaudio int r, total_size; 2172ffcd4e0Sclaudio u_int16_t seg_size; 2182ffcd4e0Sclaudio u_int8_t i, seg_type, seg_len; 2192ffcd4e0Sclaudio 2202ffcd4e0Sclaudio total_size = 0; 2212ffcd4e0Sclaudio seg = data; 2222ffcd4e0Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 2232ffcd4e0Sclaudio seg_type = seg[0]; 2242ffcd4e0Sclaudio seg_len = seg[1]; 2250c88bf70Sclaudio seg_size = 2 + sizeof(u_int32_t) * seg_len; 2262ffcd4e0Sclaudio 2271e590dcfSclaudio r = snprintf(buf, size, "%s%s", 2281e590dcfSclaudio total_size != 0 ? " " : "", 2291e590dcfSclaudio aspath_delim(seg_type, 0)); 2302ffcd4e0Sclaudio UPDATE(); 2312ffcd4e0Sclaudio 2322ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) { 2330c88bf70Sclaudio r = snprintf(buf, size, "%s", 2340c88bf70Sclaudio log_as(aspath_extract(seg, i))); 2352ffcd4e0Sclaudio UPDATE(); 2362ffcd4e0Sclaudio if (i + 1 < seg_len) { 2372ffcd4e0Sclaudio r = snprintf(buf, size, " "); 2382ffcd4e0Sclaudio UPDATE(); 2392ffcd4e0Sclaudio } 2402ffcd4e0Sclaudio } 2411e590dcfSclaudio r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1)); 2422ffcd4e0Sclaudio UPDATE(); 2432ffcd4e0Sclaudio } 24455e49665Sclaudio /* ensure that we have a valid C-string especially for empty as path */ 2452ffcd4e0Sclaudio if (size > 0) 2462ffcd4e0Sclaudio *buf = '\0'; 2472ffcd4e0Sclaudio 2482ffcd4e0Sclaudio return (total_size); 2492ffcd4e0Sclaudio #undef UPDATE 2502ffcd4e0Sclaudio } 2512ffcd4e0Sclaudio 2522ffcd4e0Sclaudio int 2532ffcd4e0Sclaudio aspath_asprint(char **ret, void *data, u_int16_t len) 2542ffcd4e0Sclaudio { 2552ffcd4e0Sclaudio size_t slen; 2562ffcd4e0Sclaudio int plen; 2572ffcd4e0Sclaudio 2582ffcd4e0Sclaudio slen = aspath_strlen(data, len) + 1; 2592ffcd4e0Sclaudio *ret = malloc(slen); 2602ffcd4e0Sclaudio if (*ret == NULL) 2612ffcd4e0Sclaudio return (-1); 2622ffcd4e0Sclaudio 2632ffcd4e0Sclaudio plen = aspath_snprint(*ret, slen, data, len); 2642ffcd4e0Sclaudio if (plen == -1) { 2652ffcd4e0Sclaudio free(*ret); 2662ffcd4e0Sclaudio *ret = NULL; 2672ffcd4e0Sclaudio return (-1); 2682ffcd4e0Sclaudio } 2692ffcd4e0Sclaudio 2702ffcd4e0Sclaudio return (0); 2712ffcd4e0Sclaudio } 2722ffcd4e0Sclaudio 2732ffcd4e0Sclaudio size_t 2742ffcd4e0Sclaudio aspath_strlen(void *data, u_int16_t len) 2752ffcd4e0Sclaudio { 2762ffcd4e0Sclaudio u_int8_t *seg; 2772ffcd4e0Sclaudio int total_size; 2780c88bf70Sclaudio u_int32_t as; 2790c88bf70Sclaudio u_int16_t seg_size; 2802ffcd4e0Sclaudio u_int8_t i, seg_type, seg_len; 2812ffcd4e0Sclaudio 2822ffcd4e0Sclaudio total_size = 0; 2832ffcd4e0Sclaudio seg = data; 2842ffcd4e0Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 2852ffcd4e0Sclaudio seg_type = seg[0]; 2862ffcd4e0Sclaudio seg_len = seg[1]; 2870c88bf70Sclaudio seg_size = 2 + sizeof(u_int32_t) * seg_len; 2882ffcd4e0Sclaudio 2892ffcd4e0Sclaudio if (seg_type == AS_SET) 2902ffcd4e0Sclaudio if (total_size != 0) 2912ffcd4e0Sclaudio total_size += 3; 2922ffcd4e0Sclaudio else 2932ffcd4e0Sclaudio total_size += 2; 2942ffcd4e0Sclaudio else if (total_size != 0) 2952ffcd4e0Sclaudio total_size += 1; 2962ffcd4e0Sclaudio 2972ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) { 2982ffcd4e0Sclaudio as = aspath_extract(seg, i); 2990c88bf70Sclaudio 3008db4f5d2Sclaudio do { 3018db4f5d2Sclaudio total_size++; 3028db4f5d2Sclaudio } while ((as = as / 10) != 0); 3032ffcd4e0Sclaudio 3042ffcd4e0Sclaudio if (i + 1 < seg_len) 3052ffcd4e0Sclaudio total_size += 1; 3062ffcd4e0Sclaudio } 3072ffcd4e0Sclaudio 3082ffcd4e0Sclaudio if (seg_type == AS_SET) 3092ffcd4e0Sclaudio total_size += 2; 3102ffcd4e0Sclaudio } 3112ffcd4e0Sclaudio return (total_size); 3122ffcd4e0Sclaudio } 3132ffcd4e0Sclaudio 3142ffcd4e0Sclaudio /* 3152ffcd4e0Sclaudio * Extract the asnum out of the as segment at the specified position. 3162ffcd4e0Sclaudio * Direct access is not possible because of non-aligned reads. 317c5508ee4Sclaudio * ATTENTION: no bounds checks are done. 3182ffcd4e0Sclaudio */ 3190c88bf70Sclaudio u_int32_t 3202ffcd4e0Sclaudio aspath_extract(const void *seg, int pos) 3212ffcd4e0Sclaudio { 3222ffcd4e0Sclaudio const u_char *ptr = seg; 3230c88bf70Sclaudio u_int32_t as; 3242ffcd4e0Sclaudio 3250c88bf70Sclaudio ptr += 2 + sizeof(u_int32_t) * pos; 3260c88bf70Sclaudio memcpy(&as, ptr, sizeof(u_int32_t)); 3270c88bf70Sclaudio return (ntohl(as)); 3282ffcd4e0Sclaudio } 32921a825c9Sclaudio 330de5c2eedSclaudio /* 33129328a94Sclaudio * Verify that the aspath is correctly encoded. 33229328a94Sclaudio */ 33329328a94Sclaudio int 33429328a94Sclaudio aspath_verify(void *data, u_int16_t len, int as4byte) 33529328a94Sclaudio { 33629328a94Sclaudio u_int8_t *seg = data; 33729328a94Sclaudio u_int16_t seg_size, as_size = 2; 33829328a94Sclaudio u_int8_t seg_len, seg_type; 33929328a94Sclaudio int error = 0; 34029328a94Sclaudio 34129328a94Sclaudio if (len & 1) 34229328a94Sclaudio /* odd length aspath are invalid */ 34329328a94Sclaudio return (AS_ERR_BAD); 34429328a94Sclaudio 34529328a94Sclaudio if (as4byte) 34629328a94Sclaudio as_size = 4; 34729328a94Sclaudio 34829328a94Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 34951491708Sclaudio const u_int8_t *ptr; 35029328a94Sclaudio int pos; 35129328a94Sclaudio 35229328a94Sclaudio if (len < 2) /* header length check */ 35329328a94Sclaudio return (AS_ERR_BAD); 35429328a94Sclaudio seg_type = seg[0]; 35529328a94Sclaudio seg_len = seg[1]; 35629328a94Sclaudio 357d04df938Sclaudio if (seg_len == 0) 358d04df938Sclaudio /* empty aspath segments are not allowed */ 359d04df938Sclaudio return (AS_ERR_BAD); 360d04df938Sclaudio 36129328a94Sclaudio /* 36229328a94Sclaudio * BGP confederations should not show up but consider them 36329328a94Sclaudio * as a soft error which invalidates the path but keeps the 36429328a94Sclaudio * bgp session running. 36529328a94Sclaudio */ 36629328a94Sclaudio if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET) 36729328a94Sclaudio error = AS_ERR_SOFT; 36829328a94Sclaudio if (seg_type != AS_SET && seg_type != AS_SEQUENCE && 36929328a94Sclaudio seg_type != AS_CONFED_SEQUENCE && seg_type != AS_CONFED_SET) 37029328a94Sclaudio return (AS_ERR_TYPE); 37129328a94Sclaudio 37229328a94Sclaudio seg_size = 2 + as_size * seg_len; 37329328a94Sclaudio 37429328a94Sclaudio if (seg_size > len) 37529328a94Sclaudio return (AS_ERR_LEN); 37629328a94Sclaudio 37729328a94Sclaudio /* RFC 7607 - AS 0 is considered malformed */ 37829328a94Sclaudio ptr = seg + 2; 37929328a94Sclaudio for (pos = 0; pos < seg_len; pos++) { 38051491708Sclaudio u_int32_t as; 38129328a94Sclaudio 38229328a94Sclaudio memcpy(&as, ptr, as_size); 38329328a94Sclaudio if (as == 0) 38456a9a1b8Sclaudio error = AS_ERR_SOFT; 38551491708Sclaudio ptr += as_size; 38629328a94Sclaudio } 38729328a94Sclaudio } 38829328a94Sclaudio return (error); /* aspath is valid but probably not loop free */ 38929328a94Sclaudio } 39029328a94Sclaudio 39129328a94Sclaudio /* 39229328a94Sclaudio * convert a 2 byte aspath to a 4 byte one. 39329328a94Sclaudio */ 39429328a94Sclaudio u_char * 39529328a94Sclaudio aspath_inflate(void *data, u_int16_t len, u_int16_t *newlen) 39629328a94Sclaudio { 39729328a94Sclaudio u_int8_t *seg, *nseg, *ndata; 39829328a94Sclaudio u_int16_t seg_size, olen, nlen; 39929328a94Sclaudio u_int8_t seg_len; 40029328a94Sclaudio 40129328a94Sclaudio /* first calculate the length of the aspath */ 40229328a94Sclaudio seg = data; 40329328a94Sclaudio nlen = 0; 40429328a94Sclaudio for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) { 40529328a94Sclaudio seg_len = seg[1]; 40629328a94Sclaudio seg_size = 2 + sizeof(u_int16_t) * seg_len; 40729328a94Sclaudio nlen += 2 + sizeof(u_int32_t) * seg_len; 40829328a94Sclaudio 40929328a94Sclaudio if (seg_size > olen) { 41029328a94Sclaudio errno = ERANGE; 41129328a94Sclaudio return (NULL); 41229328a94Sclaudio } 41329328a94Sclaudio } 41429328a94Sclaudio 41529328a94Sclaudio *newlen = nlen; 41629328a94Sclaudio if ((ndata = malloc(nlen)) == NULL) 41729328a94Sclaudio return (NULL); 41829328a94Sclaudio 41929328a94Sclaudio /* then copy the aspath */ 42029328a94Sclaudio seg = data; 42129328a94Sclaudio for (nseg = ndata; nseg < ndata + nlen; ) { 42229328a94Sclaudio *nseg++ = *seg++; 42329328a94Sclaudio *nseg++ = seg_len = *seg++; 42429328a94Sclaudio for (; seg_len > 0; seg_len--) { 42529328a94Sclaudio *nseg++ = 0; 42629328a94Sclaudio *nseg++ = 0; 42729328a94Sclaudio *nseg++ = *seg++; 42829328a94Sclaudio *nseg++ = *seg++; 42929328a94Sclaudio } 43029328a94Sclaudio } 43129328a94Sclaudio 43229328a94Sclaudio return (ndata); 43329328a94Sclaudio } 43429328a94Sclaudio 4356d3e8673Sclaudio /* NLRI functions to extract prefixes from the NLRI blobs */ 4366d3e8673Sclaudio static int 4376d3e8673Sclaudio extract_prefix(u_char *p, u_int16_t len, void *va, 4386d3e8673Sclaudio u_int8_t pfxlen, u_int8_t max) 4396d3e8673Sclaudio { 4406d3e8673Sclaudio static u_char addrmask[] = { 4416d3e8673Sclaudio 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 4426d3e8673Sclaudio u_char *a = va; 4436d3e8673Sclaudio int i; 4446d3e8673Sclaudio u_int16_t plen = 0; 4456d3e8673Sclaudio 4466d3e8673Sclaudio for (i = 0; pfxlen && i < max; i++) { 4476d3e8673Sclaudio if (len <= plen) 4486d3e8673Sclaudio return (-1); 4496d3e8673Sclaudio if (pfxlen < 8) { 4506d3e8673Sclaudio a[i] = *p++ & addrmask[pfxlen]; 4516d3e8673Sclaudio plen++; 4526d3e8673Sclaudio break; 4536d3e8673Sclaudio } else { 4546d3e8673Sclaudio a[i] = *p++; 4556d3e8673Sclaudio plen++; 4566d3e8673Sclaudio pfxlen -= 8; 4576d3e8673Sclaudio } 4586d3e8673Sclaudio } 4596d3e8673Sclaudio return (plen); 4606d3e8673Sclaudio } 4616d3e8673Sclaudio 4626d3e8673Sclaudio int 4636d3e8673Sclaudio nlri_get_prefix(u_char *p, u_int16_t len, struct bgpd_addr *prefix, 4646d3e8673Sclaudio u_int8_t *prefixlen) 4656d3e8673Sclaudio { 4666d3e8673Sclaudio u_int8_t pfxlen; 4676d3e8673Sclaudio int plen; 4686d3e8673Sclaudio 4696d3e8673Sclaudio if (len < 1) 4706d3e8673Sclaudio return (-1); 4716d3e8673Sclaudio 4726d3e8673Sclaudio pfxlen = *p++; 4736d3e8673Sclaudio len--; 4746d3e8673Sclaudio 4756d3e8673Sclaudio bzero(prefix, sizeof(struct bgpd_addr)); 4766d3e8673Sclaudio prefix->aid = AID_INET; 4776d3e8673Sclaudio *prefixlen = pfxlen; 4786d3e8673Sclaudio 4796d3e8673Sclaudio if (pfxlen > 32) 4806d3e8673Sclaudio return (-1); 4816d3e8673Sclaudio if ((plen = extract_prefix(p, len, &prefix->v4, pfxlen, 4826d3e8673Sclaudio sizeof(prefix->v4))) == -1) 4836d3e8673Sclaudio return (-1); 4846d3e8673Sclaudio 4856d3e8673Sclaudio return (plen + 1); /* pfxlen needs to be added */ 4866d3e8673Sclaudio } 4876d3e8673Sclaudio 4886d3e8673Sclaudio int 4896d3e8673Sclaudio nlri_get_prefix6(u_char *p, u_int16_t len, struct bgpd_addr *prefix, 4906d3e8673Sclaudio u_int8_t *prefixlen) 4916d3e8673Sclaudio { 4926d3e8673Sclaudio int plen; 4936d3e8673Sclaudio u_int8_t pfxlen; 4946d3e8673Sclaudio 4956d3e8673Sclaudio if (len < 1) 4966d3e8673Sclaudio return (-1); 4976d3e8673Sclaudio 4986d3e8673Sclaudio pfxlen = *p++; 4996d3e8673Sclaudio len--; 5006d3e8673Sclaudio 5016d3e8673Sclaudio bzero(prefix, sizeof(struct bgpd_addr)); 5026d3e8673Sclaudio prefix->aid = AID_INET6; 5036d3e8673Sclaudio *prefixlen = pfxlen; 5046d3e8673Sclaudio 5056d3e8673Sclaudio if (pfxlen > 128) 5066d3e8673Sclaudio return (-1); 5076d3e8673Sclaudio if ((plen = extract_prefix(p, len, &prefix->v6, pfxlen, 5086d3e8673Sclaudio sizeof(prefix->v6))) == -1) 5096d3e8673Sclaudio return (-1); 5106d3e8673Sclaudio 5116d3e8673Sclaudio return (plen + 1); /* pfxlen needs to be added */ 5126d3e8673Sclaudio } 5136d3e8673Sclaudio 5146d3e8673Sclaudio int 5156d3e8673Sclaudio nlri_get_vpn4(u_char *p, u_int16_t len, struct bgpd_addr *prefix, 5166d3e8673Sclaudio u_int8_t *prefixlen, int withdraw) 5176d3e8673Sclaudio { 5186d3e8673Sclaudio int rv, done = 0; 5196d3e8673Sclaudio u_int8_t pfxlen; 5206d3e8673Sclaudio u_int16_t plen; 5216d3e8673Sclaudio 5226d3e8673Sclaudio if (len < 1) 5236d3e8673Sclaudio return (-1); 5246d3e8673Sclaudio 5256d3e8673Sclaudio memcpy(&pfxlen, p, 1); 5266d3e8673Sclaudio p += 1; 5276d3e8673Sclaudio plen = 1; 5286d3e8673Sclaudio 5296d3e8673Sclaudio bzero(prefix, sizeof(struct bgpd_addr)); 5306d3e8673Sclaudio 5316d3e8673Sclaudio /* label stack */ 5326d3e8673Sclaudio do { 5336d3e8673Sclaudio if (len - plen < 3 || pfxlen < 3 * 8) 5346d3e8673Sclaudio return (-1); 5356d3e8673Sclaudio if (prefix->vpn4.labellen + 3U > 5366d3e8673Sclaudio sizeof(prefix->vpn4.labelstack)) 5376d3e8673Sclaudio return (-1); 5386d3e8673Sclaudio if (withdraw) { 5396d3e8673Sclaudio /* on withdraw ignore the labelstack all together */ 5406d3e8673Sclaudio plen += 3; 5416d3e8673Sclaudio pfxlen -= 3 * 8; 5426d3e8673Sclaudio break; 5436d3e8673Sclaudio } 5446d3e8673Sclaudio prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++; 5456d3e8673Sclaudio prefix->vpn4.labelstack[prefix->vpn4.labellen++] = *p++; 5466d3e8673Sclaudio prefix->vpn4.labelstack[prefix->vpn4.labellen] = *p++; 5476d3e8673Sclaudio if (prefix->vpn4.labelstack[prefix->vpn4.labellen] & 5486d3e8673Sclaudio BGP_MPLS_BOS) 5496d3e8673Sclaudio done = 1; 5506d3e8673Sclaudio prefix->vpn4.labellen++; 5516d3e8673Sclaudio plen += 3; 5526d3e8673Sclaudio pfxlen -= 3 * 8; 5536d3e8673Sclaudio } while (!done); 5546d3e8673Sclaudio 5556d3e8673Sclaudio /* RD */ 5566d3e8673Sclaudio if (len - plen < (int)sizeof(u_int64_t) || 5576d3e8673Sclaudio pfxlen < sizeof(u_int64_t) * 8) 5586d3e8673Sclaudio return (-1); 5596d3e8673Sclaudio memcpy(&prefix->vpn4.rd, p, sizeof(u_int64_t)); 5606d3e8673Sclaudio pfxlen -= sizeof(u_int64_t) * 8; 5616d3e8673Sclaudio p += sizeof(u_int64_t); 5626d3e8673Sclaudio plen += sizeof(u_int64_t); 5636d3e8673Sclaudio 5646d3e8673Sclaudio /* prefix */ 5656d3e8673Sclaudio prefix->aid = AID_VPN_IPv4; 5666d3e8673Sclaudio *prefixlen = pfxlen; 5676d3e8673Sclaudio 5686d3e8673Sclaudio if (pfxlen > 32) 5696d3e8673Sclaudio return (-1); 5706d3e8673Sclaudio if ((rv = extract_prefix(p, len, &prefix->vpn4.addr, 5716d3e8673Sclaudio pfxlen, sizeof(prefix->vpn4.addr))) == -1) 5726d3e8673Sclaudio return (-1); 5736d3e8673Sclaudio 5746d3e8673Sclaudio return (plen + rv); 5756d3e8673Sclaudio } 5766d3e8673Sclaudio 577290f96faSdenis int 578290f96faSdenis nlri_get_vpn6(u_char *p, u_int16_t len, struct bgpd_addr *prefix, 579290f96faSdenis u_int8_t *prefixlen, int withdraw) 580290f96faSdenis { 581290f96faSdenis int rv, done = 0; 582290f96faSdenis u_int8_t pfxlen; 583290f96faSdenis u_int16_t plen; 584290f96faSdenis 585290f96faSdenis if (len < 1) 586290f96faSdenis return (-1); 587290f96faSdenis 588290f96faSdenis memcpy(&pfxlen, p, 1); 589290f96faSdenis p += 1; 590290f96faSdenis plen = 1; 591290f96faSdenis 592290f96faSdenis memset(prefix, 0, sizeof(struct bgpd_addr)); 593290f96faSdenis 594290f96faSdenis /* label stack */ 595290f96faSdenis do { 596290f96faSdenis if (len - plen < 3 || pfxlen < 3 * 8) 597290f96faSdenis return (-1); 598290f96faSdenis if (prefix->vpn6.labellen + 3U > 599290f96faSdenis sizeof(prefix->vpn6.labelstack)) 600290f96faSdenis return (-1); 601290f96faSdenis if (withdraw) { 602290f96faSdenis /* on withdraw ignore the labelstack all together */ 603290f96faSdenis plen += 3; 604290f96faSdenis pfxlen -= 3 * 8; 605290f96faSdenis break; 606290f96faSdenis } 607290f96faSdenis 608290f96faSdenis prefix->vpn6.labelstack[prefix->vpn6.labellen++] = *p++; 609290f96faSdenis prefix->vpn6.labelstack[prefix->vpn6.labellen++] = *p++; 610290f96faSdenis prefix->vpn6.labelstack[prefix->vpn6.labellen] = *p++; 611290f96faSdenis if (prefix->vpn6.labelstack[prefix->vpn6.labellen] & 612290f96faSdenis BGP_MPLS_BOS) 613290f96faSdenis done = 1; 614290f96faSdenis prefix->vpn6.labellen++; 615290f96faSdenis plen += 3; 616290f96faSdenis pfxlen -= 3 * 8; 617290f96faSdenis } while (!done); 618290f96faSdenis 619290f96faSdenis /* RD */ 620290f96faSdenis if (len - plen < (int)sizeof(u_int64_t) || 621290f96faSdenis pfxlen < sizeof(u_int64_t) * 8) 622290f96faSdenis return (-1); 623290f96faSdenis 624290f96faSdenis memcpy(&prefix->vpn6.rd, p, sizeof(u_int64_t)); 625290f96faSdenis pfxlen -= sizeof(u_int64_t) * 8; 626290f96faSdenis p += sizeof(u_int64_t); 627290f96faSdenis plen += sizeof(u_int64_t); 628290f96faSdenis 629290f96faSdenis /* prefix */ 630290f96faSdenis prefix->aid = AID_VPN_IPv6; 631290f96faSdenis *prefixlen = pfxlen; 632290f96faSdenis 633290f96faSdenis if (pfxlen > 128) 634290f96faSdenis return (-1); 635290f96faSdenis 636290f96faSdenis if ((rv = extract_prefix(p, len, &prefix->vpn6.addr, 637290f96faSdenis pfxlen, sizeof(prefix->vpn6.addr))) == -1) 638290f96faSdenis return (-1); 639290f96faSdenis 640290f96faSdenis return (plen + rv); 641290f96faSdenis } 642290f96faSdenis 643290f96faSdenis 644290f96faSdenis 64529328a94Sclaudio /* 646de5c2eedSclaudio * This function will have undefined behaviour if the passed in prefixlen is 647290f96faSdenis * too large for the respective bgpd_addr address family. 648de5c2eedSclaudio */ 649fafbb788Sclaudio int 650fafbb788Sclaudio prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, 651fafbb788Sclaudio int prefixlen) 652fafbb788Sclaudio { 653fafbb788Sclaudio in_addr_t mask, aa, ba; 654fafbb788Sclaudio int i; 655fafbb788Sclaudio u_int8_t m; 656fafbb788Sclaudio 657fafbb788Sclaudio if (a->aid != b->aid) 658fafbb788Sclaudio return (a->aid - b->aid); 659fafbb788Sclaudio 660fafbb788Sclaudio switch (a->aid) { 661fafbb788Sclaudio case AID_INET: 6627da59fecSclaudio if (prefixlen == 0) 6637da59fecSclaudio return (0); 664fafbb788Sclaudio if (prefixlen > 32) 665de5c2eedSclaudio return (-1); 666fafbb788Sclaudio mask = htonl(prefixlen2mask(prefixlen)); 667fafbb788Sclaudio aa = ntohl(a->v4.s_addr & mask); 668fafbb788Sclaudio ba = ntohl(b->v4.s_addr & mask); 669fafbb788Sclaudio if (aa != ba) 670fafbb788Sclaudio return (aa - ba); 671fafbb788Sclaudio return (0); 672fafbb788Sclaudio case AID_INET6: 6737da59fecSclaudio if (prefixlen == 0) 6747da59fecSclaudio return (0); 675fafbb788Sclaudio if (prefixlen > 128) 676de5c2eedSclaudio return (-1); 677fafbb788Sclaudio for (i = 0; i < prefixlen / 8; i++) 678fafbb788Sclaudio if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 679fafbb788Sclaudio return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 680fafbb788Sclaudio i = prefixlen % 8; 681fafbb788Sclaudio if (i) { 682fafbb788Sclaudio m = 0xff00 >> i; 683fafbb788Sclaudio if ((a->v6.s6_addr[prefixlen / 8] & m) != 684fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m)) 685fafbb788Sclaudio return ((a->v6.s6_addr[prefixlen / 8] & m) - 686fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m)); 687fafbb788Sclaudio } 688fafbb788Sclaudio return (0); 689fafbb788Sclaudio case AID_VPN_IPv4: 690fafbb788Sclaudio if (prefixlen > 32) 691de5c2eedSclaudio return (-1); 692f4c0eb52Sclaudio if (be64toh(a->vpn4.rd) > be64toh(b->vpn4.rd)) 693fafbb788Sclaudio return (1); 694f4c0eb52Sclaudio if (be64toh(a->vpn4.rd) < be64toh(b->vpn4.rd)) 695fafbb788Sclaudio return (-1); 696fafbb788Sclaudio mask = htonl(prefixlen2mask(prefixlen)); 697fafbb788Sclaudio aa = ntohl(a->vpn4.addr.s_addr & mask); 698fafbb788Sclaudio ba = ntohl(b->vpn4.addr.s_addr & mask); 699fafbb788Sclaudio if (aa != ba) 700fafbb788Sclaudio return (aa - ba); 701fafbb788Sclaudio if (a->vpn4.labellen > b->vpn4.labellen) 702fafbb788Sclaudio return (1); 703fafbb788Sclaudio if (a->vpn4.labellen < b->vpn4.labellen) 704fafbb788Sclaudio return (-1); 705fafbb788Sclaudio return (memcmp(a->vpn4.labelstack, b->vpn4.labelstack, 706fafbb788Sclaudio a->vpn4.labellen)); 707290f96faSdenis case AID_VPN_IPv6: 708290f96faSdenis if (prefixlen > 128) 709290f96faSdenis return (-1); 710f4c0eb52Sclaudio if (be64toh(a->vpn6.rd) > be64toh(b->vpn6.rd)) 711290f96faSdenis return (1); 712f4c0eb52Sclaudio if (be64toh(a->vpn6.rd) < be64toh(b->vpn6.rd)) 713290f96faSdenis return (-1); 714290f96faSdenis for (i = 0; i < prefixlen / 8; i++) 715290f96faSdenis if (a->vpn6.addr.s6_addr[i] != b->vpn6.addr.s6_addr[i]) 716290f96faSdenis return (a->vpn6.addr.s6_addr[i] - 717290f96faSdenis b->vpn6.addr.s6_addr[i]); 718290f96faSdenis i = prefixlen % 8; 719290f96faSdenis if (i) { 720290f96faSdenis m = 0xff00 >> i; 721290f96faSdenis if ((a->vpn6.addr.s6_addr[prefixlen / 8] & m) != 722290f96faSdenis (b->vpn6.addr.s6_addr[prefixlen / 8] & m)) 723290f96faSdenis return ((a->vpn6.addr.s6_addr[prefixlen / 8] & 724290f96faSdenis m) - (b->vpn6.addr.s6_addr[prefixlen / 8] & 725290f96faSdenis m)); 726290f96faSdenis } 727290f96faSdenis if (a->vpn6.labellen > b->vpn6.labellen) 728290f96faSdenis return (1); 729290f96faSdenis if (a->vpn6.labellen < b->vpn6.labellen) 730290f96faSdenis return (-1); 731290f96faSdenis return (memcmp(a->vpn6.labelstack, b->vpn6.labelstack, 732290f96faSdenis a->vpn6.labellen)); 733fafbb788Sclaudio } 734fafbb788Sclaudio return (-1); 735fafbb788Sclaudio } 736fafbb788Sclaudio 73721a825c9Sclaudio in_addr_t 73821a825c9Sclaudio prefixlen2mask(u_int8_t prefixlen) 73921a825c9Sclaudio { 74021a825c9Sclaudio if (prefixlen == 0) 74121a825c9Sclaudio return (0); 74221a825c9Sclaudio 74321a825c9Sclaudio return (0xffffffff << (32 - prefixlen)); 74421a825c9Sclaudio } 74521a825c9Sclaudio 74621a825c9Sclaudio void 7472b5c88feSclaudio inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen) 7482b5c88feSclaudio { 7492b5c88feSclaudio struct in_addr mask; 7502b5c88feSclaudio 7512b5c88feSclaudio mask.s_addr = htonl(prefixlen2mask(prefixlen)); 7522b5c88feSclaudio dest->s_addr = src->s_addr & mask.s_addr; 7532b5c88feSclaudio } 7542b5c88feSclaudio 7552b5c88feSclaudio void 75621a825c9Sclaudio inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 75721a825c9Sclaudio { 75821a825c9Sclaudio struct in6_addr mask; 75921a825c9Sclaudio int i; 76021a825c9Sclaudio 76121a825c9Sclaudio bzero(&mask, sizeof(mask)); 76221a825c9Sclaudio for (i = 0; i < prefixlen / 8; i++) 76321a825c9Sclaudio mask.s6_addr[i] = 0xff; 76421a825c9Sclaudio i = prefixlen % 8; 76521a825c9Sclaudio if (i) 76621a825c9Sclaudio mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 76721a825c9Sclaudio 76821a825c9Sclaudio for (i = 0; i < 16; i++) 76921a825c9Sclaudio dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 77021a825c9Sclaudio } 771d6c2e4e8Sclaudio 772d6c2e4e8Sclaudio /* address family translation functions */ 773d6c2e4e8Sclaudio const struct aid aid_vals[AID_MAX] = AID_VALS; 774d6c2e4e8Sclaudio 77586729c90Sclaudio const char * 77686729c90Sclaudio aid2str(u_int8_t aid) 77786729c90Sclaudio { 77886729c90Sclaudio if (aid < AID_MAX) 77986729c90Sclaudio return (aid_vals[aid].name); 78086729c90Sclaudio return ("unknown AID"); 78186729c90Sclaudio } 78286729c90Sclaudio 783d6c2e4e8Sclaudio int 784d6c2e4e8Sclaudio aid2afi(u_int8_t aid, u_int16_t *afi, u_int8_t *safi) 785d6c2e4e8Sclaudio { 786d6c2e4e8Sclaudio if (aid < AID_MAX) { 787d6c2e4e8Sclaudio *afi = aid_vals[aid].afi; 788d6c2e4e8Sclaudio *safi = aid_vals[aid].safi; 789d6c2e4e8Sclaudio return (0); 790d6c2e4e8Sclaudio } 791d6c2e4e8Sclaudio return (-1); 792d6c2e4e8Sclaudio } 793d6c2e4e8Sclaudio 794d6c2e4e8Sclaudio int 795d6c2e4e8Sclaudio afi2aid(u_int16_t afi, u_int8_t safi, u_int8_t *aid) 796d6c2e4e8Sclaudio { 797d6c2e4e8Sclaudio u_int8_t i; 798d6c2e4e8Sclaudio 799d6c2e4e8Sclaudio for (i = 0; i < AID_MAX; i++) 800d6c2e4e8Sclaudio if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) { 801d6c2e4e8Sclaudio *aid = i; 802d6c2e4e8Sclaudio return (0); 803d6c2e4e8Sclaudio } 804d6c2e4e8Sclaudio 805d6c2e4e8Sclaudio return (-1); 806d6c2e4e8Sclaudio } 807d6c2e4e8Sclaudio 808d6c2e4e8Sclaudio sa_family_t 809d6c2e4e8Sclaudio aid2af(u_int8_t aid) 810d6c2e4e8Sclaudio { 811d6c2e4e8Sclaudio if (aid < AID_MAX) 812d6c2e4e8Sclaudio return (aid_vals[aid].af); 813d6c2e4e8Sclaudio return (AF_UNSPEC); 814d6c2e4e8Sclaudio } 815d6c2e4e8Sclaudio 816d6c2e4e8Sclaudio int 817d6c2e4e8Sclaudio af2aid(sa_family_t af, u_int8_t safi, u_int8_t *aid) 818d6c2e4e8Sclaudio { 819d6c2e4e8Sclaudio u_int8_t i; 820d6c2e4e8Sclaudio 821d6c2e4e8Sclaudio if (safi == 0) /* default to unicast subclass */ 822d6c2e4e8Sclaudio safi = SAFI_UNICAST; 823d6c2e4e8Sclaudio 824d6c2e4e8Sclaudio for (i = 0; i < AID_MAX; i++) 825d6c2e4e8Sclaudio if (aid_vals[i].af == af && aid_vals[i].safi == safi) { 826d6c2e4e8Sclaudio *aid = i; 827d6c2e4e8Sclaudio return (0); 828d6c2e4e8Sclaudio } 829d6c2e4e8Sclaudio 830d6c2e4e8Sclaudio return (-1); 831d6c2e4e8Sclaudio } 832d6c2e4e8Sclaudio 83345350f87Sclaudio /* 83445350f87Sclaudio * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses 83545350f87Sclaudio * the included label stack is ignored and needs to be handled by the caller. 83645350f87Sclaudio */ 837d6c2e4e8Sclaudio struct sockaddr * 8385624d029Sclaudio addr2sa(const struct bgpd_addr *addr, u_int16_t port, socklen_t *len) 839d6c2e4e8Sclaudio { 840d6c2e4e8Sclaudio static struct sockaddr_storage ss; 841d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; 842d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; 843d6c2e4e8Sclaudio 844*4886db4cSclaudio if (addr == NULL || addr->aid == AID_UNSPEC) 845*4886db4cSclaudio return (NULL); 84645350f87Sclaudio 847*4886db4cSclaudio bzero(&ss, sizeof(ss)); 848d6c2e4e8Sclaudio switch (addr->aid) { 849d6c2e4e8Sclaudio case AID_INET: 850d6c2e4e8Sclaudio sa_in->sin_family = AF_INET; 851d6c2e4e8Sclaudio sa_in->sin_addr.s_addr = addr->v4.s_addr; 852d6c2e4e8Sclaudio sa_in->sin_port = htons(port); 853255fe563Sclaudio *len = sizeof(struct sockaddr_in); 854d6c2e4e8Sclaudio break; 855d6c2e4e8Sclaudio case AID_INET6: 856d6c2e4e8Sclaudio sa_in6->sin6_family = AF_INET6; 857d6c2e4e8Sclaudio memcpy(&sa_in6->sin6_addr, &addr->v6, 858d6c2e4e8Sclaudio sizeof(sa_in6->sin6_addr)); 859d6c2e4e8Sclaudio sa_in6->sin6_port = htons(port); 860d6c2e4e8Sclaudio sa_in6->sin6_scope_id = addr->scope_id; 861255fe563Sclaudio *len = sizeof(struct sockaddr_in6); 862d6c2e4e8Sclaudio break; 86345350f87Sclaudio case AID_VPN_IPv4: 86445350f87Sclaudio sa_in->sin_family = AF_INET; 86545350f87Sclaudio sa_in->sin_addr.s_addr = addr->vpn4.addr.s_addr; 86645350f87Sclaudio sa_in->sin_port = htons(port); 86745350f87Sclaudio *len = sizeof(struct sockaddr_in); 86845350f87Sclaudio break; 86945350f87Sclaudio case AID_VPN_IPv6: 87045350f87Sclaudio sa_in6->sin6_family = AF_INET6; 87145350f87Sclaudio memcpy(&sa_in6->sin6_addr, &addr->vpn6.addr, 87245350f87Sclaudio sizeof(sa_in6->sin6_addr)); 87345350f87Sclaudio sa_in6->sin6_port = htons(port); 87445350f87Sclaudio sa_in6->sin6_scope_id = addr->scope_id; 87545350f87Sclaudio *len = sizeof(struct sockaddr_in6); 87645350f87Sclaudio break; 877d6c2e4e8Sclaudio } 878d6c2e4e8Sclaudio 879d6c2e4e8Sclaudio return ((struct sockaddr *)&ss); 880d6c2e4e8Sclaudio } 881d6c2e4e8Sclaudio 882d6c2e4e8Sclaudio void 883a27d9e33Sclaudio sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, u_int16_t *port) 884d6c2e4e8Sclaudio { 885d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 886d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 887d6c2e4e8Sclaudio 888d6c2e4e8Sclaudio bzero(addr, sizeof(*addr)); 889d6c2e4e8Sclaudio switch (sa->sa_family) { 890d6c2e4e8Sclaudio case AF_INET: 891d6c2e4e8Sclaudio addr->aid = AID_INET; 892d6c2e4e8Sclaudio memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4)); 893a27d9e33Sclaudio if (port) 894a27d9e33Sclaudio *port = ntohs(sa_in->sin_port); 895d6c2e4e8Sclaudio break; 896d6c2e4e8Sclaudio case AF_INET6: 897d6c2e4e8Sclaudio addr->aid = AID_INET6; 898d6c2e4e8Sclaudio memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6)); 899be6ced5eSclaudio #ifdef __KAME__ 900be6ced5eSclaudio /* 901be6ced5eSclaudio * XXX thanks, KAME, for this ugliness... 902be6ced5eSclaudio * adopted from route/show.c 903be6ced5eSclaudio */ 904be6ced5eSclaudio if (IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) || 905be6ced5eSclaudio IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr)) { 906be6ced5eSclaudio uint16_t tmp16; 907be6ced5eSclaudio memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2], 908be6ced5eSclaudio sizeof(tmp16)); 909be6ced5eSclaudio if (tmp16 != 0) { 910be6ced5eSclaudio sa_in6->sin6_scope_id = ntohs(tmp16); 911be6ced5eSclaudio sa_in6->sin6_addr.s6_addr[2] = 0; 912be6ced5eSclaudio sa_in6->sin6_addr.s6_addr[3] = 0; 913be6ced5eSclaudio } 914be6ced5eSclaudio } 915be6ced5eSclaudio #endif 916d6c2e4e8Sclaudio addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */ 917a27d9e33Sclaudio if (port) 918a27d9e33Sclaudio *port = ntohs(sa_in6->sin6_port); 919d6c2e4e8Sclaudio break; 920d6c2e4e8Sclaudio } 921d6c2e4e8Sclaudio } 9226e8089a5Sclaudio 9236e8089a5Sclaudio const char * 924bc757ddaSclaudio get_baudrate(unsigned long long baudrate, char *unit) 9256e8089a5Sclaudio { 9266e8089a5Sclaudio static char bbuf[16]; 9273eaf1285Sclaudio const unsigned long long kilo = 1000; 9283eaf1285Sclaudio const unsigned long long mega = 1000ULL * kilo; 9293eaf1285Sclaudio const unsigned long long giga = 1000ULL * mega; 9306e8089a5Sclaudio 9313eaf1285Sclaudio if (baudrate > giga) 9326e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu G%s", 9333eaf1285Sclaudio baudrate / giga, unit); 9343eaf1285Sclaudio else if (baudrate > mega) 9356e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu M%s", 9363eaf1285Sclaudio baudrate / mega, unit); 9373eaf1285Sclaudio else if (baudrate > kilo) 9386e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu K%s", 9393eaf1285Sclaudio baudrate / kilo, unit); 9406e8089a5Sclaudio else 9416e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu %s", 9426e8089a5Sclaudio baudrate, unit); 9436e8089a5Sclaudio 9446e8089a5Sclaudio return (bbuf); 9456e8089a5Sclaudio } 946