aboutsummaryrefslogtreecommitdiff
path: root/src/util.rs
blob: cd595dd06d47a9c1beeff1db61a66500f5d1b0a0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
use crate::{Error, Result};

use std::ffi::{c_char, c_int};
use std::io;
use std::net::{IpAddr, Ipv4Addr};

use dhcproto::v4::DhcpOption;
use rsdsl_netlinklib::blocking::Connection;

/// Helper macro to execute a system call that returns an `io::Result`.
macro_rules! syscall {
    ($fn: ident ( $($arg: expr),* $(,)* ) ) => {{
        #[allow(unused_unsafe)]
        let res = unsafe { libc::$fn($($arg, )*) };
        if res == -1 {
            Err(io::Error::last_os_error())
        } else {
            Ok(res)
        }
    }};
}

pub fn gen_client_id(hwaddr: &[u8]) -> DhcpOption {
    let mut client_id = vec![0x01];
    client_id.extend_from_slice(hwaddr);

    DhcpOption::ClientIdentifier(client_id)
}

pub fn format_client_id(client_id: &[u8]) -> String {
    client_id
        .iter()
        .map(|octet| format!("{:02x}", octet))
        .reduce(|acc, octet| acc + ":" + &octet)
        .unwrap_or(String::new())
}

pub fn local_ip(conn: &Connection, link: String) -> Result<Ipv4Addr> {
    conn.address_get(link.clone())?
        .into_iter()
        .filter_map(|addr| {
            if let IpAddr::V4(v4) = addr {
                Some(v4)
            } else {
                None
            }
        })
        .next()
        .ok_or(Error::NoIpv4Addr(link))
}

#[allow(clippy::missing_safety_doc)]
pub unsafe fn setsockopt(
    fd: c_int,
    opt: c_int,
    val: c_int,
    payload: *const c_char,
    optlen: c_int,
) -> io::Result<()> {
    syscall!(setsockopt(
        fd,
        opt,
        val,
        payload.cast(),
        optlen as libc::socklen_t
    ))
    .map(|_| ())
}