diff --git a/README.md b/README.md index b00b54e..ef8f6fa 100644 --- a/README.md +++ b/README.md @@ -290,6 +290,7 @@ example below: ipfw add pass all from 193.193.192.0/19 to any Recognized format characters: '%n' - network, '%l' - mask length, +'%a' - aggregate low mask length, '%A' - aggregate high mask length, '%N' - object name, '%m' - object mask and '%i' - inversed mask. Recognized escape characters: '\n' - new line, '\t' - tabulation. Please note that no new lines inserted automatically after each sentence, diff --git a/bgpq4.8 b/bgpq4.8 index 2ef891b..801bc86 100644 --- a/bgpq4.8 +++ b/bgpq4.8 @@ -251,6 +251,7 @@ ipfw add pass all from 193.193.192.0/19 to any .fi .Pp Recognized format characters: %n - network, %l - mask length, +%a - aggregate low mask length, %A - aggregate high mask length, %N - object name, %m - object mask and %i - inversed mask. Recognized escape characters: \\n - new line, \\t - tabulation. Please note that no new lines inserted automatically after each sentence, diff --git a/bgpq4.c b/bgpq4.c index 7a3605b..a1bfdeb 100644 --- a/bgpq4.c +++ b/bgpq4.c @@ -459,12 +459,6 @@ main(int argc, char* argv[]) sx_report(SX_FATAL, "Sorry, only prefix-lists supported in formatted " "output\n"); - if (expander.vendor == V_FORMAT && (refine || refineLow)) { - sx_report(SX_FATAL, "Sorry, formatted output (-F ) in not " - "compatible with -R/-r options\n"); - exit(1); - } - if (expander.vendor == V_HUAWEI && expander.generation != T_ASPATH && expander.generation != T_OASPATH && expander.generation != T_PREFIXLIST) sx_report(SX_FATAL, "Sorry, only as-paths and prefix-lists supported " @@ -486,12 +480,6 @@ main(int argc, char* argv[]) exit(1); } - if(aggregate && expander.vendor == V_FORMAT) { - sx_report(SX_FATAL, "Sorry, aggregation (-A) is not compatible with " - "formatted output (-F )\n"); - exit(1); - } - if (aggregate && (expander.vendor == V_NOKIA_MD || expander.vendor == V_NOKIA) && expander.generation != T_PREFIXLIST) { sx_report(SX_FATAL, "Sorry, aggregation (-A) is not supported with " diff --git a/bgpq4_printer.c b/bgpq4_printer.c index fd9dda0..f863f33 100644 --- a/bgpq4_printer.c +++ b/bgpq4_printer.c @@ -1633,24 +1633,39 @@ struct fpcbdata { void bgpq4_print_format_prefix(struct sx_radix_node* n, void* ff) { - char prefix[128]; struct fpcbdata* fpc = (struct fpcbdata*)ff; FILE* f = fpc->f; struct bgpq_expander* b = fpc->b; if (n->isGlue) - return; + goto checkSon; if (!f) f = stdout; - memset(prefix, 0, sizeof(prefix)); + if (!n->isAggregate) { + sx_prefix_snprintf_fmt(n->prefix, f, + b->name ? b->name : "NN", + b->format, + n->prefix->masklen, + n->prefix->masklen); + } else if (n->aggregateLow > n->prefix->masklen) { + sx_prefix_snprintf_fmt(n->prefix, f, + b->name ? b->name : "NN", + b->format, + n->aggregateLow, + n->aggregateHi); + } else { + sx_prefix_snprintf_fmt(n->prefix, f, + b->name ? b->name : "NN", + b->format, + n->prefix->masklen, + n->aggregateHi); + } - sx_prefix_snprintf_fmt(n->prefix, prefix, sizeof(prefix), - b->name ? b->name : "NN", - b->format); - - fprintf(f, "%s", prefix); +checkSon: + if (n->son) + bgpq4_print_format_prefix(n->son, ff); } @@ -1658,10 +1673,13 @@ int bgpq4_print_format_prefixlist(FILE* f, struct bgpq_expander* b) { struct fpcbdata ff = {.f=f, .b=b}; + int len = strlen(b->format); sx_radix_tree_foreach(b->tree, bgpq4_print_format_prefix, &ff); - if (strcmp(b->format + strlen(b->format - 2), "\n")) + // Add newline if format doesn't already end with one. + if (len < 2 || + !(b->format[len-2] == '\\' && b->format[len-1] == 'n')) fprintf(f, "\n"); return 0; diff --git a/bgpq_expander.c b/bgpq_expander.c index 175748c..eee41e5 100644 --- a/bgpq_expander.c +++ b/bgpq_expander.c @@ -914,7 +914,7 @@ bgpq_expand(struct bgpq_expander* b) SX_DEBUG(debug_expander, "Sending '!!' to server to request for the" "connection to remain open\n"); if ((ret = write(fd, "!!\n", 3)) != 3) { - sx_report(SX_ERROR,"Partial write to IRRd: %i bytes, %s\n", + sx_report(SX_ERROR, "Partial write of multiple command mode to IRRd: %i bytes, %s\n", ret, strerror(errno)); exit(1); } @@ -923,24 +923,48 @@ bgpq_expand(struct bgpq_expander* b) SX_DEBUG(debug_expander, "b->identify: Sending '!n " PACKAGE_STRING "' to server.\n"); char ident[128]; - snprintf(ident, sizeof(ident), "!n" PACKAGE_STRING "\n"); - write(fd, ident, strlen(ident)); - read(fd, ident, sizeof(ident)); + int ilen = snprintf(ident, sizeof(ident), "!n" PACKAGE_STRING "\n"); + if (ilen > 0) { + if ((ret = write(fd, ident, ilen)) != ilen) { + sx_report(SX_ERROR, "Partial write of identifier to IRRd: %i bytes, %s\n", + ret, strerror(errno)); + exit(1); + } + memset(ident, 0, sizeof(ident)); + if (0 < read(fd, ident, sizeof(ident))) { + SX_DEBUG(debug_expander, "Got answer %s", ident); + } else { + sx_report(SX_ERROR, "ident - failed read from IRRd\n"); + exit(1); + } + } else { + sx_report(SX_ERROR, "snprintf(ident) failed\n"); + exit(1); + } } /* Test whether the server has support for the A query */ - if (b->generation >= T_PREFIXLIST) { + if (b->generation >= T_PREFIXLIST && !STAILQ_EMPTY(&b->macroses)) { char aret[128]; char aresp[] = "F Missing required set name for A query"; SX_DEBUG(debug_expander, "Testing support for A queries\n"); - write(fd, "!a\n", 3); + 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)); + exit(1); + } memset(aret, 0, sizeof(aret)); - read(fd, aret, sizeof(aret)); - if (strncmp(aret, aresp, strlen(aresp)) == 0) { - SX_DEBUG(debug_expander, "Server supports A query\n"); - aquery = 1; - } else - SX_DEBUG(debug_expander, "No support for A queries\n"); + if (0 < read(fd, aret, sizeof(aret))) { + if (strncmp(aret, aresp, strlen(aresp)) == 0) { + SX_DEBUG(debug_expander, "Server supports A query\n"); + aquery = 1; + } else { + SX_DEBUG(debug_expander, "No support for A queries\n"); + } + } else { + sx_report(SX_ERROR, "'!a' query test - failed read from IRRd\n"); + exit(1); + } } if (b->sources && b->sources[0] != 0) { @@ -948,15 +972,28 @@ bgpq_expand(struct bgpq_expander* b) if (slen < 128) slen = 128; char sources[slen]; - snprintf(sources, sizeof(sources), "!s%s\n", b->sources); - SX_DEBUG(debug_expander, "Requesting sources %s", sources); - write(fd, sources, strlen(sources)); - memset(sources, 0, slen); - read(fd, sources, slen); - SX_DEBUG(debug_expander,"Got answer %s", sources); - if (sources[0] != 'C') { - sx_report(SX_ERROR, "Invalid source(s) '%s': %s\n", - b->sources, sources); + slen = snprintf(sources, sizeof(sources), "!s%s\n", b->sources); + if (slen > 0) { + SX_DEBUG(debug_expander, "Requesting sources %s", sources); + if ((ret = write(fd, sources, slen)) != slen) { + sx_report(SX_ERROR, "Partial write of sources to IRRd: %i bytes, %s\n", + ret, strerror(errno)); + exit(1); + } + memset(sources, 0, sizeof(sources)); + if (0 < read(fd, sources, sizeof(sources))) { + SX_DEBUG(debug_expander, "Got answer %s", sources); + if (sources[0] != 'C') { + sx_report(SX_ERROR, "Invalid source(s) '%s': %s\n", + b->sources, sources); + exit(1); + } + } else { + sx_report(SX_ERROR, "sources - failed read from IRRd\n"); + exit(1); + } + } else { + sx_report(SX_ERROR, "snprintf(sources) failed\n"); exit(1); } } @@ -1037,7 +1074,11 @@ bgpq_expand(struct bgpq_expander* b) } } - write(fd, "!q\n",3); + if ((ret = write(fd, "!q\n", 3)) != 3) { + sx_report(SX_ERROR, "Partial write of quit to IRRd: %i bytes, %s\n", + ret, strerror(errno)); + // not worth exiting due to this + } if (pipelining) { int fl = fcntl(fd, F_GETFL); fl &= ~O_NONBLOCK; diff --git a/sx_prefix.c b/sx_prefix.c index b59440c..3f09b35 100644 --- a/sx_prefix.c +++ b/sx_prefix.c @@ -399,74 +399,88 @@ sx_prefix_snprintf(struct sx_prefix* p, char* rbuffer, int srb) return sx_prefix_snprintf_sep(p, rbuffer, srb, "/"); } -int -sx_prefix_snprintf_fmt(struct sx_prefix* p, char* buffer, int size, - const char* name, const char* format) +void +sx_prefix_snprintf_fmt(struct sx_prefix* p, FILE* f, + const char* name, const char* format, + unsigned int aggregateLow, unsigned int aggregateHi) { unsigned off = 0; const char* c = format; struct sx_prefix *q = sx_prefix_alloc(NULL); + char prefix[128]; while (*c) { if(*c == '%') { switch (*(c + 1)) { case 'r': case 'n': - inet_ntop(p->family, &p->addr, buffer+off, size-off); - off = strlen(buffer); + if (NULL != inet_ntop(p->family, &p->addr, prefix, sizeof(prefix))) { + fprintf(f, "%s", prefix); + } else { + sx_report(SX_ERROR, "inet_ntop failed\n"); + return; + } break; case 'l': - off += snprintf(buffer + off, size - off, - "%i", p->masklen); + fprintf(f, "%i", p->masklen); + break; + case 'a': + fprintf(f, "%u", aggregateLow); + break; + case 'A': + fprintf(f, "%u", aggregateHi); break; case '%': - buffer[off++] = '%'; + fprintf(f, "%%"); break; case 'N': - off += snprintf(buffer + off, size - off, - "%s", name); + fprintf(f, "%s", name); break; case 'm': sx_prefix_mask(p, q); - inet_ntop(p->family, &q->addr, buffer + off, - size - off); - off = strlen(buffer); + if (NULL != inet_ntop(p->family, &q->addr, prefix, sizeof(prefix))) { + fprintf(f, "%s", prefix); + } else { + sx_report(SX_ERROR, "inet_ntop failed\n"); + return; + } break; case 'i': sx_prefix_imask(p, q); - inet_ntop(p->family, &q->addr, buffer + off, - size - off); - off = strlen(buffer); + if (NULL != inet_ntop(p->family, &q->addr, prefix, sizeof(prefix))) { + fprintf(f, "%s", prefix); + } else { + sx_report(SX_ERROR, "inet_ntop failed\n"); + return; + } break; default : sx_report(SX_ERROR, "Unknown format char " "'%c'\n", *(c + 1)); - return 0; + return; } c += 2; } else if (*c == '\\') { switch(*(c+1)) { case 'n': - buffer[off++] = '\n'; + fprintf(f, "\n"); break; case 't': - buffer[off++] = '\t'; + fprintf(f, "\t"); break; case '\\': - buffer[off++] = '\\'; + fprintf(f, "\\"); break; default: - buffer[off++] = *(c + 1); + fprintf(f, "%c", *(c + 1)); break; } c += 2; } else { - buffer[off++] = *c; + fprintf(f, "%c", *c); c++; } } - - return strlen(buffer); } int diff --git a/sx_prefix.h b/sx_prefix.h index b7133e6..507317d 100644 --- a/sx_prefix.h +++ b/sx_prefix.h @@ -51,8 +51,9 @@ int sx_prefix_range_parse(struct sx_radix_tree* t, int af, int ml, char* text); int sx_prefix_fprint(FILE* f, struct sx_prefix* p); int sx_prefix_snprintf(struct sx_prefix* p, char* rbuffer, int srb); int sx_prefix_snprintf_sep(struct sx_prefix* p, char* rbuffer, int srb, char*); -int sx_prefix_snprintf_fmt(struct sx_prefix* p, char* rbuffer, int srb, - const char* name, const char* fmt); +void sx_prefix_snprintf_fmt(struct sx_prefix* p, FILE* f, + const char* name, const char* fmt, + unsigned int aggregateLow, unsigned int aggregateHi); int sx_prefix_jsnprintf(struct sx_prefix* p, char* rbuffer, int srb); struct sx_radix_tree* sx_radix_tree_new(int af); struct sx_radix_node* sx_radix_node_new(struct sx_prefix* prefix);