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