/* SNMP management daemon for the Discworld Mudlib. Technically this daemon responds with v1 as it's protocol. However it does not support the full MIB-II spec mainly because a lot of it is not relevant to the information I wanted to advertise. Everything is advertised via the system entity in MIB-II using the identifiers 101 and up. OID 100 is there as a dummy, it returns 0 and is for mrtg which requires 2 mibs to graph. So, for example, number of players on is numPlayers or 1.3.6.1.2.1.1.101 */ #include "socket.h" #include "socket_errors.h" #include "snmp.h" int s; class SnmpMessage { int version; string community; string SourceAddress; int RequestType; int *PacketID; int ErrorStatus; int ErrorIndex; buffer *ObjectData; } void WriteBuffer(string what, buffer tbuf) { string tstr; int ti; tstr=""; for(ti=0;ti<sizeof(tbuf);ti++) { tstr+=sprintf("%X ", tbuf[ti]); } tell_creator("sojan", "Buffer %s: %s\n", what, tstr); } void create() { int tmp; s=socket_create(DATAGRAM_BINARY, "ReceiveData"); tmp=socket_bind(s, LISTEN_PORT); } void SendReply(class SnmpMessage Reply) { buffer ReplyBuf, RealReplyBuf, tmpbuf; int i,j,k,l,m; ReplyBuf=allocate_buffer(500); ReplyBuf[0]=SEQUENCE; ReplyBuf[1]=0; ReplyBuf[2]=INTEGER; ReplyBuf[3]=1; ReplyBuf[4]=Reply->version; ReplyBuf[5]=OCTET_STRING; ReplyBuf[6]=sizeof(Reply->community); i=write_buffer(ReplyBuf, 7, Reply->community); i=sizeof(Reply->community)+7; ReplyBuf[i]=Reply->RequestType; ReplyBuf[i+1]=0; ReplyBuf[i+2]=2; ReplyBuf[i+3]=sizeof(Reply->PacketID); k=i+4; for(j=0;j<sizeof(Reply->PacketID);j++) { ReplyBuf[k]=Reply->PacketID[j]; k++; } ReplyBuf[k]=2; ReplyBuf[k+1]=1; ReplyBuf[k+2]=0; ReplyBuf[k+3]=2; ReplyBuf[k+4]=1; ReplyBuf[k+5]=0; ReplyBuf[k+6]=SEQUENCE; ReplyBuf[k+7]=0; l=k+8; for(j=0;j<sizeof(Reply->ObjectData);j++) { m=write_buffer(ReplyBuf, l, Reply->ObjectData[j]); l=l+sizeof(Reply->ObjectData[j]); } ReplyBuf[1]=l-2; ReplyBuf[k+7]=l-(k+8); RealReplyBuf=allocate_buffer(l); RealReplyBuf=ReplyBuf[0..l-1]; RealReplyBuf[i+1]=sizeof(RealReplyBuf)-i-2; socket_write(s, RealReplyBuf, Reply->SourceAddress); return; } void ParseObjects(class SnmpMessage CurrentMessage) { int i,j; class SnmpMessage MyReply; buffer mibdata; MyReply=new( class SnmpMessage, version:CurrentMessage->version, community:CurrentMessage->community, RequestType:GETRESPONSEPDU, SourceAddress:CurrentMessage->SourceAddress, PacketID:CurrentMessage->PacketID, ErrorStatus:0, ErrorIndex:0, ObjectData:({}) ); for(i=0;i<sizeof(CurrentMessage->ObjectData);i++) { j=CurrentMessage->ObjectData[i][1]; mibdata=SNMPHANDLER->GetData(CurrentMessage->ObjectData[i][2..j+1]); if(mibdata[0]==SEQUENCE) MyReply->ObjectData+=({mibdata,}); } SendReply(MyReply); return; } void ReceiveData(int fd, buffer message, string address) { int i,j,k,ss,is,id,es,ei; class SnmpMessage NewMessage; id=0; es=0; ei=0; is=0; ss=0; NewMessage=new( class SnmpMessage, version:message[4], community:read_buffer(message, 7, message[6]), RequestType:message[message[6]+7], SourceAddress:address, PacketID:({}), ErrorStatus:0, ErrorIndex:0, ObjectData:({}) ); for(i=message[6]+9;i<message[1]+2;i++) { switch(message[i]) { case INTEGER : switch(is) { case ID : i++; k=i; is++; for(j=0;j<message[k];j++) { i++; NewMessage->PacketID+=({message[i],}); } break; case ES : i++; i++; is++; NewMessage->ErrorStatus=message[i]; break; case EI : i++; i++; is++; NewMessage->ErrorIndex=message[i]; break; } break; case SEQUENCE : if(!ss) { ss++; i++; break; } i++; j=message[i]; i++; NewMessage->ObjectData+=({message[i..(i+j-1)],}); break; } } ParseObjects(NewMessage); return; }