|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inherit "global_variables"; |
inherit Roxen; |
#define roxen roxenp() |
|
|
|
|
|
#define NO_THREADS 1 |
|
|
#ifdef SNMPAGENT_DEBUG |
# define SNMPAGENT_MSG(X) report_notice("SNMPagent: "+X+"\n") |
# define SNMPAGENT_MSGS(X, Y) report_notice("SNMPagent: "+X+"\n", @Y) |
#else |
# define SNMPAGENT_MSG(X) |
# define SNMPAGENT_MSGS(X, Y) |
#endif |
|
#define SNMP_OP_GETREQUEST 0 |
#define SNMP_OP_GETNEXT 1 |
#define SNMP_OP_GETRESPONSE 2 |
#define SNMP_OP_SETREQUEST 3 |
#define SNMP_OP_TRAP 4 |
|
#define RISMIB_BASE "1.3.6.1.4.1.8614" |
#define RISMIB_BASE_WEBSERVER RISMIB_BASE+".1.1" |
|
#define RET_NEXTOID(oidnext) if(op == SNMP_OP_GETNEXT) rdata += ([attrname:({"oid", oidnext+".0"})]) |
|
#define RET_VALUE(arr) rdata[attrname] += arr |
#define LOG_EVENT(txt, pkt) log_event(txt, pkt) |
|
|
|
string get_description() { return("Roxen Webserver SNMP agent v"+("$Revision: 1.4 $"/" ")[1]+" (devel. rel.)"); } |
|
|
string get_sysoid() { return RISMIB_BASE_WEBSERVER; } |
|
|
int get_uptime() { return ((time(1) - roxen->start_time)*100); } |
|
|
string get_syscontact() { return query("snmp_syscontact"); } |
|
|
string get_sysname() { return query("snmp_sysname"); } |
|
|
string get_syslocation() { return query("snmp_syslocation"); } |
|
|
int get_sysservices() { return query("snmp_sysservices"); } |
|
|
|
class SNMPagent { |
private int enabled; |
|
|
private object fd; |
private int inited; |
private int snmpinpkts; |
private int snmpoutpkts; |
private int snmpbadver; |
private int snmpbadcommnames; |
private int snmpbadcommuses; |
private int snmpenaauth; |
private mapping events; |
private mixed co; |
private object th; |
private static SNMPmib mib; |
|
int get_null() { return 0; } |
|
|
int get_snmpinpkts() { return(snmpinpkts); }; |
int get_snmpoutpkts() { return(snmpoutpkts); }; |
int get_snmpbadver() { return(snmpbadver); }; |
int get_snmpbadcommnames() { return(snmpbadcommnames); }; |
int get_snmpbadcommuses() { return(snmpbadcommuses); }; |
int get_snmpenaauth() { return(snmpenaauth); }; |
|
class SNMPmib { |
#define MIBTREE_BASE "1.3.6.1" |
|
private mapping(string:array) mibtable; |
|
public string|int oid_strip (string oid) { |
|
|
array arr = oid / "."; |
if (sizeof(arr) < 7) |
return 0; |
oid = arr[4..] * "."; |
return oid; |
} |
|
private int|string oid_check(string oid) { |
|
if(!(oid = oid_strip(oid))) return 0; |
return zero_type(mibtable[oid]) ? 0 : oid; |
} |
|
int register(string oid, array data) { |
|
if(!(oid = oid_strip(oid))) return -1; |
if(oid_check(oid)) |
return 0; |
mibtable += ([oid: data]); |
return 1; |
} |
|
void create(string|void filename) { |
|
mibtable = ([ |
|
"2.1.1": ({ 0, get_null, "2.1.1.1.0"}), |
|
"2.1.1.1.0": ({ "str", |
get_description, |
"2.1.1.2.0"}), |
|
"2.1.1.2.0": |
({ "oid", get_sysoid, "2.1.1.3.0" }), |
|
"2.1.1.3.0": |
({ "tick", get_uptime, "2.1.1.4.0" }), |
|
"2.1.1.4.0": |
({ "str", get_syscontact, "2.1.1.5.0" }), |
|
"2.1.1.5.0": |
({ "str", get_sysname, "2.1.1.6.0" }), |
|
"2.1.1.6.0": |
({ "str", get_syslocation, "2.1.1.7.0" }), |
|
"2.1.1.7.0": |
({ "int", get_sysservices, 0 }), |
|
|
"2.1.11": |
({ 0, get_null, "2.1.11.1.0" }), |
|
"2.1.11.1.0": |
({ "count", get_snmpinpkts, "2.1.11.2.0" }), |
|
"2.1.11.2.0": |
({ "count", get_snmpoutpkts, "2.1.11.3.0" }), |
|
"2.1.11.3.0": |
({ "count", get_snmpbadver, "2.1.11.4.0" }), |
|
"2.1.11.4.0": |
({ "count", get_snmpbadcommnames, "2.1.11.5.0" }), |
|
"2.1.11.5.0": |
({ "count", get_null, "2.1.11.6.0" }), |
|
"2.1.11.6.0": |
({ "count", get_null, "2.1.11.8.0" }), |
|
|
"2.1.11.8.0": |
({ "count", get_null, "2.1.11.9.0" }), |
|
"2.1.11.9.0": |
({ "count", get_null, "2.1.11.10.0" }), |
|
"2.1.11.10.0": |
({ "count", get_null, "2.1.11.11.0" }), |
|
"2.1.11.11.0": |
({ "count", get_null, "2.1.11.12.0" }), |
|
"2.1.11.12.0": |
({ "count", get_null, "2.1.11.13.0" }), |
|
"2.1.11.13.0": |
({ "count", get_null, "2.1.11.14.0" }), |
|
"2.1.11.14.0": |
({ "count", get_null, "2.1.11.15.0" }), |
|
"2.1.11.15.0": |
({ "count", get_null, "2.1.11.16.0" }), |
|
"2.1.11.16.0": |
({ "count", get_null, "2.1.11.17.0" }), |
|
"2.1.11.17.0": |
({ "count", get_null, "2.1.11.18.0" }), |
|
"2.1.11.18.0": |
({ "count", get_null, "2.1.11.19.0" }), |
|
"2.1.11.19.0": |
({ "count", get_null, "2.1.11.20.0" }), |
|
"2.1.11.20.0": |
({ "count", get_null, "2.1.11.21.0" }), |
|
"2.1.11.21.0": |
({ "count", get_null, "2.1.11.22.0" }), |
|
"2.1.11.22.0": |
({ "count", get_null, "2.1.11.24.0" }), |
|
|
"2.1.11.24.0": |
({ "count", get_null, "2.1.11.25.0" }), |
|
"2.1.11.25.0": |
({ "count", get_null, "2.1.11.26.0" }), |
|
"2.1.11.26.0": |
({ "count", get_null, "2.1.11.27.0" }), |
|
"2.1.11.27.0": |
({ "count", get_null, "2.1.11.28.0" }), |
|
"2.1.11.28.0": |
({ "count", get_null, "2.1.11.29.0" }), |
|
"2.1.11.29.0": |
({ "count", get_null, "2.1.11.30.0" }), |
|
"2.1.11.30.0": |
({ "int", get_snmpenaauth, 0 }), |
|
|
"4.1.8614.1.1": |
({ 0, get_null, "4.1.8614.1.1.999.0" }), |
|
"4.1.8614.1.1.999.0": |
({ 0, get_null, 0 }) |
|
]); |
|
#if 0 |
|
if (stringp(filename)) { |
|
} |
#endif |
|
} |
|
array `[](string oid) { |
|
if (!oid_check(oid)) { |
return 0; |
} |
oid = oid_strip(oid); |
return (({mibtable[oid][0], mibtable[oid][1](), mibtable[oid][2]})); |
} |
|
string|int oid_guess_next(string oid) { |
|
|
|
if(oid_check(oid+".0")) |
return oid+".1"; |
return 0; |
} |
|
} |
|
void create() { |
|
} |
|
int enable() { |
|
|
mib = SNMPmib(); |
if (!status()) |
start(); |
enabled = 1; |
return (enabled); |
} |
|
int disable() { |
|
if(status()) |
stop(); |
enabled = 0; |
return (!enabled); |
} |
|
int status() { |
return enabled; |
} |
|
private void log_event(string txt, mapping pkt) { |
|
SNMPAGENT_MSG(sprintf("event: %O", txt)); |
if(zero_type(events[txt])) |
events[txt] += ([ pkt->ip : ([ pkt->community: 1]) ]) ; |
else if(zero_type(events[txt][pkt->ip])) |
events[txt][pkt->ip] += ([ pkt->community: 1]); |
else |
events[txt][pkt->ip][pkt->community]++; |
} |
|
private int chk_access(string level , mapping pkt) { |
|
|
return |
(search(query("snmp_community"), pkt->community+":"+level) > -1) || |
(search(query("snmp_community"), pkt->community+":"+"rw") > -1); |
} |
|
|
private void process_query(mapping data) { |
|
|
mapping pdata, rdata = ([]); |
int msgid, op, errnum = 0, setflg = 0; |
string attrname, comm; |
array val; |
|
snmpinpkts++; |
pdata = fd->decode_asn1_msg(data); |
|
SNMPAGENT_MSG(sprintf("Got parsed: %O", pdata)); |
|
if(!mappingp(pdata)) { |
SNMPAGENT_MSG("SNMP message can not be decoded. Silently ommited."); |
return; |
} |
|
msgid = indices(pdata)[0]; |
comm = pdata[msgid]->community || ""; |
op = pdata[msgid]->op; |
|
|
if(!chk_access("ro", pdata[msgid])) { |
snmpbadcommnames++; |
errnum = 5 ; |
attrname = indices(pdata[msgid]->attribute[0])[0]; |
LOG_EVENT("Bad community name", pdata[msgid]); |
} else |
foreach(pdata[msgid]->attribute, mapping attrs) { |
mixed attrval = values(attrs)[0]; |
attrname = indices(attrs)[0]; |
|
if(!mib) |
SNMPAGENT_MSG(" MIB table isn't loaded!\n"); |
val = mib[attrname]; |
if (!val && op == SNMP_OP_GETNEXT) { |
val = mib[attrname+".0"]; |
if(arrayp(val)) |
val[2] = mib->oid_strip(attrname)+".0"; |
} |
if (val) |
switch(op) { |
|
case SNMP_OP_GETREQUEST: |
if (val[0]) |
rdata[attrname] += val[0..1]; |
break; |
|
case SNMP_OP_GETNEXT: |
if (val[2]) { |
string noid = MIBTREE_BASE+"."+val[2]; |
val = mib[noid]; |
if (val && val[0]) |
rdata[noid] += val[0..1]; |
} |
break; |
|
case SNMP_OP_SETREQUEST: |
|
switch (attrname) { |
case RISMIB_BASE_WEBSERVER+".1.0": |
|
|
if(chk_access("rw", pdata[msgid])) { |
setflg = 1; |
rdata[attrname] += ({ "int", attrval }); |
rdata["1.3.6.1.2.1.1.3.0"] += ({"tick", get_uptime() }); |
if(attrval == 1 || attrval == 2) { |
report_warning("SNMPagent: Initiated " + ((attrval==1)?"restart":"shutdown") + " from snmp://" + pdata[msgid]->community + "@" + pdata[msgid]->ip + "/\n"); |
if (attrval == 1) roxen->restart(0.5); |
if (attrval == 2) roxen->shutdown(0.5); |
} |
} else |
snmpbadcommuses++; |
break; |
case MIBTREE_BASE+".2.1.11.30.0": |
|
if(chk_access("rw", pdata[msgid])) { |
setflg = 1; |
rdata[attrname] += ({ "int", attrval }); |
rdata["1.3.6.1.2.1.1.3.0"] += ({"tick", get_uptime() }); |
if(attrval == 0 || attrval == 1) { |
report_warning("SNMPagent: Requested " + attrval?"en":"dis" + "abling of auth. traps from snmp://" + pdata[msgid]->community + "@" + pdata[msgid]->ip + "/\n"); |
|
} |
} else |
snmpbadcommuses++; |
break; |
|
} |
break; |
} |
else |
SNMPAGENT_MSG(sprintf(" unknown or unsupported OID: %O:%O", attrname, attrval)); |
|
|
|
|
|
|
|
|
|
|
} |
|
if(op == SNMP_OP_SETREQUEST && !setflg && !errnum) { |
LOG_EVENT("Set not allowed", pdata[msgid]); |
} |
|
|
snmpoutpkts++; |
if(!sizeof(rdata)) { |
if (!errnum) LOG_EVENT("No such name", pdata[msgid]); |
fd->get_response(([attrname:({"oid", attrname})]), pdata, errnum || 2 ); |
} else |
fd->get_response(rdata, pdata); |
} |
|
private void real_start() { |
|
|
mixed err; |
mapping data; |
array hp = query("snmp_hostport")/":"; |
int p = (sizeof(hp)>1) ? (int)hp[1] : 161; |
|
|
fd = Protocols.SNMP.protocol(0, hp[0], p||161); |
if(arrayp(err)) |
RXML.run_error("SNMPagent: can't open UDP port " + hp[0]+":"+(string)(p||161)+"[" + err[0] + "]."); |
SNMPAGENT_MSG(sprintf("SNMP UDP port %s:%d binded successfully.", hp[0], p||161)); |
|
#ifdef COLDSTART_TRAP // Not working, yet |
|
if (sizeof(query("snmp_traphost"))) { |
mapping rdata; |
rdata = ([attrname:({"oid", "1.3.6.1.4.1.0.1.1"})]); |
rdata += ([attrname:({"ipaddr", "127.0.0.1" }) ]); |
rdata += ([attrname:({"int", 1 }) ]); |
rdata += ([attrname:({"int", 0 }) ]); |
rdata += ([attrname:({"tick", (time(1) - roxen->start_time)*1000 }) ]); |
} |
#endif |
|
enabled = 1; |
#if NO_THREADS |
|
fd->set_nonblocking(process_query); |
#else |
|
|
while(enabled) |
if(!arrayp(err=catch(data=fd->read()))) |
process_query(data); |
#endif |
|
} |
|
private void start() { |
|
events = ([]); |
if(!inited) { |
inited++; |
SNMPAGENT_MSG("Initializing..."); |
|
|
#if NO_THREADS |
|
co = call_out( real_start, 1 ); |
#else |
|
th = thread_create( real_start ); |
#endif |
} |
} |
|
void stop() { |
|
SNMPAGENT_MSG("Shutting down..."); |
fd->set_read_callback(0); |
catch(fd->set_blocking()); |
catch(fd->close()); |
#if NO_THREADS |
remove_call_out(co); |
#else |
th = 0; |
#endif |
destruct(fd); |
fd = 0; |
inited = 0; |
SNMPAGENT_MSG("Shutdown complete."); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int add_virtserv(int vs) { |
report_debug(sprintf("snmpagent:DEB: add: %O->%O\n",vs,roxen->configurations[vs]->name)); |
|
return(1); |
} |
|
int del_virtserv(int vs) { |
report_debug(sprintf("snmpagent:DEB: del: %O->%O\n",vs,roxen->configurations[vs]->name)); |
|
return(1); |
} |
|
} |
|
SNMPagent snmpagent; |
|
|
|