From mboxrd@z Thu Jan 1 00:00:00 1970 From: erik quanstrom Date: Thu, 28 Oct 2010 19:14:26 -0400 To: 9fans@9fans.net Message-ID: <88f0178840512f08eb010c723b458fb5@plug.quanstro.net> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="upas-jilnhxxtnrlxoztterkzrijhrp" Subject: [9fans] ndb database checker: ndb/vrfy Topicbox-Message-UUID: 70de398e-ead6-11e9-9d60-3106f5b1d025 This is a multi-part message in MIME format. --upas-jilnhxxtnrlxoztterkzrijhrp Content-Disposition: inline Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit a number of weeks ago, to facilitate migrating many hundreds of machines to a new network setup, i wrote a simple and fairly bone-headed ndb database checker, ndb/vrfy. it was amazingly effective, if provincial. it catches all the classics like badly formatted eas, duplicate eas, mistyped keys (eg ethr and not ether) the referenced, but not included, checkndb, checks to see that the user was "okay" (not expired, in ndb), but depends on local rules, kenfs and /adm/keystat, none of which are universal. /adm/keystat is a local invention to allow anyone to make a rough check for expired keys. if you really want a copy email me privately. - erik --upas-jilnhxxtnrlxoztterkzrijhrp Content-Type: multipart/mixed; boundary="upas-mosoigtirwvumprwjylvdfcwds" Content-Disposition: inline This is a multi-part message in MIME format. --upas-mosoigtirwvumprwjylvdfcwds Content-Disposition: inline Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit from postmaster@plug: The following attachment had content that we can't prove to be harmless. To avoid possible automatic execution, we changed the content headers. The original header was: Content-Type: text/troff Content-Disposition: attachment; filename=ndbvrfy Content-Transfer-Encoding: base64 --upas-mosoigtirwvumprwjylvdfcwds Content-Type: application/octet-stream Content-Disposition: attachment; filename="ndbvrfy.suspect" Content-Transfer-Encoding: base64 LlRIIE5EQlZSRlkgOQouU0ggTkFNRQpuZGIvdnJmeSwgY2hlY2tuZGIgXC0gY2hlY2sgbmRi IGRhdGFiYXNlCi5TSCBTWU5PUFNJUwouQiBuZGIvdnJmeQpbCi5CIC1jCl0gWwotQiAtbQou SSBpcC9tYXNrCl0gWwouSSBmaWxlIC4uLgpdCi5icgpjaGVja25kYgouU0ggREVTQ1JJUFRJ T04KLkkgTmRiL3ZyZnkKdmVyaWZpZXMgdGhlIHN5bnRheCBkYXRhYmFzZSBmaWxlIGdpdmVu CmFuZCBhcHBsaWVzIGEgZmV3IGFkLWhvYyBoZXVyaXN0aWNzLiAgV2l0aAp0aGUKLkIgLW0K ZmxhZywgYWxsIElQIGFkZHJlc3NlcyBpbgouSSBmaWxlCmFyZSBjaGVja2VkIGFnYWluc3Qg dGhlIGdpdmVuCi5JUiBpcC9tYXNrIC4KTm9ybWFsbHksCi5JIG5kYi92cmZ5CmNoZWNrcyBh dHRyaWJ1dGVzIGFnYWluc3QgYSBnZW5lcmljIGxpc3Qgb2YKYXR0cmlidXRlcy4gIHdpdGgK LkJSIC1jLAphdHRyaWJ1dGVzIHN1aXRhYmxlIGZvciB1c2Ugd2l0aAouSVIgY29uc29sZWRi ICg4KQphcmUgdXNlZC4KLlBQCi5JIENoZWNrbmRiCmNoZWNrcyBhbGwgdGhlIGZpbGVzIGlu Ci5CIC9saWIvbmRiCmZvciByZWFzb25hYmxlbmVzcyBpbiB0aGUgQ29yYWlkIGVudmlyb25t ZW50LgpJdCBpcyBhc3N1bWVkIHRoYXQgdGhlIG93bmVyJ3MgdWlkIG9uIHRoZSBmaWxlIHNl cnZlcgptYXRjaCB0aGUgdGhpcmQgb2N0ZXQgb2YgdGhlIG5ldHdvcmsuICBUaHVzIGl0Cmlz IGFzc3VtZWQgdGhhdAouSSB0b3IKb3ducwouQlIgL2xpYi9uZGIvMTAuMjIwLjEgLgphbmQg YWxsIHRoZSBJUCBhZGRyZXNzZXMgaW4gdGhpcyBmaWxlIGFyZSB3aXRoaW4gdGhlCi5CIDEw LjIyMC4xLjAvMTEyCm5ldHdvcmsuCi5TSCBTT1VSQ0UKLkIgL3N5cy9zcmMvY21kL25kYi92 cmZ5LnkKLmJyCi5CIC9yYy9iaW4vY2hlY2tuZGIKLlNIIFNFRSBBTFNPCi5JUiBjb25zb2xl ZGIgKDgpLAouSVIgbmRiICg4KQouU0ggQlVHUwpIb3BlbGVzcyBwcm92aW5jaWFsaXR5Lgo= --upas-mosoigtirwvumprwjylvdfcwds-- Content-Disposition: attachment; filename=vrfy.y Content-Type: text/plain; charset="US-ASCII" Content-Transfer-Encoding: 7bit %{ #include #include #include #include typedef struct T T; struct T{ T *next; T *down; char *s; char *t; int line; char *file; }; #pragma varargck type "T" T* Biobuf in; char *file; char *ipmask; int line; int factotum; T *dblist; T *ll0; T **ll; T *tab0; T **tab; int fd; extern int yyparse(void); extern void yyerror(char*, ...); char* nonil(char *s) { if(s == nil) return ""; return s; } int Tfmt(Fmt *f) { int sharp; T *t, *t0; t0 = va_arg(f->args, T*); sharp = f->flags & FmtSharp; for(; t0 != nil; t0 = t0->down){ if((t = t0) != nil) fmtprint(f, "%s=%s", t->s, nonil(t->t)); while(t = t->next) fmtprint(f, " %s=%s", t->s, nonil(t->t)); if(sharp == 0) break; if(t0->down != nil) fmtprint(f, "\n"); } return 0; } T* newt(char *s, char *t) { T *x; x = malloc(sizeof *x); if(x == nil) sysfatal("malloc: %r"); memset(x, 0, sizeof *x); x->s = s; x->t = t; x->line = line; x->file = file; return x; } static char *nakedtab[] = { "database", "soa", "trampok", }; int cknaked(char *s) { int i; for(i = 0; i < nelem(nakedtab); i++) if(strcmp(nakedtab[i], s) == 0) return 0; yyerror("naked token %s", s); return -1; } %} %union{ T *t; char *s; } %type rhs %token S %start db %% db : | db '\n' | db tuples '\n' ; tuples: tuple { *tab = ll0; tab = &ll0->down; ll0 = nil; ll = &ll0; } | tuple tuples ; tuple: S rhs { T *x; if($2 == nil) cknaked($1); x = *ll = newt($1, $2); ll = &x->next; } ; rhs: { $$ = nil; } | '=' S { $$ = $2; } ; %% void freet(T *t) { T *n, *d; for(; t != nil; t = d){ d = t->down; for(; t != nil; t = n){ n = t->next; free(t->s); free(t->t); free(t); } } } void yyinit(char *f) { file = f; line = 1; fd = open(file, OREAD); if(fd == -1) sysfatal("open: %r"); if(Binit(&in, fd, OREAD) == -1) sysfatal("Binit: %r"); freet(tab0); ll0 = nil; tab0 = nil; ll = &ll0; tab = &tab0; } void yyerror(char *fmt, ...) { char buf[256], *p, *e; va_list arg; static int nerrors; e = buf + sizeof buf; va_start(arg, fmt); p = seprint(buf, e, "%s:%d ", file, line); p = vseprint(p, e, fmt, arg); p = seprint(p, e, "\n"); va_end(arg); write(2, buf, p - buf); nerrors++; if(nerrors > 5) sysfatal("too many errors"); } void tokerror(T *t, char *fmt, ...) { char buf[256], *p, *e; va_list arg; static int nerrors; e = buf + sizeof buf; va_start(arg, fmt); p = seprint(buf, e, "%s:%d ", t->file, t->line); p = vseprint(p, e, fmt, arg); p = seprint(p, e, "\n"); va_end(arg); write(2, buf, p - buf); } enum{ Base, Seeneq, }; int yylex(void) { char buf[128], *s; int c, i; Rune r; static int state = Base; static int quoting; if(quoting != 0){ yyerror("bad quote"); quoting = 0; } i = 0; again: c = Bgetrune(&in); if(c == Beof) return 0; r = c; switch(r){ case ' ': case '\0': yyerror("bad character %#ux\n", r); goto again; case '#': for(;;){ switch(Bgetrune(&in)){ case Beof: yyerror("EOF in comment"); return 0; case '\n': Bungetrune(&in); goto again; } } case '\n': if(state != Base){ Bungetrune(&in); goto tok; } line++; switch(Bgetrune(&in)){ case Beof: return '\n'; case ' ': case '\t': goto again; } Bungetrune(&in); return '\n'; case ' ': case '\t': if(state != Base){ Bungetrune(&in); goto tok; } goto again; case '=': if(state != Base) break; state = Seeneq; return '='; default: break; } /* token */ if(r == '"'){ quoting = 1; c = Bgetrune(&in); r = c; } for(;;){ if(i >= sizeof buf - UTFmax - 1){ yyerror("token too long"); break; } i += runetochar(buf + i, &r); c = Bgetrune(&in); if(c == Beof) break; r = c; switch(r){ case ' ': case '\0': yyerror("bad character %#ux\n", r); goto tok; case ' ': case '\t': if(quoting) break; case '\n': Bungetrune(&in); goto tok; case '=': if(state == Base){ Bungetrune(&in); goto tok; } break; case '\'': if(factotum) goto quote; break; case '"': if(!factotum) if(quoting == 1){ quoting = 0; goto tok; } break; case '#': yyerror("# in token"); } } tok: if(state == Base && i == 0) yyerror("name is nil"); if(state == Seeneq) state = Base; buf[i] = 0; s = strdup(buf); if(s == nil) sysfatal("malloc: %r"); yylval.s = s; return S; quote: quoting = 1; for(;;){ /* extra space for ' if quoting fails. ndb is wierd */ if(i >= sizeof buf - UTFmax - 1 - 1){ yyerror("token too long"); break; } i += runetochar(buf + i, &r); c = Bgetrune(&in); if(c == Beof) break; r = c; switch(r){ case '\n': /* wierd! this is actually what ndb does */ Bungetrune(&in); memmove(buf, buf + 1, i); buf[0] = '\''; goto tok; case '\'': if(Bgetrune(&in) == '\'') break; Bungetrune(&in); goto tok; } } goto tok; } void go(char *file) { yyinit(file); yyparse(); close(fd); } int parseipxmask(uchar *ip, uchar *m, char *s0) { uchar tmp[IPaddrlen]; char *msk, s[4*8+4]; snprint(s, sizeof s, "%s", s0); msk = strchr(s, '/'); if(msk == nil){ if(parseipmask(m, "/120") == -1) return -1; }else{ if(parseipmask(m, msk) == -1) return -1; *msk = 0; } if(parseip(tmp, s) == -1) return -1; maskip(tmp, m, ip); return 0; } void checkip(void) { uchar m0[IPaddrlen], mask[IPaddrlen], ip1[IPaddrlen], m1[IPaddrlen]; int havemsk; T *d, *t; havemsk = 0; if(ipmask != nil) if(parseipxmask(m0, mask, ipmask) == 0) havemsk = 1; for(d = tab0; d != nil; d = d->down) for(t = d; t != nil; t = t->next){ if(strcmp(t->s, "ip") != 0) continue; if(parseip(ip1, t->t) == -1){ tokerror(t, "bad ip %T", d); continue; } if(havemsk == 0) continue; maskip(ip1, mask, m1); if(ipcmp(m0, m1) != 0) tokerror(t, "wrong file: %I", t, ip1); } } typedef struct { uchar ea[IPaddrlen]; T *d[10]; int nd; } B; static B *btab; static uint nbtab; static uint nbtaba; int addrcmp(uchar *a, uchar *b) { int d; d = memcmp(a, b, IPaddrlen); if(d > 0) return 1; if(d < 0) return -1; return 0; } static B* bsearch(uchar *ea) { B *tab, *m; int n, i, d; tab = btab; for(n = nbtab; n > 0;){ i = n/2; m = tab+i; d = addrcmp(m->ea, ea); if(d == 0) return m; if(d < 0){ tab += i+1; n -= i+1; }else n = i; } return nil; } void binsert(B *m, T *d, uchar *ea) { char buf[256], *p, *e; int i; T **x; if(m == nil){ if(nbtab + 1 >= nbtaba){ nbtaba = nbtab + 1 << 1; btab = realloc(btab, sizeof btab[0]*nbtaba); if(btab == nil) sysfatal("realloc: %r"); } for(m=btab+nbtab; m > btab && addrcmp(m[-1].ea, ea) > 0; m--) m[0] = m[-1]; m->nd = 0; memcpy(m->ea, ea, IPaddrlen); nbtab++; } m->d[m->nd++] = d; if(m->nd > 1){ x = m->d; p = buf; e = buf + sizeof buf; for(i = 0; i < m->nd - 1; i++) p = seprint(p, e, "%s:%d ", x[i]->file, x[i]->line); tokerror(d, "duplicate ea %E %s", m->ea, buf); } } void prdb(void) { int i; for(i = 0; i < nbtab; i++) print("%E\n", btab[i].ea); } void checkether(void) { uchar ea[IPaddrlen]; T *d, *t; for(d = tab0; d != nil; d = d->down) for(t = d; t != nil; t = t->next){ if(strcmp(t->s, "ether") != 0) continue; if(strspn(t->t, "0123456789abcdef") != 12) tokerror(t, "bad ea %s", t->t); parseether(ea, t->t); binsert(bsearch(ea), d, ea); } } static char *soaattr[] = { "refresh", "ttl", "ns", "mx", "pref", "mbox", }; static char *cattrtab[] = { "clog", /* only in consoledb */ "console", "dev", "gid", "group", "speed", "uid", "openondemand", }; static char *xattrtab[] = { "auth", "authdom", "bootf", "cname", "console", "database", "dns", "dnsdomain", "dom", "el", "ether", "file", "fs", "gw", "imap", "ip", "ipgw", "ipmask", "ipnet", "mb", "mbox", "mx", "ns", "pref", "proto", "refresh", "smtp", "soa", "sys", "trampok", "ttl", "txtrr", "pri", "srv", "weight", "gre", "il", "ipv4proto", "port", "protocol", "restricted", "tcp", "udp", "uid", "hostid" }; char **attrtab = xattrtab; int nattrtab = nelem(xattrtab); void checkattrs(void) { int i; T *d, *t; for(d = tab0; d != nil; d = d->down) for(t = d; t != nil; t = t->next){ for(i = 0; i < nattrtab; i++) if(strcmp(t->s, attrtab[i]) == 0) break; if(i == nattrtab) tokerror(t, "unknown attr %s", t->s); } } void usage(void) { fprint(2, "usage: ndb/vrfy [-m ip/mask] [file ...]\n"); exits("usage"); } void main(int argc, char **argv) { int i; fmtinstall('T', Tfmt); fmtinstall('I', eipfmt); fmtinstall('M', eipfmt); fmtinstall('E', eipfmt); ARGBEGIN{ case 'c': attrtab = cattrtab; nattrtab = nelem(cattrtab); break; case 'm': ipmask = EARGF(usage()); break; default: usage(); }ARGEND for(i = 0; i < argc; i++){ go(argv[i]); checkip(); checkether(); checkattrs(); } exits(""); } --upas-jilnhxxtnrlxoztterkzrijhrp--