From 648234cc68b93278b1d3b6fa361c64134228e963 Mon Sep 17 00:00:00 2001 From: Antonio Quartulli Date: Tue, 21 Apr 2020 15:22:57 +0200 Subject: [PATCH] sitnl: implement net_iface_new and net_iface_del These two new methods can be used to create and delete a tun or an ovpn-dco interface via RTNL API. Signed-off-by: Antonio Quartulli Signed-off-by: Lev Stipakov --- openvpn/tun/linux/client/sitnl.hpp | 74 +++++++++++++++++++++++++ openvpn/tun/linux/client/tunnetlink.hpp | 52 +++++++++++++++++ 2 files changed, 126 insertions(+) diff --git a/openvpn/tun/linux/client/sitnl.hpp b/openvpn/tun/linux/client/sitnl.hpp index 39f8d19f..ff6e4327 100644 --- a/openvpn/tun/linux/client/sitnl.hpp +++ b/openvpn/tun/linux/client/sitnl.hpp @@ -831,6 +831,80 @@ err: return ret; } + /** + * @brief Add new interface (similar to ip link add) + * + * @param iface interface name + * @param type interface link type (for example "ovpn-dco") + * @return int 0 on success, negative error code on error + */ + static int + net_iface_new(const std::string& iface, const std::string& type) + { + struct sitnl_link_req req = { }; + struct rtattr *tail = NULL; + int ret = -1; + + if (iface.empty()) + { + OPENVPN_LOG(__func__ << ": passed empty interface"); + return -EINVAL; + } + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i)); + req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL; + req.n.nlmsg_type = RTM_NEWLINK; + + SITNL_ADDATTR(&req.n, sizeof(req), IFLA_IFNAME, iface.c_str(), + iface.length() + 1); + tail = NLMSG_TAIL(&req.n); + SITNL_ADDATTR(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); + SITNL_ADDATTR(&req.n, sizeof(req), IFLA_INFO_KIND, type.c_str(), + type.length() + 1); + tail->rta_len = (uint8_t *)NLMSG_TAIL(&req.n) - (uint8_t *)tail; + + req.i.ifi_family = AF_PACKET; + req.i.ifi_index = 0; + + OPENVPN_LOG(__func__ << ": add " << iface << " type " << type); + + ret = sitnl_send(&req.n, 0, 0, NULL, NULL); +err: + return ret; + } + + static int + net_iface_del(const std::string& iface) + { + struct sitnl_link_req req = { }; + int ifindex; + + if (iface.empty()) + { + OPENVPN_LOG(__func__ << ": passed empty interface"); + return -EINVAL; + } + + ifindex = if_nametoindex(iface.c_str()); + if (ifindex == 0) + { + OPENVPN_LOG(__func__ << ": rtnl: cannot get ifindex for " << iface + << ": " << strerror(errno)); + return -ENOENT; + } + + req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i)); + req.n.nlmsg_flags = NLM_F_REQUEST; + req.n.nlmsg_type = RTM_DELLINK; + + req.i.ifi_family = AF_PACKET; + req.i.ifi_index = ifindex; + + OPENVPN_LOG(__func__ << ": idel " << iface); + + return sitnl_send(&req.n, 0, 0, NULL, NULL); + } + static int net_iface_up(std::string& iface, bool up) { diff --git a/openvpn/tun/linux/client/tunnetlink.hpp b/openvpn/tun/linux/client/tunnetlink.hpp index 66734db4..20b9f3d2 100644 --- a/openvpn/tun/linux/client/tunnetlink.hpp +++ b/openvpn/tun/linux/client/tunnetlink.hpp @@ -431,6 +431,58 @@ namespace openvpn { R_ADD_ALL=R_ADD_SYS|R_ADD_DCO, }; + /** + * @brief Add new interface + * + * @param os output stream to where error message is written + * @param dev interface name + * @param type interface link type (such as "ovpn-dco") + * @return int 0 on success, negative error code on error + */ + inline int iface_new(std::ostringstream& os, const std::string& dev, const std::string& type) + { + int ret = -1; + + if (dev.empty()) + { + os << "Error: can't call NetlinkLinkNew with no interface" << std::endl; + return ret; + } + + if (type.empty()) + { + os << "Error: can't call NetlinkLinkNew with no interfacei type" << std::endl; + return ret; + } + + ret = SITNL::net_iface_new(dev, type); + if (ret) + { + os << "Error while executing NetlinkLinkNew " << dev << ": " << ret << std::endl; + } + + return ret; + } + + inline int iface_del(std::ostringstream& os, const std::string& dev) + { + int ret = -1; + + if (dev.empty()) + { + os << "Error: can't call NetlinkLinkDel with no interface" << std::endl; + return ret; + } + + ret = SITNL::net_iface_del(dev); + if (ret) + { + os << "Error while executing NetlinkLinkDel " << dev << ": " << ret << std::endl; + } + + return ret; + } + /*inline IPv4::Addr cvt_pnr_ip_v4(const std::string& hexaddr) { BufferAllocated v(4, BufferAllocated::CONSTRUCT_ZERO);