1 // Copyright 2021 Google LLC 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "net_iface.h" 16 17 #include <arpa/inet.h> 18 #include <linux/if.h> 19 #include <linux/if_ether.h> 20 #include <linux/if_packet.h> 21 #include <sys/ioctl.h> 22 #include <sys/socket.h> 23 #include <unistd.h> 24 25 #include <cstring> 26 #include <stdexcept> 27 28 namespace net 29 { 30 31 IFaceBase::IFaceBase(const std::string& name) : name_{name} 32 { 33 if (name.size() >= IFNAMSIZ) 34 { 35 throw std::length_error("Interface name is too long"); 36 } 37 } 38 39 int IFaceBase::get_index() const 40 { 41 struct ifreq ifr; 42 std::memset(&ifr, 0, sizeof(ifr)); 43 int ret = ioctl(SIOCGIFINDEX, &ifr); 44 if (ret < 0) 45 { 46 return ret; 47 } 48 49 return ifr.ifr_ifindex; 50 } 51 52 int IFaceBase::set_sock_flags(int sockfd, short flags) const 53 { 54 return mod_sock_flags(sockfd, flags, true); 55 } 56 57 int IFaceBase::clear_sock_flags(int sockfd, short flags) const 58 { 59 return mod_sock_flags(sockfd, flags, false); 60 } 61 62 int IFaceBase::mod_sock_flags(int sockfd, short flags, bool set) const 63 { 64 struct ifreq ifr; 65 std::memset(&ifr, 0, sizeof(ifr)); 66 67 int ret = ioctl_sock(sockfd, SIOCGIFFLAGS, &ifr); 68 if (ret < 0) 69 { 70 return ret; 71 } 72 73 if (set) 74 { 75 ifr.ifr_flags |= flags; 76 } 77 else 78 { 79 ifr.ifr_flags &= ~flags; 80 } 81 return ioctl_sock(sockfd, SIOCSIFFLAGS, &ifr); 82 } 83 84 int IFace::ioctl_sock(int sockfd, int request, struct ifreq* ifr) const 85 { 86 if (ifr == nullptr) 87 { 88 return -1; 89 } 90 91 /* Avoid string truncation. */ 92 size_t len = name_.length(); 93 if (len + 1 >= sizeof(ifr->ifr_name)) 94 { 95 return -1; 96 } 97 98 std::memcpy(ifr->ifr_name, name_.c_str(), len); 99 ifr->ifr_name[len] = 0; 100 101 return ::ioctl(sockfd, request, ifr); 102 } 103 104 int IFace::bind_sock(int sockfd) const 105 { 106 struct sockaddr_ll saddr; 107 std::memset(&saddr, 0, sizeof(saddr)); 108 saddr.sll_family = AF_PACKET; 109 saddr.sll_protocol = htons(ETH_P_ALL); 110 saddr.sll_ifindex = get_index(); 111 return bind(sockfd, reinterpret_cast<struct sockaddr*>(&saddr), 112 sizeof(saddr)); 113 } 114 115 int IFace::ioctl(int request, struct ifreq* ifr) const 116 { 117 if (ifr == nullptr) 118 { 119 return -1; 120 } 121 122 int tempsock = socket(AF_INET, SOCK_DGRAM, 0); 123 if (tempsock < 0) 124 { 125 return tempsock; 126 } 127 128 int ret = ioctl_sock(tempsock, request, ifr); 129 close(tempsock); 130 131 return ret; 132 } 133 134 } // namespace net 135