2
* Smux module authored by Rohit Dube.
3
* Rewritten by Nick Amato <naamato@merit.net>.
6
#include <net-snmp/net-snmp-config.h>
10
#if HAVE_IO_H /* win32 */
28
#if TIME_WITH_SYS_TIME
30
# include <sys/timeb.h>
32
# include <sys/time.h>
37
# include <sys/time.h>
49
#include <sys/socket.h>
54
#include <sys/filio.h>
58
#include <netinet/in.h>
62
#include <arpa/inet.h>
66
#include <sys/ioctl.h>
69
#include <net-snmp/net-snmp-includes.h>
70
#include <net-snmp/agent/net-snmp-agent-includes.h>
73
#include "util_funcs.h"
79
struct sockaddr_in smux_sa;
80
struct counter64 smux_counter64;
81
oid smux_objid[MAX_OID_LEN];
82
u_char smux_str[SMUXMAXSTRLEN];
83
int smux_listen_sd = -1;
85
static struct timeval smux_rcv_timeout;
86
static u_long smux_reqid;
89
static u_char *smux_open_process(int, u_char *, size_t *, int *);
90
static u_char *smux_rreq_process(int, u_char *, size_t *);
91
static u_char *smux_close_process(int, u_char *, size_t *);
92
static u_char *smux_trap_process(u_char *, size_t *);
93
static u_char *smux_parse(u_char *, oid *, size_t *, size_t *, u_char *);
94
static u_char *smux_parse_var(u_char *, size_t *, oid *, size_t *,
96
static void smux_send_close(int, int);
97
static void smux_list_detach(smux_reg **, smux_reg **);
98
static void smux_replace_active(smux_reg *, smux_reg *);
99
static void smux_peer_cleanup(int);
100
static int smux_auth_peer(oid *, size_t, char *, int);
101
static int smux_build(u_char, u_long, oid *,
102
size_t *, u_char, u_char *, size_t, u_char *,
104
static int smux_list_add(smux_reg **, smux_reg *);
105
static int smux_pdu_process(int, u_char *, size_t);
106
static int smux_send_rrsp(int, int);
107
static smux_reg *smux_find_match(smux_reg *, int, oid *, size_t, long);
108
static smux_reg *smux_find_replacement(oid *, size_t);
109
u_char *var_smux(struct variable *, oid *, size_t *, int, size_t *,
110
WriteMethod ** write_method);
111
int var_smux_write(int, u_char *, u_char, size_t, u_char *,
114
static smux_reg *ActiveRegs; /* Active registrations */
115
static smux_reg *PassiveRegs; /* Currently unused registrations */
117
static smux_peer_auth *Auths[SMUX_MAX_PEERS]; /* Configured peers */
118
static int nauths, npeers = 0;
120
struct variable2 smux_variables[] = {
122
* bogus entry, as in pass.c
124
{MIBINDEX, ASN_INTEGER, RWRITE, var_smux, 0, {MIBINDEX}},
130
smux_parse_smux_socket(const char *token, char *cptr)
132
DEBUGMSGTL(("smux", "port spec: %s\n", cptr));
133
netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_SMUX_SOCKET, cptr);
137
smux_parse_peer_auth(const char *token, char *cptr)
139
smux_peer_auth *aptr;
142
(smux_peer_auth *) calloc(1, sizeof(smux_peer_auth))) == NULL) {
143
snmp_log_perror("smux_parse_peer_auth: malloc");
146
aptr->sa_active_fd = -1;
151
Auths[nauths++] = aptr;
152
DEBUGMSGTL(("smux_conf", "null password\n"));
159
if (!isdigit(*cptr)) {
160
config_perror("second token is not an OID");
167
aptr->sa_oid_len = parse_miboid(cptr, aptr->sa_oid);
169
DEBUGMSGTL(("smux_conf", "parsing registration for: %s\n", cptr));
171
while (isdigit(*cptr) || *cptr == '.')
173
cptr = skip_white(cptr);
179
strcpy(aptr->sa_passwd, cptr);
181
Auths[nauths++] = aptr;
185
smux_free_peer_auth(void)
189
for (i = 0; i < nauths; i++) {
199
snmpd_register_config_handler("smuxpeer", smux_parse_peer_auth,
201
"OID-IDENTITY PASSWORD");
202
snmpd_register_config_handler("smuxsocket",
203
smux_parse_smux_socket, NULL,
204
"SMUX bind address");
210
struct sockaddr_in lo_socket;
214
if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) {
228
smux_rcv_timeout.tv_sec = 0;
229
smux_rcv_timeout.tv_usec = 500000;
232
* Get ready to listen on the SMUX port
234
memset(&lo_socket, (0), sizeof(lo_socket));
235
lo_socket.sin_family = AF_INET;
237
smux_socket = netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
238
NETSNMP_DS_SMUX_SOCKET);
241
smux_socket = "127.0.0.1"; /* By default, listen on localhost only */
243
netsnmp_sockaddr_in( &lo_socket, smux_socket, SMUXPORT );
245
if ((smux_listen_sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
246
snmp_log_perror("[init_smux] socket failed");
251
* At least on Linux, when the master agent terminates, any
252
* TCP connections for SMUX peers are put in the TIME_WAIT
253
* state for about 60 seconds. If the master agent is started
254
* during this time, the bind for the listening socket will
255
* fail because the SMUX port is in use.
257
if (setsockopt(smux_listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
259
snmp_log_perror("[init_smux] setsockopt(SO_REUSEADDR) failed");
261
#endif /* SO_REUSEADDR */
263
if (bind(smux_listen_sd, (struct sockaddr *) &lo_socket,
264
sizeof(lo_socket)) < 0) {
265
snmp_log_perror("[init_smux] bind failed");
266
close(smux_listen_sd);
271
if (setsockopt(smux_listen_sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one,
273
snmp_log_perror("[init_smux] setsockopt(SO_KEEPALIVE) failed");
274
close(smux_listen_sd);
278
#endif /* SO_KEEPALIVE */
280
if (listen(smux_listen_sd, SOMAXCONN) == -1) {
281
snmp_log_perror("[init_smux] listen failed");
282
close(smux_listen_sd);
287
DEBUGMSGTL(("smux_init",
288
"[smux_init] done; smux listen sd is %d, smux port is %d\n",
289
smux_listen_sd, ntohs(lo_socket.sin_port)));
293
var_smux(struct variable * vp,
296
int exact, size_t * var_len, WriteMethod ** write_method)
298
u_char *valptr, val_type;
301
*write_method = var_smux_write;
303
* search the active registration list
305
for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) {
306
if (0 >= snmp_oidtree_compare(vp->name, vp->namelen, rptr->sr_name,
312
else if (exact && (*length < rptr->sr_name_len))
315
valptr = smux_snmp_process(exact, name, length,
316
var_len, &val_type, rptr->sr_fd);
321
if ((snmp_oidtree_compare(name, *length, rptr->sr_name,
322
rptr->sr_name_len)) != 0) {
324
* the peer has returned a value outside
325
* * of the registered tree
330
* set the type and return the value
338
var_smux_write(int action,
342
u_char * statP, oid * name, size_t name_len)
345
u_char buf[SMUXMAXPKTSIZE], *ptr, sout[3], type;
347
size_t var_len, datalen, name_length, packet_len;
349
long reqid, errsts, erridx;
350
u_char var_type, *dataptr;
352
DEBUGMSGTL(("smux", "[var_smux_write] entering var_smux_write\n"));
354
len = SMUXMAXPKTSIZE;
355
reterr = SNMP_ERR_NOERROR;
356
var_len = var_val_len;
357
var_type = var_val_type;
358
name_length = name_len;
361
* XXX find the descriptor again
363
for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) {
364
if (!snmp_oidtree_compare(name, name_len, rptr->sr_name,
371
DEBUGMSGTL(("smux", "[var_smux_write] entering RESERVE1\n"));
374
* length might be long
376
var_len += (*(var_val + 1) & ASN_LONG_LEN) ?
377
var_len + ((*(var_val + 1) & 0x7F) + 2) : 2;
379
switch (var_val_type) {
392
datalen = var_val_len;
395
case SNMP_NOSUCHOBJECT:
396
case SNMP_NOSUCHINSTANCE:
397
case SNMP_ENDOFMIBVIEW:
401
"[var_smux_write] variable not supported\n"));
402
return SNMP_ERR_GENERR;
406
if ((smux_build((u_char) SMUX_SET, smux_reqid,
407
name, &name_length, var_val_type, dataptr,
408
datalen, buf, &len)) < 0) {
409
DEBUGMSGTL(("smux", "[var_smux_write] smux build failed\n"));
410
return SNMP_ERR_GENERR;
413
if (send(rptr->sr_fd, buf, len, 0) < 0) {
414
DEBUGMSGTL(("smux", "[var_smux_write] send failed\n"));
415
return SNMP_ERR_GENERR;
420
* peek at what's received
422
if ((len = recv(rptr->sr_fd, buf,
423
SMUXMAXPKTSIZE, MSG_PEEK)) <= 0) {
425
"[var_smux_write] peek failed or timed out\n"));
427
* do we need to do a peer cleanup in this case??
429
smux_peer_cleanup(rptr->sr_fd);
430
return SNMP_ERR_GENERR;
433
DEBUGMSGTL(("smux", "[var_smux_write] Peeked at %d bytes\n",
435
DEBUGDUMPSETUP("var_smux_write", buf, len);
438
* determine if we received more than one packet
441
ptr = asn_parse_header(buf, &packet_len, &type);
442
packet_len += (ptr - buf);
443
if (len > (ssize_t)packet_len) {
445
* set length to receive only the first packet
451
* receive the first packet
453
if ((len = recv(rptr->sr_fd, buf, len, 0)) <= 0) {
455
"[var_smux_write] recv failed or timed out\n"));
457
* do we need to do a peer cleanup in this case??
459
smux_peer_cleanup(rptr->sr_fd);
460
return SNMP_ERR_GENERR;
463
DEBUGMSGTL(("smux", "[var_smux_write] Received %d bytes\n",
466
if (buf[0] == SMUX_TRAP) {
467
DEBUGMSGTL(("smux", "[var_smux_write] Received trap\n"));
468
snmp_log(LOG_INFO, "Got trap from peer on fd %d\n",
470
ptr = asn_parse_header(buf, &len, &type);
471
smux_trap_process(ptr, &len);
475
* go and peek at received data again
478
* we could receive the reply or another trap
482
ptr = asn_parse_header(ptr, &len, &type);
483
if ((ptr == NULL) || type != SNMP_MSG_RESPONSE)
484
return SNMP_ERR_GENERR;
487
asn_parse_int(ptr, &len, &type, &reqid, sizeof(reqid));
488
if ((ptr == NULL) || type != ASN_INTEGER)
489
return SNMP_ERR_GENERR;
492
asn_parse_int(ptr, &len, &type, &errsts,
494
if ((ptr == NULL) || type != ASN_INTEGER)
495
return SNMP_ERR_GENERR;
499
"[var_smux_write] errsts returned\n"));
504
asn_parse_int(ptr, &len, &type, &erridx,
506
if ((ptr == NULL) || type != ASN_INTEGER)
507
return SNMP_ERR_GENERR;
509
reterr = SNMP_ERR_NOERROR;
513
break; /* case Action == RESERVE1 */
516
DEBUGMSGTL(("smux", "[var_smux_write] entering RESERVE2\n"));
517
reterr = SNMP_ERR_NOERROR;
518
break; /* case Action == RESERVE2 */
523
*(ptr++) = (u_char) SMUX_SOUT;
524
*(ptr++) = (u_char) 1;
525
if (action == FREE) {
526
*ptr = (u_char) 1; /* rollback */
528
"[var_smux_write] entering FREE - sending RollBack \n"));
530
*ptr = (u_char) 0; /* commit */
532
"[var_smux_write] entering FREE - sending Commit \n"));
535
if ((send(rptr->sr_fd, sout, 3, 0)) < 0) {
537
"[var_smux_write] send rollback/commit failed\n"));
538
return SNMP_ERR_GENERR;
541
reterr = SNMP_ERR_NOERROR;
542
break; /* case Action == COMMIT */
554
u_char data[SMUXMAXPKTSIZE], *ptr, type;
555
struct sockaddr_in in_socket;
561
alen = sizeof(struct sockaddr_in);
563
* this may be too high
571
DEBUGMSGTL(("smux", "[smux_accept] Calling accept()\n"));
573
if ((fd = accept(sd, (struct sockaddr *) &in_socket, &alen)) < 0) {
574
snmp_log_perror("[smux_accept] accept failed");
577
snmp_log(LOG_INFO, "[smux_accept] accepted fd %d from %s:%d\n",
578
fd, inet_ntoa(in_socket.sin_addr),
579
ntohs(in_socket.sin_port));
580
if (npeers + 1 == SMUXMAXPEERS) {
582
"[smux_accept] denied peer on fd %d, limit %d reached",
589
* now block for an OpenPDU
591
if ((length = recv(fd, (char *) data, SMUXMAXPKTSIZE, 0)) <= 0) {
593
"[smux_accept] peer on fd %d died or timed out\n",
599
* try to authorize him
603
if ((ptr = asn_parse_header(ptr, &len, &type)) == NULL) {
604
smux_send_close(fd, SMUXC_PACKETFORMAT);
606
DEBUGMSGTL(("smux", "[smux_accept] peer on %d sent bad open"));
608
} else if (type != (u_char) SMUX_OPEN) {
609
smux_send_close(fd, SMUXC_PROTOCOLERROR);
612
"[smux_accept] peer on %d did not send open: (%d)\n",
616
ptr = smux_open_process(fd, ptr, &len, &fail);
618
smux_send_close(fd, SMUXC_AUTHENTICATIONFAILURE);
621
"[smux_accept] peer on %d failed authentication\n",
631
(fd, SOL_SOCKET, SO_RCVTIMEO, (void *) &tv, sizeof(tv)) < 0) {
633
"[smux_accept] setsockopt(SO_RCVTIMEO) failed fd %d\n",
635
snmp_log_perror("smux_accept: setsockopt SO_RCVTIMEO");
639
DEBUGMSGTL(("smux", "[smux_accept] fd %d\n", fd));
642
* Process other PDUs already read, e.g. a registerRequest.
644
len = length - (ptr - data);
645
if (smux_pdu_process(fd, ptr, len) < 0) {
647
* Easy come, easy go. Clean-up is already done.
659
u_char data[SMUXMAXPKTSIZE];
661
length = recv(fd, (char *) data, SMUXMAXPKTSIZE, 0);
664
* the peer went away, close this descriptor
665
* * and delete it from the list
668
"[smux_process] peer on fd %d died or timed out\n",
670
smux_peer_cleanup(fd);
674
return smux_pdu_process(fd, data, length);
678
smux_pdu_process(int fd, u_char * data, size_t length)
684
DEBUGMSGTL(("smux", "[smux_pdu_process] Processing %d bytes\n",
689
while (error == 0 && ptr != NULL && ptr < data + length) {
690
len = length - (ptr - data);
691
ptr = asn_parse_header(ptr, &len, &type);
692
DEBUGMSGTL(("smux", "[smux_pdu_process] type is %d\n",
696
smux_send_close(fd, SMUXC_PROTOCOLERROR);
698
"[smux_pdu_process] peer on fd %d sent duplicate open?\n",
700
smux_peer_cleanup(fd);
704
ptr = smux_close_process(fd, ptr, &len);
705
smux_peer_cleanup(fd);
709
ptr = smux_rreq_process(fd, ptr, &len);
713
smux_send_close(fd, SMUXC_PROTOCOLERROR);
714
smux_peer_cleanup(fd);
716
"[smux_pdu_process] peer on fd %d sent RRSP!\n",
721
smux_send_close(fd, SMUXC_PROTOCOLERROR);
722
smux_peer_cleanup(fd);
723
DEBUGMSGTL(("smux", "This shouldn't have happened!\n"));
726
snmp_log(LOG_INFO, "Got trap from peer on fd %d\n", fd);
727
ptr = smux_trap_process(ptr, &len);
729
* watch out for close on top of this...should return correct end
737
smux_send_close(fd, SMUXC_PACKETFORMAT);
738
smux_peer_cleanup(fd);
739
DEBUGMSGTL(("smux", "[smux_pdu_process] Wrong type %d\n",
749
smux_open_process(int fd, u_char * ptr, size_t * len, int *fail)
753
oid oid_name[MAX_OID_LEN];
754
char passwd[SMUXMAXSTRLEN];
755
char descr[SMUXMAXSTRLEN];
756
char oid_print[SMUXMAXSTRLEN];
758
size_t oid_name_len, string_len;
760
if (!(ptr = asn_parse_int(ptr, len, &type, &version, sizeof(version)))) {
761
DEBUGMSGTL(("smux", "[smux_open_process] version parse failed\n"));
763
return ((ptr += *len));
766
"[smux_open_process] version %d, len %d, type %d\n",
767
version, *len, (int) type));
769
oid_name_len = MAX_OID_LEN;
770
if ((ptr = asn_parse_objid(ptr, len, &type, oid_name,
771
&oid_name_len)) == NULL) {
772
DEBUGMSGTL(("smux", "[smux_open_process] oid parse failed\n"));
774
return ((ptr += *len));
776
snprint_objid(oid_print, sizeof(oid_print), oid_name, oid_name_len);
778
if (snmp_get_do_debugging()) {
779
DEBUGMSGTL(("smux", "[smux_open_process] smux peer: %s\n",
781
DEBUGMSGTL(("smux", "[smux_open_process] len %d, type %d\n", *len,
785
string_len = SMUXMAXSTRLEN;
786
if ((ptr = asn_parse_string(ptr, len, &type, (u_char *) descr,
787
&string_len)) == NULL) {
788
DEBUGMSGTL(("smux", "[smux_open_process] descr parse failed\n"));
790
return ((ptr += *len));
793
if (snmp_get_do_debugging()) {
794
DEBUGMSGTL(("smux", "[smux_open_process] smux peer descr: "));
795
for (i = 0; i < (int) string_len; i++)
796
DEBUGMSG(("smux", "%c", descr[i]));
797
DEBUGMSG(("smux", "\n"));
798
DEBUGMSGTL(("smux", "[smux_open_process] len %d, type %d\n", *len,
801
descr[string_len] = 0;
803
string_len = SMUXMAXSTRLEN;
804
if ((ptr = asn_parse_string(ptr, len, &type, (u_char *) passwd,
805
&string_len)) == NULL) {
806
DEBUGMSGTL(("smux", "[smux_open_process] passwd parse failed\n"));
808
return ((ptr += *len));
811
if (snmp_get_do_debugging()) {
812
DEBUGMSGTL(("smux", "[smux_open_process] smux peer passwd: "));
813
for (i = 0; i < (int) string_len; i++)
814
DEBUGMSG(("smux", "%c", passwd[i]));
815
DEBUGMSG(("smux", "\n"));
816
DEBUGMSGTL(("smux", "[smux_open_process] len %d, type %d\n", *len,
819
passwd[string_len] = '\0';
820
if (!smux_auth_peer(oid_name, oid_name_len, passwd, fd)) {
821
snmp_log(LOG_WARNING,
822
"refused smux peer: oid %s, password %s, descr %s\n",
823
oid_print, passwd, descr);
828
"accepted smux peer: oid %s, password %s, descr %s\n",
829
oid_print, passwd, descr);
835
smux_send_close(int fd, int reason)
837
u_char outpacket[3], *ptr;
841
*(ptr++) = (u_char) SMUX_CLOSE;
842
*(ptr++) = (u_char) 1;
843
*ptr = (u_char) (reason & 0xFF);
845
if (snmp_get_do_debugging())
847
"[smux_close] sending close to fd %d, reason %d\n", fd,
851
* send a response back
853
if (send(fd, (char *) outpacket, 3, 0) < 0) {
854
snmp_log_perror("[smux_snmp_close] send failed");
860
smux_auth_peer(oid * name, size_t namelen, char *passwd, int fd)
864
for (i = 0; i < nauths; i++) {
865
if (snmp_oid_compare(Auths[i]->sa_oid, Auths[i]->sa_oid_len,
866
name, namelen) == 0) {
867
if (!(strcmp(Auths[i]->sa_passwd, passwd)) &&
868
(Auths[i]->sa_active_fd == -1)) {
870
* matched, mark the auth
872
Auths[i]->sa_active_fd = fd;
878
* did not match oid and passwd
885
* XXX - Bells and Whistles:
886
* Need to catch signal when snmpd goes down and send close pdu to gated
889
smux_close_process(int fd, u_char * ptr, size_t * len)
895
* This is the integer part of the close pdu
898
down = (down << 8) | (long) *ptr;
903
"[smux_close_process] close from peer on fd %d reason %d\n",
905
smux_peer_cleanup(fd);
911
smux_rreq_process(int sd, u_char * ptr, size_t * len)
913
long priority, rpriority;
915
oid oid_name[MAX_OID_LEN];
919
smux_reg *rptr, *nrptr;
921
oid_name_len = MAX_OID_LEN;
922
ptr = asn_parse_objid(ptr, len, &type, oid_name, &oid_name_len);
924
DEBUGMSGTL(("smux", "[smux_rreq_process] smux subtree: "));
925
DEBUGMSGOID(("smux", oid_name, oid_name_len));
926
DEBUGMSG(("smux", "\n"));
928
if ((ptr = asn_parse_int(ptr, len, &type, &priority,
929
sizeof(priority))) == NULL) {
931
"[smux_rreq_process] priority parse failed\n"));
932
smux_send_rrsp(sd, -1);
935
DEBUGMSGTL(("smux", "[smux_rreq_process] priority %d\n", priority));
937
if ((ptr = asn_parse_int(ptr, len, &type, &operation,
938
sizeof(operation))) == NULL) {
940
"[smux_rreq_process] operation parse failed\n"));
941
smux_send_rrsp(sd, -1);
944
DEBUGMSGTL(("smux", "[smux_rreq_process] operation %d\n", operation));
946
if (operation == SMUX_REGOP_DELETE) {
948
* search the active list for this registration
951
smux_find_match(ActiveRegs, sd, oid_name, oid_name_len,
954
rpriority = rptr->sr_priority;
958
unregister_mib(rptr->sr_name, rptr->sr_name_len);
963
smux_find_replacement(rptr->sr_name, rptr->sr_name_len);
968
smux_replace_active(rptr, nrptr);
971
* no replacement found
973
smux_list_detach(&ActiveRegs, &rptr);
976
smux_send_rrsp(sd, rpriority);
980
* search the passive list for this registration
983
smux_find_match(PassiveRegs, sd, oid_name, oid_name_len,
986
rpriority = rptr->sr_priority;
987
smux_list_detach(&PassiveRegs, &rptr);
989
smux_send_rrsp(sd, rpriority);
993
* This peer cannot unregister the tree, it does not
994
* * belong to him. Send him an error.
996
smux_send_rrsp(sd, -1);
999
} else if ((operation == SMUX_REGOP_REGISTER_RO) ||
1000
(operation == SMUX_REGOP_REGISTER_RW)) {
1001
if (priority < -1) {
1003
"[smux_rreq_process] peer fd %d invalid priority",
1005
smux_send_rrsp(sd, -1);
1008
if ((nrptr = malloc(sizeof(smux_reg))) == NULL) {
1009
snmp_log_perror("[smux_rreq_process] malloc");
1010
smux_send_rrsp(sd, -1);
1013
nrptr->sr_priority = priority;
1014
nrptr->sr_name_len = oid_name_len;
1016
for (i = 0; i < (int) oid_name_len; i++)
1017
nrptr->sr_name[i] = oid_name[i];
1020
* See if this tree matches or scopes any of the
1023
for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) {
1025
snmp_oid_compare(oid_name, oid_name_len, rptr->sr_name,
1028
if ((oid_name_len == rptr->sr_name_len)) {
1029
if ((nrptr->sr_priority == -1)) {
1030
nrptr->sr_priority = rptr->sr_priority;
1032
nrptr->sr_priority++;
1033
} while (smux_list_add(&PassiveRegs, nrptr));
1035
} else if (nrptr->sr_priority < rptr->sr_priority) {
1037
* Better priority. There are no better
1038
* * priorities for this tree in the passive list,
1039
* * so replace the current active tree.
1041
smux_replace_active(rptr, nrptr);
1045
* Equal or worse priority
1048
nrptr->sr_priority++;
1049
} while (smux_list_add(&PassiveRegs, nrptr) == -1);
1052
} else if (oid_name_len < rptr->sr_name_len) {
1054
* This tree scopes a current active
1055
* * tree. Replace the current active tree.
1057
smux_replace_active(rptr, nrptr);
1059
} else { /* oid_name_len > rptr->sr_name_len */
1061
* This tree is scoped by a current
1065
nrptr->sr_priority++;
1066
} while (smux_list_add(&PassiveRegs, nrptr) == -1);
1072
* We didn't find it in the active list. Add it at
1073
* * the requested priority.
1075
if (nrptr->sr_priority == -1)
1076
nrptr->sr_priority = 0;
1077
smux_list_add(&ActiveRegs, nrptr);
1078
register_mib("smux", (struct variable *)
1079
smux_variables, sizeof(struct variable2),
1080
1, nrptr->sr_name, nrptr->sr_name_len);
1082
smux_send_rrsp(sd, nrptr->sr_priority);
1085
DEBUGMSGTL(("smux", "[smux_rreq_process] unknown operation\n"));
1086
smux_send_rrsp(sd, -1);
1092
* Find the registration with a matching descriptor, OID and priority. If
1093
* the priority is -1 then find a registration with a matching descriptor,
1094
* a matching OID, and the highest priority.
1097
smux_find_match(smux_reg * regs, int sd, oid * oid_name,
1098
size_t oid_name_len, long priority)
1100
smux_reg *rptr, *bestrptr;
1103
for (rptr = regs; rptr; rptr = rptr->sr_next) {
1104
if (rptr->sr_fd != sd)
1106
if (snmp_oid_compare
1107
(rptr->sr_name, rptr->sr_name_len, oid_name, oid_name_len))
1109
if (rptr->sr_priority == priority)
1114
if (bestrptr->sr_priority > rptr->sr_priority)
1124
smux_replace_active(smux_reg * actptr, smux_reg * pasptr)
1126
smux_list_detach(&ActiveRegs, &actptr);
1127
unregister_mib(actptr->sr_name, actptr->sr_name_len);
1129
smux_list_detach(&PassiveRegs, &pasptr);
1130
(void) smux_list_add(&ActiveRegs, pasptr);
1132
register_mib("smux", (struct variable *) smux_variables,
1133
sizeof(struct variable2), 1, pasptr->sr_name,
1134
pasptr->sr_name_len);
1139
smux_list_detach(smux_reg ** head, smux_reg ** m_remove)
1141
smux_reg *rptr, *rptr2;
1143
if (*head == NULL) {
1144
DEBUGMSGTL(("smux", "[smux_list_detach] Ouch!"));
1147
if (*head == *m_remove) {
1149
*head = (*head)->sr_next;
1152
for (rptr = *head, rptr2 = rptr->sr_next; rptr2;
1153
rptr2 = rptr2->sr_next, rptr = rptr->sr_next) {
1154
if (rptr2 == *m_remove) {
1156
rptr->sr_next = rptr2->sr_next;
1163
* Attempt to add a registration (in order) to a list. If the
1164
* add fails (because of an existing registration with equal
1165
* priority) return -1.
1168
smux_list_add(smux_reg ** head, smux_reg * add)
1173
if (*head == NULL) {
1175
(*head)->sr_next = NULL;
1178
for (rptr = *head; rptr->sr_next; rptr = rptr->sr_next) {
1179
result = snmp_oid_compare(add->sr_name, add->sr_name_len,
1180
rptr->sr_name, rptr->sr_name_len);
1181
if ((result == 0) && (add->sr_priority == rptr->sr_priority)) {
1183
* same tree, same pri, nope
1186
} else if (result < 0) {
1188
* this can only happen if we go before the head
1190
add->sr_next = *head;
1193
} else if ((snmp_oid_compare(add->sr_name, add->sr_name_len,
1194
rptr->sr_next->sr_name,
1195
rptr->sr_next->sr_name_len)) < 0) {
1199
add->sr_next = rptr->sr_next;
1200
rptr->sr_next = add;
1205
* compare the last one
1207
if ((snmp_oid_compare(add->sr_name, add->sr_name_len, rptr->sr_name,
1208
rptr->sr_name_len) == 0)
1209
&& add->sr_priority == rptr->sr_priority)
1212
rptr->sr_next = add;
1213
add->sr_next = NULL;
1219
* Find a replacement for this registration. In order
1222
* - Least difference in subtree length
1223
* - Best (lowest) priority
1225
* For example, if we need to replace .1.3.6.1.69,
1226
* we would pick .1.3.6.1.69.1 instead of .1.3.6.69.1.1
1230
smux_find_replacement(oid * name, size_t name_len)
1232
smux_reg *rptr, *bestptr;
1233
int bestlen, difflen;
1235
bestlen = SMUX_MAX_PRIORITY;
1238
for (rptr = PassiveRegs; rptr; rptr = rptr->sr_next) {
1239
if (!snmp_oidtree_compare(rptr->sr_name, rptr->sr_name_len,
1241
if ((difflen = rptr->sr_name_len - name_len)
1245
} else if ((difflen == bestlen) &&
1246
(rptr->sr_priority < bestptr->sr_priority))
1254
smux_snmp_process(int exact,
1257
size_t * return_len, u_char * return_type, int sd)
1259
u_char packet[SMUXMAXPKTSIZE], *ptr, result[SMUXMAXPKTSIZE];
1260
size_t length = SMUXMAXPKTSIZE;
1265
* Send the query to the peer
1272
type = SMUX_GETNEXT;
1274
if (smux_build(type, smux_reqid, objid, len, 0, NULL,
1275
*len, packet, &length) < 0) {
1276
snmp_log(LOG_ERR, "[smux_snmp_process]: smux_build failed\n");
1279
DEBUGMSGTL(("smux", "[smux_snmp_process] oid from build: "));
1280
DEBUGMSGOID(("smux", objid, *len));
1281
DEBUGMSG(("smux", "\n"));
1283
if (send(sd, (char *) packet, length, 0) < 0) {
1284
snmp_log_perror("[smux_snmp_process] send failed");
1288
"[smux_snmp_process] Sent %d request to peer; %d bytes\n",
1289
(int) type, length));
1293
* peek at what's received
1295
length = recv(sd, (char *) result, SMUXMAXPKTSIZE, MSG_PEEK);
1297
snmp_log_perror("[smux_snmp_process] peek failed");
1298
smux_peer_cleanup(sd);
1302
DEBUGMSGTL(("smux", "[smux_snmp_process] Peeked at %d bytes\n",
1304
DEBUGDUMPSETUP("smux_snmp_process", result, length);
1307
* determine if we received more than one packet
1309
packet_len = length;
1310
ptr = asn_parse_header(result, &packet_len, &type);
1311
packet_len += (ptr - result);
1312
if (length > packet_len) {
1314
* set length to receive only the first packet
1316
length = packet_len;
1320
* receive the first packet
1322
length = recv(sd, (char *) result, length, 0);
1324
snmp_log_perror("[smux_snmp_process] recv failed");
1325
smux_peer_cleanup(sd);
1329
DEBUGMSGTL(("smux", "[smux_snmp_process] Received %d bytes\n",
1332
if (result[0] == SMUX_TRAP) {
1333
DEBUGMSGTL(("smux", "[smux_snmp_process] Received trap\n"));
1334
snmp_log(LOG_INFO, "Got trap from peer on fd %d\n", sd);
1335
ptr = asn_parse_header(result, &length, &type);
1336
smux_trap_process(ptr, &length);
1339
* go and peek at received data again
1342
* we could receive the reply or another trap
1348
ptr = smux_parse(result, objid, len, return_len, return_type);
1350
* ptr will point to query result or NULL if error
1360
smux_parse(u_char * rsp,
1362
size_t * oidlen, size_t * return_len, u_char * return_type)
1364
size_t length = SMUXMAXPKTSIZE;
1366
long reqid, errstat, errindex;
1371
* Return pointer to the snmp/smux return value.
1372
* return_len should contain the number of bytes in the value
1374
* objid is the next object, with len for GETNEXT.
1375
* objid and len are not changed for GET
1377
ptr = asn_parse_header(ptr, &length, &type);
1378
if (ptr == NULL || type != SNMP_MSG_RESPONSE)
1381
if ((ptr = asn_parse_int(ptr, &length, &type, &reqid,
1382
sizeof(reqid))) == NULL) {
1383
DEBUGMSGTL(("smux", "[smux_parse] parse of reqid failed\n"));
1386
if ((ptr = asn_parse_int(ptr, &length, &type, &errstat,
1387
sizeof(errstat))) == NULL) {
1389
"[smux_parse] parse of error status failed\n"));
1392
if ((ptr = asn_parse_int(ptr, &length, &type, &errindex,
1393
sizeof(errindex))) == NULL) {
1394
DEBUGMSGTL(("smux", "[smux_parse] parse of error index failed\n"));
1399
* XXX How to send something intelligent back in case of an error
1402
"[smux_parse] Message type %d, reqid %d, errstat %d, \n\terrindex %d\n",
1403
(int) type, reqid, errstat, errindex));
1404
if (ptr == NULL || errstat != SNMP_ERR_NOERROR)
1410
return (smux_parse_var
1411
(ptr, &length, objid, oidlen, return_len, return_type));
1416
smux_parse_var(u_char * varbind,
1417
size_t * varbindlength,
1419
size_t * oidlen, size_t * varlength, u_char * vartype)
1421
oid var_name[MAX_OID_LEN];
1422
size_t var_name_len;
1425
size_t str_len, objid_len;
1431
len = *varbindlength;
1433
DEBUGMSGTL(("smux", "[smux_parse_var] before any processing: "));
1434
DEBUGMSGOID(("smux", objid, *oidlen));
1435
DEBUGMSG(("smux", "\n"));
1437
ptr = asn_parse_header(ptr, &len, &type);
1438
if (ptr == NULL || type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
1439
snmp_log(LOG_NOTICE, "[smux_parse_var] Panic: type %d\n",
1445
* get hold of the objid and the asn1 coded value
1447
var_name_len = MAX_OID_LEN;
1448
ptr = snmp_parse_var_op(ptr, var_name, &var_name_len, vartype,
1449
&var_val_len, &var_val, &len);
1451
*oidlen = var_name_len;
1452
memcpy(objid, var_name, var_name_len * sizeof(oid));
1454
DEBUGMSGTL(("smux", "[smux_parse_var] returning oid : "));
1455
DEBUGMSGOID(("smux", objid, *oidlen));
1456
DEBUGMSG(("smux", "\n"));
1460
len = SMUXMAXPKTSIZE;
1462
"[smux_parse_var] Asn coded len of var %d, type %d\n",
1463
var_val_len, (int) *vartype));
1465
switch ((short) *vartype) {
1467
*varlength = sizeof(long);
1468
asn_parse_int(var_val, &len, vartype,
1469
(long *) &smux_long, *varlength);
1470
return (u_char *) & smux_long;
1476
*varlength = sizeof(u_long);
1477
asn_parse_unsigned_int(var_val, &len, vartype,
1478
(u_long *) & smux_ulong, *varlength);
1479
return (u_char *) & smux_ulong;
1482
*varlength = sizeof(smux_counter64);
1483
asn_parse_unsigned_int64(var_val, &len, vartype,
1484
(struct counter64 *) &smux_counter64,
1486
return (u_char *) & smux_counter64;
1491
* consume the tag and length, but just copy here
1492
* because we know it is an ip address
1494
if ((var_val = asn_parse_header(var_val, &len, &type)) == NULL)
1496
memcpy((u_char *) & (smux_sa.sin_addr.s_addr), var_val,
1498
return (u_char *) & (smux_sa.sin_addr.s_addr);
1506
str_len = SMUXMAXSTRLEN;
1507
asn_parse_string(var_val, &len, vartype, smux_str, &str_len);
1508
*varlength = str_len;
1514
objid_len = MAX_OID_LEN;
1515
asn_parse_objid(var_val, &len, vartype, smux_objid, &objid_len);
1516
*varlength = objid_len * sizeof(oid);
1517
return (u_char *) smux_objid;
1519
case SNMP_NOSUCHOBJECT:
1520
case SNMP_NOSUCHINSTANCE:
1521
case SNMP_ENDOFMIBVIEW:
1531
str_len = SMUXMAXSTRLEN;
1532
asn_parse_bitstring(var_val, &len, vartype, smux_str, &str_len);
1533
*varlength = str_len;
1534
return (u_char *) smux_str;
1537
snmp_log(LOG_ERR, "bad type returned (%x)\n", *vartype);
1544
* XXX This is a bad hack - do not want to muck with ucd code
1547
smux_build(u_char type,
1552
u_char * val, size_t val_len, u_char * packet, size_t * length)
1554
u_char *ptr, *save1, *save2;
1560
* leave space for Seq and length
1569
ptr = asn_build_unsigned_int(ptr, &len,
1570
(u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1571
ASN_INTEGER), &reqid,
1580
ptr = asn_build_int(ptr, &len,
1581
(u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1582
ASN_INTEGER), &errstat, sizeof(errstat));
1590
ptr = asn_build_int(ptr, &len,
1591
(u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1592
ASN_INTEGER), &errindex,
1602
if (type != SMUX_SET) {
1603
val_type = ASN_NULL;
1608
* build var list : snmp_build_var_op not liked by gated XXX
1610
ptr = snmp_build_var_op(ptr, objid, oidlen, val_type, val_len,
1617
asn_build_sequence(save1, &len, type, (ptr - save1 - 4));
1620
asn_build_sequence(save2, &len,
1621
(ASN_SEQUENCE | ASN_CONSTRUCTOR),
1624
*length = ptr - packet;
1630
smux_peer_cleanup(int sd)
1632
smux_reg *nrptr, *rptr, *rptr2;
1638
* close the descriptor
1643
* delete all of the passive registrations that this peer owns
1645
for (rptr = PassiveRegs; rptr; rptr = nrptr) {
1646
nrptr = rptr->sr_next;
1647
if (rptr->sr_fd == sd) {
1648
smux_list_detach(&PassiveRegs, &rptr);
1654
* find replacements for all of the active registrations found
1656
for (rptr = ActiveRegs; rptr; rptr = rptr2) {
1657
rptr2 = rptr->sr_next;
1658
if (rptr->sr_fd == sd) {
1659
smux_list_detach(&ActiveRegs, &rptr);
1660
unregister_mib(rptr->sr_name, rptr->sr_name_len);
1661
if ((nrptr = smux_find_replacement(rptr->sr_name,
1662
rptr->sr_name_len)) !=
1664
smux_list_detach(&PassiveRegs, &nrptr);
1665
smux_list_add(&ActiveRegs, nrptr);
1666
register_mib("smux", (struct variable *)
1667
smux_variables, sizeof(struct variable2),
1668
1, nrptr->sr_name, nrptr->sr_name_len);
1675
* decrement the peer count
1680
* make his auth available again
1682
for (i = 0; i < nauths; i++) {
1683
if (Auths[i]->sa_active_fd == sd) {
1685
Auths[i]->sa_active_fd = -1;
1686
snprint_objid(oid_name, sizeof(oid_name), Auths[i]->sa_oid,
1687
Auths[i]->sa_oid_len);
1688
snmp_log(LOG_INFO, "peer disconnected: %s\n", oid_name);
1694
smux_send_rrsp(int sd, int pri)
1696
u_char outdata[2 + sizeof(int)];
1697
u_char *ptr = outdata;
1698
int intsize = sizeof(int);
1699
u_int mask = ((u_int) 0xFF) << (8 * (sizeof(int) - 1));
1701
* e.g. mask is 0xFF000000 on a 32-bit machine
1706
* This is kind of like calling asn_build_int(), but the
1707
* encoding will always be the size of an integer on this
1708
* machine, never shorter.
1710
*ptr++ = (u_char) SMUX_RRSP;
1711
*ptr++ = (u_char) intsize;
1714
* Copy each byte, most significant first.
1717
*ptr++ = (u_char) ((pri & mask) >> (8 * (sizeof(int) - 1)));
1721
sent = send(sd, (char *) outdata, sizeof outdata, 0);
1723
DEBUGMSGTL(("smux", "[smux_send_rrsp] send failed\n"));
1729
smux_trap_process(u_char * rsp, size_t * len)
1731
oid sa_enterpriseoid[MAX_OID_LEN], var_name[MAX_OID_LEN];
1732
size_t datalen, var_name_len, var_val_len, maxlen;
1733
size_t sa_enterpriseoid_len;
1734
u_char vartype, *ptr, *var_val;
1736
long trap, specific;
1739
netsnmp_variable_list *snmptrap_head, *snmptrap_ptr, *snmptrap_tmp;
1740
snmptrap_head = NULL;
1741
snmptrap_ptr = NULL;
1746
* parse the sub-agent enterprise oid
1748
datalen = MAX_OID_LEN;
1749
if ((ptr = asn_parse_objid(ptr, len,
1750
&vartype, (oid *) & sa_enterpriseoid,
1751
&sa_enterpriseoid_len)) == NULL) {
1753
"[smux_trap_process] asn_parse_objid failed\n"));
1758
* parse the agent-addr ipAddress
1760
datalen = SMUXMAXSTRLEN;
1761
if (((ptr = asn_parse_string(ptr, len,
1763
&datalen)) == NULL) ||
1764
(vartype != (u_char) ASN_IPADDRESS)) {
1766
"[smux_trap_process] asn_parse_string failed\n"));
1771
* parse the generic trap int
1773
datalen = sizeof(long);
1774
if ((ptr = asn_parse_int(ptr, len, &vartype, &trap, datalen)) == NULL) {
1776
"[smux_trap_process] asn_parse_int generic failed\n"));
1781
* parse the specific trap int
1783
datalen = sizeof(long);
1784
if ((ptr = asn_parse_int(ptr, len,
1785
&vartype, &specific, datalen)) == NULL) {
1787
"[smux_trap_process] asn_parse_int specific failed\n"));
1792
* parse the timeticks timestamp
1794
datalen = sizeof(u_long);
1795
if (((ptr = asn_parse_unsigned_int(ptr, len,
1796
&vartype, (u_long *) & timestamp,
1797
datalen)) == NULL) ||
1798
(vartype != (u_char) ASN_TIMETICKS)) {
1800
"[smux_trap_process] asn_parse_unsigned_int (timestamp) failed\n"));
1805
* parse out the overall sequence
1807
ptr = asn_parse_header(ptr, len, &vartype);
1808
if (ptr == NULL || vartype != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
1813
* parse the variable bindings
1815
while (ptr && *len) {
1818
* get the objid and the asn1 coded value
1820
var_name_len = MAX_OID_LEN;
1821
ptr = snmp_parse_var_op(ptr, var_name, &var_name_len, &vartype,
1822
&var_val_len, (u_char **) & var_val, len);
1828
maxlen = SMUXMAXPKTSIZE;
1829
switch ((short) vartype) {
1831
var_val_len = sizeof(long);
1832
asn_parse_int(var_val, &maxlen, &vartype,
1833
(long *) &smux_long, var_val_len);
1834
var_val = (u_char *) & smux_long;
1840
var_val_len = sizeof(u_long);
1841
asn_parse_unsigned_int(var_val, &maxlen, &vartype,
1842
(u_long *) & smux_ulong, var_val_len);
1843
var_val = (u_char *) & smux_ulong;
1846
var_val_len = sizeof(smux_counter64);
1847
asn_parse_unsigned_int64(var_val, &maxlen, &vartype,
1848
(struct counter64 *) &smux_counter64,
1850
var_val = (u_char *) & smux_counter64;
1855
* consume the tag and length, but just copy here
1856
* because we know it is an ip address
1859
asn_parse_header(var_val, &maxlen, &vartype)) == NULL)
1861
memcpy((u_char *) & (smux_sa.sin_addr.s_addr), var_val,
1863
var_val = (u_char *) & (smux_sa.sin_addr.s_addr);
1872
var_val_len = SMUXMAXSTRLEN;
1873
asn_parse_string(var_val, &maxlen, &vartype,
1874
smux_str, &var_val_len);
1878
var_val_len = MAX_OID_LEN;
1879
asn_parse_objid(var_val, &maxlen, &vartype,
1880
smux_objid, &var_val_len);
1881
var_val_len *= sizeof(oid);
1882
var_val = (u_char *) smux_objid;
1884
case SNMP_NOSUCHOBJECT:
1885
case SNMP_NOSUCHINSTANCE:
1886
case SNMP_ENDOFMIBVIEW:
1896
var_val_len = SMUXMAXSTRLEN;
1897
asn_parse_bitstring(var_val, &maxlen, &vartype,
1898
smux_str, &var_val_len);
1899
var_val = (u_char *) smux_str;
1903
snmp_log(LOG_ERR, "bad type returned (%x)\n", vartype);
1909
(netsnmp_variable_list *)
1910
malloc(sizeof(netsnmp_variable_list));
1911
if (snmptrap_tmp == NULL)
1913
memset(snmptrap_tmp, 0, sizeof(netsnmp_variable_list));
1914
if (snmptrap_head == NULL) {
1915
snmptrap_head = snmptrap_tmp;
1916
snmptrap_ptr = snmptrap_head;
1918
snmptrap_ptr->next_variable = snmptrap_tmp;
1919
snmptrap_ptr = snmptrap_ptr->next_variable;
1922
snmp_set_var_objid(snmptrap_ptr, var_name, var_name_len);
1923
snmp_set_var_value(snmptrap_ptr, (char *) var_val, var_val_len);
1924
snmptrap_ptr->type = vartype;
1925
snmptrap_ptr->next_variable = NULL;
1932
send_enterprise_trap_vars(trap, specific, (oid *) & sa_enterpriseoid,
1933
sa_enterpriseoid_len, snmptrap_head);
1936
* free trap variables
1938
snmp_free_varbind(snmptrap_head);