1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
|
#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#ifdef WIRELESS
#include <iwlib.h>
#endif
#include <debian-installer.h>
#include "netplan-conf.h"
/* Functions for printing information in Netplan format. */
static void netplan_write_header(FILE *fd)
{
// Consider using libnetplan.so instead of writing plain YAML.
fprintf(fd, "# This is the network config written by debian-installer.\n");
fprintf(fd, "# For more information, see netplan(5).\n");
fprintf(fd, "network:\n");
fprintf(fd, " version: 2\n");
}
static void netplan_write_wireless(FILE *fd, const struct netcfg_interface *interface)
{
if (!(interface->essid && *interface->essid)) {
di_error("Unspecified SSID"); // "essid=any" not supported by Netplan
exit(1);
}
fprintf(fd, " wifis:\n");
fprintf(fd, " %s:\n", interface->name); // consider matching on mac address
fprintf(fd, " access-points:\n");
fprintf(fd, " \"%s\":\n", interface->essid);
if (interface->wifi_security == REPLY_WPA || interface->wpa_supplicant_status == WPA_QUEUED)
fprintf(fd, " password: %s\n", interface->passphrase);
else {
fprintf(fd, " auth:\n");
fprintf(fd, " key-management: none\n"); // open network
}
if (interface->mode == ADHOC)
fprintf(fd, " mode: adhoc\n");
}
static void netplan_write_wired(FILE *fd, const struct netcfg_interface *interface)
{
fprintf(fd, " ethernets:\n");
fprintf(fd, " %s:\n", interface->name); // consider matching on mac address
}
static void netplan_write_common(FILE *fd, const struct netcfg_interface *interface)
{
// DNS: nameservers and search domain
if (!empty_str(interface->nameservers[0]) || !empty_str(domain)) {
fprintf(fd, " nameservers:\n");
unsigned int i = 0;
if (!empty_str(interface->nameservers[0])) {
fprintf(fd, " addresses:\n");
for (i = 0; i < NETCFG_NAMESERVERS_MAX; i++) {
if (!empty_str(interface->nameservers[i]))
fprintf(fd, " - %s\n", interface->nameservers[i]);
}
}
if (!empty_str(domain)) {
fprintf(fd, " search:\n");
fprintf(fd, " - %s\n", domain);
}
}
// Hotplug
if (iface_is_hotpluggable(interface->name) || find_in_stab(interface->name)) {
fprintf(fd, " optional: true\n");
}
// DHCP
if (interface->dhcp == 1) {
di_debug("Writing DHCP stanza for %s", interface->name);
fprintf(fd, " ipv6-privacy: true\n");
fprintf(fd, " dhcp4: true\n");
fprintf(fd, " dhcp6: true\n");
if (!empty_str(interface->dhcp_hostname)) {
fprintf(fd, " dhcp4-overrides:\n");
fprintf(fd, " hostname: \"%s\"\n", interface->dhcp_hostname);
fprintf(fd, " dhcp6-overrides:\n");
fprintf(fd, " hostname: \"%s\"\n", interface->dhcp_hostname);
}
}
// SLAAC
if (interface->slaac == 1) {
di_debug("Writing SLAAC stanza for %s", interface->name);
// Implicitly enable Netplan's dhcp6 & ipv6-privacy, see:
// https://netplan.rtfd.io/en/stable/netplan-yaml/#properties-for-all-device-types
if (interface->dhcp == 0) {
fprintf(fd, " ipv6-privacy: true\n");
fprintf(fd, " dhcp6: true\n");
}
fprintf(fd, " accept-ra: true\n");
}
// Static IP
// IPv6 is unsupported on point-to-point links, according to
// "netcfg-static.templates", so we can hardcode a /32 netmask in that case.
if (interface->address_family == AF_INET || interface->address_family == AF_INET6) {
di_debug("Writing static IP stanza for %s", interface->name);
fprintf(fd, " addresses:\n");
fprintf(fd, " - \"%s/%i\"\n", interface->ipaddress,
empty_str(interface->pointopoint) ? interface->masklen : 32);
}
// Default gateway
// Installing an "on-link" route for point-to-point or manual IPv4 /32 or
// IPv6 /128 netmasks. See: https://salsa.debian.org/installer-team/netcfg/-/merge_requests/10
if (!empty_str(interface->gateway) || !empty_str(interface->pointopoint)) {
fprintf(fd, " routes:\n");
fprintf(fd, " - to: default\n");
fprintf(fd, " via: %s\n",
empty_str(interface->pointopoint) ? interface->gateway : interface->pointopoint);
if (!empty_str(interface->pointopoint) ||
(interface->address_family == AF_INET && interface->masklen == 32) ||
(interface->address_family == AF_INET6 && interface->masklen == 128))
fprintf(fd, " on-link: true\n");
}
}
/* Write Netplan config file. */
void netplan_write_configuration(const struct netcfg_interface *interface)
{
FILE *config_file = NULL;
char buffer[NETPLAN_MAX_LEN_BUF] = {0};
int is_loopback = (interface->loopback == 1);
int is_wireless = is_wireless_iface(interface->name);
// WEP is deprecated and not supported by Netplan. Do not write any configuration.
if (is_wireless && interface->wepkey != NULL) {
di_warning("Netplan does not support insecure WEP wireless networks.");
di_debug("Not writing any Netplan configuration.");
return;
}
/* Create the directory for the config file and clear any possible
* previous files found there. */
sprintf(buffer, "mkdir -p %s", NETPLAN_CONFIG_FILE_PATH);
di_exec_shell(buffer);
/* If the directory exist mkdir will do nothing, so just remove every file
* there. Rely on the fact that for now netcfg only does config for one
* interface. */
sprintf(buffer, "rm %s/*", NETPLAN_CONFIG_FILE_PATH);
di_exec_shell(buffer);
/* Open file using its full path. */
sprintf(buffer, "%s/%s", NETPLAN_CONFIG_FILE_PATH, NETPLAN_INSTALLER_FILE);
config_file = fopen(buffer, "w");
if (config_file == NULL) {
di_info("Unable to open file for writing Netplan configuration: "
"%s", strerror(errno));
return;
}
if (fchmod(fileno(config_file), 0600) != 0) {
di_error("Netplan configuration file cannot be protected "
"from reading: %s", strerror(errno));
exit(1);
}
netplan_write_header(config_file);
// Do not write anything, as loopback is set up by systemd implicitly.
// Being a dependency, systemd is always available when Netplan is in use.
if (is_loopback) {}
else if (is_wireless)
netplan_write_wireless(config_file, interface);
else
netplan_write_wired(config_file, interface);
netplan_write_common(config_file, interface);
fclose(config_file);
}
|