blob: 0a647b466a6cac095c39d95c153352638870d07b [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
17#include <linux/if_packet.h>
18#include <net/ethernet.h>
19#include <sys/socket.h>
20#include <unistd.h>
21
22#include <cstdio>
23#include <cstring>
24#include <stdexcept>
25
26namespace net
27{
28
29IFaceBase::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
37int 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
50int IFaceBase::set_sock_flags(int sockfd, short flags) const
51{
52 return mod_sock_flags(sockfd, flags, true);
53}
54
55int IFaceBase::clear_sock_flags(int sockfd, short flags) const
56{
57 return mod_sock_flags(sockfd, flags, false);
58}
59
60int 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
82int 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
102int 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
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