Skip to content

Commit

Permalink
Adds support for discussed values to WG interface
Browse files Browse the repository at this point in the history
  • Loading branch information
b-m-f committed Nov 9, 2022
1 parent 864eaeb commit 2d48fe3
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 77 deletions.
47 changes: 0 additions & 47 deletions src/network/netlink.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use crate::{
error::{ErrorWrap, NetavarkError, NetavarkResult},
wrap,
};
use genetlink::message::map_to_rawgenlmsg;
use log::trace;
use netlink_packet_generic::{
ctrl::{nlas::GenlCtrlAttrs, GenlCtrl, GenlCtrlCmd},
Expand All @@ -22,10 +21,6 @@ use netlink_packet_route::{
NLM_F_EXCL, NLM_F_REQUEST, RTN_UNICAST, RTPROT_STATIC, RTPROT_UNSPEC, RT_SCOPE_UNIVERSE,
RT_TABLE_MAIN,
};
use netlink_packet_wireguard::{
nlas::{WgAllowedIp, WgAllowedIpAttrs, WgDeviceAttrs, WgPeer, WgPeerAttrs},
Wireguard, WireguardCmd,
};
use netlink_sys::{protocols::NETLINK_ROUTE, SocketAddr};

pub struct Socket {
Expand Down Expand Up @@ -176,24 +171,6 @@ impl Socket {
Ok(())
}

pub fn set_wireguard_private_key(
&mut self,
link_id: u32,
name: String,
private_key: [u8; 32],
) -> NetavarkResult<()> {
let msg: GenlMessage<Wireguard> = GenlMessage::from_payload(Wireguard {
cmd: WireguardCmd::SetDevice,
nlas: vec![
WgDeviceAttrs::IfName(name),
WgDeviceAttrs::PrivateKey(private_key),
],
});
let result = self.make_netlink_wireguard_request(msg, NLM_F_ACK)?;
expect_netlink_result!(result, 0);
Ok(())
}

fn create_addr_msg(link_id: u32, addr: &ipnet::IpNet) -> AddressMessage {
let mut msg = AddressMessage::default();
msg.header.index = link_id;
Expand Down Expand Up @@ -384,30 +361,6 @@ impl Socket {
self.send(msg, flags).wrap("send to netlink")?;
self.recv(flags & NLM_F_DUMP == NLM_F_DUMP)
}
fn make_netlink_wireguard_request(
&mut self,
msg: GenlMessage<Wireguard>,
flags: u16,
) -> NetavarkResult<Vec<RtnlMessage>> {
self.send_generic(msg, flags).wrap("send to netlink")?;
self.recv(flags & NLM_F_DUMP == NLM_F_DUMP)
}

fn send_generic(&mut self, msg: GenlMessage<Wireguard>, flags: u16) -> NetavarkResult<()> {
let mut nlmsg = netlink_packet_core::NetlinkMessage::from(msg);
// packet.header.message_type = "wireguard".to_string();
// packet.header.message_type = packet.g
nlmsg.header.flags = NLM_F_REQUEST | flags;
nlmsg.header.sequence_number = {
self.sequence_number += 1;
self.sequence_number
};
let packet = map_to_rawgenlmsg(nlmsg);

trace!("send WireGuard netlink packet: {:?}", packet);
self.socket.send(&self.buffer[..packet.buffer_len()], 0)?;
Ok(())
}

fn send(&mut self, msg: RtnlMessage, flags: u16) -> NetavarkResult<()> {
let mut packet = NetlinkMessage {
Expand Down
38 changes: 17 additions & 21 deletions src/network/netlink_generic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::{
error::{ErrorWrap, NetavarkError, NetavarkResult},
wrap,
};
use ipnet::IpNet;
use log::trace;
use netlink_packet_core::{NetlinkMessage, NetlinkPayload, NLM_F_ACK, NLM_F_DUMP, NLM_F_REQUEST};
use netlink_packet_generic::{
Expand All @@ -12,9 +13,11 @@ use netlink_packet_wireguard::{
nlas::{WgAllowedIp, WgAllowedIpAttrs, WgDeviceAttrs, WgPeer, WgPeerAttrs},
Wireguard, WireguardCmd,
};

use netlink_sys::{protocols::NETLINK_GENERIC, SocketAddr};
use std::collections::HashMap;


pub struct Socket {
socket: netlink_sys::Socket,
sequence_number: HashMap<String, u32>,
Expand Down Expand Up @@ -60,7 +63,7 @@ impl Socket {
wrap!(socket.bind_auto(), "bind")?;
wrap!(socket.connect(kernel_addr), "connect")?;

let sequence_numbers = HashMap::new();
let mut sequence_numbers = HashMap::new();
sequence_numbers.insert("wireguard".into(), 0);
sequence_numbers.insert("ctrl".into(), 0);
Ok(Socket {
Expand All @@ -70,21 +73,8 @@ impl Socket {
})
}

pub fn set_wireguard_private_key(
&mut self,
name: String,
private_key: [u8; 32],
port: Option<u16>,
) -> NetavarkResult<()> {
let nlas = vec![
WgDeviceAttrs::IfName(name),
WgDeviceAttrs::PrivateKey(private_key),
];
match port {
Some(port) => nlas.push(WgDeviceAttrs::ListenPort(port)),
None => (),
}
let mut msg: GenlMessage<Wireguard> = GenlMessage::from_payload(Wireguard {
pub fn set_wireguard_device(&mut self, nlas: Vec<WgDeviceAttrs>) -> NetavarkResult<()> {
let msg: GenlMessage<Wireguard> = GenlMessage::from_payload(Wireguard {
cmd: WireguardCmd::SetDevice,
nlas,
});
Expand Down Expand Up @@ -143,13 +133,17 @@ impl Socket {
let mut nlmsg = NetlinkMessage::from(msg);

nlmsg.header.flags = NLM_F_REQUEST | flags;

let sequence = self
.sequence_number
.get("wireguard".into())
.expect("Unable to retrieve sequence number for WireGuard netlink package");
nlmsg.header.sequence_number = sequence.clone();
.expect("Unable to retrieve sequence number for WireGuard netlink package")
.clone();

self.sequence_number
.insert("wireguard".into(), sequence + 1);

nlmsg.header.sequence_number = sequence + 1;
nlmsg.finalize();
nlmsg.header.message_type = family;

Expand Down Expand Up @@ -183,7 +177,7 @@ impl Socket {
trace!("read netlink packet: {:?}", rx_packet);
let sequence = self
.sequence_number
.get("ctrl".into())
.get("wireguard".into())
.expect("Unable to retrieve sequence number for WireGuard netlink package");

if rx_packet.header.sequence_number != sequence.clone() {
Expand Down Expand Up @@ -235,9 +229,11 @@ impl Socket {
let sequence = self
.sequence_number
.get("ctrl".into())
.expect("Unable to retrieve sequence number for netlink ctrl package");
nlmsg.header.sequence_number = sequence.clone();
.expect("Unable to retrieve sequence number for netlink ctrl package")
.clone();

self.sequence_number.insert("ctrl".into(), sequence + 1);
nlmsg.header.sequence_number = sequence + 1;

nlmsg.finalize();
nlmsg.serialize(&mut self.buffer[..]);
Expand Down
107 changes: 98 additions & 9 deletions src/network/wireguard.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ use std::{
use base64::decode;
use ipnet::IpNet;
use libc::printf;
use log::debug;
use log::{debug, trace};
use netlink_packet_route::nlas::link::{InfoData, InfoKind, InfoMacVlan, Nla};
use netlink_packet_wireguard::constants::{AF_INET, AF_INET6};
use netlink_packet_wireguard::nlas::{
WgAllowedIp, WgAllowedIpAttrs, WgDeviceAttrs, WgPeer, WgPeerAttrs,
};
use rand::distributions::{Alphanumeric, DistString};
use rand::thread_rng;

Expand Down Expand Up @@ -37,7 +41,8 @@ struct Peer {
/// Optional
persistent_keepalive: Option<u16>,
/// Peers public key to verify traffic during crypto routing
public_key: String,
public_key: [u8; 32],
preshared_key: Option<[u8; 32]>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -110,7 +115,7 @@ impl driver::NetworkDriver for WireGuard<'_> {

// Peer Validation
for (index, peer) in data.peers.iter().enumerate() {
if peer.public_key == "" {
if peer.public_key == [0; 32] {
return Err(NetavarkError::msg(format!(
"invalid WireGuard configuration: Peer #{:?} is missing a PublicKey",
index
Expand All @@ -126,7 +131,7 @@ impl driver::NetworkDriver for WireGuard<'_> {

// Interface Validation
// will succeed if the interface has an Address and a PrivateKey
if data.private_key == [0x00; 32] {
if data.private_key == [0; 32] {
return Err(NetavarkError::msg(format!(
"invalid WireGuard configuration: Interface is missing a PrivateKey",
)));
Expand Down Expand Up @@ -236,9 +241,57 @@ fn create_wireguard_interface(
"Setting PrivateKey to WireGuard interface {}",
data.interface_name.to_string()
);
let mut nlas = vec![
WgDeviceAttrs::IfName(data.interface_name.to_string()),
WgDeviceAttrs::PrivateKey(data.private_key),
];
match data.port {
Some(port) => nlas.push(WgDeviceAttrs::ListenPort(port)),
None => (),
}
if data.peers.len() > 0 {
let mut peers_nla: Vec<WgPeer> = vec![];

for peer in &data.peers {
let mut allowed_ip_nla = vec![];
for ip in &peer.allowed_ips {
let mut family: u16 = AF_INET;

match ip {
IpNet::V4(_) => (),
IpNet::V6(_) => family = AF_INET6,
}
allowed_ip_nla.push(WgAllowedIp {
0: vec![
WgAllowedIpAttrs::IpAddr(ip.network()),
WgAllowedIpAttrs::Cidr(ip.prefix_len()),
WgAllowedIpAttrs::Family(family),
],
});
}
let mut wg_peer = WgPeer {
0: vec![
WgPeerAttrs::PublicKey(peer.public_key),
WgPeerAttrs::AllowedIps(allowed_ip_nla),
],
};
match peer.preshared_key {
Some(key) => wg_peer.0.push(WgPeerAttrs::PresharedKey(key)),
None => (),
}
match peer.persistent_keepalive {
Some(keepalive) => wg_peer.0.push(WgPeerAttrs::PersistentKeepalive(keepalive)),
None => (),
}
peers_nla.push(wg_peer);
}
//TODO_WG: remove
trace!("{:?}", peers_nla);
nlas.push(WgDeviceAttrs::Peers(peers_nla));
}

host_generic_socket
.set_wireguard_private_key(data.interface_name.to_string(), data.private_key)
.set_wireguard_device(nlas)
.wrap("add private key to WireGuard interface")?;

for addr in &data.addresses {
Expand Down Expand Up @@ -397,7 +450,8 @@ fn parse_config(path: &String) -> Result<InternalData, NetavarkError> {
peers.push(Peer {
allowed_ips: vec![],
persistent_keepalive: None,
public_key: "".to_string(),
public_key: [0; 32],
preshared_key: None,
});
continue;
}
Expand Down Expand Up @@ -480,16 +534,51 @@ fn parse_config(path: &String) -> Result<InternalData, NetavarkError> {
Ok(ip) => ip,
Err(e) => {
return Err(NetavarkError::msg(format!(
"error `{:?}` when reading WireGuard peers AllowedIPs: {:?}",
e, value
"error `{:?}` when reading WireGuard peers AllowedIPs: {:?}. Occurs in {:?}",
e, value, ip
)))
}
};
current_peer.allowed_ips.push(ip);
}
}
"PublicKey" => {
current_peer.public_key = value.to_string();
current_peer.public_key = match decode(value.clone()) {
Ok(key) => match key.try_into() {
Ok(key) => key,
Err(e) => {
return Err(NetavarkError::msg(format!(
"error `{:?}` when decoding base64 PublicKey: {:?} for peer {:?}. Is it 32 bytes?",
e, value, current_peer_index
)))
}
},
Err(e) => {
return Err(NetavarkError::msg(format!(
"error `{:?}` when decoding base64 PublicKey: {:?} for peer {:?}",
e, value, current_peer_index
)))
}
}
}
"PresharedKey" => {
current_peer.preshared_key = match decode(value.clone()) {
Ok(key) => match key.try_into() {
Ok(key) => Some(key),
Err(e) => {
return Err(NetavarkError::msg(format!(
"error `{:?}` when decoding base64 PresharedKey: {:?} for peer {:?}. Is it 32 bytes?",
e, value, current_peer_index
)))
}
},
Err(e) => {
return Err(NetavarkError::msg(format!(
"error `{:?}` when decoding base64 PresharedKey: {:?} for peer {:?}",
e, value, current_peer_index
)))
}
}
}
"PersistentKeepalive" => {
let keepalive = match value.parse::<u16>() {
Expand Down
19 changes: 19 additions & 0 deletions test/testfiles/wireguard.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[Interface]
Address = 10.192.122.1/24
Address = 10.10.0.1/16
SaveConfig = true
ListenPort = 51820
PrivateKey = yAnz5TF+lXXJte14tji3zlMNq+hd2rYUIgJBgB3fBmk=

[Peer]
PublicKey = xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=
AllowedIPs = 10.192.122.3/32, 10.192.124.0/24
Endpoint = 123.456.78.9:12345

[Peer]
PublicKey = TrMvSoP4jYQlY6RIzBgbssQqY3vxI2Pi+y71lOWWXX0=
AllowedIPs = ffff::abcd/128, 192.168.0.0/16

[Peer]
PublicKey = gN65BkIKy1eCE9pP1wdc8ROUtkHLF2PfAqYdyYBz6EA=
AllowedIPs = ffff:ffff::/32

0 comments on commit 2d48fe3

Please sign in to comment.