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
// Copyright (C) 2018 - Will Glozer. All rights reserved.

use std::convert::TryFrom;
use std::net::IpAddr;
use crate::Message;
use crate::api::IFA;
use crate::err::Invalid;
use crate::ffi::{AF_INET, AF_INET6, ifaddrmsg};

#[derive(Debug)]
pub struct Addr {
    pub index:  u32,
    pub label:  String,
    pub flags:  u8,
    pub prefix: u8,
    pub scope:  u8,
    pub addr:   IpAddr,
}

pub fn addr(msg: &Message<ifaddrmsg>) -> Result<Addr, Invalid> {
    let mut addr = Addr {
        index:  msg.ifa_index,
        label:  String::new(),
        flags:  msg.ifa_flags,
        prefix: msg.ifa_prefixlen,
        scope:  msg.ifa_scope,
        addr:   IpAddr::V4(0.into()),
    };

    let ip = |octets| ip(msg.ifa_family, octets);

    for attr in msg.attrs() {
        match attr? {
            IFA::Label(label)    => addr.label = label.to_string(),
            IFA::Address(octets) => addr.addr  = ip(octets)?,
            _                    => (),
        }
    }

    Ok(addr)
}

pub fn ip(family: u8, octets: &[u8]) -> Result<IpAddr, Invalid> {
    Ok(match family {
        AF_INET  => IpAddr::from(<[u8;  4]>::try_from(octets)?),
        AF_INET6 => IpAddr::from(<[u8; 16]>::try_from(octets)?),
        family   => return Err(Invalid::Family(family)),
    })
}