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