xref: /plan9/sys/src/cmd/ip/dhcpd/ndb.c (revision 3b86f2f88bade1f00206c7aa750b7add255f5724)
1 /*
2  *  this currently only works for ethernet bootp's -- presotto
3  */
4 #include <u.h>
5 #include <libc.h>
6 #include <ip.h>
7 #include <bio.h>
8 #include <ndb.h>
9 #include "dat.h"
10 
11 static Ndb *db;
12 char *ndbfile;
13 
14 /*
15  * open ndbfile as db if not already open.  also check for stale data
16  * and reload as needed.
17  */
18 static Ndb *
opendb(void)19 opendb(void)
20 {
21 	static ulong lastcheck;
22 
23 	/* check no more often than once every minute */
24 	if(db == nil) {
25 		db = ndbopen(ndbfile);
26 		if(db != nil)
27 			lastcheck = now;
28 	} else if(now >= lastcheck + 60) {
29 		if (ndbchanged(db))
30 			ndbreopen(db);
31 		lastcheck = now;
32 	}
33 	return db;
34 }
35 
36 Iplifc*
findlifc(uchar * ip)37 findlifc(uchar *ip)
38 {
39 	uchar x[IPaddrlen];
40 	Ipifc *ifc;
41 	Iplifc *lifc;
42 
43 	for(ifc = ipifcs; ifc; ifc = ifc->next){
44 		for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next){
45 			if(lifc->net[0] == 0)
46 				continue;
47 			maskip(ip, lifc->mask, x);
48 			if(memcmp(x, lifc->net, IPaddrlen) == 0)
49 				return lifc;
50 		}
51 	}
52 	return nil;
53 }
54 
55 int
forme(uchar * ip)56 forme(uchar *ip)
57 {
58 	Ipifc *ifc;
59 	Iplifc *lifc;
60 
61 	for(ifc = ipifcs; ifc; ifc = ifc->next){
62 		for(lifc = ifc->lifc; lifc != nil; lifc = lifc->next)
63 			if(memcmp(ip, lifc->ip, IPaddrlen) == 0)
64 				return 1;
65 	}
66 	return 0;
67 }
68 
69 uchar noetheraddr[6];
70 
71 static void
setipaddr(uchar * addr,char * ip)72 setipaddr(uchar *addr, char *ip)
73 {
74 	if(ipcmp(addr, IPnoaddr) == 0)
75 		parseip(addr, ip);
76 }
77 
78 static void
setipmask(uchar * mask,char * ip)79 setipmask(uchar *mask, char *ip)
80 {
81 	if(ipcmp(mask, IPnoaddr) == 0)
82 		parseipmask(mask, ip);
83 }
84 
85 /*
86  *  do an ipinfo with defaults
87  */
88 int
lookupip(uchar * ipaddr,Info * iip,int gate)89 lookupip(uchar *ipaddr, Info *iip, int gate)
90 {
91 	char ip[32];
92 	Ndbtuple *t, *nt;
93 	char *attrs[32], **p;
94 
95 	if(opendb() == nil){
96 		warning(1, "can't open db");
97 		return -1;
98 	}
99 
100 	p = attrs;
101 	*p++ = "ip";
102 	*p++ = "ipmask";
103 	*p++ = "@ipgw";
104 	if(!gate){
105 		*p++ = "bootf";
106 		*p++ = "bootf2";
107 		*p++ = "@tftp";
108 		*p++ = "@tftp2";
109 		*p++ = "rootpath";
110 		*p++ = "dhcp";
111 		*p++ = "vendorclass";
112 		*p++ = "ether";
113 		*p++ = "dom";
114 		*p++ = "@fs";
115 		*p++ = "@auth";
116 	}
117 	*p = 0;
118 
119 	memset(iip, 0, sizeof(*iip));
120 	snprint(ip, sizeof(ip), "%I", ipaddr);
121 	t = ndbipinfo(db, "ip", ip, attrs, p - attrs);
122 	if(t == nil)
123 		return -1;
124 
125 	for(nt = t; nt != nil; nt = nt->entry){
126 		if(strcmp(nt->attr, "ip") == 0)
127 			setipaddr(iip->ipaddr, nt->val);
128 		else
129 		if(strcmp(nt->attr, "ipmask") == 0)
130 			setipmask(iip->ipmask, nt->val);
131 		else
132 		if(strcmp(nt->attr, "fs") == 0)
133 			setipaddr(iip->fsip, nt->val);
134 		else
135 		if(strcmp(nt->attr, "auth") == 0)
136 			setipaddr(iip->auip, nt->val);
137 		else
138 		if(strcmp(nt->attr, "tftp") == 0)
139 			setipaddr(iip->tftp, nt->val);
140 		else
141 		if(strcmp(nt->attr, "tftp2") == 0)
142 			setipaddr(iip->tftp2, nt->val);
143 		else
144 		if(strcmp(nt->attr, "ipgw") == 0)
145 			setipaddr(iip->gwip, nt->val);
146 		else
147 		if(strcmp(nt->attr, "ether") == 0){
148 			/*
149 			 * this is probably wrong for machines with multiple
150 			 * ethers.  bootp or dhcp requests could come from any
151 			 * of the ethers listed in the ndb entry.
152 			 */
153 			if(memcmp(iip->etheraddr, noetheraddr, 6) == 0)
154 				parseether(iip->etheraddr, nt->val);
155 			iip->indb = 1;
156 		}
157 		else
158 		if(strcmp(nt->attr, "dhcp") == 0){
159 			if(iip->dhcpgroup[0] == 0)
160 				strcpy(iip->dhcpgroup, nt->val);
161 		}
162 		else
163 		if(strcmp(nt->attr, "bootf") == 0){
164 			if(iip->bootf[0] == 0)
165 				strcpy(iip->bootf, nt->val);
166 		}
167 		else
168 		if(strcmp(nt->attr, "bootf2") == 0){
169 			if(iip->bootf2[0] == 0)
170 				strcpy(iip->bootf2, nt->val);
171 		}
172 		else
173 		if(strcmp(nt->attr, "vendor") == 0){
174 			if(iip->vendor[0] == 0)
175 				strcpy(iip->vendor, nt->val);
176 		}
177 		else
178 		if(strcmp(nt->attr, "dom") == 0){
179 			if(iip->domain[0] == 0)
180 				strcpy(iip->domain, nt->val);
181 		}
182 		else
183 		if(strcmp(nt->attr, "rootpath") == 0){
184 			if(iip->rootpath[0] == 0)
185 				strcpy(iip->rootpath, nt->val);
186 		}
187 	}
188 	ndbfree(t);
189 	maskip(iip->ipaddr, iip->ipmask, iip->ipnet);
190 	return 0;
191 }
192 
193 static uchar zeroes[6];
194 
195 /*
196  *  lookup info about a client in the database.  Find an address on the
197  *  same net as riip.
198  */
199 int
lookup(Bootp * bp,Info * iip,Info * riip)200 lookup(Bootp *bp, Info *iip, Info *riip)
201 {
202 	Ndbtuple *t, *nt;
203 	Ndbs s;
204 	char *hwattr;
205 	char *hwval, hwbuf[33];
206 	uchar ciaddr[IPaddrlen];
207 
208 	if(opendb() == nil){
209 		warning(1, "can't open db");
210 		return -1;
211 	}
212 
213 	memset(iip, 0, sizeof(*iip));
214 
215 	/* client knows its address? */
216 	v4tov6(ciaddr, bp->ciaddr);
217 	if(validip(ciaddr)){
218 		if(lookupip(ciaddr, iip, 0) < 0) {
219 			if (debug)
220 				warning(0, "don't know %I", ciaddr);
221 			return -1;	/* don't know anything about it */
222 		}
223 		if(!samenet(riip->ipaddr, iip)){
224 			warning(0, "%I not on %I", ciaddr, riip->ipnet);
225 			return -1;
226 		}
227 
228 		/*
229 		 *  see if this is a masquerade, i.e., if the ether
230 		 *  address doesn't match what we expected it to be.
231 		 */
232 		if(memcmp(iip->etheraddr, zeroes, 6) != 0)
233 		if(memcmp(bp->chaddr, iip->etheraddr, 6) != 0)
234 			warning(0, "ciaddr %I rcvd from %E instead of %E",
235 				ciaddr, bp->chaddr, iip->etheraddr);
236 
237 		return 0;
238 	}
239 
240 	if(bp->hlen > Maxhwlen)
241 		return -1;
242 	switch(bp->htype){
243 	case 1:
244 		hwattr = "ether";
245 		hwval = hwbuf;
246 		snprint(hwbuf, sizeof(hwbuf), "%E", bp->chaddr);
247 		break;
248 	default:
249 		syslog(0, blog, "not ethernet %E, htype %d, hlen %d",
250 			bp->chaddr, bp->htype, bp->hlen);
251 		return -1;
252 	}
253 
254 	/*
255 	 *  use hardware address to find an ip address on
256 	 *  same net as riip
257 	 */
258 	t = ndbsearch(db, &s, hwattr, hwval);
259 	while(t){
260 		for(nt = t; nt; nt = nt->entry){
261 			if(strcmp(nt->attr, "ip") != 0)
262 				continue;
263 			parseip(ciaddr, nt->val);
264 			if(lookupip(ciaddr, iip, 0) < 0)
265 				continue;
266 			if(samenet(riip->ipaddr, iip)){
267 				ndbfree(t);
268 				return 0;
269 			}
270 		}
271 		ndbfree(t);
272 		t = ndbsnext(&s, hwattr, hwval);
273 	}
274 	return -1;
275 }
276 
277 /*
278  *  interface to ndbipinfo
279  */
280 Ndbtuple*
lookupinfo(uchar * ipaddr,char ** attr,int n)281 lookupinfo(uchar *ipaddr, char **attr, int n)
282 {
283 	char ip[32];
284 
285 	sprint(ip, "%I", ipaddr);
286 	return ndbipinfo(db, "ip", ip, attr, n);
287 }
288 
289 /*
290  *  return the ip addresses for a type of server for system ip
291  */
292 int
lookupserver(char * attr,uchar ** ipaddrs,Ndbtuple * t)293 lookupserver(char *attr, uchar **ipaddrs, Ndbtuple *t)
294 {
295 	Ndbtuple *nt;
296 	int rv = 0;
297 
298 	for(nt = t; rv < 2 && nt != nil; nt = nt->entry)
299 		if(strcmp(nt->attr, attr) == 0){
300 			parseip(ipaddrs[rv], nt->val);
301 			rv++;
302 		}
303 	return rv;
304 }
305 
306 /*
307  *  just lookup the name
308  */
309 void
lookupname(char * val,Ndbtuple * t)310 lookupname(char *val, Ndbtuple *t)
311 {
312 	Ndbtuple *nt;
313 
314 	for(nt = t; nt != nil; nt = nt->entry)
315 		if(strcmp(nt->attr, "dom") == 0){
316 			strcpy(val, nt->val);
317 			break;
318 		}
319 }
320