blob: 753ab74c8a4be6691911d4f5aa232e7ade1bea25 [file] [log] [blame]
William A. Kennington III7d6fa422021-02-08 17:04:02 -08001#include "net_iface.h"
2
3#include <linux/if_packet.h>
4#include <net/ethernet.h>
5#include <sys/socket.h>
6#include <unistd.h>
7
8#include <cstdio>
9#include <cstring>
10#include <stdexcept>
11
12namespace net
13{
14
15IFaceBase::IFaceBase(const std::string& name) : name_{name}
16{
17 if (name.size() >= IFNAMSIZ)
18 {
19 throw std::length_error("Interface name is too long");
20 }
21}
22
23int IFaceBase::get_index() const
24{
25 struct ifreq ifr;
26 std::memset(&ifr, 0, sizeof(ifr));
27 int ret = ioctl(SIOCGIFINDEX, &ifr);
28 if (ret < 0)
29 {
30 return ret;
31 }
32
33 return ifr.ifr_ifindex;
34}
35
36int IFaceBase::set_sock_flags(int sockfd, short flags) const
37{
38 return mod_sock_flags(sockfd, flags, true);
39}
40
41int IFaceBase::clear_sock_flags(int sockfd, short flags) const
42{
43 return mod_sock_flags(sockfd, flags, false);
44}
45
46int IFaceBase::mod_sock_flags(int sockfd, short flags, bool set) const
47{
48 struct ifreq ifr;
49 std::memset(&ifr, 0, sizeof(ifr));
50
51 int ret = ioctl_sock(sockfd, SIOCGIFFLAGS, &ifr);
52 if (ret < 0)
53 {
54 return ret;
55 }
56
57 if (set)
58 {
59 ifr.ifr_flags |= flags;
60 }
61 else
62 {
63 ifr.ifr_flags &= ~flags;
64 }
65 return ioctl_sock(sockfd, SIOCSIFFLAGS, &ifr);
66}
67
68int IFace::ioctl_sock(int sockfd, int request, struct ifreq* ifr) const
69{
70 if (ifr == nullptr)
71 {
72 return -1;
73 }
74
75 /* Avoid string truncation. */
76 size_t len = name_.length();
77 if (len + 1 >= sizeof(ifr->ifr_name))
78 {
79 return -1;
80 }
81
82 std::memcpy(ifr->ifr_name, name_.c_str(), len);
83 ifr->ifr_name[len] = 0;
84
85 return ::ioctl(sockfd, request, ifr);
86}
87
88int IFace::bind_sock(int sockfd, struct sockaddr_ll* saddr) const
89{
90 if (saddr == nullptr)
91 {
92 return -1;
93 }
94
95 saddr->sll_ifindex = get_index();
96
97 return bind(sockfd, reinterpret_cast<struct sockaddr*>(saddr),
98 sizeof(*saddr));
99}
100
101int IFace::ioctl(int request, struct ifreq* ifr) const
102{
103 if (ifr == nullptr)
104 {
105 return -1;
106 }
107
108 int tempsock = socket(AF_INET, SOCK_DGRAM, 0);
109 if (tempsock < 0)
110 {
111 return tempsock;
112 }
113
114 int ret = ioctl_sock(tempsock, request, ifr);
115 close(tempsock);
116
117 return ret;
118}
119
120} // namespace net