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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
mod client;
mod format_var_bind;
mod msg_factory;
mod params;
mod request;
mod session;

use client::Client;
use failure::Error;
pub use params::{Command, Params};
use session::{Session, Step};
use snmp_mp::PduType;
use snmp_usm::{
    Aes128PrivKey, AuthKey, DesPrivKey, Digest, LocalizedKey, Md5, PrivKey, Sha1, WithLocalizedKey,
};

#[macro_use]
extern crate failure;

const SNMP_PORT_NUM: u32 = 161;

macro_rules! execute_request {
    ($digest:ty, $params:expr) => {{
        if Some(Params::AES128_ENCRYPTION) == $params.privacy_protocol.as_deref() {
            let salt = rand::random();
            execute_request::<
                $digest,
                Aes128PrivKey<$digest>,
                <Aes128PrivKey<$digest> as PrivKey>::Salt,
            >($params, salt)
        } else {
            let salt = rand::random();
            execute_request::<$digest, DesPrivKey<$digest>, <DesPrivKey<$digest> as PrivKey>::Salt>(
                $params, salt,
            )
        }
    }};
}

pub fn run(params: Params) -> Result<(), Error> {
    if Some(Params::SHA1_DIGEST) == params.auth_protocol.as_deref() {
        execute_request!(Sha1, params)
    } else {
        execute_request!(Md5, params)
    }
}

fn execute_request<'a, D: 'a, P, S>(params: Params, salt: P::Salt) -> Result<(), Error>
where
    D: Digest,
    P: PrivKey<Salt = S> + WithLocalizedKey<'a, D>,
    S: Step + Copy,
{
    let host = if params.host.find(':').is_none() {
        format!("{}:{}", params.host, SNMP_PORT_NUM)
    } else {
        params.host
    };

    let mut client = Client::new(host)?;
    let mut session = Session::new(&mut client, params.user.as_bytes())?;

    if let Some(auth_passwd) = params.auth {
        let localized_key = LocalizedKey::<D>::new(auth_passwd.as_bytes(), session.engine_id());
        let auth_key = AuthKey::new(localized_key);
        session.set_auth_key(auth_key);

        if let Some(priv_passwd) = params.privacy {
            let localized_key = LocalizedKey::<D>::new(priv_passwd.as_bytes(), session.engine_id());
            let priv_key = P::with_localized_key(localized_key);
            session.set_priv_key_and_salt(priv_key, salt);
        }
    }

    match params.cmd {
        Command::Get { oids } => {
            request::snmp_get(PduType::GetRequest, oids, &mut client, &mut session)?;
        }
        Command::GetNext { oids } => {
            request::snmp_get(PduType::GetRequest, oids, &mut client, &mut session)?;
        }
        Command::Walk { oid } => {
            request::snmp_walk(oid, &mut client, &mut session)?;
        }
    }

    Ok(())
}