]> git.stg.codes - stg.git/blob - projects/stargazer/plugins/other/snmp/snmp.cpp
Todo for SMUX added
[stg.git] / projects / stargazer / plugins / other / snmp / snmp.cpp
1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <arpa/inet.h>
4
5 #include <cstring>
6 #include <cerrno>
7 #include <ctime>
8 #include <csignal>
9
10 #include <vector>
11 #include <algorithm>
12
13 #include "asn1/OpenPDU.h"
14 #include "asn1/ClosePDU.h"
15 #include "asn1/RReqPDU.h"
16 #include "asn1/GetRequest-PDU.h"
17 #include "asn1/GetResponse-PDU.h"
18 #include "asn1/VarBindList.h"
19 #include "asn1/VarBind.h"
20 #include "asn1/OBJECT_IDENTIFIER.h"
21 #include "asn1/ber_decoder.h"
22 #include "asn1/der_encoder.h"
23
24 #include "snmp.h"
25 #include "stg/common.h"
26
27 bool WaitPackets(int sd);
28
29 std::string OI2String(OBJECT_IDENTIFIER_t * oi)
30 {
31 std::string res;
32
33 int arcs[1024];
34 int count = OBJECT_IDENTIFIER_get_arcs(oi, arcs, sizeof(arcs[0]), 1024);
35
36 if (count > 1024)
37     return "";
38
39 for (int i = 0; i < count; ++i)
40     {
41     res += ".";
42     std::string arc;
43     strprintf(&arc, "%d", arcs[i]);
44     res += arc;
45     }
46
47 return res;
48 }
49
50 bool String2OI(const std::string & str, OBJECT_IDENTIFIER_t * oi)
51 {
52 size_t left = 0, pos = 0, arcPos = 0;
53 int arcs[1024];
54 pos = str.find_first_of('.', left);
55 if (pos == 0)
56     {
57     left = 1;
58     pos = str.find_first_of('.', left);
59     }
60 while (pos != std::string::npos)
61     {
62     int arc = 0;
63     if (str2x(str.substr(left, left - pos), arc))
64         {
65         return false;
66         }
67     arcs[arcPos++] = arc;
68     left = pos + 1;
69     pos = str.find_first_of('.', left);
70     }
71 if (left < str.length())
72     {
73     int arc = 0;
74     if (str2x(str.substr(left, left - pos), arc))
75         {
76         return false;
77         }
78     arcs[arcPos++] = arc;
79     }
80 printfd(__FILE__, "String2OI() - arcPos: %d\n", arcPos);
81 OBJECT_IDENTIFIER_set_arcs(oi, arcs, sizeof(arcs[0]), arcPos);
82 return true;
83 }
84
85 class SNMP_AGENT_CREATOR
86 {
87 private:
88     SNMP_AGENT * snmpAgent;
89
90 public:
91     SNMP_AGENT_CREATOR()
92         : snmpAgent(new SNMP_AGENT())
93         {
94         };
95     ~SNMP_AGENT_CREATOR()
96         {
97         printfd(__FILE__, "SNMP_AGENT_CREATOR::~SNMP_AGENT_CREATOR()\n");
98         delete snmpAgent;
99         };
100
101     SNMP_AGENT * GetPlugin()
102         {
103         return snmpAgent;
104         };
105 };
106
107 SNMP_AGENT_CREATOR sac;
108
109 PLUGIN * GetPlugin()
110 {
111 return sac.GetPlugin();
112 }
113
114 int SendOpenPDU(int fd)
115 {
116 const char * description = "Stg SNMP Agent";
117 //int oid[] = {1, 3, 6, 1, 4, 1, 9363, 1, 5, 2, 1, 1};
118 asn_enc_rval_t error;
119 OpenPDU_t msg;
120
121 memset(&msg, 0, sizeof(msg));
122
123 msg.present = OpenPDU_PR_simple;
124 asn_long2INTEGER(&msg.choice.simple.version, SimpleOpen__version_version_1);
125 /*OBJECT_IDENTIFIER_set_arcs(&msg.choice.simple.identity,
126                            oid,
127                            sizeof(oid[0]),
128                            7);*/
129 if (!String2OI(".1.3.6.1.4.1.9363", &msg.choice.simple.identity))
130     {
131     printfd(__FILE__, "SendOpenPDU() - failed to convert string to OBJECT_IDENTIFIER\n");
132     return -1;
133     }
134 OCTET_STRING_fromString(&msg.choice.simple.description,
135                      description);
136 OCTET_STRING_fromString(&msg.choice.simple.password,
137                      "");
138
139 char buffer[1024];
140 error = der_encode_to_buffer(&asn_DEF_OpenPDU, &msg, buffer, sizeof(buffer));
141
142 if (error.encoded == -1)
143     {
144     printfd(__FILE__, "Could not encode OpenPDU (at %s)\n",
145             error.failed_type ? error.failed_type->name : "unknown");
146     return -1;
147     }
148 else
149     {
150     write(fd, buffer, error.encoded);
151     printfd(__FILE__, "OpenPDU encoded successfully to %d bytes\n", error.encoded);
152     }
153 return 0;
154 }
155
156 int SendClosePDU(int fd)
157 {
158 ClosePDU_t msg;
159
160 memset(&msg, 0, sizeof(msg));
161
162 asn_long2INTEGER(&msg, ClosePDU_goingDown);
163
164 char buffer[1024];
165 asn_enc_rval_t error;
166 error = der_encode_to_buffer(&asn_DEF_ClosePDU, &msg, buffer, sizeof(buffer));
167
168 if (error.encoded == -1)
169     {
170     printfd(__FILE__, "Could not encode ClosePDU (at %s)\n",
171             error.failed_type ? error.failed_type->name : "unknown");
172     return -1;
173     }
174 else
175     {
176     write(fd, buffer, error.encoded);
177     printfd(__FILE__, "ClosePDU encoded successfully\n");
178     }
179 return 0;
180 }
181
182 int SendRReqPDU(int fd)
183 {
184 int oid[] = {1, 3, 6, 1, 4, 1, 9363, 1};
185 asn_enc_rval_t error;
186 RReqPDU_t msg;
187
188 memset(&msg, 0, sizeof(msg));
189
190 msg.priority = 0;
191 asn_long2INTEGER(&msg.operation, RReqPDU__operation_readOnly);
192 OBJECT_IDENTIFIER_set_arcs(&msg.subtree,
193                            oid,
194                            sizeof(oid[0]),
195                            8);
196
197 char buffer[1024];
198 error = der_encode_to_buffer(&asn_DEF_RReqPDU, &msg, buffer, sizeof(buffer));
199
200 if (error.encoded == -1)
201     {
202     printfd(__FILE__, "Could not encode RReqPDU (at %s)\n",
203             error.failed_type ? error.failed_type->name : "unknown");
204     return -1;
205     }
206 else
207     {
208     write(fd, buffer, error.encoded);
209     printfd(__FILE__, "RReqPDU encoded successfully to %d bytes\n", error.encoded);
210     }
211 return 0;
212 }
213
214 int SendGetResponsePDU(int fd, const PDU_t * pdu)
215 {
216 asn_enc_rval_t error;
217 GetResponse_PDU_t msg;
218
219 memset(&msg, 0, sizeof(msg));
220
221 msg.request_id = pdu->request_id;
222 asn_long2INTEGER(&msg.error_status, 0);
223 asn_long2INTEGER(&msg.error_index, 0);
224
225 VarBind_t vb;
226
227 memset(&vb, 0, sizeof(vb));
228
229 if (!String2OI(".1.3.6.1.4.1.9363.1", &vb.name))
230     {
231     printfd(__FILE__, "SendSetResponsePDU() - failed to convert string to OBJECT_IDENTIFIER\n");
232     return -1;
233     }
234
235 ObjectSyntax_t * objectSyntax = &vb.value;
236 objectSyntax->present = ObjectSyntax_PR_simple;
237 SimpleSyntax_t * simpleSyntax = &objectSyntax->choice.simple;
238 simpleSyntax->present = SimpleSyntax_PR_number;
239 asn_long2INTEGER(&simpleSyntax->choice.number, 1);
240
241
242 ASN_SEQUENCE_ADD(&msg.variable_bindings, &vb);
243
244 /*const VarBindList_t * vbl = &pdu->variable_bindings; 
245 for (int i = 0; i < vbl->list.count; ++i)
246     {
247     VarBind_t * vb = pdu->variable_bindings.list.array[i];
248     printfd(__FILE__, "OID: %s\n", OI2String(&vb->name).c_str());
249     asn_fprint(stderr, &asn_DEF_ObjectSyntax, &vb->value);
250     }*/
251
252 char buffer[1024];
253 error = der_encode_to_buffer(&asn_DEF_GetResponse_PDU, &msg, buffer, sizeof(buffer));
254
255 if (error.encoded == -1)
256     {
257     printfd(__FILE__, "Could not encode GetResponsePDU (at %s)\n",
258             error.failed_type ? error.failed_type->name : "unknown");
259     return -1;
260     }
261 else
262     {
263     write(fd, buffer, error.encoded);
264     printfd(__FILE__, "GetResponsePDU encoded successfully to %d bytes\n", error.encoded);
265     }
266 return 0;
267 }
268
269 int SendSetResponsePDU(int fd, const PDU_t * pdu)
270 {
271 //int oid[] = {1, 3, 6, 1, 4, 1, 9363, 1};
272 asn_enc_rval_t error;
273 GetResponse_PDU_t msg;
274
275 memset(&msg, 0, sizeof(msg));
276
277 msg.request_id = pdu->request_id;
278 asn_long2INTEGER(&msg.error_status, PDU__error_status_readOnly);
279 asn_long2INTEGER(&msg.error_index, 0);
280
281 char buffer[1024];
282 error = der_encode_to_buffer(&asn_DEF_GetResponse_PDU, &msg, buffer, sizeof(buffer));
283
284 if (error.encoded == -1)
285     {
286     printfd(__FILE__, "Could not encode GetResponsePDU (at %s)\n",
287             error.failed_type ? error.failed_type->name : "unknown");
288     return -1;
289     }
290 else
291     {
292     write(fd, buffer, error.encoded);
293     printfd(__FILE__, "GetResponsePDU encoded successfully to %d bytes\n", error.encoded);
294     }
295 return 0;
296 }
297
298 SMUX_PDUs_t * RecvSMUXPDUs(int fd)
299 {
300 char buffer[1024];
301 SMUX_PDUs_t * pdus = NULL;
302
303 memset(buffer, 0, sizeof(buffer));
304
305 size_t length = read(fd, buffer, sizeof(buffer));
306 if (length < 1)
307     return NULL;
308 asn_dec_rval_t error;
309 error = ber_decode(0, &asn_DEF_SMUX_PDUs, (void **)&pdus, buffer, length);
310 if(error.code != RC_OK)
311     {
312     printfd(__FILE__, "Failed to decode PDUs at byte %ld\n",
313             (long)error.consumed);
314     return NULL;
315     }
316 return pdus;
317 }
318
319 int ParseIntInRange(const std::string & str,
320                     int min,
321                     int max,
322                     int * val)
323 {
324 if (str2x(str.c_str(), *val))
325     {
326     return -1;
327     }
328 if (*val < min || *val > max)
329     {
330     return -1;
331     }
332 return 0;
333 }
334
335 SNMP_AGENT_SETTINGS::SNMP_AGENT_SETTINGS()
336     : ip(0),
337       port(0)
338 {}
339
340 int SNMP_AGENT_SETTINGS::ParseSettings(const MODULE_SETTINGS & s)
341 {
342 PARAM_VALUE pv;
343 std::vector<PARAM_VALUE>::const_iterator pvi;
344 int p;
345 ///////////////////////////
346 pv.param = "Port";
347 pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
348 if (pvi == s.moduleParams.end())
349     {
350     errorStr = "Parameter \'Port\' not found.";
351     printfd(__FILE__, "Parameter 'Port' not found\n");
352     return -1;
353     }
354 if (ParseIntInRange(pvi->value[0], 2, 65535, &p))
355     {
356     errorStr = "Cannot parse parameter \'Port\': " + errorStr;
357     printfd(__FILE__, "Cannot parse parameter 'Port'\n");
358     return -1;
359     }
360 port = p;
361
362 pv.param = "Password";
363 pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
364 if (pvi == s.moduleParams.end())
365     {
366     errorStr = "Parameter \'Password\' not found.";
367     printfd(__FILE__, "Parameter 'Password' not found\n");
368     password = "";
369     }
370 else
371     {
372     password = pvi->value[0];
373     }
374
375 pv.param = "Server";
376 pvi = std::find(s.moduleParams.begin(), s.moduleParams.end(), pv);
377 if (pvi == s.moduleParams.end())
378     {
379     errorStr = "Parameter \'Server\' not found.";
380     printfd(__FILE__, "Parameter 'Server' not found\n");
381     return -1;
382     }
383 ip = inet_strington(pvi->value[0]);
384
385 return 0;
386 }
387
388 SNMP_AGENT::SNMP_AGENT()
389     : PLUGIN(),
390       running(false),
391       stopped(true),
392       sock(-1)
393 {
394 pthread_mutex_init(&mutex, NULL);
395
396 smuxHandlers[SMUX_PDUs_PR_close] = &SNMP_AGENT::CloseHandler;
397 smuxHandlers[SMUX_PDUs_PR_registerResponse] = &SNMP_AGENT::RegisterResponseHandler;
398 smuxHandlers[SMUX_PDUs_PR_pdus] = &SNMP_AGENT::PDUsHandler;
399 smuxHandlers[SMUX_PDUs_PR_commitOrRollback] = &SNMP_AGENT::CommitOrRollbackHandler;
400
401 pdusHandlers[PDUs_PR_get_request] = &SNMP_AGENT::GetRequestHandler;
402 pdusHandlers[PDUs_PR_get_next_request] = &SNMP_AGENT::GetNextRequestHandler;
403 pdusHandlers[PDUs_PR_set_request] = &SNMP_AGENT::SetRequestHandler;
404 }
405
406 SNMP_AGENT::~SNMP_AGENT()
407 {
408 printfd(__FILE__, "SNMP_AGENT::~SNMP_AGENT()\n");
409 pthread_mutex_destroy(&mutex);
410 }
411
412 int SNMP_AGENT::ParseSettings()
413 {
414 return snmpAgentSettings.ParseSettings(settings);
415 }
416
417 int SNMP_AGENT::Start()
418 {
419 if (PrepareNet())
420     return -1;
421
422 if (!running)
423     {
424     if (pthread_create(&thread, NULL, Runner, this))
425         {
426         errorStr = "Cannot create thread.";
427         printfd(__FILE__, "Cannot create thread\n");
428         return -1;
429         }
430     }
431
432 return 0;
433 }
434
435 int SNMP_AGENT::Stop()
436 {
437 printfd(__FILE__, "SNMP_AGENT::Stop() - Before\n");
438 running = false;
439
440 if (!stopped)
441     {
442     //5 seconds to thread stops itself
443     for (int i = 0; i < 25 && !stopped; i++)
444         {
445         struct timespec ts = {0, 200000000};
446         nanosleep(&ts, NULL);
447         }
448
449     //after 5 seconds waiting thread still running. now killing it
450     if (!stopped)
451         {
452         printfd(__FILE__, "SNMP_AGENT::Stop() - failed to stop thread, killing it\n");
453         if (pthread_kill(thread, SIGINT))
454             {
455             errorStr = "Cannot kill thread.";
456             printfd(__FILE__, "SNMP_AGENT::Stop() - Cannot kill thread\n");
457             return -1;
458             }
459         printfd(__FILE__, "SNMP_AGENT::Stop() -  killed Run\n");
460         }
461     }
462
463 pthread_join(thread, NULL);
464
465 close(sock);
466
467 printfd(__FILE__, "SNMP_AGENT::Stop() - After\n");
468 return 0;
469 }
470
471 void * SNMP_AGENT::Runner(void * d)
472 {
473 SNMP_AGENT * snmpAgent = static_cast<SNMP_AGENT *>(d);
474
475 snmpAgent->Run();
476
477 return NULL;
478 }
479
480 void SNMP_AGENT::Run()
481 {
482 SendOpenPDU(sock);
483 SendRReqPDU(sock);
484 running = true;
485 stopped = false;
486 printfd(__FILE__, "SNMP_AGENT::Run() - Before\n");
487 while(running)
488     {
489     if (WaitPackets(sock))
490         {
491         SMUX_PDUs_t * pdus = RecvSMUXPDUs(sock);
492         if (pdus)
493             DispatchPDUs(pdus);
494         }
495     if (!running)
496         break;
497     }
498 printfd(__FILE__, "SNMP_AGENT::Run() - After\n");
499 SendClosePDU(sock);
500 stopped = true;
501 }
502
503 bool SNMP_AGENT::PrepareNet()
504 {
505 sock = socket(AF_INET, SOCK_STREAM, 0);
506
507 if (sock < 0)
508     {
509     errorStr = "Cannot create socket.";
510     printfd(__FILE__, "Cannot create socket\n");
511     return true;
512     }
513
514 struct sockaddr_in addr;
515
516 addr.sin_family = AF_INET;
517 addr.sin_port = htons(snmpAgentSettings.GetPort());
518 addr.sin_addr.s_addr = snmpAgentSettings.GetIP();
519
520 if (connect(sock, reinterpret_cast<struct sockaddr *>(&addr), sizeof(addr)))
521     {
522     errorStr = "Cannot connect.";
523     printfd(__FILE__, "Cannot connect. Message: '%s'\n", strerror(errno));
524     return true;
525     }
526
527 return false;
528 }
529
530 bool WaitPackets(int sd)
531 {
532 fd_set rfds;
533 FD_ZERO(&rfds);
534 FD_SET(sd, &rfds);
535
536 struct timeval tv;
537 tv.tv_sec = 0;
538 tv.tv_usec = 500000;
539
540 int res = select(sd + 1, &rfds, NULL, NULL, &tv);
541 if (res == -1) // Error
542     {
543     if (errno != EINTR)
544         {
545         printfd(__FILE__, "Error on select: '%s'\n", strerror(errno));
546         }
547     return false;
548     }
549
550 if (res == 0) // Timeout
551     {
552     return false;
553     }
554
555 return true;
556 }
557
558 bool SNMP_AGENT::DispatchPDUs(const SMUX_PDUs_t * pdus)
559 {
560 SMUXHandlers::iterator it;
561 it = smuxHandlers.find(pdus->present);
562 if (it != smuxHandlers.end())
563     {
564     return (this->*(it->second))(pdus);
565     }
566 else
567     {
568     switch (pdus->present)
569         {
570         case SMUX_PDUs_PR_NOTHING:
571             printfd(__FILE__, "PDUs: nothing\n");
572             break;
573         case SMUX_PDUs_PR_open:
574             printfd(__FILE__, "PDUs: open\n");
575             break;
576         case SMUX_PDUs_PR_registerRequest:
577             printfd(__FILE__, "PDUs: registerRequest\n");
578             break;
579         default:
580             printfd(__FILE__, "PDUs: undefined\n");
581         }
582     asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
583     }
584 return false;
585 }
586
587 bool SNMP_AGENT::CloseHandler(const SMUX_PDUs_t * pdus)
588 {
589 printfd(__FILE__, "SNMP_AGENT::CloseHandler()\n");
590 asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
591 return false;
592 }
593
594 bool SNMP_AGENT::RegisterResponseHandler(const SMUX_PDUs_t * pdus)
595 {
596 printfd(__FILE__, "SNMP_AGENT::RegisterResponseHandler()\n");
597 asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
598 return false;
599 }
600
601 bool SNMP_AGENT::PDUsHandler(const SMUX_PDUs_t * pdus)
602 {
603 printfd(__FILE__, "SNMP_AGENT::PDUsHandler()\n");
604 asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
605 PDUsHandlers::iterator it;
606 it = pdusHandlers.find(pdus->choice.pdus.present);
607 if (it != pdusHandlers.end())
608     {
609     return (this->*(it->second))(&pdus->choice.pdus);
610     }
611 else
612     {
613     switch (pdus->present)
614         {
615         case PDUs_PR_NOTHING:
616             printfd(__FILE__, "SNMP_AGENT::PDUsHandler() - nothing\n");
617             break;
618         case PDUs_PR_get_response:
619             printfd(__FILE__, "SNMP_AGENT::PDUsHandler() - get response\n");
620             break;
621         case PDUs_PR_trap:
622             printfd(__FILE__, "SNMP_AGENT::PDUsHandler() - trap\n");
623             break;
624         default:
625             printfd(__FILE__, "SNMP_AGENT::PDUsHandler() - undefined\n");
626         }
627     }
628 return false;
629 }
630
631 bool SNMP_AGENT::CommitOrRollbackHandler(const SMUX_PDUs_t * pdus)
632 {
633 printfd(__FILE__, "SNMP_AGENT::CommitOrRollbackHandler()\n");
634 asn_fprint(stderr, &asn_DEF_SMUX_PDUs, pdus);
635 return false;
636 }
637
638 bool SNMP_AGENT::GetRequestHandler(const PDUs_t * pdus)
639 {
640 printfd(__FILE__, "SNMP_AGENT::GetRequestHandler()\n");
641 asn_fprint(stderr, &asn_DEF_PDUs, pdus);
642 SendGetResponsePDU(sock, &pdus->choice.get_request);
643 return false;
644 }
645
646 bool SNMP_AGENT::GetNextRequestHandler(const PDUs_t * pdus)
647 {
648 printfd(__FILE__, "SNMP_AGENT::GetNextRequestHandler()\n");
649 asn_fprint(stderr, &asn_DEF_PDUs, pdus);
650 return false;
651 }
652
653 bool SNMP_AGENT::SetRequestHandler(const PDUs_t * pdus)
654 {
655 printfd(__FILE__, "SNMP_AGENT::SetRequestHandler()\n");
656 asn_fprint(stderr, &asn_DEF_PDUs, pdus);
657 SendSetResponsePDU(sock, &pdus->choice.set_request);
658 return false;
659 }
660