main.c 37 KB

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