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.
 
 
 
 

278 lines
8.8 KiB

  1. /*
  2. * Functions to write things into /etc/network/interfaces
  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 <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <unistd.h>
  25. #include <fcntl.h>
  26. #include <debian-installer.h>
  27. static int nc_wi_header(FILE *fd)
  28. {
  29. fprintf(fd, "# This file describes the network interfaces available on your system\n");
  30. fprintf(fd, "# and how to activate them. For more information, see interfaces(5).\n");
  31. fprintf(fd, "\nsource /etc/network/interfaces.d/*\n");
  32. return 1;
  33. }
  34. static int nc_wi_loopback(const struct netcfg_interface *interface, FILE *fd)
  35. {
  36. fprintf(fd, "\n# The loopback network interface\n");
  37. fprintf(fd, "auto %s\n", interface->name);
  38. fprintf(fd, "iface %s inet loopback\n", interface->name);
  39. return 1;
  40. }
  41. static int nc_wi_wireless_options(const struct netcfg_interface *interface, FILE *fd)
  42. {
  43. /*
  44. * Write wireless-tools options
  45. */
  46. /* FIXME: Whether this is a wireless interface should be stored
  47. * with the interface
  48. */
  49. if (interface->wpa_supplicant_status == WPA_QUEUED) {
  50. fprintf(fd, "\twpa-ssid %s\n", interface->essid);
  51. fprintf(fd, "\twpa-psk %s\n", interface->passphrase);
  52. } else {
  53. fprintf(fd, "\t# wireless-* options are implemented by the wireless-tools package\n");
  54. fprintf(fd, "\twireless-mode %s\n",
  55. (interface->mode == MANAGED) ? "managed" : "ad-hoc");
  56. fprintf(fd, "\twireless-essid %s\n",
  57. (interface->essid && *interface->essid) ? interface->essid : "any");
  58. if (interface->wepkey != NULL)
  59. fprintf(fd, "\twireless-key1 %s\n", interface->wepkey);
  60. }
  61. return 1;
  62. }
  63. /* Write out a DHCP stanza for the given interface
  64. */
  65. static int nc_wi_dhcp(const struct netcfg_interface *interface, FILE *fd)
  66. {
  67. fprintf(fd, "\n# The primary network interface\n");
  68. if (!iface_is_hotpluggable(interface->name) && !find_in_stab(interface->name))
  69. fprintf(fd, "auto %s\n", interface->name);
  70. else
  71. fprintf(fd, "allow-hotplug %s\n", interface->name);
  72. fprintf(fd, "iface %s inet dhcp\n", interface->name);
  73. if (!empty_str(interface->dhcp_hostname)) {
  74. fprintf(fd, "\thostname %s\n", interface->dhcp_hostname);
  75. }
  76. return 1;
  77. }
  78. /* Write out a SLAAC stanza for the given interface
  79. */
  80. static int nc_wi_slaac(const struct netcfg_interface *interface, FILE *fd)
  81. {
  82. if (interface->dhcp == 0)
  83. fprintf(fd, "\n# The primary network interface\n");
  84. fprintf(fd, "# This is an autoconfigured IPv6 interface\n");
  85. if (interface->dhcp == 0) {
  86. if (!iface_is_hotpluggable(interface->name) && !find_in_stab(interface->name))
  87. fprintf(fd, "auto %s\n", interface->name);
  88. else
  89. fprintf(fd, "allow-hotplug %s\n", interface->name);
  90. }
  91. fprintf(fd, "iface %s inet6 auto\n", interface->name);
  92. /* fprintf(fd, "\t# Activate RFC 4941 privacy extensions for outgoing connections. The\n");
  93. fprintf(fd, "\t# machine will still be reachable via its EUI-64 interface identifier.\n");
  94. fprintf(fd, "\tprivext 2\n");*/
  95. return 1;
  96. }
  97. /* Write out a static IPv4 config stanza for the given interface
  98. */
  99. static int nc_wi_static_ipv4(const struct netcfg_interface *interface, FILE *fd)
  100. {
  101. fprintf(fd, "\n# The primary network interface\n");
  102. if (!iface_is_hotpluggable(interface->name) && !find_in_stab(interface->name))
  103. fprintf(fd, "auto %s\n", interface->name);
  104. else
  105. fprintf(fd, "allow-hotplug %s\n", interface->name);
  106. fprintf(fd, "iface %s inet static\n", interface->name);
  107. fprintf(fd, "\taddress %s/%i\n", interface->ipaddress,
  108. empty_str(interface->pointopoint) ? interface->masklen : 32);
  109. if (!empty_str(interface->gateway))
  110. fprintf(fd, "\tgateway %s\n",
  111. empty_str(interface->pointopoint) ? interface->gateway : interface->pointopoint);
  112. if (!empty_str(interface->pointopoint))
  113. fprintf(fd, "\tpointopoint %s\n", interface->pointopoint);
  114. return 1;
  115. }
  116. /* Write out a static IPv6 config stanza for the given interface
  117. */
  118. static int nc_wi_static_ipv6(const struct netcfg_interface *interface, FILE *fd)
  119. {
  120. fprintf(fd, "\n# The primary network interface\n");
  121. if (!iface_is_hotpluggable(interface->name) && !find_in_stab(interface->name))
  122. fprintf(fd, "auto %s\n", interface->name);
  123. else
  124. fprintf(fd, "allow-hotplug %s\n", interface->name);
  125. fprintf(fd, "iface %s inet6 static\n", interface->name);
  126. fprintf(fd, "\taddress %s/%i\n", interface->ipaddress, interface->masklen);
  127. if (!empty_str(interface->gateway))
  128. fprintf(fd, "\tgateway %s\n", interface->gateway);
  129. return 1;
  130. }
  131. /* The main function for writing things to INTERFACES_FILE (aka
  132. * /etc/network/interfaces).
  133. *
  134. * In principle, this function is very simple: just examine the interface
  135. * we've been passed, and call out to the relevant private helper function.
  136. * In practice...
  137. *
  138. * Takes the interface struct to write out. If you pass NULL, the file gets
  139. * deleted and a helpful comment header gets written.
  140. *
  141. * Returns a true/false boolean representing "did everything go OK"; if 0 is
  142. * returned, the interfaces file will not have been modified, and errno will
  143. * contain the details.
  144. */
  145. int netcfg_write_interface(const struct netcfg_interface *interface)
  146. {
  147. FILE *fd;
  148. int rv;
  149. struct stat stat_buf;
  150. if (!interface) {
  151. di_debug("No interface given; clearing " INTERFACES_FILE);
  152. rv = unlink(INTERFACES_FILE);
  153. if (rv < 0 && errno != ENOENT) {
  154. di_info("Error clearing %s: %s", INTERFACES_FILE, strerror(errno));
  155. return 0;
  156. }
  157. }
  158. fd = file_open(INTERFACES_FILE ".tmp", "w");
  159. if (!fd) {
  160. di_warning("Failed to open %s.tmp: %s", INTERFACES_FILE, strerror(errno));
  161. return 0;
  162. }
  163. /* All of this code is to handle the apparently simple task of
  164. * copying the existing interfaces file to the tmpfile (if it exists)
  165. * so we can add our new stuff to it. Bloody longwinded way of doing
  166. * it, I'm sure you'll agree.
  167. */
  168. rv = stat(INTERFACES_FILE, &stat_buf);
  169. if (rv < 0 && errno != ENOENT) {
  170. di_warning("Failed to stat %s: %s", INTERFACES_FILE, strerror(errno));
  171. unlink(INTERFACES_FILE ".tmp");
  172. return 0;
  173. }
  174. if (rv == 0) {
  175. char *tmpbuf = malloc(stat_buf.st_size + 1);
  176. int origfd;
  177. origfd = open(INTERFACES_FILE, O_RDONLY);
  178. if (origfd < 0) {
  179. di_warning("Failed to open %s: %s", INTERFACES_FILE, strerror(errno));
  180. fclose(fd);
  181. unlink(INTERFACES_FILE ".tmp");
  182. free(tmpbuf);
  183. return 0;
  184. }
  185. rv = read(origfd, tmpbuf, stat_buf.st_size);
  186. if (rv < 0) {
  187. di_warning("Failed to read %s: %s", INTERFACES_FILE, strerror(errno));
  188. fclose(fd);
  189. unlink(INTERFACES_FILE ".tmp");
  190. free(tmpbuf);
  191. close(origfd);
  192. return 0;
  193. }
  194. if (rv != stat_buf.st_size) {
  195. di_warning("Short read on %s", INTERFACES_FILE);
  196. fclose(fd);
  197. unlink(INTERFACES_FILE ".tmp");
  198. free(tmpbuf);
  199. close(origfd);
  200. return 0;
  201. }
  202. rv = fwrite(tmpbuf, sizeof(char), stat_buf.st_size, fd);
  203. if (rv != (int)stat_buf.st_size) {
  204. di_warning("Short write on %s.tmp", INTERFACES_FILE);
  205. fclose(fd);
  206. unlink(INTERFACES_FILE ".tmp");
  207. free(tmpbuf);
  208. close(origfd);
  209. return 0;
  210. }
  211. free(tmpbuf);
  212. close(origfd);
  213. }
  214. /* Thank $DEITY all that's out of the way... now we can write a
  215. * freaking interfaces file entry */
  216. rv = 1;
  217. if (!interface) {
  218. di_debug("Writing informative header");
  219. rv = nc_wi_header(fd);
  220. } else if (interface->loopback == 1) {
  221. di_debug("Writing loopback interface");
  222. rv = nc_wi_loopback(interface, fd);
  223. } else if (interface->dhcp == 1 || interface->slaac == 1) {
  224. if (interface->dhcp == 1) {
  225. di_debug("Writing DHCP stanza for %s", interface->name);
  226. rv = nc_wi_dhcp(interface, fd);
  227. }
  228. if (interface->slaac == 1) {
  229. di_debug("Writing SLAAC stanza for %s", interface->name);
  230. rv = nc_wi_slaac(interface, fd);
  231. }
  232. } else if (interface->address_family == AF_INET) {
  233. di_debug("Writing static IPv4 stanza for %s", interface->name);
  234. rv = nc_wi_static_ipv4(interface, fd);
  235. } else if (interface->address_family == AF_INET6) {
  236. di_debug("Writing static IPv6 stanza for %s", interface->name);
  237. rv = nc_wi_static_ipv6(interface, fd);
  238. }
  239. if (rv && interface && is_wireless_iface(interface->name)) {
  240. di_debug("Writing wireless options for %s", interface->name);
  241. rv = nc_wi_wireless_options(interface, fd);
  242. }
  243. if (rv) {
  244. di_debug("Success!");
  245. rename(INTERFACES_FILE ".tmp", INTERFACES_FILE);
  246. }
  247. fclose(fd);
  248. unlink(INTERFACES_FILE ".tmp");
  249. return rv;
  250. }