1 /*
2  * Copyright 2021 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <linux/if.h>
20 #include <linux/if_packet.h>
21 #include <net/ethernet.h>
22 #include <netinet/in.h>
23 #include <sys/ioctl.h>
24 #include <sys/socket.h>
25 
26 #include <functional>
27 #include <string>
28 
29 namespace net
30 {
31 
32 class IFaceBase
33 {
34   public:
35     explicit IFaceBase(const std::string& name);
36     virtual ~IFaceBase() = default;
37 
38     /** @brief Get the index of the network interface corresponding
39      * to this object.
40      */
41     int get_index() const;
42 
43     /** @brief Set interface flags using provided socket.
44      *
45      *  @param[in] sockfd - Socket to use for SIOCSIFFLAGS ioctl call.
46      *  @param[in] flags - Flags to set.
47      */
48     int set_sock_flags(int sockfd, short flags) const;
49 
50     /** @brief Clear interface flags using provided socket.
51      *
52      *  @param[in] sockfd - Socket to use for SIOCSIFFLAGS/SIOCGIFFLAGS
53      *      ioctl call.
54      *  @param[in] flags - Flags to clear.
55      */
56     int clear_sock_flags(int sockfd, short flags) const;
57 
58     /** @brief Bind given socket to this interface. Similar to bind
59      *     syscall, except that it fills in sll_ifindex field
60      *     of struct sockaddr_ll with the index of this interface.
61      */
62     virtual int bind_sock(int sockfd, struct sockaddr_ll* saddr) const = 0;
63 
64   protected:
65     std::string name_;
66 
67   private:
68     /** @brief Similar to ioctl syscall, but the socket is created inside
69      *      the function and the interface name in struct ifreq is
70      *      properly populated with the index of this interface.
71      */
72     virtual int ioctl(int request, struct ifreq* ifr) const = 0;
73 
74     /** @brief Similar to ioctl syscall. The interface index in
75      *      struct ifreq is
76      *      properly populated with the index of this interface.
77      */
78     virtual int ioctl_sock(int sockfd, int request,
79                            struct ifreq* ifr) const = 0;
80 
81     /** @brief Modify interface flags, using the given socket for
82      *      ioctl call.
83      */
84     int mod_sock_flags(int sockfd, short flags, bool set) const;
85 };
86 
87 class IFace : public IFaceBase
88 {
89   public:
90     explicit IFace(const std::string& name) : IFaceBase(name)
91     {}
92 
93     /** @brief Bind given socket to this interface. Similar to bind
94      *     syscall, except that it fills in sll_ifindex field
95      *     of struct sockaddr_ll with the index of this interface.
96      */
97     int bind_sock(int sockfd, struct sockaddr_ll* saddr) const override;
98 
99   private:
100     /** @brief Similar to ioctl syscall, but the socket is created inside
101      *      the function and the interface name in struct ifreq is
102      *      properly populated with the index of this interface.
103      */
104     int ioctl(int request, struct ifreq* ifr) const override;
105     /** @brief Similar to ioctl syscall. The interface index in
106      *      struct ifreq is
107      *      properly populated with the index of this interface.
108      */
109     int ioctl_sock(int sockfd, int request, struct ifreq* ifr) const override;
110 };
111 
112 } // namespace net
113