OpenVPN 3 Core Library
Loading...
Searching...
No Matches
route.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// Add routes on Linux using AF_NETLINK socket
13
14#ifndef OPENVPN_NETCONF_LINUX_ROUTE_H
15#define OPENVPN_NETCONF_LINUX_ROUTE_H
16
17#include <cstring>
18#include <unistd.h>
19#include <sys/types.h>
20#include <sys/socket.h>
21#include <linux/netlink.h>
22#include <linux/rtnetlink.h>
23#include <net/if.h>
24#include <errno.h>
25
26#include <string>
27
32
33namespace openvpn {
34
36{
37 public:
38 OPENVPN_EXCEPTION(linux_route_error);
39
41 {
42 fd.reset(::socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE));
43 if (!fd.defined())
44 throw linux_route_error("creating AF_NETLINK socket");
45
46 struct sockaddr_nl local;
47 ::memset(&local, 0, sizeof(local));
48 local.nl_family = AF_NETLINK;
49 local.nl_pad = 0;
50 local.nl_pid = 0; // only use getpid() if unique instantiation per process
51 local.nl_groups = 0;
52 if (::bind(fd(), (struct sockaddr *)&local, sizeof(local)) < 0)
53 throw linux_route_error("binding to AF_NETLINK socket");
54 }
55
56 void add_delete(const bool add,
57 const IP::Route &route,
58 const int if_index,
59 const int table = RT_TABLE_MAIN)
60 {
61 typedef struct
62 {
63 struct nlmsghdr nlmsg_info;
64 struct rtmsg rtmsg_info;
65 char buffer[64]; // must be large enough to contain request
66 } netlink_req_t;
67
68 struct rtattr *rtattr_ptr;
69 int rtmsg_len;
70 struct sockaddr_nl peer;
71 struct msghdr msg_info;
72 struct iovec iov_info;
73 netlink_req_t netlink_req;
74
75 ::memset(&peer, 0, sizeof(peer));
76 peer.nl_family = AF_NETLINK;
77 peer.nl_pad = 0;
78 peer.nl_pid = 0;
79 peer.nl_groups = 0;
80
81 ::memset(&msg_info, 0, sizeof(msg_info));
82 msg_info.msg_name = (void *)&peer;
83 msg_info.msg_namelen = sizeof(peer);
84
85 ::memset(&netlink_req, 0, sizeof(netlink_req));
86
87 rtmsg_len = sizeof(struct rtmsg);
88
89 // add destination addr
90 rtattr_ptr = (struct rtattr *)netlink_req.buffer;
91 rtattr_ptr->rta_type = RTA_DST;
92 rtattr_ptr->rta_len = sizeof(struct rtattr) + route.addr.size_bytes();
93 route.addr.to_byte_string_variable(((unsigned char *)rtattr_ptr) + sizeof(struct rtattr));
94 rtmsg_len += rtattr_ptr->rta_len;
95
96 // add if_index
97 rtattr_ptr = (struct rtattr *)(((unsigned char *)rtattr_ptr) + rtattr_ptr->rta_len);
98 rtattr_ptr->rta_type = RTA_OIF;
99 rtattr_ptr->rta_len = sizeof(struct rtattr) + 4;
100 ::memcpy(((unsigned char *)rtattr_ptr) + sizeof(struct rtattr), &if_index, 4);
101 rtmsg_len += rtattr_ptr->rta_len;
102
103 netlink_req.nlmsg_info.nlmsg_len = NLMSG_LENGTH(rtmsg_len);
104
105 if (add)
106 {
107 netlink_req.nlmsg_info.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
108 netlink_req.nlmsg_info.nlmsg_type = RTM_NEWROUTE;
109 }
110 else // delete
111 {
112 netlink_req.nlmsg_info.nlmsg_flags = NLM_F_REQUEST;
113 netlink_req.nlmsg_info.nlmsg_type = RTM_DELROUTE;
114 }
115
116 netlink_req.rtmsg_info.rtm_family = route.addr.family();
117 netlink_req.rtmsg_info.rtm_table = table;
118 netlink_req.rtmsg_info.rtm_dst_len = route.prefix_len; // add prefix
119
120 netlink_req.rtmsg_info.rtm_protocol = RTPROT_STATIC;
121 netlink_req.rtmsg_info.rtm_scope = RT_SCOPE_UNIVERSE;
122 netlink_req.rtmsg_info.rtm_type = RTN_UNICAST;
123
124 iov_info.iov_base = (void *)&netlink_req.nlmsg_info;
125 iov_info.iov_len = netlink_req.nlmsg_info.nlmsg_len;
126 msg_info.msg_iov = &iov_info;
127 msg_info.msg_iovlen = 1;
128
129 const ssize_t status = ::sendmsg(fd(), &msg_info, 0);
130 if (status < 0)
131 {
132 const int eno = errno;
133 OPENVPN_THROW(linux_route_error, "add_delete: sendmsg failed: " << strerror_str(eno));
134 }
135 }
136
137 static int if_index(const std::string &iface)
138 {
139 const unsigned int ret = ::if_nametoindex(iface.c_str());
140 if (!ret)
141 OPENVPN_THROW(linux_route_error, "if_index: no such interface: " << iface);
142 return ret;
143 }
144
145 private:
147};
148
149} // namespace openvpn
150
151#endif
unsigned int prefix_len
Definition route.hpp:38
OPENVPN_EXCEPTION(linux_route_error)
void add_delete(const bool add, const IP::Route &route, const int if_index, const int table=RT_TABLE_MAIN)
Definition route.hpp:56
static int if_index(const std::string &iface)
Definition route.hpp:137
void reset(const int fd_arg)
Definition scoped_fd.hpp:68
bool defined() const
Definition scoped_fd.hpp:58
#define OPENVPN_THROW(exc, stuff)
std::string strerror_str(const int errnum)
Definition strerror.hpp:21
#define RTA_DST
Definition net-route.h:224
std::string ret
static void add(const Time &t1, const Time::Duration &d1)