ipconfig.c 34 KB

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