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.
 
 
 
 

237 lines
7.0 KiB

  1. /*
  2. * IPv6-specific functions for netcfg.
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  17. */
  18. #include "netcfg.h"
  19. #include <errno.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <debian-installer.h>
  23. /* Obsessively watch the network configuration for the given interface,
  24. * waiting for it to be properly configured. If the +interface+ struct has
  25. * an address configured, we'll wait until that address is available,
  26. * otherwise we're just interested in any global address.
  27. */
  28. void nc_v6_wait_for_complete_configuration(const struct netcfg_interface *interface)
  29. {
  30. while (!nc_v6_interface_configured(interface, 0)) {
  31. usleep(250000);
  32. }
  33. }
  34. /* Obsessively watch the network configuration for the given interface,
  35. * waiting for it to have completed configuration of a link-local address.
  36. */
  37. void nc_v6_wait_for_link_local(const struct netcfg_interface *interface)
  38. {
  39. while (!nc_v6_interface_configured(interface, 1)) {
  40. usleep(250000);
  41. }
  42. }
  43. /* Inspect the live configuration of the given interface, and return a boolean
  44. * indicating whether it's configuration is complete. "Complete" is defined
  45. * as having an IPv6 address properly assigned (ie not "tentative"). If
  46. * +link_local+ is true, then we'll be satisfied with a link-scope address;
  47. * if +link_local+ is false, then we require a global scope address.
  48. *
  49. * If an IP address is specified in the +interface+ struct, then we require that
  50. * address to have been configured.
  51. */
  52. int nc_v6_interface_configured(const struct netcfg_interface *interface, const int link_local)
  53. {
  54. FILE *cmdfd;
  55. char l[256];
  56. char cmd[512];
  57. int address_found = 0;
  58. di_debug("nc_v6_interface_configured(%s, scope %s)", interface->name, link_local ? "local" : "global");
  59. #if defined(__FreeBSD_kernel__)
  60. snprintf(cmd, 512, "ifconfig %s", interface->name);
  61. #else
  62. snprintf(cmd, 512, "ip addr show %s", interface->name);
  63. #endif
  64. di_debug("Running %s to look for address", cmd);
  65. if ((cmdfd = popen(cmd, "r")) != NULL) {
  66. while (fgets(l, 256, cmdfd) != NULL) {
  67. di_debug("ip line: %s", l);
  68. /* Aah, string manipulation in C. What fun. */
  69. #if defined(__FreeBSD_kernel__)
  70. if (strncmp("\tinet6 ", l, 7)) {
  71. continue;
  72. }
  73. /* An address with a scopeid isn't a global
  74. * address, apparently
  75. */
  76. if (!link_local && strstr(l, " scopeid")) {
  77. continue;
  78. }
  79. #else
  80. if (strncmp(" inet6 ", l, 10)) {
  81. continue;
  82. }
  83. if (!link_local && !strstr(l, " scope global")) {
  84. continue;
  85. }
  86. #endif
  87. if (!empty_str(interface->ipaddress)) {
  88. if (!strstr(l, interface->ipaddress)) {
  89. continue;
  90. }
  91. }
  92. if (strstr(l, " tentative")) {
  93. continue;
  94. }
  95. /* The address is in the interface and not tentative.
  96. * Good enough for me.
  97. */
  98. di_debug("Configured address found");
  99. address_found = 1;
  100. }
  101. pclose(cmdfd);
  102. }
  103. return address_found;
  104. }
  105. /* Discover if the ManageConfig and/or OtherConfig flags are set in the RAs
  106. * that we're receiving.
  107. *
  108. * Calls out to rdisc6 to get the data we're looking for. If we get a good
  109. * response out of rdisc6, we set the v6_stateful_config and v6_stateless_config
  110. * flags to true/false (1/0) as appropriate and return true. If ndisc6
  111. * doesn't give us anything, we set the flags to unknown (-1) and return
  112. * false.
  113. *
  114. * We call out to rdisc6 multiple times, as it seems like it can take a little
  115. * while for radvd to get into gear. Yay for progress bars.
  116. */
  117. int nc_v6_get_config_flags(struct debconfclient *client, struct netcfg_interface *interface)
  118. {
  119. FILE *cmdfd;
  120. char l[512], cmd[512];
  121. const int RDISC6_TRIES = 12;
  122. int count, ll_ok = 0;
  123. /* First things first... we need to have a link-local address before
  124. * we can send/receive RAs... and those can take some time to
  125. * appear due to DAD
  126. */
  127. debconf_capb(client, "progresscancel");
  128. debconf_progress_start(client, 0, RDISC6_TRIES, "netcfg/ipv6_link_local_wait_title");
  129. for (count = 0; count < RDISC6_TRIES; count++) {
  130. usleep(250000);
  131. if (debconf_progress_step(client, 1) == 30) {
  132. /* User cancel */
  133. break;
  134. }
  135. if (nc_v6_interface_configured(interface, 1)) {
  136. /* We got a useful response */
  137. debconf_progress_set(client, RDISC6_TRIES);
  138. ll_ok = 1;
  139. break;
  140. }
  141. }
  142. debconf_progress_stop(client);
  143. if (!ll_ok) {
  144. di_info("No IPv6 support found... how does that happen?");
  145. return 0;
  146. }
  147. snprintf(cmd, sizeof(cmd), "rdisc6 -1 -r 1 -w 500 -n %s", interface->name);
  148. di_debug("Running %s to get IPv6 config flags", cmd);
  149. interface->v6_stateful_config = -1;
  150. interface->v6_stateless_config = -1;
  151. debconf_capb(client, "progresscancel");
  152. debconf_progress_start(client, 0, RDISC6_TRIES, "netcfg/ipv6_config_flags_wait_title");
  153. for (count = 0; count < RDISC6_TRIES; count++) {
  154. if ((cmdfd = popen(cmd, "r")) != NULL) {
  155. while (fgets(l, sizeof(l), cmdfd) != NULL) {
  156. di_debug("rdisc6 line: %s", l);
  157. if (strncmp("Stateful address conf", l, 21) == 0) {
  158. di_debug("Got stateful address line");
  159. /* stateful_config flag */
  160. if (strstr(l, " No")) {
  161. di_debug("stateful=0");
  162. interface->v6_stateful_config = 0;
  163. } else if (strstr(l, " Yes")) {
  164. di_debug("stateful=1");
  165. interface->v6_stateful_config = 1;
  166. }
  167. } else if (strncmp("Stateful other conf", l, 19) == 0) {
  168. /* other_config flag */
  169. if (strstr(l, " No")) {
  170. di_debug("stateless=0");
  171. interface->v6_stateless_config = 0;
  172. } else if (strstr(l, " Yes")) {
  173. di_debug("stateless=1");
  174. interface->v6_stateless_config = 1;
  175. }
  176. }
  177. }
  178. di_debug("rdisc6 parsing finished");
  179. pclose(cmdfd);
  180. }
  181. if (debconf_progress_step(client, 1) == 30) {
  182. /* User cancel */
  183. break;
  184. }
  185. if (interface->v6_stateful_config != -1 &&
  186. interface->v6_stateless_config != -1) {
  187. /* We got a useful response */
  188. debconf_progress_set(client, RDISC6_TRIES);
  189. break;
  190. }
  191. }
  192. /* In theory managed and other are independent of each other. In
  193. * practise both being present means that addresses and configuration
  194. * are available via DHCPv6. Hence set stateless_config to 0.
  195. * Otherwise the autoconfiguration logic will only spawn a stateless
  196. * client.
  197. */
  198. if (interface->v6_stateful_config == 1 &&
  199. interface->v6_stateless_config == 1) {
  200. interface->v6_stateless_config = 0;
  201. }
  202. debconf_progress_stop(client);
  203. if (interface->v6_stateful_config != -1 &&
  204. interface->v6_stateless_config != -1) {
  205. return 1;
  206. } else {
  207. return 0;
  208. }
  209. }