/* * look through a containing subset */ static Ndbtuple* subnet(Ndb *db, uint8_t *net, Ndbtuple *f, int prefix) { Ndbs s; Ndbtuple *t, *nt, *xt; char netstr[128]; uint8_t mask[IPaddrlen]; int masklen; t = nil; sprint(netstr, "%I", net); nt = ndbsearch(db, &s, "ip", netstr); while(nt != nil){ xt = ndbfindattr(nt, nt, "ipnet"); if(xt){ xt = ndbfindattr(nt, nt, "ipmask"); if(xt) parseipmask(mask, xt->val); else ipmove(mask, defmask(net)); masklen = prefixlen(mask); if(masklen <= prefix){ t = ndbconcatenate(t, filter(db, nt, f)); nt = nil; } } ndbfree(nt); nt = ndbsnext(&s, "ip", netstr); } ndbsetmalloctag(t, getcallerpc(&db)); return t; }
/* * use dns to resolve the mx request */ static int mxlookup(DS *ds, char *domain) { int i, n, nmx; Ndbtuple *t, *tmx, *tpref, *tip; strcpy(domain, ds->host); ds->netdir = "/net"; nmx = 0; if((t = dnsquery(nil, ds->host, "mx")) != nil){ for(tmx=t; (tmx=ndbfindattr(tmx->entry, nil, "mx")) != nil && nmx<Nmx; ){ for(tpref=tmx->line; tpref != tmx; tpref=tpref->line){ if(strcmp(tpref->attr, "pref") == 0){ strncpy(mx[nmx].host, tmx->val, sizeof(mx[n].host)-1); mx[nmx].pref = atoi(tpref->val); nmx++; break; } } } ndbfree(t); } /* * no mx record? try name itself. */ /* * BUG? If domain has no dots, then we used to look up ds->host * but return domain instead of ds->host in the list. Now we return * ds->host. What will this break? */ if(nmx == 0){ mx[0].pref = 1; strncpy(mx[0].host, ds->host, sizeof(mx[0].host)); nmx++; } /* * look up all ip addresses */ for(i = 0; i < nmx; i++){ if((t = dnsquery(nil, mx[i].host, "ip")) == nil) goto no; if((tip = ndbfindattr(t, nil, "ip")) == nil){ ndbfree(t); goto no; } strncpy(mx[i].ip, tip->val, sizeof(mx[i].ip)-1); ndbfree(t); continue; no: /* remove mx[i] and go around again */ nmx--; mx[i] = mx[nmx]; i--; } return nmx; }
Ndbtuple* ndblookval(Ndbtuple *entry, Ndbtuple *line, char *attr, char *to) { Ndbtuple *t; t = ndbfindattr(entry, line, attr); if(t != nil){ strncpy(to, t->val, Ndbvlen-1); to[Ndbvlen-1] = 0; } return t; }
/* * fill in all the requested attributes for a system. * if the system's entry doesn't have all required, * walk through successively more inclusive networks * for inherited attributes. */ Ndbtuple* ndbipinfo(Ndb *db, char *attr, char *val, char **alist, int n) { Ndbtuple *t, *nt, *f; Ndbs s; char *ipstr; uint8_t net[IPaddrlen], ip[IPaddrlen]; int prefix, smallestprefix, force; int64_t r; /* just in case */ fmtinstall('I', eipfmt); fmtinstall('M', eipfmt); /* get needed attributes */ f = mkfilter(n, alist); /* * first look for a matching entry with an ip address */ t = nil; ipstr = ndbgetvalue(db, &s, attr, val, "ip", &nt); if(ipstr == nil){ /* none found, make one up */ if(strcmp(attr, "ip") != 0) { ndbfree(f); return nil; } t = ndbnew("ip", val); t->line = t; t->entry = nil; r = parseip(net, val); if(r == -1) ndbfree(t); } else { /* found one */ while(nt != nil){ nt = ndbreorder(nt, s.t); t = ndbconcatenate(t, nt); nt = ndbsnext(&s, attr, val); } r = parseip(net, ipstr); free(ipstr); } if(r < 0){ ndbfree(f); return nil; } ipmove(ip, net); t = filter(db, t, f); /* * now go through subnets to fill in any missing attributes */ if(isv4(net)){ prefix = 127; smallestprefix = 100; force = 0; } else { /* in v6, the last 8 bytes have no structure (we hope) */ prefix = 64; smallestprefix = 2; memset(net+8, 0, 8); force = 1; } /* * to find a containing network, keep turning off * the lower bit and look for a network with * that address and a shorter mask. tedius but * complete, we may need to find a trick to speed this up. */ for(; prefix >= smallestprefix; prefix--){ if(filtercomplete(f)) break; if(!force && (net[prefix/8] & (1<<(7-(prefix%8)))) == 0) continue; force = 0; net[prefix/8] &= ~(1<<(7-(prefix%8))); t = ndbconcatenate(t, subnet(db, net, f, prefix)); } /* * if there's an unfulfilled ipmask, make one up */ nt = ndbfindattr(f, f, "ipmask"); if(nt && !(nt->ptr & Fignore)){ char x[64]; snprint(x, sizeof(x), "%M", defmask(ip)); t = ndbconcatenate(t, ndbnew("ipmask", x)); } ndbfree(f); ndbsetmalloctag(t, getcallerpc(&db)); return t; }
int classify(char *ip, Ndbtuple *t) { int isgov, iscountry, isbadc, isgoodc; char dom[256]; char *df[128]; Ndbtuple *nt, *x; int n; isgov = iscountry = isbadc = 0; isgoodc = 1; for(nt = t; nt != nil; nt = nt->entry){ if(strcmp(nt->attr, "country") == 0){ iscountry = 1; if(incountries(nt->val, badc)){ if(classdebug)fprint(2, "isbadc\n"); isbadc = 1; isgoodc = 0; } else if(!incountries(nt->val, goodc)){ if(classdebug)fprint(2, "!isgoodc\n"); isgoodc = 0; } } /* domain names can always hurt, even without forward verification */ if(strcmp(nt->attr, "dom") == 0){ strncpy(dom, nt->val, sizeof dom); dom[sizeof(dom)-1] = 0; n = getfields(dom, df, nelem(df), 0, "."); /* a bad country in a domain name is always believed */ if(incountries(df[n-1], badc)){ if(classdebug)fprint(2, "isbadc dom\n"); isbadc = 1; isgoodc = 0; } /* a goverment in a domain name is always believed */ if(n > 1 && indomains(df[n-2], gov)) isgov = 1; } } if(iscountry == 0){ /* did the forward lookup work? */ for(nt = t; nt != nil; nt = nt->entry){ if(strcmp(nt->attr, "ip") == 0 && strcmp(nt->val, ip) == 0) break; } /* see if the domain name ends in a country code */ if(nt != nil && (x = ndbfindattr(t, nt, "dom")) != nil){ strncpy(dom, x->val, sizeof dom); dom[sizeof(dom)-1] = 0; n = getfields(dom, df, nelem(df), 0, "."); if(incountries(df[n-1], allc)) iscountry = 1; } } if(iscountry == 0) return Cunknown; if(isbadc) return Cbadc; if(!isgoodc && isgov) return Cbadgov; return C*k; }