24#include <netlink/genl/ctrl.h>
25#include <netlink/genl/family.h>
26#include <netlink/genl/genl.h>
27#include <netlink/netlink.h>
28#include <netlink/socket.h>
54#define nla_nest_start(_msg, _type) nla_nest_start(_msg, (_type) | NLA_F_NESTED)
59 if (nla_len(attr) ==
sizeof(uint32_t))
60 return nla_get_u32(attr);
62 return nla_get_u64(attr);
105template <
typename ReadHandler>
106class GeNL :
public RC<thread_unsafe_refcount>
110 typedef std::unique_ptr<nl_msg,
decltype(&nlmsg_free)>
NlMsgPtr;
111 typedef std::unique_ptr<nl_sock,
decltype(&nl_socket_free)>
NlSockPtr;
112 typedef std::unique_ptr<nl_cb,
decltype(&nl_cb_put)>
NlCbPtr;
126 int nl_family_id = -1;
130 return nl_family_id >= 0;
141 explicit GeNL(openvpn_io::io_context &io_context,
142 unsigned int ifindex_arg,
143 ReadHandler read_handler_arg)
144 :
sock_ptr(nl_socket_alloc(), nl_socket_free),
145 cb_ptr(nl_cb_alloc(NL_CB_DEFAULT), nl_cb_put),
152 nl_socket_set_buffer_size(
sock, 8192, 8192);
154 int ret = genl_connect(
sock);
157 " cannot connect to generic netlink: " << nl_geterror(ret));
160 if (setsockopt(nl_socket_get_fd(
sock), SOL_NETLINK, NETLINK_EXT_ACK, &ret,
sizeof(ret)) < 0)
162 " cannot enable NETLINK_EXT_ACK on socket: " << errno);
167 " cannot get multicast group: " << nl_geterror(mcast_id));
169 ret = nl_socket_add_membership(
sock, mcast_id);
171 OPENVPN_THROW(netlink_error,
"failed to join mcast group: " << ret);
176 " cannot find ovpn_dco netlink component: " <<
ovpn_dco_id);
182 nl_cb_set(
cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM,
183 [](
struct nl_msg *,
void *) ->
int
188 nl_socket_set_cb(
sock,
cb);
191 stream.reset(
new openvpn_io::posix::stream_descriptor(
192 io_context, nl_socket_get_fd(
sock)));
194 nl_socket_set_nonblocking(
sock);
219 struct sockaddr_in *sin = (
struct sockaddr_in *)sa;
221 auto *
msg = msg_ptr.get();
226 if (sa->sa_family == AF_INET)
230 else if (sa->sa_family == AF_INET6)
232 struct sockaddr_in6 *sin6 = (
struct sockaddr_in6 *)sa;
238 OPENVPN_THROW(netlink_error,
" new_peer() bogus remote address family " << sa->sa_family);
253 nla_nest_end(
msg, attr);
272 auto *
msg = msg_ptr.get();
274 const int NONCE_TAIL_LEN = 8;
276 struct nlattr *key_dir;
280 OPENVPN_THROW(netlink_error,
" new_key() cannot allocate submessage");
290 " new_key() cannot allocate encrypt key submessage");
298 nla_nest_end(
msg, key_dir);
303 " new_key() cannot allocate decrypt key submessage");
311 nla_nest_end(
msg, key_dir);
313 nla_nest_end(
msg, attr);
332 auto *
msg = msg_ptr.get();
335 OPENVPN_THROW(netlink_error,
" swap_keys() cannot allocate submessage");
339 nla_nest_end(
msg, attr);
345 OPENVPN_THROW(netlink_error,
" swap_keys() nla_put_failure");
355 void del_key(
int peer_id,
unsigned int key_slot)
358 auto *
msg = msg_ptr.get();
361 OPENVPN_THROW(netlink_error,
" del_key() cannot allocate submessage");
366 nla_nest_end(
msg, attr);
385 void set_peer(
int peer_id,
unsigned int keepalive_interval,
unsigned int keepalive_timeout)
388 auto *
msg = msg_ptr.get();
391 OPENVPN_THROW(netlink_error,
" set_peer() cannot allocate submessage");
397 nla_nest_end(
msg, attr);
415 auto *
msg = msg_ptr.get();
418 OPENVPN_THROW(netlink_error,
" del_peer() cannot allocate submessage");
422 nla_nest_end(
msg, attr);
441 auto *
msg = msg_ptr.get();
444 OPENVPN_THROW(netlink_error,
" get_peer() cannot allocate submessage");
448 nla_nest_end(
msg, attr);
458 stream->wait(openvpn_io::posix::stream_descriptor::wait_read);
510 struct nlattr *tb[CTRL_ATTR_MAX + 1];
511 struct genlmsghdr *gnlh =
static_cast<genlmsghdr *
>(
512 nlmsg_data(
reinterpret_cast<const nlmsghdr *
>(nlmsg_hdr(
msg))));
513 struct nlattr *mcgrp;
516 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
518 if (!tb[CTRL_ATTR_MCAST_GROUPS])
521 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], rem_mcgrp)
523 struct nlattr *tb_mcgrp[CTRL_ATTR_MCAST_GRP_MAX + 1];
526 CTRL_ATTR_MCAST_GRP_MAX,
527 static_cast<nlattr *
>(nla_data(mcgrp)),
531 if (!tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME] || !tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID])
533 if (strncmp((
const char *)nla_data(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME]),
535 nla_len(tb_mcgrp[CTRL_ATTR_MCAST_GRP_NAME])))
537 grp->
id = nla_get_u32(tb_mcgrp[CTRL_ATTR_MCAST_GRP_ID]);
557 NlMsgPtr msg_ptr(nlmsg_alloc(), nlmsg_free);
558 auto *
msg = msg_ptr.get();
560 NlCbPtr mcast_cb_ptr(nl_cb_alloc(NL_CB_DEFAULT), nl_cb_put);
561 auto *mcast_cb = mcast_cb_ptr.get();
563 int ctrlid = genl_ctrl_resolve(
sock,
"nlctrl");
565 genlmsg_put(
msg, 0, 0, ctrlid, 0, 0, CTRL_CMD_GETFAMILY, 0);
571 nl_cb_err(mcast_cb, NL_CB_CUSTOM,
572 [](
struct sockaddr_nl *nla,
struct nlmsgerr *err,
void *arg) ->
int
574 int *ret =
static_cast<int *
>(arg);
578 nl_cb_set(mcast_cb, NL_CB_ACK, NL_CB_CUSTOM,
579 [](
struct nl_msg *
msg,
void *arg) ->
int
581 int *ret =
static_cast<int *
>(arg);
590 nl_recvmsgs(
sock, mcast_cb);
598 OPENVPN_THROW(netlink_error,
"get_mcast_id() nla_put_failure");
606 std::ostringstream os;
609 os <<
"error reading netlink message: " << error.message() <<
", "
623 catch (
const netlink_error &e)
635 stream->async_wait(openvpn_io::posix::stream_descriptor::wait_read,
636 [self =
Ptr(
this)](
const openvpn_io::error_code &error)
638 self->handle_read(error);
644 NlMsgPtr msg_ptr(nlmsg_alloc(), nlmsg_free);
645 genlmsg_put(msg_ptr.get(), 0, 0,
ovpn_dco_id, 0, 0, cmd, 0);
650 OPENVPN_THROW(netlink_error,
" create_msg() nla_put_failure");
657 int ovpn_dco_err = 0;
662 int netlink_err = nl_recvmsgs(
sock,
cb);
664 if (ovpn_dco_err != 0)
666 "ovpn-dco error on receiving message: "
667 << strerror(-ovpn_dco_err) <<
", " << ovpn_dco_err);
671 "netlink error on receiving message: "
672 << nl_geterror(netlink_err) <<
", " << netlink_err);
685 GeNL *self =
static_cast<GeNL *
>(arg);
688 struct genlmsghdr *gnlh =
static_cast<genlmsghdr *
>(
689 nlmsg_data(
reinterpret_cast<const nlmsghdr *
>(nlmsg_hdr(
msg))));
690 struct nlmsghdr *nlh = nlmsg_hdr(
msg);
693 if (!genlmsg_valid_hdr(nlh, 0))
699 if (nla_parse(attrs,
OVPN_A_MAX, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL))
710 OPENVPN_LOG(
"missing OVPN_A_IFINDEX attribute in message");
718 OPENVPN_THROW(netlink_error,
"missing OVPN_A_PEER attribute in "
719 "OVPN_CMD_PEER_DEL_NTF message");
725 "cannot parse OVPN_A_PEER attribute");
728 OPENVPN_THROW(netlink_error,
"missing attributes in OVPN_CMD_PEER_DEL_NTF");
731 self->
buf.
write(&gnlh->cmd,
sizeof(gnlh->cmd));
735 self->
buf.
write(&peer_id,
sizeof(peer_id));
740 self->
buf.
write(&reason,
sizeof(reason));
749 OPENVPN_THROW(netlink_error,
"missing OVPN_A_PEER attribute in "
750 "OVPN_CMD_PEER_GET command reply");
755 OPENVPN_THROW(netlink_error,
"cannot parse OVPN_A_PEER attribute");
758 OPENVPN_THROW(netlink_error,
"missing attribute PEER_ID in OVPN_CMD_PEER_GET reply");
797 self->
buf.
write(&gnlh->cmd,
sizeof(gnlh->cmd));
798 self->
buf.
write(&peer,
sizeof(peer));
806 OPENVPN_LOG(__func__ <<
" unknown netlink command: " << (
int)gnlh->cmd);
828 struct nlmsgerr *err,
831 struct nlmsghdr *nlh = (
struct nlmsghdr *)err - 1;
833 int len = nlh->nlmsg_len;
834 struct nlattr *attrs;
835 int *ret =
static_cast<int *
>(arg);
836 int ack_len =
sizeof(*nlh) +
sizeof(int) +
sizeof(*nlh);
840 if (!(nlh->nlmsg_flags & NLM_F_ACK_TLVS))
843 if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
844 ack_len +=
static_cast<int>(err->msg.nlmsg_len -
sizeof(*nlh));
849 attrs =
reinterpret_cast<nlattr *
>((
unsigned char *)nlh + ack_len);
852 nla_parse(tb_msg, NLMSGERR_ATTR_MAX, attrs, len, NULL);
853 if (tb_msg[NLMSGERR_ATTR_MSG])
856 << (
char *)nla_data(tb_msg[NLMSGERR_ATTR_MSG]));
861 OPENVPN_LOG(__func__ <<
"missing required nesting type "
867 OPENVPN_LOG(__func__ <<
"missing required attribute type "
876 int netlink_err = nl_send_auto(
sock,
msg);
880 "netlink error on sending message: "
881 << nl_geterror(netlink_err) <<
", " << netlink_err);
898 std::unique_ptr<openvpn_io::posix::stream_descriptor>
stream;
902template <
typename ReadHandler>
void reset(const size_t min_capacity, const BufferFlags flags=BufAllocFlags::NO_FLAGS)
Resets the buffer with the specified minimum capacity and flags.
void write(const T *data, const size_t size)
Write data to the buffer.
OPENVPN_EXCEPTION(netlink_error)
void new_key(unsigned int key_slot, const KoRekey::KeyConfig *kc)
std::unique_ptr< nl_cb, decltype(&nl_cb_put)> NlCbPtr
static int mcast_family_handler(struct nl_msg *msg, void *arg)
void handle_read(const openvpn_io::error_code &error)
void new_peer(int peer_id, int fd, struct sockaddr *sa, socklen_t salen, IPv4::Addr vpn4, IPv6::Addr vpn6)
NlMsgPtr create_msg(int cmd)
void get_peer(int peer_id, bool sync)
void send_netlink_message(struct nl_msg *msg)
void swap_keys(int peer_id)
static int ovpn_nl_cb_error(struct sockaddr_nl *nla, struct nlmsgerr *err, void *arg)
void read_netlink_message()
GeNL(openvpn_io::io_context &io_context, unsigned int ifindex_arg, ReadHandler read_handler_arg)
void del_peer(int peer_id)
void del_key(int peer_id, unsigned int key_slot)
std::unique_ptr< nl_sock, decltype(&nl_socket_free)> NlSockPtr
std::unique_ptr< openvpn_io::posix::stream_descriptor > stream
void set_peer(int peer_id, unsigned int keepalive_interval, unsigned int keepalive_timeout)
std::unique_ptr< nl_msg, decltype(&nlmsg_free)> NlMsgPtr
static int message_received(struct nl_msg *msg, void *arg)
std::uint32_t to_uint32_net() const
in6_addr to_in6_addr() const
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
#define OPENVPN_THROW(exc, stuff)
#define nla_nest_start(_msg, _type)
@ OVPN_NLMSGERR_ATTR_MISS_TYPE
@ OVPN_NLMSGERR_ATTR_MISS_NEST
#define OPENVPN_LOG(args)
constexpr BufferFlags GROW(1U<< 2)
if enabled, buffer will grow (otherwise buffer_full exception will be thrown)
constexpr BufferFlags DESTRUCT_ZERO(1U<< 1)
if enabled, destructor will zero data before deletion
constexpr BufferFlags CONSTRUCT_ZERO(1U<< 0)
if enabled, constructors/init will zero allocated space
uint64_t ovpn_nla_get_uint(struct nlattr *attr)
int(* ovpn_nl_cb)(struct nl_msg *msg, void *arg)
void buf_write_string(Buffer &buf, const std::string &str)
@ OVPN_CIPHER_ALG_CHACHA20_POLY1305
@ OVPN_CIPHER_ALG_AES_GCM
@ OVPN_A_KEYCONF_DECRYPT_DIR
@ OVPN_A_KEYCONF_CIPHER_ALG
@ OVPN_A_KEYCONF_ENCRYPT_DIR
@ OVPN_A_KEYDIR_CIPHER_KEY
@ OVPN_A_KEYDIR_NONCE_TAIL
@ OVPN_A_PEER_LINK_RX_BYTES
@ OVPN_A_PEER_LINK_TX_BYTES
@ OVPN_A_PEER_KEEPALIVE_TIMEOUT
@ OVPN_A_PEER_LINK_TX_PACKETS
@ OVPN_A_PEER_VPN_RX_PACKETS
@ OVPN_A_PEER_VPN_TX_BYTES
@ OVPN_A_PEER_REMOTE_IPV6
@ OVPN_A_PEER_VPN_RX_BYTES
@ OVPN_A_PEER_LINK_RX_PACKETS
@ OVPN_A_PEER_VPN_TX_PACKETS
@ OVPN_A_PEER_REMOTE_IPV4
@ OVPN_A_PEER_KEEPALIVE_INTERVAL
@ OVPN_A_PEER_REMOTE_IPV6_SCOPE_ID
@ OVPN_A_PEER_REMOTE_PORT
const unsigned char * cipher_key
unsigned int cipher_key_size
unsigned char nonce_tail[8]
struct sockaddr_storage remote
struct openvpn::OvpnDcoPeer::@110 vpn
struct openvpn::OvpnDcoPeer::@111 transport
RCPtr< struct OvpnDcoPeer > Ptr
struct openvpn::OvpnDcoPeer::@109 keepalive