source: trunk/Packages/synapse/snmpsend.pas

Last change on this file was 5, checked in by chronos, 12 years ago
  • Added: Required packages.
File size: 34.9 KB
Line 
1{==============================================================================|
2| Project : Ararat Synapse | 003.000.009 |
3|==============================================================================|
4| Content: SNMP client |
5|==============================================================================|
6| Copyright (c)1999-2007, Lukas Gebauer |
7| All rights reserved. |
8| |
9| Redistribution and use in source and binary forms, with or without |
10| modification, are permitted provided that the following conditions are met: |
11| |
12| Redistributions of source code must retain the above copyright notice, this |
13| list of conditions and the following disclaimer. |
14| |
15| Redistributions in binary form must reproduce the above copyright notice, |
16| this list of conditions and the following disclaimer in the documentation |
17| and/or other materials provided with the distribution. |
18| |
19| Neither the name of Lukas Gebauer nor the names of its contributors may |
20| be used to endorse or promote products derived from this software without |
21| specific prior written permission. |
22| |
23| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
24| AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
25| IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
26| ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
27| ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
28| DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
29| SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
30| CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
31| LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
32| OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
33| DAMAGE. |
34|==============================================================================|
35| The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
36| Portions created by Lukas Gebauer are Copyright (c)2000-2007. |
37| All Rights Reserved. |
38|==============================================================================|
39| Contributor(s): |
40| Jean-Fabien Connault (cycocrew@worldnet.fr) |
41|==============================================================================|
42| History: see HISTORY.HTM from distribution package |
43| (Found at URL: http://www.ararat.cz/synapse/) |
44|==============================================================================}
45
46{:@abstract(SNMP client)
47Supports SNMPv1 include traps, SNMPv2c and SNMPv3 include authorization
48 (encryption not yet supported!)
49
50Used RFC: RFC-1157, RFC-1901, RFC-3412, RFC-3414, RFC-3416
51}
52
53{$IFDEF FPC}
54 {$MODE DELPHI}
55{$ENDIF}
56{$Q-}
57{$H+}
58
59unit snmpsend;
60
61interface
62
63uses
64 Classes, SysUtils,
65 blcksock, synautil, asn1util, synaip, synacode;
66
67const
68 cSnmpProtocol = '161';
69 cSnmpTrapProtocol = '162';
70
71 SNMP_V1 = 0;
72 SNMP_V2C = 1;
73 SNMP_V3 = 3;
74
75 //PDU type
76 PDUGetRequest = $A0;
77 PDUGetNextRequest = $A1;
78 PDUGetResponse = $A2;
79 PDUSetRequest = $A3;
80 PDUTrap = $A4; //Obsolete
81 //for SNMPv2
82 PDUGetBulkRequest = $A5;
83 PDUInformRequest = $A6;
84 PDUTrapV2 = $A7;
85 PDUReport = $A8;
86
87 //errors
88 ENoError = 0;
89 ETooBig = 1;
90 ENoSuchName = 2;
91 EBadValue = 3;
92 EReadOnly = 4;
93 EGenErr = 5;
94 //errors SNMPv2
95 ENoAccess = 6;
96 EWrongType = 7;
97 EWrongLength = 8;
98 EWrongEncoding = 9;
99 EWrongValue = 10;
100 ENoCreation = 11;
101 EInconsistentValue = 12;
102 EResourceUnavailable = 13;
103 ECommitFailed = 14;
104 EUndoFailed = 15;
105 EAuthorizationError = 16;
106 ENotWritable = 17;
107 EInconsistentName = 18;
108
109type
110
111 {:@abstract(Possible values for SNMPv3 flags.)
112 This flags specify level of authorization and encryption.}
113 TV3Flags = (
114 NoAuthNoPriv,
115 AuthNoPriv,
116 AuthPriv);
117
118 {:@abstract(Type of SNMPv3 authorization)}
119 TV3Auth = (
120 AuthMD5,
121 AuthSHA1);
122
123 {:@abstract(Data object with one record of MIB OID and corresponding values.)}
124 TSNMPMib = class(TObject)
125 protected
126 FOID: AnsiString;
127 FValue: AnsiString;
128 FValueType: Integer;
129 published
130 {:OID number in string format.}
131 property OID: AnsiString read FOID write FOID;
132
133 {:Value of OID object in string format.}
134 property Value: AnsiString read FValue write FValue;
135
136 {:Define type of Value. Supported values are defined in @link(asn1util).
137 For queries use ASN1_NULL, becouse you don't know type in response!}
138 property ValueType: Integer read FValueType write FValueType;
139 end;
140
141 {:@abstract(It holding all information for SNMPv3 agent synchronization)
142 Used internally.}
143 TV3Sync = record
144 EngineID: AnsiString;
145 EngineBoots: integer;
146 EngineTime: integer;
147 EngineStamp: Cardinal;
148 end;
149
150 {:@abstract(Data object abstracts SNMP data packet)}
151 TSNMPRec = class(TObject)
152 protected
153 FVersion: Integer;
154 FPDUType: Integer;
155 FID: Integer;
156 FErrorStatus: Integer;
157 FErrorIndex: Integer;
158 FCommunity: AnsiString;
159 FSNMPMibList: TList;
160 FMaxSize: Integer;
161 FFlags: TV3Flags;
162 FFlagReportable: Boolean;
163 FContextEngineID: AnsiString;
164 FContextName: AnsiString;
165 FAuthMode: TV3Auth;
166 FAuthEngineID: AnsiString;
167 FAuthEngineBoots: integer;
168 FAuthEngineTime: integer;
169 FAuthEngineTimeStamp: cardinal;
170 FUserName: AnsiString;
171 FPassword: AnsiString;
172 FAuthKey: AnsiString;
173 FPrivKey: AnsiString;
174 FOldTrapEnterprise: AnsiString;
175 FOldTrapHost: AnsiString;
176 FOldTrapGen: Integer;
177 FOldTrapSpec: Integer;
178 FOldTrapTimeTicks: Integer;
179 function Pass2Key(const Value: AnsiString): AnsiString;
180 public
181 constructor Create;
182 destructor Destroy; override;
183
184 {:Decode SNMP packet in buffer to object properties.}
185 function DecodeBuf(const Buffer: AnsiString): Boolean;
186
187 {:Encode obeject properties to SNMP packet.}
188 function EncodeBuf: AnsiString;
189
190 {:Clears all object properties to default values.}
191 procedure Clear;
192
193 {:Add entry to @link(SNMPMibList). For queries use value as empty string,
194 and ValueType as ASN1_NULL.}
195 procedure MIBAdd(const MIB, Value: AnsiString; ValueType: Integer);
196
197 {:Delete entry from @link(SNMPMibList).}
198 procedure MIBDelete(Index: Integer);
199
200 {:Search @link(SNMPMibList) list for MIB and return correspond value.}
201 function MIBGet(const MIB: AnsiString): AnsiString;
202
203 {:return number of entries in MIB array.}
204 function MIBCount: integer;
205
206 {:Return MIB information from given row of MIB array.}
207 function MIBByIndex(Index: Integer): TSNMPMib;
208
209 {:List of @link(TSNMPMib) objects.}
210 property SNMPMibList: TList read FSNMPMibList;
211 published
212 {:Version of SNMP packet. Default value is 0 (SNMP ver. 1). You can use
213 value 1 for SNMPv2c or value 3 for SNMPv3.}
214 property Version: Integer read FVersion write FVersion;
215
216 {:Community string for autorize access to SNMP server. (Case sensitive!)
217 Community string is not used in SNMPv3! Use @link(Username) and
218 @link(password) instead!}
219 property Community: AnsiString read FCommunity write FCommunity;
220
221 {:Define type of SNMP operation.}
222 property PDUType: Integer read FPDUType write FPDUType;
223
224 {:Contains ID number. Not need to use.}
225 property ID: Integer read FID write FID;
226
227 {:When packet is reply, contains error code. Supported values are defined by
228 E* constants.}
229 property ErrorStatus: Integer read FErrorStatus write FErrorStatus;
230
231 {:Point to error position in reply packet. Not usefull for users. It only
232 good for debugging!}
233 property ErrorIndex: Integer read FErrorIndex write FErrorIndex;
234
235 {:special value for GetBulkRequest of SNMPv2 and v3.}
236 property NonRepeaters: Integer read FErrorStatus write FErrorStatus;
237
238 {:special value for GetBulkRequest of SNMPv2 and v3.}
239 property MaxRepetitions: Integer read FErrorIndex write FErrorIndex;
240
241 {:Maximum message size in bytes for SNMPv3. For sending is default 1472 bytes.}
242 property MaxSize: Integer read FMaxSize write FMaxSize;
243
244 {:Specify if message is authorised or encrypted. Used only in SNMPv3, and
245 encryption is not yet supported!}
246 property Flags: TV3Flags read FFlags write FFlags;
247
248 {:For SNMPv3.... If is @true, SNMP agent must send reply (at least with some
249 error).}
250 property FlagReportable: Boolean read FFlagReportable write FFlagReportable;
251
252 {:For SNMPv3. If not specified, is used value from @link(AuthEngineID)}
253 property ContextEngineID: AnsiString read FContextEngineID write FContextEngineID;
254
255 {:For SNMPv3.}
256 property ContextName: AnsiString read FContextName write FContextName;
257
258 {:For SNMPv3. Specify Authorization mode. (specify used hash for
259 authorization)}
260 property AuthMode: TV3Auth read FAuthMode write FAuthMode;
261
262 {:value used by SNMPv3 authorisation for synchronization with SNMP agent.}
263 property AuthEngineID: AnsiString read FAuthEngineID write FAuthEngineID;
264
265 {:value used by SNMPv3 authorisation for synchronization with SNMP agent.}
266 property AuthEngineBoots: Integer read FAuthEngineBoots write FAuthEngineBoots;
267
268 {:value used by SNMPv3 authorisation for synchronization with SNMP agent.}
269 property AuthEngineTime: Integer read FAuthEngineTime write FAuthEngineTime;
270
271 {:value used by SNMPv3 authorisation for synchronization with SNMP agent.}
272 property AuthEngineTimeStamp: Cardinal read FAuthEngineTimeStamp Write FAuthEngineTimeStamp;
273
274 {:SNMPv3 authorization username}
275 property UserName: AnsiString read FUserName write FUserName;
276
277 {:SNMPv3 authorization password}
278 property Password: AnsiString read FPassword write FPassword;
279
280 {:For SNMPv3. Computed Athorization key from @link(password).}
281 property AuthKey: AnsiString read FAuthKey write FAuthKey;
282
283 {:For SNMPv3. Encryption key for message encryption. Not yet used!}
284 property PrivKey: AnsiString read FPrivKey write FPrivKey;
285
286 {:MIB value to identify the object that sent the TRAPv1.}
287 property OldTrapEnterprise: AnsiString read FOldTrapEnterprise write FOldTrapEnterprise;
288
289 {:Address of TRAPv1 sender (IP address).}
290 property OldTrapHost: AnsiString read FOldTrapHost write FOldTrapHost;
291
292 {:Generic TRAPv1 identification.}
293 property OldTrapGen: Integer read FOldTrapGen write FOldTrapGen;
294
295 {:Specific TRAPv1 identification.}
296 property OldTrapSpec: Integer read FOldTrapSpec write FOldTrapSpec;
297
298 {:Number of 1/100th of seconds since last reboot or power up. (for TRAPv1)}
299 property OldTrapTimeTicks: Integer read FOldTrapTimeTicks write FOldTrapTimeTicks;
300 end;
301
302 {:@abstract(Implementation of SNMP protocol.)
303
304 Note: Are you missing properties for specify server address and port? Look to
305 parent @link(TSynaClient) too!}
306 TSNMPSend = class(TSynaClient)
307 protected
308 FSock: TUDPBlockSocket;
309 FBuffer: AnsiString;
310 FHostIP: AnsiString;
311 FQuery: TSNMPRec;
312 FReply: TSNMPRec;
313 function InternalSendSnmp(const Value: TSNMPRec): Boolean;
314 function InternalRecvSnmp(const Value: TSNMPRec): Boolean;
315 function InternalSendRequest(const QValue, RValue: TSNMPRec): Boolean;
316 function GetV3EngineID: AnsiString;
317 function GetV3Sync: TV3Sync;
318 public
319 constructor Create;
320 destructor Destroy; override;
321
322 {:Connects to a Host and send there query. If in timeout SNMP server send
323 back query, result is @true. If is used SNMPv3, then it synchronize self
324 with SNMPv3 agent first. (It is needed for SNMPv3 auhorization!)}
325 function SendRequest: Boolean;
326
327 {:Send SNMP packet only, but not waits for reply. Good for sending traps.}
328 function SendTrap: Boolean;
329
330 {:Receive SNMP packet only. Good for receiving traps.}
331 function RecvTrap: Boolean;
332
333 {:Mapped to @link(SendRequest) internally. This function is only for
334 backward compatibility.}
335 function DoIt: Boolean;
336 published
337 {:contains raw binary form of SNMP packet. Good for debugging.}
338 property Buffer: AnsiString read FBuffer write FBuffer;
339
340 {:After SNMP operation hold IP address of remote side.}
341 property HostIP: AnsiString read FHostIP;
342
343 {:Data object contains SNMP query.}
344 property Query: TSNMPRec read FQuery;
345
346 {:Data object contains SNMP reply.}
347 property Reply: TSNMPRec read FReply;
348
349 {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.}
350 property Sock: TUDPBlockSocket read FSock;
351 end;
352
353{:A very useful function and example of its use would be found in the TSNMPSend
354 object. It implements basic GET method of the SNMP protocol. The MIB value is
355 located in the "OID" variable, and is sent to the requested "SNMPHost" with
356 the proper "Community" access identifier. Upon a successful retrieval, "Value"
357 will contain the information requested. If the SNMP operation is successful,
358 the result returns @true.}
359function SNMPGet(const OID, Community, SNMPHost: AnsiString; var Value: AnsiString): Boolean;
360
361{:This is useful function and example of use TSNMPSend object. It implements
362 the basic SET method of the SNMP protocol. If the SNMP operation is successful,
363 the result is @true. "Value" is value of MIB Oid for "SNMPHost" with "Community"
364 access identifier. You must specify "ValueType" too.}
365function SNMPSet(const OID, Community, SNMPHost, Value: AnsiString; ValueType: Integer): Boolean;
366
367{:A very useful function and example of its use would be found in the TSNMPSend
368 object. It implements basic GETNEXT method of the SNMP protocol. The MIB value
369 is located in the "OID" variable, and is sent to the requested "SNMPHost" with
370 the proper "Community" access identifier. Upon a successful retrieval, "Value"
371 will contain the information requested. If the SNMP operation is successful,
372 the result returns @true.}
373function SNMPGetNext(var OID: AnsiString; const Community, SNMPHost: AnsiString; var Value: AnsiString): Boolean;
374
375{:A very useful function and example of its use would be found in the TSNMPSend
376 object. It implements basic read of SNMP MIB tables. As BaseOID you must
377 specify basic MIB OID of requested table (base IOD is OID without row and
378 column specificator!)
379 Table is readed into stringlist, where each string is comma delimited string.
380
381 Warning: this function is not have best performance. For better performance
382 you must write your own function. best performace you can get by knowledge
383 of structuture of table and by more then one MIB on one query. }
384function SNMPGetTable(const BaseOID, Community, SNMPHost: AnsiString; const Value: TStrings): Boolean;
385
386{:A very useful function and example of its use would be found in the TSNMPSend
387 object. It implements basic read of SNMP MIB table element. As BaseOID you must
388 specify basic MIB OID of requested table (base IOD is OID without row and
389 column specificator!)
390 As next you must specify identificator of row and column for specify of needed
391 field of table.}
392function SNMPGetTableElement(const BaseOID, RowID, ColID, Community, SNMPHost: AnsiString; var Value: AnsiString): Boolean;
393
394{:A very useful function and example of its use would be found in the TSNMPSend
395 object. It implements a TRAPv1 to send with all data in the parameters.}
396function SendTrap(const Dest, Source, Enterprise, Community: AnsiString;
397 Generic, Specific, Seconds: Integer; const MIBName, MIBValue: AnsiString;
398 MIBtype: Integer): Integer;
399
400{:A very useful function and example of its use would be found in the TSNMPSend
401 object. It receives a TRAPv1 and returns all the data that comes with it.}
402function RecvTrap(var Dest, Source, Enterprise, Community: AnsiString;
403 var Generic, Specific, Seconds: Integer; const MIBName,
404 MIBValue: TStringList): Integer;
405
406implementation
407
408{==============================================================================}
409
410constructor TSNMPRec.Create;
411begin
412 inherited Create;
413 FSNMPMibList := TList.Create;
414 Clear;
415 FID := 1;
416 FMaxSize := 1472;
417end;
418
419destructor TSNMPRec.Destroy;
420var
421 i: Integer;
422begin
423 for i := 0 to FSNMPMibList.Count - 1 do
424 TSNMPMib(FSNMPMibList[i]).Free;
425 FSNMPMibList.Clear;
426 FSNMPMibList.Free;
427 inherited Destroy;
428end;
429
430function TSNMPRec.Pass2Key(const Value: AnsiString): AnsiString;
431var
432 key: AnsiString;
433begin
434 case FAuthMode of
435 AuthMD5:
436 begin
437 key := MD5LongHash(Value, 1048576);
438 Result := MD5(key + FAuthEngineID + key);
439 end;
440 AuthSHA1:
441 begin
442 key := SHA1LongHash(Value, 1048576);
443 Result := SHA1(key + FAuthEngineID + key);
444 end;
445 else
446 Result := '';
447 end;
448end;
449
450
451function TSNMPRec.DecodeBuf(const Buffer: AnsiString): Boolean;
452var
453 Pos: Integer;
454 EndPos: Integer;
455 sm, sv: AnsiString;
456 Svt: Integer;
457 s: AnsiString;
458 Spos: integer;
459 x: Byte;
460begin
461 Clear;
462 Result := False;
463 if Length(Buffer) < 2 then
464 Exit;
465 if (Ord(Buffer[1]) and $20) = 0 then
466 Exit;
467 Pos := 2;
468 EndPos := ASNDecLen(Pos, Buffer);
469 if Length(Buffer) < (EndPos + 2) then
470 Exit;
471 Self.FVersion := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0);
472
473 if FVersion = 3 then
474 begin
475 ASNItem(Pos, Buffer, Svt); //header data seq
476 ASNItem(Pos, Buffer, Svt); //ID
477 FMaxSize := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0);
478 s := ASNItem(Pos, Buffer, Svt);
479 x := 0;
480 if s <> '' then
481 x := Ord(s[1]);
482 FFlagReportable := (x and 4) > 0;
483 x := x and 3;
484 case x of
485 1:
486 FFlags := AuthNoPriv;
487 3:
488 FFlags := AuthPriv;
489 else
490 FFlags := NoAuthNoPriv;
491 end;
492
493 x := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0);
494 s := ASNItem(Pos, Buffer, Svt); //SecurityParameters
495 //if SecurityModel is USM, then try to decode SecurityParameters
496 if (x = 3) and (s <> '') then
497 begin
498 spos := 1;
499 ASNItem(SPos, s, Svt);
500 FAuthEngineID := ASNItem(SPos, s, Svt);
501 FAuthEngineBoots := StrToIntDef(ASNItem(SPos, s, Svt), 0);
502 FAuthEngineTime := StrToIntDef(ASNItem(SPos, s, Svt), 0);
503 FAuthEngineTimeStamp := GetTick;
504 FUserName := ASNItem(SPos, s, Svt);
505 FAuthKey := ASNItem(SPos, s, Svt);
506 FPrivKey := ASNItem(SPos, s, Svt);
507 end;
508 //scopedPDU
509 s := ASNItem(Pos, Buffer, Svt);
510 if Svt = ASN1_OCTSTR then
511 begin
512 //decrypt!
513 end;
514 FContextEngineID := ASNItem(Pos, Buffer, Svt);
515 FContextName := ASNItem(Pos, Buffer, Svt);
516 end
517 else
518 begin
519 //old packet
520 Self.FCommunity := ASNItem(Pos, Buffer, Svt);
521 end;
522
523 ASNItem(Pos, Buffer, Svt);
524 Self.FPDUType := Svt;
525 if Self.FPDUType = PDUTrap then
526 begin
527 FOldTrapEnterprise := ASNItem(Pos, Buffer, Svt);
528 FOldTrapHost := ASNItem(Pos, Buffer, Svt);
529 FOldTrapGen := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0);
530 FOldTrapSpec := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0);
531 FOldTrapTimeTicks := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0);
532 end
533 else
534 begin
535 Self.FID := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0);
536 Self.FErrorStatus := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0);
537 Self.FErrorIndex := StrToIntDef(ASNItem(Pos, Buffer, Svt), 0);
538 end;
539 ASNItem(Pos, Buffer, Svt);
540 while Pos < EndPos do
541 begin
542 ASNItem(Pos, Buffer, Svt);
543 Sm := ASNItem(Pos, Buffer, Svt);
544 Sv := ASNItem(Pos, Buffer, Svt);
545 Self.MIBAdd(sm, sv, Svt);
546 end;
547 Result := True;
548end;
549
550function TSNMPRec.EncodeBuf: AnsiString;
551var
552 s: AnsiString;
553 SNMPMib: TSNMPMib;
554 n: Integer;
555 pdu, head, auth, authbeg: AnsiString;
556 x: Byte;
557begin
558 pdu := '';
559 for n := 0 to FSNMPMibList.Count - 1 do
560 begin
561 SNMPMib := TSNMPMib(FSNMPMibList[n]);
562 case SNMPMib.ValueType of
563 ASN1_INT:
564 s := ASNObject(MibToID(SNMPMib.OID), ASN1_OBJID) +
565 ASNObject(ASNEncInt(StrToIntDef(SNMPMib.Value, 0)), SNMPMib.ValueType);
566 ASN1_COUNTER, ASN1_GAUGE, ASN1_TIMETICKS:
567 s := ASNObject(MibToID(SNMPMib.OID), ASN1_OBJID) +
568 ASNObject(ASNEncUInt(StrToIntDef(SNMPMib.Value, 0)), SNMPMib.ValueType);
569 ASN1_OBJID:
570 s := ASNObject(MibToID(SNMPMib.OID), ASN1_OBJID) +
571 ASNObject(MibToID(SNMPMib.Value), SNMPMib.ValueType);
572 ASN1_IPADDR:
573 s := ASNObject(MibToID(SNMPMib.OID), ASN1_OBJID) +
574 ASNObject(IPToID(SNMPMib.Value), SNMPMib.ValueType);
575 ASN1_NULL:
576 s := ASNObject(MibToID(SNMPMib.OID), ASN1_OBJID) +
577 ASNObject('', ASN1_NULL);
578 else
579 s := ASNObject(MibToID(SNMPMib.OID), ASN1_OBJID) +
580 ASNObject(SNMPMib.Value, SNMPMib.ValueType);
581 end;
582 pdu := pdu + ASNObject(s, ASN1_SEQ);
583 end;
584 pdu := ASNObject(pdu, ASN1_SEQ);
585
586 if Self.FPDUType = PDUTrap then
587 pdu := ASNObject(MibToID(FOldTrapEnterprise), ASN1_OBJID) +
588 ASNObject(IPToID(FOldTrapHost), ASN1_IPADDR) +
589 ASNObject(ASNEncInt(FOldTrapGen), ASN1_INT) +
590 ASNObject(ASNEncInt(FOldTrapSpec), ASN1_INT) +
591 ASNObject(ASNEncUInt(FOldTrapTimeTicks), ASN1_TIMETICKS) +
592 pdu
593 else
594 pdu := ASNObject(ASNEncInt(Self.FID), ASN1_INT) +
595 ASNObject(ASNEncInt(Self.FErrorStatus), ASN1_INT) +
596 ASNObject(ASNEncInt(Self.FErrorIndex), ASN1_INT) +
597 pdu;
598 pdu := ASNObject(pdu, Self.FPDUType);
599
600 if FVersion = 3 then
601 begin
602 if FContextEngineID = '' then
603 FContextEngineID := FAuthEngineID;
604 //complete PDUv3...
605 pdu := ASNObject(FContextEngineID, ASN1_OCTSTR)
606 + ASNObject(FContextName, ASN1_OCTSTR)
607 + pdu;
608 //maybe encrypt pdu... in future
609 pdu := ASNObject(pdu, ASN1_SEQ);
610
611 //prepare flags
612 case FFlags of
613 AuthNoPriv:
614 x := 1;
615 AuthPriv:
616 x := 3;
617 else
618 x := 0;
619 end;
620 if FFlagReportable then
621 x := x or 4;
622 head := ASNObject(ASNEncInt(Self.FVersion), ASN1_INT);
623 s := ASNObject(ASNEncInt(FID), ASN1_INT)
624 + ASNObject(ASNEncInt(FMaxSize), ASN1_INT)
625 + ASNObject(AnsiChar(x), ASN1_OCTSTR)
626 //encode security model USM
627 + ASNObject(ASNEncInt(3), ASN1_INT);
628 head := head + ASNObject(s, ASN1_SEQ);
629
630 //compute engine time difference
631 x := TickDelta(FAuthEngineTimeStamp, GetTick) div 1000;
632
633 authbeg := ASNObject(FAuthEngineID, ASN1_OCTSTR)
634 + ASNObject(ASNEncInt(FAuthEngineBoots), ASN1_INT)
635 + ASNObject(ASNEncInt(FAuthEngineTime + x), ASN1_INT)
636 + ASNObject(FUserName, ASN1_OCTSTR);
637
638
639 case FFlags of
640 AuthNoPriv,
641 AuthPriv:
642 begin
643 s := authbeg + ASNObject(StringOfChar(#0, 12), ASN1_OCTSTR)
644 + ASNObject(FPrivKey, ASN1_OCTSTR);
645 s := ASNObject(s, ASN1_SEQ);
646 s := head + ASNObject(s, ASN1_OCTSTR);
647 s := ASNObject(s + pdu, ASN1_SEQ);
648 //in s is entire packet without auth info...
649 case FAuthMode of
650 AuthMD5:
651 begin
652 s := HMAC_MD5(s, Pass2Key(FPassword) + StringOfChar(#0, 48));
653 //strip to HMAC-MD5-96
654 delete(s, 13, 4);
655 end;
656 AuthSHA1:
657 begin
658 s := HMAC_SHA1(s, Pass2Key(FPassword) + StringOfChar(#0, 44));
659 //strip to HMAC-SHA-96
660 delete(s, 13, 8);
661 end;
662 else
663 s := '';
664 end;
665 FAuthKey := s;
666 end;
667 end;
668
669 auth := authbeg + ASNObject(FAuthKey, ASN1_OCTSTR)
670 + ASNObject(FPrivKey, ASN1_OCTSTR);
671 auth := ASNObject(auth, ASN1_SEQ);
672
673 head := head + ASNObject(auth, ASN1_OCTSTR);
674 Result := ASNObject(head + pdu, ASN1_SEQ);
675 end
676 else
677 begin
678 head := ASNObject(ASNEncInt(Self.FVersion), ASN1_INT) +
679 ASNObject(Self.FCommunity, ASN1_OCTSTR);
680 Result := ASNObject(head + pdu, ASN1_SEQ);
681 end;
682 inc(self.FID);
683end;
684
685procedure TSNMPRec.Clear;
686var
687 i: Integer;
688begin
689 FVersion := SNMP_V1;
690 FCommunity := 'public';
691 FUserName := '';
692 FPassword := '';
693 FPDUType := 0;
694 FErrorStatus := 0;
695 FErrorIndex := 0;
696 for i := 0 to FSNMPMibList.Count - 1 do
697 TSNMPMib(FSNMPMibList[i]).Free;
698 FSNMPMibList.Clear;
699 FOldTrapEnterprise := '';
700 FOldTrapHost := '';
701 FOldTrapGen := 0;
702 FOldTrapSpec := 0;
703 FOldTrapTimeTicks := 0;
704 FFlags := NoAuthNoPriv;
705 FFlagReportable := false;
706 FContextEngineID := '';
707 FContextName := '';
708 FAuthMode := AuthMD5;
709 FAuthEngineID := '';
710 FAuthEngineBoots := 0;
711 FAuthEngineTime := 0;
712 FAuthEngineTimeStamp := 0;
713 FAuthKey := '';
714 FPrivKey := '';
715end;
716
717procedure TSNMPRec.MIBAdd(const MIB, Value: AnsiString; ValueType: Integer);
718var
719 SNMPMib: TSNMPMib;
720begin
721 SNMPMib := TSNMPMib.Create;
722 SNMPMib.OID := MIB;
723 SNMPMib.Value := Value;
724 SNMPMib.ValueType := ValueType;
725 FSNMPMibList.Add(SNMPMib);
726end;
727
728procedure TSNMPRec.MIBDelete(Index: Integer);
729begin
730 if (Index >= 0) and (Index < MIBCount) then
731 begin
732 TSNMPMib(FSNMPMibList[Index]).Free;
733 FSNMPMibList.Delete(Index);
734 end;
735end;
736
737function TSNMPRec.MIBCount: integer;
738begin
739 Result := FSNMPMibList.Count;
740end;
741
742function TSNMPRec.MIBByIndex(Index: Integer): TSNMPMib;
743begin
744 Result := nil;
745 if (Index >= 0) and (Index < MIBCount) then
746 Result := TSNMPMib(FSNMPMibList[Index]);
747end;
748
749function TSNMPRec.MIBGet(const MIB: AnsiString): AnsiString;
750var
751 i: Integer;
752begin
753 Result := '';
754 for i := 0 to MIBCount - 1 do
755 begin
756 if ((TSNMPMib(FSNMPMibList[i])).OID = MIB) then
757 begin
758 Result := (TSNMPMib(FSNMPMibList[i])).Value;
759 Break;
760 end;
761 end;
762end;
763
764{==============================================================================}
765
766constructor TSNMPSend.Create;
767begin
768 inherited Create;
769 FQuery := TSNMPRec.Create;
770 FReply := TSNMPRec.Create;
771 FQuery.Clear;
772 FReply.Clear;
773 FSock := TUDPBlockSocket.Create;
774 FTimeout := 5000;
775 FTargetPort := cSnmpProtocol;
776 FHostIP := '';
777end;
778
779destructor TSNMPSend.Destroy;
780begin
781 FSock.Free;
782 FReply.Free;
783 FQuery.Free;
784 inherited Destroy;
785end;
786
787function TSNMPSend.InternalSendSnmp(const Value: TSNMPRec): Boolean;
788begin
789 FBuffer := Value.EncodeBuf;
790 FSock.SendString(FBuffer);
791 Result := FSock.LastError = 0;
792end;
793
794function TSNMPSend.InternalRecvSnmp(const Value: TSNMPRec): Boolean;
795begin
796 Result := False;
797 FReply.Clear;
798 FHostIP := cAnyHost;
799 FBuffer := FSock.RecvPacket(FTimeout);
800 if FSock.LastError = 0 then
801 begin
802 FHostIP := FSock.GetRemoteSinIP;
803 Result := Value.DecodeBuf(FBuffer);
804 end;
805end;
806
807function TSNMPSend.InternalSendRequest(const QValue, RValue: TSNMPRec): Boolean;
808begin
809 Result := False;
810 FSock.Bind(FIPInterface, cAnyPort);
811 FSock.Connect(FTargetHost, FTargetPort);
812 if InternalSendSnmp(QValue) then
813 Result := InternalRecvSnmp(RValue);
814end;
815
816function TSNMPSend.SendRequest: Boolean;
817var
818 sync: TV3Sync;
819begin
820 Result := False;
821 if FQuery.FVersion = 3 then
822 begin
823 sync := GetV3Sync;
824 FQuery.AuthEngineBoots := Sync.EngineBoots;
825 FQuery.AuthEngineTime := Sync.EngineTime;
826 FQuery.AuthEngineTimeStamp := Sync.EngineStamp;
827 FQuery.AuthEngineID := Sync.EngineID;
828 end;
829 FSock.Bind(FIPInterface, cAnyPort);
830 FSock.Connect(FTargetHost, FTargetPort);
831 if InternalSendSnmp(FQuery) then
832 Result := InternalRecvSnmp(FReply);
833end;
834
835function TSNMPSend.SendTrap: Boolean;
836begin
837 FSock.Bind(FIPInterface, cAnyPort);
838 FSock.Connect(FTargetHost, FTargetPort);
839 Result := InternalSendSnmp(FQuery);
840end;
841
842function TSNMPSend.RecvTrap: Boolean;
843begin
844 FSock.Bind(FIPInterface, FTargetPort);
845 Result := InternalRecvSnmp(FReply);
846end;
847
848function TSNMPSend.DoIt: Boolean;
849begin
850 Result := SendRequest;
851end;
852
853function TSNMPSend.GetV3EngineID: AnsiString;
854var
855 DisQuery: TSNMPRec;
856begin
857 Result := '';
858 DisQuery := TSNMPRec.Create;
859 try
860 DisQuery.Version := 3;
861 DisQuery.UserName := '';
862 DisQuery.FlagReportable := True;
863 DisQuery.PDUType := PDUGetRequest;
864 if InternalSendRequest(DisQuery, FReply) then
865 Result := FReply.FAuthEngineID;
866 finally
867 DisQuery.Free;
868 end;
869end;
870
871function TSNMPSend.GetV3Sync: TV3Sync;
872var
873 SyncQuery: TSNMPRec;
874begin
875 Result.EngineID := GetV3EngineID;
876 Result.EngineBoots := FReply.AuthEngineBoots;
877 Result.EngineTime := FReply.AuthEngineTime;
878 Result.EngineStamp := FReply.AuthEngineTimeStamp;
879 if Result.EngineTime = 0 then
880 begin
881 //still not have sync...
882 SyncQuery := TSNMPRec.Create;
883 try
884 SyncQuery.Version := 3;
885 SyncQuery.UserName := FQuery.UserName;
886 SyncQuery.Password := FQuery.Password;
887 SyncQuery.FlagReportable := True;
888 SyncQuery.Flags := FQuery.Flags;
889 SyncQuery.PDUType := PDUGetRequest;
890 SyncQuery.AuthEngineID := FReply.FAuthEngineID;
891 if InternalSendRequest(SyncQuery, FReply) then
892 begin
893 Result.EngineBoots := FReply.AuthEngineBoots;
894 Result.EngineTime := FReply.AuthEngineTime;
895 Result.EngineStamp := FReply.AuthEngineTimeStamp;
896 end;
897 finally
898 SyncQuery.Free;
899 end;
900 end;
901end;
902
903{==============================================================================}
904
905function SNMPGet(const OID, Community, SNMPHost: AnsiString; var Value: AnsiString): Boolean;
906var
907 SNMPSend: TSNMPSend;
908begin
909 SNMPSend := TSNMPSend.Create;
910 try
911 SNMPSend.Query.Clear;
912 SNMPSend.Query.Community := Community;
913 SNMPSend.Query.PDUType := PDUGetRequest;
914 SNMPSend.Query.MIBAdd(OID, '', ASN1_NULL);
915 SNMPSend.TargetHost := SNMPHost;
916 Result := SNMPSend.SendRequest;
917 Value := '';
918 if Result then
919 Value := SNMPSend.Reply.MIBGet(OID);
920 finally
921 SNMPSend.Free;
922 end;
923end;
924
925function SNMPSet(const OID, Community, SNMPHost, Value: AnsiString; ValueType: Integer): Boolean;
926var
927 SNMPSend: TSNMPSend;
928begin
929 SNMPSend := TSNMPSend.Create;
930 try
931 SNMPSend.Query.Clear;
932 SNMPSend.Query.Community := Community;
933 SNMPSend.Query.PDUType := PDUSetRequest;
934 SNMPSend.Query.MIBAdd(OID, Value, ValueType);
935 SNMPSend.TargetHost := SNMPHost;
936 Result := SNMPSend.Sendrequest = True;
937 finally
938 SNMPSend.Free;
939 end;
940end;
941
942function InternalGetNext(const SNMPSend: TSNMPSend; var OID: AnsiString;
943 const Community: AnsiString; var Value: AnsiString): Boolean;
944begin
945 SNMPSend.Query.Clear;
946 SNMPSend.Query.ID := SNMPSend.Query.ID + 1;
947 SNMPSend.Query.Community := Community;
948 SNMPSend.Query.PDUType := PDUGetNextRequest;
949 SNMPSend.Query.MIBAdd(OID, '', ASN1_NULL);
950 Result := SNMPSend.Sendrequest;
951 Value := '';
952 if Result then
953 if SNMPSend.Reply.SNMPMibList.Count > 0 then
954 begin
955 OID := TSNMPMib(SNMPSend.Reply.SNMPMibList[0]).OID;
956 Value := TSNMPMib(SNMPSend.Reply.SNMPMibList[0]).Value;
957 end;
958end;
959
960function SNMPGetNext(var OID: AnsiString; const Community, SNMPHost: AnsiString; var Value: AnsiString): Boolean;
961var
962 SNMPSend: TSNMPSend;
963begin
964 SNMPSend := TSNMPSend.Create;
965 try
966 SNMPSend.TargetHost := SNMPHost;
967 Result := InternalGetNext(SNMPSend, OID, Community, Value);
968 finally
969 SNMPSend.Free;
970 end;
971end;
972
973function SNMPGetTable(const BaseOID, Community, SNMPHost: AnsiString; const Value: TStrings): Boolean;
974var
975 OID: AnsiString;
976 s: AnsiString;
977 col,row: String;
978 x: integer;
979 SNMPSend: TSNMPSend;
980 RowList: TStringList;
981begin
982 Value.Clear;
983 SNMPSend := TSNMPSend.Create;
984 RowList := TStringList.Create;
985 try
986 SNMPSend.TargetHost := SNMPHost;
987 OID := BaseOID;
988 repeat
989 Result := InternalGetNext(SNMPSend, OID, Community, s);
990 if Pos(BaseOID, OID) <> 1 then
991 break;
992 row := separateright(oid, baseoid + '.');
993 col := fetch(row, '.');
994
995 if IsBinaryString(s) then
996 s := StrToHex(s);
997 x := RowList.indexOf(Row);
998 if x < 0 then
999 begin
1000 x := RowList.add(Row);
1001 Value.Add('');
1002 end;
1003 if (Value[x] <> '') then
1004 Value[x] := Value[x] + ',';
1005 Value[x] := Value[x] + AnsiQuotedStr(s, '"');
1006 until not result;
1007 finally
1008 SNMPSend.Free;
1009 RowList.Free;
1010 end;
1011end;
1012
1013function SNMPGetTableElement(const BaseOID, RowID, ColID, Community, SNMPHost: AnsiString; var Value: AnsiString): Boolean;
1014var
1015 s: AnsiString;
1016begin
1017 s := BaseOID + '.' + ColID + '.' + RowID;
1018 Result := SnmpGet(s, Community, SNMPHost, Value);
1019end;
1020
1021function SendTrap(const Dest, Source, Enterprise, Community: AnsiString;
1022 Generic, Specific, Seconds: Integer; const MIBName, MIBValue: AnsiString;
1023 MIBtype: Integer): Integer;
1024var
1025 SNMPSend: TSNMPSend;
1026begin
1027 SNMPSend := TSNMPSend.Create;
1028 try
1029 SNMPSend.TargetHost := Dest;
1030 SNMPSend.TargetPort := cSnmpTrapProtocol;
1031 SNMPSend.Query.Community := Community;
1032 SNMPSend.Query.Version := SNMP_V1;
1033 SNMPSend.Query.PDUType := PDUTrap;
1034 SNMPSend.Query.OldTrapHost := Source;
1035 SNMPSend.Query.OldTrapEnterprise := Enterprise;
1036 SNMPSend.Query.OldTrapGen := Generic;
1037 SNMPSend.Query.OldTrapSpec := Specific;
1038 SNMPSend.Query.OldTrapTimeTicks := Seconds;
1039 SNMPSend.Query.MIBAdd(MIBName, MIBValue, MIBType);
1040 Result := Ord(SNMPSend.SendTrap);
1041 finally
1042 SNMPSend.Free;
1043 end;
1044end;
1045
1046function RecvTrap(var Dest, Source, Enterprise, Community: AnsiString;
1047 var Generic, Specific, Seconds: Integer;
1048 const MIBName, MIBValue: TStringList): Integer;
1049var
1050 SNMPSend: TSNMPSend;
1051 i: Integer;
1052begin
1053 SNMPSend := TSNMPSend.Create;
1054 try
1055 Result := 0;
1056 SNMPSend.TargetPort := cSnmpTrapProtocol;
1057 if SNMPSend.RecvTrap then
1058 begin
1059 Result := 1;
1060 Dest := SNMPSend.HostIP;
1061 Community := SNMPSend.Reply.Community;
1062 Source := SNMPSend.Reply.OldTrapHost;
1063 Enterprise := SNMPSend.Reply.OldTrapEnterprise;
1064 Generic := SNMPSend.Reply.OldTrapGen;
1065 Specific := SNMPSend.Reply.OldTrapSpec;
1066 Seconds := SNMPSend.Reply.OldTrapTimeTicks;
1067 MIBName.Clear;
1068 MIBValue.Clear;
1069 for i := 0 to SNMPSend.Reply.SNMPMibList.Count - 1 do
1070 begin
1071 MIBName.Add(TSNMPMib(SNMPSend.Reply.SNMPMibList[i]).OID);
1072 MIBValue.Add(TSNMPMib(SNMPSend.Reply.SNMPMibList[i]).Value);
1073 end;
1074 end;
1075 finally
1076 SNMPSend.Free;
1077 end;
1078end;
1079
1080
1081end.
1082
1083
Note: See TracBrowser for help on using the repository browser.