1*e386eeb1Sclaudio /* $OpenBSD: rde_attr.c,v 1.135 2024/09/10 09:38:45 claudio Exp $ */ 268f72004Sclaudio 368f72004Sclaudio /* 468f72004Sclaudio * Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org> 5280f24a4Sphessler * Copyright (c) 2016 Job Snijders <job@instituut.net> 6280f24a4Sphessler * Copyright (c) 2016 Peter Hessler <phessler@openbsd.org> 768f72004Sclaudio * 868f72004Sclaudio * Permission to use, copy, modify, and distribute this software for any 968f72004Sclaudio * purpose with or without fee is hereby granted, provided that the above 1068f72004Sclaudio * copyright notice and this permission notice appear in all copies. 1168f72004Sclaudio * 1268f72004Sclaudio * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1368f72004Sclaudio * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1468f72004Sclaudio * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1568f72004Sclaudio * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1668f72004Sclaudio * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1768f72004Sclaudio * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1868f72004Sclaudio * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1968f72004Sclaudio */ 2068f72004Sclaudio 2168f72004Sclaudio #include <sys/queue.h> 2268f72004Sclaudio 235bdfc2adSclaudio #include <endian.h> 24b2cd1366Sguenther #include <limits.h> 2568f72004Sclaudio #include <stdlib.h> 2668f72004Sclaudio #include <string.h> 2768f72004Sclaudio 2868f72004Sclaudio #include "bgpd.h" 2968f72004Sclaudio #include "rde.h" 305e3f6f95Sbenno #include "log.h" 3168f72004Sclaudio 3268f72004Sclaudio int 3339386878Sclaudio attr_writebuf(struct ibuf *buf, uint8_t flags, uint8_t type, void *data, 3439386878Sclaudio uint16_t data_len) 358a72043eSclaudio { 368a72043eSclaudio u_char hdr[4]; 378a72043eSclaudio 38caea8f61Sclaudio flags &= ~ATTR_DEFMASK; 398a72043eSclaudio if (data_len > 255) { 408a72043eSclaudio flags |= ATTR_EXTLEN; 418a72043eSclaudio hdr[2] = (data_len >> 8) & 0xff; 428a72043eSclaudio hdr[3] = data_len & 0xff; 438a72043eSclaudio } else { 448a72043eSclaudio hdr[2] = data_len & 0xff; 458a72043eSclaudio } 468a72043eSclaudio 478a72043eSclaudio hdr[0] = flags; 488a72043eSclaudio hdr[1] = type; 498a72043eSclaudio 50e39620e5Snicm if (ibuf_add(buf, hdr, flags & ATTR_EXTLEN ? 4 : 3) == -1) 518a72043eSclaudio return (-1); 528cd4606cSclaudio if (data != NULL && ibuf_add(buf, data, data_len) == -1) 538a72043eSclaudio return (-1); 548a72043eSclaudio return (0); 558a72043eSclaudio } 568a72043eSclaudio 5755e823c7Sclaudio /* optional attribute specific functions */ 581f826a12Sclaudio struct attr *attr_alloc(uint8_t, uint8_t, void *, uint16_t); 591f826a12Sclaudio struct attr *attr_lookup(uint8_t, uint8_t, void *, uint16_t); 6055e823c7Sclaudio void attr_put(struct attr *); 6155e823c7Sclaudio 621f826a12Sclaudio static inline int attr_diff(struct attr *, struct attr *); 6355e823c7Sclaudio 641f826a12Sclaudio RB_HEAD(attr_tree, attr) attrtable = RB_INITIALIZER(&attr); 651f826a12Sclaudio RB_GENERATE_STATIC(attr_tree, attr, entry, attr_diff); 667e8b30f9Stedu 6755e823c7Sclaudio 6855e823c7Sclaudio void 6955e823c7Sclaudio attr_shutdown(void) 7055e823c7Sclaudio { 711f826a12Sclaudio if (!RB_EMPTY(&attrtable)) 721f826a12Sclaudio log_warnx("%s: free non-free attr table", __func__); 734670f09dSclaudio } 744670f09dSclaudio 75e22cf8c8Sclaudio int 7639386878Sclaudio attr_optadd(struct rde_aspath *asp, uint8_t flags, uint8_t type, 7739386878Sclaudio void *data, uint16_t len) 7868f72004Sclaudio { 7939386878Sclaudio uint8_t l; 8055e823c7Sclaudio struct attr *a, *t; 8188a24b5dShenning void *p; 8268f72004Sclaudio 8327e1f569Sclaudio /* known optional attributes were validated previously */ 840422f938Sclaudio if ((a = attr_lookup(flags, type, data, len)) == NULL) 8555e823c7Sclaudio a = attr_alloc(flags, type, data, len); 8655e823c7Sclaudio 8755e823c7Sclaudio /* attribute allowed only once */ 8855e823c7Sclaudio for (l = 0; l < asp->others_len; l++) { 8955e823c7Sclaudio if (asp->others[l] == NULL) 9055e823c7Sclaudio break; 91f1a84a52Sclaudio if (type == asp->others[l]->type) { 92f1a84a52Sclaudio if (a->refcnt == 0) 93f1a84a52Sclaudio attr_put(a); 9455e823c7Sclaudio return (-1); 9555e823c7Sclaudio } 96f1a84a52Sclaudio } 9755e823c7Sclaudio 9855e823c7Sclaudio /* add attribute to the table but first bump refcnt */ 9955e823c7Sclaudio a->refcnt++; 10055e823c7Sclaudio rdemem.attr_refs++; 10155e823c7Sclaudio 10255e823c7Sclaudio for (l = 0; l < asp->others_len; l++) { 10355e823c7Sclaudio if (asp->others[l] == NULL) { 10455e823c7Sclaudio asp->others[l] = a; 10555e823c7Sclaudio return (0); 10655e823c7Sclaudio } 10755e823c7Sclaudio /* list is sorted */ 10855e823c7Sclaudio if (a->type < asp->others[l]->type) { 10955e823c7Sclaudio t = asp->others[l]; 11055e823c7Sclaudio asp->others[l] = a; 11155e823c7Sclaudio a = t; 11255e823c7Sclaudio } 11355e823c7Sclaudio } 11455e823c7Sclaudio 11555e823c7Sclaudio /* no empty slot found, need to realloc */ 116fc7c6d34Sclaudio if (asp->others_len == UCHAR_MAX) 117fc7c6d34Sclaudio fatalx("attr_optadd: others_len overflow"); 118fc7c6d34Sclaudio 11955e823c7Sclaudio asp->others_len++; 120b795643eSderaadt if ((p = reallocarray(asp->others, 121b795643eSderaadt asp->others_len, sizeof(struct attr *))) == NULL) 12267fd830bSclaudio fatal("%s", __func__); 12388a24b5dShenning asp->others = p; 12455e823c7Sclaudio 12555e823c7Sclaudio /* l stores the size of others before resize */ 12655e823c7Sclaudio asp->others[l] = a; 12755e823c7Sclaudio return (0); 12855e823c7Sclaudio } 12955e823c7Sclaudio 13055e823c7Sclaudio struct attr * 13139386878Sclaudio attr_optget(const struct rde_aspath *asp, uint8_t type) 13255e823c7Sclaudio { 13339386878Sclaudio uint8_t l; 13455e823c7Sclaudio 13555e823c7Sclaudio for (l = 0; l < asp->others_len; l++) { 13655e823c7Sclaudio if (asp->others[l] == NULL) 13755e823c7Sclaudio break; 13855e823c7Sclaudio if (type == asp->others[l]->type) 13955e823c7Sclaudio return (asp->others[l]); 14055e823c7Sclaudio if (type < asp->others[l]->type) 14155e823c7Sclaudio break; 14255e823c7Sclaudio } 14355e823c7Sclaudio return (NULL); 14455e823c7Sclaudio } 14555e823c7Sclaudio 14655e823c7Sclaudio void 1475d2e648fSclaudio attr_copy(struct rde_aspath *t, const struct rde_aspath *s) 14855e823c7Sclaudio { 14939386878Sclaudio uint8_t l; 15055e823c7Sclaudio 15155e823c7Sclaudio if (t->others != NULL) 15255e823c7Sclaudio attr_freeall(t); 15355e823c7Sclaudio 15490b77beaSclaudio t->others_len = s->others_len; 15590b77beaSclaudio if (t->others_len == 0) { 15690b77beaSclaudio t->others = NULL; 15790b77beaSclaudio return; 15890b77beaSclaudio } 15990b77beaSclaudio 16055e823c7Sclaudio if ((t->others = calloc(s->others_len, sizeof(struct attr *))) == 0) 16167fd830bSclaudio fatal("%s", __func__); 16255e823c7Sclaudio 16355e823c7Sclaudio for (l = 0; l < t->others_len; l++) { 16455e823c7Sclaudio if (s->others[l] == NULL) 16555e823c7Sclaudio break; 16655e823c7Sclaudio s->others[l]->refcnt++; 16755e823c7Sclaudio rdemem.attr_refs++; 16855e823c7Sclaudio t->others[l] = s->others[l]; 16955e823c7Sclaudio } 17055e823c7Sclaudio } 17155e823c7Sclaudio 1721f826a12Sclaudio static inline int 17355e823c7Sclaudio attr_diff(struct attr *oa, struct attr *ob) 17455e823c7Sclaudio { 17555e823c7Sclaudio int r; 17655e823c7Sclaudio 1777e5c8c52Sclaudio if (ob == NULL) 1787e5c8c52Sclaudio return (1); 1797e5c8c52Sclaudio if (oa == NULL) 1807e5c8c52Sclaudio return (-1); 1810422f938Sclaudio if (oa->flags > ob->flags) 1820422f938Sclaudio return (1); 1830422f938Sclaudio if (oa->flags < ob->flags) 1840422f938Sclaudio return (-1); 18555e823c7Sclaudio if (oa->type > ob->type) 18655e823c7Sclaudio return (1); 18755e823c7Sclaudio if (oa->type < ob->type) 18855e823c7Sclaudio return (-1); 18955e823c7Sclaudio if (oa->len > ob->len) 19055e823c7Sclaudio return (1); 19155e823c7Sclaudio if (oa->len < ob->len) 19255e823c7Sclaudio return (-1); 19355e823c7Sclaudio r = memcmp(oa->data, ob->data, oa->len); 19455e823c7Sclaudio if (r > 0) 19555e823c7Sclaudio return (1); 19655e823c7Sclaudio if (r < 0) 19755e823c7Sclaudio return (-1); 1981f826a12Sclaudio return (0); 19955e823c7Sclaudio } 20055e823c7Sclaudio 20155e823c7Sclaudio int 20255e823c7Sclaudio attr_compare(struct rde_aspath *a, struct rde_aspath *b) 20355e823c7Sclaudio { 20439386878Sclaudio uint8_t l, min; 20555e823c7Sclaudio 20655e823c7Sclaudio min = a->others_len < b->others_len ? a->others_len : b->others_len; 20755e823c7Sclaudio for (l = 0; l < min; l++) 20855e823c7Sclaudio if (a->others[l] != b->others[l]) 20955e823c7Sclaudio return (attr_diff(a->others[l], b->others[l])); 21055e823c7Sclaudio 21155e823c7Sclaudio if (a->others_len < b->others_len) { 21255e823c7Sclaudio for (; l < b->others_len; l++) 21355e823c7Sclaudio if (b->others[l] != NULL) 21455e823c7Sclaudio return (-1); 2159b79c7ebSclaudio } else if (a->others_len > b->others_len) { 21655e823c7Sclaudio for (; l < a->others_len; l++) 21755e823c7Sclaudio if (a->others[l] != NULL) 21855e823c7Sclaudio return (1); 21955e823c7Sclaudio } 22055e823c7Sclaudio 22155e823c7Sclaudio return (0); 22255e823c7Sclaudio } 22355e823c7Sclaudio 22455e823c7Sclaudio void 225ec8297f3Sclaudio attr_free(struct rde_aspath *asp, struct attr *attr) 226ec8297f3Sclaudio { 22739386878Sclaudio uint8_t l; 228ec8297f3Sclaudio 229ec8297f3Sclaudio for (l = 0; l < asp->others_len; l++) 230ec8297f3Sclaudio if (asp->others[l] == attr) { 231ec8297f3Sclaudio attr_put(asp->others[l]); 2327e5c8c52Sclaudio for (++l; l < asp->others_len; l++) 2337e5c8c52Sclaudio asp->others[l - 1] = asp->others[l]; 2347e5c8c52Sclaudio asp->others[asp->others_len - 1] = NULL; 235ec8297f3Sclaudio return; 236ec8297f3Sclaudio } 237ec8297f3Sclaudio 2387e5c8c52Sclaudio /* no realloc() because the slot may be reused soon */ 239ec8297f3Sclaudio } 240ec8297f3Sclaudio 241ec8297f3Sclaudio void 24255e823c7Sclaudio attr_freeall(struct rde_aspath *asp) 24355e823c7Sclaudio { 24439386878Sclaudio uint8_t l; 24555e823c7Sclaudio 24655e823c7Sclaudio for (l = 0; l < asp->others_len; l++) 24755e823c7Sclaudio attr_put(asp->others[l]); 24855e823c7Sclaudio 24955e823c7Sclaudio free(asp->others); 25055e823c7Sclaudio asp->others = NULL; 25155e823c7Sclaudio asp->others_len = 0; 25255e823c7Sclaudio } 25355e823c7Sclaudio 25455e823c7Sclaudio struct attr * 2551f826a12Sclaudio attr_alloc(uint8_t flags, uint8_t type, void *data, uint16_t len) 25655e823c7Sclaudio { 25755e823c7Sclaudio struct attr *a; 25855e823c7Sclaudio 25968f72004Sclaudio a = calloc(1, sizeof(struct attr)); 26068f72004Sclaudio if (a == NULL) 26167fd830bSclaudio fatal("%s", __func__); 2626b5f6ff8Sclaudio rdemem.attr_cnt++; 263af6b2e43Sclaudio 264caea8f61Sclaudio flags &= ~ATTR_DEFMASK; /* normalize mask */ 26568f72004Sclaudio a->flags = flags; 26668f72004Sclaudio a->type = type; 26768f72004Sclaudio a->len = len; 26868f72004Sclaudio if (len != 0) { 26955e823c7Sclaudio if ((a->data = malloc(len)) == NULL) 27067fd830bSclaudio fatal("%s", __func__); 271af6b2e43Sclaudio 272fc4470d5Sclaudio rdemem.attr_dcnt++; 2736b5f6ff8Sclaudio rdemem.attr_data += len; 27468f72004Sclaudio memcpy(a->data, data, len); 275e22cf8c8Sclaudio } else 276e22cf8c8Sclaudio a->data = NULL; 277e22cf8c8Sclaudio 2781f826a12Sclaudio if (RB_INSERT(attr_tree, &attrtable, a) != NULL) 2791f826a12Sclaudio fatalx("corrupted attr tree"); 28055e823c7Sclaudio 28155e823c7Sclaudio return (a); 28268f72004Sclaudio } 28368f72004Sclaudio 2840df2230cSclaudio struct attr * 2851f826a12Sclaudio attr_lookup(uint8_t flags, uint8_t type, void *data, uint16_t len) 2860df2230cSclaudio { 2871f826a12Sclaudio struct attr needle; 2880df2230cSclaudio 289caea8f61Sclaudio flags &= ~ATTR_DEFMASK; /* normalize mask */ 2907e8b30f9Stedu 2911f826a12Sclaudio needle.flags = flags; 2921f826a12Sclaudio needle.type = type; 2931f826a12Sclaudio needle.len = len; 2941f826a12Sclaudio needle.data = data; 2951f826a12Sclaudio return RB_FIND(attr_tree, &attrtable, &needle); 2960df2230cSclaudio } 2970df2230cSclaudio 29868f72004Sclaudio void 29955e823c7Sclaudio attr_put(struct attr *a) 300af6b2e43Sclaudio { 30155e823c7Sclaudio if (a == NULL) 30255e823c7Sclaudio return; 303af6b2e43Sclaudio 30455e823c7Sclaudio rdemem.attr_refs--; 30555e823c7Sclaudio if (--a->refcnt > 0) 30655e823c7Sclaudio /* somebody still holds a reference */ 30755e823c7Sclaudio return; 308af6b2e43Sclaudio 30955e823c7Sclaudio /* unlink */ 3101f826a12Sclaudio RB_REMOVE(attr_tree, &attrtable, a); 31168f72004Sclaudio 312fc4470d5Sclaudio if (a->len != 0) 313fc4470d5Sclaudio rdemem.attr_dcnt--; 3146b5f6ff8Sclaudio rdemem.attr_data -= a->len; 3156b5f6ff8Sclaudio rdemem.attr_cnt--; 31668f72004Sclaudio free(a->data); 31768f72004Sclaudio free(a); 31868f72004Sclaudio } 31968f72004Sclaudio 32068f72004Sclaudio /* aspath specific functions */ 32168f72004Sclaudio 32239386878Sclaudio static uint16_t aspath_count(const void *, uint16_t); 32339386878Sclaudio static uint32_t aspath_extract_origin(const void *, uint16_t); 32439386878Sclaudio static uint16_t aspath_countlength(struct aspath *, uint16_t, int); 32539386878Sclaudio static void aspath_countcopy(struct aspath *, uint16_t, uint8_t *, 32639386878Sclaudio uint16_t, int); 32768f72004Sclaudio 3283487a040Sclaudio int 3293487a040Sclaudio aspath_compare(struct aspath *a1, struct aspath *a2) 33068f72004Sclaudio { 3313487a040Sclaudio int r; 332b33564f7Sclaudio 3333487a040Sclaudio if (a1->len > a2->len) 3343487a040Sclaudio return (1); 3353487a040Sclaudio if (a1->len < a2->len) 3363487a040Sclaudio return (-1); 3373487a040Sclaudio r = memcmp(a1->data, a2->data, a1->len); 3383487a040Sclaudio if (r > 0) 3393487a040Sclaudio return (1); 3403487a040Sclaudio if (r < 0) 3413487a040Sclaudio return (-1); 3423487a040Sclaudio return (0); 3434670f09dSclaudio } 3444670f09dSclaudio 345b33564f7Sclaudio struct aspath * 34639386878Sclaudio aspath_get(void *data, uint16_t len) 347b33564f7Sclaudio { 34868f72004Sclaudio struct aspath *aspath; 34968f72004Sclaudio 35068f72004Sclaudio aspath = malloc(ASPATH_HEADER_SIZE + len); 35168f72004Sclaudio if (aspath == NULL) 3523487a040Sclaudio fatal("%s", __func__); 353b33564f7Sclaudio 3546b5f6ff8Sclaudio rdemem.aspath_cnt++; 3556b5f6ff8Sclaudio rdemem.aspath_size += ASPATH_HEADER_SIZE + len; 3566b5f6ff8Sclaudio 357b33564f7Sclaudio aspath->len = len; 358b33564f7Sclaudio aspath->ascnt = aspath_count(data, len); 359a34ea928Sclaudio aspath->source_as = aspath_extract_origin(data, len); 360*e386eeb1Sclaudio if (len != 0) 36168f72004Sclaudio memcpy(aspath->data, data, len); 36268f72004Sclaudio 3633487a040Sclaudio return (aspath); 364b33564f7Sclaudio } 3653487a040Sclaudio 3663487a040Sclaudio struct aspath * 3673487a040Sclaudio aspath_copy(struct aspath *a) 3683487a040Sclaudio { 3693487a040Sclaudio struct aspath *aspath; 3703487a040Sclaudio 3713487a040Sclaudio aspath = malloc(ASPATH_HEADER_SIZE + a->len); 3723487a040Sclaudio if (aspath == NULL) 3733487a040Sclaudio fatal("%s", __func__); 3743487a040Sclaudio 3753487a040Sclaudio rdemem.aspath_cnt++; 3763487a040Sclaudio rdemem.aspath_size += ASPATH_HEADER_SIZE + a->len; 3773487a040Sclaudio 3783487a040Sclaudio memcpy(aspath, a, ASPATH_HEADER_SIZE + a->len); 37968f72004Sclaudio 380ba0c695bSclaudio return (aspath); 38168f72004Sclaudio } 38268f72004Sclaudio 38368f72004Sclaudio void 384b33564f7Sclaudio aspath_put(struct aspath *aspath) 38568f72004Sclaudio { 386b33564f7Sclaudio if (aspath == NULL) 387b33564f7Sclaudio return; 388b33564f7Sclaudio 3896b5f6ff8Sclaudio rdemem.aspath_cnt--; 3906b5f6ff8Sclaudio rdemem.aspath_size -= ASPATH_HEADER_SIZE + aspath->len; 39168f72004Sclaudio free(aspath); 39268f72004Sclaudio } 39368f72004Sclaudio 39429328a94Sclaudio /* 39529328a94Sclaudio * convert a 4 byte aspath to a 2 byte one. 39629328a94Sclaudio */ 3970c88bf70Sclaudio u_char * 39839386878Sclaudio aspath_deflate(u_char *data, uint16_t *len, int *flagnew) 3990c88bf70Sclaudio { 400*e386eeb1Sclaudio uint8_t *seg, *nseg, *ndata = NULL; 40139386878Sclaudio uint32_t as; 4020c88bf70Sclaudio int i; 40339386878Sclaudio uint16_t seg_size, olen, nlen; 40439386878Sclaudio uint8_t seg_len; 4050c88bf70Sclaudio 4060c88bf70Sclaudio /* first calculate the length of the aspath */ 4070c88bf70Sclaudio nlen = 0; 4080c88bf70Sclaudio seg = data; 4090c88bf70Sclaudio olen = *len; 4100c88bf70Sclaudio for (; olen > 0; olen -= seg_size, seg += seg_size) { 4110c88bf70Sclaudio seg_len = seg[1]; 41239386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 41339386878Sclaudio nlen += 2 + sizeof(uint16_t) * seg_len; 4140c88bf70Sclaudio 4150c88bf70Sclaudio if (seg_size > olen) 4166f1dba6eSclaudio fatalx("%s: would overflow", __func__); 4170c88bf70Sclaudio } 4180c88bf70Sclaudio 419*e386eeb1Sclaudio if (nlen == 0) 420*e386eeb1Sclaudio goto done; 421*e386eeb1Sclaudio 4220c88bf70Sclaudio if ((ndata = malloc(nlen)) == NULL) 42367fd830bSclaudio fatal("%s", __func__); 4240c88bf70Sclaudio 4250c88bf70Sclaudio /* then copy the aspath */ 4260c88bf70Sclaudio seg = data; 4270c88bf70Sclaudio olen = *len; 4280c88bf70Sclaudio for (nseg = ndata; seg < data + olen; seg += seg_size) { 4290c88bf70Sclaudio *nseg++ = seg[0]; 4300c88bf70Sclaudio *nseg++ = seg_len = seg[1]; 43139386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 4320c88bf70Sclaudio 4330c88bf70Sclaudio for (i = 0; i < seg_len; i++) { 4340c88bf70Sclaudio as = aspath_extract(seg, i); 4350c88bf70Sclaudio if (as > USHRT_MAX) { 4360c88bf70Sclaudio as = AS_TRANS; 4370c88bf70Sclaudio *flagnew = 1; 4380c88bf70Sclaudio } 4390c88bf70Sclaudio *nseg++ = (as >> 8) & 0xff; 4400c88bf70Sclaudio *nseg++ = as & 0xff; 4410c88bf70Sclaudio } 4420c88bf70Sclaudio } 4430c88bf70Sclaudio 444*e386eeb1Sclaudio done: 4450c88bf70Sclaudio *len = nlen; 4460c88bf70Sclaudio return (ndata); 4470c88bf70Sclaudio } 4480c88bf70Sclaudio 4490c88bf70Sclaudio void 4500c88bf70Sclaudio aspath_merge(struct rde_aspath *a, struct attr *attr) 4510c88bf70Sclaudio { 45239386878Sclaudio uint8_t *np; 45339386878Sclaudio uint16_t ascnt, diff, nlen, difflen; 4540c88bf70Sclaudio int hroom = 0; 4550c88bf70Sclaudio 4560c88bf70Sclaudio ascnt = aspath_count(attr->data, attr->len); 4570c88bf70Sclaudio if (ascnt > a->aspath->ascnt) { 4585beb19c6Ssthen /* ASPATH is shorter then AS4_PATH no way to merge */ 4590c88bf70Sclaudio attr_free(a, attr); 4600c88bf70Sclaudio return; 4610c88bf70Sclaudio } 4620c88bf70Sclaudio 4630c88bf70Sclaudio diff = a->aspath->ascnt - ascnt; 464fd203cf3Sclaudio if (diff && attr->len > 2 && attr->data[0] == AS_SEQUENCE) 4650c88bf70Sclaudio hroom = attr->data[1]; 4660c88bf70Sclaudio difflen = aspath_countlength(a->aspath, diff, hroom); 4670c88bf70Sclaudio nlen = attr->len + difflen; 4680c88bf70Sclaudio 4690c88bf70Sclaudio if ((np = malloc(nlen)) == NULL) 47067fd830bSclaudio fatal("%s", __func__); 4710c88bf70Sclaudio 4720c88bf70Sclaudio /* copy head from old aspath */ 4730c88bf70Sclaudio aspath_countcopy(a->aspath, diff, np, difflen, hroom); 4740c88bf70Sclaudio 4750c88bf70Sclaudio /* copy tail from new aspath */ 4760c88bf70Sclaudio if (hroom > 0) 4770c88bf70Sclaudio memcpy(np + nlen - attr->len + 2, attr->data + 2, 4780c88bf70Sclaudio attr->len - 2); 4790c88bf70Sclaudio else 4800c88bf70Sclaudio memcpy(np + nlen - attr->len, attr->data, attr->len); 4810c88bf70Sclaudio 4820c88bf70Sclaudio aspath_put(a->aspath); 4830c88bf70Sclaudio a->aspath = aspath_get(np, nlen); 4840c88bf70Sclaudio free(np); 4850c88bf70Sclaudio attr_free(a, attr); 4860c88bf70Sclaudio } 4870c88bf70Sclaudio 48839386878Sclaudio uint32_t 489a34ea928Sclaudio aspath_neighbor(struct aspath *aspath) 490a34ea928Sclaudio { 491a3d44d86Sclaudio /* 492a3d44d86Sclaudio * Empty aspath is OK -- internal AS route. 493a3d44d86Sclaudio * Additionally the RFC specifies that if the path starts with an 494a3d44d86Sclaudio * AS_SET the neighbor AS is also the local AS. 495a3d44d86Sclaudio */ 496a3d44d86Sclaudio if (aspath->len == 0 || 497a3d44d86Sclaudio aspath->data[0] != AS_SEQUENCE) 498a34ea928Sclaudio return (rde_local_as()); 499a34ea928Sclaudio return (aspath_extract(aspath->data, 0)); 500a34ea928Sclaudio } 501a34ea928Sclaudio 50239386878Sclaudio static uint16_t 50339386878Sclaudio aspath_count(const void *data, uint16_t len) 50468f72004Sclaudio { 50539386878Sclaudio const uint8_t *seg; 50639386878Sclaudio uint16_t cnt, seg_size; 50739386878Sclaudio uint8_t seg_type, seg_len; 50868f72004Sclaudio 50968f72004Sclaudio cnt = 0; 510b33564f7Sclaudio seg = data; 511b33564f7Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 51268f72004Sclaudio seg_type = seg[0]; 51368f72004Sclaudio seg_len = seg[1]; 51439386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 51568f72004Sclaudio 51668f72004Sclaudio if (seg_type == AS_SET) 51768f72004Sclaudio cnt += 1; 51868f72004Sclaudio else 51968f72004Sclaudio cnt += seg_len; 520b33564f7Sclaudio 521b33564f7Sclaudio if (seg_size > len) 5226f1dba6eSclaudio fatalx("%s: would overflow", __func__); 52368f72004Sclaudio } 524ba0c695bSclaudio return (cnt); 52568f72004Sclaudio } 52668f72004Sclaudio 527a34ea928Sclaudio /* 528a34ea928Sclaudio * The origin AS number derived from a Route as follows: 529a34ea928Sclaudio * o the rightmost AS in the final segment of the AS_PATH attribute 530a34ea928Sclaudio * in the Route if that segment is of type AS_SEQUENCE, or 531a34ea928Sclaudio * o the BGP speaker's own AS number if that segment is of type 532a34ea928Sclaudio * AS_CONFED_SEQUENCE or AS_CONFED_SET or if the AS_PATH is empty, 533a34ea928Sclaudio * o the distinguished value "NONE" if the final segment of the 534a34ea928Sclaudio * AS_PATH attribute is of any other type. 535a34ea928Sclaudio */ 53639386878Sclaudio static uint32_t 53739386878Sclaudio aspath_extract_origin(const void *data, uint16_t len) 538a34ea928Sclaudio { 53939386878Sclaudio const uint8_t *seg; 54039386878Sclaudio uint32_t as = AS_NONE; 54139386878Sclaudio uint16_t seg_size; 54239386878Sclaudio uint8_t seg_len; 543a34ea928Sclaudio 544a34ea928Sclaudio /* AS_PATH is empty */ 545a34ea928Sclaudio if (len == 0) 546a34ea928Sclaudio return (rde_local_as()); 547a34ea928Sclaudio 548a34ea928Sclaudio seg = data; 549a34ea928Sclaudio for (; len > 0; len -= seg_size, seg += seg_size) { 550a34ea928Sclaudio seg_len = seg[1]; 55139386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 552a34ea928Sclaudio 553a34ea928Sclaudio if (len == seg_size && seg[0] == AS_SEQUENCE) { 554a34ea928Sclaudio as = aspath_extract(seg, seg_len - 1); 555a34ea928Sclaudio } 556a34ea928Sclaudio if (seg_size > len) 557a34ea928Sclaudio fatalx("%s: would overflow", __func__); 558a34ea928Sclaudio } 559a34ea928Sclaudio return (as); 560a34ea928Sclaudio } 561a34ea928Sclaudio 56239386878Sclaudio static uint16_t 56339386878Sclaudio aspath_countlength(struct aspath *aspath, uint16_t cnt, int headcnt) 5640c88bf70Sclaudio { 56539386878Sclaudio const uint8_t *seg; 56639386878Sclaudio uint16_t seg_size, len, clen; 56739386878Sclaudio uint8_t seg_type = 0, seg_len = 0; 5680c88bf70Sclaudio 5690c88bf70Sclaudio seg = aspath->data; 5700c88bf70Sclaudio clen = 0; 5710c88bf70Sclaudio for (len = aspath->len; len > 0 && cnt > 0; 5720c88bf70Sclaudio len -= seg_size, seg += seg_size) { 5730c88bf70Sclaudio seg_type = seg[0]; 5740c88bf70Sclaudio seg_len = seg[1]; 57539386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 5760c88bf70Sclaudio 5770c88bf70Sclaudio if (seg_type == AS_SET) 5780c88bf70Sclaudio cnt -= 1; 5790c88bf70Sclaudio else if (seg_len > cnt) { 5800c88bf70Sclaudio seg_len = cnt; 58139386878Sclaudio clen += 2 + sizeof(uint32_t) * cnt; 5820c88bf70Sclaudio break; 5830c88bf70Sclaudio } else 5840c88bf70Sclaudio cnt -= seg_len; 5850c88bf70Sclaudio 5860c88bf70Sclaudio clen += seg_size; 5870c88bf70Sclaudio 5880c88bf70Sclaudio if (seg_size > len) 5896f1dba6eSclaudio fatalx("%s: would overflow", __func__); 5900c88bf70Sclaudio } 5910c88bf70Sclaudio if (headcnt > 0 && seg_type == AS_SEQUENCE && headcnt + seg_len < 256) 5920c88bf70Sclaudio /* no need for additional header from the new aspath. */ 5930c88bf70Sclaudio clen -= 2; 5940c88bf70Sclaudio 5950c88bf70Sclaudio return (clen); 5960c88bf70Sclaudio } 5970c88bf70Sclaudio 59813409241Sclaudio static void 59939386878Sclaudio aspath_countcopy(struct aspath *aspath, uint16_t cnt, uint8_t *buf, 60039386878Sclaudio uint16_t size, int headcnt) 6010c88bf70Sclaudio { 60239386878Sclaudio const uint8_t *seg; 60339386878Sclaudio uint16_t seg_size, len; 60439386878Sclaudio uint8_t seg_type, seg_len; 6050c88bf70Sclaudio 6060c88bf70Sclaudio if (headcnt > 0) 6070c88bf70Sclaudio /* 6080c88bf70Sclaudio * additional room because we steal the segment header 6090c88bf70Sclaudio * from the other aspath 6100c88bf70Sclaudio */ 6110c88bf70Sclaudio size += 2; 6120c88bf70Sclaudio seg = aspath->data; 6130c88bf70Sclaudio for (len = aspath->len; len > 0 && cnt > 0; 6140c88bf70Sclaudio len -= seg_size, seg += seg_size) { 6150c88bf70Sclaudio seg_type = seg[0]; 6160c88bf70Sclaudio seg_len = seg[1]; 61739386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 6180c88bf70Sclaudio 6190c88bf70Sclaudio if (seg_type == AS_SET) 6200c88bf70Sclaudio cnt -= 1; 6210c88bf70Sclaudio else if (seg_len > cnt) { 6220c88bf70Sclaudio seg_len = cnt + headcnt; 62339386878Sclaudio seg_size = 2 + sizeof(uint32_t) * cnt; 6240c88bf70Sclaudio cnt = 0; 6250c88bf70Sclaudio } else { 6260c88bf70Sclaudio cnt -= seg_len; 6270c88bf70Sclaudio if (cnt == 0) 6280c88bf70Sclaudio seg_len += headcnt; 6290c88bf70Sclaudio } 6300c88bf70Sclaudio 6310c88bf70Sclaudio memcpy(buf, seg, seg_size); 6320c88bf70Sclaudio buf[0] = seg_type; 6330c88bf70Sclaudio buf[1] = seg_len; 6340c88bf70Sclaudio buf += seg_size; 6350c88bf70Sclaudio if (size < seg_size) 6366f1dba6eSclaudio fatalx("%s: would overflow", __func__); 6370c88bf70Sclaudio size -= seg_size; 6380c88bf70Sclaudio } 6390c88bf70Sclaudio } 6400c88bf70Sclaudio 6411384e26cSclaudio int 64239386878Sclaudio aspath_loopfree(struct aspath *aspath, uint32_t myAS) 6431384e26cSclaudio { 64439386878Sclaudio uint8_t *seg; 64539386878Sclaudio uint16_t len, seg_size; 64639386878Sclaudio uint8_t i, seg_len; 6471384e26cSclaudio 6481384e26cSclaudio seg = aspath->data; 649b33564f7Sclaudio for (len = aspath->len; len > 0; len -= seg_size, seg += seg_size) { 6501384e26cSclaudio seg_len = seg[1]; 65139386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 6521384e26cSclaudio 6531384e26cSclaudio for (i = 0; i < seg_len; i++) { 6541384e26cSclaudio if (myAS == aspath_extract(seg, i)) 655ba0c695bSclaudio return (0); 6561384e26cSclaudio } 657b33564f7Sclaudio 658b33564f7Sclaudio if (seg_size > len) 6596f1dba6eSclaudio fatalx("%s: would overflow", __func__); 6601384e26cSclaudio } 661ba0c695bSclaudio return (1); 6621384e26cSclaudio } 6631384e26cSclaudio 664a34ea928Sclaudio static int 66539386878Sclaudio as_compare(struct filter_as *f, uint32_t as, uint32_t neighas) 666a34ea928Sclaudio { 66739386878Sclaudio uint32_t match; 668a34ea928Sclaudio 669a34ea928Sclaudio if (f->flags & AS_FLAG_AS_SET_NAME) /* should not happen */ 670a34ea928Sclaudio return (0); 671a34ea928Sclaudio if (f->flags & AS_FLAG_AS_SET) 672a34ea928Sclaudio return (as_set_match(f->aset, as)); 673a34ea928Sclaudio 674a34ea928Sclaudio if (f->flags & AS_FLAG_NEIGHBORAS) 675a34ea928Sclaudio match = neighas; 676a34ea928Sclaudio else 677a34ea928Sclaudio match = f->as_min; 678a34ea928Sclaudio 679a34ea928Sclaudio switch (f->op) { 680a34ea928Sclaudio case OP_NONE: 681a34ea928Sclaudio case OP_EQ: 682a34ea928Sclaudio if (as == match) 683a34ea928Sclaudio return (1); 684a34ea928Sclaudio break; 685a34ea928Sclaudio case OP_NE: 686a34ea928Sclaudio if (as != match) 687a34ea928Sclaudio return (1); 688a34ea928Sclaudio break; 689a34ea928Sclaudio case OP_RANGE: 690a34ea928Sclaudio if (as >= f->as_min && as <= f->as_max) 691a34ea928Sclaudio return (1); 692a34ea928Sclaudio break; 693a34ea928Sclaudio case OP_XRANGE: 694a34ea928Sclaudio if (as < f->as_min || as > f->as_max) 695a34ea928Sclaudio return (1); 696a34ea928Sclaudio break; 697a34ea928Sclaudio } 698a34ea928Sclaudio return (0); 699a34ea928Sclaudio } 700a34ea928Sclaudio 701a34ea928Sclaudio /* we need to be able to search more than one as */ 702a34ea928Sclaudio int 70339386878Sclaudio aspath_match(struct aspath *aspath, struct filter_as *f, uint32_t neighas) 704a34ea928Sclaudio { 70539386878Sclaudio const uint8_t *seg; 706a34ea928Sclaudio int final; 70739386878Sclaudio uint16_t len, seg_size; 70839386878Sclaudio uint8_t i, seg_len; 70939386878Sclaudio uint32_t as = AS_NONE; 710a34ea928Sclaudio 711a34ea928Sclaudio if (f->type == AS_EMPTY) { 712a34ea928Sclaudio if (aspath_length(aspath) == 0) 713a34ea928Sclaudio return (1); 714a34ea928Sclaudio else 715a34ea928Sclaudio return (0); 716a34ea928Sclaudio } 717a34ea928Sclaudio 718a34ea928Sclaudio /* just check the leftmost AS */ 719a34ea928Sclaudio if (f->type == AS_PEER) { 720a34ea928Sclaudio as = aspath_neighbor(aspath); 721a34ea928Sclaudio if (as_compare(f, as, neighas)) 722a34ea928Sclaudio return (1); 723a34ea928Sclaudio else 724a34ea928Sclaudio return (0); 725a34ea928Sclaudio } 726a34ea928Sclaudio 727a34ea928Sclaudio seg = aspath->data; 728a34ea928Sclaudio len = aspath->len; 729a34ea928Sclaudio for (; len >= 6; len -= seg_size, seg += seg_size) { 730a34ea928Sclaudio seg_len = seg[1]; 73139386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 732a34ea928Sclaudio 733a34ea928Sclaudio final = (len == seg_size); 734a34ea928Sclaudio 735a34ea928Sclaudio if (f->type == AS_SOURCE) { 736a34ea928Sclaudio /* 737a34ea928Sclaudio * Just extract the rightmost AS 738a34ea928Sclaudio * but if that segment is an AS_SET then the rightmost 739a34ea928Sclaudio * AS of a previous AS_SEQUENCE segment should be used. 740a34ea928Sclaudio * Because of that just look at AS_SEQUENCE segments. 741a34ea928Sclaudio */ 742a34ea928Sclaudio if (seg[0] == AS_SEQUENCE) 743a34ea928Sclaudio as = aspath_extract(seg, seg_len - 1); 744a34ea928Sclaudio /* not yet in the final segment */ 745a34ea928Sclaudio if (!final) 746a34ea928Sclaudio continue; 747a34ea928Sclaudio if (as_compare(f, as, neighas)) 748a34ea928Sclaudio return (1); 749a34ea928Sclaudio else 750a34ea928Sclaudio return (0); 751a34ea928Sclaudio } 752a34ea928Sclaudio /* AS_TRANSIT or AS_ALL */ 753a34ea928Sclaudio for (i = 0; i < seg_len; i++) { 754a34ea928Sclaudio /* 755a34ea928Sclaudio * the source (rightmost) AS is excluded from 756a34ea928Sclaudio * AS_TRANSIT matches. 757a34ea928Sclaudio */ 758a34ea928Sclaudio if (final && i == seg_len - 1 && f->type == AS_TRANSIT) 759a34ea928Sclaudio return (0); 760a34ea928Sclaudio as = aspath_extract(seg, i); 761a34ea928Sclaudio if (as_compare(f, as, neighas)) 762a34ea928Sclaudio return (1); 763a34ea928Sclaudio } 764d7a2dcd7Sclaudio 765d7a2dcd7Sclaudio if (seg_size > len) 766d7a2dcd7Sclaudio fatalx("%s: would overflow", __func__); 767a34ea928Sclaudio } 768a34ea928Sclaudio return (0); 769a34ea928Sclaudio } 770a34ea928Sclaudio 771b33564f7Sclaudio /* 772b33564f7Sclaudio * Returns a new prepended aspath. Old needs to be freed by caller. 773b33564f7Sclaudio */ 7740c88bf70Sclaudio u_char * 77539386878Sclaudio aspath_prepend(struct aspath *asp, uint32_t as, int quantum, uint16_t *len) 776b33564f7Sclaudio { 777b33564f7Sclaudio u_char *p; 7780c88bf70Sclaudio int l, overflow = 0, shift = 0, size, wpos = 0; 77939386878Sclaudio uint8_t type; 780b33564f7Sclaudio 781b33564f7Sclaudio /* lunatic prepends are blocked in the parser and limited */ 782b33564f7Sclaudio 783b33564f7Sclaudio /* first calculate new size */ 784b33564f7Sclaudio if (asp->len > 0) { 785b33564f7Sclaudio if (asp->len < 2) 78610004ee3Sclaudio fatalx("aspath_prepend: bad aspath length"); 787b33564f7Sclaudio type = asp->data[0]; 788b33564f7Sclaudio size = asp->data[1]; 789b33564f7Sclaudio } else { 790b33564f7Sclaudio /* empty as path */ 791b33564f7Sclaudio type = AS_SET; 792b33564f7Sclaudio size = 0; 793b33564f7Sclaudio } 794b33564f7Sclaudio 795df364eccSclaudio if (quantum > 255) 796df364eccSclaudio fatalx("aspath_prepend: preposterous prepend"); 797b33564f7Sclaudio if (quantum == 0) { 7980c88bf70Sclaudio /* no change needed but return a copy */ 799*e386eeb1Sclaudio if (asp->len == 0) { 800*e386eeb1Sclaudio *len = 0; 801*e386eeb1Sclaudio return (NULL); 802*e386eeb1Sclaudio } 8030c88bf70Sclaudio p = malloc(asp->len); 8040c88bf70Sclaudio if (p == NULL) 80567fd830bSclaudio fatal("%s", __func__); 8060c88bf70Sclaudio memcpy(p, asp->data, asp->len); 8070c88bf70Sclaudio *len = asp->len; 8080c88bf70Sclaudio return (p); 809b33564f7Sclaudio } else if (type == AS_SET || size + quantum > 255) { 810b33564f7Sclaudio /* need to attach a new AS_SEQUENCE */ 81139386878Sclaudio l = 2 + quantum * sizeof(uint32_t) + asp->len; 812df364eccSclaudio if (type == AS_SET) 813df364eccSclaudio overflow = quantum; 814df364eccSclaudio else 815df364eccSclaudio overflow = size + quantum - 255; 816b33564f7Sclaudio } else 81739386878Sclaudio l = quantum * sizeof(uint32_t) + asp->len; 818b33564f7Sclaudio 819b33564f7Sclaudio quantum -= overflow; 820b33564f7Sclaudio 8210c88bf70Sclaudio p = malloc(l); 822b33564f7Sclaudio if (p == NULL) 82367fd830bSclaudio fatal("%s", __func__); 824b33564f7Sclaudio 825b33564f7Sclaudio /* first prepends */ 8260c88bf70Sclaudio as = htonl(as); 827b33564f7Sclaudio if (overflow > 0) { 828b33564f7Sclaudio p[wpos++] = AS_SEQUENCE; 829b33564f7Sclaudio p[wpos++] = overflow; 830b33564f7Sclaudio 831b33564f7Sclaudio for (; overflow > 0; overflow--) { 83239386878Sclaudio memcpy(p + wpos, &as, sizeof(uint32_t)); 83339386878Sclaudio wpos += sizeof(uint32_t); 834b33564f7Sclaudio } 835b33564f7Sclaudio } 836b33564f7Sclaudio if (quantum > 0) { 837b33564f7Sclaudio shift = 2; 838b33564f7Sclaudio p[wpos++] = AS_SEQUENCE; 839b33564f7Sclaudio p[wpos++] = quantum + size; 840b33564f7Sclaudio 841b33564f7Sclaudio for (; quantum > 0; quantum--) { 84239386878Sclaudio memcpy(p + wpos, &as, sizeof(uint32_t)); 84339386878Sclaudio wpos += sizeof(uint32_t); 844b33564f7Sclaudio } 845b33564f7Sclaudio } 846*e386eeb1Sclaudio if (asp->len > shift) 847b33564f7Sclaudio memcpy(p + wpos, asp->data + shift, asp->len - shift); 848b33564f7Sclaudio 8490c88bf70Sclaudio *len = l; 8500c88bf70Sclaudio return (p); 85168f72004Sclaudio } 85268f72004Sclaudio 853d7a2dcd7Sclaudio /* 854d7a2dcd7Sclaudio * Returns a new aspath where neighbor_as is replaced by local_as. 855d7a2dcd7Sclaudio */ 856d7a2dcd7Sclaudio u_char * 85739386878Sclaudio aspath_override(struct aspath *asp, uint32_t neighbor_as, uint32_t local_as, 85839386878Sclaudio uint16_t *len) 859d7a2dcd7Sclaudio { 860d7a2dcd7Sclaudio u_char *p, *seg, *nseg; 86139386878Sclaudio uint32_t as; 86239386878Sclaudio uint16_t l, seg_size; 86339386878Sclaudio uint8_t i, seg_len, seg_type; 864d7a2dcd7Sclaudio 865*e386eeb1Sclaudio if (asp->len == 0) { 866*e386eeb1Sclaudio *len = 0; 867*e386eeb1Sclaudio return (NULL); 868*e386eeb1Sclaudio } 869*e386eeb1Sclaudio 870d7a2dcd7Sclaudio p = malloc(asp->len); 871d7a2dcd7Sclaudio if (p == NULL) 87267fd830bSclaudio fatal("%s", __func__); 873d7a2dcd7Sclaudio 874d7a2dcd7Sclaudio seg = asp->data; 875d7a2dcd7Sclaudio nseg = p; 876d7a2dcd7Sclaudio for (l = asp->len; l > 0; l -= seg_size, seg += seg_size) { 877d7a2dcd7Sclaudio *nseg++ = seg_type = seg[0]; 878d7a2dcd7Sclaudio *nseg++ = seg_len = seg[1]; 87939386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 880d7a2dcd7Sclaudio 881d7a2dcd7Sclaudio for (i = 0; i < seg_len; i++) { 882d7a2dcd7Sclaudio as = aspath_extract(seg, i); 883d7a2dcd7Sclaudio if (as == neighbor_as) 884d7a2dcd7Sclaudio as = local_as; 885d7a2dcd7Sclaudio as = htonl(as); 886d7a2dcd7Sclaudio memcpy(nseg, &as, sizeof(as)); 887d7a2dcd7Sclaudio nseg += sizeof(as); 888d7a2dcd7Sclaudio } 889d7a2dcd7Sclaudio 890d7a2dcd7Sclaudio if (seg_size > l) 891d7a2dcd7Sclaudio fatalx("%s: would overflow", __func__); 892d7a2dcd7Sclaudio } 893d7a2dcd7Sclaudio 894d7a2dcd7Sclaudio *len = asp->len; 895d7a2dcd7Sclaudio return (p); 896d7a2dcd7Sclaudio } 897d7a2dcd7Sclaudio 8984a044d31Sclaudio int 8994a044d31Sclaudio aspath_lenmatch(struct aspath *a, enum aslen_spec type, u_int aslen) 9004a044d31Sclaudio { 90139386878Sclaudio uint8_t *seg; 90239386878Sclaudio uint32_t as, lastas = 0; 9034a044d31Sclaudio u_int count = 0; 90439386878Sclaudio uint16_t len, seg_size; 90539386878Sclaudio uint8_t i, seg_len, seg_type; 9064a044d31Sclaudio 9074a044d31Sclaudio if (type == ASLEN_MAX) { 9084a044d31Sclaudio if (aslen < aspath_count(a->data, a->len)) 9094a044d31Sclaudio return (1); 9104a044d31Sclaudio else 9114a044d31Sclaudio return (0); 9124a044d31Sclaudio } 9134a044d31Sclaudio 9144a044d31Sclaudio /* type == ASLEN_SEQ */ 9154a044d31Sclaudio seg = a->data; 9164a044d31Sclaudio for (len = a->len; len > 0; len -= seg_size, seg += seg_size) { 917bce5f8adSclaudio seg_type = seg[0]; 9184a044d31Sclaudio seg_len = seg[1]; 91939386878Sclaudio seg_size = 2 + sizeof(uint32_t) * seg_len; 9204a044d31Sclaudio 9214a044d31Sclaudio for (i = 0; i < seg_len; i++) { 9224a044d31Sclaudio as = aspath_extract(seg, i); 9234a044d31Sclaudio if (as == lastas) { 9244a044d31Sclaudio if (aslen < ++count) 9254a044d31Sclaudio return (1); 926bce5f8adSclaudio } else if (seg_type == AS_SET) { 927bce5f8adSclaudio /* AS path 3 { 4 3 7 } 3 will have count = 3 */ 928bce5f8adSclaudio continue; 9294a044d31Sclaudio } else 9304a044d31Sclaudio count = 1; 9314a044d31Sclaudio lastas = as; 9324a044d31Sclaudio } 933d7a2dcd7Sclaudio 934d7a2dcd7Sclaudio if (seg_size > len) 935d7a2dcd7Sclaudio fatalx("%s: would overflow", __func__); 9364a044d31Sclaudio } 9374a044d31Sclaudio return (0); 9384a044d31Sclaudio } 939