bgpq3 - complete rewrite of bgpq

This commit is contained in:
snar
2007-03-22 18:12:32 +00:00
commit bbea84badd
12 changed files with 5083 additions and 0 deletions

18
Makefile.in Normal file
View File

@@ -0,0 +1,18 @@
CC=@CC@
CFLAGS=@CFLAGS@ @DEFS@ -g -Wall -I. -O0
LDADD=@LDFLAGS@ @LIBS@
OBJECTS=bgpq3.o sx_report.o bgpq_expander.o sx_slentry.o bgpq3_printer.o
all: bgpq3
bgpq3: ${OBJECTS}
${CC} ${CFLAGS} -o bgpq3 ${OBJECTS} ${LDADD}
.c.o:
${CC} ${CFLAGS} -c $<
clean:
rm -rf Makefile autom4te.cache bgpq3 config.h config.log config.status
rm -rf *.o *.core core.* core

122
bgpq3.c Normal file
View File

@@ -0,0 +1,122 @@
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>
#include "bgpq3.h"
#include "sx_report.h"
int
usage(int ecode)
{
printf("Usage: bgpq3 [-h] [-S sources] <OBJECTS>...\n");
printf(" -h : this help\n");
printf(" -J : use Juniper replace formatted output\n");
printf(" -l : use specified name for generated access/prefix/.. list\n");
printf(" -S sources: use only specified sources (default:"
" RADB,RIPE,APNIC)\n");
exit(ecode);
};
int
main(int argc, char* argv[])
{
int c;
struct bgpq_expander expander;
int af=AF_INET;
int widthSet=0;
bgpq_expander_init(&expander,af);
expander.sources=getenv("IRRD_SOURCES");
while((c=getopt(argc,argv,"6hS:Jf:l:W:P"))!=EOF) {
switch(c) {
case '6': af=AF_INET6;
expander.family=AF_INET6;
break;
case 'J': expander.vendor=V_JUNIPER;
break;
case 'f': expander.asnumber=atoi(optarg);
if(expander.asnumber<0 || expander.asnumber>65535) {
sx_report(SX_FATAL,"Invalid AS number: %s\n", optarg);
exit(1);
};
expander.generation=T_ASPATH;
break;
case 'P': expander.generation=T_PREFIXLIST;
break;
case 'l': expander.name=optarg;
break;
case 'S': expander.sources=optarg;
break;
case 'W': expander.aswidth=atoi(optarg);
if(expander.aswidth<1) {
sx_report(SX_FATAL,"Invalid as-width: %s\n", optarg);
exit(1);
};
widthSet=1;
break;
case 'h': usage(0);
default : usage(1);
};
};
argc-=optind;
argv+=optind;
if(!widthSet) {
if(expander.generation==T_ASPATH) {
if(expander.vendor==V_CISCO) {
expander.aswidth=4;
} else if(expander.vendor==V_JUNIPER) {
expander.aswidth=8;
};
} else if(expander.generation==T_OASPATH) {
if(expander.vendor==V_CISCO) {
expander.aswidth=5;
} else if(expander.vendor==V_JUNIPER) {
expander.aswidth=8;
};
};
};
if(!argv[0]) usage(1);
while(argv[0]) {
if(!strncasecmp(argv[0],"AS-",3)) {
bgpq_expander_add_asset(&expander,argv[0]);
} else if(!strncasecmp(argv[0],"AS",2)) {
bgpq_expander_add_as(&expander,argv[0]);
} else {
if(!bgpq_expander_add_prefix(&expander,argv[0]))
exit(1);
};
argv++;
argc--;
};
if(!bgpq_expand(&expander)) {
exit(1);
};
switch(expander.generation) {
case T_ASPATH: bgpq3_print_aspath(stdout,&expander);
break;
case T_PREFIXLIST: bgpq3_print_prefixlist(stdout,&expander);
default :
break;
};
return 0;
};

37
bgpq3.h Normal file
View File

@@ -0,0 +1,37 @@
#ifndef BGPQ3_H_
#define BGPQ3_H_
#include "sx_prefix.h"
#include "sx_slentry.h"
typedef enum {
V_CISCO = 0,
V_JUNIPER
} bgpq_vendor_t;
typedef enum {
T_NONE = 0,
T_ASPATH,
T_OASPATH,
T_PREFIXLIST
} bgpq_gen_t;
struct bgpq_expander {
struct sx_radix_tree* tree;
unsigned char asnumbers[8192];
struct sx_slentry* macroses;
int family;
char* sources;
int asnumber, aswidth;
char* name;
bgpq_vendor_t vendor;
bgpq_gen_t generation;
};
int bgpq_expander_init(struct bgpq_expander* b, int af);
int bgpq_expander_add_asset(struct bgpq_expander* b, char* set);
int bgpq_expander_add_as(struct bgpq_expander* b, char* as);
int bgpq_expander_add_prefix(struct bgpq_expander* b, char* prefix);
#endif

123
bgpq3_printer.c Normal file
View File

@@ -0,0 +1,123 @@
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include "bgpq3.h"
#include "sx_report.h"
int
bgpq3_print_cisco_aspath(FILE* f, struct bgpq_expander* b)
{
int nc=0, i, j;
fprintf(f,"no ip as-path access-list %s\n", b->name?b->name:"UNKNOWN");
if(b->asnumbers[b->asnumber/8]&(0x80>>(b->asnumber%8))) {
fprintf(f,"ip as-path access-list %s permit ^%i(_%i)*$\n",
b->name?b->name:"UNKNOWN",b->asnumber,b->asnumber);
};
for(i=0;i<sizeof(b->asnumbers);i++) {
for(j=0;j<8;j++) {
if(b->asnumbers[i]&(0x80>>j)) {
if(i*8+j==b->asnumber) continue;
if(!nc) {
fprintf(f,"ip as-path access-list %s permit"
" ^%i(_[0-9]+)*_(%i", b->name?b->name:"UNKNOWN",
b->asnumber,i*8+j);
} else {
fprintf(f,"|%i",i*8+j);
}
nc++;
if(nc==b->aswidth) {
fprintf(f,")$\n");
nc=0;
};
};
};
};
if(nc) fprintf(f,")$\n");
return 0;
};
int
bgpq3_print_juniper_aspath(FILE* f, struct bgpq_expander* b)
{
int nc=0, lineNo=0, i, j;
fprintf(f,"policy-options {\nreplace:\n as-path-group %s {\n",
b->name?b->name:"UNKNOWN");
if(b->asnumbers[b->asnumber/8]&(0x80>>(b->asnumber%8))) {
fprintf(f," as-path a%i \"^%i(%i)*$\";\n", lineNo, b->asnumber,
b->asnumber);
lineNo++;
};
for(i=0;i<sizeof(b->asnumbers);i++) {
for(j=0;j<8;j++) {
if(b->asnumbers[i]&(0x80>>j)) {
if(i*8+j==b->asnumber) continue;
if(!nc) {
fprintf(f," as-path a%i \"^%i(.)*(%i",
lineNo,b->asnumber,i*8+j);
} else {
fprintf(f,"|%i",i*8+j);
}
nc++;
if(nc==b->aswidth) {
fprintf(f,")$\";\n");
nc=0;
lineNo++;
};
};
};
};
if(nc) fprintf(f,")$\";\n");
fprintf(f," }\n}\n");
return 0;
};
int
bgpq3_print_aspath(FILE* f, struct bgpq_expander* b)
{
if(b->vendor==V_JUNIPER) {
return bgpq3_print_juniper_aspath(f,b);
} else if(b->vendor==V_CISCO) {
return bgpq3_print_cisco_aspath(f,b);
} else {
sx_report(SX_FATAL,"Unknown vendor %i\n", b->vendor);
};
return 0;
};
void
bgpq3_print_jprefix(struct sx_radix_node* n, void* ff)
{
char prefix[128];
FILE* f=(FILE*)ff;
if(!f) f=stdout;
sx_prefix_snprintf(&n->prefix,prefix,sizeof(prefix));
fprintf(f," %s; (%i)\n",prefix,n->isGlue);
};
int
bgpq3_print_juniper_prefixlist(FILE* f, struct bgpq_expander* b)
{
printf("prefix-printer called\n");
sx_radix_tree_foreach(b->tree,bgpq3_print_jprefix,stdout);
return 0;
};
int
bgpq3_print_prefixlist(FILE* f, struct bgpq_expander* b)
{
switch(b->vendor) {
case V_JUNIPER: return bgpq3_print_juniper_prefixlist(f,b);
};
return 0;
};

300
bgpq_expander.c Normal file
View File

@@ -0,0 +1,300 @@
#if HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <strings.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "bgpq3.h"
#include "sx_report.h"
int
bgpq_expander_init(struct bgpq_expander* b, int af)
{
if(!af) af=AF_INET;
if(!b) return 0;
memset(b,0,sizeof(struct bgpq_expander));
b->tree=sx_radix_tree_new(af);
if(!b->tree) goto fixups;
b->family=af;
b->sources="ripe,radb,apnic";
b->aswidth=8;
return 1;
fixups:
/* if(b->tree) XXXXXXXXXXXXX sx_radix_tree_destroy(b->tree); */
b->tree=NULL;
free(b);
return 0;
};
int
bgpq_expander_add_asset(struct bgpq_expander* b, char* as)
{
struct sx_slentry* le;
if(!b || !as) return 0;
le=sx_slentry_new(as);
if(!le) return 0;
if(!b->macroses) {
b->macroses=le;
} else {
struct sx_slentry* ln=b->macroses;
while(ln->next) ln=ln->next;
ln->next=le;
};
return 1;
};
int
bgpq_expander_add_as(struct bgpq_expander* b, char* as)
{
char* eoa;
uint32_t asno;
if(!b || !as) return 0;
asno=strtoul(as+2,&eoa,10);
if(eoa && (*eoa!='.' && *eoa!=0)) {
sx_report(SX_ERROR,"Invalid symbol in AS number: '%c' in %s\n",
*eoa, as);
return 0;
};
if(*eoa=='.') {
sx_report(SX_ERROR,"32-bit as numbers is not supported yet (%s)\n",as);
return 0;
};
if(asno<1 || asno>65535) {
sx_report(SX_ERROR,"Invalid AS number in %s\n", as);
return 0;
};
b->asnumbers[asno/8]|=(0x80>>(asno%8));
return 1;
};
int
bgpq_expander_add_prefix(struct bgpq_expander* b, char* prefix)
{
struct sx_prefix p;
if(!sx_prefix_parse(&p,b->family,prefix)) {
sx_report(SX_ERROR,"Unable to parse prefix %s\n", prefix);
return 0;
};
sx_radix_tree_insert(b->tree,&p);
return 0;
};
int
bgpq_expanded_macro(char* as, void* udata)
{
struct bgpq_expander* ex=(struct bgp_expander*)udata;
if(!ex) return 0;
bgpq_expander_add_as(ex,as);
return 1;
};
int
bgpq_expanded_prefix(char* as, void* udata)
{
struct bgpq_expander* ex=(struct bgp_expander*)udata;
if(!ex) return 0;
printf("expanded prefix %s\n", as);
bgpq_expander_add_prefix(ex,as);
return 1;
};
int
bgpq_expand_radb(int fd, int (*callback)(char*, void*), void* udata,
char* fmt, ...)
{
char request[128];
va_list ap;
int ret;
va_start(ap,fmt);
vsnprintf(request,sizeof(request),fmt,ap);
va_end(ap);
write(fd,request,strlen(request));
memset(request,0,sizeof(request));
ret=read(fd,request,sizeof(request)-1);
if(ret<0) {
sx_report(SX_ERROR,"Error reading data from radb: %s\n",
strerror(errno));
exit(1);
};
if(ret==0) {
sx_report(SX_ERROR,"Connection with radb closed inexpeced\n");
exit(1);
};
if(request[0]=='A') {
char* eon, *c;
long togot=strtol(request+1,&eon,10);
char recvbuffer[togot+128];
char* recvto;
if(eon && *eon!='\n') {
sx_report(SX_ERROR,"Number ends at wrong character: '%c'(%s)\n"
,*eon,request);
exit(1);
};
eon++;
memset(recvbuffer,0,togot+128);
memcpy(recvbuffer,eon,ret-(eon-request));
recvto=recvbuffer+ret-(eon-request);
togot-=ret-(eon-request);
while(togot>0) {
ret=read(fd,recvto,togot);
if(ret<0) {
sx_report(SX_ERROR,"Error reading data: %s\n",
strerror(errno));
exit(1);
};
if(ret==0) {
sx_report(SX_ERROR,"Server unexpectedly closed the"
" connection\n");
exit(1);
};
togot-=ret;
recvto+=ret;
};
if(togot==0) {
memset(request,0,sizeof(request));
ret=read(fd,request,sizeof(request)-1);
if(ret>0) {
if(request[0]!='C') {
sx_report(SX_ERROR,"Wrong character after reply: %s\n",
request);
exit(0);
};
} else {
if(ret==0) {
sx_report(SX_ERROR,"Server inexpectedly closed"
" connection\n");
exit(0);
} else {
sx_report(SX_ERROR,"Error reading data from server:"
" %s\n",
strerror(errno));
};
};
} else {
/* togot < 0, initially. */
if(recvto[togot]=='C') {
/* ok, finised */
} else if(recvto[togot]=='D') {
/* nodata */
} else if(recvto[togot]=='E') {
} else if(recvto[togot]=='F') {
sx_report(SX_FATAL,"Error from server: %s", recvto+togot);
exit(1);
};
recvto[togot]=0;
};
for(c=recvbuffer; c<recvto;) {
size_t spn=strcspn(c," \n");
if(spn) c[spn]=0;
if(c[0]==0) break;
if(callback) callback(c,udata);
c+=spn+1;
};
} else if(request[0]=='C') {
/* no data */
} else if(request[0]=='D') {
/* ... */
} else if(request[0]=='E') {
/* XXXXXX */
} else if(request[0]=='F') {
/* XXXXXX */
} else {
sx_report(SX_ERROR,"Wrong reply: %s\n", request);
exit(0);
};
return 0;
};
int
bgpq_expand(struct bgpq_expander* b)
{
int fd=-1, err;
struct sx_slentry* mc;
struct addrinfo hints, *res=NULL, *rp;
memset(&hints,0,sizeof(struct addrinfo));
hints.ai_socktype=SOCK_STREAM;
err=getaddrinfo("whois.radb.net","43",&hints,&res);
if(err) {
sx_report(SX_ERROR,"Unable to resolve whois.radb.net: %s\n",
gai_strerror(err));
exit(1);
};
for(rp=res; rp; rp=rp->ai_next) {
fd=socket(rp->ai_family,rp->ai_socktype,0);
if(fd==-1) {
if(errno==EPROTONOSUPPORT) continue;
sx_report(SX_ERROR,"Unable to create socket: %s\n",
strerror(errno));
exit(1);
};
err=connect(fd,rp->ai_addr,rp->ai_addrlen);
if(err) {
shutdown(fd,SHUT_RDWR);
close(fd);
fd=-1;
continue;
};
break;
};
freeaddrinfo(res);
if(fd==-1) {
/* all our attempts to connect failed */
sx_report(SX_ERROR,"All attempts to connect failed\n");
exit(1);
};
write(fd,"!!\n",3);
if(b->sources && b->sources[0]!=0) {
char sources[128];
snprintf(sources,sizeof(sources),"!s%s\n", b->sources);
write(fd,sources,strlen(sources));
};
for(mc=b->macroses;mc;mc=mc->next) {
bgpq_expand_radb(fd,bgpq_expanded_macro,b,"!i%s,1\n",mc->text);
};
if(b->generation>=T_PREFIXLIST) {
int i, j;
for(i=0;i<sizeof(b->asnumbers);i++) {
for(j=0;j<8;j++) {
if(b->asnumbers[i]&(0x80>>j)) {
bgpq_expand_radb(fd,bgpq_expanded_prefix,b,"!gas%i\n",
i*8+j);
};
};
};
};
write(fd,"!q\n",3);
shutdown(fd,SHUT_RDWR);
close(fd);
return 1;
};

16
config.h.in Normal file
View File

@@ -0,0 +1,16 @@
/* config.h.in. Generated from configure.in by autoheader. */
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION

4295
configure vendored Executable file

File diff suppressed because it is too large Load Diff

24
configure.in Normal file
View File

@@ -0,0 +1,24 @@
AC_INIT(bgpq3.c)
AC_CONFIG_HEADER(config.h)
AC_PROG_CC
if test -d "../libsxreport" ; then
CFLAGS="$CFLAGS -I../libsxreport"
CPPFLAGS="$CPPFLAGS -I../libsxreport"
LDFLAGS="$LDFLAGS -L../libsxreport"
fi
AC_CHECK_HEADERS(sx_report.h,,[AC_MSG_ERROR([no sx_report.h])])
AC_CHECK_LIB(sxreport,sx_report,,[AC_MSG_ERROR([no -lsxreport])])
if test -d "../libptree" ; then
CFLAGS="$CFLAGS -I../libptree"
CPPFLAGS="$CPPFLAGS -I../libptree"
LDFLAGS="$LDFLAGS -L../libptree"
fi
AC_CHECK_HEADERS(sx_prefix.h,,[AC_MSG_ERROR([no sx_prefix.h])])
AC_CHECK_LIB(sxprefix,sx_prefix_new,,[AC_MSG_ERROR([no -lsxprefix])])
AC_OUTPUT(Makefile)

97
sx_report.c Normal file
View File

@@ -0,0 +1,97 @@
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <errno.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <syslog.h>
#include "sx_report.h"
static int reportStderr=1;
static char const* const
sx_report_name(sx_report_t t)
{
switch(t) {
case SX_MISFEATURE: return "MISSING FEATURE:";
case SX_FATAL: return "FATAL ERROR:";
case SX_ERROR: return "ERROR:";
case SX_NOTICE: return "Notice:";
case SX_DEBUG: return "Debug:";
};
return "...... HMMMMM.... ERROR... \n";
};
int
sx_report(sx_report_t t, char* fmt, ...)
{
char buffer[1024];
va_list ap;
va_start(ap,fmt);
vsnprintf(buffer,sizeof(buffer),fmt,ap);
va_end(ap);
if(reportStderr) {
fputs(sx_report_name(t),stderr);
fputs(buffer,stderr);
} else {
switch(t) {
case SX_FATAL:
syslog(LOG_ERR,"FATAL ERROR: %s", buffer);
break;
case SX_MISFEATURE:
case SX_ERROR:
syslog(LOG_ERR,"ERROR: %s", buffer);
break;
case SX_NOTICE:
syslog(LOG_WARNING,"Warning: %s", buffer);
break;
case SX_DEBUG:
syslog(LOG_DEBUG,"Debug: %s", buffer);
break;
};
};
if(t==SX_FATAL) exit(-1);
return 0;
};
int
sx_debug(char const* const file, char const* const func, int const line,
char* fmt, ...)
{
char buffer[1024];
char bline[1024];
va_list ap;
va_start(ap,fmt);
vsnprintf(buffer,sizeof(buffer),fmt,ap);
va_end(ap);
snprintf(bline,sizeof(bline),"DEBUG: %s:%i %s ", file, line, func);
if(reportStderr) {
fputs(bline,stderr);
fputs(buffer,stderr);
} else {
syslog(LOG_DEBUG,"%s %s", bline, buffer);
};
return 0;
};
void
sx_openlog(char* progname)
{
openlog(progname?progname:"<unknown>",LOG_PID,LOG_DAEMON);
reportStderr=0;
};

24
sx_report.h Normal file
View File

@@ -0,0 +1,24 @@
#ifndef SX_REPORT_H_
#define SX_REPORT_H_
typedef enum {
SX_DEBUG = 0,
SX_NOTICE,
SX_ERROR,
SX_MISFEATURE,
SX_FATAL
} sx_report_t;
/* opens syslog and disables logging to stderr */
void sx_openlog(char* progname);
int sx_report(sx_report_t, char* fmt, ...)
__attribute__ ((format (printf, 2, 3)));
int sx_debug(char const* const, char const* const, int const, char* fmt, ...)
__attribute__ ((format (printf, 4, 5)));
#define SX_DEBUG(a,b,c...) if(a) sx_debug(__FILE__,__FUNCTION__,__LINE__,\
b, ## c);
#endif

16
sx_slentry.c Normal file
View File

@@ -0,0 +1,16 @@
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "sx_slentry.h"
struct sx_slentry*
sx_slentry_new(char* t)
{
struct sx_slentry* e=malloc(sizeof(struct sx_slentry));
if(!e) return NULL;
memset(e,0,sizeof(struct sx_slentry));
if(t) e->text=strdup(t);
return e;
};

11
sx_slentry.h Normal file
View File

@@ -0,0 +1,11 @@
#ifndef SX_SLENTRY_H_
#define SX_SLENTRY_H_
struct sx_slentry {
struct sx_slentry* next;
char* text;
};
struct sx_slentry* sx_slentry_new(char* text);
#endif