Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 15 additions & 7 deletions src/vpn/linux.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,25 @@ namespace srouter::vpn
void disarm() { f = nullptr; }
};

// Send a netlink request and wait for the response. Returns an error string on error, nullopt
// on success. Must have set NLM_F_ACK on the request header flags!
// Send a netlink request and wait for the response. Returns an {errno, error string} on error,
// nullopt on success. Must have set NLM_F_ACK on the request header flags!
template <typename NLRequestT>
std::optional<std::string> nl_submit(int nlfd, const NLRequestT& req)
std::optional<std::pair<int, std::string>> nl_submit(int nlfd, const NLRequestT& req)
{
assert(req.header.nlmsg_flags & NLM_F_REQUEST);
log::trace(logcat, "submitting netlink request to fd {}", nlfd);
if (-1 == send(nlfd, &req, req.header.nlmsg_len, 0))
return strerror(errno);
return std::pair<int, std::string>{errno, strerror(errno)};

char resp_buf[4096];
log::trace(logcat, "waiting for netlink response");
auto resp_len = recv(nlfd, resp_buf, sizeof(resp_buf), 0);
log::trace(logcat, "got netlink response");
auto* resp = reinterpret_cast<nlmsghdr*>(resp_buf);
if (!NLMSG_OK(resp, resp_len) || resp->nlmsg_type != NLMSG_ERROR)
return "Invalid netlink response"s;
return std::pair<int, std::string>{EIO, "Invalid netlink response"s};
if (auto* nlerr = reinterpret_cast<nlmsgerr*>(NLMSG_DATA(resp_buf)); nlerr->error < 0)
return strerror(-nlerr->error);
return std::pair<int, std::string>{-nlerr->error, strerror(-nlerr->error)};
return std::nullopt;
}

Expand Down Expand Up @@ -193,8 +193,16 @@ namespace srouter::vpn
}

if (auto err = nl_submit(nlfd, request))
{
if (n6 && err->first == EACCES)
log::critical(
logcat,
"IPv6 support appears to be disabled or restricted on this system, "
"but private IPv6 addressing is required for Session Router");

throw std::runtime_error{
"Failed to add address {} to {}: {}"_format(addr_strings.back(), _info.ifname, *err)};
"Failed to add address {} to {}: {}"_format(addr_strings.back(), _info.ifname, err->second)};
}

// Adding a conflicting address does not fail, and so we need to go query all the
// addresses on the system to see if the same address exists on any *other*
Expand Down