1 module snmp.v3; 2 3 import c.net_snmp; 4 import snmp.types; 5 import snmp.oid; 6 7 private alias size_t = object.size_t; 8 import snmp.session : SNMPSession; 9 import snmp.pdu : SNMPResponse; 10 11 enum AuthProtocol { none, md5, sha1, sha256, sha384, sha512 } 12 enum PrivProtocol { none, des, aes128, aes192, aes256 } 13 14 enum SecurityLevel : int 15 { 16 noAuthNoPriv = SNMP_SEC_LEVEL_NOAUTH, 17 authNoPriv = SNMP_SEC_LEVEL_AUTHNOPRIV, 18 authPriv = SNMP_SEC_LEVEL_AUTHPRIV, 19 } 20 21 private void authProtoOID(AuthProtocol p, out const(oid)* optr, out size_t olen) @trusted @nogc nothrow 22 { 23 final switch (p) 24 { 25 case AuthProtocol.none: 26 optr = usmNoAuthProtocol.ptr; olen = usmNoAuthProtocol.length; break; 27 case AuthProtocol.md5: 28 optr = usmHMACMD5AuthProtocol.ptr; olen = usmHMACMD5AuthProtocol.length; break; 29 case AuthProtocol.sha1: 30 optr = usmHMACSHA1AuthProtocol.ptr; olen = usmHMACSHA1AuthProtocol.length; break; 31 case AuthProtocol.sha256: 32 optr = usmHMAC192SHA256AuthProtocol.ptr; olen = usmHMAC192SHA256AuthProtocol.length; break; 33 case AuthProtocol.sha384: 34 optr = usmHMAC384SHA512AuthProtocol.ptr; olen = usmHMAC384SHA512AuthProtocol.length; break; 35 case AuthProtocol.sha512: 36 optr = usmHMAC384SHA512AuthProtocol.ptr; olen = usmHMAC384SHA512AuthProtocol.length; break; 37 } 38 } 39 40 private void privProtoOID(PrivProtocol p, out const(oid)* optr, out size_t olen) @trusted @nogc nothrow 41 { 42 final switch (p) 43 { 44 case PrivProtocol.none: 45 optr = usmNoPrivProtocol.ptr; olen = usmNoPrivProtocol.length; break; 46 case PrivProtocol.des: 47 optr = usmDESPrivProtocol.ptr; olen = usmDESPrivProtocol.length; break; 48 case PrivProtocol.aes128: 49 optr = usmAESPrivProtocol.ptr; olen = usmAESPrivProtocol.length; break; 50 case PrivProtocol.aes192: 51 version (OSX) { optr = usmAESPrivProtocol.ptr; olen = usmAESPrivProtocol.length; } 52 else { optr = usmAES192PrivProtocol.ptr; olen = usmAES192PrivProtocol.length; } 53 break; 54 case PrivProtocol.aes256: 55 version (OSX) { optr = usmAESPrivProtocol.ptr; olen = usmAESPrivProtocol.length; } 56 else { optr = usmAES256PrivProtocol.ptr; olen = usmAES256PrivProtocol.length; } 57 break; 58 } 59 } 60 61 /// SNMPv3/USM session. RAII via SNMPSession base destructor. 62 struct SNMPV3Session 63 { 64 SNMPSession base; 65 alias base this; 66 67 @disable this(this); 68 69 static SNMPV3Session open( 70 scope const(char)* peername, 71 scope const(char)* user, 72 AuthProtocol auth = AuthProtocol.sha1, 73 scope const(char)* authPass = null, 74 PrivProtocol priv = PrivProtocol.none, 75 scope const(char)* privPass = null, 76 SecurityLevel level = SecurityLevel.authNoPriv) @trusted @nogc nothrow 77 { 78 SNMPV3Session s; 79 80 if (!peername || !user || !authPass) 81 return s; 82 83 import core.stdc.string : strlen; 84 85 netsnmp_session sess; 86 snmp_sess_init(&sess); 87 88 // `version` is a D keyword — access via __traits 89 __traits(getMember, sess, "version") = cast(long) SNMP_VERSION_3; 90 sess.peername = cast(char*) peername; 91 sess.securityName = cast(char*) user; 92 sess.securityNameLen = strlen(user); 93 sess.securityLevel = cast(int) level; 94 95 const(oid)* authOIDPtr; 96 size_t authOIDLen; 97 authProtoOID(auth, authOIDPtr, authOIDLen); 98 sess.securityAuthProto = cast(oid*) authOIDPtr; 99 sess.securityAuthProtoLen = authOIDLen; 100 sess.securityAuthKeyLen = USM_AUTH_KU_LEN; 101 102 if (auth != AuthProtocol.none && authPass) 103 { 104 if (generate_Ku(sess.securityAuthProto, 105 cast(uint) sess.securityAuthProtoLen, 106 cast(ubyte*) authPass, strlen(authPass), 107 sess.securityAuthKey.ptr, 108 &sess.securityAuthKeyLen) != SNMPERR_SUCCESS) 109 return s; 110 } 111 112 const(oid)* privOIDPtr; 113 size_t privOIDLen; 114 privProtoOID(priv, privOIDPtr, privOIDLen); 115 sess.securityPrivProto = cast(oid*) privOIDPtr; 116 sess.securityPrivProtoLen = privOIDLen; 117 sess.securityPrivKeyLen = USM_PRIV_KU_LEN; 118 119 if (priv != PrivProtocol.none && privPass) 120 { 121 if (generate_Ku(sess.securityAuthProto, 122 cast(uint) sess.securityAuthProtoLen, 123 cast(ubyte*) privPass, strlen(privPass), 124 sess.securityPrivKey.ptr, 125 &sess.securityPrivKeyLen) != SNMPERR_SUCCESS) 126 return s; 127 } 128 129 s.base.handle = snmp_open(&sess); 130 return s; 131 } 132 133 static SNMPV3Session open( 134 string peername, 135 string user, 136 AuthProtocol auth = AuthProtocol.sha1, 137 string authPass = null, 138 PrivProtocol priv = PrivProtocol.none, 139 string privPass = null, 140 SecurityLevel level = SecurityLevel.authNoPriv) @trusted nothrow 141 { 142 import std.string : toStringz; 143 144 return open(peername.toStringz, user.toStringz, auth, 145 authPass ? authPass.toStringz : null, priv, 146 privPass ? privPass.toStringz : null, level); 147 } 148 } 149 150 unittest 151 { 152 init_snmp("snmp-d-v3-test"); 153 154 auto s = SNMPV3Session.open( 155 cast(const(char)*) null, "noUser", 156 AuthProtocol.sha1, "badPass", 157 PrivProtocol.none, cast(const(char)*) null, 158 SecurityLevel.authNoPriv); 159 assert(!s.isOpen); 160 161 auto s2 = SNMPV3Session.open( 162 "udp:127.0.0.1:161", "noUser", 163 AuthProtocol.sha1, "short", 164 PrivProtocol.none, cast(const(char)*) null, 165 SecurityLevel.authNoPriv); 166 s2.close(); 167 }