Commit 5da7c39c authored by jan.koester's avatar jan.koester
Browse files

test

parent 3722746c
Loading
Loading
Loading
Loading
+69 −0
Changes for include/sysbus/client.h: 69 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include "sysbus/message.h"

#include <functional>
#include <optional>
#include <string>
#include <vector>

@@ -29,17 +30,34 @@ constexpr const char *GetUnit = "GetUnit";
constexpr const char *ListUnits = "ListUnits";
constexpr const char *Reload = "Reload";
constexpr const char *Subscribe = "Subscribe";

// Network interfaces. Configurations are .network files in
// /etc/syslite/network; Create/Edit/Delete change only the files, Start,
// Reload and Restart apply them.
constexpr const char *ListInterfaces = "ListInterfaces";
constexpr const char *GetInterface = "GetInterface";
constexpr const char *CreateInterface = "CreateInterface";
constexpr const char *EditInterface = "EditInterface";
constexpr const char *DeleteInterface = "DeleteInterface";
constexpr const char *StartInterface = "StartInterface";
constexpr const char *StopInterface = "StopInterface";
constexpr const char *RestartInterface = "RestartInterface";
constexpr const char *ReloadInterface = "ReloadInterface";            // no interface: all
constexpr const char *ForceReloadInterface = "ForceReloadInterface";  // no interface: all
} // namespace method

namespace signal {
// fields: unit, state, pid, exit_code
constexpr const char *UnitStateChanged = "UnitStateChanged";
// fields: interface, operstate, address (repeated)
constexpr const char *InterfaceStateChanged = "InterfaceStateChanged";
} // namespace signal

// Error names.
namespace error {
constexpr const char *UnknownMethod = "sysbus.Error.UnknownMethod";
constexpr const char *UnknownUnit = "sysbus.Error.UnknownUnit";
constexpr const char *UnknownInterface = "sysbus.Error.UnknownInterface";
constexpr const char *AccessDenied = "sysbus.Error.AccessDenied";
constexpr const char *Failed = "sysbus.Error.Failed";
constexpr const char *InvalidArgs = "sysbus.Error.InvalidArgs";
@@ -57,6 +75,40 @@ struct UnitInfo {
    int restarts = 0;
};

struct InterfaceInfo {
    std::string name;
    std::string mac;
    std::string operState;     // kernel operstate: up, down, unknown, ...
    bool adminUp = false;
    bool carrier = false;
    bool stopped = false;      // stopped on request: stays down
    std::vector<std::string> addresses;  // current, "a.b.c.d/len"
    // the configuration that applies (first matching .network file), if any
    std::string config;        // file name without ".network"
    std::string configPath;
    std::string match;         // [Match] Name=
    bool dhcp = false;
    std::string configAddress; // [Network] Address=
    std::string gateway;
    std::vector<std::string> dns;
};

// Create: interface is required; the configuration is named
// "10-<interface>" (so it wins over the catch-all 80-dhcp) and matches
// that interface unless config/match say otherwise.
// Edit: changes only the fields that are set; the target is config if
// given, else the configuration that applies to interface. An empty
// address/gateway, or an empty dns list, clears it.
struct InterfaceSettings {
    std::string interface;
    std::string config;
    std::optional<std::string> match;
    std::optional<bool> dhcp;
    std::optional<std::string> address;
    std::optional<std::string> gateway;
    std::optional<std::vector<std::string>> dns;
};

// "sshd.service" -> "sshd"
std::string unitName(const std::string &name);

@@ -89,6 +141,19 @@ public:
    bool getUnit(const std::string &name, UnitInfo &out);
    std::vector<UnitInfo> listUnits();

    // Network interfaces: true on success, otherwise see lastError().
    std::vector<InterfaceInfo> listInterfaces();
    bool getInterface(const std::string &name, InterfaceInfo &out);
    bool createInterface(const InterfaceSettings &settings);
    bool editInterface(const InterfaceSettings &settings);
    // by configuration name if given, else the configuration of interface
    bool deleteInterface(const std::string &interface, const std::string &config = "");
    bool startInterface(const std::string &name);
    bool stopInterface(const std::string &name);
    bool restartInterface(const std::string &name);
    bool reloadInterface(const std::string &name = "");       // empty: all
    bool forceReloadInterface(const std::string &name = "");  // empty: all

    // Signals: subscribe once, then waitSignal() returns the next one
    // (false on timeout or a closed connection; timeoutMs < 0 waits forever).
    bool subscribe();
@@ -100,6 +165,8 @@ public:
private:
    bool readSome(int timeoutMs);
    bool simpleCall(const char *member, const std::string &unit);
    bool checkedCall(const char *member, const std::vector<std::pair<std::string, std::string>> &args,
                     Message *reply = nullptr);

    int _fd = -1;
    uint32_t _serial = 0;
@@ -111,5 +178,7 @@ private:

// Reads a UnitInfo from the fields of a GetUnit reply / ListUnits entry.
UnitInfo unitFromFields(const std::vector<std::pair<std::string, std::string>> &fields);
// Reads an InterfaceInfo from a GetInterface reply / ListInterfaces entry.
InterfaceInfo interfaceFromFields(const std::vector<std::pair<std::string, std::string>> &fields);

} // namespace sysbus
+321 −25
Changes for src/network.cpp: 321 added lines, 25 removed lines.
Original line number Diff line number Diff line
@@ -7,6 +7,8 @@
#include <algorithm>
#include <cstring>
#include <cerrno>
#include <cctype>
#include <cstdlib>

#include <unistd.h>
#include <fcntl.h>
@@ -249,21 +251,35 @@ std::vector<std::string> NetworkManager::enumInterfaces() {
    return result;
}

void NetworkManager::applyAll() {
    auto interfaces = enumInterfaces();
// The first configuration matching ifname, in file-name order across both
// directories (systemd-networkd semantics: the first match wins, so a
// specific 10-eth0.network beats the catch-all 80-dhcp.network)
const NetworkConfig *NetworkManager::configFor(const std::string &ifname) const {
    for (auto &cfg : _configs)
        if (const_cast<NetworkManager *>(this)->matchInterface(cfg.matchName, ifname))
            return &cfg;
    return nullptr;
}

    // Always bring up loopback via netlink
    setLinkUp("lo");
    // Add 127.0.0.1/8 to lo
    addAddress("lo", "127.0.0.1/8");
const NetworkConfig *NetworkManager::findConfig(const std::string &name) const {
    for (auto &cfg : _configs)
        if (cfg.name == name) return &cfg;
    return nullptr;
}

    for (auto &cfg : _configs) {
        for (auto &ifname : interfaces) {
            if (!matchInterface(cfg.matchName, ifname))
                continue;
void NetworkManager::reloadConfigs() {
    _configs.clear();
    loadDirectory("/etc/systemd/network");
    loadDirectory(ConfigDir);
    std::stable_sort(_configs.begin(), _configs.end(), [](const NetworkConfig &a, const NetworkConfig &b) {
        return std::filesystem::path(a.filePath).filename() < std::filesystem::path(b.filePath).filename();
    });
}

void NetworkManager::configureInterface(const std::string &ifname, const NetworkConfig &cfg) {
    std::cout << "[syslite/net] Configuring " << ifname
              << " (" << cfg.name << ".network)" << std::endl;
    _dnsByIf.erase(ifname);

    // Bring interface up
    if (cfg.linkUp)
@@ -296,29 +312,309 @@ void NetworkManager::applyAll() {
            std::cout << "[syslite/net] " << ifname << ": gw " << cfg.gateway << std::endl;
        }
        for (auto &d : cfg.dns)
                    _dnsServers.push_back(d);
            _dnsByIf[ifname].push_back(d);
    }
    _configured.insert(ifname);
}

void NetworkManager::unconfigureInterface(const std::string &ifname) {
    flushIpv4Addresses(ifname);
    _dnsByIf.erase(ifname);
    _configured.erase(ifname);
}

void NetworkManager::updateResolv() {
    std::vector<std::string> servers;
    for (auto &[ifname, list] : _dnsByIf)
        servers.insert(servers.end(), list.begin(), list.end());
    // Until syslite has DNS servers to offer, the image's own resolv.yaml
    // stays; from then on it reflects the configured interfaces
    if (servers.empty() && !_resolvWritten)
        return;
    writeResolvYaml(servers);
    _resolvWritten = true;
}

void NetworkManager::applyAll() {
    // Always bring up loopback via netlink
    setLinkUp("lo");
    // Add 127.0.0.1/8 to lo
    addAddress("lo", "127.0.0.1/8");

    for (auto &ifname : enumInterfaces()) {
        if (_stopped.count(ifname)) continue;
        if (const NetworkConfig *cfg = configFor(ifname))
            configureInterface(ifname, *cfg);
    }
    updateResolv();
}

    // Write resolv.yaml if we have DNS servers
    if (!_dnsServers.empty())
        writeResolvYaml(_dnsServers);
void NetworkManager::applyNewDevices() {
    bool changed = false;
    for (auto &ifname : enumInterfaces()) {
        if (_configured.count(ifname) || _stopped.count(ifname)) continue;
        if (const NetworkConfig *cfg = configFor(ifname)) {
            configureInterface(ifname, *cfg);
            changed = true;
        }
    }
    if (changed) updateResolv();
}

void NetworkManager::reload() {
    std::cout << "[syslite/net] Flushing and reloading network config..." << std::endl;
    std::cout << "[syslite/net] Reloading network config..." << std::endl;
    std::string err;
    reloadInterface("", &err);
}

    // Flush existing state
    _configs.clear();
    _dnsServers.clear();
// ─── Per-interface control ──────────────────────────────────────────────────

    // Re-read .network files
    loadDirectory("/etc/systemd/network");
    loadDirectory("/etc/syslite/network");
std::vector<std::string> NetworkManager::allInterfaces() {
    std::vector<std::string> result;
    std::error_code ec;
    for (auto &entry : std::filesystem::directory_iterator("/sys/class/net", ec))
        result.push_back(entry.path().filename().string());
    std::sort(result.begin(), result.end());
    return result;
}

bool NetworkManager::interfaceExists(const std::string &ifname) {
    if (ifname.empty() || ifname.find('/') != std::string::npos) return false;
    std::error_code ec;
    return std::filesystem::exists("/sys/class/net/" + ifname, ec);
}

static std::string readSysfs(const std::string &ifname, const char *attr) {
    std::ifstream f("/sys/class/net/" + ifname + "/" + attr);
    std::string v;
    if (f.is_open()) std::getline(f, v);
    return trim(v);
}

InterfaceStatus NetworkManager::status(const std::string &ifname) {
    InterfaceStatus st;
    st.name = ifname;
    st.mac = readSysfs(ifname, "address");
    st.operState = readSysfs(ifname, "operstate");
    st.adminUp = (std::strtoul(readSysfs(ifname, "flags").c_str(), nullptr, 16) & IFF_UP) != 0;
    st.carrier = readSysfs(ifname, "carrier") == "1";
    st.stopped = _stopped.count(ifname) != 0;
    st.addresses = listAddresses(ifname);
    st.config = configFor(ifname);
    return st;
}

bool NetworkManager::startInterface(const std::string &ifname, std::string *err) {
    if (!interfaceExists(ifname)) { if (err) *err = "no interface " + ifname; return false; }
    _stopped.erase(ifname);
    if (_configured.count(ifname)) return true;  // already started
    const NetworkConfig *cfg = configFor(ifname);
    if (!cfg) {
        // nothing to configure: just the link
        if (!setLinkUp(ifname)) { if (err) *err = "cannot bring " + ifname + " up"; return false; }
        return true;
    }
    configureInterface(ifname, *cfg);
    updateResolv();
    return true;
}

    // Re-apply
    applyAll();
bool NetworkManager::stopInterface(const std::string &ifname, std::string *err) {
    if (!interfaceExists(ifname)) { if (err) *err = "no interface " + ifname; return false; }
    if (ifname == "lo") { if (err) *err = "refusing to stop the loopback interface"; return false; }
    std::cout << "[syslite/net] Stopping " << ifname << std::endl;
    _stopped.insert(ifname);
    unconfigureInterface(ifname);
    setLinkDown(ifname);
    updateResolv();
    return true;
}

bool NetworkManager::restartInterface(const std::string &ifname, std::string *err) {
    return stopInterface(ifname, err) && startInterface(ifname, err);
}

bool NetworkManager::reloadInterface(const std::string &ifname, std::string *err) {
    if (!ifname.empty() && !interfaceExists(ifname)) { if (err) *err = "no interface " + ifname; return false; }
    reloadConfigs();
    std::vector<std::string> targets = ifname.empty() ? enumInterfaces() : std::vector<std::string>{ifname};
    for (auto &i : targets) {
        if (_stopped.count(i)) continue;
        if (_configured.count(i)) unconfigureInterface(i);
        if (const NetworkConfig *cfg = configFor(i))
            configureInterface(i, *cfg);
    }
    updateResolv();
    return true;
}

bool NetworkManager::forceReloadInterface(const std::string &ifname, std::string *err) {
    if (!ifname.empty() && !interfaceExists(ifname)) { if (err) *err = "no interface " + ifname; return false; }
    reloadConfigs();
    std::vector<std::string> targets;
    if (!ifname.empty()) {
        targets.push_back(ifname);
    } else {
        // all: only interfaces syslite manages, not every link on the system
        for (auto &i : enumInterfaces())
            if (_configured.count(i) || configFor(i)) targets.push_back(i);
    }
    bool ok = true;
    for (auto &i : targets) {
        if (_stopped.count(i)) continue;
        ok = restartInterface(i, err) && ok;
    }
    return ok;
}

// ─── Configuration files ────────────────────────────────────────────────────

static bool validConfigName(const std::string &name) {
    if (name.empty() || name.size() > 64 || name[0] == '.') return false;
    for (char c : name)
        if (!std::isalnum(static_cast<unsigned char>(c)) && c != '-' && c != '_' && c != '.' && c != '@')
            return false;
    return true;
}

// one value per line: a value may not smuggle in further keys or sections
static bool validValue(const std::string &v) {
    return v.find_first_of("\r\n") == std::string::npos;
}

bool NetworkManager::saveConfig(const NetworkConfig &cfg, std::string *err) {
    if (!validConfigName(cfg.name)) { if (err) *err = "invalid configuration name '" + cfg.name + "'"; return false; }
    if (!validValue(cfg.matchName) || !validValue(cfg.address) || !validValue(cfg.gateway)) {
        if (err) *err = "values must be single lines";
        return false;
    }
    for (auto &d : cfg.dns)
        if (!validValue(d)) { if (err) *err = "values must be single lines"; return false; }

    std::error_code ec;
    std::filesystem::create_directories(ConfigDir, ec);
    const std::string path = std::string(ConfigDir) + "/" + cfg.name + ".network";
    const std::string tmp = path + ".syslite-tmp";
    {
        std::ofstream f(tmp, std::ios::trunc);
        if (!f.is_open()) { if (err) *err = "cannot write " + path; return false; }
        f << "# Managed by syslite (sysbus)\n"
          << "[Match]\n"
          << "Name=" << cfg.matchName << "\n"
          << "\n[Network]\n"
          << "DHCP=" << (cfg.dhcp ? "yes" : "no") << "\n";
        if (!cfg.address.empty()) f << "Address=" << cfg.address << "\n";
        if (!cfg.gateway.empty()) f << "Gateway=" << cfg.gateway << "\n";
        for (auto &d : cfg.dns) f << "DNS=" << d << "\n";
        f.close();
        if (!f) { ::unlink(tmp.c_str()); if (err) *err = "cannot write " + path; return false; }
    }
    ::chmod(tmp.c_str(), 0644);
    if (::rename(tmp.c_str(), path.c_str()) != 0) {
        ::unlink(tmp.c_str());
        if (err) *err = std::string("cannot write ") + path + ": " + std::strerror(errno);
        return false;
    }
    reloadConfigs();
    return true;
}

bool NetworkManager::deleteConfig(const std::string &name, std::string *err) {
    if (!validConfigName(name)) { if (err) *err = "invalid configuration name '" + name + "'"; return false; }
    const std::string path = std::string(ConfigDir) + "/" + name + ".network";
    std::error_code ec;
    if (!std::filesystem::remove(path, ec)) {
        if (err) *err = ec ? ec.message() : "no configuration " + path;
        return false;
    }
    reloadConfigs();
    return true;
}

// ─── Netlink: addresses ─────────────────────────────────────────────────────

// Calls fn for every address of interface idx (RTM_GETADDR dump).
template <class Fn>
static void forEachAddress(int idx, Fn fn) {
    int fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
    if (fd < 0) return;
    struct sockaddr_nl sa{};
    sa.nl_family = AF_NETLINK;  // nl_pid 0: the kernel picks one
    if (bind(fd, reinterpret_cast<struct sockaddr *>(&sa), sizeof(sa)) < 0) { close(fd); return; }

    struct {
        struct nlmsghdr hdr;
        struct ifaddrmsg ifa;
    } req{};
    req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
    req.hdr.nlmsg_type = RTM_GETADDR;
    req.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
    req.hdr.nlmsg_seq = 1;
    req.ifa.ifa_family = AF_UNSPEC;
    if (send(fd, &req, req.hdr.nlmsg_len, 0) < 0) { close(fd); return; }

    char buf[16384];
    for (;;) {
        ssize_t len = recv(fd, buf, sizeof(buf), 0);
        if (len <= 0) break;
        for (auto *nlh = reinterpret_cast<struct nlmsghdr *>(buf); NLMSG_OK(nlh, static_cast<unsigned>(len));
             nlh = NLMSG_NEXT(nlh, len)) {
            if (nlh->nlmsg_type == NLMSG_DONE || nlh->nlmsg_type == NLMSG_ERROR) { close(fd); return; }
            if (nlh->nlmsg_type != RTM_NEWADDR) continue;
            auto *ifa = reinterpret_cast<struct ifaddrmsg *>(NLMSG_DATA(nlh));
            if (static_cast<int>(ifa->ifa_index) != idx) continue;
            const void *local = nullptr, *address = nullptr;
            int rtl = static_cast<int>(IFA_PAYLOAD(nlh));
            for (auto *rta = IFA_RTA(ifa); RTA_OK(rta, rtl); rta = RTA_NEXT(rta, rtl)) {
                if (rta->rta_type == IFA_LOCAL) local = RTA_DATA(rta);
                else if (rta->rta_type == IFA_ADDRESS) address = RTA_DATA(rta);
            }
            fn(*ifa, local ? local : address, address);
        }
    }
    close(fd);
}

std::vector<std::string> NetworkManager::listAddresses(const std::string &ifname) {
    std::vector<std::string> out;
    int idx = getIfIndex(ifname);
    if (idx < 0) return out;
    forEachAddress(idx, [&](const struct ifaddrmsg &ifa, const void *addr, const void *) {
        if (!addr || (ifa.ifa_family != AF_INET && ifa.ifa_family != AF_INET6)) return;
        char buf[INET6_ADDRSTRLEN];
        if (inet_ntop(ifa.ifa_family, addr, buf, sizeof(buf)))
            out.push_back(std::string(buf) + "/" + std::to_string(ifa.ifa_prefixlen));
    });
    return out;
}

void NetworkManager::flushIpv4Addresses(const std::string &ifname) {
    int idx = getIfIndex(ifname);
    if (idx < 0) return;
    struct Addr { struct ifaddrmsg ifa; uint32_t local, address; };
    std::vector<Addr> addrs;
    forEachAddress(idx, [&](const struct ifaddrmsg &ifa, const void *local, const void *address) {
        if (ifa.ifa_family != AF_INET || !local) return;
        Addr a{ifa, 0, 0};
        std::memcpy(&a.local, local, 4);
        std::memcpy(&a.address, address ? address : local, 4);
        addrs.push_back(a);
    });
    for (auto &a : addrs) {
        int fd = netlinkOpen();
        if (fd < 0) return;
        NlMsg msg{};
        msg.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
        msg.hdr.nlmsg_type = RTM_DELADDR;
        msg.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
        msg.hdr.nlmsg_seq = 1;
        auto *ifa = reinterpret_cast<struct ifaddrmsg *>(NLMSG_DATA(&msg.hdr));
        *ifa = a.ifa;
        nlAddAttr(&msg.hdr, sizeof(msg), IFA_LOCAL, &a.local, 4);
        nlAddAttr(&msg.hdr, sizeof(msg), IFA_ADDRESS, &a.address, 4);
        netlinkSend(fd, &msg.hdr);
        close(fd);
    }
}

// ─── Netlink: set link up ───────────────────────────────────────────────────
@@ -738,9 +1034,9 @@ bool NetworkManager::doDhcp(const std::string &ifname) {
        addRoute(ifname, formatIpv4(lease.gateway));

    if (lease.dns1 != 0)
        _dnsServers.push_back(formatIpv4(lease.dns1));
        _dnsByIf[ifname].push_back(formatIpv4(lease.dns1));
    if (lease.dns2 != 0)
        _dnsServers.push_back(formatIpv4(lease.dns2));
        _dnsByIf[ifname].push_back(formatIpv4(lease.dns2));

    return true;
}
+69 −2
Changes for src/network.h: 69 added lines, 2 removed lines.
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@
#include <string>
#include <vector>
#include <map>
#include <set>
#include <cstdint>

namespace syslite {
@@ -27,6 +28,18 @@ namespace syslite {
        std::string name;
    };

    // Runtime state of one network interface (from /sys/class/net and netlink)
    struct InterfaceStatus {
        std::string name;
        std::string mac;
        std::string operState;      // /sys/class/net/<if>/operstate: up, down, ...
        bool        adminUp = false; // IFF_UP
        bool        carrier = false;
        bool        stopped = false; // stopped on request (stays down)
        std::vector<std::string> addresses; // "a.b.c.d/len", IPv6 too
        const NetworkConfig *config = nullptr; // first matching configuration
    };

    // DHCP lease result
    struct DhcpLease {
        uint32_t clientIp = 0;
@@ -49,9 +62,48 @@ namespace syslite {
        // Apply all loaded network configurations
        void applyAll();

        // Flush current configs and re-apply (runtime reload)
        // Re-read the .network files and reconfigure every managed interface
        // that isn't stopped (addresses replaced; links stay up)
        void reload();

        // Configure devices that appeared since (netlink RTM_NEWLINK); already
        // configured interfaces are left alone
        void applyNewDevices();

        // Directory of the configurations syslite manages (create/edit/delete)
        static constexpr const char *ConfigDir = "/etc/syslite/network";

        // Every interface in /sys/class/net, lo included
        std::vector<std::string> allInterfaces();
        bool interfaceExists(const std::string &ifname);
        InterfaceStatus status(const std::string &ifname);

        // Per-interface control; false and *err on failure.
        //   start: apply its configuration (no-op if already started)
        //   stop: remove its addresses, take the link down, drop its DNS
        //         servers; it stays down (also for new-device events) until
        //         started again
        //   reload: re-read the files and reconfigure without taking the
        //           link down (empty ifname: all interfaces)
        //   forceReload: re-read the files and stop + start (empty: all)
        bool startInterface(const std::string &ifname, std::string *err);
        bool stopInterface(const std::string &ifname, std::string *err);
        bool restartInterface(const std::string &ifname, std::string *err);
        bool reloadInterface(const std::string &ifname, std::string *err);
        bool forceReloadInterface(const std::string &ifname, std::string *err);

        // Configurations (files only: applied by start/reload/restart)
        const std::vector<NetworkConfig> &configs() const { return _configs; }
        const NetworkConfig *configFor(const std::string &ifname) const;
        const NetworkConfig *findConfig(const std::string &name) const;
        // Writes cfg to ConfigDir/<cfg.name>.network (creating or replacing
        // it) and re-reads the configuration files
        bool saveConfig(const NetworkConfig &cfg, std::string *err);
        // Deletes ConfigDir/<name>.network and re-reads the files
        bool deleteConfig(const std::string &name, std::string *err);
        // Re-read the .network files only (nothing is applied)
        void reloadConfigs();

        // Start listening for new network devices (netlink RTNLGRP_LINK)
        // Returns fd to poll in the main loop (-1 on failure)
        int startDeviceMonitor();
@@ -87,6 +139,18 @@ namespace syslite {

        // Write /etc/resolv.yaml (systempp's resolver configuration)
        void writeResolvYaml(const std::vector<std::string> &servers);
        // ...from the DNS servers of all configured interfaces
        void updateResolv();

        // Apply cfg to one interface (link up, DHCP or static address/route,
        // DNS servers); records it as configured
        void configureInterface(const std::string &ifname, const NetworkConfig &cfg);
        // Undo it: delete its IPv4 addresses (and with them its routes), drop
        // its DNS servers
        void unconfigureInterface(const std::string &ifname);
        // Netlink: the interface's addresses; delete its IPv4 addresses
        std::vector<std::string> listAddresses(const std::string &ifname);
        void flushIpv4Addresses(const std::string &ifname);

        // Helper: get interface index
        int getIfIndex(const std::string &ifname);
@@ -97,7 +161,10 @@ namespace syslite {
        static std::string formatIpv4(uint32_t ip);

        std::vector<NetworkConfig> _configs;
        std::vector<std::string> _dnsServers;
        std::map<std::string, std::vector<std::string>> _dnsByIf; // DNS servers per interface
        std::set<std::string> _configured; // interfaces configureInterface() set up
        std::set<std::string> _stopped;    // interfaces stopped on request
        bool _resolvWritten = false;       // resolv.yaml is ours once written
        int _monitorFd = -1;
    };

+99 −0

File changed.

Preview size limit exceeded, changes collapsed.

+127 −7

File changed.

Preview size limit exceeded, changes collapsed.

Loading