/* * 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; }
uint8_t* v4defmask(uint8_t *ip) { uint8_t v6ip[IPaddrlen]; v4tov6(v6ip, ip); ip = defmask(v6ip); return ip+IPv4off; }
/* * parse a v4 ip address/mask in cidr format */ char* v4parsecidr(uint8_t *addr, uint8_t *mask, char *from) { int i; char *p; uint8_t *a; p = v4parseip(addr, from); if(*p == '/'){ /* as a number of prefix bits */ i = strtoul(p+1, &p, 0); if(i > 32) i = 32; memset(mask, 0, IPv4addrlen); for(a = mask; i >= 8; i -= 8) *a++ = 0xff; if(i > 0) *a = ~((1<<(8-i))-1); } else memcpy(mask, defmask(addr), IPv4addrlen); return p; }
/* * 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; }
/* * add an address to an interface. */ char* ipifcadd(Ipifc *ifc, char **argv, int argc, int tentative, Iplifc *lifcp) { int i, type, mtu, sendnbrdisc = 0; uint8_t ip[IPaddrlen], mask[IPaddrlen], rem[IPaddrlen]; uint8_t bcast[IPaddrlen], net[IPaddrlen]; Iplifc *lifc, **l; Fs *f; if(ifc->medium == nil) return "ipifc not yet bound to device"; f = ifc->conv->p->f; type = Rifc; memset(ip, 0, IPaddrlen); memset(mask, 0, IPaddrlen); memset(rem, 0, IPaddrlen); switch(argc){ case 6: if(strcmp(argv[5], "proxy") == 0) type |= Rproxy; /* fall through */ case 5: mtu = strtoul(argv[4], 0, 0); if(mtu >= ifc->medium->mintu && mtu <= ifc->medium->maxtu) ifc->maxtu = mtu; /* fall through */ case 4: if (parseip(ip, argv[1]) == -1 || parseip(rem, argv[3]) == -1) return Ebadip; parseipmask(mask, argv[2]); maskip(rem, mask, net); break; case 3: if (parseip(ip, argv[1]) == -1) return Ebadip; parseipmask(mask, argv[2]); maskip(ip, mask, rem); maskip(rem, mask, net); break; case 2: if (parseip(ip, argv[1]) == -1) return Ebadip; memmove(mask, defmask(ip), IPaddrlen); maskip(ip, mask, rem); maskip(rem, mask, net); break; default: return Ebadarg; } if(isv4(ip)) tentative = 0; wlock(ifc); /* ignore if this is already a local address for this ifc */ for(lifc = ifc->lifc; lifc; lifc = lifc->next) { if(ipcmp(lifc->local, ip) == 0) { if(lifc->tentative != tentative) lifc->tentative = tentative; if(lifcp) { lifc->onlink = lifcp->onlink; lifc->autoflag = lifcp->autoflag; lifc->validlt = lifcp->validlt; lifc->preflt = lifcp->preflt; lifc->origint = lifcp->origint; } goto out; } } /* add the address to the list of logical ifc's for this ifc */ lifc = smalloc(sizeof(Iplifc)); ipmove(lifc->local, ip); ipmove(lifc->mask, mask); ipmove(lifc->remote, rem); ipmove(lifc->net, net); lifc->tentative = tentative; if(lifcp) { lifc->onlink = lifcp->onlink; lifc->autoflag = lifcp->autoflag; lifc->validlt = lifcp->validlt; lifc->preflt = lifcp->preflt; lifc->origint = lifcp->origint; } else { /* default values */ lifc->onlink = lifc->autoflag = 1; lifc->validlt = lifc->preflt = ~0L; lifc->origint = NOW / 1000; } lifc->next = nil; for(l = &ifc->lifc; *l; l = &(*l)->next) ; *l = lifc; /* check for point-to-point interface */ if(ipcmp(ip, v6loopback)) /* skip v6 loopback, it's a special address */ if(ipcmp(mask, IPallbits) == 0) type |= Rptpt; /* add local routes */ if(isv4(ip)) v4addroute(f, tifc, rem+IPv4off, mask+IPv4off, rem+IPv4off, type); else v6addroute(f, tifc, rem, mask, rem, type); addselfcache(f, ifc, lifc, ip, Runi); if((type & (Rproxy|Rptpt)) == (Rproxy|Rptpt)){ ipifcregisterproxy(f, ifc, rem); goto out; } if(isv4(ip) || ipcmp(ip, IPnoaddr) == 0) { /* add subnet directed broadcast address to the self cache */ for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) | ~mask[i]; addselfcache(f, ifc, lifc, bcast, Rbcast); /* add subnet directed network address to the self cache */ for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) & mask[i]; addselfcache(f, ifc, lifc, bcast, Rbcast); /* add network directed broadcast address to the self cache */ memmove(mask, defmask(ip), IPaddrlen); for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) | ~mask[i]; addselfcache(f, ifc, lifc, bcast, Rbcast); /* add network directed network address to the self cache */ memmove(mask, defmask(ip), IPaddrlen); for(i = 0; i < IPaddrlen; i++) bcast[i] = (ip[i] & mask[i]) & mask[i]; addselfcache(f, ifc, lifc, bcast, Rbcast); addselfcache(f, ifc, lifc, IPv4bcast, Rbcast); } else { if(ipcmp(ip, v6loopback) == 0) { /* add node-local mcast address */ addselfcache(f, ifc, lifc, v6allnodesN, Rmulti); /* add route for all node multicast */ v6addroute(f, tifc, v6allnodesN, v6allnodesNmask, v6allnodesN, Rmulti); } /* add all nodes multicast address */ addselfcache(f, ifc, lifc, v6allnodesL, Rmulti); /* add route for all nodes multicast */ v6addroute(f, tifc, v6allnodesL, v6allnodesLmask, v6allnodesL, Rmulti); /* add solicited-node multicast address */ ipv62smcast(bcast, ip); addselfcache(f, ifc, lifc, bcast, Rmulti); sendnbrdisc = 1; } /* register the address on this network for address resolution */ if(isv4(ip) && ifc->medium->areg != nil) (*ifc->medium->areg)(ifc, ip); out: wunlock(ifc); if(tentative && sendnbrdisc) icmpns(f, 0, SRC_UNSPEC, ip, TARG_MULTI, ifc->mac); return nil; }