ipconfig.c 27 KB

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