You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

dhcp.c 24 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748
  1. /*
  2. * DHCP module for netcfg/netcfg-dhcp.
  3. *
  4. * Licensed under the terms of the GNU General Public License
  5. */
  6. #include "netcfg.h"
  7. #include <errno.h>
  8. #include <stdlib.h>
  9. #include <unistd.h>
  10. #include <debian-installer.h>
  11. #include <stdio.h>
  12. #include <assert.h>
  13. #include <sys/param.h>
  14. #include <sys/socket.h>
  15. #include <sys/stat.h>
  16. #include <sys/ioctl.h>
  17. #include <sys/utsname.h>
  18. #include <sys/wait.h>
  19. #include <arpa/inet.h>
  20. #include <net/if.h>
  21. #include <time.h>
  22. #include <netdb.h>
  23. #define DHCP_OPTION_LEN 1236 /* pump 0.8.24 defines a max option size of 57,
  24. dhcp 2.0pl5 uses 1222, dhcp3 3.0.6 uses 1236 */
  25. const char* dhclient_request_options_dhclient[] = { "subnet-mask",
  26. "broadcast-address",
  27. "time-offset",
  28. "routers",
  29. "domain-name",
  30. "domain-name-servers",
  31. "host-name",
  32. "ntp-servers", /* extra */
  33. NULL };
  34. const char* dhclient_request_options_udhcpc[] = { "subnet",
  35. "broadcast",
  36. "router",
  37. "domain",
  38. "hostname",
  39. "dns",
  40. "ntpsrv", /* extra */
  41. NULL };
  42. static int dhcp_exit_status = 1;
  43. static pid_t dhcp_pid = -1;
  44. /*
  45. * Add DHCP-related lines to /etc/network/interfaces
  46. */
  47. static void netcfg_write_dhcp (char *iface, char *dhostname)
  48. {
  49. FILE *fp;
  50. if ((fp = file_open(INTERFACES_FILE, "a"))) {
  51. fprintf(fp, "\n# The primary network interface\n");
  52. if (!iface_is_hotpluggable(iface) && !find_in_stab(iface))
  53. fprintf(fp, "auto %s\n", iface);
  54. else
  55. fprintf(fp, "allow-hotplug %s\n", iface);
  56. fprintf(fp, "iface %s inet dhcp\n", iface);
  57. if (dhostname) {
  58. fprintf(fp, "\thostname %s\n", dhostname);
  59. }
  60. if (is_wireless_iface(iface)) {
  61. if (wpa_supplicant_status == WPA_QUEUED) {
  62. fprintf(fp, "\twpa-ssid %s\n", essid);
  63. fprintf(fp, "\twpa-psk %s\n", passphrase);
  64. } else {
  65. fprintf(fp, "\t# wireless-* options are implemented by the wireless-tools package\n");
  66. fprintf(fp, "\twireless-mode %s\n",
  67. (mode == MANAGED) ? "managed" : "ad-hoc");
  68. fprintf(fp, "\twireless-essid %s\n",
  69. (essid && *essid) ? essid : "any");
  70. if (wepkey != NULL)
  71. fprintf(fp, "\twireless-key1 %s\n", wepkey);
  72. }
  73. }
  74. fclose(fp);
  75. }
  76. }
  77. /* Returns 1 if no default route is available */
  78. static short no_default_route (void)
  79. {
  80. #if defined(__FreeBSD_kernel__)
  81. int status;
  82. status = system("exec /lib/freebsd/route show default >/dev/null 2>&1");
  83. return WEXITSTATUS(status) != 0;
  84. #else
  85. FILE* iproute = NULL;
  86. char buf[256] = { 0 };
  87. if ((iproute = popen("ip route", "r")) != NULL) {
  88. while (fgets (buf, 256, iproute) != NULL) {
  89. if (buf[0] == 'd' && strstr (buf, "default via ")) {
  90. pclose(iproute);
  91. return 0;
  92. }
  93. }
  94. pclose(iproute);
  95. }
  96. return 1;
  97. #endif
  98. }
  99. /*
  100. * Signal handler for DHCP client child
  101. *
  102. * When the child exits (either because it failed to obtain a
  103. * lease or because it succeeded and daemonized itself), this
  104. * gets the child's exit status and sets dhcp_pid to -1
  105. */
  106. static void dhcp_client_sigchld(int sig __attribute__ ((unused)))
  107. {
  108. di_debug("dhcp_client_sigchld() called");
  109. if (dhcp_pid <= 0)
  110. /* Already cleaned up */
  111. return;
  112. /*
  113. * I hope it's OK to call waitpid() from the SIGCHLD signal handler
  114. */
  115. di_debug("Waiting for dhcp_pid = %i", dhcp_pid);
  116. waitpid(dhcp_pid, &dhcp_exit_status, WNOHANG);
  117. if (WIFEXITED(dhcp_exit_status)) {
  118. dhcp_pid = -1;
  119. }
  120. }
  121. /*
  122. * This function will start whichever DHCP client is available
  123. * using the provided DHCP hostname, if supplied
  124. *
  125. * The client's PID is stored in dhcp_pid.
  126. */
  127. int start_dhcp_client (struct debconfclient *client, char* dhostname)
  128. {
  129. FILE *dc = NULL;
  130. const char **ptr;
  131. char **arguments;
  132. int options_count;
  133. enum { DHCLIENT, PUMP, UDHCPC } dhcp_client;
  134. int dhcp_seconds;
  135. char dhcp_seconds_str[16];
  136. if (access("/sbin/dhclient", F_OK) == 0)
  137. dhcp_client = DHCLIENT;
  138. else if (access("/sbin/pump", F_OK) == 0)
  139. dhcp_client = PUMP;
  140. else if (access("/sbin/udhcpc", F_OK) == 0)
  141. dhcp_client = UDHCPC;
  142. else {
  143. debconf_input(client, "critical", "netcfg/no_dhcp_client");
  144. debconf_go(client);
  145. exit(1);
  146. }
  147. debconf_get(client, "netcfg/dhcp_timeout");
  148. dhcp_seconds = atoi(client->value);
  149. snprintf(dhcp_seconds_str, sizeof dhcp_seconds_str, "%d", dhcp_seconds-1);
  150. if ((dhcp_pid = fork()) == 0) { /* child */
  151. /* disassociate from debconf */
  152. fclose(client->out);
  153. /* get dhcp lease */
  154. switch (dhcp_client) {
  155. case PUMP:
  156. if (dhostname)
  157. execlp("pump", "pump", "-i", interface, "-h", dhostname, NULL);
  158. else
  159. execlp("pump", "pump", "-i", interface, NULL);
  160. break;
  161. case DHCLIENT:
  162. /* First, set up dhclient.conf */
  163. if ((dc = file_open(DHCLIENT_CONF, "w"))) {
  164. fprintf(dc, "send vendor-class-identifier \"d-i\";\n" );
  165. fprintf(dc, "request ");
  166. for (ptr = dhclient_request_options_dhclient; *ptr; ptr++) {
  167. fprintf(dc, *ptr);
  168. /* look ahead to see if it is the last entry */
  169. if (*(ptr + 1))
  170. fprintf(dc, ", ");
  171. else
  172. fprintf(dc, ";\n");
  173. }
  174. if (dhostname) {
  175. fprintf(dc, "send host-name \"%s\";\n", dhostname);
  176. }
  177. fprintf(dc, "timeout %d;\n", dhcp_seconds);
  178. fclose(dc);
  179. }
  180. execlp("dhclient", "dhclient", "-1", interface, NULL);
  181. break;
  182. case UDHCPC:
  183. /* figure how many options we have */
  184. options_count = 0;
  185. for (ptr = dhclient_request_options_udhcpc; *ptr; ptr++)
  186. options_count++;
  187. arguments = malloc((options_count * 2 /* -O <option> repeatedly */
  188. + 9 /* Other arguments (listed below) */
  189. + 2 /* dhostname (maybe) */
  190. + 1 /* NULL */
  191. ) * sizeof(char **));
  192. /* set the command options */
  193. options_count = 0;
  194. arguments[options_count++] = "udhcpc";
  195. arguments[options_count++] = "-i";
  196. arguments[options_count++] = interface;
  197. arguments[options_count++] = "-V";
  198. arguments[options_count++] = "d-i";
  199. arguments[options_count++] = "-T";
  200. arguments[options_count++] = "1";
  201. arguments[options_count++] = "-t";
  202. arguments[options_count++] = dhcp_seconds_str;
  203. for (ptr = dhclient_request_options_udhcpc; *ptr; ptr++) {
  204. arguments[options_count++] = "-O";
  205. arguments[options_count++] = (char *)*ptr;
  206. }
  207. if (dhostname) {
  208. arguments[options_count++] = "-H";
  209. arguments[options_count++] = dhostname;
  210. }
  211. arguments[options_count] = NULL;
  212. execvp("udhcpc", arguments);
  213. free(arguments);
  214. break;
  215. }
  216. if (errno != 0)
  217. di_error("Could not exec dhcp client: %s", strerror(errno));
  218. return 1; /* should NEVER EVER get here */
  219. }
  220. else if (dhcp_pid == -1) {
  221. di_warning("DHCP fork failed; this is unlikely to end well");
  222. return 1;
  223. } else {
  224. /* dhcp_pid contains the child's PID */
  225. di_warning("Started DHCP client; PID is %i", dhcp_pid);
  226. signal(SIGCHLD, &dhcp_client_sigchld);
  227. return 0;
  228. }
  229. }
  230. static int kill_dhcp_client(void)
  231. {
  232. system("killall.sh");
  233. return 0;
  234. }
  235. /*
  236. * Poll the started DHCP client for netcfg/dhcp_timeout seconds (def. 15)
  237. * and return 0 if a lease is known to have been acquired,
  238. * 1 otherwise.
  239. *
  240. * The client should be run such that it exits once a lease is acquired
  241. * (although its child continues to run as a daemon)
  242. *
  243. * This function will NOT kill the child if time runs out. This allows
  244. * the user to choose to wait longer for the lease to be acquired.
  245. */
  246. int poll_dhcp_client (struct debconfclient *client)
  247. {
  248. int seconds_slept = 0;
  249. int ret = 1;
  250. int dhcp_seconds;
  251. debconf_get(client, "netcfg/dhcp_timeout");
  252. dhcp_seconds = atoi(client->value);
  253. /* show progress bar */
  254. debconf_capb(client, "backup progresscancel");
  255. debconf_progress_start(client, 0, dhcp_seconds, "netcfg/dhcp_progress");
  256. if (debconf_progress_info(client, "netcfg/dhcp_progress_note") == 30) {
  257. kill_dhcp_client();
  258. goto stop;
  259. }
  260. netcfg_progress_displayed = 1;
  261. /* wait between 2 and dhcp_seconds seconds for a DHCP lease */
  262. while ( ((dhcp_pid > 0) || (seconds_slept < 2))
  263. && (seconds_slept < dhcp_seconds) ) {
  264. sleep(1);
  265. seconds_slept++; /* Not exact but close enough */
  266. if (debconf_progress_step(client, 1) == 30)
  267. goto stop;
  268. }
  269. /* Either the client exited or time ran out */
  270. /* got a lease? display a success message */
  271. if (!(dhcp_pid > 0) && (dhcp_exit_status == 0)) {
  272. ret = 0;
  273. debconf_capb(client, "backup"); /* stop displaying cancel button */
  274. if (debconf_progress_set(client, dhcp_seconds) == 30)
  275. goto stop;
  276. if (debconf_progress_info(client, "netcfg/dhcp_success_note") == 30)
  277. goto stop;
  278. sleep(2);
  279. }
  280. stop:
  281. /* stop progress bar */
  282. debconf_progress_stop(client);
  283. debconf_capb(client, "backup");
  284. netcfg_progress_displayed = 0;
  285. return ret;
  286. }
  287. #define REPLY_RETRY_AUTOCONFIG 0
  288. #define REPLY_RETRY_WITH_HOSTNAME 1
  289. #define REPLY_CONFIGURE_MANUALLY 2
  290. #define REPLY_DONT_CONFIGURE 3
  291. #define REPLY_RECONFIGURE_WIFI 4
  292. #define REPLY_LOOP_BACK 5
  293. #define REPLY_CHECK_DHCP 6
  294. #define REPLY_ASK_OPTIONS 7
  295. int ask_dhcp_options (struct debconfclient *client)
  296. {
  297. int ret;
  298. if (is_wireless_iface(interface)) {
  299. debconf_metaget(client, "netcfg/internal-wifireconf", "description");
  300. debconf_subst(client, "netcfg/dhcp_options", "wifireconf", client->value);
  301. }
  302. else /* blank from last time */
  303. debconf_subst(client, "netcfg/dhcp_options", "wifireconf", "");
  304. /* critical, we don't want to enter a loop */
  305. debconf_input(client, "critical", "netcfg/dhcp_options");
  306. ret = debconf_go(client);
  307. if (ret == 30)
  308. return GO_BACK;
  309. debconf_get(client, "netcfg/dhcp_options");
  310. /* strcmp sucks */
  311. if (client->value[0] == 'R') { /* _R_etry ... or _R_econfigure ... */
  312. size_t len = strlen(client->value);
  313. if (client->value[len - 1] == 'e') /* ... with DHCP hostnam_e_ */
  314. return REPLY_RETRY_WITH_HOSTNAME;
  315. else if (client->value[len - 1] == 'k') /* ... wireless networ_k_ */
  316. return REPLY_RECONFIGURE_WIFI;
  317. else
  318. return REPLY_RETRY_AUTOCONFIG;
  319. }
  320. else if (client->value[0] == 'C') /* _C_onfigure ... */
  321. return REPLY_CONFIGURE_MANUALLY;
  322. else if (empty_str(client->value))
  323. return REPLY_LOOP_BACK;
  324. else
  325. return REPLY_DONT_CONFIGURE;
  326. }
  327. int ask_wifi_configuration (struct debconfclient *client)
  328. {
  329. enum { ABORT, ESSID, SECURITY_TYPE, WEP, WPA, START, DONE } wifistate = ESSID;
  330. extern enum wpa_t wpa_supplicant_status;
  331. if (wpa_supplicant_status != WPA_UNAVAIL)
  332. kill_wpa_supplicant();
  333. for (;;) {
  334. switch (wifistate) {
  335. case ESSID:
  336. if (wpa_supplicant_status == WPA_UNAVAIL)
  337. wifistate = (netcfg_wireless_set_essid(client, interface, "high") == GO_BACK) ?
  338. ABORT : WEP;
  339. else
  340. wifistate = (netcfg_wireless_set_essid(client, interface, "high") == GO_BACK) ?
  341. ABORT : SECURITY_TYPE;
  342. break;
  343. case SECURITY_TYPE:
  344. {
  345. int ret;
  346. ret = wireless_security_type(client, interface);
  347. if (ret == GO_BACK)
  348. wifistate = ESSID;
  349. else if (ret == REPLY_WPA)
  350. wifistate = WPA;
  351. else
  352. wifistate = WEP;
  353. break;
  354. }
  355. case WEP:
  356. if (wpa_supplicant_status == WPA_UNAVAIL)
  357. wifistate = (netcfg_wireless_set_wep(client, interface) == GO_BACK) ?
  358. ESSID : DONE;
  359. else
  360. wifistate = (netcfg_wireless_set_wep(client, interface) == GO_BACK) ?
  361. SECURITY_TYPE : DONE;
  362. break;
  363. case WPA:
  364. wifistate = (netcfg_set_passphrase(client, interface) == GO_BACK) ?
  365. SECURITY_TYPE : START;
  366. break;
  367. case START:
  368. wifistate = (wpa_supplicant_start(client, interface, essid, passphrase) == GO_BACK) ?
  369. ESSID : DONE;
  370. break;
  371. case ABORT:
  372. return REPLY_ASK_OPTIONS;
  373. break;
  374. case DONE:
  375. return REPLY_CHECK_DHCP;
  376. break;
  377. }
  378. }
  379. }
  380. int netcfg_activate_dhcp (struct debconfclient *client)
  381. {
  382. char* dhostname = NULL;
  383. enum { START, POLL, ASK_OPTIONS, DHCP_HOSTNAME, HOSTNAME, DOMAIN, HOSTNAME_SANS_NETWORK } state = START;
  384. kill_dhcp_client();
  385. loop_setup();
  386. for (;;) {
  387. switch (state) {
  388. case START:
  389. if (start_dhcp_client(client, dhostname))
  390. netcfg_die(client); /* change later */
  391. else
  392. state = POLL;
  393. break;
  394. case POLL:
  395. if (poll_dhcp_client(client)) {
  396. /* could not get a lease, show the error, present options */
  397. debconf_capb(client, "");
  398. debconf_input(client, "critical", "netcfg/dhcp_failed");
  399. debconf_go(client);
  400. debconf_capb(client, "backup");
  401. state = ASK_OPTIONS;
  402. } else {
  403. /* got a lease */
  404. /*
  405. * That means that the DHCP client has exited, although its
  406. * child is still running as a daemon
  407. */
  408. /* Before doing anything else, check for a default route */
  409. if (no_default_route()) {
  410. debconf_input(client, "critical", "netcfg/no_default_route");
  411. debconf_go(client);
  412. debconf_get(client, "netcfg/no_default_route");
  413. if (!strcmp(client->value, "false")) {
  414. state = ASK_OPTIONS;
  415. break;
  416. }
  417. }
  418. /*
  419. * Set defaults for domain name and hostname
  420. */
  421. char buf[MAXHOSTNAMELEN + 1] = { 0 };
  422. char *ptr = NULL;
  423. FILE *d = NULL;
  424. have_domain = 0;
  425. /*
  426. * Default to the domain name returned via DHCP, if any
  427. */
  428. if ((d = fopen(DOMAIN_FILE, "r")) != NULL) {
  429. char domain[_UTSNAME_LENGTH + 1] = { 0 };
  430. fgets(domain, _UTSNAME_LENGTH, d);
  431. fclose(d);
  432. unlink(DOMAIN_FILE);
  433. if (!empty_str(domain) && valid_domain(domain)) {
  434. debconf_set(client, "netcfg/get_domain", domain);
  435. have_domain = 1;
  436. }
  437. }
  438. /*
  439. * Record any ntp server information from DHCP for later
  440. * verification and use by clock-setup
  441. */
  442. if ((d = fopen(NTP_SERVER_FILE, "r")) != NULL) {
  443. char ntpservers[DHCP_OPTION_LEN + 1] = { 0 };
  444. fgets(ntpservers, DHCP_OPTION_LEN, d);
  445. fclose(d);
  446. unlink(NTP_SERVER_FILE);
  447. if (!empty_str(ntpservers)) {
  448. debconf_set(client, "netcfg/dhcp_ntp_servers",
  449. ntpservers);
  450. }
  451. }
  452. /*
  453. * Default to the hostname returned via DHCP, if any,
  454. * otherwise to the requested DHCP hostname
  455. * otherwise to the hostname found in DNS for the IP address
  456. * of the interface
  457. */
  458. if (gethostname(buf, sizeof(buf)) == 0
  459. && !empty_str(buf)
  460. && strcmp(buf, "(none)")
  461. && valid_domain(buf)
  462. ) {
  463. di_info("DHCP hostname: \"%s\"", buf);
  464. debconf_set(client, "netcfg/get_hostname", buf);
  465. }
  466. else if (dhostname) {
  467. debconf_set(client, "netcfg/get_hostname", dhostname);
  468. } else {
  469. struct ifreq ifr;
  470. struct in_addr d_ipaddr = { 0 };
  471. ifr.ifr_addr.sa_family = AF_INET;
  472. strncpy(ifr.ifr_name, interface, IFNAMSIZ);
  473. if (ioctl(skfd, SIOCGIFADDR, &ifr) == 0) {
  474. d_ipaddr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
  475. seed_hostname_from_dns(client, &d_ipaddr);
  476. }
  477. else
  478. di_warning("ioctl failed (%s)", strerror(errno));
  479. }
  480. /*
  481. * Default to the domain name that is the domain part
  482. * of the hostname, if any
  483. */
  484. if (have_domain == 0 && (ptr = strchr(buf, '.')) != NULL) {
  485. debconf_set(client, "netcfg/get_domain", ptr + 1);
  486. have_domain = 1;
  487. }
  488. /* Make sure we have NS going if the DHCP server didn't serve it up */
  489. if (resolv_conf_entries() <= 0) {
  490. char *nameservers = NULL;
  491. if (netcfg_get_nameservers (client, &nameservers) == GO_BACK) {
  492. state = ASK_OPTIONS;
  493. break;
  494. }
  495. netcfg_nameservers_to_array (nameservers, nameserver_array);
  496. netcfg_write_resolv (domain, nameserver_array);
  497. }
  498. state = HOSTNAME;
  499. }
  500. break;
  501. case ASK_OPTIONS:
  502. /* DHCP client may still be running */
  503. switch (ask_dhcp_options (client)) {
  504. case GO_BACK:
  505. kill_dhcp_client();
  506. return 10;
  507. case REPLY_RETRY_WITH_HOSTNAME:
  508. state = DHCP_HOSTNAME;
  509. break;
  510. case REPLY_CONFIGURE_MANUALLY:
  511. kill_dhcp_client();
  512. return 15;
  513. break;
  514. case REPLY_DONT_CONFIGURE:
  515. kill_dhcp_client();
  516. netcfg_write_loopback();
  517. state = HOSTNAME_SANS_NETWORK;
  518. break;
  519. case REPLY_RETRY_AUTOCONFIG:
  520. if (dhcp_pid > 0)
  521. state = POLL;
  522. else {
  523. kill_dhcp_client();
  524. state = START;
  525. }
  526. break;
  527. case REPLY_RECONFIGURE_WIFI:
  528. if (ask_wifi_configuration(client) == REPLY_CHECK_DHCP) {
  529. kill_dhcp_client();
  530. state = START;
  531. }
  532. else
  533. state = ASK_OPTIONS;
  534. break;
  535. }
  536. break;
  537. case DHCP_HOSTNAME:
  538. /* DHCP client may still be running */
  539. if (netcfg_get_hostname(client, "netcfg/dhcp_hostname", &dhostname, 0))
  540. state = ASK_OPTIONS;
  541. else {
  542. if (empty_str(dhostname)) {
  543. free(dhostname);
  544. dhostname = NULL;
  545. }
  546. kill_dhcp_client();
  547. state = START;
  548. }
  549. break;
  550. case HOSTNAME:
  551. if (netcfg_get_hostname (client, "netcfg/get_hostname", &hostname, 1)) {
  552. /*
  553. * Going back to POLL wouldn't make much sense.
  554. * However, it does make sense to go to the retry
  555. * screen where the user can elect to retry DHCP with
  556. * a requested DHCP hostname, etc.
  557. */
  558. state = ASK_OPTIONS;
  559. }
  560. else
  561. state = DOMAIN;
  562. break;
  563. case DOMAIN:
  564. if (!have_domain && netcfg_get_domain (client, &domain))
  565. state = HOSTNAME;
  566. else {
  567. netcfg_write_common(ipaddress, hostname, domain);
  568. netcfg_write_dhcp(interface, dhostname);
  569. /* If the resolv.conf was written by udhcpc, then nameserver_array
  570. * will be empty and we'll need to populate it. If we asked for
  571. * the nameservers, then it'll be full, but nobody will care if we
  572. * refill it.
  573. */
  574. if (read_resolv_conf_nameservers(nameserver_array))
  575. netcfg_write_resolv(domain, nameserver_array);
  576. else
  577. printf("Error reading resolv.conf for nameservers\n");
  578. return 0;
  579. }
  580. break;
  581. case HOSTNAME_SANS_NETWORK:
  582. if (netcfg_get_hostname (client, "netcfg/get_hostname", &hostname, 0))
  583. state = ASK_OPTIONS;
  584. else {
  585. struct in_addr null_ipaddress;
  586. null_ipaddress.s_addr = 0;
  587. netcfg_write_common(null_ipaddress, hostname, NULL);
  588. return 0;
  589. }
  590. break;
  591. }
  592. }
  593. }
  594. /* returns number of 'nameserver' entries in resolv.conf */
  595. int resolv_conf_entries (void)
  596. {
  597. FILE *f;
  598. int count = 0;
  599. if ((f = fopen(RESOLV_FILE, "r")) != NULL) {
  600. char buf[256];
  601. while (fgets(buf, 256, f) != NULL) {
  602. char *ptr;
  603. if ((ptr = strchr(buf, ' ')) != NULL) {
  604. *ptr = '\0';
  605. if (strcmp(buf, "nameserver") == 0)
  606. count++;
  607. }
  608. }
  609. fclose(f);
  610. }
  611. else
  612. count = -1;
  613. return count;
  614. }
  615. /* Read the nameserver entries out of resolv.conf and stick them into
  616. * nameservers_array, so we can write out a newer, shinier resolv.conf
  617. */
  618. int read_resolv_conf_nameservers(struct in_addr array[])
  619. {
  620. FILE *f;
  621. int i = 0;
  622. if ((f = fopen(RESOLV_FILE, "r")) != NULL) {
  623. char buf[256];
  624. while (fgets(buf, 256, f) != NULL) {
  625. char *ptr;
  626. if (strncmp(buf, "nameserver ", strlen("nameserver ")) == 0) {
  627. /* Chop off trailing \n */
  628. if (buf[strlen(buf)-1] == '\n')
  629. buf[strlen(buf)-1] = '\0';
  630. ptr = buf + strlen("nameserver ");
  631. inet_pton(AF_INET, ptr, &array[i++]);
  632. if (i == 3) {
  633. /* We can only hold so many nameservers, and we've reached
  634. * our limit. Sorry.
  635. */
  636. break;
  637. }
  638. }
  639. }
  640. fclose(f);
  641. array[i].s_addr = 0;
  642. return 1;
  643. }
  644. else
  645. return 0;
  646. }