OpenVPN 3 Core Library
Loading...
Searching...
No Matches
gw.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// Get IPv4 gateway info on Mac OS X.
13
14#ifndef OPENVPN_TUN_MAC_GWV4_H
15#define OPENVPN_TUN_MAC_GWV4_H
16
17#include <sys/types.h>
18#include <sys/socket.h>
19#include <sys/ioctl.h>
20#include <netinet/in.h>
21#include <net/route.h>
22#include <net/if.h>
23#include <net/if_dl.h>
24#include <netinet6/in6_var.h>
25
26#include <cstring>
27#include <string>
28#include <sstream>
29#include <algorithm> // for std::max
30#include <cstdint> // for std::uint32_t
31#include <memory>
32
38#include <openvpn/addr/ip.hpp>
41#include <ifaddrs.h>
42
43namespace openvpn {
45{
46 struct rtmsg
47 {
49 char m_space[512];
50 };
51
52 constexpr std::uint32_t openvpn_roundup(std::uint32_t a)
53 {
54 constexpr std::uint32_t size = sizeof(std::uint32_t);
55 return a > 0 ? (1 + ((a - 1) | (size - 1))) : size;
56 }
57
58 public:
59 OPENVPN_EXCEPTION(route_gateway_error);
60
61 enum
62 {
63 ADDR_DEFINED = (1 << 0), /* set if gateway.addr defined */
64 NETMASK_DEFINED = (1 << 1), /* set if gateway.netmask defined */
65 HWADDR_DEFINED = (1 << 2), /* set if hwaddr is defined */
66 IFACE_DEFINED = (1 << 3), /* set if iface is defined */
67 };
68
69 MacGatewayInfo(IP::Addr dest, std::ostream *os = nullptr)
70 {
71 /* setup data to send to routing socket */
72 int seq = 0;
73
74 struct rtmsg m_rtmsg{};
75
76 m_rtmsg.m_rtm.rtm_type = RTM_GET;
77 m_rtmsg.m_rtm.rtm_flags = RTF_UP;
79 m_rtmsg.m_rtm.rtm_seq = ++seq;
81 m_rtmsg.m_rtm.rtm_msglen = sizeof(struct rt_msghdr);
82
83 if (!dest.is_ipv6())
84 {
85 auto dst4 = reinterpret_cast<sockaddr_in *>(&m_rtmsg.m_space);
86 *dst4 = dest.to_ipv4().to_sockaddr();
87
88 m_rtmsg.m_rtm.rtm_msglen += openvpn_roundup(sizeof(struct sockaddr_in));
89 }
90 else
91 {
92 auto dst6 = reinterpret_cast<sockaddr_in6 *>(&m_rtmsg.m_space);
93 *dst6 = dest.to_ipv6().to_sockaddr();
94
95 m_rtmsg.m_rtm.rtm_msglen += openvpn_roundup(sizeof(struct sockaddr_in6));
96 }
97
98 /* transact with routing socket */
99 ScopedFD sockfd;
100 sockfd.reset(socket(PF_ROUTE, SOCK_RAW, 0));
101 if (!sockfd.defined())
102 throw route_gateway_error("GDG: socket #1 failed");
103
104 auto ret = ::write(sockfd(), &m_rtmsg, m_rtmsg.m_rtm.rtm_msglen);
105 if (ret < 0)
106 {
107 // likely no default gw or IPv6 connectivity
108 if (os)
109 {
110 *os << "GDG: problem writing to routing socket: " << std::to_string(ret) << " errno: " << std::to_string(errno) << " msg: " << ::strerror(errno) << std::endl;
111 }
112
113 return;
114 }
115
116 int l = 0;
117 int pid = ::getpid();
118 do
119 {
120 l = ::read(sockfd(), &m_rtmsg, sizeof(m_rtmsg));
121 } while (l > 0 && (m_rtmsg.m_rtm.rtm_seq != seq || m_rtmsg.m_rtm.rtm_pid != pid));
122 sockfd.close();
123
124 /* extract return data from routing socket */
125 struct sockaddr *gate = nullptr, *ifp = nullptr, *sa;
126 struct rt_msghdr *rtm_aux = &m_rtmsg.m_rtm;
127 auto cp = reinterpret_cast<char *>(rtm_aux + 1);
128 if (rtm_aux->rtm_addrs)
129 {
130 for (unsigned int i = 1; i; i <<= 1u)
131 {
132 if (i & rtm_aux->rtm_addrs)
133 {
134 sa = reinterpret_cast<struct sockaddr *>(cp);
135 if (i == RTA_GATEWAY)
136 gate = sa;
137 else if (i == RTA_IFP)
138 ifp = sa;
139 cp += openvpn_roundup(sa->sa_len);
140 }
141 }
142 }
143 else
144 return;
145
146 /* get gateway addr and interface name */
147 if (gate != nullptr)
148 {
149 /* get default gateway addr */
153
154 if (ifp)
155 {
156 /* get interface name */
157 const auto adl = reinterpret_cast<struct sockaddr_dl *>(ifp);
158 const size_t len = adl->sdl_nlen;
159 if (len && len < sizeof(iface_))
160 {
161 std::memcpy(iface_, adl->sdl_data, len);
162 iface_[len] = '\0';
164 }
165 }
166 }
167
168 /* get netmask of interface that owns default gateway. Querying the IPv6 netmask does not
169 * seem to work on my system (Arne), so it is disabled for now until we can figure out why it
170 * doesn't work */
172 {
173 ifreq ifr{};
174 sa_family_t sa_family;
175
176 sa_family = AF_INET;
177 ifr.ifr_addr.sa_family = sa_family;
178 string::strncpynt(ifr.ifr_name, iface_, IFNAMSIZ);
179
180 sockfd.reset(socket(sa_family, SOCK_DGRAM, 0));
181 if (!sockfd.defined())
182 throw route_gateway_error("GDG: socket #2 failed");
183
184 if (::ioctl(sockfd(), SIOCGIFNETMASK, (char *)&ifr) < 0)
185 throw route_gateway_error("GDG: ioctl SIOCGIFNETMASK failed");
186
189
190 sockfd.close();
191 }
192
193 /* try to read MAC addr associated with interface that owns default gateway */
194 if (flags_ & IFACE_DEFINED)
195 {
196 struct ifaddrs *ifaddrp, *ifa;
197
198 if (getifaddrs(&ifaddrp) != 0)
199 {
200 throw route_gateway_error("GDG: getifaddrs failed errno: " + std::to_string(errno) + " msg: " + ::strerror(errno));
201 }
202
203 /* put the pointer into a unique_ptr to have RAII (allow throwing etc) */
204 std::unique_ptr<::ifaddrs, decltype(&::freeifaddrs)> ifap{ifaddrp, &::freeifaddrs};
205
206 for (ifa = ifap.get(); ifa != nullptr; ifa = ifa->ifa_next)
207 {
208 if (ifa->ifa_addr == nullptr)
209 continue;
210
212 && ifa->ifa_addr->sa_family == AF_LINK
213 && !strncmp(ifa->ifa_name, iface_, IFNAMSIZ))
214 {
215 const auto sockaddr_dl = reinterpret_cast<struct sockaddr_dl *>(ifa->ifa_addr);
216
217 hwaddr_.reset(reinterpret_cast<unsigned char *>(LLADDR(sockaddr_dl)));
219 }
220 }
221 }
222 }
223
224 std::string info() const
225 {
226 std::ostringstream os;
227 os << "GATEWAY";
228 if (flags_ & ADDR_DEFINED)
229 {
230 os << " ADDR=" << gateway_.addr;
232 {
233 os << '/' << gateway_.netmask;
234 }
235 }
236 if (flags_ & IFACE_DEFINED)
237 os << " IFACE=" << iface_;
239 os << " HWADDR=" << hwaddr_;
240 return os.str();
241 }
242
243 unsigned int flags() const
244 {
245 return flags_;
246 }
247 const IP::Addr &gateway_addr() const
248 {
249 return gateway_.addr;
250 }
251 std::string gateway_addr_str() const
252 {
253 return gateway_addr().to_string();
254 }
256 {
257 return gateway_.netmask;
258 }
259 std::string gateway_netmask_str() const
260 {
261 return gateway_netmask().to_string();
262 }
263 std::string iface() const
264 {
265 return iface_;
266 }
267 const MACAddr &hwaddr() const
268 {
269 return hwaddr_;
270 }
271
273 {
275 }
276
277 bool hwaddr_defined() const
278 {
279 return flags_ & HWADDR_DEFINED;
280 }
281
282 private:
283 unsigned int flags_ = 0;
285 char iface_[16];
287};
288
289} // namespace openvpn
290
291#endif
Version version() const
Definition ip.hpp:895
static Addr from_sockaddr(const struct sockaddr *sa)
Definition ip.hpp:326
std::string to_string() const
Definition ip.hpp:528
const IPv4::Addr & to_ipv4() const
Definition ip.hpp:276
const IPv6::Addr & to_ipv6() const
Definition ip.hpp:296
bool is_ipv6() const
Definition ip.hpp:949
bool unspecified() const
Definition ip.hpp:806
sockaddr_in to_sockaddr(const unsigned short port=0) const
Definition ipv4.hpp:87
sockaddr_in6 to_sockaddr(const unsigned short port=0) const
Definition ipv6.hpp:87
void reset(const unsigned char *addr)
Definition macaddr.hpp:35
bool iface_addr_defined() const
Definition gw.hpp:272
unsigned int flags() const
Definition gw.hpp:243
const IP::Addr & gateway_addr() const
Definition gw.hpp:247
bool hwaddr_defined() const
Definition gw.hpp:277
std::string gateway_netmask_str() const
Definition gw.hpp:259
OPENVPN_EXCEPTION(route_gateway_error)
unsigned int flags_
Definition gw.hpp:283
IP::AddrMaskPair gateway_
Definition gw.hpp:284
const MACAddr & hwaddr() const
Definition gw.hpp:267
std::string info() const
Definition gw.hpp:224
std::string iface() const
Definition gw.hpp:263
constexpr std::uint32_t openvpn_roundup(std::uint32_t a)
Definition gw.hpp:52
std::string gateway_addr_str() const
Definition gw.hpp:251
MacGatewayInfo(IP::Addr dest, std::ostream *os=nullptr)
Definition gw.hpp:69
const IP::Addr & gateway_netmask() const
Definition gw.hpp:255
void reset(const int fd_arg)
Definition scoped_fd.hpp:68
bool defined() const
Definition scoped_fd.hpp:58
void strncpynt(char *dest, const char *src, size_t maxlen)
Definition string.hpp:54
#define RTM_GET
Definition net-route.h:192
#define RTF_UP
Definition net-route.h:97
#define RTA_IFP
Definition net-route.h:228
#define RTA_DST
Definition net-route.h:224
#define RTA_GATEWAY
Definition net-route.h:225
#define RTM_VERSION
Definition net-route.h:184
struct rt_msghdr m_rtm
Definition gw.hpp:48
int rtm_flags
Definition net-route.h:157
pid_t rtm_pid
Definition net-route.h:159
u_short rtm_msglen
Definition net-route.h:153
u_char rtm_type
Definition net-route.h:155
int rtm_addrs
Definition net-route.h:158
u_char rtm_version
Definition net-route.h:154
int rtm_seq
Definition net-route.h:160
std::string ret
std::ostringstream os