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