302 lines
10 KiB
C++
302 lines
10 KiB
C++
|
|
extern "C" {
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <sys/ioctl.h>
|
|
#include <net/if.h>
|
|
#include <linux/if.h>
|
|
#include <linux/if_tun.h>
|
|
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
|
|
#include <arpa/inet.h>
|
|
#include <linux/netlink.h>
|
|
#include <linux/rtnetlink.h>
|
|
}
|
|
|
|
#include <cstring>
|
|
#include <expected>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <span>
|
|
#include <iostream>
|
|
#include <thread>
|
|
#include <chrono>
|
|
|
|
#include <interface.hpp>
|
|
|
|
std::expected<void, std::string> Interface::Create(const std::string name) {
|
|
if ((tunfd = open("/dev/net/tun", O_RDWR | O_CLOEXEC)) < 0) {
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Create interface error: " + error);
|
|
}
|
|
|
|
struct ifreq ifr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
|
|
strncpy(ifr.ifr_name, name.data(), IFNAMSIZ - 1);
|
|
if (ioctl(tunfd, TUNSETIFF, (void*)(&ifr)) < 0) {
|
|
close(tunfd);
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Create interface error: " + error);
|
|
}
|
|
ifname = ifr.ifr_name;
|
|
|
|
#if DEFINE_TUNPERSIST
|
|
if (ioctl(tunfd, TUNSETPERSIST, 0) < 0) {
|
|
close(tunfd);
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Create interface error: " + error);
|
|
}
|
|
#endif
|
|
|
|
//struct ifreq ifr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
int sockfd = 0;
|
|
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
close(tunfd);
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Get MTU error: " + error);
|
|
}
|
|
strncpy(ifr.ifr_name, ifname.data(), IFNAMSIZ - 1);
|
|
if (ioctl(sockfd, SIOCGIFMTU, &ifr) < 0) {
|
|
close(tunfd);
|
|
close(sockfd);
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Get MTU error: " + error);
|
|
}
|
|
close(sockfd);
|
|
mtu = ifr.ifr_mtu;
|
|
return {};
|
|
}
|
|
|
|
std::expected<void, std::string> Interface::SetMTU(int ifmtu) {
|
|
int sockfd = 0;
|
|
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Set MTU error: " + error);
|
|
}
|
|
struct ifreq ifr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strncpy(ifr.ifr_name, ifname.data(), IFNAMSIZ - 1);
|
|
ifr.ifr_mtu = ifmtu;
|
|
if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) {
|
|
close(sockfd);
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Set MTU error: " + error);
|
|
}
|
|
close(sockfd);
|
|
return {};
|
|
}
|
|
|
|
std::expected<int, std::string> Interface::GetMTU(void) {
|
|
struct ifreq ifr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
int sockfd = 0;
|
|
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Get MTU error: " + error);
|
|
}
|
|
strncpy(ifr.ifr_name, ifname.data(), IFNAMSIZ - 1);
|
|
if (ioctl(sockfd, SIOCGIFMTU, &ifr) < 0) {
|
|
close(sockfd);
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Get MTU error: " + error);
|
|
}
|
|
close(sockfd);
|
|
return ifr.ifr_mtu;
|
|
}
|
|
|
|
std::expected<std::string, std::string> Interface::GetIP4Address(void) {
|
|
struct ifreq ifr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
int sockfd = 0;
|
|
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Get MTU error: " + error);
|
|
}
|
|
ifr.ifr_addr.sa_family = AF_INET;
|
|
strncpy(ifr.ifr_name, ifname.data(), IFNAMSIZ - 1);
|
|
|
|
if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0) {
|
|
close(sockfd);
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Get MTU error: " + error);
|
|
}
|
|
close(sockfd);
|
|
|
|
auto sinaddr = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
|
|
std::string addr = inet_ntoa(sinaddr);
|
|
return addr;
|
|
}
|
|
|
|
std::expected<void, std::string> Interface::SetIP4Address(std::string ipaddr) {
|
|
struct ifreq ifr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
ifr.ifr_addr.sa_family = AF_INET;
|
|
strncpy(ifr.ifr_name, ifname.data(), IFNAMSIZ - 1);
|
|
|
|
struct sockaddr_in* addr = (struct sockaddr_in *)&ifr.ifr_addr;
|
|
addr->sin_family = AF_INET;
|
|
if (inet_pton(AF_INET, ipaddr.data(), &addr->sin_addr) <= 0) {
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Set address error: " + error);
|
|
}
|
|
|
|
int sockfd = 0;
|
|
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Set address error: " + error);
|
|
}
|
|
|
|
if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
|
|
close(sockfd);
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Set address error: " + error);
|
|
}
|
|
close(sockfd);
|
|
return {};
|
|
}
|
|
|
|
std::expected<void, std::string> Interface::SetIP4Netmask(int prefix) {
|
|
if (prefix < 0 || prefix > 32) {
|
|
return std::unexpected("Invalid prefix");
|
|
}
|
|
//uint32_t mask = (prefix == 0) ? 0 : (~0U << (32 - prefix));
|
|
uint32_t mask = (prefix == 0) ? 0 : htonl(~((1U << (32 - prefix)) - 1));
|
|
|
|
struct in_addr maskaddr;
|
|
maskaddr.s_addr = htonl(mask);
|
|
char buffer[INET_ADDRSTRLEN];
|
|
if (inet_ntop(AF_INET, &maskaddr, buffer, sizeof(buffer)) == NULL) {
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Set netmask error: " + error);
|
|
}
|
|
auto netmask = std::string(buffer);
|
|
|
|
struct ifreq ifr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
ifr.ifr_addr.sa_family = AF_INET;
|
|
strncpy(ifr.ifr_name, ifname.data(), IFNAMSIZ - 1);
|
|
|
|
struct sockaddr_in* addr = (struct sockaddr_in *)&ifr.ifr_addr;
|
|
addr->sin_family = AF_INET;
|
|
if (inet_pton(AF_INET, netmask.data(), &addr->sin_addr) < 0) {
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Set netmask error: " + error);
|
|
}
|
|
|
|
int sockfd = 0;
|
|
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Set netmask error: " + error);
|
|
}
|
|
if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
|
|
close(sockfd);
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Set4 netmask error: " + error);
|
|
}
|
|
close(sockfd);
|
|
return {};
|
|
}
|
|
|
|
std::expected<void, std::string> Interface::Up(void) {
|
|
int sockfd = 0;
|
|
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Up interface error: " + error);
|
|
}
|
|
|
|
struct ifreq ifr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strncpy(ifr.ifr_name, ifname.data(), IFNAMSIZ - 1);
|
|
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
|
|
close(sockfd);
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Up interface error: " + error);
|
|
}
|
|
ifr.ifr_flags |= (IFF_UP | IFF_RUNNING);
|
|
if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
|
|
close(sockfd);
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Up interface error: " + error);
|
|
}
|
|
close(sockfd);
|
|
return {};
|
|
}
|
|
|
|
std::expected<void, std::string> Interface::Down(void) {
|
|
int sockfd = 0;
|
|
if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Up interface error: " + error);
|
|
}
|
|
struct ifreq ifr;
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
strncpy(ifr.ifr_name, ifname.data(), IFNAMSIZ - 1);
|
|
if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) {
|
|
close(sockfd);
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Up interface error: " + error);
|
|
}
|
|
ifr.ifr_flags &= ~IFF_UP;
|
|
if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) {
|
|
close(sockfd);
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Up interface error: " + error);
|
|
}
|
|
close(sockfd);
|
|
return {};
|
|
}
|
|
|
|
std::expected<std::string, std::string> Interface::Read() {
|
|
char buffer[mtu];
|
|
int rsize = 0;
|
|
if ((rsize = read(tunfd, buffer, sizeof(buffer))) < 0) {
|
|
int errnocopy = errno;
|
|
std::string error = std::strerror(errnocopy);
|
|
return std::unexpected("Read interface error: " + error);
|
|
}
|
|
std::string rdata;
|
|
rdata.append(buffer, rsize);
|
|
return rdata;
|
|
}
|
|
|
|
std::string Interface::Name() {
|
|
return ifname;
|
|
}
|
|
|
|
int Interface::MTU() {
|
|
return mtu;
|
|
}
|
|
|
|
Interface::~Interface() {
|
|
close(tunfd);
|
|
}
|
|
|