1 #include "net_iface.h" 2 3 #include <linux/if_packet.h> 4 #include <net/ethernet.h> 5 #include <sys/socket.h> 6 #include <unistd.h> 7 8 #include <cstdio> 9 #include <cstring> 10 #include <stdexcept> 11 12 namespace net 13 { 14 15 IFaceBase::IFaceBase(const std::string& name) : name_{name} 16 { 17 if (name.size() >= IFNAMSIZ) 18 { 19 throw std::length_error("Interface name is too long"); 20 } 21 } 22 23 int IFaceBase::get_index() const 24 { 25 struct ifreq ifr; 26 std::memset(&ifr, 0, sizeof(ifr)); 27 int ret = ioctl(SIOCGIFINDEX, &ifr); 28 if (ret < 0) 29 { 30 return ret; 31 } 32 33 return ifr.ifr_ifindex; 34 } 35 36 int IFaceBase::set_sock_flags(int sockfd, short flags) const 37 { 38 return mod_sock_flags(sockfd, flags, true); 39 } 40 41 int IFaceBase::clear_sock_flags(int sockfd, short flags) const 42 { 43 return mod_sock_flags(sockfd, flags, false); 44 } 45 46 int IFaceBase::mod_sock_flags(int sockfd, short flags, bool set) const 47 { 48 struct ifreq ifr; 49 std::memset(&ifr, 0, sizeof(ifr)); 50 51 int ret = ioctl_sock(sockfd, SIOCGIFFLAGS, &ifr); 52 if (ret < 0) 53 { 54 return ret; 55 } 56 57 if (set) 58 { 59 ifr.ifr_flags |= flags; 60 } 61 else 62 { 63 ifr.ifr_flags &= ~flags; 64 } 65 return ioctl_sock(sockfd, SIOCSIFFLAGS, &ifr); 66 } 67 68 int IFace::ioctl_sock(int sockfd, int request, struct ifreq* ifr) const 69 { 70 if (ifr == nullptr) 71 { 72 return -1; 73 } 74 75 /* Avoid string truncation. */ 76 size_t len = name_.length(); 77 if (len + 1 >= sizeof(ifr->ifr_name)) 78 { 79 return -1; 80 } 81 82 std::memcpy(ifr->ifr_name, name_.c_str(), len); 83 ifr->ifr_name[len] = 0; 84 85 return ::ioctl(sockfd, request, ifr); 86 } 87 88 int IFace::bind_sock(int sockfd, struct sockaddr_ll* saddr) const 89 { 90 if (saddr == nullptr) 91 { 92 return -1; 93 } 94 95 saddr->sll_ifindex = get_index(); 96 97 return bind(sockfd, reinterpret_cast<struct sockaddr*>(saddr), 98 sizeof(*saddr)); 99 } 100 101 int IFace::ioctl(int request, struct ifreq* ifr) const 102 { 103 if (ifr == nullptr) 104 { 105 return -1; 106 } 107 108 int tempsock = socket(AF_INET, SOCK_DGRAM, 0); 109 if (tempsock < 0) 110 { 111 return tempsock; 112 } 113 114 int ret = ioctl_sock(tempsock, request, ifr); 115 close(tempsock); 116 117 return ret; 118 } 119 120 } // namespace net 121