1*5177244fSclaudio /* $OpenBSD: util.c,v 1.65 2022/06/17 09:12:06 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 3539386878Sclaudio const char *aspath_delim(uint8_t, int); 361e590dcfSclaudio 372ffcd4e0Sclaudio const char * 382ffcd4e0Sclaudio log_addr(const struct bgpd_addr *addr) 392ffcd4e0Sclaudio { 40290f96faSdenis static char buf[74]; 4145350f87Sclaudio struct sockaddr *sa; 425624d029Sclaudio socklen_t len; 432ffcd4e0Sclaudio 4445350f87Sclaudio sa = addr2sa(addr, 0, &len); 4515d8de66Sclaudio switch (addr->aid) { 4615d8de66Sclaudio case AID_INET: 4715d8de66Sclaudio case AID_INET6: 4845350f87Sclaudio return log_sockaddr(sa, len); 4915d8de66Sclaudio case AID_VPN_IPv4: 50290f96faSdenis case AID_VPN_IPv6: 513038d3d1Sclaudio snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->rd), 5245350f87Sclaudio log_sockaddr(sa, len)); 53290f96faSdenis return (buf); 5415d8de66Sclaudio } 5515d8de66Sclaudio return ("???"); 562ffcd4e0Sclaudio } 572ffcd4e0Sclaudio 582ffcd4e0Sclaudio const char * 592ffcd4e0Sclaudio log_in6addr(const struct in6_addr *addr) 602ffcd4e0Sclaudio { 612ffcd4e0Sclaudio struct sockaddr_in6 sa_in6; 622ffcd4e0Sclaudio 632ffcd4e0Sclaudio bzero(&sa_in6, sizeof(sa_in6)); 642ffcd4e0Sclaudio sa_in6.sin6_family = AF_INET6; 652ffcd4e0Sclaudio memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr)); 662ffcd4e0Sclaudio 67be6ced5eSclaudio #ifdef __KAME__ 682ffcd4e0Sclaudio /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */ 692ffcd4e0Sclaudio if (IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) || 702ffcd4e0Sclaudio IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr)) { 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: 132256b680eSclaudio return ("rd ?"); 133256b680eSclaudio } 134256b680eSclaudio return (buf); 135256b680eSclaudio } 136256b680eSclaudio 137bf8e2920Sclaudio const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES; 138bf8e2920Sclaudio 139256b680eSclaudio /* NOTE: this function does not check if the type/subtype combo is 140536f41e5Sclaudio * actually valid. */ 141536f41e5Sclaudio const char * 142f8162053Sclaudio log_ext_subtype(int type, uint8_t subtype) 143536f41e5Sclaudio { 144536f41e5Sclaudio static char etype[6]; 145bf8e2920Sclaudio const struct ext_comm_pairs *cp; 146536f41e5Sclaudio 147bf8e2920Sclaudio for (cp = iana_ext_comms; cp->subname != NULL; cp++) { 1480e6216fdSclaudio if ((type == cp->type || type == -1) && subtype == cp->subtype) 149bf8e2920Sclaudio return (cp->subname); 150bf8e2920Sclaudio } 151d6340f7aSderaadt snprintf(etype, sizeof(etype), "[%u]", subtype); 152536f41e5Sclaudio return (etype); 153536f41e5Sclaudio } 154536f41e5Sclaudio 1551e590dcfSclaudio const char * 156a78f83ceSderaadt log_reason(const char *communication) { 157a78f83ceSderaadt static char buf[(REASON_LEN - 1) * 4 + 1]; 1580561b344Sphessler 1590561b344Sphessler strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL); 1600561b344Sphessler 1610561b344Sphessler return buf; 1620561b344Sphessler } 1630561b344Sphessler 1640561b344Sphessler const char * 165bd9df44eSclaudio log_rtr_error(enum rtr_error err) 166bd9df44eSclaudio { 167bd9df44eSclaudio static char buf[20]; 168bd9df44eSclaudio 169bd9df44eSclaudio switch (err) { 170bd9df44eSclaudio case NO_ERROR: 171bd9df44eSclaudio return "No Error"; 172bd9df44eSclaudio case CORRUPT_DATA: 173bd9df44eSclaudio return "Corrupt Data"; 174bd9df44eSclaudio case INTERNAL_ERROR: 175bd9df44eSclaudio return "Internal Error"; 176bd9df44eSclaudio case NO_DATA_AVAILABLE: 177bd9df44eSclaudio return "No Data Available"; 178bd9df44eSclaudio case INVALID_REQUEST: 179bd9df44eSclaudio return "Invalid Request"; 180bd9df44eSclaudio case UNSUPP_PROTOCOL_VERS: 181bd9df44eSclaudio return "Unsupported Protocol Version"; 182bd9df44eSclaudio case UNSUPP_PDU_TYPE: 183bd9df44eSclaudio return "Unsupported PDU Type"; 184bd9df44eSclaudio case UNK_REC_WDRAWL: 185bd9df44eSclaudio return "Withdrawl of Unknown Record"; 186bd9df44eSclaudio case DUP_REC_RECV: 187bd9df44eSclaudio return "Duplicate Announcement Received"; 188bd9df44eSclaudio case UNEXP_PROTOCOL_VERS: 189bd9df44eSclaudio return "Unexpected Protocol Version"; 190bd9df44eSclaudio default: 191bd9df44eSclaudio snprintf(buf, sizeof(buf), "unknown %u", err); 192bd9df44eSclaudio return buf; 193bd9df44eSclaudio } 194bd9df44eSclaudio } 195bd9df44eSclaudio 196bd9df44eSclaudio const char * 19739386878Sclaudio aspath_delim(uint8_t seg_type, int closing) 1981e590dcfSclaudio { 1991e590dcfSclaudio static char db[8]; 2001e590dcfSclaudio 2011e590dcfSclaudio switch (seg_type) { 2021e590dcfSclaudio case AS_SET: 2031e590dcfSclaudio if (!closing) 2041e590dcfSclaudio return ("{ "); 2051e590dcfSclaudio else 2061e590dcfSclaudio return (" }"); 2071e590dcfSclaudio case AS_SEQUENCE: 2081e590dcfSclaudio return (""); 2091e590dcfSclaudio case AS_CONFED_SEQUENCE: 2101e590dcfSclaudio if (!closing) 2111e590dcfSclaudio return ("( "); 2121e590dcfSclaudio else 2131e590dcfSclaudio return (" )"); 2141e590dcfSclaudio case AS_CONFED_SET: 2151e590dcfSclaudio if (!closing) 2161e590dcfSclaudio return ("[ "); 2171e590dcfSclaudio else 2181e590dcfSclaudio return (" ]"); 2191e590dcfSclaudio default: 2201e590dcfSclaudio if (!closing) 2211e590dcfSclaudio snprintf(db, sizeof(db), "!%u ", seg_type); 2221e590dcfSclaudio else 2231e590dcfSclaudio snprintf(db, sizeof(db), " !%u", seg_type); 2241e590dcfSclaudio return (db); 2251e590dcfSclaudio } 2261e590dcfSclaudio } 2271e590dcfSclaudio 2282ffcd4e0Sclaudio int 22939386878Sclaudio aspath_snprint(char *buf, size_t size, void *data, uint16_t len) 2302ffcd4e0Sclaudio { 2312ffcd4e0Sclaudio #define UPDATE() \ 2322ffcd4e0Sclaudio do { \ 233515e489cSderaadt if (r < 0) \ 2342ffcd4e0Sclaudio return (-1); \ 2352ffcd4e0Sclaudio total_size += r; \ 2362ffcd4e0Sclaudio if ((unsigned int)r < size) { \ 2372ffcd4e0Sclaudio size -= r; \ 2382ffcd4e0Sclaudio buf += r; \ 2392ffcd4e0Sclaudio } else { \ 2402ffcd4e0Sclaudio buf += size; \ 2412ffcd4e0Sclaudio size = 0; \ 2422ffcd4e0Sclaudio } \ 2432ffcd4e0Sclaudio } while (0) 24439386878Sclaudio uint8_t *seg; 2452ffcd4e0Sclaudio int r, total_size; 24639386878Sclaudio uint16_t seg_size; 24739386878Sclaudio uint8_t i, seg_type, seg_len; 2482ffcd4e0Sclaudio 2492ffcd4e0Sclaudio total_size = 0; 2502ffcd4e0Sclaudio seg = data; 2512ffcd4e0Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 2522ffcd4e0Sclaudio seg_type = seg[0]; 2532ffcd4e0Sclaudio seg_len = seg[1]; 25439386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 2552ffcd4e0Sclaudio 2561e590dcfSclaudio r = snprintf(buf, size, "%s%s", 2571e590dcfSclaudio total_size != 0 ? " " : "", 2581e590dcfSclaudio aspath_delim(seg_type, 0)); 2592ffcd4e0Sclaudio UPDATE(); 2602ffcd4e0Sclaudio 2612ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) { 2620c88bf70Sclaudio r = snprintf(buf, size, "%s", 2630c88bf70Sclaudio log_as(aspath_extract(seg, i))); 2642ffcd4e0Sclaudio UPDATE(); 2652ffcd4e0Sclaudio if (i + 1 < seg_len) { 2662ffcd4e0Sclaudio r = snprintf(buf, size, " "); 2672ffcd4e0Sclaudio UPDATE(); 2682ffcd4e0Sclaudio } 2692ffcd4e0Sclaudio } 2701e590dcfSclaudio r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1)); 2712ffcd4e0Sclaudio UPDATE(); 2722ffcd4e0Sclaudio } 27355e49665Sclaudio /* ensure that we have a valid C-string especially for empty as path */ 2742ffcd4e0Sclaudio if (size > 0) 2752ffcd4e0Sclaudio *buf = '\0'; 2762ffcd4e0Sclaudio 2772ffcd4e0Sclaudio return (total_size); 2782ffcd4e0Sclaudio #undef UPDATE 2792ffcd4e0Sclaudio } 2802ffcd4e0Sclaudio 2812ffcd4e0Sclaudio int 28239386878Sclaudio aspath_asprint(char **ret, void *data, uint16_t len) 2832ffcd4e0Sclaudio { 2842ffcd4e0Sclaudio size_t slen; 2852ffcd4e0Sclaudio int plen; 2862ffcd4e0Sclaudio 2872ffcd4e0Sclaudio slen = aspath_strlen(data, len) + 1; 2882ffcd4e0Sclaudio *ret = malloc(slen); 2892ffcd4e0Sclaudio if (*ret == NULL) 2902ffcd4e0Sclaudio return (-1); 2912ffcd4e0Sclaudio 2922ffcd4e0Sclaudio plen = aspath_snprint(*ret, slen, data, len); 2932ffcd4e0Sclaudio if (plen == -1) { 2942ffcd4e0Sclaudio free(*ret); 2952ffcd4e0Sclaudio *ret = NULL; 2962ffcd4e0Sclaudio return (-1); 2972ffcd4e0Sclaudio } 2982ffcd4e0Sclaudio 2992ffcd4e0Sclaudio return (0); 3002ffcd4e0Sclaudio } 3012ffcd4e0Sclaudio 3022ffcd4e0Sclaudio size_t 30339386878Sclaudio aspath_strlen(void *data, uint16_t len) 3042ffcd4e0Sclaudio { 30539386878Sclaudio uint8_t *seg; 3062ffcd4e0Sclaudio int total_size; 30739386878Sclaudio uint32_t as; 30839386878Sclaudio uint16_t seg_size; 30939386878Sclaudio uint8_t i, seg_type, seg_len; 3102ffcd4e0Sclaudio 3112ffcd4e0Sclaudio total_size = 0; 3122ffcd4e0Sclaudio seg = data; 3132ffcd4e0Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 3142ffcd4e0Sclaudio seg_type = seg[0]; 3152ffcd4e0Sclaudio seg_len = seg[1]; 31639386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 3172ffcd4e0Sclaudio 3182ffcd4e0Sclaudio if (seg_type == AS_SET) 3192ffcd4e0Sclaudio if (total_size != 0) 3202ffcd4e0Sclaudio total_size += 3; 3212ffcd4e0Sclaudio else 3222ffcd4e0Sclaudio total_size += 2; 3232ffcd4e0Sclaudio else if (total_size != 0) 3242ffcd4e0Sclaudio total_size += 1; 3252ffcd4e0Sclaudio 3262ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) { 3272ffcd4e0Sclaudio as = aspath_extract(seg, i); 3280c88bf70Sclaudio 3298db4f5d2Sclaudio do { 3308db4f5d2Sclaudio total_size++; 3318db4f5d2Sclaudio } while ((as = as / 10) != 0); 3322ffcd4e0Sclaudio 3332ffcd4e0Sclaudio if (i + 1 < seg_len) 3342ffcd4e0Sclaudio total_size += 1; 3352ffcd4e0Sclaudio } 3362ffcd4e0Sclaudio 3372ffcd4e0Sclaudio if (seg_type == AS_SET) 3382ffcd4e0Sclaudio total_size += 2; 3392ffcd4e0Sclaudio } 3402ffcd4e0Sclaudio return (total_size); 3412ffcd4e0Sclaudio } 3422ffcd4e0Sclaudio 3432ffcd4e0Sclaudio /* 3442ffcd4e0Sclaudio * Extract the asnum out of the as segment at the specified position. 3452ffcd4e0Sclaudio * Direct access is not possible because of non-aligned reads. 346c5508ee4Sclaudio * ATTENTION: no bounds checks are done. 3472ffcd4e0Sclaudio */ 34839386878Sclaudio uint32_t 3492ffcd4e0Sclaudio aspath_extract(const void *seg, int pos) 3502ffcd4e0Sclaudio { 3512ffcd4e0Sclaudio const u_char *ptr = seg; 35239386878Sclaudio uint32_t as; 3532ffcd4e0Sclaudio 35439386878Sclaudio ptr += 2 + sizeof(uint32_t) * pos; 35539386878Sclaudio memcpy(&as, ptr, sizeof(uint32_t)); 3560c88bf70Sclaudio return (ntohl(as)); 3572ffcd4e0Sclaudio } 35821a825c9Sclaudio 359de5c2eedSclaudio /* 36029328a94Sclaudio * Verify that the aspath is correctly encoded. 36129328a94Sclaudio */ 36229328a94Sclaudio int 36339386878Sclaudio aspath_verify(void *data, uint16_t len, int as4byte, int noset) 36429328a94Sclaudio { 36539386878Sclaudio uint8_t *seg = data; 36639386878Sclaudio uint16_t seg_size, as_size = 2; 36739386878Sclaudio uint8_t seg_len, seg_type; 36829328a94Sclaudio int error = 0; 36929328a94Sclaudio 37029328a94Sclaudio if (len & 1) 37129328a94Sclaudio /* odd length aspath are invalid */ 37229328a94Sclaudio return (AS_ERR_BAD); 37329328a94Sclaudio 37429328a94Sclaudio if (as4byte) 37529328a94Sclaudio as_size = 4; 37629328a94Sclaudio 37729328a94Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 37839386878Sclaudio const uint8_t *ptr; 37929328a94Sclaudio int pos; 38029328a94Sclaudio 38129328a94Sclaudio if (len < 2) /* header length check */ 38229328a94Sclaudio return (AS_ERR_BAD); 38329328a94Sclaudio seg_type = seg[0]; 38429328a94Sclaudio seg_len = seg[1]; 38529328a94Sclaudio 386d04df938Sclaudio if (seg_len == 0) 387d04df938Sclaudio /* empty aspath segments are not allowed */ 388d04df938Sclaudio return (AS_ERR_BAD); 389d04df938Sclaudio 39029328a94Sclaudio /* 39129328a94Sclaudio * BGP confederations should not show up but consider them 39229328a94Sclaudio * as a soft error which invalidates the path but keeps the 39329328a94Sclaudio * bgp session running. 39429328a94Sclaudio */ 39529328a94Sclaudio if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET) 39629328a94Sclaudio error = AS_ERR_SOFT; 397aa528464Sclaudio /* 398aa528464Sclaudio * If AS_SET filtering (RFC6472) is on, error out on AS_SET 399aa528464Sclaudio * as well. 400aa528464Sclaudio */ 401aa528464Sclaudio if (noset && seg_type == AS_SET) 402aa528464Sclaudio error = AS_ERR_SOFT; 40329328a94Sclaudio if (seg_type != AS_SET && seg_type != AS_SEQUENCE && 40429328a94Sclaudio seg_type != AS_CONFED_SEQUENCE && seg_type != AS_CONFED_SET) 40529328a94Sclaudio return (AS_ERR_TYPE); 40629328a94Sclaudio 40729328a94Sclaudio seg_size = 2 + as_size * seg_len; 40829328a94Sclaudio 40929328a94Sclaudio if (seg_size > len) 41029328a94Sclaudio return (AS_ERR_LEN); 41129328a94Sclaudio 41229328a94Sclaudio /* RFC 7607 - AS 0 is considered malformed */ 41329328a94Sclaudio ptr = seg + 2; 41429328a94Sclaudio for (pos = 0; pos < seg_len; pos++) { 41539386878Sclaudio uint32_t as; 41629328a94Sclaudio 41729328a94Sclaudio memcpy(&as, ptr, as_size); 41829328a94Sclaudio if (as == 0) 41956a9a1b8Sclaudio error = AS_ERR_SOFT; 42051491708Sclaudio ptr += as_size; 42129328a94Sclaudio } 42229328a94Sclaudio } 42329328a94Sclaudio return (error); /* aspath is valid but probably not loop free */ 42429328a94Sclaudio } 42529328a94Sclaudio 42629328a94Sclaudio /* 42729328a94Sclaudio * convert a 2 byte aspath to a 4 byte one. 42829328a94Sclaudio */ 42929328a94Sclaudio u_char * 43039386878Sclaudio aspath_inflate(void *data, uint16_t len, uint16_t *newlen) 43129328a94Sclaudio { 43239386878Sclaudio uint8_t *seg, *nseg, *ndata; 43339386878Sclaudio uint16_t seg_size, olen, nlen; 43439386878Sclaudio uint8_t seg_len; 43529328a94Sclaudio 43629328a94Sclaudio /* first calculate the length of the aspath */ 43729328a94Sclaudio seg = data; 43829328a94Sclaudio nlen = 0; 43929328a94Sclaudio for (olen = len; olen > 0; olen -= seg_size, seg += seg_size) { 44029328a94Sclaudio seg_len = seg[1]; 44139386878Sclaudio seg_size = 2 + sizeof(uint16_t) * seg_len; 44239386878Sclaudio nlen += 2 + sizeof(uint32_t) * seg_len; 44329328a94Sclaudio 44429328a94Sclaudio if (seg_size > olen) { 44529328a94Sclaudio errno = ERANGE; 44629328a94Sclaudio return (NULL); 44729328a94Sclaudio } 44829328a94Sclaudio } 44929328a94Sclaudio 45029328a94Sclaudio *newlen = nlen; 45129328a94Sclaudio if ((ndata = malloc(nlen)) == NULL) 45229328a94Sclaudio return (NULL); 45329328a94Sclaudio 45429328a94Sclaudio /* then copy the aspath */ 45529328a94Sclaudio seg = data; 45629328a94Sclaudio for (nseg = ndata; nseg < ndata + nlen; ) { 45729328a94Sclaudio *nseg++ = *seg++; 45829328a94Sclaudio *nseg++ = seg_len = *seg++; 45929328a94Sclaudio for (; seg_len > 0; seg_len--) { 46029328a94Sclaudio *nseg++ = 0; 46129328a94Sclaudio *nseg++ = 0; 46229328a94Sclaudio *nseg++ = *seg++; 46329328a94Sclaudio *nseg++ = *seg++; 46429328a94Sclaudio } 46529328a94Sclaudio } 46629328a94Sclaudio 46729328a94Sclaudio return (ndata); 46829328a94Sclaudio } 46929328a94Sclaudio 4706d3e8673Sclaudio /* NLRI functions to extract prefixes from the NLRI blobs */ 4716d3e8673Sclaudio static int 47239386878Sclaudio extract_prefix(u_char *p, uint16_t len, void *va, 47339386878Sclaudio uint8_t pfxlen, uint8_t max) 4746d3e8673Sclaudio { 4756d3e8673Sclaudio static u_char addrmask[] = { 4766d3e8673Sclaudio 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; 4776d3e8673Sclaudio u_char *a = va; 4786d3e8673Sclaudio int i; 47939386878Sclaudio uint16_t plen = 0; 4806d3e8673Sclaudio 4816d3e8673Sclaudio for (i = 0; pfxlen && i < max; i++) { 4826d3e8673Sclaudio if (len <= plen) 4836d3e8673Sclaudio return (-1); 4846d3e8673Sclaudio if (pfxlen < 8) { 4856d3e8673Sclaudio a[i] = *p++ & addrmask[pfxlen]; 4866d3e8673Sclaudio plen++; 4876d3e8673Sclaudio break; 4886d3e8673Sclaudio } else { 4896d3e8673Sclaudio a[i] = *p++; 4906d3e8673Sclaudio plen++; 4916d3e8673Sclaudio pfxlen -= 8; 4926d3e8673Sclaudio } 4936d3e8673Sclaudio } 4946d3e8673Sclaudio return (plen); 4956d3e8673Sclaudio } 4966d3e8673Sclaudio 4976d3e8673Sclaudio int 49839386878Sclaudio nlri_get_prefix(u_char *p, uint16_t len, struct bgpd_addr *prefix, 49939386878Sclaudio uint8_t *prefixlen) 5006d3e8673Sclaudio { 5016d3e8673Sclaudio int plen; 50239386878Sclaudio uint8_t pfxlen; 5036d3e8673Sclaudio 5046d3e8673Sclaudio if (len < 1) 5056d3e8673Sclaudio return (-1); 5066d3e8673Sclaudio 5076d3e8673Sclaudio pfxlen = *p++; 5086d3e8673Sclaudio len--; 5096d3e8673Sclaudio 5106d3e8673Sclaudio bzero(prefix, sizeof(struct bgpd_addr)); 5116d3e8673Sclaudio prefix->aid = AID_INET; 5126d3e8673Sclaudio *prefixlen = pfxlen; 5136d3e8673Sclaudio 5146d3e8673Sclaudio if (pfxlen > 32) 5156d3e8673Sclaudio return (-1); 5166d3e8673Sclaudio if ((plen = extract_prefix(p, len, &prefix->v4, pfxlen, 5176d3e8673Sclaudio sizeof(prefix->v4))) == -1) 5186d3e8673Sclaudio return (-1); 5196d3e8673Sclaudio 5206d3e8673Sclaudio return (plen + 1); /* pfxlen needs to be added */ 5216d3e8673Sclaudio } 5226d3e8673Sclaudio 5236d3e8673Sclaudio int 52439386878Sclaudio nlri_get_prefix6(u_char *p, uint16_t len, struct bgpd_addr *prefix, 52539386878Sclaudio uint8_t *prefixlen) 5266d3e8673Sclaudio { 5276d3e8673Sclaudio int plen; 52839386878Sclaudio uint8_t pfxlen; 5296d3e8673Sclaudio 5306d3e8673Sclaudio if (len < 1) 5316d3e8673Sclaudio return (-1); 5326d3e8673Sclaudio 5336d3e8673Sclaudio pfxlen = *p++; 5346d3e8673Sclaudio len--; 5356d3e8673Sclaudio 5366d3e8673Sclaudio bzero(prefix, sizeof(struct bgpd_addr)); 5376d3e8673Sclaudio prefix->aid = AID_INET6; 5386d3e8673Sclaudio *prefixlen = pfxlen; 5396d3e8673Sclaudio 5406d3e8673Sclaudio if (pfxlen > 128) 5416d3e8673Sclaudio return (-1); 5426d3e8673Sclaudio if ((plen = extract_prefix(p, len, &prefix->v6, pfxlen, 5436d3e8673Sclaudio sizeof(prefix->v6))) == -1) 5446d3e8673Sclaudio return (-1); 5456d3e8673Sclaudio 5466d3e8673Sclaudio return (plen + 1); /* pfxlen needs to be added */ 5476d3e8673Sclaudio } 5486d3e8673Sclaudio 5496d3e8673Sclaudio int 55039386878Sclaudio nlri_get_vpn4(u_char *p, uint16_t len, struct bgpd_addr *prefix, 55139386878Sclaudio uint8_t *prefixlen, int withdraw) 5526d3e8673Sclaudio { 5536d3e8673Sclaudio int rv, done = 0; 55439386878Sclaudio uint16_t plen; 55539386878Sclaudio uint8_t pfxlen; 5566d3e8673Sclaudio 5576d3e8673Sclaudio if (len < 1) 5586d3e8673Sclaudio return (-1); 5596d3e8673Sclaudio 5606d3e8673Sclaudio memcpy(&pfxlen, p, 1); 5616d3e8673Sclaudio p += 1; 5626d3e8673Sclaudio plen = 1; 5636d3e8673Sclaudio 5646d3e8673Sclaudio bzero(prefix, sizeof(struct bgpd_addr)); 5656d3e8673Sclaudio 5666d3e8673Sclaudio /* label stack */ 5676d3e8673Sclaudio do { 5686d3e8673Sclaudio if (len - plen < 3 || pfxlen < 3 * 8) 5696d3e8673Sclaudio return (-1); 5703038d3d1Sclaudio if (prefix->labellen + 3U > 5713038d3d1Sclaudio sizeof(prefix->labelstack)) 5726d3e8673Sclaudio return (-1); 5736d3e8673Sclaudio if (withdraw) { 5746d3e8673Sclaudio /* on withdraw ignore the labelstack all together */ 5756d3e8673Sclaudio plen += 3; 5766d3e8673Sclaudio pfxlen -= 3 * 8; 5776d3e8673Sclaudio break; 5786d3e8673Sclaudio } 5793038d3d1Sclaudio prefix->labelstack[prefix->labellen++] = *p++; 5803038d3d1Sclaudio prefix->labelstack[prefix->labellen++] = *p++; 5813038d3d1Sclaudio prefix->labelstack[prefix->labellen] = *p++; 5823038d3d1Sclaudio if (prefix->labelstack[prefix->labellen] & 5836d3e8673Sclaudio BGP_MPLS_BOS) 5846d3e8673Sclaudio done = 1; 5853038d3d1Sclaudio prefix->labellen++; 5866d3e8673Sclaudio plen += 3; 5876d3e8673Sclaudio pfxlen -= 3 * 8; 5886d3e8673Sclaudio } while (!done); 5896d3e8673Sclaudio 5906d3e8673Sclaudio /* RD */ 59139386878Sclaudio if (len - plen < (int)sizeof(uint64_t) || 59239386878Sclaudio pfxlen < sizeof(uint64_t) * 8) 5936d3e8673Sclaudio return (-1); 59439386878Sclaudio memcpy(&prefix->rd, p, sizeof(uint64_t)); 59539386878Sclaudio pfxlen -= sizeof(uint64_t) * 8; 59639386878Sclaudio p += sizeof(uint64_t); 59739386878Sclaudio plen += sizeof(uint64_t); 5986d3e8673Sclaudio 5996d3e8673Sclaudio /* prefix */ 6006d3e8673Sclaudio prefix->aid = AID_VPN_IPv4; 6016d3e8673Sclaudio *prefixlen = pfxlen; 6026d3e8673Sclaudio 6036d3e8673Sclaudio if (pfxlen > 32) 6046d3e8673Sclaudio return (-1); 6053038d3d1Sclaudio if ((rv = extract_prefix(p, len, &prefix->v4, 6063038d3d1Sclaudio pfxlen, sizeof(prefix->v4))) == -1) 6076d3e8673Sclaudio return (-1); 6086d3e8673Sclaudio 6096d3e8673Sclaudio return (plen + rv); 6106d3e8673Sclaudio } 6116d3e8673Sclaudio 612290f96faSdenis int 61339386878Sclaudio nlri_get_vpn6(u_char *p, uint16_t len, struct bgpd_addr *prefix, 61439386878Sclaudio uint8_t *prefixlen, int withdraw) 615290f96faSdenis { 616290f96faSdenis int rv, done = 0; 61739386878Sclaudio uint16_t plen; 61839386878Sclaudio uint8_t pfxlen; 619290f96faSdenis 620290f96faSdenis if (len < 1) 621290f96faSdenis return (-1); 622290f96faSdenis 623290f96faSdenis memcpy(&pfxlen, p, 1); 624290f96faSdenis p += 1; 625290f96faSdenis plen = 1; 626290f96faSdenis 627290f96faSdenis memset(prefix, 0, sizeof(struct bgpd_addr)); 628290f96faSdenis 629290f96faSdenis /* label stack */ 630290f96faSdenis do { 631290f96faSdenis if (len - plen < 3 || pfxlen < 3 * 8) 632290f96faSdenis return (-1); 6333038d3d1Sclaudio if (prefix->labellen + 3U > 6343038d3d1Sclaudio sizeof(prefix->labelstack)) 635290f96faSdenis return (-1); 636290f96faSdenis if (withdraw) { 637290f96faSdenis /* on withdraw ignore the labelstack all together */ 638290f96faSdenis plen += 3; 639290f96faSdenis pfxlen -= 3 * 8; 640290f96faSdenis break; 641290f96faSdenis } 642290f96faSdenis 6433038d3d1Sclaudio prefix->labelstack[prefix->labellen++] = *p++; 6443038d3d1Sclaudio prefix->labelstack[prefix->labellen++] = *p++; 6453038d3d1Sclaudio prefix->labelstack[prefix->labellen] = *p++; 6463038d3d1Sclaudio if (prefix->labelstack[prefix->labellen] & 647290f96faSdenis BGP_MPLS_BOS) 648290f96faSdenis done = 1; 6493038d3d1Sclaudio prefix->labellen++; 650290f96faSdenis plen += 3; 651290f96faSdenis pfxlen -= 3 * 8; 652290f96faSdenis } while (!done); 653290f96faSdenis 654290f96faSdenis /* RD */ 65539386878Sclaudio if (len - plen < (int)sizeof(uint64_t) || 65639386878Sclaudio pfxlen < sizeof(uint64_t) * 8) 657290f96faSdenis return (-1); 658290f96faSdenis 65939386878Sclaudio memcpy(&prefix->rd, p, sizeof(uint64_t)); 66039386878Sclaudio pfxlen -= sizeof(uint64_t) * 8; 66139386878Sclaudio p += sizeof(uint64_t); 66239386878Sclaudio plen += sizeof(uint64_t); 663290f96faSdenis 664290f96faSdenis /* prefix */ 665290f96faSdenis prefix->aid = AID_VPN_IPv6; 666290f96faSdenis *prefixlen = pfxlen; 667290f96faSdenis 668290f96faSdenis if (pfxlen > 128) 669290f96faSdenis return (-1); 670290f96faSdenis 6713038d3d1Sclaudio if ((rv = extract_prefix(p, len, &prefix->v6, 6723038d3d1Sclaudio pfxlen, sizeof(prefix->v6))) == -1) 673290f96faSdenis return (-1); 674290f96faSdenis 675290f96faSdenis return (plen + rv); 676290f96faSdenis } 677290f96faSdenis 678fa3a38bbSclaudio static in_addr_t 679fa3a38bbSclaudio prefixlen2mask(uint8_t prefixlen) 680fa3a38bbSclaudio { 681fa3a38bbSclaudio if (prefixlen == 0) 682fa3a38bbSclaudio return (0); 683290f96faSdenis 684fa3a38bbSclaudio return (0xffffffff << (32 - prefixlen)); 685fa3a38bbSclaudio } 686290f96faSdenis 68729328a94Sclaudio /* 688de5c2eedSclaudio * This function will have undefined behaviour if the passed in prefixlen is 689290f96faSdenis * too large for the respective bgpd_addr address family. 690de5c2eedSclaudio */ 691fafbb788Sclaudio int 692fafbb788Sclaudio prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b, 693fafbb788Sclaudio int prefixlen) 694fafbb788Sclaudio { 695fafbb788Sclaudio in_addr_t mask, aa, ba; 696fafbb788Sclaudio int i; 69739386878Sclaudio uint8_t m; 698fafbb788Sclaudio 699fafbb788Sclaudio if (a->aid != b->aid) 700fafbb788Sclaudio return (a->aid - b->aid); 701fafbb788Sclaudio 702fafbb788Sclaudio switch (a->aid) { 7033038d3d1Sclaudio case AID_VPN_IPv4: 7043038d3d1Sclaudio if (be64toh(a->rd) > be64toh(b->rd)) 7053038d3d1Sclaudio return (1); 7063038d3d1Sclaudio if (be64toh(a->rd) < be64toh(b->rd)) 7073038d3d1Sclaudio return (-1); 7083038d3d1Sclaudio /* FALLTHROUGH */ 709fafbb788Sclaudio case AID_INET: 7107da59fecSclaudio if (prefixlen == 0) 7117da59fecSclaudio return (0); 712fafbb788Sclaudio if (prefixlen > 32) 713de5c2eedSclaudio return (-1); 714fafbb788Sclaudio mask = htonl(prefixlen2mask(prefixlen)); 715fafbb788Sclaudio aa = ntohl(a->v4.s_addr & mask); 716fafbb788Sclaudio ba = ntohl(b->v4.s_addr & mask); 7173038d3d1Sclaudio if (aa > ba) 7183038d3d1Sclaudio return (1); 7193038d3d1Sclaudio if (aa < ba) 7203038d3d1Sclaudio return (-1); 7213038d3d1Sclaudio break; 7223038d3d1Sclaudio case AID_VPN_IPv6: 7233038d3d1Sclaudio if (be64toh(a->rd) > be64toh(b->rd)) 7243038d3d1Sclaudio return (1); 7253038d3d1Sclaudio if (be64toh(a->rd) < be64toh(b->rd)) 7263038d3d1Sclaudio return (-1); 7273038d3d1Sclaudio /* FALLTHROUGH */ 728fafbb788Sclaudio case AID_INET6: 7297da59fecSclaudio if (prefixlen == 0) 7307da59fecSclaudio return (0); 731fafbb788Sclaudio if (prefixlen > 128) 732de5c2eedSclaudio return (-1); 733fafbb788Sclaudio for (i = 0; i < prefixlen / 8; i++) 734fafbb788Sclaudio if (a->v6.s6_addr[i] != b->v6.s6_addr[i]) 735fafbb788Sclaudio return (a->v6.s6_addr[i] - b->v6.s6_addr[i]); 736fafbb788Sclaudio i = prefixlen % 8; 737fafbb788Sclaudio if (i) { 738fafbb788Sclaudio m = 0xff00 >> i; 739fafbb788Sclaudio if ((a->v6.s6_addr[prefixlen / 8] & m) != 740fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m)) 741fafbb788Sclaudio return ((a->v6.s6_addr[prefixlen / 8] & m) - 742fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m)); 743fafbb788Sclaudio } 7443038d3d1Sclaudio break; 7453038d3d1Sclaudio default: 7463038d3d1Sclaudio return (-1); 7473038d3d1Sclaudio } 7483038d3d1Sclaudio 7493038d3d1Sclaudio if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) { 7503038d3d1Sclaudio if (a->labellen > b->labellen) 7513038d3d1Sclaudio return (1); 7523038d3d1Sclaudio if (a->labellen < b->labellen) 7533038d3d1Sclaudio return (-1); 7543038d3d1Sclaudio return (memcmp(a->labelstack, b->labelstack, a->labellen)); 7553038d3d1Sclaudio } 756fafbb788Sclaudio return (0); 7573038d3d1Sclaudio 758fafbb788Sclaudio } 759fafbb788Sclaudio 76021a825c9Sclaudio void 7612b5c88feSclaudio inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen) 7622b5c88feSclaudio { 7632b5c88feSclaudio struct in_addr mask; 7642b5c88feSclaudio 7652b5c88feSclaudio mask.s_addr = htonl(prefixlen2mask(prefixlen)); 7662b5c88feSclaudio dest->s_addr = src->s_addr & mask.s_addr; 7672b5c88feSclaudio } 7682b5c88feSclaudio 7692b5c88feSclaudio void 77021a825c9Sclaudio inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen) 77121a825c9Sclaudio { 77221a825c9Sclaudio struct in6_addr mask; 77321a825c9Sclaudio int i; 77421a825c9Sclaudio 77521a825c9Sclaudio bzero(&mask, sizeof(mask)); 77621a825c9Sclaudio for (i = 0; i < prefixlen / 8; i++) 77721a825c9Sclaudio mask.s6_addr[i] = 0xff; 77821a825c9Sclaudio i = prefixlen % 8; 77921a825c9Sclaudio if (i) 78021a825c9Sclaudio mask.s6_addr[prefixlen / 8] = 0xff00 >> i; 78121a825c9Sclaudio 78221a825c9Sclaudio for (i = 0; i < 16; i++) 78321a825c9Sclaudio dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i]; 78421a825c9Sclaudio } 785d6c2e4e8Sclaudio 786d6c2e4e8Sclaudio /* address family translation functions */ 787d6c2e4e8Sclaudio const struct aid aid_vals[AID_MAX] = AID_VALS; 788d6c2e4e8Sclaudio 78986729c90Sclaudio const char * 79039386878Sclaudio aid2str(uint8_t aid) 79186729c90Sclaudio { 79286729c90Sclaudio if (aid < AID_MAX) 79386729c90Sclaudio return (aid_vals[aid].name); 79486729c90Sclaudio return ("unknown AID"); 79586729c90Sclaudio } 79686729c90Sclaudio 797d6c2e4e8Sclaudio int 79839386878Sclaudio aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi) 799d6c2e4e8Sclaudio { 800d6c2e4e8Sclaudio if (aid < AID_MAX) { 801d6c2e4e8Sclaudio *afi = aid_vals[aid].afi; 802d6c2e4e8Sclaudio *safi = aid_vals[aid].safi; 803d6c2e4e8Sclaudio return (0); 804d6c2e4e8Sclaudio } 805d6c2e4e8Sclaudio return (-1); 806d6c2e4e8Sclaudio } 807d6c2e4e8Sclaudio 808d6c2e4e8Sclaudio int 80939386878Sclaudio afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid) 810d6c2e4e8Sclaudio { 81139386878Sclaudio uint8_t i; 812d6c2e4e8Sclaudio 813d6c2e4e8Sclaudio for (i = 0; i < AID_MAX; i++) 814d6c2e4e8Sclaudio if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) { 815d6c2e4e8Sclaudio *aid = i; 816d6c2e4e8Sclaudio return (0); 817d6c2e4e8Sclaudio } 818d6c2e4e8Sclaudio 819d6c2e4e8Sclaudio return (-1); 820d6c2e4e8Sclaudio } 821d6c2e4e8Sclaudio 822d6c2e4e8Sclaudio sa_family_t 82339386878Sclaudio aid2af(uint8_t aid) 824d6c2e4e8Sclaudio { 825d6c2e4e8Sclaudio if (aid < AID_MAX) 826d6c2e4e8Sclaudio return (aid_vals[aid].af); 827d6c2e4e8Sclaudio return (AF_UNSPEC); 828d6c2e4e8Sclaudio } 829d6c2e4e8Sclaudio 830d6c2e4e8Sclaudio int 83139386878Sclaudio af2aid(sa_family_t af, uint8_t safi, uint8_t *aid) 832d6c2e4e8Sclaudio { 83339386878Sclaudio uint8_t i; 834d6c2e4e8Sclaudio 835d6c2e4e8Sclaudio if (safi == 0) /* default to unicast subclass */ 836d6c2e4e8Sclaudio safi = SAFI_UNICAST; 837d6c2e4e8Sclaudio 838d6c2e4e8Sclaudio for (i = 0; i < AID_MAX; i++) 839d6c2e4e8Sclaudio if (aid_vals[i].af == af && aid_vals[i].safi == safi) { 840d6c2e4e8Sclaudio *aid = i; 841d6c2e4e8Sclaudio return (0); 842d6c2e4e8Sclaudio } 843d6c2e4e8Sclaudio 844d6c2e4e8Sclaudio return (-1); 845d6c2e4e8Sclaudio } 846d6c2e4e8Sclaudio 84745350f87Sclaudio /* 84845350f87Sclaudio * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses 84945350f87Sclaudio * the included label stack is ignored and needs to be handled by the caller. 85045350f87Sclaudio */ 851d6c2e4e8Sclaudio struct sockaddr * 85239386878Sclaudio addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len) 853d6c2e4e8Sclaudio { 854d6c2e4e8Sclaudio static struct sockaddr_storage ss; 855d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss; 856d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss; 857d6c2e4e8Sclaudio 8584886db4cSclaudio if (addr == NULL || addr->aid == AID_UNSPEC) 8594886db4cSclaudio return (NULL); 86045350f87Sclaudio 8614886db4cSclaudio bzero(&ss, sizeof(ss)); 862d6c2e4e8Sclaudio switch (addr->aid) { 863d6c2e4e8Sclaudio case AID_INET: 8643038d3d1Sclaudio case AID_VPN_IPv4: 865d6c2e4e8Sclaudio sa_in->sin_family = AF_INET; 866d6c2e4e8Sclaudio sa_in->sin_addr.s_addr = addr->v4.s_addr; 867d6c2e4e8Sclaudio sa_in->sin_port = htons(port); 868255fe563Sclaudio *len = sizeof(struct sockaddr_in); 869d6c2e4e8Sclaudio break; 870d6c2e4e8Sclaudio case AID_INET6: 87145350f87Sclaudio case AID_VPN_IPv6: 87245350f87Sclaudio sa_in6->sin6_family = AF_INET6; 8733038d3d1Sclaudio memcpy(&sa_in6->sin6_addr, &addr->v6, 87445350f87Sclaudio sizeof(sa_in6->sin6_addr)); 87545350f87Sclaudio sa_in6->sin6_port = htons(port); 87645350f87Sclaudio sa_in6->sin6_scope_id = addr->scope_id; 87745350f87Sclaudio *len = sizeof(struct sockaddr_in6); 87845350f87Sclaudio break; 879d6c2e4e8Sclaudio } 880d6c2e4e8Sclaudio 881d6c2e4e8Sclaudio return ((struct sockaddr *)&ss); 882d6c2e4e8Sclaudio } 883d6c2e4e8Sclaudio 884d6c2e4e8Sclaudio void 88539386878Sclaudio sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port) 886d6c2e4e8Sclaudio { 887d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)sa; 888d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa; 889d6c2e4e8Sclaudio 890d6c2e4e8Sclaudio bzero(addr, sizeof(*addr)); 891d6c2e4e8Sclaudio switch (sa->sa_family) { 892d6c2e4e8Sclaudio case AF_INET: 893d6c2e4e8Sclaudio addr->aid = AID_INET; 894d6c2e4e8Sclaudio memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4)); 895a27d9e33Sclaudio if (port) 896a27d9e33Sclaudio *port = ntohs(sa_in->sin_port); 897d6c2e4e8Sclaudio break; 898d6c2e4e8Sclaudio case AF_INET6: 899d6c2e4e8Sclaudio addr->aid = AID_INET6; 900be6ced5eSclaudio #ifdef __KAME__ 901be6ced5eSclaudio /* 902be6ced5eSclaudio * XXX thanks, KAME, for this ugliness... 903be6ced5eSclaudio * adopted from route/show.c 904be6ced5eSclaudio */ 905*5177244fSclaudio if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) || 906*5177244fSclaudio IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr) || 907*5177244fSclaudio IN6_IS_ADDR_MC_INTFACELOCAL(&sa_in6->sin6_addr)) && 908*5177244fSclaudio sa_in6->sin6_scope_id == 0) { 909be6ced5eSclaudio uint16_t tmp16; 910be6ced5eSclaudio memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2], 911be6ced5eSclaudio sizeof(tmp16)); 912be6ced5eSclaudio sa_in6->sin6_scope_id = ntohs(tmp16); 913be6ced5eSclaudio sa_in6->sin6_addr.s6_addr[2] = 0; 914be6ced5eSclaudio sa_in6->sin6_addr.s6_addr[3] = 0; 915be6ced5eSclaudio } 916be6ced5eSclaudio #endif 917*5177244fSclaudio memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6)); 918d6c2e4e8Sclaudio addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */ 919a27d9e33Sclaudio if (port) 920a27d9e33Sclaudio *port = ntohs(sa_in6->sin6_port); 921d6c2e4e8Sclaudio break; 922d6c2e4e8Sclaudio } 923d6c2e4e8Sclaudio } 9246e8089a5Sclaudio 9256e8089a5Sclaudio const char * 926bc757ddaSclaudio get_baudrate(unsigned long long baudrate, char *unit) 9276e8089a5Sclaudio { 9286e8089a5Sclaudio static char bbuf[16]; 9293eaf1285Sclaudio const unsigned long long kilo = 1000; 9303eaf1285Sclaudio const unsigned long long mega = 1000ULL * kilo; 9313eaf1285Sclaudio const unsigned long long giga = 1000ULL * mega; 9326e8089a5Sclaudio 9333eaf1285Sclaudio if (baudrate > giga) 9346e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu G%s", 9353eaf1285Sclaudio baudrate / giga, unit); 9363eaf1285Sclaudio else if (baudrate > mega) 9376e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu M%s", 9383eaf1285Sclaudio baudrate / mega, unit); 9393eaf1285Sclaudio else if (baudrate > kilo) 9406e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu K%s", 9413eaf1285Sclaudio baudrate / kilo, unit); 9426e8089a5Sclaudio else 9436e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu %s", 9446e8089a5Sclaudio baudrate, unit); 9456e8089a5Sclaudio 9466e8089a5Sclaudio return (bbuf); 9476e8089a5Sclaudio } 948