netlink-bindings 0.3.3

Type-safe Rust bindings for Netlink generated from YAML specifications
Documentation
use crate::utils::*;

use crate::wireguard;
use crate::wireguard::*;

#[test]
#[should_panic(expected = "Error parsing header of \"Wgdevice\" (unknown attribute) at offset 4")]
fn invalid_header_size() {
    let payload = &[0x01, 0x01, 0x00, 0x00, 0x01, 0x00];

    dump_hex(payload);

    // NOTE: Decoder is configured to panic on error in #[cfg(test)]
    println!("{:#?}", OpSetDeviceDo::decode_request(payload));
}

#[test]
#[should_panic(expected = "Error parsing header of \"Wgdevice\" (unknown attribute) at offset 4")]
fn overflowing_header_size() {
    let payload = &[0x01, 0x01, 0x00, 0x00, 0x04];

    dump_hex(payload);

    println!("{:#?}", OpSetDeviceDo::decode_request(payload));
}

#[test]
#[should_panic(expected = "Error parsing attribute \"Ifindex\" of \"Wgdevice\" at offset 4")]
fn invalid_len_of_fixed_payload() {
    let payload = &[
        0x01, 0x01, 0x00, 0x00, 0x06, 0x00, 0x01, 0x00, 0xff, 0x00, 0x00, 0x00,
    ];

    dump_hex(payload);

    println!("{:#?}", OpSetDeviceDo::decode_request(payload));
}

#[test]
#[should_panic(expected = "Missing attribute \"PublicKey\" in \"Wgdevice\"")]
fn missing_attribute() {
    let payload = &[0x01, 0x01, 0x00, 0x00];

    dump_hex(payload);

    let iter = OpSetDeviceDo::decode_request(payload);
    println!("{:#?}", iter);

    iter.get_public_key().ok();
}

const PUB_KEY: [u8; wireguard::KEY_LEN as usize] = [
    0x8d, 0x9d, 0x60, 0x90, 0x6b, 0xfd, 0xa7, 0x7e, 0x4e, 0x4d, 0x3a, 0x06, 0x9c, 0x2f, 0x2d, 0x3c,
    0xc3, 0x30, 0xe1, 0xeb, 0xfb, 0xce, 0xf6, 0x6a, 0x85, 0xed, 0xd3, 0xe6, 0xc1, 0xf7, 0xf6, 0x73,
];

#[test]
fn wg0_set_2_allowed_addresses() {
    #[cfg_attr(any(), rustfmt::skip)]
    let payload = &[
        // 0x8c, 0x00, 0x00, 0x00, 0x26, 0x00, 0x05, 0x00, 0xde, 0x54, 0xc8, 0x68, 0x00, 0x00, 0x00, 0x00, 
        // ^ Message header handled by transport layer
        0x01, 0x01, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x77, 0x67, 0x30, 0x00, 0x70, 0x00, 0x08, 0x80,
        0x6c, 0x00, 0x00, 0x80, 0x24, 0x00, 0x01, 0x00, 0x8d, 0x9d, 0x60, 0x90, 0x6b, 0xfd, 0xa7, 0x7e,
        0x4e, 0x4d, 0x3a, 0x06, 0x9c, 0x2f, 0x2d, 0x3c, 0xc3, 0x30, 0xe1, 0xeb, 0xfb, 0xce, 0xf6, 0x6a,
        0x85, 0xed, 0xd3, 0xe6, 0xc1, 0xf7, 0xf6, 0x73, 0x08, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
        0x3c, 0x00, 0x09, 0x80, 0x1c, 0x00, 0x00, 0x80, 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
        0x08, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x00, 0x05, 0x05, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00,
        0x1c, 0x00, 0x01, 0x80, 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00,
        //          ^^^^ array index corrected manually (0x00 -> 0x01)
        //               as `wg` doesn't correctly increment it
        0x0a, 0x00, 0x00, 0x06, 0x05, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00,
    ];

    dump_hex(payload);

    let req = OpSetDeviceDo::decode_request(payload);

    // We should be binary compatible too
    assert_eq!(req.get_ifname(), Ok(c"wg0"));
    let mut peers = req.get_peers().unwrap();
    let peer = peers.next().unwrap();
    assert_eq!(peer.get_public_key(), Ok(&PUB_KEY[..]));
    assert_eq!(peer.get_flags(), Ok(WgpeerFlags::ReplaceAllowedips as u32));
    let mut ips = peer.get_allowedips().unwrap();

    let ip = ips.next().unwrap();
    assert_eq!(ip.get_family(), Ok(2));
    assert_eq!(ip.get_ipaddr(), Ok("10.0.0.5".parse().unwrap()));
    assert_eq!(ip.get_cidr_mask(), Ok(32));

    let ip = ips.next().unwrap();
    assert_eq!(ip.get_family(), Ok(2));
    assert_eq!(ip.get_ipaddr(), Ok("10.0.0.6".parse().unwrap()));
    assert_eq!(ip.get_cidr_mask(), Ok(32));

    assert!(ips.next().is_none());

    assert!(peers.next().is_none());

    let mut vec = Vec::new();
    OpSetDeviceDo::encode_request(&mut vec)
        .push_ifname(c"wg0")
        .array_peers()
        .entry_nested()
        .push_public_key(&PUB_KEY[..])
        .push_flags(WgpeerFlags::ReplaceAllowedips as u32)
        .array_allowedips()
        .entry_nested()
        .push_family(2)
        .push_ipaddr("10.0.0.5".parse().unwrap())
        .push_cidr_mask(32)
        .end_nested()
        .entry_nested()
        .push_family(2)
        .push_ipaddr("10.0.0.6".parse().unwrap())
        .push_cidr_mask(32)
        .end_nested();

    dump_assert_eq(&payload[..], &vec[..])
}

#[test]
fn wg0_set_allowed_addr() {
    #[cfg_attr(any(), rustfmt::skip)]
        let payload = &[
            // 0x70, 0x00, 0x00, 0x00, 0x26, 0x00, 0x05, 0x00, 0x99, 0x34, 0xc8, 0x68, 0x00, 0x00, 0x00, 0x00,
            0x01, 0x01, 0x00, 0x00, 0x08, 0x00, 0x02, 0x00, 0x77, 0x67, 0x30, 0x00, 0x54, 0x00, 0x08, 0x80,
            0x50, 0x00, 0x00, 0x80, 0x24, 0x00, 0x01, 0x00, 0x8d, 0x9d, 0x60, 0x90, 0x6b, 0xfd, 0xa7, 0x7e,
            0x4e, 0x4d, 0x3a, 0x06, 0x9c, 0x2f, 0x2d, 0x3c, 0xc3, 0x30, 0xe1, 0xeb, 0xfb, 0xce, 0xf6, 0x6a,
            0x85, 0xed, 0xd3, 0xe6, 0xc1, 0xf7, 0xf6, 0x73, 0x08, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
            0x20, 0x00, 0x09, 0x80, 0x1c, 0x00, 0x00, 0x80, 0x06, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00,
            0x08, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x00, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00,
        ];

    dump_hex(payload);
}