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