ipconfig.c 27 KB

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