ipconfig.c 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749
  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. int i;
  1478. Option *o;
  1479. if(opt == nil)
  1480. return -1;
  1481. for(o = option; o < &option[nelem(option)]; o++){
  1482. if(o->name == nil)
  1483. continue;
  1484. if(strcmp(opt, o->name) == 0){
  1485. i = o-option;
  1486. if(!memchr(requested, i, nrequested))
  1487. if(nrequested < nelem(requested))
  1488. requested[nrequested++] = i;
  1489. return 0;
  1490. }
  1491. }
  1492. return -1;
  1493. }
  1494. char*
  1495. optgetx(uchar *p, uchar opt)
  1496. {
  1497. Option *o;
  1498. int i, n;
  1499. ulong x;
  1500. char *s, *ns;
  1501. uchar ip[IPaddrlen];
  1502. uchar ips[16*IPaddrlen];
  1503. char str[256];
  1504. uchar vec[256];
  1505. o = &option[opt];
  1506. if(o->name == nil)
  1507. return nil;
  1508. s = nil;
  1509. switch(o->type){
  1510. case Taddr:
  1511. if(optgetaddr(p, opt, ip))
  1512. s = smprint("%s=%I", o->name, ip);
  1513. break;
  1514. case Taddrs:
  1515. n = optgetaddrs(p, opt, ips, 16);
  1516. if(n > 0)
  1517. s = smprint("%s=%I", o->name, ips);
  1518. for(i = 1; i < n; i++){
  1519. ns = smprint("%s %s=%I", s, o->name, &ips[i*IPaddrlen]);
  1520. free(s);
  1521. s = ns;
  1522. }
  1523. break;
  1524. case Tulong:
  1525. x = optgetulong(p, opt);
  1526. if(x != 0)
  1527. s = smprint("%s=%lud", o->name, x);
  1528. break;
  1529. case Tbyte:
  1530. x = optgetbyte(p, opt);
  1531. if(x != 0)
  1532. s = smprint("%s=%lud", o->name, x);
  1533. break;
  1534. case Tstr:
  1535. if(optgetstr(p, opt, str, sizeof(str)))
  1536. s = smprint("%s=%s", o->name, str);
  1537. break;
  1538. case Tvec:
  1539. n = optgetvec(p, opt, vec, sizeof(vec));
  1540. if(n > 0)
  1541. s = smprint("%s=%.*H", o->name, n, vec);
  1542. break;
  1543. }
  1544. return s;
  1545. }
  1546. void
  1547. getoptions(uchar *p)
  1548. {
  1549. int i;
  1550. char *s, *t;
  1551. for(i = nelem(defrequested); i < nrequested; i++){
  1552. s = optgetx(p, requested[i]);
  1553. if(s != nil)
  1554. DEBUG("%s ", s);
  1555. if(ndboptions == nil)
  1556. ndboptions = smprint("\t%s", s);
  1557. else{
  1558. t = ndboptions;
  1559. ndboptions = smprint("\t%s%s", s, ndboptions);
  1560. free(t);
  1561. }
  1562. free(s);
  1563. }
  1564. }