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 <sys/socket.h>
22 
23 #include <string>
24 
25 namespace net
26 {
27 
28 class IFaceBase
29 {
30   public:
31     explicit IFaceBase(const std::string& name);
32     virtual ~IFaceBase() = default;
33 
34     /** @brief Get the index of the network interface corresponding
35      * to this object.
36      */
37     int get_index() const;
38 
39     /** @brief Set interface flags using provided socket.
40      *
41      *  @param[in] sockfd - Socket to use for SIOCSIFFLAGS ioctl call.
42      *  @param[in] flags - Flags to set.
43      */
44     int set_sock_flags(int sockfd, short flags) const;
45 
46     /** @brief Clear interface flags using provided socket.
47      *
48      *  @param[in] sockfd - Socket to use for SIOCSIFFLAGS/SIOCGIFFLAGS
49      *      ioctl call.
50      *  @param[in] flags - Flags to clear.
51      */
52     int clear_sock_flags(int sockfd, short flags) const;
53 
54     /** @brief Bind given socket to this interface. Similar to bind
55      *     syscall, except that it fills in sll_ifindex field
56      *     of struct sockaddr_ll with the index of this interface.
57      */
58     virtual int bind_sock(int sockfd) const = 0;
59 
60   protected:
61     std::string name_;
62 
63   private:
64     /** @brief Similar to ioctl syscall, but the socket is created inside
65      *      the function and the interface name in struct ifreq is
66      *      properly populated with the index of this interface.
67      */
68     virtual int ioctl(int request, struct ifreq* ifr) const = 0;
69 
70     /** @brief Similar to ioctl syscall. The interface index in
71      *      struct ifreq is
72      *      properly populated with the index of this interface.
73      */
74     virtual int ioctl_sock(int sockfd, int request,
75                            struct ifreq* ifr) const = 0;
76 
77     /** @brief Modify interface flags, using the given socket for
78      *      ioctl call.
79      */
80     int mod_sock_flags(int sockfd, short flags, bool set) const;
81 };
82 
83 class IFace : public IFaceBase
84 {
85   public:
86     explicit IFace(const std::string& name) : IFaceBase(name) {}
87 
88     /** @brief Bind given socket to this interface. Similar to bind
89      *     syscall, except that it fills in sll_ifindex field
90      *     of struct sockaddr_ll with the index of this interface.
91      */
92     int bind_sock(int sockfd) const override;
93 
94   private:
95     /** @brief Similar to ioctl syscall, but the socket is created inside
96      *      the function and the interface name in struct ifreq is
97      *      properly populated with the index of this interface.
98      */
99     int ioctl(int request, struct ifreq* ifr) const override;
100     /** @brief Similar to ioctl syscall. The interface index in
101      *      struct ifreq is
102      *      properly populated with the index of this interface.
103      */
104     int ioctl_sock(int sockfd, int request, struct ifreq* ifr) const override;
105 };
106 
107 } // namespace net
108