File: netplan-conf.c

package info (click to toggle)
netcfg 1.201
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 4,036 kB
  • sloc: ansic: 5,719; sh: 209; makefile: 83
file content (185 lines) | stat: -rw-r--r-- 6,978 bytes parent folder | download | duplicates (2)
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);
}