ipconfig.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515
  1. #include <u.h>
  2. #include <libc.h>
  3. #include <ip.h>
  4. #include <bio.h>
  5. #include <ndb.h>
  6. #include "dhcp.h"
  7. int noconfig;
  8. int debug;
  9. int dodhcp;
  10. int nip;
  11. int myifc = -1;
  12. int plan9 = 1;
  13. int beprimary = -1;
  14. int nodhcpwatch;
  15. int sendhostname;
  16. int dondbconfig = 0;
  17. Ipifc *ifc;
  18. // possible verbs
  19. enum
  20. {
  21. Vadd,
  22. Vremove,
  23. Vunbind,
  24. Vether,
  25. Vloopback,
  26. };
  27. struct {
  28. // locally generated
  29. char *type;
  30. char *dev;
  31. char mpoint[32];
  32. int cfd; // ifc control channel
  33. int dfd; // ifc data channel (for ppp)
  34. char *cputype;
  35. uchar hwa[32]; // hardware address
  36. int hwatype;
  37. int hwalen;
  38. uchar cid[32];
  39. int cidlen;
  40. char *baud;
  41. // learned info
  42. uchar gaddr[IPaddrlen];
  43. uchar laddr[IPaddrlen];
  44. uchar mask[IPaddrlen];
  45. uchar raddr[IPaddrlen];
  46. uchar dns[2*IPaddrlen];
  47. uchar fs[2*IPaddrlen];
  48. uchar auth[2*IPaddrlen];
  49. uchar ntp[IPaddrlen];
  50. int mtu;
  51. // dhcp specific
  52. int state;
  53. int fd;
  54. ulong xid;
  55. ulong starttime;
  56. char sname[64];
  57. char hostname[32];
  58. char domainname[64];
  59. uchar server[IPaddrlen]; /* server IP address */
  60. ulong offered; /* offered lease time */
  61. ulong lease; /* lease time */
  62. ulong resend; /* number of resends for current state */
  63. ulong timeout; /* time to timeout - seconds */
  64. } conf;
  65. void adddefroute(char*, uchar*);
  66. void binddevice(void);
  67. void controldevice(void);
  68. void bootprequest(void);
  69. void dhcprecv(void);
  70. void dhcpsend(int);
  71. int dhcptimer(void);
  72. void dhcpquery(int, int);
  73. void dhcpwatch(int);
  74. int getndb(void);
  75. int ipconfig(void);
  76. void lookforip(char*);
  77. uchar *optadd(uchar*, int, void*, int);
  78. uchar *optaddbyte(uchar*, int, int);
  79. uchar *optaddulong(uchar*, int, ulong);
  80. uchar *optaddaddr(uchar*, int, uchar*);
  81. uchar *optaddstr(uchar*, int, char*);
  82. uchar *optaddvec(uchar*, int, uchar*, int);
  83. uchar *optget(uchar*, int, int*);
  84. int optgetbyte(uchar*, int);
  85. ulong optgetulong(uchar*, int);
  86. int optgetaddr(uchar*, int, uchar*);
  87. int optgetaddrs(uchar*, int, uchar*, int);
  88. int optgetstr(uchar*, int, char*, int);
  89. int optgetvec(uchar*, int, uchar*, int);
  90. void mkclientid(void);
  91. int nipifcs(char*);
  92. int openlisten(void);
  93. int parseoptions(uchar *p, int n);
  94. Bootp *parsebootp(uchar*, int);
  95. void putndb(void);
  96. void tweakservers(void);
  97. void writendb(char*, int, int);
  98. void usage(void);
  99. int validip(uchar*);
  100. int parseverb(char*);
  101. void doadd(int);
  102. void doremove(void);
  103. void dounbind(void);
  104. void ndbconfig(void);
  105. char optmagic[4] = { 0x63, 0x82, 0x53, 0x63 };
  106. #define DEBUG if(debug)print
  107. typedef struct Ctl Ctl;
  108. struct Ctl
  109. {
  110. Ctl *next;
  111. char *ctl;
  112. };
  113. Ctl *firstctl, **ctll;
  114. void
  115. usage(void)
  116. {
  117. fprint(2, "usage: %s [-ndDrGX] [-x netmtpt] [-m mtu] [-b baud] [-g gateway] [-h hostname] [-c control-string]* type device [verb] [localaddr [mask [remoteaddr [fsaddr [authaddr]]]]]\n", argv0);
  118. exits("usage");
  119. }
  120. void
  121. main(int argc, char **argv)
  122. {
  123. char *p;
  124. int retry, verb, action;
  125. Ctl *cp;
  126. srand(truerand());
  127. fmtinstall('E', eipfmt);
  128. fmtinstall('I', eipfmt);
  129. fmtinstall('M', eipfmt);
  130. fmtinstall('V', eipfmt);
  131. setnetmtpt(conf.mpoint, sizeof(conf.mpoint), nil);
  132. conf.cputype = getenv("cputype");
  133. if(conf.cputype == nil)
  134. conf.cputype = "386";
  135. retry = 0;
  136. ctll = &firstctl;
  137. ARGBEGIN {
  138. case 'D':
  139. debug = 1;
  140. break;
  141. case 'G':
  142. plan9 = 0;
  143. break;
  144. case 'N':
  145. dondbconfig = 1;
  146. break;
  147. case 'p':
  148. beprimary = 1;
  149. break;
  150. case 'P':
  151. beprimary = 0;
  152. case 'b':
  153. p = ARGF();
  154. if(p == nil)
  155. usage();
  156. conf.baud = p;
  157. break;
  158. case 'c':
  159. p = ARGF();
  160. if(p == nil)
  161. usage();
  162. cp = malloc(sizeof(*cp));
  163. if(cp == nil)
  164. sysfatal("%r");
  165. *ctll = cp;
  166. ctll = &cp->next;
  167. cp->next = nil;
  168. cp->ctl = p;
  169. break;
  170. case 'd':
  171. dodhcp = 1;
  172. break;
  173. case 'g':
  174. p = ARGF();
  175. if(p == nil)
  176. usage();
  177. parseip(conf.gaddr, p);
  178. break;
  179. case 'h':
  180. p = ARGF();
  181. if(p == nil)
  182. usage();
  183. snprint(conf.hostname, sizeof(conf.hostname), "%s", p);
  184. sendhostname = 1;
  185. break;
  186. case 'n':
  187. noconfig = 1;
  188. break;
  189. case 'm':
  190. p = ARGF();
  191. if(p == nil)
  192. usage();
  193. conf.mtu = atoi(p);
  194. break;
  195. case 'r':
  196. retry = 1;
  197. break;
  198. case 'x':
  199. p = ARGF();
  200. if(p == nil)
  201. usage();
  202. setnetmtpt(conf.mpoint, sizeof(conf.mpoint), p);
  203. break;
  204. case 'X':
  205. nodhcpwatch = 1;
  206. break;
  207. } ARGEND;
  208. // default to any host name we already have
  209. if(*conf.hostname == 0){
  210. p = getenv("sysname");
  211. if(p == nil || *p == 0)
  212. p = sysname();
  213. if(p != nil)
  214. strncpy(conf.hostname, p, sizeof(conf.hostname)-1);
  215. }
  216. // default
  217. conf.type = "ether";
  218. conf.dev = "/net/ether0";
  219. action = Vadd;
  220. // get verb, default is "add"
  221. while(argc > 0){
  222. verb = parseverb(argv[0]);
  223. switch(verb){
  224. case Vadd:
  225. case Vremove:
  226. case Vunbind:
  227. action = verb;
  228. break;
  229. case Vether:
  230. case Vloopback:
  231. conf.type = argv[0];
  232. if(argc > 1){
  233. conf.dev = argv[1];
  234. argc--, argv++;
  235. }
  236. break;
  237. }
  238. if(verb < 0)
  239. break;
  240. argc--, argv++;
  241. }
  242. // get addresses
  243. switch(argc){
  244. case 5:
  245. parseip(conf.auth, argv[4]);
  246. /* fall through */
  247. case 4:
  248. parseip(conf.fs, argv[3]);
  249. /* fall through */
  250. case 3:
  251. parseip(conf.raddr, argv[2]);
  252. /* fall through */
  253. case 2:
  254. parseipmask(conf.mask, argv[1]);
  255. /* fall through */
  256. case 1:
  257. parseip(conf.laddr, argv[0]);
  258. break;
  259. }
  260. switch(action){
  261. case Vadd:
  262. doadd(retry);
  263. break;
  264. case Vremove:
  265. doremove();
  266. break;
  267. case Vunbind:
  268. dounbind();
  269. break;
  270. }
  271. exits(0);
  272. }
  273. int
  274. havendb(char *net)
  275. {
  276. Dir *d;
  277. char buf[128];
  278. snprint(buf, sizeof buf, "%s/ndb", net);
  279. if((d = dirstat("/net/ndb")) == nil)
  280. return 0;
  281. if(d->length == 0){
  282. free(d);
  283. return 0;
  284. }
  285. free(d);
  286. return 1;
  287. }
  288. void
  289. doadd(int retry)
  290. {
  291. int tries;
  292. // get number of preexisting interfaces
  293. nip = nipifcs(conf.mpoint);
  294. if(beprimary == -1 && (nip == 0 || !havendb(conf.mpoint)))
  295. beprimary = 1;
  296. // get ipifc into name space and condition device for ip
  297. if(!noconfig){
  298. lookforip(conf.mpoint);
  299. controldevice();
  300. binddevice();
  301. }
  302. if(!validip(conf.laddr)){
  303. if(dondbconfig)
  304. ndbconfig();
  305. else
  306. dodhcp = 1;
  307. }
  308. // run dhcp if we need something
  309. if(dodhcp){
  310. mkclientid();
  311. for(tries = 0; tries < 6; tries++){
  312. dhcpquery(!noconfig, Sselecting);
  313. if(conf.state == Sbound)
  314. break;
  315. sleep(1000);
  316. }
  317. }
  318. if(!validip(conf.laddr)){
  319. if(retry && dodhcp && !noconfig){
  320. fprint(2, "%s: couldn't determine ip address, retrying\n", argv0);
  321. dhcpwatch(1);
  322. return;
  323. } else {
  324. fprint(2, "%s: no success with DHCP\n", argv0);
  325. exits("failed");
  326. }
  327. }
  328. if(!noconfig){
  329. if(ipconfig() < 0)
  330. sysfatal("can't start ip");
  331. if(dodhcp && conf.lease != Lforever)
  332. dhcpwatch(0);
  333. }
  334. // leave everything we've learned somewhere other procs can find it
  335. if(beprimary == 1){
  336. putndb();
  337. tweakservers();
  338. }
  339. }
  340. void
  341. doremove(void)
  342. {
  343. char file[128];
  344. int cfd;
  345. Ipifc *nifc;
  346. Iplifc *lifc;
  347. if(!validip(conf.laddr)){
  348. fprint(2, "%s: remove requires an address\n", argv0);
  349. exits("usage");
  350. }
  351. ifc = readipifc(conf.mpoint, ifc, -1);
  352. for(nifc = ifc; nifc != nil; nifc = nifc->next){
  353. if(strcmp(nifc->dev, conf.dev) != 0)
  354. continue;
  355. for(lifc = nifc->lifc; lifc != nil; lifc = lifc->next){
  356. if(ipcmp(conf.laddr, lifc->ip) != 0)
  357. continue;
  358. if(validip(conf.mask) && ipcmp(conf.mask, lifc->mask) != 0)
  359. continue;
  360. if(validip(conf.raddr) && ipcmp(conf.raddr, lifc->net) != 0)
  361. continue;
  362. snprint(file, sizeof(file), "%s/ipifc/%d/ctl", conf.mpoint, nifc->index);
  363. cfd = open(file, ORDWR);
  364. if(cfd < 0){
  365. fprint(2, "%s: can't open %s: %r\n", argv0, conf.mpoint);
  366. continue;
  367. }
  368. if(fprint(cfd, "remove %I %M", lifc->ip, lifc->mask) < 0)
  369. fprint(2, "%s: can't remove %I %I from %s: %r\n", argv0,
  370. lifc->ip, lifc->mask, file);
  371. }
  372. }
  373. }
  374. void
  375. dounbind(void)
  376. {
  377. Ipifc *nifc;
  378. char file[128];
  379. int cfd;
  380. ifc = readipifc(conf.mpoint, ifc, -1);
  381. for(nifc = ifc; nifc != nil; nifc = nifc->next){
  382. if(strcmp(nifc->dev, conf.dev) == 0){
  383. snprint(file, sizeof(file), "%s/ipifc/%d/ctl", conf.mpoint, nifc->index);
  384. cfd = open(file, ORDWR);
  385. if(cfd < 0){
  386. fprint(2, "%s: can't open %s: %r\n", argv0, conf.mpoint);
  387. break;
  388. }
  389. if(fprint(cfd, "unbind") < 0)
  390. fprint(2, "%s: can't unbind from %s: %r\n", argv0, file);
  391. break;
  392. }
  393. }
  394. }
  395. // set the default route
  396. void
  397. adddefroute(char *mpoint, uchar *gaddr)
  398. {
  399. char buf[256];
  400. int cfd;
  401. sprint(buf, "%s/iproute", mpoint);
  402. cfd = open(buf, ORDWR);
  403. if(cfd < 0)
  404. return;
  405. fprint(cfd, "add 0 0 %I", gaddr);
  406. close(cfd);
  407. }
  408. // create a client id
  409. void
  410. mkclientid(void)
  411. {
  412. if(strcmp(conf.type, "ether") == 0)
  413. if(myetheraddr(conf.hwa, conf.dev) == 0){
  414. conf.hwalen = 6;
  415. conf.hwatype = 1;
  416. conf.cid[0] = conf.hwatype;
  417. memmove(&conf.cid[1], conf.hwa, conf.hwalen);
  418. conf.cidlen = conf.hwalen+1;
  419. } else {
  420. conf.hwatype = -1;
  421. snprint((char*)conf.cid, sizeof(conf.cid), "plan9_%ld.%d", lrand(), getpid());
  422. conf.cidlen = strlen((char*)conf.cid);
  423. }
  424. }
  425. // bind ip into the namespace
  426. void
  427. lookforip(char *net)
  428. {
  429. char proto[64];
  430. snprint(proto, sizeof(proto), "%s/ipifc", net);
  431. if(access(proto, 0) == 0)
  432. return;
  433. sysfatal("no ip stack bound onto %s", net);
  434. }
  435. // send some ctls to a device
  436. void
  437. controldevice(void)
  438. {
  439. char ctlfile[256];
  440. int fd;
  441. Ctl *cp;
  442. if(firstctl == nil)
  443. return;
  444. if(strcmp(conf.type, "ether") == 0)
  445. snprint(ctlfile, sizeof(ctlfile), "%s/clone", conf.dev);
  446. else
  447. return;
  448. fd = open(ctlfile, ORDWR);
  449. if(fd < 0)
  450. sysfatal("can't open %s", ctlfile);
  451. for(cp = firstctl; cp != nil; cp = cp->next){
  452. if(write(fd, cp->ctl, strlen(cp->ctl)) < 0)
  453. sysfatal("ctl message %s: %r", cp->ctl);
  454. seek(fd, 0, 0);
  455. }
  456. }
  457. // bind an ip stack to a device, leave the control channel open
  458. void
  459. binddevice(void)
  460. {
  461. char buf[256];
  462. if(myifc < 0){
  463. // get a new ip interface
  464. snprint(buf, sizeof(buf), "%s/ipifc/clone", conf.mpoint);
  465. conf.cfd = open(buf, ORDWR);
  466. if(conf.cfd < 0)
  467. sysfatal("opening %s/ipifc/clone: %r", conf.mpoint);
  468. // specify the medium as an ethernet, and bind the interface to it
  469. if(fprint(conf.cfd, "bind %s %s", conf.type, conf.dev) < 0)
  470. sysfatal("binding device: %r");
  471. } else {
  472. // open the old interface
  473. snprint(buf, sizeof(buf), "%s/ipifc/%d/ctl", conf.mpoint, myifc);
  474. conf.cfd = open(buf, ORDWR);
  475. if(conf.cfd < 0)
  476. sysfatal("opening %s/ipifc/%d/ctl: %r", conf.mpoint, myifc);
  477. }
  478. }
  479. // add a logical interface to the ip stack
  480. int
  481. ipconfig(void)
  482. {
  483. char buf[256];
  484. int n;
  485. if(!validip(conf.laddr))
  486. return -1;
  487. n = sprint(buf, "add");
  488. n += snprint(buf+n, sizeof(buf)-n, " %I", conf.laddr);
  489. if(!validip(conf.mask))
  490. ipmove(conf.mask, defmask(conf.laddr));
  491. n += snprint(buf+n, sizeof(buf)-n, " %I", conf.mask);
  492. if(validip(conf.raddr)){
  493. n += snprint(buf+n, sizeof(buf)-n, " %I", conf.raddr);
  494. if(conf.mtu != 0)
  495. n += snprint(buf+n, sizeof(buf)-n, " %d", conf.mtu);
  496. }
  497. if(write(conf.cfd, buf, n) < 0){
  498. fprint(2, "ipconfig: write(%s): %r\n", buf);
  499. return -1;
  500. }
  501. if(beprimary==1 && validip(conf.gaddr))
  502. adddefroute(conf.mpoint, conf.gaddr);
  503. return 0;
  504. }
  505. // remove a logical interface to the ip stack
  506. void
  507. ipunconfig(void)
  508. {
  509. char buf[256];
  510. int n;
  511. if(!validip(conf.laddr))
  512. return;
  513. DEBUG("couldn't renew IP lease, releasing %I\n", conf.laddr);
  514. n = sprint(buf, "remove");
  515. n += snprint(buf+n, sizeof(buf)-n, " %I", conf.laddr);
  516. if(!validip(conf.mask))
  517. ipmove(conf.mask, defmask(conf.laddr));
  518. n += snprint(buf+n, sizeof(buf)-n, " %I", conf.mask);
  519. write(conf.cfd, buf, n);
  520. ipmove(conf.laddr, IPnoaddr);
  521. ipmove(conf.raddr, IPnoaddr);
  522. ipmove(conf.mask, IPnoaddr);
  523. // forget configuration info
  524. if(beprimary==1)
  525. writendb("", 0, 0);
  526. }
  527. void
  528. ding(void*, char *msg)
  529. {
  530. if(strstr(msg, "alarm"))
  531. noted(NCONT);
  532. noted(NDFLT);
  533. }
  534. void
  535. dhcpquery(int needconfig, int startstate)
  536. {
  537. if(needconfig)
  538. fprint(conf.cfd, "add %I %I", IPnoaddr, IPnoaddr);
  539. conf.fd = openlisten();
  540. if(conf.fd < 0){
  541. conf.state = Sinit;
  542. return;
  543. }
  544. notify(ding);
  545. // try dhcp for 10 seconds
  546. conf.xid = lrand();
  547. conf.starttime = time(0);
  548. conf.state = startstate;
  549. switch(startstate){
  550. case Sselecting:
  551. conf.offered = 0;
  552. dhcpsend(Discover);
  553. break;
  554. case Srenewing:
  555. dhcpsend(Request);
  556. break;
  557. default:
  558. sysfatal("internal error 0");
  559. }
  560. conf.resend = 0;
  561. conf.timeout = time(0) + 4;
  562. while(conf.state != Sbound){
  563. dhcprecv();
  564. if(dhcptimer() < 0)
  565. break;
  566. if(time(0) - conf.starttime > 10)
  567. break;
  568. }
  569. close(conf.fd);
  570. if(needconfig)
  571. fprint(conf.cfd, "remove %I %I", IPnoaddr, IPnoaddr);
  572. }
  573. #define HOUR (60*60)
  574. void
  575. dhcpwatch(int needconfig)
  576. {
  577. int secs, s;
  578. ulong t;
  579. if(nodhcpwatch)
  580. return;
  581. switch(rfork(RFPROC|RFFDG|RFNOWAIT|RFNOTEG)){
  582. default:
  583. return;
  584. case 0:
  585. break;
  586. }
  587. // keep trying to renew the lease
  588. for(;;){
  589. if(conf.lease == 0)
  590. secs = 5;
  591. else
  592. secs = conf.lease>>1;
  593. // avoid overflows
  594. for(s = secs; s > 0; s -= t){
  595. if(s > HOUR)
  596. t = HOUR;
  597. else
  598. t = s;
  599. sleep(t*1000);
  600. }
  601. if(conf.lease > 0){
  602. // during boot, the starttime can be bogus so avoid
  603. // spurious ipinconfig's
  604. t = time(0) - conf.starttime;
  605. if(t > (3*secs)/2)
  606. t = secs;
  607. if(t >= conf.lease){
  608. conf.lease = 0;
  609. if(!noconfig){
  610. ipunconfig();
  611. needconfig = 1;
  612. }
  613. } else
  614. conf.lease -= t;
  615. }
  616. dhcpquery(needconfig, needconfig ? Sselecting : Srenewing);
  617. if(needconfig && conf.state == Sbound){
  618. if(ipconfig() < 0)
  619. sysfatal("can't start ip: %r");
  620. needconfig = 0;
  621. // leave everything we've learned somewhere other procs can find it
  622. if(beprimary==1){
  623. putndb();
  624. tweakservers();
  625. }
  626. }
  627. }
  628. }
  629. int
  630. dhcptimer(void)
  631. {
  632. ulong now;
  633. now = time(0);
  634. if(now < conf.timeout)
  635. return 0;
  636. switch(conf.state) {
  637. default:
  638. sysfatal("dhcptimer: unknown state %d", conf.state);
  639. case Sinit:
  640. break;
  641. case Sselecting:
  642. dhcpsend(Discover);
  643. conf.timeout = now + 4;
  644. conf.resend++;
  645. if(conf.resend>5)
  646. goto err;
  647. break;
  648. case Srequesting:
  649. dhcpsend(Request);
  650. conf.timeout = now + 4;
  651. conf.resend++;
  652. if(conf.resend>5)
  653. goto err;
  654. break;
  655. case Srenewing:
  656. dhcpsend(Request);
  657. conf.timeout = now + 1;
  658. conf.resend++;
  659. if(conf.resend>3) {
  660. conf.state = Srebinding;
  661. conf.resend = 0;
  662. }
  663. break;
  664. case Srebinding:
  665. dhcpsend(Request);
  666. conf.timeout = now + 4;
  667. conf.resend++;
  668. if(conf.resend>5)
  669. goto err;
  670. break;
  671. case Sbound:
  672. break;
  673. }
  674. return 0;
  675. err:
  676. conf.state = Sinit;
  677. return -1;
  678. }
  679. uchar requested[] = {
  680. OBmask, OBrouter, OBdnserver, OBhostname, OBdomainname, OBntpserver,
  681. };
  682. void
  683. dhcpsend(int type)
  684. {
  685. Bootp bp;
  686. uchar *p;
  687. int n;
  688. uchar vendor[64];
  689. OUdphdr *up = (OUdphdr*)bp.udphdr;
  690. memset(&bp, 0, sizeof(bp));
  691. hnputs(up->rport, 67);
  692. bp.op = Bootrequest;
  693. hnputl(bp.xid, conf.xid);
  694. hnputs(bp.secs, time(0)-conf.starttime);
  695. hnputs(bp.flags, 0);
  696. memmove(bp.optmagic, optmagic, 4);
  697. if(conf.hwatype >= 0 && conf.hwalen < sizeof(bp.chaddr)){
  698. memmove(bp.chaddr, conf.hwa, conf.hwalen);
  699. bp.hlen = conf.hwalen;
  700. bp.htype = conf.hwatype;
  701. }
  702. p = bp.optdata;
  703. p = optaddbyte(p, ODtype, type);
  704. p = optadd(p, ODclientid, conf.cid, conf.cidlen);
  705. switch(type) {
  706. default:
  707. sysfatal("dhcpsend: unknown message type: %d", type);
  708. case Discover:
  709. ipmove(up->raddr, IPv4bcast); // broadcast
  710. if(*conf.hostname && sendhostname)
  711. p = optaddstr(p, OBhostname, conf.hostname);
  712. if(plan9){
  713. n = snprint((char*)vendor, sizeof(vendor), "plan9_%s", conf.cputype);
  714. p = optaddvec(p, ODvendorclass, vendor, n);
  715. }
  716. p = optaddvec(p, ODparams, requested, sizeof(requested));
  717. if(validip(conf.laddr))
  718. p = optaddaddr(p, ODipaddr, conf.laddr);
  719. break;
  720. case Request:
  721. switch(conf.state){
  722. case Srenewing:
  723. ipmove(up->raddr, conf.server);
  724. v6tov4(bp.ciaddr, conf.laddr);
  725. break;
  726. case Srebinding:
  727. ipmove(up->raddr, IPv4bcast); // broadcast
  728. v6tov4(bp.ciaddr, conf.laddr);
  729. break;
  730. case Srequesting:
  731. ipmove(up->raddr, IPv4bcast); // broadcast
  732. p = optaddaddr(p, ODipaddr, conf.laddr);
  733. p = optaddaddr(p, ODserverid, conf.server);
  734. break;
  735. }
  736. p = optaddulong(p, ODlease, conf.offered);
  737. if(plan9){
  738. n = snprint((char*)vendor, sizeof(vendor), "plan9_%s", conf.cputype);
  739. p = optaddvec(p, ODvendorclass, vendor, n);
  740. }
  741. p = optaddvec(p, ODparams, requested, sizeof(requested));
  742. if(*conf.hostname && sendhostname)
  743. p = optaddstr(p, OBhostname, conf.hostname);
  744. break;
  745. case Release:
  746. ipmove(up->raddr, conf.server);
  747. v6tov4(bp.ciaddr, conf.laddr);
  748. p = optaddaddr(p, ODipaddr, conf.laddr);
  749. p = optaddaddr(p, ODserverid, conf.server);
  750. break;
  751. }
  752. *p++ = OBend;
  753. n = p - (uchar*)&bp;
  754. USED(n);
  755. /*
  756. * We use a maximum size DHCP packet to survive the
  757. * All_Aboard NAT package from Internet Share. It
  758. * always replies to DHCP requests with a packet of the
  759. * same size, so if the request is too short the reply
  760. * is truncated.
  761. */
  762. if(write(conf.fd, &bp, sizeof(bp)) != sizeof(bp))
  763. fprint(2, "dhcpsend: write failed: %r\n");
  764. }
  765. void
  766. dhcprecv(void)
  767. {
  768. uchar buf[8000];
  769. Bootp *bp;
  770. int i, n, type;
  771. ulong lease;
  772. char err[ERRMAX];
  773. uchar vopts[256];
  774. alarm(1000);
  775. n = read(conf.fd, buf, sizeof(buf));
  776. alarm(0);
  777. if(n < 0){
  778. errstr(err, sizeof err);
  779. if(strstr(err, "interrupt") == nil)
  780. fprint(2, "ipconfig: bad read: %s\n", err);
  781. else
  782. DEBUG("read timed out\n");
  783. return;
  784. }
  785. bp = parsebootp(buf, n);
  786. if(bp == 0) {
  787. DEBUG("parsebootp failed: dropping packet\n");
  788. return;
  789. }
  790. type = optgetbyte(bp->optdata, ODtype);
  791. switch(type) {
  792. default:
  793. fprint(2, "%s: unknown type: %d\n", argv0, type);
  794. break;
  795. case Offer:
  796. DEBUG("got offer from %V ", bp->siaddr);
  797. if(conf.state != Sselecting){
  798. DEBUG("\n");
  799. break;
  800. }
  801. lease = optgetulong(bp->optdata, ODlease);
  802. if(lease == 0){
  803. /*
  804. * The All_Aboard NAT package from Internet Share doesn't
  805. * give a lease time, so we have to assume one.
  806. */
  807. fprint(2, "%s: Offer with %lud lease, using %d\n", argv0, lease, MinLease);
  808. lease = MinLease;
  809. }
  810. DEBUG("lease %lud ", lease);
  811. if(!optgetaddr(bp->optdata, ODserverid, conf.server)) {
  812. fprint(2, "%s: Offer from server with invalid serverid\n", argv0);
  813. break;
  814. }
  815. v4tov6(conf.laddr, bp->yiaddr);
  816. memmove(conf.sname, bp->sname, sizeof(conf.sname));
  817. conf.sname[sizeof(conf.sname)-1] = 0;
  818. DEBUG("server %I %s\n", conf.server, conf.sname);
  819. conf.offered = lease;
  820. conf.state = Srequesting;
  821. dhcpsend(Request);
  822. conf.resend = 0;
  823. conf.timeout = time(0) + 4;
  824. break;
  825. case Ack:
  826. DEBUG("got ack from %V ", bp->siaddr);
  827. if(conf.state != Srequesting)
  828. if(conf.state != Srenewing)
  829. if(conf.state != Srebinding)
  830. break;
  831. // ignore a bad lease
  832. lease = optgetulong(bp->optdata, ODlease);
  833. if(lease == 0){
  834. /*
  835. * The All_Aboard NAT package from Internet Share doesn't
  836. * give a lease time, so we have to assume one.
  837. */
  838. fprint(2, "%s: Ack with %lud lease, using %d\n", argv0, lease, MinLease);
  839. lease = MinLease;
  840. }
  841. DEBUG("lease %lud ", lease);
  842. // address and mask
  843. v4tov6(conf.laddr, bp->yiaddr);
  844. if(!optgetaddr(bp->optdata, OBmask, conf.mask))
  845. ipmove(conf.mask, IPnoaddr);
  846. DEBUG("addr %I mask %M ", conf.laddr, conf.mask);
  847. // get a router address either from the router option
  848. // or from the router that forwarded the dhcp packet
  849. if(optgetaddr(bp->optdata, OBrouter, conf.gaddr)){
  850. DEBUG("router %I ", conf.gaddr);
  851. } else {
  852. if(memcmp(bp->giaddr, IPnoaddr+IPv4off, IPv4addrlen) != 0){
  853. v4tov6(conf.gaddr, bp->giaddr);
  854. DEBUG("giaddr %I ", conf.gaddr);
  855. }
  856. }
  857. // get dns servers
  858. memset(conf.dns, 0, sizeof(conf.dns));
  859. n = optgetaddrs(bp->optdata, OBdnserver, conf.dns,
  860. sizeof(conf.dns)/IPaddrlen);
  861. for(i = 0; i < n; i++)
  862. DEBUG("dns %I ", conf.dns+i*IPaddrlen);
  863. // get ntp servers
  864. memset(conf.ntp, 0, sizeof(conf.ntp));
  865. n = optgetaddrs(bp->optdata, OBntpserver, conf.ntp,
  866. sizeof(conf.ntp)/IPaddrlen);
  867. for(i = 0; i < n; i++)
  868. DEBUG("ntp %I ", conf.ntp+i*IPaddrlen);
  869. // get names
  870. optgetstr(bp->optdata, OBhostname, conf.hostname, sizeof(conf.hostname));
  871. optgetstr(bp->optdata, OBdomainname, conf.domainname, sizeof(conf.domainname));
  872. // get plan9 specific options
  873. n = optgetvec(bp->optdata, OBvendorinfo, vopts, sizeof(vopts)-1);
  874. if(n > 0){
  875. if(parseoptions(vopts, n) == 0){
  876. n = optgetaddrs(vopts, OP9fs, conf.fs, 2);
  877. for(i = 0; i < n; i++)
  878. DEBUG("fs %I ", conf.fs+i*IPaddrlen);
  879. n = optgetaddrs(vopts, OP9auth, conf.auth, 2);
  880. for(i = 0; i < n; i++)
  881. DEBUG("auth %I ", conf.auth+i*IPaddrlen);
  882. }
  883. }
  884. conf.lease = lease;
  885. conf.state = Sbound;
  886. DEBUG("server %I %s\n", conf.server, conf.sname);
  887. break;
  888. case Nak:
  889. conf.state = Sinit;
  890. fprint(2, "%s: recved dhcpnak on %s\n", argv0, conf.mpoint);
  891. break;
  892. }
  893. }
  894. int
  895. openlisten()
  896. {
  897. int fd, cfd;
  898. char data[128];
  899. char devdir[40];
  900. int n;
  901. if(validip(conf.laddr)
  902. && (conf.state == Srenewing || conf.state == Srebinding))
  903. sprint(data, "%s/udp!%I!68", conf.mpoint, conf.laddr);
  904. else
  905. sprint(data, "%s/udp!*!68", conf.mpoint);
  906. for(n=0;;n++) {
  907. cfd = announce(data, devdir);
  908. if(cfd >= 0)
  909. break;
  910. if(!noconfig)
  911. sysfatal("can't announce for dhcp: %r");
  912. // might be another client - wait and try again
  913. fprint(2, "%s: can't announce: %r\n", argv0);
  914. sleep((nrand(10)+1)*1000);
  915. if(n > 10)
  916. return -1;
  917. }
  918. if(fprint(cfd, "headers") < 0)
  919. sysfatal("can't set header mode: %r");
  920. fprint(cfd, "oldheaders");
  921. sprint(data, "%s/data", devdir);
  922. fd = open(data, ORDWR);
  923. if(fd < 0)
  924. sysfatal("open udp data: %r");
  925. close(cfd);
  926. return fd;
  927. }
  928. uchar*
  929. optadd(uchar *p, int op, void *d, int n)
  930. {
  931. p[0] = op;
  932. p[1] = n;
  933. memmove(p+2, d, n);
  934. return p+n+2;
  935. }
  936. uchar*
  937. optaddbyte(uchar *p, int op, int b)
  938. {
  939. p[0] = op;
  940. p[1] = 1;
  941. p[2] = b;
  942. return p+3;
  943. }
  944. uchar*
  945. optaddulong(uchar *p, int op, ulong x)
  946. {
  947. p[0] = op;
  948. p[1] = 4;
  949. hnputl(p+2, x);
  950. return p+6;
  951. }
  952. uchar *
  953. optaddaddr(uchar *p, int op, uchar *ip)
  954. {
  955. p[0] = op;
  956. p[1] = 4;
  957. v6tov4(p+2, ip);
  958. return p+6;
  959. }
  960. uchar *
  961. optaddvec(uchar *p, int op, uchar *v, int n)
  962. {
  963. p[0] = op;
  964. p[1] = n;
  965. memmove(p+2, v, n);
  966. return p+2+n;
  967. }
  968. uchar *
  969. optaddstr(uchar *p, int op, char *v)
  970. {
  971. int n;
  972. n = strlen(v)+1; // microsoft leaves on the null, so we do too
  973. p[0] = op;
  974. p[1] = n;
  975. memmove(p+2, v, n);
  976. return p+2+n;
  977. }
  978. uchar*
  979. optget(uchar *p, int op, int *np)
  980. {
  981. int len, code;
  982. for(;;) {
  983. code = *p++;
  984. if(code == OBpad)
  985. continue;
  986. if(code == OBend)
  987. return 0;
  988. len = *p++;
  989. if(code != op) {
  990. p += len;
  991. continue;
  992. }
  993. if(np != nil){
  994. if(*np > len)
  995. return 0;
  996. *np = len;
  997. }
  998. return p;
  999. }
  1000. }
  1001. int
  1002. optgetbyte(uchar *p, int op)
  1003. {
  1004. int len;
  1005. len = 1;
  1006. p = optget(p, op, &len);
  1007. if(p == 0)
  1008. return 0;
  1009. return *p;
  1010. }
  1011. ulong
  1012. optgetulong(uchar *p, int op)
  1013. {
  1014. int len;
  1015. len = 4;
  1016. p = optget(p, op, &len);
  1017. if(p == 0)
  1018. return 0;
  1019. return nhgetl(p);
  1020. }
  1021. int
  1022. optgetaddr(uchar *p, int op, uchar *ip)
  1023. {
  1024. int len;
  1025. len = 4;
  1026. p = optget(p, op, &len);
  1027. if(p == 0)
  1028. return 0;
  1029. v4tov6(ip, p);
  1030. return 1;
  1031. }
  1032. int
  1033. optgetaddrs(uchar *p, int op, uchar *ip, int n)
  1034. {
  1035. int len, i;
  1036. len = 4;
  1037. p = optget(p, op, &len);
  1038. if(p == 0)
  1039. return 0;
  1040. len /= IPv4addrlen;
  1041. if(len > n)
  1042. len = n;
  1043. for(i = 0; i < len; i++)
  1044. v4tov6(&ip[i*IPaddrlen], &p[i*IPv4addrlen]);
  1045. return i;
  1046. }
  1047. int
  1048. optgetvec(uchar *p, int op, uchar *v, int n)
  1049. {
  1050. int len;
  1051. len = 1;
  1052. p = optget(p, op, &len);
  1053. if(p == 0)
  1054. return 0;
  1055. if(len > n)
  1056. len = n;
  1057. memmove(v, p, len);
  1058. return len;
  1059. }
  1060. int
  1061. optgetstr(uchar *p, int op, char *s, int n)
  1062. {
  1063. int len;
  1064. len = 1;
  1065. p = optget(p, op, &len);
  1066. if(p == 0)
  1067. return 0;
  1068. if(len >= n)
  1069. len = n-1;
  1070. memmove(s, p, len);
  1071. s[len] = 0;
  1072. return len;
  1073. }
  1074. // sanity check options area
  1075. // - options don't overflow packet
  1076. // - options end with an OBend
  1077. int
  1078. parseoptions(uchar *p, int n)
  1079. {
  1080. int code, len;
  1081. int nin = n;
  1082. while(n>0) {
  1083. code = *p++;
  1084. n--;
  1085. if(code == OBpad)
  1086. continue;
  1087. if(code == OBend)
  1088. return 0;
  1089. if(n == 0) {
  1090. fprint(2, "%s: parse: bad option: 0x%ux: truncated: opt length = %d\n",
  1091. argv0, code, nin);
  1092. return -1;
  1093. }
  1094. len = *p++;
  1095. n--;
  1096. if(len > n) {
  1097. fprint(2, "%s: parse: bad option: 0x%ux: %d > %d: opt length = %d\n",
  1098. argv0, code, len, n, nin);
  1099. return -1;
  1100. }
  1101. p += len;
  1102. n -= len;
  1103. }
  1104. // make sure packet ends with an OBend all the optget code
  1105. *p = OBend;
  1106. return 0;
  1107. }
  1108. // sanity check received packet:
  1109. // - magic is dhcp magic
  1110. // - options don't overflow packet
  1111. Bootp *
  1112. parsebootp(uchar *p, int n)
  1113. {
  1114. Bootp *bp;
  1115. bp = (Bootp*)p;
  1116. if(n < bp->optmagic - p) {
  1117. fprint(2, "%s: parse: short bootp packet\n", argv0);
  1118. return nil;
  1119. }
  1120. if(conf.xid != nhgetl(bp->xid))
  1121. return nil;
  1122. if(bp->op != Bootreply) {
  1123. fprint(2, "%s: parse: bad op\n", argv0);
  1124. return nil;
  1125. }
  1126. n -= bp->optmagic - p;
  1127. p = bp->optmagic;
  1128. if(n < 4) {
  1129. fprint(2, "%s: parse: not option data\n", argv0);
  1130. return nil;
  1131. }
  1132. if(memcmp(optmagic, p, 4) != 0) {
  1133. fprint(2, "%s: parse: bad opt magic %ux %ux %ux %ux\n", argv0,
  1134. p[0], p[1], p[2], p[3]);
  1135. return nil;
  1136. }
  1137. p += 4;
  1138. n -= 4;
  1139. if(parseoptions(p, n) < 0)
  1140. return nil;
  1141. return bp;
  1142. }
  1143. // write out an ndb entry
  1144. void
  1145. writendb(char *s, int n, int append)
  1146. {
  1147. char file[64];
  1148. int fd;
  1149. snprint(file, sizeof file, "%s/ndb", conf.mpoint);
  1150. if(append){
  1151. fd = open(file, OWRITE);
  1152. seek(fd, 0, 2);
  1153. } else
  1154. fd = open(file, OWRITE|OTRUNC);
  1155. write(fd, s, n);
  1156. close(fd);
  1157. }
  1158. // put server addresses into the ndb entry
  1159. char*
  1160. putaddrs(char *p, char *e, char *attr, uchar *a, int len)
  1161. {
  1162. int i;
  1163. for(i = 0; i < len; i += IPaddrlen, a += IPaddrlen){
  1164. if(!validip(a))
  1165. break;
  1166. p = seprint(p, e, "%s=%I\n", attr, a);
  1167. }
  1168. return p;
  1169. }
  1170. // make an ndb entry and put it into /net/ndb for the servers to see
  1171. void
  1172. putndb(void)
  1173. {
  1174. char buf[1024];
  1175. char *p, *e, *np;
  1176. int append;
  1177. e = buf + sizeof(buf);
  1178. p = buf;
  1179. if(getndb() == 0){
  1180. append = 1;
  1181. } else {
  1182. append = 0;
  1183. p = seprint(p, e, "ip=%I ipmask=%M ipgw=%I\n",
  1184. conf.laddr, conf.mask, conf.gaddr);
  1185. }
  1186. if(np = strchr(conf.hostname, '.')){
  1187. if(*conf.domainname == 0)
  1188. strcpy(conf.domainname, np+1);
  1189. *np = 0;
  1190. }
  1191. if(*conf.hostname)
  1192. p = seprint(p, e, "\tsys=%s\n", conf.hostname);
  1193. if(*conf.domainname)
  1194. p = seprint(p, e, "\tdom=%s.%s\n", conf.hostname, conf.domainname);
  1195. if(validip(conf.fs))
  1196. p = putaddrs(p, e, "\tfs", conf.fs, sizeof(conf.fs));
  1197. if(validip(conf.auth))
  1198. p = putaddrs(p, e, "\tauth", conf.auth, sizeof(conf.auth));
  1199. if(validip(conf.dns))
  1200. p = putaddrs(p, e, "\tdns", conf.dns, sizeof(conf.dns));
  1201. if(validip(conf.ntp))
  1202. p = putaddrs(p, e, "\tntp", conf.ntp, sizeof(conf.ntp));
  1203. if(p > buf)
  1204. writendb(buf, p-buf, append);
  1205. }
  1206. // get an ndb entry someone else wrote
  1207. int
  1208. getndb(void)
  1209. {
  1210. char buf[1024];
  1211. int fd;
  1212. int n;
  1213. char *p;
  1214. snprint(buf, sizeof buf, "%s/ndb", conf.mpoint);
  1215. fd = open(buf, OREAD);
  1216. n = read(fd, buf, sizeof(buf)-1);
  1217. close(fd);
  1218. if(n <= 0)
  1219. return -1;
  1220. buf[n] = 0;
  1221. p = strstr(buf, "ip=");
  1222. if(p == nil)
  1223. return -1;
  1224. parseip(conf.laddr, p+3);
  1225. return 0;
  1226. }
  1227. // tell a server to refresh
  1228. void
  1229. tweakserver(char *server)
  1230. {
  1231. char file[64];
  1232. int fd;
  1233. snprint(file, sizeof(file), "%s/%s", conf.mpoint, server);
  1234. fd = open(file, ORDWR);
  1235. if(fd < 0)
  1236. return;
  1237. fprint(fd, "refresh");
  1238. close(fd);
  1239. }
  1240. // tell all servers to refresh their information
  1241. void
  1242. tweakservers(void)
  1243. {
  1244. tweakserver("dns");
  1245. tweakserver("cs");
  1246. }
  1247. // return number of networks
  1248. int
  1249. nipifcs(char *net)
  1250. {
  1251. Ipifc *nifc;
  1252. Iplifc *lifc;
  1253. int n;
  1254. n = 0;
  1255. ifc = readipifc(net, ifc, -1);
  1256. for(nifc = ifc; nifc != nil; nifc = nifc->next){
  1257. /*
  1258. * ignore loopback devices when trying to
  1259. * figure out if we're the primary interface.
  1260. */
  1261. if(strcmp(nifc->dev, "/dev/null") != 0)
  1262. for(lifc = nifc->lifc; lifc != nil; lifc = lifc->next)
  1263. if(validip(lifc->ip)){
  1264. n++;
  1265. break;
  1266. }
  1267. if(strcmp(nifc->dev, conf.dev) == 0)
  1268. myifc = nifc->index;
  1269. }
  1270. return n;
  1271. }
  1272. // return true if this is a valid v4 address
  1273. int
  1274. validip(uchar *addr)
  1275. {
  1276. return ipcmp(addr, IPnoaddr) != 0 && ipcmp(addr, v4prefix) != 0;
  1277. }
  1278. char *verbs[] = {
  1279. [Vadd] "add",
  1280. [Vremove] "remove",
  1281. [Vunbind] "unbind",
  1282. [Vether] "ether",
  1283. [Vloopback] "loopback",
  1284. };
  1285. // look for an action
  1286. int
  1287. parseverb(char *name)
  1288. {
  1289. int i;
  1290. for(i = 0; i < nelem(verbs); i++){
  1291. if(verbs[i] == 0)
  1292. continue;
  1293. if(strcmp(name, verbs[i]) == 0)
  1294. return i;
  1295. }
  1296. return -1;
  1297. }
  1298. // get everything out of ndb
  1299. void
  1300. ndbconfig(void)
  1301. {
  1302. Ndb *db;
  1303. Ndbtuple *t, *nt;
  1304. char etheraddr[32];
  1305. char *attrs[10];
  1306. int nattr;
  1307. int ndns = 0;
  1308. int nfs = 0;
  1309. int nauth = 0;
  1310. db = ndbopen(0);
  1311. if(db == nil)
  1312. sysfatal("can't open ndb: %r");
  1313. if(strcmp(conf.type, "ether") != 0 || myetheraddr(conf.hwa, conf.dev) != 0)
  1314. sysfatal("can't read hardware address");
  1315. sprint(etheraddr, "%E", conf.hwa);
  1316. nattr = 0;
  1317. attrs[nattr++] = "ip";
  1318. attrs[nattr++] = "ipmask";
  1319. attrs[nattr++] = "ipgw";
  1320. attrs[nattr++] = "@dns";
  1321. attrs[nattr++] = "@ntp";
  1322. attrs[nattr++] = "@fs";
  1323. attrs[nattr++] = "@auth";
  1324. attrs[nattr] = nil;
  1325. t = ndbipinfo(db, "ether", etheraddr, attrs, nattr);
  1326. for(nt = t; nt != nil; nt = nt->entry){
  1327. if(strcmp(nt->attr, "ip") == 0){
  1328. parseip(conf.laddr, nt->val);
  1329. } else if(strcmp(nt->attr, "ipmask") == 0){
  1330. parseipmask(conf.mask, nt->val);
  1331. } else if(strcmp(nt->attr, "ipgw") == 0){
  1332. parseip(conf.gaddr, nt->val);
  1333. } else if(ndns < 2 && strcmp(nt->attr, "dns") == 0){
  1334. parseip(conf.dns+IPaddrlen*ndns, nt->val);
  1335. } else if(strcmp(nt->attr, "ntp") == 0){
  1336. parseip(conf.ntp, nt->val);
  1337. } else if(nfs < 2 && strcmp(nt->attr, "fs") == 0){
  1338. parseip(conf.fs+IPaddrlen*nfs, nt->val);
  1339. } else if(nauth < 2 && strcmp(nt->attr, "auth") == 0){
  1340. parseip(conf.auth+IPaddrlen*nauth, nt->val);
  1341. }
  1342. }
  1343. ndbfree(t);
  1344. if(!validip(conf.laddr))
  1345. sysfatal("address not found in ndb");
  1346. }