snmpsend.pas 34 KB

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