1*9ad78aa8Sclaudio /* $OpenBSD: util.c,v 1.86 2024/05/29 10:34:07 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
35eff7ddafSclaudio char *
ibuf_get_string(struct ibuf * buf,size_t len)36eff7ddafSclaudio ibuf_get_string(struct ibuf *buf, size_t len)
37eff7ddafSclaudio {
38eff7ddafSclaudio char *str;
39eff7ddafSclaudio
40eff7ddafSclaudio if (ibuf_size(buf) < len) {
41eff7ddafSclaudio errno = EBADMSG;
42eff7ddafSclaudio return (NULL);
43eff7ddafSclaudio }
44eff7ddafSclaudio str = strndup(ibuf_data(buf), len);
45eff7ddafSclaudio if (str == NULL)
46eff7ddafSclaudio return (NULL);
47eff7ddafSclaudio ibuf_skip(buf, len);
48eff7ddafSclaudio return (str);
49eff7ddafSclaudio }
50eff7ddafSclaudio
512ffcd4e0Sclaudio const char *
log_addr(const struct bgpd_addr * addr)522ffcd4e0Sclaudio log_addr(const struct bgpd_addr *addr)
532ffcd4e0Sclaudio {
54290f96faSdenis static char buf[74];
5545350f87Sclaudio struct sockaddr *sa;
565624d029Sclaudio socklen_t len;
572ffcd4e0Sclaudio
5845350f87Sclaudio sa = addr2sa(addr, 0, &len);
5915d8de66Sclaudio switch (addr->aid) {
6015d8de66Sclaudio case AID_INET:
6115d8de66Sclaudio case AID_INET6:
6245350f87Sclaudio return log_sockaddr(sa, len);
6315d8de66Sclaudio case AID_VPN_IPv4:
64290f96faSdenis case AID_VPN_IPv6:
653038d3d1Sclaudio snprintf(buf, sizeof(buf), "%s %s", log_rd(addr->rd),
6645350f87Sclaudio log_sockaddr(sa, len));
67290f96faSdenis return (buf);
6815d8de66Sclaudio }
6915d8de66Sclaudio return ("???");
702ffcd4e0Sclaudio }
712ffcd4e0Sclaudio
722ffcd4e0Sclaudio const char *
log_in6addr(const struct in6_addr * addr)732ffcd4e0Sclaudio log_in6addr(const struct in6_addr *addr)
742ffcd4e0Sclaudio {
752ffcd4e0Sclaudio struct sockaddr_in6 sa_in6;
762ffcd4e0Sclaudio
77eafe309eSclaudio memset(&sa_in6, 0, sizeof(sa_in6));
782ffcd4e0Sclaudio sa_in6.sin6_family = AF_INET6;
792ffcd4e0Sclaudio memcpy(&sa_in6.sin6_addr, addr, sizeof(sa_in6.sin6_addr));
802ffcd4e0Sclaudio
81be6ced5eSclaudio #ifdef __KAME__
822ffcd4e0Sclaudio /* XXX thanks, KAME, for this ugliness... adopted from route/show.c */
83bdec2ffaStb if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6.sin6_addr) ||
84bdec2ffaStb IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6.sin6_addr) ||
854ff2dba3Sclaudio IN6_IS_ADDR_MC_NODELOCAL(&sa_in6.sin6_addr)) &&
86bdec2ffaStb sa_in6.sin6_scope_id == 0) {
8739386878Sclaudio uint16_t tmp16;
882ffcd4e0Sclaudio memcpy(&tmp16, &sa_in6.sin6_addr.s6_addr[2], sizeof(tmp16));
892ffcd4e0Sclaudio sa_in6.sin6_scope_id = ntohs(tmp16);
902ffcd4e0Sclaudio sa_in6.sin6_addr.s6_addr[2] = 0;
912ffcd4e0Sclaudio sa_in6.sin6_addr.s6_addr[3] = 0;
922ffcd4e0Sclaudio }
93be6ced5eSclaudio #endif
942ffcd4e0Sclaudio
95255fe563Sclaudio return (log_sockaddr((struct sockaddr *)&sa_in6, sizeof(sa_in6)));
962ffcd4e0Sclaudio }
972ffcd4e0Sclaudio
982ffcd4e0Sclaudio const char *
log_sockaddr(struct sockaddr * sa,socklen_t len)99255fe563Sclaudio log_sockaddr(struct sockaddr *sa, socklen_t len)
1002ffcd4e0Sclaudio {
101*9ad78aa8Sclaudio static char buf[4][NI_MAXHOST];
102*9ad78aa8Sclaudio static int bufidx;
1032ffcd4e0Sclaudio
104*9ad78aa8Sclaudio bufidx = (bufidx + 1) % 4;
105*9ad78aa8Sclaudio if (sa == NULL || getnameinfo(sa, len, buf[bufidx], sizeof(buf[0]),
106*9ad78aa8Sclaudio NULL, 0, NI_NUMERICHOST))
1072ffcd4e0Sclaudio return ("(unknown)");
1082ffcd4e0Sclaudio else
109*9ad78aa8Sclaudio return (buf[bufidx]);
1102ffcd4e0Sclaudio }
1112ffcd4e0Sclaudio
1120c88bf70Sclaudio const char *
log_as(uint32_t as)11339386878Sclaudio log_as(uint32_t as)
1140c88bf70Sclaudio {
11506bcde9cSphessler static char buf[11]; /* "4294967294\0" */
1160c88bf70Sclaudio
117515e489cSderaadt if (snprintf(buf, sizeof(buf), "%u", as) < 0)
1180c88bf70Sclaudio return ("?");
11906bcde9cSphessler
1200c88bf70Sclaudio return (buf);
1210c88bf70Sclaudio }
1220c88bf70Sclaudio
123256b680eSclaudio const char *
log_rd(uint64_t rd)12439386878Sclaudio log_rd(uint64_t rd)
125256b680eSclaudio {
126256b680eSclaudio static char buf[32];
127256b680eSclaudio struct in_addr addr;
12839386878Sclaudio uint32_t u32;
12939386878Sclaudio uint16_t u16;
130256b680eSclaudio
131f4c0eb52Sclaudio rd = be64toh(rd);
132256b680eSclaudio switch (rd >> 48) {
133bf8e2920Sclaudio case EXT_COMMUNITY_TRANS_TWO_AS:
134256b680eSclaudio u32 = rd & 0xffffffff;
135256b680eSclaudio u16 = (rd >> 32) & 0xffff;
13632ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %hu:%u", u16, u32);
137256b680eSclaudio break;
138bf8e2920Sclaudio case EXT_COMMUNITY_TRANS_FOUR_AS:
139256b680eSclaudio u32 = (rd >> 16) & 0xffffffff;
140256b680eSclaudio u16 = rd & 0xffff;
14132ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %s:%hu", log_as(u32), u16);
142256b680eSclaudio break;
143bf8e2920Sclaudio case EXT_COMMUNITY_TRANS_IPV4:
144256b680eSclaudio u32 = (rd >> 16) & 0xffffffff;
145256b680eSclaudio u16 = rd & 0xffff;
146256b680eSclaudio addr.s_addr = htonl(u32);
14732ecd2d8Sderaadt snprintf(buf, sizeof(buf), "rd %s:%hu", inet_ntoa(addr), u16);
148256b680eSclaudio break;
149256b680eSclaudio default:
150ec5cb450Sclaudio snprintf(buf, sizeof(buf), "rd #%016llx",
151ec5cb450Sclaudio (unsigned long long)rd);
152ec5cb450Sclaudio break;
153256b680eSclaudio }
154256b680eSclaudio return (buf);
155256b680eSclaudio }
156256b680eSclaudio
157bf8e2920Sclaudio const struct ext_comm_pairs iana_ext_comms[] = IANA_EXT_COMMUNITIES;
158bf8e2920Sclaudio
159256b680eSclaudio /* NOTE: this function does not check if the type/subtype combo is
160536f41e5Sclaudio * actually valid. */
161536f41e5Sclaudio const char *
log_ext_subtype(int type,uint8_t subtype)162f8162053Sclaudio log_ext_subtype(int type, uint8_t subtype)
163536f41e5Sclaudio {
164536f41e5Sclaudio static char etype[6];
165bf8e2920Sclaudio const struct ext_comm_pairs *cp;
166536f41e5Sclaudio
167bf8e2920Sclaudio for (cp = iana_ext_comms; cp->subname != NULL; cp++) {
1680e6216fdSclaudio if ((type == cp->type || type == -1) && subtype == cp->subtype)
169bf8e2920Sclaudio return (cp->subname);
170bf8e2920Sclaudio }
171d6340f7aSderaadt snprintf(etype, sizeof(etype), "[%u]", subtype);
172536f41e5Sclaudio return (etype);
173536f41e5Sclaudio }
174536f41e5Sclaudio
1751e590dcfSclaudio const char *
log_reason(const char * communication)176a78f83ceSderaadt log_reason(const char *communication) {
177a78f83ceSderaadt static char buf[(REASON_LEN - 1) * 4 + 1];
1780561b344Sphessler
1790561b344Sphessler strnvis(buf, communication, sizeof(buf), VIS_NL | VIS_OCTAL);
1800561b344Sphessler
1810561b344Sphessler return buf;
1820561b344Sphessler }
1830561b344Sphessler
1846290e740Sclaudio static const char *
log_expires(time_t expires)1856290e740Sclaudio log_expires(time_t expires)
1866290e740Sclaudio {
1876290e740Sclaudio static char buf[32];
1886290e740Sclaudio
1896290e740Sclaudio buf[0] = '\0';
1906290e740Sclaudio if (expires != 0)
1916290e740Sclaudio snprintf(buf, sizeof(buf), " expires %lld", (long long)expires);
1926290e740Sclaudio return buf;
1936290e740Sclaudio }
1946290e740Sclaudio
1956290e740Sclaudio const char *
log_roa(struct roa * roa)1966290e740Sclaudio log_roa(struct roa *roa)
1976290e740Sclaudio {
1986290e740Sclaudio static char buf[256];
1996290e740Sclaudio char maxbuf[32];
2002fd9f52dSmiod #if defined(__GNUC__) && __GNUC__ < 4
2012fd9f52dSmiod struct bgpd_addr addr = { .aid = roa->aid };
2022fd9f52dSmiod addr.v6 = roa->prefix.inet6;
2032fd9f52dSmiod #else
2042fd9f52dSmiod struct bgpd_addr addr = { .aid = roa->aid, .v6 = roa->prefix.inet6 };
2052fd9f52dSmiod #endif
2066290e740Sclaudio
2076290e740Sclaudio maxbuf[0] = '\0';
2086290e740Sclaudio if (roa->prefixlen != roa->maxlen)
2096290e740Sclaudio snprintf(maxbuf, sizeof(maxbuf), " maxlen %u", roa->maxlen);
2106290e740Sclaudio snprintf(buf, sizeof(buf), "%s/%u%s source-as %u%s", log_addr(&addr),
2116290e740Sclaudio roa->prefixlen, maxbuf, roa->asnum, log_expires(roa->expires));
2126290e740Sclaudio return buf;
2136290e740Sclaudio }
2146290e740Sclaudio
2156290e740Sclaudio const char *
log_aspa(struct aspa_set * aspa)2166290e740Sclaudio log_aspa(struct aspa_set *aspa)
2176290e740Sclaudio {
2186290e740Sclaudio static char errbuf[256];
2196290e740Sclaudio static char *buf;
2206290e740Sclaudio static size_t len;
2216290e740Sclaudio char asbuf[16];
2226290e740Sclaudio size_t needed;
2236290e740Sclaudio uint32_t i;
2246290e740Sclaudio
2256290e740Sclaudio /* include enough space for header and trailer */
2266290e740Sclaudio if ((uint64_t)aspa->num > (SIZE_MAX / sizeof(asbuf) - 72))
2276290e740Sclaudio goto fail;
2286290e740Sclaudio needed = aspa->num * sizeof(asbuf) + 72;
2296290e740Sclaudio if (needed > len) {
2306290e740Sclaudio char *nbuf;
2316290e740Sclaudio
2326290e740Sclaudio if ((nbuf = realloc(buf, needed)) == NULL)
2336290e740Sclaudio goto fail;
2346290e740Sclaudio len = needed;
2356290e740Sclaudio buf = nbuf;
2366290e740Sclaudio }
2376290e740Sclaudio
2386290e740Sclaudio snprintf(buf, len, "customer-as %s%s provider-as { ",
2396290e740Sclaudio log_as(aspa->as), log_expires(aspa->expires));
2406290e740Sclaudio
2416290e740Sclaudio for (i = 0; i < aspa->num; i++) {
2426290e740Sclaudio snprintf(asbuf, sizeof(asbuf), "%s ", log_as(aspa->tas[i]));
2436290e740Sclaudio if (strlcat(buf, asbuf, len) >= len)
2446290e740Sclaudio goto fail;
2456290e740Sclaudio }
2466290e740Sclaudio if (strlcat(buf, "}", len) >= len)
2476290e740Sclaudio goto fail;
2486290e740Sclaudio return buf;
2496290e740Sclaudio
2506290e740Sclaudio fail:
2516290e740Sclaudio free(buf);
2526290e740Sclaudio buf = NULL;
2536290e740Sclaudio len = 0;
2546290e740Sclaudio snprintf(errbuf, sizeof(errbuf), "customer-as %s%s provider-as { ... }",
2556290e740Sclaudio log_as(aspa->as), log_expires(aspa->expires));
2566290e740Sclaudio return errbuf;
2576290e740Sclaudio }
2586290e740Sclaudio
2590561b344Sphessler const char *
log_aspath_error(int error)26004349dffSclaudio log_aspath_error(int error)
26104349dffSclaudio {
26204349dffSclaudio static char buf[20];
26304349dffSclaudio
26404349dffSclaudio switch (error) {
26504349dffSclaudio case AS_ERR_LEN:
26604349dffSclaudio return "inconsitent lenght";
26704349dffSclaudio case AS_ERR_TYPE:
26804349dffSclaudio return "unknown segment type";
26904349dffSclaudio case AS_ERR_BAD:
27004349dffSclaudio return "invalid encoding";
27104349dffSclaudio case AS_ERR_SOFT:
27204349dffSclaudio return "soft failure";
27304349dffSclaudio default:
27404349dffSclaudio snprintf(buf, sizeof(buf), "unknown %d", error);
27504349dffSclaudio return buf;
27604349dffSclaudio }
27704349dffSclaudio }
27804349dffSclaudio
27904349dffSclaudio const char *
log_rtr_error(enum rtr_error err)280bd9df44eSclaudio log_rtr_error(enum rtr_error err)
281bd9df44eSclaudio {
282bd9df44eSclaudio static char buf[20];
283bd9df44eSclaudio
284bd9df44eSclaudio switch (err) {
285bd9df44eSclaudio case NO_ERROR:
286bd9df44eSclaudio return "No Error";
287bd9df44eSclaudio case CORRUPT_DATA:
288bd9df44eSclaudio return "Corrupt Data";
289bd9df44eSclaudio case INTERNAL_ERROR:
290bd9df44eSclaudio return "Internal Error";
291bd9df44eSclaudio case NO_DATA_AVAILABLE:
292bd9df44eSclaudio return "No Data Available";
293bd9df44eSclaudio case INVALID_REQUEST:
294bd9df44eSclaudio return "Invalid Request";
295bd9df44eSclaudio case UNSUPP_PROTOCOL_VERS:
296bd9df44eSclaudio return "Unsupported Protocol Version";
297bd9df44eSclaudio case UNSUPP_PDU_TYPE:
298bd9df44eSclaudio return "Unsupported PDU Type";
299bd9df44eSclaudio case UNK_REC_WDRAWL:
300f4123069Smbuhl return "Withdrawal of Unknown Record";
301bd9df44eSclaudio case DUP_REC_RECV:
302bd9df44eSclaudio return "Duplicate Announcement Received";
303bd9df44eSclaudio case UNEXP_PROTOCOL_VERS:
304bd9df44eSclaudio return "Unexpected Protocol Version";
305bd9df44eSclaudio default:
306bd9df44eSclaudio snprintf(buf, sizeof(buf), "unknown %u", err);
307bd9df44eSclaudio return buf;
308bd9df44eSclaudio }
309bd9df44eSclaudio }
310bd9df44eSclaudio
311bd9df44eSclaudio const char *
log_policy(enum role role)312c0c94bccSclaudio log_policy(enum role role)
313202e5273Stb {
314202e5273Stb switch (role) {
315c0c94bccSclaudio case ROLE_PROVIDER:
316202e5273Stb return "provider";
317c0c94bccSclaudio case ROLE_RS:
318202e5273Stb return "rs";
319c0c94bccSclaudio case ROLE_RS_CLIENT:
320202e5273Stb return "rs-client";
321c0c94bccSclaudio case ROLE_CUSTOMER:
322202e5273Stb return "customer";
323c0c94bccSclaudio case ROLE_PEER:
324202e5273Stb return "peer";
325202e5273Stb default:
326202e5273Stb return "unknown";
327202e5273Stb }
328202e5273Stb }
329202e5273Stb
330beb044e9Sclaudio const char *
log_capability(uint8_t capa)331beb044e9Sclaudio log_capability(uint8_t capa)
332beb044e9Sclaudio {
333beb044e9Sclaudio static char buf[20];
334beb044e9Sclaudio
335beb044e9Sclaudio switch (capa) {
336beb044e9Sclaudio case CAPA_MP:
337beb044e9Sclaudio return "Multiprotocol Extensions";
338beb044e9Sclaudio case CAPA_REFRESH:
339beb044e9Sclaudio return "Route Refresh";
340beb044e9Sclaudio case CAPA_ROLE:
341beb044e9Sclaudio return "BGP Role";
342beb044e9Sclaudio case CAPA_RESTART:
343beb044e9Sclaudio return "Graceful Restart";
344beb044e9Sclaudio case CAPA_AS4BYTE:
345beb044e9Sclaudio return "4-octet AS number";
346beb044e9Sclaudio case CAPA_ADD_PATH:
347beb044e9Sclaudio return "ADD-PATH";
348beb044e9Sclaudio case CAPA_ENHANCED_RR:
349beb044e9Sclaudio return "Enhanced Route Refresh";
350beb044e9Sclaudio default:
351beb044e9Sclaudio snprintf(buf, sizeof(buf), "unknown %u", capa);
352beb044e9Sclaudio return buf;
353beb044e9Sclaudio }
354beb044e9Sclaudio }
355beb044e9Sclaudio
35604349dffSclaudio static const char *
aspath_delim(uint8_t seg_type,int closing)35739386878Sclaudio aspath_delim(uint8_t seg_type, int closing)
3581e590dcfSclaudio {
3591e590dcfSclaudio static char db[8];
3601e590dcfSclaudio
3611e590dcfSclaudio switch (seg_type) {
3621e590dcfSclaudio case AS_SET:
3631e590dcfSclaudio if (!closing)
3641e590dcfSclaudio return ("{ ");
3651e590dcfSclaudio else
3661e590dcfSclaudio return (" }");
3671e590dcfSclaudio case AS_SEQUENCE:
3681e590dcfSclaudio return ("");
3691e590dcfSclaudio case AS_CONFED_SEQUENCE:
3701e590dcfSclaudio if (!closing)
3711e590dcfSclaudio return ("( ");
3721e590dcfSclaudio else
3731e590dcfSclaudio return (" )");
3741e590dcfSclaudio case AS_CONFED_SET:
3751e590dcfSclaudio if (!closing)
3761e590dcfSclaudio return ("[ ");
3771e590dcfSclaudio else
3781e590dcfSclaudio return (" ]");
3791e590dcfSclaudio default:
3801e590dcfSclaudio if (!closing)
3811e590dcfSclaudio snprintf(db, sizeof(db), "!%u ", seg_type);
3821e590dcfSclaudio else
3831e590dcfSclaudio snprintf(db, sizeof(db), " !%u", seg_type);
3841e590dcfSclaudio return (db);
3851e590dcfSclaudio }
3861e590dcfSclaudio }
3871e590dcfSclaudio
38804349dffSclaudio static int
aspath_snprint(char * buf,size_t size,struct ibuf * in)38904349dffSclaudio aspath_snprint(char *buf, size_t size, struct ibuf *in)
3902ffcd4e0Sclaudio {
3912ffcd4e0Sclaudio #define UPDATE() \
3922ffcd4e0Sclaudio do { \
39304349dffSclaudio if (r < 0 || (unsigned int)r >= size) \
3942ffcd4e0Sclaudio return (-1); \
3952ffcd4e0Sclaudio size -= r; \
3962ffcd4e0Sclaudio buf += r; \
3972ffcd4e0Sclaudio } while (0)
39804349dffSclaudio
39904349dffSclaudio struct ibuf data;
40004349dffSclaudio uint32_t as;
40104349dffSclaudio int r, n = 0;
40239386878Sclaudio uint8_t i, seg_type, seg_len;
4032ffcd4e0Sclaudio
40404349dffSclaudio ibuf_from_ibuf(&data, in);
40504349dffSclaudio while (ibuf_size(&data) > 0) {
40604349dffSclaudio if (ibuf_get_n8(&data, &seg_type) == -1 ||
40704349dffSclaudio ibuf_get_n8(&data, &seg_len) == -1 ||
40804349dffSclaudio seg_len == 0)
40904349dffSclaudio return (-1);
4102ffcd4e0Sclaudio
41104349dffSclaudio r = snprintf(buf, size, "%s%s", n++ != 0 ? " " : "",
4121e590dcfSclaudio aspath_delim(seg_type, 0));
4132ffcd4e0Sclaudio UPDATE();
4142ffcd4e0Sclaudio
4152ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) {
41604349dffSclaudio if (ibuf_get_n32(&data, &as) == -1)
41704349dffSclaudio return -1;
41804349dffSclaudio
41904349dffSclaudio r = snprintf(buf, size, "%s", log_as(as));
4202ffcd4e0Sclaudio UPDATE();
4212ffcd4e0Sclaudio if (i + 1 < seg_len) {
4222ffcd4e0Sclaudio r = snprintf(buf, size, " ");
4232ffcd4e0Sclaudio UPDATE();
4242ffcd4e0Sclaudio }
4252ffcd4e0Sclaudio }
4261e590dcfSclaudio r = snprintf(buf, size, "%s", aspath_delim(seg_type, 1));
4272ffcd4e0Sclaudio UPDATE();
4282ffcd4e0Sclaudio }
42955e49665Sclaudio /* ensure that we have a valid C-string especially for empty as path */
4302ffcd4e0Sclaudio *buf = '\0';
43104349dffSclaudio return (0);
4322ffcd4e0Sclaudio #undef UPDATE
4332ffcd4e0Sclaudio }
4342ffcd4e0Sclaudio
43504349dffSclaudio static ssize_t
aspath_strsize(struct ibuf * in)43604349dffSclaudio aspath_strsize(struct ibuf *in)
4372ffcd4e0Sclaudio {
43804349dffSclaudio struct ibuf buf;
43904349dffSclaudio ssize_t total_size = 0;
44039386878Sclaudio uint32_t as;
44139386878Sclaudio uint8_t i, seg_type, seg_len;
4422ffcd4e0Sclaudio
44304349dffSclaudio ibuf_from_ibuf(&buf, in);
44404349dffSclaudio while (ibuf_size(&buf) > 0) {
44504349dffSclaudio if (ibuf_get_n8(&buf, &seg_type) == -1 ||
44604349dffSclaudio ibuf_get_n8(&buf, &seg_len) == -1 ||
44704349dffSclaudio seg_len == 0)
44804349dffSclaudio return (-1);
4492ffcd4e0Sclaudio
4502ffcd4e0Sclaudio if (total_size != 0)
4512ffcd4e0Sclaudio total_size += 1;
45204349dffSclaudio total_size += strlen(aspath_delim(seg_type, 0));
4532ffcd4e0Sclaudio
4542ffcd4e0Sclaudio for (i = 0; i < seg_len; i++) {
45504349dffSclaudio if (ibuf_get_n32(&buf, &as) == -1)
45604349dffSclaudio return (-1);
4570c88bf70Sclaudio
4588db4f5d2Sclaudio do {
4598db4f5d2Sclaudio total_size++;
4608db4f5d2Sclaudio } while ((as = as / 10) != 0);
46104349dffSclaudio }
46204349dffSclaudio total_size += seg_len - 1;
4632ffcd4e0Sclaudio
46404349dffSclaudio total_size += strlen(aspath_delim(seg_type, 1));
46504349dffSclaudio }
46604349dffSclaudio return (total_size + 1);
4672ffcd4e0Sclaudio }
4682ffcd4e0Sclaudio
46904349dffSclaudio int
aspath_asprint(char ** ret,struct ibuf * data)47004349dffSclaudio aspath_asprint(char **ret, struct ibuf *data)
47104349dffSclaudio {
47204349dffSclaudio ssize_t slen;
47304349dffSclaudio
47404349dffSclaudio if ((slen = aspath_strsize(data)) == -1) {
47504349dffSclaudio *ret = NULL;
47604349dffSclaudio errno = EINVAL;
47704349dffSclaudio return (-1);
4782ffcd4e0Sclaudio }
47904349dffSclaudio
48004349dffSclaudio *ret = malloc(slen);
48104349dffSclaudio if (*ret == NULL)
48204349dffSclaudio return (-1);
48304349dffSclaudio
48404349dffSclaudio if (aspath_snprint(*ret, slen, data) == -1) {
48504349dffSclaudio free(*ret);
48604349dffSclaudio *ret = NULL;
48704349dffSclaudio errno = EINVAL;
48804349dffSclaudio return (-1);
48904349dffSclaudio }
49004349dffSclaudio
49104349dffSclaudio return (0);
4922ffcd4e0Sclaudio }
4932ffcd4e0Sclaudio
4942ffcd4e0Sclaudio /*
4952ffcd4e0Sclaudio * Extract the asnum out of the as segment at the specified position.
4962ffcd4e0Sclaudio * Direct access is not possible because of non-aligned reads.
497506f72cfSclaudio * Only works on verified 4-byte AS paths.
4982ffcd4e0Sclaudio */
49939386878Sclaudio uint32_t
aspath_extract(const void * seg,int pos)5002ffcd4e0Sclaudio aspath_extract(const void *seg, int pos)
5012ffcd4e0Sclaudio {
5022ffcd4e0Sclaudio const u_char *ptr = seg;
50339386878Sclaudio uint32_t as;
5042ffcd4e0Sclaudio
505506f72cfSclaudio /* minimal pos check, return 0 since that is an invalid ASN */
506506f72cfSclaudio if (pos < 0 || pos >= ptr[1])
507506f72cfSclaudio return (0);
50839386878Sclaudio ptr += 2 + sizeof(uint32_t) * pos;
50939386878Sclaudio memcpy(&as, ptr, sizeof(uint32_t));
5100c88bf70Sclaudio return (ntohl(as));
5112ffcd4e0Sclaudio }
51221a825c9Sclaudio
513de5c2eedSclaudio /*
51429328a94Sclaudio * Verify that the aspath is correctly encoded.
51529328a94Sclaudio */
51629328a94Sclaudio int
aspath_verify(struct ibuf * in,int as4byte,int noset)51704349dffSclaudio aspath_verify(struct ibuf *in, int as4byte, int noset)
51829328a94Sclaudio {
51904349dffSclaudio struct ibuf buf;
52004349dffSclaudio int pos, error = 0;
52139386878Sclaudio uint8_t seg_len, seg_type;
52229328a94Sclaudio
52304349dffSclaudio ibuf_from_ibuf(&buf, in);
52404349dffSclaudio if (ibuf_size(&buf) & 1) {
52529328a94Sclaudio /* odd length aspath are invalid */
52604349dffSclaudio error = AS_ERR_BAD;
52704349dffSclaudio goto done;
52804349dffSclaudio }
52929328a94Sclaudio
53004349dffSclaudio while (ibuf_size(&buf) > 0) {
53104349dffSclaudio if (ibuf_get_n8(&buf, &seg_type) == -1 ||
53204349dffSclaudio ibuf_get_n8(&buf, &seg_len) == -1) {
53304349dffSclaudio error = AS_ERR_LEN;
53404349dffSclaudio goto done;
53504349dffSclaudio }
53629328a94Sclaudio
53704349dffSclaudio if (seg_len == 0) {
538d04df938Sclaudio /* empty aspath segments are not allowed */
53904349dffSclaudio error = AS_ERR_BAD;
54004349dffSclaudio goto done;
54104349dffSclaudio }
542d04df938Sclaudio
54329328a94Sclaudio /*
54429328a94Sclaudio * BGP confederations should not show up but consider them
54529328a94Sclaudio * as a soft error which invalidates the path but keeps the
54629328a94Sclaudio * bgp session running.
54729328a94Sclaudio */
54829328a94Sclaudio if (seg_type == AS_CONFED_SEQUENCE || seg_type == AS_CONFED_SET)
54929328a94Sclaudio error = AS_ERR_SOFT;
550aa528464Sclaudio /*
551aa528464Sclaudio * If AS_SET filtering (RFC6472) is on, error out on AS_SET
552aa528464Sclaudio * as well.
553aa528464Sclaudio */
554aa528464Sclaudio if (noset && seg_type == AS_SET)
555aa528464Sclaudio error = AS_ERR_SOFT;
55629328a94Sclaudio if (seg_type != AS_SET && seg_type != AS_SEQUENCE &&
55704349dffSclaudio seg_type != AS_CONFED_SEQUENCE &&
55804349dffSclaudio seg_type != AS_CONFED_SET) {
55904349dffSclaudio error = AS_ERR_TYPE;
56004349dffSclaudio goto done;
56104349dffSclaudio }
56229328a94Sclaudio
56329328a94Sclaudio /* RFC 7607 - AS 0 is considered malformed */
56429328a94Sclaudio for (pos = 0; pos < seg_len; pos++) {
56539386878Sclaudio uint32_t as;
56629328a94Sclaudio
56704349dffSclaudio if (as4byte) {
56804349dffSclaudio if (ibuf_get_n32(&buf, &as) == -1) {
56904349dffSclaudio error = AS_ERR_LEN;
57004349dffSclaudio goto done;
57104349dffSclaudio }
57204349dffSclaudio } else {
57304349dffSclaudio uint16_t tmp;
57404349dffSclaudio if (ibuf_get_n16(&buf, &tmp) == -1) {
57504349dffSclaudio error = AS_ERR_LEN;
57604349dffSclaudio goto done;
57704349dffSclaudio }
57804349dffSclaudio as = tmp;
57904349dffSclaudio }
58029328a94Sclaudio if (as == 0)
58156a9a1b8Sclaudio error = AS_ERR_SOFT;
58229328a94Sclaudio }
58329328a94Sclaudio }
58404349dffSclaudio
58504349dffSclaudio done:
58629328a94Sclaudio return (error); /* aspath is valid but probably not loop free */
58729328a94Sclaudio }
58829328a94Sclaudio
58929328a94Sclaudio /*
59029328a94Sclaudio * convert a 2 byte aspath to a 4 byte one.
59129328a94Sclaudio */
59204349dffSclaudio struct ibuf *
aspath_inflate(struct ibuf * in)59304349dffSclaudio aspath_inflate(struct ibuf *in)
59429328a94Sclaudio {
59504349dffSclaudio struct ibuf *out;
59604349dffSclaudio uint16_t short_as;
59704349dffSclaudio uint8_t seg_type, seg_len;
59829328a94Sclaudio
5994ac10ff8Sclaudio /*
6004ac10ff8Sclaudio * Allocate enough space for the worst case.
6014ac10ff8Sclaudio * XXX add 1 byte for the empty ASPATH case since we can't
6024ac10ff8Sclaudio * allocate an ibuf of 0 length.
6034ac10ff8Sclaudio */
6044ac10ff8Sclaudio if ((out = ibuf_open(ibuf_size(in) * 2 + 1)) == NULL)
60529328a94Sclaudio return (NULL);
60629328a94Sclaudio
60729328a94Sclaudio /* then copy the aspath */
60804349dffSclaudio while (ibuf_size(in) > 0) {
60904349dffSclaudio if (ibuf_get_n8(in, &seg_type) == -1 ||
61004349dffSclaudio ibuf_get_n8(in, &seg_len) == -1 ||
61104349dffSclaudio seg_len == 0)
61204349dffSclaudio goto fail;
61304349dffSclaudio if (ibuf_add_n8(out, seg_type) == -1 ||
61404349dffSclaudio ibuf_add_n8(out, seg_len) == -1)
61504349dffSclaudio goto fail;
61604349dffSclaudio
61729328a94Sclaudio for (; seg_len > 0; seg_len--) {
61804349dffSclaudio if (ibuf_get_n16(in, &short_as) == -1)
61904349dffSclaudio goto fail;
62004349dffSclaudio if (ibuf_add_n32(out, short_as) == -1)
62104349dffSclaudio goto fail;
62229328a94Sclaudio }
62329328a94Sclaudio }
62429328a94Sclaudio
62504349dffSclaudio return (out);
62604349dffSclaudio
62704349dffSclaudio fail:
62804349dffSclaudio ibuf_free(out);
62904349dffSclaudio return (NULL);
63029328a94Sclaudio }
63129328a94Sclaudio
6325c4d2233Sclaudio static const u_char addrmask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0,
6335c4d2233Sclaudio 0xf8, 0xfc, 0xfe, 0xff };
6345c4d2233Sclaudio
6356d3e8673Sclaudio /* NLRI functions to extract prefixes from the NLRI blobs */
6360f144400Sclaudio int
extract_prefix(const u_char * p,int len,void * va,uint8_t pfxlen,uint8_t max)6370f144400Sclaudio extract_prefix(const u_char *p, int len, void *va, uint8_t pfxlen, uint8_t max)
6386d3e8673Sclaudio {
6396d3e8673Sclaudio u_char *a = va;
6403f0f322fSclaudio int plen;
6416d3e8673Sclaudio
6423f0f322fSclaudio plen = PREFIX_SIZE(pfxlen) - 1;
6433f0f322fSclaudio if (len < plen || max < plen)
6443f0f322fSclaudio return -1;
6453f0f322fSclaudio
6463f0f322fSclaudio while (pfxlen > 0) {
6476d3e8673Sclaudio if (pfxlen < 8) {
6483f0f322fSclaudio *a++ = *p++ & addrmask[pfxlen];
6496d3e8673Sclaudio break;
6506d3e8673Sclaudio } else {
6513f0f322fSclaudio *a++ = *p++;
6526d3e8673Sclaudio pfxlen -= 8;
6536d3e8673Sclaudio }
6546d3e8673Sclaudio }
6556d3e8673Sclaudio return (plen);
6566d3e8673Sclaudio }
6576d3e8673Sclaudio
6585c4d2233Sclaudio static int
extract_prefix_buf(struct ibuf * buf,void * va,uint8_t pfxlen,uint8_t max)6595c4d2233Sclaudio extract_prefix_buf(struct ibuf *buf, void *va, uint8_t pfxlen, uint8_t max)
6606d3e8673Sclaudio {
6615c4d2233Sclaudio u_char *a = va;
6625c4d2233Sclaudio unsigned int plen;
6635c4d2233Sclaudio uint8_t tmp;
6645c4d2233Sclaudio
6655c4d2233Sclaudio plen = PREFIX_SIZE(pfxlen) - 1;
6665c4d2233Sclaudio if (ibuf_size(buf) < plen || max < plen)
6675c4d2233Sclaudio return -1;
6685c4d2233Sclaudio
6695c4d2233Sclaudio while (pfxlen > 0) {
6705c4d2233Sclaudio if (ibuf_get_n8(buf, &tmp) == -1)
6715c4d2233Sclaudio return -1;
6725c4d2233Sclaudio
6735c4d2233Sclaudio if (pfxlen < 8) {
6745c4d2233Sclaudio *a++ = tmp & addrmask[pfxlen];
6755c4d2233Sclaudio break;
6765c4d2233Sclaudio } else {
6775c4d2233Sclaudio *a++ = tmp;
6785c4d2233Sclaudio pfxlen -= 8;
6795c4d2233Sclaudio }
6805c4d2233Sclaudio }
6815c4d2233Sclaudio return (0);
6825c4d2233Sclaudio }
6835c4d2233Sclaudio
6845c4d2233Sclaudio int
nlri_get_prefix(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen)6855c4d2233Sclaudio nlri_get_prefix(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen)
6865c4d2233Sclaudio {
68739386878Sclaudio uint8_t pfxlen;
6886d3e8673Sclaudio
6895c4d2233Sclaudio if (ibuf_get_n8(buf, &pfxlen) == -1)
6906d3e8673Sclaudio return (-1);
6915c4d2233Sclaudio if (pfxlen > 32)
6925c4d2233Sclaudio return (-1);
6936d3e8673Sclaudio
694eafe309eSclaudio memset(prefix, 0, sizeof(struct bgpd_addr));
6956d3e8673Sclaudio prefix->aid = AID_INET;
6965c4d2233Sclaudio
6975c4d2233Sclaudio if (extract_prefix_buf(buf, &prefix->v4, pfxlen,
6985c4d2233Sclaudio sizeof(prefix->v4)) == -1)
6995c4d2233Sclaudio return (-1);
7005c4d2233Sclaudio
7016d3e8673Sclaudio *prefixlen = pfxlen;
7025c4d2233Sclaudio return (0);
7036d3e8673Sclaudio }
7046d3e8673Sclaudio
7056d3e8673Sclaudio int
nlri_get_prefix6(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen)7065c4d2233Sclaudio nlri_get_prefix6(struct ibuf *buf, struct bgpd_addr *prefix, uint8_t *prefixlen)
7076d3e8673Sclaudio {
70839386878Sclaudio uint8_t pfxlen;
7096d3e8673Sclaudio
7105c4d2233Sclaudio if (ibuf_get_n8(buf, &pfxlen) == -1)
7116d3e8673Sclaudio return (-1);
7125c4d2233Sclaudio if (pfxlen > 128)
7135c4d2233Sclaudio return (-1);
7146d3e8673Sclaudio
715eafe309eSclaudio memset(prefix, 0, sizeof(struct bgpd_addr));
7166d3e8673Sclaudio prefix->aid = AID_INET6;
7175c4d2233Sclaudio
7185c4d2233Sclaudio if (extract_prefix_buf(buf, &prefix->v6, pfxlen,
7195c4d2233Sclaudio sizeof(prefix->v6)) == -1)
7205c4d2233Sclaudio return (-1);
7215c4d2233Sclaudio
7226d3e8673Sclaudio *prefixlen = pfxlen;
7235c4d2233Sclaudio return (0);
7246d3e8673Sclaudio }
7256d3e8673Sclaudio
7266d3e8673Sclaudio int
nlri_get_vpn4(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen,int withdraw)7275c4d2233Sclaudio nlri_get_vpn4(struct ibuf *buf, struct bgpd_addr *prefix,
72839386878Sclaudio uint8_t *prefixlen, int withdraw)
7296d3e8673Sclaudio {
7305c4d2233Sclaudio int done = 0;
73139386878Sclaudio uint8_t pfxlen;
7326d3e8673Sclaudio
7335c4d2233Sclaudio if (ibuf_get_n8(buf, &pfxlen) == -1)
7346d3e8673Sclaudio return (-1);
7356d3e8673Sclaudio
736eafe309eSclaudio memset(prefix, 0, sizeof(struct bgpd_addr));
7375c4d2233Sclaudio prefix->aid = AID_VPN_IPv4;
7386d3e8673Sclaudio
7396d3e8673Sclaudio /* label stack */
7406d3e8673Sclaudio do {
7415c4d2233Sclaudio if (prefix->labellen + 3U > sizeof(prefix->labelstack) ||
7425c4d2233Sclaudio pfxlen < 3 * 8)
7436d3e8673Sclaudio return (-1);
7446d3e8673Sclaudio if (withdraw) {
7456d3e8673Sclaudio /* on withdraw ignore the labelstack all together */
7465c4d2233Sclaudio if (ibuf_skip(buf, 3) == -1)
7475c4d2233Sclaudio return (-1);
7486d3e8673Sclaudio pfxlen -= 3 * 8;
7496d3e8673Sclaudio break;
7506d3e8673Sclaudio }
7515c4d2233Sclaudio if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) ==
7525c4d2233Sclaudio -1)
7535c4d2233Sclaudio return -1;
7545c4d2233Sclaudio if (prefix->labelstack[prefix->labellen + 2] &
7556d3e8673Sclaudio BGP_MPLS_BOS)
7566d3e8673Sclaudio done = 1;
7575c4d2233Sclaudio prefix->labellen += 3;
7586d3e8673Sclaudio pfxlen -= 3 * 8;
7596d3e8673Sclaudio } while (!done);
7606d3e8673Sclaudio
7616d3e8673Sclaudio /* RD */
7625c4d2233Sclaudio if (pfxlen < sizeof(uint64_t) * 8 ||
7635c4d2233Sclaudio ibuf_get_h64(buf, &prefix->rd) == -1)
7646d3e8673Sclaudio return (-1);
76539386878Sclaudio pfxlen -= sizeof(uint64_t) * 8;
7666d3e8673Sclaudio
7676d3e8673Sclaudio /* prefix */
7686d3e8673Sclaudio if (pfxlen > 32)
7696d3e8673Sclaudio return (-1);
7705c4d2233Sclaudio if (extract_prefix_buf(buf, &prefix->v4, pfxlen,
7715c4d2233Sclaudio sizeof(prefix->v4)) == -1)
7726d3e8673Sclaudio return (-1);
7736d3e8673Sclaudio
7745c4d2233Sclaudio *prefixlen = pfxlen;
7755c4d2233Sclaudio return (0);
7766d3e8673Sclaudio }
7776d3e8673Sclaudio
778290f96faSdenis int
nlri_get_vpn6(struct ibuf * buf,struct bgpd_addr * prefix,uint8_t * prefixlen,int withdraw)7795c4d2233Sclaudio nlri_get_vpn6(struct ibuf *buf, struct bgpd_addr *prefix,
78039386878Sclaudio uint8_t *prefixlen, int withdraw)
781290f96faSdenis {
7825c4d2233Sclaudio int done = 0;
78339386878Sclaudio uint8_t pfxlen;
784290f96faSdenis
7855c4d2233Sclaudio if (ibuf_get_n8(buf, &pfxlen) == -1)
786290f96faSdenis return (-1);
787290f96faSdenis
788290f96faSdenis memset(prefix, 0, sizeof(struct bgpd_addr));
7895c4d2233Sclaudio prefix->aid = AID_VPN_IPv6;
790290f96faSdenis
791290f96faSdenis /* label stack */
792290f96faSdenis do {
7935c4d2233Sclaudio if (prefix->labellen + 3U > sizeof(prefix->labelstack) ||
7945c4d2233Sclaudio pfxlen < 3 * 8)
795290f96faSdenis return (-1);
796290f96faSdenis if (withdraw) {
797290f96faSdenis /* on withdraw ignore the labelstack all together */
7985c4d2233Sclaudio if (ibuf_skip(buf, 3) == -1)
7995c4d2233Sclaudio return (-1);
800290f96faSdenis pfxlen -= 3 * 8;
801290f96faSdenis break;
802290f96faSdenis }
803290f96faSdenis
8045c4d2233Sclaudio if (ibuf_get(buf, &prefix->labelstack[prefix->labellen], 3) ==
8055c4d2233Sclaudio -1)
8065c4d2233Sclaudio return (-1);
8075c4d2233Sclaudio if (prefix->labelstack[prefix->labellen + 2] &
808290f96faSdenis BGP_MPLS_BOS)
809290f96faSdenis done = 1;
8105c4d2233Sclaudio prefix->labellen += 3;
811290f96faSdenis pfxlen -= 3 * 8;
812290f96faSdenis } while (!done);
813290f96faSdenis
814290f96faSdenis /* RD */
8155c4d2233Sclaudio if (pfxlen < sizeof(uint64_t) * 8 ||
8165c4d2233Sclaudio ibuf_get_h64(buf, &prefix->rd) == -1)
817290f96faSdenis return (-1);
81839386878Sclaudio pfxlen -= sizeof(uint64_t) * 8;
819290f96faSdenis
820290f96faSdenis /* prefix */
821290f96faSdenis if (pfxlen > 128)
822290f96faSdenis return (-1);
8235c4d2233Sclaudio if (extract_prefix_buf(buf, &prefix->v6, pfxlen,
8245c4d2233Sclaudio sizeof(prefix->v6)) == -1)
825290f96faSdenis return (-1);
826290f96faSdenis
8275c4d2233Sclaudio *prefixlen = pfxlen;
8285c4d2233Sclaudio return (0);
829290f96faSdenis }
830290f96faSdenis
831fa3a38bbSclaudio static in_addr_t
prefixlen2mask(uint8_t prefixlen)832fa3a38bbSclaudio prefixlen2mask(uint8_t prefixlen)
833fa3a38bbSclaudio {
834fa3a38bbSclaudio if (prefixlen == 0)
835fa3a38bbSclaudio return (0);
836290f96faSdenis
837fa3a38bbSclaudio return (0xffffffff << (32 - prefixlen));
838fa3a38bbSclaudio }
839290f96faSdenis
84029328a94Sclaudio /*
841de5c2eedSclaudio * This function will have undefined behaviour if the passed in prefixlen is
842290f96faSdenis * too large for the respective bgpd_addr address family.
843de5c2eedSclaudio */
844fafbb788Sclaudio int
prefix_compare(const struct bgpd_addr * a,const struct bgpd_addr * b,int prefixlen)845fafbb788Sclaudio prefix_compare(const struct bgpd_addr *a, const struct bgpd_addr *b,
846fafbb788Sclaudio int prefixlen)
847fafbb788Sclaudio {
848fafbb788Sclaudio in_addr_t mask, aa, ba;
849fafbb788Sclaudio int i;
85039386878Sclaudio uint8_t m;
851fafbb788Sclaudio
852fafbb788Sclaudio if (a->aid != b->aid)
853fafbb788Sclaudio return (a->aid - b->aid);
854fafbb788Sclaudio
855fafbb788Sclaudio switch (a->aid) {
8563038d3d1Sclaudio case AID_VPN_IPv4:
8573038d3d1Sclaudio if (be64toh(a->rd) > be64toh(b->rd))
8583038d3d1Sclaudio return (1);
8593038d3d1Sclaudio if (be64toh(a->rd) < be64toh(b->rd))
8603038d3d1Sclaudio return (-1);
8613038d3d1Sclaudio /* FALLTHROUGH */
862fafbb788Sclaudio case AID_INET:
8637da59fecSclaudio if (prefixlen == 0)
8647da59fecSclaudio return (0);
865fafbb788Sclaudio if (prefixlen > 32)
866de5c2eedSclaudio return (-1);
867fafbb788Sclaudio mask = htonl(prefixlen2mask(prefixlen));
868fafbb788Sclaudio aa = ntohl(a->v4.s_addr & mask);
869fafbb788Sclaudio ba = ntohl(b->v4.s_addr & mask);
8703038d3d1Sclaudio if (aa > ba)
8713038d3d1Sclaudio return (1);
8723038d3d1Sclaudio if (aa < ba)
8733038d3d1Sclaudio return (-1);
8743038d3d1Sclaudio break;
8753038d3d1Sclaudio case AID_VPN_IPv6:
8763038d3d1Sclaudio if (be64toh(a->rd) > be64toh(b->rd))
8773038d3d1Sclaudio return (1);
8783038d3d1Sclaudio if (be64toh(a->rd) < be64toh(b->rd))
8793038d3d1Sclaudio return (-1);
8803038d3d1Sclaudio /* FALLTHROUGH */
881fafbb788Sclaudio case AID_INET6:
8827da59fecSclaudio if (prefixlen == 0)
8837da59fecSclaudio return (0);
884fafbb788Sclaudio if (prefixlen > 128)
885de5c2eedSclaudio return (-1);
886fafbb788Sclaudio for (i = 0; i < prefixlen / 8; i++)
887fafbb788Sclaudio if (a->v6.s6_addr[i] != b->v6.s6_addr[i])
888fafbb788Sclaudio return (a->v6.s6_addr[i] - b->v6.s6_addr[i]);
889fafbb788Sclaudio i = prefixlen % 8;
890fafbb788Sclaudio if (i) {
891fafbb788Sclaudio m = 0xff00 >> i;
892fafbb788Sclaudio if ((a->v6.s6_addr[prefixlen / 8] & m) !=
893fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m))
894fafbb788Sclaudio return ((a->v6.s6_addr[prefixlen / 8] & m) -
895fafbb788Sclaudio (b->v6.s6_addr[prefixlen / 8] & m));
896fafbb788Sclaudio }
8973038d3d1Sclaudio break;
8983038d3d1Sclaudio default:
8993038d3d1Sclaudio return (-1);
9003038d3d1Sclaudio }
9013038d3d1Sclaudio
9023038d3d1Sclaudio if (a->aid == AID_VPN_IPv4 || a->aid == AID_VPN_IPv6) {
9033038d3d1Sclaudio if (a->labellen > b->labellen)
9043038d3d1Sclaudio return (1);
9053038d3d1Sclaudio if (a->labellen < b->labellen)
9063038d3d1Sclaudio return (-1);
9073038d3d1Sclaudio return (memcmp(a->labelstack, b->labelstack, a->labellen));
9083038d3d1Sclaudio }
909fafbb788Sclaudio return (0);
9103038d3d1Sclaudio
911fafbb788Sclaudio }
912fafbb788Sclaudio
91321a825c9Sclaudio void
inet4applymask(struct in_addr * dest,const struct in_addr * src,int prefixlen)9142b5c88feSclaudio inet4applymask(struct in_addr *dest, const struct in_addr *src, int prefixlen)
9152b5c88feSclaudio {
9162b5c88feSclaudio struct in_addr mask;
9172b5c88feSclaudio
9182b5c88feSclaudio mask.s_addr = htonl(prefixlen2mask(prefixlen));
9192b5c88feSclaudio dest->s_addr = src->s_addr & mask.s_addr;
9202b5c88feSclaudio }
9212b5c88feSclaudio
9222b5c88feSclaudio void
inet6applymask(struct in6_addr * dest,const struct in6_addr * src,int prefixlen)92321a825c9Sclaudio inet6applymask(struct in6_addr *dest, const struct in6_addr *src, int prefixlen)
92421a825c9Sclaudio {
92521a825c9Sclaudio struct in6_addr mask;
92621a825c9Sclaudio int i;
92721a825c9Sclaudio
928eafe309eSclaudio memset(&mask, 0, sizeof(mask));
92921a825c9Sclaudio for (i = 0; i < prefixlen / 8; i++)
93021a825c9Sclaudio mask.s6_addr[i] = 0xff;
93121a825c9Sclaudio i = prefixlen % 8;
93221a825c9Sclaudio if (i)
93321a825c9Sclaudio mask.s6_addr[prefixlen / 8] = 0xff00 >> i;
93421a825c9Sclaudio
93521a825c9Sclaudio for (i = 0; i < 16; i++)
93621a825c9Sclaudio dest->s6_addr[i] = src->s6_addr[i] & mask.s6_addr[i];
93721a825c9Sclaudio }
938d6c2e4e8Sclaudio
93913bcf54fSclaudio void
applymask(struct bgpd_addr * dest,const struct bgpd_addr * src,int prefixlen)94013bcf54fSclaudio applymask(struct bgpd_addr *dest, const struct bgpd_addr *src, int prefixlen)
94113bcf54fSclaudio {
94213bcf54fSclaudio *dest = *src;
94313bcf54fSclaudio switch (src->aid) {
94413bcf54fSclaudio case AID_INET:
94513bcf54fSclaudio case AID_VPN_IPv4:
94613bcf54fSclaudio inet4applymask(&dest->v4, &src->v4, prefixlen);
94713bcf54fSclaudio break;
94813bcf54fSclaudio case AID_INET6:
94913bcf54fSclaudio case AID_VPN_IPv6:
95013bcf54fSclaudio inet6applymask(&dest->v6, &src->v6, prefixlen);
95113bcf54fSclaudio break;
95213bcf54fSclaudio }
95313bcf54fSclaudio }
95413bcf54fSclaudio
955d6c2e4e8Sclaudio /* address family translation functions */
956d6c2e4e8Sclaudio const struct aid aid_vals[AID_MAX] = AID_VALS;
957d6c2e4e8Sclaudio
95886729c90Sclaudio const char *
aid2str(uint8_t aid)95939386878Sclaudio aid2str(uint8_t aid)
96086729c90Sclaudio {
96186729c90Sclaudio if (aid < AID_MAX)
96286729c90Sclaudio return (aid_vals[aid].name);
96386729c90Sclaudio return ("unknown AID");
96486729c90Sclaudio }
96586729c90Sclaudio
966d6c2e4e8Sclaudio int
aid2afi(uint8_t aid,uint16_t * afi,uint8_t * safi)96739386878Sclaudio aid2afi(uint8_t aid, uint16_t *afi, uint8_t *safi)
968d6c2e4e8Sclaudio {
969110c1584Sclaudio if (aid != AID_UNSPEC && aid < AID_MAX) {
970d6c2e4e8Sclaudio *afi = aid_vals[aid].afi;
971d6c2e4e8Sclaudio *safi = aid_vals[aid].safi;
972d6c2e4e8Sclaudio return (0);
973d6c2e4e8Sclaudio }
974d6c2e4e8Sclaudio return (-1);
975d6c2e4e8Sclaudio }
976d6c2e4e8Sclaudio
977d6c2e4e8Sclaudio int
afi2aid(uint16_t afi,uint8_t safi,uint8_t * aid)97839386878Sclaudio afi2aid(uint16_t afi, uint8_t safi, uint8_t *aid)
979d6c2e4e8Sclaudio {
98039386878Sclaudio uint8_t i;
981d6c2e4e8Sclaudio
982110c1584Sclaudio for (i = AID_MIN; i < AID_MAX; i++)
983d6c2e4e8Sclaudio if (aid_vals[i].afi == afi && aid_vals[i].safi == safi) {
984d6c2e4e8Sclaudio *aid = i;
985d6c2e4e8Sclaudio return (0);
986d6c2e4e8Sclaudio }
987d6c2e4e8Sclaudio
988d6c2e4e8Sclaudio return (-1);
989d6c2e4e8Sclaudio }
990d6c2e4e8Sclaudio
991d6c2e4e8Sclaudio sa_family_t
aid2af(uint8_t aid)99239386878Sclaudio aid2af(uint8_t aid)
993d6c2e4e8Sclaudio {
994d6c2e4e8Sclaudio if (aid < AID_MAX)
995d6c2e4e8Sclaudio return (aid_vals[aid].af);
996d6c2e4e8Sclaudio return (AF_UNSPEC);
997d6c2e4e8Sclaudio }
998d6c2e4e8Sclaudio
999d6c2e4e8Sclaudio int
af2aid(sa_family_t af,uint8_t safi,uint8_t * aid)100039386878Sclaudio af2aid(sa_family_t af, uint8_t safi, uint8_t *aid)
1001d6c2e4e8Sclaudio {
100239386878Sclaudio uint8_t i;
1003d6c2e4e8Sclaudio
1004d6c2e4e8Sclaudio if (safi == 0) /* default to unicast subclass */
1005d6c2e4e8Sclaudio safi = SAFI_UNICAST;
1006d6c2e4e8Sclaudio
1007110c1584Sclaudio for (i = AID_UNSPEC; i < AID_MAX; i++)
1008d6c2e4e8Sclaudio if (aid_vals[i].af == af && aid_vals[i].safi == safi) {
1009d6c2e4e8Sclaudio *aid = i;
1010d6c2e4e8Sclaudio return (0);
1011d6c2e4e8Sclaudio }
1012d6c2e4e8Sclaudio
1013d6c2e4e8Sclaudio return (-1);
1014d6c2e4e8Sclaudio }
1015d6c2e4e8Sclaudio
101645350f87Sclaudio /*
101745350f87Sclaudio * Convert a struct bgpd_addr into a struct sockaddr. For VPN addresses
101845350f87Sclaudio * the included label stack is ignored and needs to be handled by the caller.
101945350f87Sclaudio */
1020d6c2e4e8Sclaudio struct sockaddr *
addr2sa(const struct bgpd_addr * addr,uint16_t port,socklen_t * len)102139386878Sclaudio addr2sa(const struct bgpd_addr *addr, uint16_t port, socklen_t *len)
1022d6c2e4e8Sclaudio {
1023d6c2e4e8Sclaudio static struct sockaddr_storage ss;
1024d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)&ss;
1025d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)&ss;
1026d6c2e4e8Sclaudio
10274886db4cSclaudio if (addr == NULL || addr->aid == AID_UNSPEC)
10284886db4cSclaudio return (NULL);
102945350f87Sclaudio
1030eafe309eSclaudio memset(&ss, 0, sizeof(ss));
1031d6c2e4e8Sclaudio switch (addr->aid) {
1032d6c2e4e8Sclaudio case AID_INET:
10333038d3d1Sclaudio case AID_VPN_IPv4:
1034d6c2e4e8Sclaudio sa_in->sin_family = AF_INET;
1035d6c2e4e8Sclaudio sa_in->sin_addr.s_addr = addr->v4.s_addr;
1036d6c2e4e8Sclaudio sa_in->sin_port = htons(port);
1037255fe563Sclaudio *len = sizeof(struct sockaddr_in);
1038d6c2e4e8Sclaudio break;
1039d6c2e4e8Sclaudio case AID_INET6:
104045350f87Sclaudio case AID_VPN_IPv6:
104145350f87Sclaudio sa_in6->sin6_family = AF_INET6;
10423038d3d1Sclaudio memcpy(&sa_in6->sin6_addr, &addr->v6,
104345350f87Sclaudio sizeof(sa_in6->sin6_addr));
104445350f87Sclaudio sa_in6->sin6_port = htons(port);
104545350f87Sclaudio sa_in6->sin6_scope_id = addr->scope_id;
104645350f87Sclaudio *len = sizeof(struct sockaddr_in6);
104745350f87Sclaudio break;
104841c1c374Sclaudio case AID_FLOWSPECv4:
104941c1c374Sclaudio case AID_FLOWSPECv6:
105041c1c374Sclaudio return (NULL);
1051d6c2e4e8Sclaudio }
1052d6c2e4e8Sclaudio
1053d6c2e4e8Sclaudio return ((struct sockaddr *)&ss);
1054d6c2e4e8Sclaudio }
1055d6c2e4e8Sclaudio
1056d6c2e4e8Sclaudio void
sa2addr(struct sockaddr * sa,struct bgpd_addr * addr,uint16_t * port)105739386878Sclaudio sa2addr(struct sockaddr *sa, struct bgpd_addr *addr, uint16_t *port)
1058d6c2e4e8Sclaudio {
1059d6c2e4e8Sclaudio struct sockaddr_in *sa_in = (struct sockaddr_in *)sa;
1060d6c2e4e8Sclaudio struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)sa;
1061d6c2e4e8Sclaudio
1062eafe309eSclaudio memset(addr, 0, sizeof(*addr));
1063d6c2e4e8Sclaudio switch (sa->sa_family) {
1064d6c2e4e8Sclaudio case AF_INET:
1065d6c2e4e8Sclaudio addr->aid = AID_INET;
1066d6c2e4e8Sclaudio memcpy(&addr->v4, &sa_in->sin_addr, sizeof(addr->v4));
1067a27d9e33Sclaudio if (port)
1068a27d9e33Sclaudio *port = ntohs(sa_in->sin_port);
1069d6c2e4e8Sclaudio break;
1070d6c2e4e8Sclaudio case AF_INET6:
1071d6c2e4e8Sclaudio addr->aid = AID_INET6;
1072be6ced5eSclaudio #ifdef __KAME__
1073be6ced5eSclaudio /*
1074be6ced5eSclaudio * XXX thanks, KAME, for this ugliness...
1075be6ced5eSclaudio * adopted from route/show.c
1076be6ced5eSclaudio */
10775177244fSclaudio if ((IN6_IS_ADDR_LINKLOCAL(&sa_in6->sin6_addr) ||
10785177244fSclaudio IN6_IS_ADDR_MC_LINKLOCAL(&sa_in6->sin6_addr) ||
10794ff2dba3Sclaudio IN6_IS_ADDR_MC_NODELOCAL(&sa_in6->sin6_addr)) &&
10805177244fSclaudio sa_in6->sin6_scope_id == 0) {
1081be6ced5eSclaudio uint16_t tmp16;
1082be6ced5eSclaudio memcpy(&tmp16, &sa_in6->sin6_addr.s6_addr[2],
1083be6ced5eSclaudio sizeof(tmp16));
1084be6ced5eSclaudio sa_in6->sin6_scope_id = ntohs(tmp16);
1085be6ced5eSclaudio sa_in6->sin6_addr.s6_addr[2] = 0;
1086be6ced5eSclaudio sa_in6->sin6_addr.s6_addr[3] = 0;
1087be6ced5eSclaudio }
1088be6ced5eSclaudio #endif
10895177244fSclaudio memcpy(&addr->v6, &sa_in6->sin6_addr, sizeof(addr->v6));
1090d6c2e4e8Sclaudio addr->scope_id = sa_in6->sin6_scope_id; /* I hate v6 */
1091a27d9e33Sclaudio if (port)
1092a27d9e33Sclaudio *port = ntohs(sa_in6->sin6_port);
1093d6c2e4e8Sclaudio break;
1094d6c2e4e8Sclaudio }
1095d6c2e4e8Sclaudio }
10966e8089a5Sclaudio
10976e8089a5Sclaudio const char *
get_baudrate(unsigned long long baudrate,char * unit)1098bc757ddaSclaudio get_baudrate(unsigned long long baudrate, char *unit)
10996e8089a5Sclaudio {
11006e8089a5Sclaudio static char bbuf[16];
11013eaf1285Sclaudio const unsigned long long kilo = 1000;
11023eaf1285Sclaudio const unsigned long long mega = 1000ULL * kilo;
11033eaf1285Sclaudio const unsigned long long giga = 1000ULL * mega;
11046e8089a5Sclaudio
11053eaf1285Sclaudio if (baudrate > giga)
11066e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu G%s",
11073eaf1285Sclaudio baudrate / giga, unit);
11083eaf1285Sclaudio else if (baudrate > mega)
11096e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu M%s",
11103eaf1285Sclaudio baudrate / mega, unit);
11113eaf1285Sclaudio else if (baudrate > kilo)
11126e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu K%s",
11133eaf1285Sclaudio baudrate / kilo, unit);
11146e8089a5Sclaudio else
11156e8089a5Sclaudio snprintf(bbuf, sizeof(bbuf), "%llu %s",
11166e8089a5Sclaudio baudrate, unit);
11176e8089a5Sclaudio
11186e8089a5Sclaudio return (bbuf);
11196e8089a5Sclaudio }
1120