use std::os::fd::RawFd;
use crate::macros::GenlTypedDumpStream;
use crate::netlink::{
Connection,
error::{Error, Result},
genl::ovpn::messages::{
OvpnKeyDelRequest, OvpnKeyGetRequest, OvpnKeyNewRequest, OvpnKeyReply,
OvpnKeySwapRequest, OvpnKeyconf, OvpnPeer, OvpnPeerDelRequest, OvpnPeerGetRequest,
OvpnPeerNewRequest, OvpnPeerReply, OvpnPeerSetRequest,
},
genl::ovpn::types::OvpnKeySlot,
};
use super::Ovpn;
impl Connection<Ovpn> {
pub async fn peer_new(&self, ifindex: u32, peer: OvpnPeer) -> Result<()> {
let _: OvpnPeerReply = self
.send_typed(OvpnPeerNewRequest::new(ifindex, peer))
.await?;
Ok(())
}
pub async fn peer_set(&self, ifindex: u32, peer: OvpnPeer) -> Result<()> {
let _: OvpnPeerReply = self
.send_typed(OvpnPeerSetRequest::new(ifindex, peer))
.await?;
Ok(())
}
pub async fn peer_get(&self, ifindex: u32, peer_id: u32) -> Result<OvpnPeer> {
let reply: OvpnPeerReply = self
.send_typed(OvpnPeerGetRequest::by_id(ifindex, peer_id))
.await?;
reply.peer.ok_or_else(|| {
Error::InvalidMessage(format!(
"peer_get(ifindex={ifindex}, peer_id={peer_id}): kernel reply missing OVPN_A_PEER"
))
})
}
pub async fn peer_dump(&self, ifindex: u32) -> Result<Vec<OvpnPeer>> {
use tokio_stream::StreamExt;
let mut stream: GenlTypedDumpStream<'_, Ovpn, OvpnPeerReply> = self
.dump_typed_stream(OvpnPeerGetRequest::dump(ifindex))
.await?;
let mut out = Vec::new();
while let Some(reply) = stream.next().await {
let reply = reply?;
if let Some(peer) = reply.peer {
out.push(peer);
}
}
Ok(out)
}
pub async fn peer_del(&self, ifindex: u32, peer_id: u32) -> Result<()> {
let _: OvpnPeerReply = self
.send_typed(OvpnPeerDelRequest::new(ifindex, peer_id))
.await?;
Ok(())
}
pub async fn key_new(&self, ifindex: u32, keyconf: OvpnKeyconf) -> Result<()> {
let _: OvpnKeyReply = self
.send_typed(OvpnKeyNewRequest::new(ifindex, keyconf))
.await?;
Ok(())
}
pub async fn key_get(
&self,
ifindex: u32,
peer_id: u32,
slot: OvpnKeySlot,
) -> Result<OvpnKeyconf> {
let reply: OvpnKeyReply = self
.send_typed(OvpnKeyGetRequest::new(ifindex, peer_id, slot))
.await?;
reply.keyconf.ok_or_else(|| {
Error::InvalidMessage(format!(
"key_get(ifindex={ifindex}, peer_id={peer_id}, slot={slot:?}): \
kernel reply missing OVPN_A_KEYCONF"
))
})
}
pub async fn key_swap(&self, ifindex: u32, peer_id: u32) -> Result<()> {
let _: OvpnKeyReply = self
.send_typed(OvpnKeySwapRequest::new(ifindex, peer_id))
.await?;
Ok(())
}
pub async fn key_del(
&self,
ifindex: u32,
peer_id: u32,
slot: OvpnKeySlot,
) -> Result<()> {
let _: OvpnKeyReply = self
.send_typed(OvpnKeyDelRequest::new(ifindex, peer_id, slot))
.await?;
Ok(())
}
pub async fn attach_socket(
&self,
_ifindex: u32,
_peer_id: u32,
_fd: RawFd,
) -> Result<()> {
Err(Error::NotSupported(
"Connection::<Ovpn>::attach_socket — cross-netns fd passing via SCM_RIGHTS \
not yet implemented. Same-netns callers should set OvpnPeer::socket = Some(fd) \
and call peer_new() directly; the kernel resolves the fd via sockfd_lookup. \
See plans/197-declarative-ovpn-plan.md §7."
.into(),
))
}
}