diff --git a/CHANGES b/CHANGES index 547e0b8..f6694a6 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,10 @@ untagged yet (2018-09-05) - fix ipv6 prefix-ranges. Reported by Jay Ford. - OpenBGPd change: -E now generates prefix-set instead of prefix-list. Based on submission by Denis Fondras + - new option -w, allowing to 'validate' AS numbers included in as-path + access-lists: only those AS having registered route-objects are allowed. + By default checks route[4] presence, to check route6 objects shall be + used together with -6. 0.1.35-rc2 (2017-06-14) - OpenBSD need . Reported by Denis Fondras. diff --git a/bgpq3.c b/bgpq3.c index 5098b51..d43fea7 100644 --- a/bgpq3.c +++ b/bgpq3.c @@ -27,7 +27,7 @@ int usage(int ecode) { printf("\nUsage: bgpq3 [-h host[:port]] [-S sources] [-P|E|G |f ]" - " [-2346ABbDJjXd] [-R len] ...\n"); + " [-2346ABbDdJjwXz] [-R len] ...\n"); printf(" -2 : allow routes belonging to as23456 (transition-as) " "(default: false)\n"); printf(" -3 : assume that your device is asn32-safe\n"); @@ -69,6 +69,8 @@ usage(int ecode) printf(" -U : generate config for Huawei (Cisco IOS by default)\n"); printf(" -W len : specify max-entries on as-path line (use 0 for " "infinity)\n"); + printf(" -w : 'validate' AS numbers: accept only ones with " + "registered routes\n"); printf(" -X : generate config for IOS XR (Cisco IOS by default)\n"); printf("\n" PACKAGE_NAME " version: " PACKAGE_VERSION "\n"); printf("Copyright(c) Alexandre Snarskii 2007-2018\n\n"); @@ -140,7 +142,7 @@ main(int argc, char* argv[]) if (getenv("IRRD_SOURCES")) expander.sources=getenv("IRRD_SOURCES"); - while((c=getopt(argc,argv,"2346a:AbBdDEF:S:jJf:l:L:m:M:NW:Ppr:R:G:Th:UXsz")) + while((c=getopt(argc,argv,"2346a:AbBdDEF:S:jJf:l:L:m:M:NW:Ppr:R:G:Th:UwXsz")) !=EOF) { switch(c) { case '2': @@ -312,6 +314,8 @@ main(int argc, char* argv[]) }; widthSet=1; break; + case 'w': expander.validate_asns=1; + break; case 'X': if(expander.vendor) vendor_exclusive(); expander.vendor=V_CISCO_XR; break; @@ -530,11 +534,17 @@ main(int argc, char* argv[]) }; if((expander.generation==T_ASPATH || expander.generation==T_OASPATH) && - af != AF_INET) { + af != AF_INET && !expander.validate_asns) { sx_report(SX_FATAL, "Sorry, -6 makes no sense with as-path (-f/-G) " "generation\n"); }; + if (expander.validate_asns && expander.generation != T_ASPATH && + expander.generation != T_OASPATH) { + sx_report(SX_FATAL, "Sorry, -w makes sense only for as-path (-f/-G) " + "generation\n"); + }; + if(!argv[0]) usage(1); diff --git a/bgpq3.h b/bgpq3.h index 9becd99..870406d 100644 --- a/bgpq3.h +++ b/bgpq3.h @@ -56,6 +56,7 @@ struct bgpq_expander { int identify; int sequence; int maxdepth; + int validate_asns; unsigned char asn32; unsigned char* asn32s[65536]; struct bgpq_prequest* firstpipe, *lastpipe; diff --git a/bgpq_expander.c b/bgpq_expander.c index cde6f08..a970f04 100644 --- a/bgpq_expander.c +++ b/bgpq_expander.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -380,6 +381,38 @@ bgpq_pipeline(struct bgpq_expander* b, return bp; }; +static void +bgpq_expander_invalidate_asn(struct bgpq_expander* b, const char* q) +{ + if (!strncmp(q, "!gas", 4) || !strncmp(q, "!6as", 4)) { + char* eptr; + unsigned long asn = strtoul(q+4, &eptr, 10), asn0, asn1 = 0; + if (!asn || asn == ULONG_MAX || asn >= 4294967295 || + (eptr && *eptr != '\n' && *eptr != '\r' && *eptr != '.')) { + sx_report(SX_ERROR, "some problem invalidating asn %s\n", q); + return; + }; + if (eptr && (*eptr == '\r' || *eptr == '\n')) { + asn1 = asn; + asn0 = 0; + } else if (eptr && *eptr == '.') { + asn0 = asn; + asn1 = strtoul(eptr+1, &eptr, 10); + }; + if (asn >= 65536) { + asn1 = asn % 65536; + asn0 = asn / 65536; + }; + if (!b->asn32s[asn0] || + !(b->asn32s[asn0][asn1/8] & (0x80 >> (asn1 % 8)))) { + sx_report(SX_NOTICE, "strange, invalidating inactive asn %lu(%s)\n", + asn, q); + } else { + b->asn32s[asn0][asn1/8] &= ~(0x80 >> (asn1 % 8)); + }; + }; +}; + static void bgpq_write(struct bgpq_expander* b) { @@ -561,10 +594,12 @@ have3: } else if(response[0]=='C') { /* No data */ SX_DEBUG(debug_expander,"No data expanding %s\n", req->request); + if (b->validate_asns) bgpq_expander_invalidate_asn(b, req->request); } else if(response[0]=='D') { /* .... */ SX_DEBUG(debug_expander,"Key not found expanding %s\n", req->request); + if (b->validate_asns) bgpq_expander_invalidate_asn(b, req->request); } else if(response[0]=='E') { sx_report(SX_ERROR, "Multiple keys expanding %s: %s\n", req->request, response); @@ -707,8 +742,10 @@ have3: free(recvbuffer); } else if(response[0]=='C') { /* no data */ + if (b->validate_asns) bgpq_expander_invalidate_asn(b, request); } else if(response[0]=='D') { /* ... */ + if (b->validate_asns) bgpq_expander_invalidate_asn(b, request); } else if(response[0]=='E') { /* XXXXXX */ } else if(response[0]=='F') { @@ -831,7 +868,7 @@ bgpq_expand(struct bgpq_expander* b) bgpq_read(b); }; - if(b->generation>=T_PREFIXLIST) { + if(b->generation>=T_PREFIXLIST || b->validate_asns) { unsigned i, j, k; STAILQ_FOREACH(mc, &b->rsets, next) { if(b->family==AF_INET) {