diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c82584 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*\.in +*\.log +*\.o +.deps +.libs diff --git a/README.md b/README.md index c24be18..1491ddc 100644 --- a/README.md +++ b/README.md @@ -27,10 +27,10 @@ The **bgpq4** -utility used to generate configurations (prefix-lists, extended +utility is used to generate configurations (prefix-lists, extended access-lists, policy-statement terms and as-path lists) based on IRR data. -The options are as follows: +It's options are as follows: **-4** @@ -162,7 +162,7 @@ The options are as follows: **-W** *len* -> generate as-path strings of no more than len items (use 0 for inifinity). +> generate as-path strings of no more than len items (use 0 for infinity). **-U** @@ -342,28 +342,70 @@ be in one line (sometimes it makes sense): # NOTES ON SOURCES -By default -*bgpq4* -trusts to data from all databases mirrored into NTT's IRR service. -Unfortunately, not all these databases are equal in how much can we -trust their data. +By default *bgpq4* trusts data from all databases mirrored into NTT's IRR service. +Unfortunately, not all these databases are equal in how much can we trust their +data. RIR maintained databases (AFRINIC, ARIN, APNIC, LACNIC and RIPE) -shall be trusted more than the others because they are indeed have the -knowledge about which address space allocated to this or that ASn, -other databases lack this knowledge and can (and, actually, do) contain -some stale data: noone but RIRs care to remove outdated route-objects -when address space revoked from one ASn and allocated to another. -In order to keep their filters both compact and actual, -*bgpq4 users* -are encouraged to use '-S' flag to limit database sources to only -ones they trust. +shall be trusted more than the others because they have the knowledge about +which address space is allocated to each ASN, other databases lack this +knowledge and can (and actually do) contain some stale data: nobody but RIRs +care to remove outdated route-objects when address space is revoked from one +ASN and allocated to another. In order to keep their filters both compact and +current, *bgpq4 users* are encouraged to use one of two method to limit +database sources to only ones they trust. + +One option is to use the '-S' flag. This limits all queries to a specific data +source. For example, the following command tells IIRd to only use data from +the RIPE RIR DB to build the prefix list for the AS-SET: + + $./bgpq4 -S RIPE AS-VOSTRON + no ip prefix-list NN + ip prefix-list NN permit 89.21.224.0/19 + ip prefix-list NN permit 134.0.64.0/21 + +Be aware though, than an AS-SET may contain members from other data sources. +In this case IRRd won't respond to the bgpq4 query will all the prefixes in the +AS-SET tree. Make sure to use the '-S' flag with all the data sources required +for the AS-SET being expanded: + + $./bgpq4 -S RIPE,ARIN AS-VOSTRON + no ip prefix-list NN + ip prefix-list NN permit 89.21.224.0/19 + ip prefix-list NN permit 134.0.64.0/21 + ip prefix-list NN permit 208.86.232.0/24 + ip prefix-list NN permit 208.86.233.0/24 + ip prefix-list NN permit 208.86.234.0/24 + ip prefix-list NN permit 208.86.235.0/24 + +The other option is to specify a source for an AS-SET or Route Set using the +"::" notation. When bgpq4 detects this, it will look for "::" in the specified +AS-SET or RS on the CLI, and in all members of the AS-SET/RS, and for each +member with a data source specified in "::" format, it will set the IRRd data +source to the given value, query the AS-SET/RS, then reset the data sources back + to the default list for the next object in the tree. + + $./bgpq4 RIPE::AS-VOSTRON + no ip prefix-list NN + ip prefix-list NN permit 89.21.224.0/19 + ip prefix-list NN permit 134.0.64.0/21 + ip prefix-list NN permit 208.86.232.0/22 + ip prefix-list NN permit 208.86.232.0/24 + ip prefix-list NN permit 208.86.233.0/24 + ip prefix-list NN permit 208.86.234.0/24 + ip prefix-list NN permit 208.86.235.0/24 + +In comparison to the '-S' flag, this method return all the prefixes under the +AS-SET, but the root of the tree "AS-VOSTRON" was queries from RIPE only. None +of the member objects used the "::" notation so they were queries from the +default source list (which is all sources). + General recommendations: Use minimal set of RIR databases (only those in which you and your customers have registered route-objects). -Avoid using ARIN-NONAUTH and RIPE-NONAUTH as trusted source: these records +Avoid using ARIN-NONAUTH and RIPE-NONAUTH as trusted sources: these records were created in database but for address space allocated to different RIR, so the NONAUTH databases have no chance to confirm validity of this route object. @@ -380,6 +422,9 @@ object. ip prefix-list NN permit 45.65.184.0/22 [...] +When known, use the "::" notation to speicy the authortative data source for +an AS-SET or RS instead of the -S flag. + # PERFORMANCE To improve \`bgpq4\` performance when expanding extra-large AS-SETs you @@ -430,7 +475,7 @@ In order to create a distribution archive, run: When everything is OK, **bgpq4** generates access-list to standard output and exits with status == 0. -In case of errors they are printed to stderr and program exits with +In case of errors they are printed to stderr and the program exits with non-zero status. # AUTHORS diff --git a/expander.c b/expander.c index 09b33a2..422c3c7 100644 --- a/expander.c +++ b/expander.c @@ -86,6 +86,7 @@ bgpq_expander_init(struct bgpq_expander *b, int af) b->family = af; b->sources = ""; + b->usesource = 0; b->name = "NN"; b->aswidth = 8; b->identify = 1; @@ -152,7 +153,7 @@ bgpq_expander_add_already(struct bgpq_expander *b, char *rs) lkey.text = rs; if (RB_FIND(tentree, &b->already, &lkey)) - return 1; + return 0; le = sx_tentry_new(rs); @@ -169,7 +170,7 @@ bgpq_expander_add_stop(struct bgpq_expander *b, char *rs) lkey.text = rs; if (RB_FIND(tentree, &b->stoplist, &lkey)) - return 1; + return 0; le = sx_tentry_new(rs); @@ -196,11 +197,13 @@ bgpq_expander_add_as(struct bgpq_expander *b, char *as) } if (!expand_special_asn && - ((asno >= 4200000000ul) || (asno >= 64496 && asno <= 65551))) + ((asno >= 4200000000ul) || (asno >= 64496 && asno <= 65551))) { + sx_report(SX_ERROR,"Invalid AS number: %u\n", asno); return 0; + } if ((asne = malloc(sizeof(struct asn_entry))) == NULL) - err(1, NULL); + sx_report(SX_FATAL, "malloc failed for asn\n"); asne->asn = asno; RB_INSERT(asn_tree, &b->asnlist, asne); @@ -240,6 +243,49 @@ bgpq_expander_add_prefix_range(struct bgpq_expander *b, char *prefix) return sx_prefix_range_parse(b->tree, b->family, b->maxlen, prefix); } +char* +bgpq_get_asset(char *object){ + char *asset, *d; + + d = strstr(object, "::"); + if (d){ + d += 2; + } else { + d = object; + } + + if ((asset = calloc(1, 256)) == NULL) + sx_report(SX_FATAL, "calloc failed for asset\n"); + memcpy(asset, d, strlen(object) - (d - object)); + return asset; +} + +char* +bgpq_get_rset(char *object){ + char *d = strstr(object, "::"); + if (d){ + d += 2; + } else { + d = object; + } + + char *rset = (char*)calloc(1, 256); + memcpy(rset, d, strlen(object) - (d - object)); + return rset; +} + +char* +bgpq_get_source(char *object){ + char *d = strstr(object, "::"); + if (d){ + char *source = (char*)calloc(1, 256); + unsigned int slen = d - object; + memcpy(source, object, slen); + return source; + } + return NULL; +} + static int bgpq_expanded_macro(char *as, struct bgpq_expander *ex, struct request *req) @@ -263,6 +309,7 @@ bgpq_expanded_macro_limit(char *as, struct bgpq_expander *b, { if (!strncasecmp(as, "AS-", 3) || strchr(as, '-') || strchr(as, ':')) { struct sx_tentry tkey = { .text = as }; + char *source; if (RB_FIND(tentree, &b->already, &tkey)) { SX_DEBUG(debug_expander > 2, "%s is already expanding, " @@ -281,14 +328,36 @@ bgpq_expanded_macro_limit(char *as, struct bgpq_expander *b, req->depth + 1 < b->maxdepth)) { bgpq_expander_add_already(b, as); if (pipelining) { + if (b->usesource) { + source = bgpq_get_source(as); + if (source){ + bgpq_pipeline(b, NULL, NULL, "!s%s\n", source); + free(source); + } else { + bgpq_pipeline( + b, NULL, NULL, "!s%s\n", b->defaultsources + ); + } + } struct request *req1 = bgpq_pipeline(b, bgpq_expanded_macro_limit, NULL, "!i%s\n", - as); + bgpq_get_asset(as)); req1->depth = req->depth + 1; } else { + if (b->usesource) { + source = bgpq_get_source(as); + if (source) { + bgpq_expand_irrd(b, NULL, NULL, "!s%s\n", source); + free(source); + } else { + bgpq_expand_irrd( + b, NULL, NULL, "!s%s\n", b->defaultsources + ); + } + } b->cdepth++; bgpq_expand_irrd(b, bgpq_expanded_macro_limit, - NULL, "!i%s\n", as); + NULL, "!i%s\n", bgpq_get_asset(as)); b->cdepth--; } } else { @@ -350,6 +419,73 @@ bgpq_expanded_v6prefix(char *prefix, struct bgpq_expander *ex, return 1; } +static char* +bgpq_get_irrd_sources(int fd) { + int ret; + char *query = "!s-lc\n"; + int qlen = strlen(query); + const unsigned int rsize = 256; + char *response = (char*)calloc(1, rsize); + char *sources = (char*)calloc(1, rsize); + + SX_DEBUG(debug_expander, "Requesting source list %s", query); + if ((ret = write(fd, query, strlen(query))) != qlen) { + sx_report(SX_ERROR, "Partial write of query to " + "IRRd: %i bytes, %s\n", ret, strerror(errno)); + close(fd); + free(sources); + free(response); + exit(1); + } + + if (0 < read(fd, response, rsize)) { + SX_DEBUG(debug_expander, "Got answer %s", response); + if (*(response + strlen(response) - 2) != 'C') { + sx_report(SX_ERROR, "Invalid response " + "'%s': %s\n", response, query); + close(fd); + free(sources); + free(response); + exit(1); + } + } else { + sx_report(SX_ERROR, "failed to read sources\n"); + close(fd); + free(sources); + free(response); + exit(1); + } + + char *start = strchr(response, '\n'); + if (start){ + start += 1; + char *end = strchr(start, '\n'); + if (!end) { + sx_report(SX_ERROR, "No 2nd newline in response '%s': %s\n", + response, query); + close(fd); + free(sources); + free(response); + exit(1); + } + unsigned int slen = end - start; + if (slen > rsize) { + memcpy(sources, start, rsize-1); + } else { + memcpy(sources, start, slen); + } + } else { + sx_report(SX_ERROR, "No 1st newline in response '%s': %s\n", + response, query); + close(fd); + free(sources); + free(response); + exit(1); + } + free(response); + return sources; +} + int bgpq_pipeline_dequeue(int fd, struct bgpq_expander *b); static struct request * @@ -385,7 +521,7 @@ bgpq_pipeline(struct bgpq_expander *b, int (*callback)(char *, struct bgpq_expander *, struct request *), void *udata, char *fmt, ...) { - char request[128]; + char request[256]; int ret; struct request *bp = NULL; va_list ap; @@ -402,7 +538,6 @@ bgpq_pipeline(struct bgpq_expander *b, sx_report(SX_FATAL,"Unable to allocate %lu bytes: %s\n", (unsigned long)sizeof(struct request), strerror(errno)); - exit(1); } if (STAILQ_EMPTY(&b->wq)) { @@ -528,6 +663,7 @@ bgpq_read(struct bgpq_expander *b) { static char response[256]; static int off = 0; + int rval = 1; if (!STAILQ_EMPTY(&b->wq)) bgpq_write(b); @@ -666,7 +802,7 @@ bgpq_read(struct bgpq_expander *b) c[spn] = 0; if (c[0] == 0) break; - req->callback(c, b, req); + if (!req->callback(c, b, req)) rval = 0; c += spn + 1; } assert(c == recvbuffer + togot); @@ -674,24 +810,26 @@ bgpq_read(struct bgpq_expander *b) free(recvbuffer); } else if (response[0] == 'C') { /* No data */ - SX_DEBUG(debug_expander,"No data expanding %s\n", + SX_DEBUG(debug_expander,"No data expanding %s", 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", + sx_report(SX_ERROR, "Key not found expanding %s", req->request); if (b->validate_asns) bgpq_expander_invalidate_asn(b, req->request); + rval = 0; } else if (response[0] == 'E') { - sx_report(SX_ERROR, "Multiple keys expanding %s: %s\n", + sx_report(SX_ERROR, "Multiple keys expanding %s: %s", req->request, response); + rval = 0; } else if ( response[0] == 'F') { - sx_report(SX_ERROR, "Error expanding %s: %s\n", + sx_report(SX_ERROR, "Error expanding %s: %s", req->request, response); + rval = 0; } else { - sx_report(SX_ERROR,"Wrong reply: %s to %s\n", response, + sx_report(SX_ERROR,"Wrong reply: %s to %s", response, req->request); exit(1); } @@ -708,7 +846,7 @@ bgpq_read(struct bgpq_expander *b) request_free(req); } - return 0; + return rval; } int @@ -716,11 +854,12 @@ bgpq_expand_irrd(struct bgpq_expander *b, int (*callback)(char *, struct bgpq_expander *, struct request *), void *udata, char *fmt, ...) { - char request[128], response[128]; + char request[256], response[256]; va_list ap; ssize_t ret; int off = 0; struct request *req; + int rval = 1; va_start(ap, fmt); vsnprintf(request, sizeof(request), fmt, ap); @@ -730,8 +869,12 @@ bgpq_expand_irrd(struct bgpq_expander *b, SX_DEBUG(debug_expander, "expander sending: %s", request); - if ((ret = write(b->fd, request, strlen(request)) == 0) || ret == -1) - err(1, "write"); + if ((ret = write(b->fd, request, strlen(request)) == 0) || ret == -1) { + sx_report(SX_ERROR, + "Partial write of request to IRRd: %li bytes, %s\n", + ret, strerror(errno)); + exit(1); + } memset(response, 0, sizeof(response)); @@ -743,7 +886,6 @@ bgpq_expand_irrd(struct bgpq_expander *b, exit(1); } else if (ret == 0) { sx_report(SX_FATAL, "EOF reading IRRd\n"); - exit(1); } off += ret; @@ -808,10 +950,8 @@ bgpq_expand_irrd(struct bgpq_expander *b, if (ret < 0) { sx_report(SX_FATAL, "error reading IRRd: %s\n", strerror(errno)); - exit(1); } else if (ret == 0) { sx_report(SX_FATAL, "eof reading IRRd\n"); - exit(1); } off += ret; @@ -831,7 +971,7 @@ bgpq_expand_irrd(struct bgpq_expander *b, if (c[0] == 0) break; if (callback) - callback(c, b, req); + if (!callback(c, b, req)) rval = 0; c += spn + 1; } memset(recvbuffer, 0, togot + 2); @@ -841,20 +981,24 @@ bgpq_expand_irrd(struct bgpq_expander *b, if (b->validate_asns) bgpq_expander_invalidate_asn(b, request); } else if (response[0] == 'D') { - /* ... */ + sx_report(SX_ERROR, "Key not found expanding %s", + req->request); if (b->validate_asns) bgpq_expander_invalidate_asn(b, request); + rval = 0; } else if (response[0] == 'E') { /* XXXXXX */ } else if (response[0] == 'F') { - /* XXXXXX */ + sx_report(SX_ERROR, "Error expanding %s: %s", + request, response); + rval = 0; } else { - sx_report(SX_ERROR,"Wrong reply: %s\n", response); - exit(0); + sx_report(SX_ERROR,"Wrong reply: %s", response); + exit(1); } request_free(req); - return 0; + return rval; } int @@ -931,6 +1075,7 @@ bgpq_expand(struct bgpq_expander *b) if ((ret = write(fd, "!!\n", 3)) != 3) { sx_report(SX_ERROR, "Partial write of multiple command mode " "to IRRd: %i bytes, %s\n", ret, strerror(errno)); + close(fd); exit(1); } @@ -944,6 +1089,7 @@ bgpq_expand(struct bgpq_expander *b) sx_report(SX_ERROR, "Partial write of " "identifier to IRRd: %i bytes, %s\n", ret, strerror(errno)); + close(fd); exit(1); } memset(ident, 0, sizeof(ident)); @@ -951,10 +1097,12 @@ bgpq_expand(struct bgpq_expander *b) SX_DEBUG(debug_expander, "Got answer %s", ident); } else { sx_report(SX_ERROR, "ident, failed read from IRRd\n"); + close(fd); exit(1); } } else { sx_report(SX_ERROR, "snprintf(ident) failed\n"); + close(fd); exit(1); } } @@ -967,6 +1115,7 @@ bgpq_expand(struct bgpq_expander *b) if ((ret = write(fd, "!a\n", 3)) != 3) { sx_report(SX_ERROR, "Partial write of '!a' test query " "to IRRd: %i bytes, %s\n", ret, strerror(errno)); + close(fd); exit(1); } memset(aret, 0, sizeof(aret)); @@ -979,14 +1128,26 @@ bgpq_expand(struct bgpq_expander *b) } } else { sx_report(SX_ERROR, "A query test failed read from IRRd\n"); + close(fd); exit(1); } } + if (b->usesource) { + if (b->sources && b->sources[0] != 0) { + b->defaultsources = (char*)calloc(1, strlen(b->sources)); + strcpy(b->defaultsources, b->sources); + } else { + b->defaultsources = bgpq_get_irrd_sources(b->fd); + } + } else { + b->defaultsources = bgpq_get_irrd_sources(b->fd); + } + if (b->sources && b->sources[0] != 0) { int slen = strlen(b->sources) + 4; - if (slen < 128) - slen = 128; + if (slen < 256) + slen = 256; char sources[slen]; slen = snprintf(sources, sizeof(sources), "!s%s\n", b->sources); if (slen > 0) { @@ -994,6 +1155,7 @@ bgpq_expand(struct bgpq_expander *b) if ((ret = write(fd, sources, slen)) != slen) { sx_report(SX_ERROR, "Partial write of sources to " "IRRd: %i bytes, %s\n", ret, strerror(errno)); + close(fd); exit(1); } memset(sources, 0, sizeof(sources)); @@ -1002,14 +1164,17 @@ bgpq_expand(struct bgpq_expander *b) if (sources[0] != 'C') { sx_report(SX_ERROR, "Invalid source(s) " "'%s': %s\n", b->sources, sources); + close(fd); exit(1); } } else { sx_report(SX_ERROR, "failed to read sources\n"); + close(fd); exit(1); } } else { sx_report(SX_ERROR, "snprintf(sources) failed\n"); + close(fd); exit(1); } } @@ -1019,25 +1184,57 @@ bgpq_expand(struct bgpq_expander *b) STAILQ_FOREACH(mc, &b->macroses, entry) { if (!b->maxdepth && RB_EMPTY(&b->stoplist)) { - if (aquery) + if (b->usesource) { + char *source = bgpq_get_source(mc->text); + if (source){ + if (pipelining){ + bgpq_pipeline(b, NULL, NULL, "!s%s\n", source); + bgpq_pipeline(b, bgpq_expanded_macro_limit, b, + "!i%s\n", bgpq_get_asset(mc->text)); + } else { + bgpq_expand_irrd(b, NULL, NULL, "!s%s\n", source); + bgpq_expand_irrd(b, bgpq_expanded_macro_limit, + b, "!i%s\n", bgpq_get_asset(mc->text)); + } + free(source); + } else { + if (pipelining){ + bgpq_pipeline(b, NULL, NULL, "!s%s\n", + b->defaultsources); + bgpq_pipeline(b, bgpq_expanded_macro_limit, b, + "!i%s\n", bgpq_get_asset(mc->text)); + } else { + bgpq_expand_irrd(b, NULL, NULL, "!s%s\n", + b->defaultsources); + bgpq_expand_irrd(b, bgpq_expanded_macro_limit, b, + "!i%s\n", bgpq_get_asset(mc->text)); + } + } + } else if (aquery) bgpq_expand_irrd(b, bgpq_expanded_prefix, b, "!a%s%s\n", b->family == AF_INET ? "4" : "6", - mc->text); + bgpq_get_asset(mc->text)); else bgpq_expand_irrd(b, bgpq_expanded_macro, b, - "!i%s,1\n", mc->text); + "!i%s,1\n", bgpq_get_asset(mc->text)); } else { - bgpq_expander_add_already(b, mc->text); + bgpq_expander_add_already(b, bgpq_get_asset(mc->text)); if (pipelining) bgpq_pipeline(b, bgpq_expanded_macro_limit, - NULL, "!i%s\n", mc->text); + NULL, "!i%s\n", bgpq_get_asset(mc->text)); else bgpq_expand_irrd(b, bgpq_expanded_macro_limit, - NULL, "!i%s\n", mc->text); + NULL, "!i%s\n", bgpq_get_asset(mc->text)); } } + if (pipelining){ + bgpq_pipeline(b, NULL, NULL, "!s%s\n", b->defaultsources); + } else { + bgpq_expand_irrd(b, NULL, NULL, "!s%s\n", b->defaultsources); + } + if (pipelining) { if (!STAILQ_EMPTY(&b->wq)) bgpq_write(b); @@ -1047,12 +1244,70 @@ bgpq_expand(struct bgpq_expander *b) if (b->generation >= T_PREFIXLIST || b->validate_asns) { STAILQ_FOREACH(mc, &b->rsets, entry) { - if (b->family == AF_INET) - bgpq_expand_irrd(b, bgpq_expanded_prefix, - NULL, "!i%s,1\n", mc->text); - else - bgpq_expand_irrd(b, bgpq_expanded_v6prefix, - NULL, "!i%s,1\n", mc->text); + if (b->usesource) { + char *source = bgpq_get_source(mc->text); + if (source){ + if (pipelining){ + printf("Checking %s\n", bgpq_get_rset(mc->text)); + bgpq_pipeline(b, NULL, NULL, "!s%s\n", source); + if (b->family == AF_INET) + bgpq_pipeline(b, bgpq_expanded_prefix, + NULL, "!i%s\n", bgpq_get_rset(mc->text)); + else + bgpq_pipeline(b, bgpq_expanded_v6prefix, + NULL, "!i%s\n", bgpq_get_rset(mc->text)); + } else { + bgpq_expand_irrd(b, NULL, NULL, "!s%s\n", source); + if (b->family == AF_INET) + bgpq_expand_irrd(b, bgpq_expanded_prefix, + NULL, "!i%s\n", bgpq_get_rset(mc->text)); + else + bgpq_expand_irrd(b, bgpq_expanded_v6prefix, + NULL, "!i%s\n", bgpq_get_rset(mc->text)); + } + free(source); + } else { + if (pipelining){ + bgpq_pipeline(b, NULL, NULL, "!s%s\n", + b->defaultsources); + if (b->family == AF_INET) + bgpq_pipeline(b, bgpq_expanded_prefix, + NULL, "!i%s\n", bgpq_get_rset(mc->text)); + else + bgpq_pipeline(b, bgpq_expanded_v6prefix, + NULL, "!i%s\n", bgpq_get_rset(mc->text)); + } else { + bgpq_expand_irrd(b, NULL, NULL, "!s%s\n", + b->defaultsources); + if (b->family == AF_INET) + bgpq_expand_irrd(b, bgpq_expanded_prefix, + NULL, "!i%s\n", bgpq_get_rset(mc->text)); + else + bgpq_expand_irrd(b, bgpq_expanded_v6prefix, + NULL, "!i%s\n", bgpq_get_rset(mc->text)); + } + } + } else { + if (pipelining){ + bgpq_pipeline(b, NULL, NULL, "!s%s\n", + b->defaultsources); + if (b->family == AF_INET) + bgpq_pipeline(b, bgpq_expanded_prefix, + NULL, "!i%s,1\n", bgpq_get_rset(mc->text)); + else + bgpq_pipeline(b, bgpq_expanded_v6prefix, + NULL, "!i%s,1\n", bgpq_get_rset(mc->text)); + } else { + bgpq_expand_irrd(b, NULL, NULL, "!s%s\n", + b->defaultsources); + if (b->family == AF_INET) + bgpq_expand_irrd(b, bgpq_expanded_prefix, + NULL, "!i%s,1\n", bgpq_get_rset(mc->text)); + else + bgpq_expand_irrd(b, bgpq_expanded_v6prefix, + NULL, "!i%s,1\n", bgpq_get_rset(mc->text)); + } + } } RB_FOREACH(asne, asn_tree, &b->asnlist) { @@ -1094,6 +1349,7 @@ bgpq_expand(struct bgpq_expander *b) fcntl(fd, F_SETFL, fl); } close(fd); + free(b->defaultsources); return 1; } diff --git a/extern.h b/extern.h index d75a76e..b729df7 100644 --- a/extern.h +++ b/extern.h @@ -91,6 +91,8 @@ struct bgpq_expander { struct sx_radix_tree *tree; int family; char *sources; + char *defaultsources; + unsigned int usesource; uint32_t asnumber; int aswidth; char *name; @@ -126,6 +128,10 @@ int bgpq_expander_add_prefix(struct bgpq_expander *b, char *prefix); int bgpq_expander_add_prefix_range(struct bgpq_expander *b, char *prefix); int bgpq_expander_add_stop(struct bgpq_expander *b, char *object); +char* bgpq_get_asset(char *object); +char* bgpq_get_rset(char *object); +char* bgpq_get_source(char *object); + int bgpq_expand(struct bgpq_expander *b); void bgpq4_print_prefixlist(FILE *f, struct bgpq_expander *b); diff --git a/main.c b/main.c index d7b9aa5..8d96266 100644 --- a/main.c +++ b/main.c @@ -190,7 +190,7 @@ main(int argc, char* argv[]) exit(1); } #endif - + bgpq_expander_init(&expander, af); if (getenv("IRRD_SOURCES")) @@ -694,17 +694,23 @@ main(int argc, char* argv[]) usage(1); while (argv[0]) { + char *obj = argv[0]; + char *delim = strstr(argv[0], "::"); + if (delim) { + expander.usesource = 1; + obj = delim + 2; + } if (!strcmp(argv[0], "EXCEPT")) { exceptmode = 1; } else if (exceptmode) { bgpq_expander_add_stop(&expander, argv[0]); - } else if (!strncasecmp(argv[0], "AS-", 3)) { + } else if (!strncasecmp(obj, "AS-", 3)) { bgpq_expander_add_asset(&expander, argv[0]); - } else if (!strncasecmp(argv[0], "RS-", 3)) { + } else if (!strncasecmp(obj, "RS-", 3)) { bgpq_expander_add_rset(&expander, argv[0]); - } else if (!strncasecmp(argv[0], "AS", 2)) { + } else if (!strncasecmp(obj, "AS", 2)) { char *ec; - if ((ec = strchr(argv[0], ':'))) { + if ((ec = strchr(obj, ':'))) { if (!strncasecmp(ec + 1, "AS-", 3)) { bgpq_expander_add_asset(&expander, argv[0]); } else if (!strncasecmp(ec + 1, "RS-", 3)) {