#if HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include #include #include #include #include "bgpq3.h" #include "sx_report.h" int debug_expander=1; 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->name="UNKNOWN"; 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; bgpq_expander_add_prefix(ex,as); return 1; }; int bgpq_expanded_v6prefix(char* prefix, void* udata) { struct bgpq_expander* ex=(struct bgp_expander*)udata; if(!ex) return 0; bgpq_expander_add_prefix(ex,prefix); return 1; }; int bgpq_expand_ripe(FILE* f, int (*callback)(char*, void*), void* udata, char* fmt, ...) { char request[128]; char* otype=NULL, *object=NULL; int sawNL=0, nObjects=0; va_list ap; if(!f) { sx_report(SX_FATAL,"Invalid argments\n"); exit(1); }; va_start(ap,fmt); vsnprintf(request,sizeof(request),fmt,ap); va_end(ap); SX_DEBUG(debug_expander,"expander(ripe): sending '%s'\n", request); fwrite(request,1,strlen(request),f); fflush(f); sawNL=0; while(fgets(request,sizeof(request),f)) { if(request[0]=='\n') { printf("ok, got object '%s': '%s'\n",otype,object); if(otype) free(otype); otype=NULL; if(object) free(object); object=NULL; nObjects++; sawNL++; if(sawNL==2) { /* ok, that's end of input */ return nObjects; }; } else { if(!otype) { /* that's the first line of object */ char* c=strchr(request,':'); if(c) { *c=0; otype=strdup(request); c++; while((isspace(*c))) c++; object=strdup(c); c=strchr(object,'\n'); if(c) *c=0; }; printf("parsed request as '%s': '%s'\n", otype, object); }; }; }; if(feof(f)) { sx_report(SX_FATAL,"EOF from server\n"); } else { sx_report(SX_FATAL,"Error reading server: %s\n", strerror(errno)); }; return 0; }; 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); SX_DEBUG(debug_expander,"expander: sending '%s'\n", request); write(fd,request,strlen(request)); memset(request,0,sizeof(request)); nread: 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); }; SX_DEBUG(debug_expander>2,"expander: initially got %i bytes, '%s'\n", ret,request); if(ret==1 && request[0]=='\n') goto nread; 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; cai_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; FILE* f=fdopen(fd,"rw"); for(i=0;iasnumbers);i++) { for(j=0;j<8;j++) { if(b->asnumbers[i]&(0x80>>j)) { if(b->family==AF_INET6) { bgpq_expand_ripe(f,bgpq_expanded_v6prefix,b, "-i origin as%i\r\n",i*8+j); } else { 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; };