diff --git a/CHANGES b/CHANGES index 5410bc4..58bf033 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,10 @@ +0.1.5 (2008-06-02): + - route-set's expansion added. Fully functional for IPv4 prefixes, but + not for IPv6 - only those prefixes explicitely marked as 'member-of: RS..' + will be expanded. This is due to limitation in IRRd. + - extended access-lists (Cisco) and route-filters (Juniper) generation + is supported now with new -E key. + 0.1.4 (2008-05-30): - bugfix for juniper as-path group generation. Thanks to Alexander Shikoff. diff --git a/Makefile.in b/Makefile.in index 41b3cea..dd314ff 100644 --- a/Makefile.in +++ b/Makefile.in @@ -23,6 +23,7 @@ clean: install: bgpq3 ${INSTALL} -c -s -m 755 bgpq3 @prefix@@bindir@ + ${INSTALL} -m 644 bgpq3.8 @prefix@@mandir@/man8 depend: makedepend -- $(CFLAGS) -- $(SRCS) diff --git a/bgpq3.8 b/bgpq3.8 new file mode 100644 index 0000000..bec4e24 --- /dev/null +++ b/bgpq3.8 @@ -0,0 +1,38 @@ +.Dd June 2, 2008 +.Dt BGPQ3 8 +.Sh NAME +.Nm bgpq3 +.Nd bgp filtering automation for cisco and juniper routers +.Sh SYNOPSIS +.Nm bgpq3 +.Op Fl h +.Op Fl S Ar sources +.Oo +.Fl E | +.Fl f Ar asnumber | +.Fl G Ar asnumber | +.Fl P +.Oc +.Oo +.Fl 3 +.Fl 6 +.Fl A +.Oc +.Op Fl R Ar len +OBJECTS +.Op "..." +.Sh DESCRIPTION +The +.Nm +ultility used to generate Cisco and Juniper prefix-lists, extended +access-lists, policy-statements and as-path lists based on RADB data. +.Pp +The options are as follows: +.Sh DIAGNOSTICS +When everyting is ok, +.Nm +generates access-list to standard output and exits with status == 0. +In case of errors they are printed to stderr and program exits with +non-zero status. +.Sh AUTHOR +Alexandre Snarskii, diff --git a/bgpq3.c b/bgpq3.c index 56d687f..d19a384 100644 --- a/bgpq3.c +++ b/bgpq3.c @@ -23,13 +23,15 @@ extern int pipelining; int usage(int ecode) { - printf("\nUsage: bgpq3 [-h] [-S sources] [-P|G |f ] [-36A]" + printf("\nUsage: bgpq3 [-h] [-S sources] [-P|E|G |f ] [-36A]" " [-R len] ...\n"); printf(" -3 : assume that your device is asn32-safe\n"); printf(" -6 : generate IPv6 prefix-lists (IPv4 by default)\n"); printf(" -A : try to aggregate prefix-lists as much as possible" " (Cisco only)\n"); printf(" -d : generate some debugging output\n"); + printf(" -E : generate extended access-list(Cisco) or " + "route-filter(Juniper)\n"); printf(" -f number : generate input as-path access-list\n"); printf(" -G number : generate output as-path access-list\n"); printf(" -h : this help\n"); @@ -49,7 +51,8 @@ usage(int ecode) void exclusive() { - fprintf(stderr,"-f , -G and -P are mutually exclusive\n"); + fprintf(stderr,"-E, -f , -G and -P are mutually " + "exclusive\n"); exit(1); }; @@ -99,7 +102,7 @@ main(int argc, char* argv[]) bgpq_expander_init(&expander,af); expander.sources=getenv("IRRD_SOURCES"); - while((c=getopt(argc,argv,"36AdhS:Jf:l:W:PR:G:T"))!=EOF) { + while((c=getopt(argc,argv,"36AdEhS:Jf:l:W:PR:G:T"))!=EOF) { switch(c) { case '3': expander.asn32=1; @@ -114,6 +117,9 @@ main(int argc, char* argv[]) break; case 'd': debug_expander++; break; + case 'E': if(expander.generation) exclusive(); + expander.generation=T_EACL; + break; case 'J': expander.vendor=V_JUNIPER; break; case 'f': @@ -187,14 +193,15 @@ main(int argc, char* argv[]) expander.asnumber=23456; }; - if(aggregate && expander.vendor==V_JUNIPER) { + if(aggregate && expander.vendor==V_JUNIPER && + expander.generation==T_PREFIXLIST) { sx_report(SX_FATAL, "Sorry, aggregation (-A) does not work in" " Juniper prefix-lists\n"); exit(1); }; if(aggregate && expander.generation #include +#include +#include #include "bgpq3.h" #include "sx_report.h" @@ -195,6 +197,30 @@ bgpq3_print_jprefix(struct sx_radix_node* n, void* ff) fprintf(f," %s;\n",prefix); }; +void +bgpq3_print_jrfilter(struct sx_radix_node* n, void* ff) +{ + char prefix[128]; + FILE* f=(FILE*)ff; + if(n->isGlue) goto checkSon; + if(!f) f=stdout; + sx_prefix_snprintf(&n->prefix,prefix,sizeof(prefix)); + if(!n->isAggregate) { + fprintf(f," route-filter %s exact;\n", prefix); + } else { + if(n->aggregateLow>n->prefix.masklen) { + fprintf(f," route-filter %s prefix-length-range /%u-/%u;\n", + prefix,n->aggregateLow,n->aggregateHi); + } else { + fprintf(f," route-filter %s upto /%u;\n", prefix,n->aggregateHi); + }; + }; +checkSon: + if(n->son) + bgpq3_print_jrfilter(n->son, ff); +}; + + static char* bname=NULL; void @@ -224,6 +250,70 @@ checkSon: bgpq3_print_cprefix(n->son,ff); }; +void +bgpq3_print_ceacl(struct sx_radix_node* n, void* ff) +{ + char prefix[128]; + FILE* f=(FILE*)ff; + char* c; + uint32_t netmask=0xfffffffful; + if(!f) f=stdout; + if(n->isGlue) goto checkSon; + sx_prefix_snprintf(&n->prefix,prefix,sizeof(prefix)); + c=strchr(prefix,'/'); + if(c) *c=0; + + if(n->prefix.masklen==32) { + netmask=0; + } else { + netmask<<=(32-n->prefix.masklen); + }; + netmask=htonl(netmask); + + if(n->isAggregate) { + unsigned long mask=0xfffffffful, wildaddr, wild2addr, wildmask; + int masklen=n->aggregateLow; + wildaddr=0xfffffffful>>n->prefix.masklen; + if(n->aggregateHi==32) { + wild2addr=0; + } else { + wild2addr=0xfffffffful>>n->aggregateHi; + }; + wildaddr=wildaddr&(~wild2addr); + + if(masklen==32) mask=0xfffffffful; + else mask=0xfffffffful<<(32-masklen); + + if(n->aggregateHi==32) wild2addr=0; + else wild2addr=0xfffffffful>>n->aggregateHi; + wildmask=(0xfffffffful>>n->aggregateLow)&(~wild2addr); + + mask=htonl(mask); + wildaddr=htonl(wildaddr); + wildmask=htonl(wildmask); + + if(wildaddr) { + fprintf(f," permit ip %s ", inet_ntoa(n->prefix.addr.addr)); + fprintf(f,"%s ", inet_ntoa(*(struct in_addr*)&wildaddr)); + } else { + fprintf(f," permit ip host %s ",inet_ntoa(n->prefix.addr.addr)); + }; + + if(wildmask) { + fprintf(f,"%s ", inet_ntoa(*(struct in_addr*)&mask)); + fprintf(f,"%s\n", inet_ntoa(*(struct in_addr*)&wildmask)); + } else { + fprintf(f,"host %s\n", inet_ntoa(*(struct in_addr*)&mask)); + }; + } else { + fprintf(f," permit ip host %s host %s\n",prefix, + inet_ntoa(*(struct in_addr*)&netmask)); + }; +checkSon: + if(n->son) + bgpq3_print_ceacl(n->son,ff); +}; + int bgpq3_print_juniper_prefixlist(FILE* f, struct bgpq_expander* b) { @@ -234,6 +324,27 @@ bgpq3_print_juniper_prefixlist(FILE* f, struct bgpq_expander* b) return 0; }; +int +bgpq3_print_juniper_routefilter(FILE* f, struct bgpq_expander* b) +{ + char* c; + if(b->name && (c=strchr(b->name,'/'))) { + *c=0; + fprintf(f,"policy-options {\n policy-statement %s {\n term %s {\n" + "replace:\n from {\n protocol bgp;\n", b->name, c+1); + } else { + fprintf(f,"policy-options {\n policy-statement %s { \n" + "replace:\n from {\n protocol bgp;\n", b->name?b->name:"NN"); + }; + sx_radix_tree_foreach(b->tree,bgpq3_print_jrfilter,f); + if(c) { + fprintf(f, " }\n }\n }\n}\n"); + } else { + fprintf(f, " }\n }\n}\n"); + }; + return 0; +}; + int bgpq3_print_cisco_prefixlist(FILE* f, struct bgpq_expander* b) { @@ -244,6 +355,16 @@ bgpq3_print_cisco_prefixlist(FILE* f, struct bgpq_expander* b) return 0; }; +int +bgpq3_print_cisco_eacl(FILE* f, struct bgpq_expander* b) +{ + bname=b->name; + fprintf(f,"no ip access-list extended %s\n", bname?bname:"NN"); + fprintf(f,"ip access-list extended %s\n", bname?bname:"NN"); + sx_radix_tree_foreach(b->tree,bgpq3_print_ceacl,f); + return 0; +}; + int bgpq3_print_prefixlist(FILE* f, struct bgpq_expander* b) { @@ -253,3 +374,13 @@ bgpq3_print_prefixlist(FILE* f, struct bgpq_expander* b) }; return 0; }; + +int +bgpq3_print_eacl(FILE* f, struct bgpq_expander* b) +{ + switch(b->vendor) { + case V_JUNIPER: return bgpq3_print_juniper_routefilter(f,b); + case V_CISCO: return bgpq3_print_cisco_eacl(f,b); + }; + return 0; +}; diff --git a/bgpq_expander.c b/bgpq_expander.c index 2cfa3c8..ab020d4 100644 --- a/bgpq_expander.c +++ b/bgpq_expander.c @@ -69,6 +69,23 @@ bgpq_expander_add_asset(struct bgpq_expander* b, char* as) return 1; }; +int +bgpq_expander_add_rset(struct bgpq_expander* b, char* rs) +{ + struct sx_slentry* le; + if(!b || !rs) return 0; + le=sx_slentry_new(rs); + if(!le) return 0; + if(!b->rsets) { + b->rsets=le; + } else { + struct sx_slentry* ln=b->rsets; + while(ln->next) ln=ln->next; + ln->next=le; + }; + return 1; +}; + int bgpq_expander_add_as(struct bgpq_expander* b, char* as) { @@ -127,9 +144,13 @@ int bgpq_expander_add_prefix(struct bgpq_expander* b, char* prefix) { struct sx_prefix p; - if(!sx_prefix_parse(&p,b->family,prefix)) { + if(!sx_prefix_parse(&p,0,prefix)) { sx_report(SX_ERROR,"Unable to parse prefix %s\n", prefix); return 0; + } else if(p.family!=b->family) { + SX_DEBUG(debug_expander,"Ignoring prefix %s with wrong address family\n" + ,prefix); + return 0; }; sx_radix_tree_insert(b->tree,&p); return 1; @@ -612,6 +633,19 @@ bgpq_expand(struct bgpq_expander* b) }; if(b->generation>=T_PREFIXLIST) { unsigned i, j, k; + for(mc=b->rsets;mc;mc=mc->next) { + if(b->family==AF_INET) { + bgpq_expand_radb(f,bgpq_expanded_prefix,b,"!i%s,1\n",mc->text); + } else { + if(!pipelining) { + bgpq_expand_ripe(f,bgpq_expanded_v6prefix,b, + "-T route6 -i member-of %s\n",mc->text); + } else { + bgpq_pipeline(f,bgpq_expanded_v6prefix,b, + "-T route6 -i member-of %s\n", mc->text); + }; + }; + }; for(k=0;kasn32s)/sizeof(unsigned char*);k++) { if(!b->asn32s[k]) continue; for(i=0;i<8192;i++) { @@ -656,7 +690,7 @@ bgpq_expand(struct bgpq_expander* b) }; }; }; - if(pipelining) { + if(pipelining && b->firstpipe) { if(b->family==AF_INET6) { bgpq_pipeline_dequeue_ripe(f,b); } else { diff --git a/configure b/configure index 82207a6..bcb97dd 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.59 for bgpq3 0.1.4. +# Generated by GNU Autoconf 2.59 for bgpq3 0.1.5. # # Report bugs to . # @@ -269,8 +269,8 @@ SHELL=${CONFIG_SHELL-/bin/sh} # Identity of this package. PACKAGE_NAME='bgpq3' PACKAGE_TARNAME='bgpq3' -PACKAGE_VERSION='0.1.4' -PACKAGE_STRING='bgpq3 0.1.4' +PACKAGE_VERSION='0.1.5' +PACKAGE_STRING='bgpq3 0.1.5' PACKAGE_BUGREPORT='snar@paranoia.ru' ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LIBOBJS LTLIBOBJS' @@ -738,7 +738,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures bgpq3 0.1.4 to adapt to many kinds of systems. +\`configure' configures bgpq3 0.1.5 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -795,7 +795,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of bgpq3 0.1.4:";; + short | recursive ) echo "Configuration of bgpq3 0.1.5:";; esac cat <<\_ACEOF @@ -906,7 +906,7 @@ fi test -n "$ac_init_help" && exit 0 if $ac_init_version; then cat <<\_ACEOF -bgpq3 configure 0.1.4 +bgpq3 configure 0.1.5 generated by GNU Autoconf 2.59 Copyright (C) 2003 Free Software Foundation, Inc. @@ -920,7 +920,7 @@ cat >&5 <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by bgpq3 $as_me 0.1.4, which was +It was created by bgpq3 $as_me 0.1.5, which was generated by GNU Autoconf 2.59. Invocation command line was $ $0 $@ @@ -2909,7 +2909,7 @@ _ASBOX } >&5 cat >&5 <<_CSEOF -This file was extended by bgpq3 $as_me 0.1.4, which was +This file was extended by bgpq3 $as_me 0.1.5, which was generated by GNU Autoconf 2.59. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -2969,7 +2969,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF ac_cs_version="\\ -bgpq3 config.status 0.1.4 +bgpq3 config.status 0.1.5 configured by $0, generated by GNU Autoconf 2.59, with options \\"`echo "$ac_configure_args" | sed 's/[\\""\`\$]/\\\\&/g'`\\" diff --git a/configure.in b/configure.in index ae433d4..cfb2148 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -AC_INIT(bgpq3,0.1.4,snar@paranoia.ru) +AC_INIT(bgpq3,0.1.5,snar@paranoia.ru) AC_CONFIG_HEADER(config.h) AC_PROG_CC AC_PROG_INSTALL