blob: 18f9b41b504f9d5ce33b732ad91e378fed64ef8a [file] [log] [blame]
Brandon Kimdab96f12021-02-18 11:21:37 -08001// 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
William A. Kennington III7d6fa422021-02-08 17:04:02 -080015#include "net_iface.h"
16
Willy Tua9a98252023-09-18 14:49:23 -070017#include <arpa/inet.h>
Willy Tuadb8ffe2023-07-17 13:44:22 -070018#include <linux/if.h>
Willy Tua9a98252023-09-18 14:49:23 -070019#include <linux/if_ether.h>
William A. Kennington III7d6fa422021-02-08 17:04:02 -080020#include <linux/if_packet.h>
Willy Tuadb8ffe2023-07-17 13:44:22 -070021#include <sys/ioctl.h>
William A. Kennington III7d6fa422021-02-08 17:04:02 -080022#include <sys/socket.h>
23#include <unistd.h>
24
William A. Kennington III7d6fa422021-02-08 17:04:02 -080025#include <cstring>
26#include <stdexcept>
27
28namespace net
29{
30
31IFaceBase::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
39int 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
52int IFaceBase::set_sock_flags(int sockfd, short flags) const
53{
54 return mod_sock_flags(sockfd, flags, true);
55}
56
57int IFaceBase::clear_sock_flags(int sockfd, short flags) const
58{
59 return mod_sock_flags(sockfd, flags, false);
60}
61
62int 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
84int 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
Willy Tua9a98252023-09-18 14:49:23 -0700104int IFace::bind_sock(int sockfd) const
William A. Kennington III7d6fa422021-02-08 17:04:02 -0800105{
Willy Tua9a98252023-09-18 14:49:23 -0700106 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));
William A. Kennington III7d6fa422021-02-08 17:04:02 -0800113}
114
115int 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