xref: /plan9/sys/src/cmd/ip/dhcpd/ndb.c (revision 3b86f2f88bade1f00206c7aa750b7add255f5724)
17dd7cddfSDavid du Colombier /*
27dd7cddfSDavid du Colombier  *  this currently only works for ethernet bootp's -- presotto
37dd7cddfSDavid du Colombier  */
47dd7cddfSDavid du Colombier #include <u.h>
57dd7cddfSDavid du Colombier #include <libc.h>
67dd7cddfSDavid du Colombier #include <ip.h>
77dd7cddfSDavid du Colombier #include <bio.h>
87dd7cddfSDavid du Colombier #include <ndb.h>
97dd7cddfSDavid du Colombier #include "dat.h"
107dd7cddfSDavid du Colombier 
11*3b86f2f8SDavid du Colombier static Ndb *db;
127dd7cddfSDavid du Colombier char *ndbfile;
137dd7cddfSDavid du Colombier 
14*3b86f2f8SDavid du Colombier /*
15*3b86f2f8SDavid du Colombier  * open ndbfile as db if not already open.  also check for stale data
16*3b86f2f8SDavid du Colombier  * and reload as needed.
17*3b86f2f8SDavid du Colombier  */
18*3b86f2f8SDavid du Colombier static Ndb *
opendb(void)19*3b86f2f8SDavid du Colombier opendb(void)
20*3b86f2f8SDavid du Colombier {
21*3b86f2f8SDavid du Colombier 	static ulong lastcheck;
22*3b86f2f8SDavid du Colombier 
23*3b86f2f8SDavid du Colombier 	/* check no more often than once every minute */
24*3b86f2f8SDavid du Colombier 	if(db == nil) {
25*3b86f2f8SDavid du Colombier 		db = ndbopen(ndbfile);
26*3b86f2f8SDavid du Colombier 		if(db != nil)
27*3b86f2f8SDavid du Colombier 			lastcheck = now;
28*3b86f2f8SDavid du Colombier 	} else if(now >= lastcheck + 60) {
29*3b86f2f8SDavid du Colombier 		if (ndbchanged(db))
30*3b86f2f8SDavid du Colombier 			ndbreopen(db);
31*3b86f2f8SDavid du Colombier 		lastcheck = now;
32*3b86f2f8SDavid du Colombier 	}
33*3b86f2f8SDavid du Colombier 	return db;
34*3b86f2f8SDavid du Colombier }
35*3b86f2f8SDavid du Colombier 
369a747e4fSDavid du Colombier Iplifc*
findlifc(uchar * ip)379a747e4fSDavid du Colombier findlifc(uchar *ip)
387dd7cddfSDavid du Colombier {
397dd7cddfSDavid du Colombier 	uchar x[IPaddrlen];
407dd7cddfSDavid du Colombier 	Ipifc *ifc;
419a747e4fSDavid du Colombier 	Iplifc *lifc;
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier 	for(ifc = ipifcs; ifc; ifc = ifc->next){
449a747e4fSDavid du Colombier 		for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
459a747e4fSDavid du Colombier 			if(lifc->net[0] == 0)
467dd7cddfSDavid du Colombier 				continue;
479a747e4fSDavid du Colombier 			maskip(ip, lifc->mask, x);
489a747e4fSDavid du Colombier 			if(memcmp(x, lifc->net, IPaddrlen) == 0)
499a747e4fSDavid du Colombier 				return lifc;
507dd7cddfSDavid du Colombier 		}
519a747e4fSDavid du Colombier 	}
529a747e4fSDavid du Colombier 	return nil;
537dd7cddfSDavid du Colombier }
547dd7cddfSDavid du Colombier 
559a747e4fSDavid du Colombier int
forme(uchar * ip)567dd7cddfSDavid du Colombier forme(uchar *ip)
577dd7cddfSDavid du Colombier {
587dd7cddfSDavid du Colombier 	Ipifc *ifc;
599a747e4fSDavid du Colombier 	Iplifc *lifc;
607dd7cddfSDavid du Colombier 
617dd7cddfSDavid du Colombier 	for(ifc = ipifcs; ifc; ifc = ifc->next){
629a747e4fSDavid du Colombier 		for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
639a747e4fSDavid du Colombier 			if(memcmp(ip, lifc->ip, IPaddrlen) == 0)
649a747e4fSDavid du Colombier 				return 1;
657dd7cddfSDavid du Colombier 	}
667dd7cddfSDavid du Colombier 	return 0;
677dd7cddfSDavid du Colombier }
687dd7cddfSDavid du Colombier 
697dd7cddfSDavid du Colombier uchar noetheraddr[6];
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier static void
setipaddr(uchar * addr,char * ip)727dd7cddfSDavid du Colombier setipaddr(uchar *addr, char *ip)
737dd7cddfSDavid du Colombier {
747dd7cddfSDavid du Colombier 	if(ipcmp(addr, IPnoaddr) == 0)
757dd7cddfSDavid du Colombier 		parseip(addr, ip);
767dd7cddfSDavid du Colombier }
777dd7cddfSDavid du Colombier 
787dd7cddfSDavid du Colombier static void
setipmask(uchar * mask,char * ip)797dd7cddfSDavid du Colombier setipmask(uchar *mask, char *ip)
807dd7cddfSDavid du Colombier {
817dd7cddfSDavid du Colombier 	if(ipcmp(mask, IPnoaddr) == 0)
827dd7cddfSDavid du Colombier 		parseipmask(mask, ip);
837dd7cddfSDavid du Colombier }
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier /*
867dd7cddfSDavid du Colombier  *  do an ipinfo with defaults
877dd7cddfSDavid du Colombier  */
887dd7cddfSDavid du Colombier int
lookupip(uchar * ipaddr,Info * iip,int gate)893ff48bf5SDavid du Colombier lookupip(uchar *ipaddr, Info *iip, int gate)
907dd7cddfSDavid du Colombier {
917dd7cddfSDavid du Colombier 	char ip[32];
927dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
937dd7cddfSDavid du Colombier 	char *attrs[32], **p;
947dd7cddfSDavid du Colombier 
95*3b86f2f8SDavid du Colombier 	if(opendb() == nil){
968c6ab946SDavid du Colombier 		warning(1, "can't open db");
977dd7cddfSDavid du Colombier 		return -1;
987dd7cddfSDavid du Colombier 	}
997dd7cddfSDavid du Colombier 
1007dd7cddfSDavid du Colombier 	p = attrs;
1017dd7cddfSDavid du Colombier 	*p++ = "ip";
1027dd7cddfSDavid du Colombier 	*p++ = "ipmask";
1033ff48bf5SDavid du Colombier 	*p++ = "@ipgw";
1043ff48bf5SDavid du Colombier 	if(!gate){
1057dd7cddfSDavid du Colombier 		*p++ = "bootf";
106da51d93aSDavid du Colombier 		*p++ = "bootf2";
1073ff48bf5SDavid du Colombier 		*p++ = "@tftp";
108da51d93aSDavid du Colombier 		*p++ = "@tftp2";
1099a747e4fSDavid du Colombier 		*p++ = "rootpath";
1107dd7cddfSDavid du Colombier 		*p++ = "dhcp";
11139734e7eSDavid du Colombier 		*p++ = "vendorclass";
1127dd7cddfSDavid du Colombier 		*p++ = "ether";
1137dd7cddfSDavid du Colombier 		*p++ = "dom";
1147dd7cddfSDavid du Colombier 		*p++ = "@fs";
1157dd7cddfSDavid du Colombier 		*p++ = "@auth";
1163ff48bf5SDavid du Colombier 	}
1177dd7cddfSDavid du Colombier 	*p = 0;
1187dd7cddfSDavid du Colombier 
1197dd7cddfSDavid du Colombier 	memset(iip, 0, sizeof(*iip));
1207dd7cddfSDavid du Colombier 	snprint(ip, sizeof(ip), "%I", ipaddr);
1217dd7cddfSDavid du Colombier 	t = ndbipinfo(db, "ip", ip, attrs, p - attrs);
1227dd7cddfSDavid du Colombier 	if(t == nil)
1237dd7cddfSDavid du Colombier 		return -1;
1247dd7cddfSDavid du Colombier 
1257dd7cddfSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry){
1267dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "ip") == 0)
1277dd7cddfSDavid du Colombier 			setipaddr(iip->ipaddr, nt->val);
1287dd7cddfSDavid du Colombier 		else
1297dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "ipmask") == 0)
1307dd7cddfSDavid du Colombier 			setipmask(iip->ipmask, nt->val);
1317dd7cddfSDavid du Colombier 		else
1327dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "fs") == 0)
1337dd7cddfSDavid du Colombier 			setipaddr(iip->fsip, nt->val);
1347dd7cddfSDavid du Colombier 		else
1357dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "auth") == 0)
1367dd7cddfSDavid du Colombier 			setipaddr(iip->auip, nt->val);
1377dd7cddfSDavid du Colombier 		else
1383ff48bf5SDavid du Colombier 		if(strcmp(nt->attr, "tftp") == 0)
1393ff48bf5SDavid du Colombier 			setipaddr(iip->tftp, nt->val);
1403ff48bf5SDavid du Colombier 		else
1413ff48bf5SDavid du Colombier 		if(strcmp(nt->attr, "tftp2") == 0)
1423ff48bf5SDavid du Colombier 			setipaddr(iip->tftp2, nt->val);
1433ff48bf5SDavid du Colombier 		else
1447dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "ipgw") == 0)
1457dd7cddfSDavid du Colombier 			setipaddr(iip->gwip, nt->val);
1467dd7cddfSDavid du Colombier 		else
1477dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "ether") == 0){
1482ddf2468SDavid du Colombier 			/*
1492ddf2468SDavid du Colombier 			 * this is probably wrong for machines with multiple
1502ddf2468SDavid du Colombier 			 * ethers.  bootp or dhcp requests could come from any
1512ddf2468SDavid du Colombier 			 * of the ethers listed in the ndb entry.
1522ddf2468SDavid du Colombier 			 */
1537dd7cddfSDavid du Colombier 			if(memcmp(iip->etheraddr, noetheraddr, 6) == 0)
1547dd7cddfSDavid du Colombier 				parseether(iip->etheraddr, nt->val);
1557dd7cddfSDavid du Colombier 			iip->indb = 1;
1567dd7cddfSDavid du Colombier 		}
1577dd7cddfSDavid du Colombier 		else
1587dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "dhcp") == 0){
1597dd7cddfSDavid du Colombier 			if(iip->dhcpgroup[0] == 0)
1607dd7cddfSDavid du Colombier 				strcpy(iip->dhcpgroup, nt->val);
1617dd7cddfSDavid du Colombier 		}
1627dd7cddfSDavid du Colombier 		else
1637dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "bootf") == 0){
1647dd7cddfSDavid du Colombier 			if(iip->bootf[0] == 0)
1657dd7cddfSDavid du Colombier 				strcpy(iip->bootf, nt->val);
1667dd7cddfSDavid du Colombier 		}
1677dd7cddfSDavid du Colombier 		else
1689a747e4fSDavid du Colombier 		if(strcmp(nt->attr, "bootf2") == 0){
1699a747e4fSDavid du Colombier 			if(iip->bootf2[0] == 0)
1709a747e4fSDavid du Colombier 				strcpy(iip->bootf2, nt->val);
1719a747e4fSDavid du Colombier 		}
1729a747e4fSDavid du Colombier 		else
1737dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "vendor") == 0){
1747dd7cddfSDavid du Colombier 			if(iip->vendor[0] == 0)
1757dd7cddfSDavid du Colombier 				strcpy(iip->vendor, nt->val);
1767dd7cddfSDavid du Colombier 		}
1777dd7cddfSDavid du Colombier 		else
1787dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "dom") == 0){
1797dd7cddfSDavid du Colombier 			if(iip->domain[0] == 0)
1807dd7cddfSDavid du Colombier 				strcpy(iip->domain, nt->val);
1817dd7cddfSDavid du Colombier 		}
1829a747e4fSDavid du Colombier 		else
1839a747e4fSDavid du Colombier 		if(strcmp(nt->attr, "rootpath") == 0){
1849a747e4fSDavid du Colombier 			if(iip->rootpath[0] == 0)
1859a747e4fSDavid du Colombier 				strcpy(iip->rootpath, nt->val);
1869a747e4fSDavid du Colombier 		}
1877dd7cddfSDavid du Colombier 	}
1887dd7cddfSDavid du Colombier 	ndbfree(t);
1897dd7cddfSDavid du Colombier 	maskip(iip->ipaddr, iip->ipmask, iip->ipnet);
1907dd7cddfSDavid du Colombier 	return 0;
1917dd7cddfSDavid du Colombier }
1927dd7cddfSDavid du Colombier 
1937dd7cddfSDavid du Colombier static uchar zeroes[6];
1947dd7cddfSDavid du Colombier 
1957dd7cddfSDavid du Colombier /*
1967dd7cddfSDavid du Colombier  *  lookup info about a client in the database.  Find an address on the
1977dd7cddfSDavid du Colombier  *  same net as riip.
1987dd7cddfSDavid du Colombier  */
1997dd7cddfSDavid du Colombier int
lookup(Bootp * bp,Info * iip,Info * riip)2007dd7cddfSDavid du Colombier lookup(Bootp *bp, Info *iip, Info *riip)
2017dd7cddfSDavid du Colombier {
2027dd7cddfSDavid du Colombier 	Ndbtuple *t, *nt;
2037dd7cddfSDavid du Colombier 	Ndbs s;
2047dd7cddfSDavid du Colombier 	char *hwattr;
2057dd7cddfSDavid du Colombier 	char *hwval, hwbuf[33];
2067dd7cddfSDavid du Colombier 	uchar ciaddr[IPaddrlen];
2077dd7cddfSDavid du Colombier 
208*3b86f2f8SDavid du Colombier 	if(opendb() == nil){
2098c6ab946SDavid du Colombier 		warning(1, "can't open db");
2107dd7cddfSDavid du Colombier 		return -1;
2117dd7cddfSDavid du Colombier 	}
2127dd7cddfSDavid du Colombier 
2137dd7cddfSDavid du Colombier 	memset(iip, 0, sizeof(*iip));
2147dd7cddfSDavid du Colombier 
2157dd7cddfSDavid du Colombier 	/* client knows its address? */
2167dd7cddfSDavid du Colombier 	v4tov6(ciaddr, bp->ciaddr);
2177dd7cddfSDavid du Colombier 	if(validip(ciaddr)){
2180a84db5eSDavid du Colombier 		if(lookupip(ciaddr, iip, 0) < 0) {
2190a84db5eSDavid du Colombier 			if (debug)
2200a84db5eSDavid du Colombier 				warning(0, "don't know %I", ciaddr);
2217dd7cddfSDavid du Colombier 			return -1;	/* don't know anything about it */
2220a84db5eSDavid du Colombier 		}
2237dd7cddfSDavid du Colombier 		if(!samenet(riip->ipaddr, iip)){
2247dd7cddfSDavid du Colombier 			warning(0, "%I not on %I", ciaddr, riip->ipnet);
2257dd7cddfSDavid du Colombier 			return -1;
2267dd7cddfSDavid du Colombier 		}
2277dd7cddfSDavid du Colombier 
2287dd7cddfSDavid du Colombier 		/*
2297dd7cddfSDavid du Colombier 		 *  see if this is a masquerade, i.e., if the ether
2307dd7cddfSDavid du Colombier 		 *  address doesn't match what we expected it to be.
2317dd7cddfSDavid du Colombier 		 */
2327dd7cddfSDavid du Colombier 		if(memcmp(iip->etheraddr, zeroes, 6) != 0)
2337dd7cddfSDavid du Colombier 		if(memcmp(bp->chaddr, iip->etheraddr, 6) != 0)
2347dd7cddfSDavid du Colombier 			warning(0, "ciaddr %I rcvd from %E instead of %E",
2357dd7cddfSDavid du Colombier 				ciaddr, bp->chaddr, iip->etheraddr);
2367dd7cddfSDavid du Colombier 
2377dd7cddfSDavid du Colombier 		return 0;
2387dd7cddfSDavid du Colombier 	}
2397dd7cddfSDavid du Colombier 
2407dd7cddfSDavid du Colombier 	if(bp->hlen > Maxhwlen)
2417dd7cddfSDavid du Colombier 		return -1;
2427dd7cddfSDavid du Colombier 	switch(bp->htype){
2437dd7cddfSDavid du Colombier 	case 1:
2447dd7cddfSDavid du Colombier 		hwattr = "ether";
2457dd7cddfSDavid du Colombier 		hwval = hwbuf;
2467dd7cddfSDavid du Colombier 		snprint(hwbuf, sizeof(hwbuf), "%E", bp->chaddr);
2477dd7cddfSDavid du Colombier 		break;
2487dd7cddfSDavid du Colombier 	default:
2497dd7cddfSDavid du Colombier 		syslog(0, blog, "not ethernet %E, htype %d, hlen %d",
2507dd7cddfSDavid du Colombier 			bp->chaddr, bp->htype, bp->hlen);
2517dd7cddfSDavid du Colombier 		return -1;
2527dd7cddfSDavid du Colombier 	}
2537dd7cddfSDavid du Colombier 
2547dd7cddfSDavid du Colombier 	/*
2557dd7cddfSDavid du Colombier 	 *  use hardware address to find an ip address on
2567dd7cddfSDavid du Colombier 	 *  same net as riip
2577dd7cddfSDavid du Colombier 	 */
2587dd7cddfSDavid du Colombier 	t = ndbsearch(db, &s, hwattr, hwval);
2597dd7cddfSDavid du Colombier 	while(t){
2607dd7cddfSDavid du Colombier 		for(nt = t; nt; nt = nt->entry){
2617dd7cddfSDavid du Colombier 			if(strcmp(nt->attr, "ip") != 0)
2627dd7cddfSDavid du Colombier 				continue;
2637dd7cddfSDavid du Colombier 			parseip(ciaddr, nt->val);
2643ff48bf5SDavid du Colombier 			if(lookupip(ciaddr, iip, 0) < 0)
2657dd7cddfSDavid du Colombier 				continue;
2667dd7cddfSDavid du Colombier 			if(samenet(riip->ipaddr, iip)){
2677dd7cddfSDavid du Colombier 				ndbfree(t);
2687dd7cddfSDavid du Colombier 				return 0;
2697dd7cddfSDavid du Colombier 			}
2707dd7cddfSDavid du Colombier 		}
2717dd7cddfSDavid du Colombier 		ndbfree(t);
2727dd7cddfSDavid du Colombier 		t = ndbsnext(&s, hwattr, hwval);
2737dd7cddfSDavid du Colombier 	}
2747dd7cddfSDavid du Colombier 	return -1;
2757dd7cddfSDavid du Colombier }
2767dd7cddfSDavid du Colombier 
2777dd7cddfSDavid du Colombier /*
2783ff48bf5SDavid du Colombier  *  interface to ndbipinfo
2793ff48bf5SDavid du Colombier  */
2803ff48bf5SDavid du Colombier Ndbtuple*
lookupinfo(uchar * ipaddr,char ** attr,int n)2813ff48bf5SDavid du Colombier lookupinfo(uchar *ipaddr, char **attr, int n)
2823ff48bf5SDavid du Colombier {
2833ff48bf5SDavid du Colombier 	char ip[32];
2843ff48bf5SDavid du Colombier 
2853ff48bf5SDavid du Colombier 	sprint(ip, "%I", ipaddr);
2863ff48bf5SDavid du Colombier 	return ndbipinfo(db, "ip", ip, attr, n);
2873ff48bf5SDavid du Colombier }
2883ff48bf5SDavid du Colombier 
2893ff48bf5SDavid du Colombier /*
2907dd7cddfSDavid du Colombier  *  return the ip addresses for a type of server for system ip
2917dd7cddfSDavid du Colombier  */
2927dd7cddfSDavid du Colombier int
lookupserver(char * attr,uchar ** ipaddrs,Ndbtuple * t)2933ff48bf5SDavid du Colombier lookupserver(char *attr, uchar **ipaddrs, Ndbtuple *t)
2947dd7cddfSDavid du Colombier {
2953ff48bf5SDavid du Colombier 	Ndbtuple *nt;
2967dd7cddfSDavid du Colombier 	int rv = 0;
2977dd7cddfSDavid du Colombier 
2987dd7cddfSDavid du Colombier 	for(nt = t; rv < 2 && nt != nil; nt = nt->entry)
2997dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, attr) == 0){
3007dd7cddfSDavid du Colombier 			parseip(ipaddrs[rv], nt->val);
3017dd7cddfSDavid du Colombier 			rv++;
3027dd7cddfSDavid du Colombier 		}
3037dd7cddfSDavid du Colombier 	return rv;
3047dd7cddfSDavid du Colombier }
3057dd7cddfSDavid du Colombier 
3067dd7cddfSDavid du Colombier /*
3077dd7cddfSDavid du Colombier  *  just lookup the name
3087dd7cddfSDavid du Colombier  */
3097dd7cddfSDavid du Colombier void
lookupname(char * val,Ndbtuple * t)3103ff48bf5SDavid du Colombier lookupname(char *val, Ndbtuple *t)
3117dd7cddfSDavid du Colombier {
3123ff48bf5SDavid du Colombier 	Ndbtuple *nt;
3137dd7cddfSDavid du Colombier 
3147dd7cddfSDavid du Colombier 	for(nt = t; nt != nil; nt = nt->entry)
3157dd7cddfSDavid du Colombier 		if(strcmp(nt->attr, "dom") == 0){
3167dd7cddfSDavid du Colombier 			strcpy(val, nt->val);
3177dd7cddfSDavid du Colombier 			break;
3187dd7cddfSDavid du Colombier 		}
3193ff48bf5SDavid du Colombier }
320