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_peer_auth(const char *token, char *cptr)
132 smux_peer_auth *aptr;
135 (smux_peer_auth *) calloc(1, sizeof(smux_peer_auth))) == NULL) {
136 snmp_log_perror("smux_parse_peer_auth: malloc");
139 aptr->sa_active_fd = -1;
144 Auths[nauths++] = aptr;
145 DEBUGMSGTL(("smux_conf", "null password\n"));
152 if (!isdigit(*cptr)) {
153 config_perror("second token is not an OID");
160 aptr->sa_oid_len = parse_miboid(cptr, aptr->sa_oid);
162 DEBUGMSGTL(("smux_conf", "parsing registration for: %s\n", cptr));
164 while (isdigit(*cptr) || *cptr == '.')
166 cptr = skip_white(cptr);
172 strcpy(aptr->sa_passwd, cptr);
174 Auths[nauths++] = aptr;
178 smux_free_peer_auth(void)
182 for (i = 0; i < nauths; i++) {
193 struct sockaddr_in lo_socket;
196 if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) {
201 snmpd_register_config_handler("smuxpeer", smux_parse_peer_auth,
203 "OID-IDENTITY PASSWORD");
213 smux_rcv_timeout.tv_sec = 0;
214 smux_rcv_timeout.tv_usec = 500000;
217 * Get ready to listen on the SMUX port
219 memset(&lo_socket, (0), sizeof(lo_socket));
220 lo_socket.sin_family = AF_INET;
221 lo_socket.sin_port = htons((u_short) SMUXPORT);
223 if ((smux_listen_sd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
224 snmp_log_perror("[init_smux] socket failed");
229 * At least on Linux, when the master agent terminates, any
230 * TCP connections for SMUX peers are put in the TIME_WAIT
231 * state for about 60 seconds. If the master agent is started
232 * during this time, the bind for the listening socket will
233 * fail because the SMUX port is in use.
235 if (setsockopt(smux_listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
237 snmp_log_perror("[init_smux] setsockopt(SO_REUSEADDR) failed");
239 #endif /* SO_REUSEADDR */
241 if (bind(smux_listen_sd, (struct sockaddr *) &lo_socket,
242 sizeof(lo_socket)) < 0) {
243 snmp_log_perror("[init_smux] bind failed");
244 close(smux_listen_sd);
249 if (setsockopt(smux_listen_sd, SOL_SOCKET, SO_KEEPALIVE, (char *) &one,
251 snmp_log_perror("[init_smux] setsockopt(SO_KEEPALIVE) failed");
252 close(smux_listen_sd);
256 #endif /* SO_KEEPALIVE */
258 if (listen(smux_listen_sd, SOMAXCONN) == -1) {
259 snmp_log_perror("[init_smux] listen failed");
260 close(smux_listen_sd);
265 DEBUGMSGTL(("smux_init",
266 "[smux_init] done; smux listen sd is %d, smux port is %d\n",
267 smux_listen_sd, ntohs(lo_socket.sin_port)));
271 var_smux(struct variable * vp,
274 int exact, size_t * var_len, WriteMethod ** write_method)
276 u_char *valptr, val_type;
279 *write_method = var_smux_write;
281 * search the active registration list
283 for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) {
284 if (0 >= snmp_oidtree_compare(vp->name, vp->namelen, rptr->sr_name,
290 else if (exact && (*length < rptr->sr_name_len))
293 valptr = smux_snmp_process(exact, name, length,
294 var_len, &val_type, rptr->sr_fd);
299 if ((snmp_oidtree_compare(name, *length, rptr->sr_name,
300 rptr->sr_name_len)) != 0) {
302 * the peer has returned a value outside
303 * * of the registered tree
308 * set the type and return the value
316 var_smux_write(int action,
320 u_char * statP, oid * name, size_t name_len)
323 u_char buf[SMUXMAXPKTSIZE], *ptr, sout[3], type;
325 size_t var_len, datalen, name_length, packet_len;
327 long reqid, errsts, erridx;
328 u_char var_type, *dataptr;
330 DEBUGMSGTL(("smux", "[var_smux_write] entering var_smux_write\n"));
332 len = SMUXMAXPKTSIZE;
333 reterr = SNMP_ERR_NOERROR;
334 var_len = var_val_len;
335 var_type = var_val_type;
336 name_length = name_len;
339 * XXX find the descriptor again
341 for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) {
342 if (!snmp_oidtree_compare(name, name_len, rptr->sr_name,
349 DEBUGMSGTL(("smux", "[var_smux_write] entering RESERVE1\n"));
352 * length might be long
354 var_len += (*(var_val + 1) & ASN_LONG_LEN) ?
355 var_len + ((*(var_val + 1) & 0x7F) + 2) : 2;
357 switch (var_val_type) {
370 datalen = var_val_len;
373 case SNMP_NOSUCHOBJECT:
374 case SNMP_NOSUCHINSTANCE:
375 case SNMP_ENDOFMIBVIEW:
379 "[var_smux_write] variable not supported\n"));
380 return SNMP_ERR_GENERR;
384 if ((smux_build((u_char) SMUX_SET, smux_reqid,
385 name, &name_length, var_val_type, dataptr,
386 datalen, buf, &len)) < 0) {
387 DEBUGMSGTL(("smux", "[var_smux_write] smux build failed\n"));
388 return SNMP_ERR_GENERR;
391 if (send(rptr->sr_fd, buf, len, 0) < 0) {
392 DEBUGMSGTL(("smux", "[var_smux_write] send failed\n"));
393 return SNMP_ERR_GENERR;
398 * peek at what's received
400 if ((len = recv(rptr->sr_fd, buf,
401 SMUXMAXPKTSIZE, MSG_PEEK)) <= 0) {
403 "[var_smux_write] peek failed or timed out\n"));
405 * do we need to do a peer cleanup in this case??
407 smux_peer_cleanup(rptr->sr_fd);
408 return SNMP_ERR_GENERR;
411 DEBUGMSGTL(("smux", "[var_smux_write] Peeked at %d bytes\n",
413 DEBUGDUMPSETUP("var_smux_write", buf, len);
416 * determine if we received more than one packet
419 ptr = asn_parse_header(buf, &packet_len, &type);
420 packet_len += (ptr - buf);
421 if (len > packet_len) {
423 * set length to receive only the first packet
429 * receive the first packet
431 if ((len = recv(rptr->sr_fd, buf, len, 0)) <= 0) {
433 "[var_smux_write] recv failed or timed out\n"));
435 * do we need to do a peer cleanup in this case??
437 smux_peer_cleanup(rptr->sr_fd);
438 return SNMP_ERR_GENERR;
441 DEBUGMSGTL(("smux", "[var_smux_write] Received %d bytes\n",
444 if (buf[0] == SMUX_TRAP) {
445 DEBUGMSGTL(("smux", "[var_smux_write] Received trap\n"));
446 snmp_log(LOG_INFO, "Got trap from peer on fd %d\n",
448 ptr = asn_parse_header(buf, &len, &type);
449 smux_trap_process(ptr, &len);
453 * go and peek at received data again
456 * we could receive the reply or another trap
460 ptr = asn_parse_header(ptr, &len, &type);
461 if ((ptr == NULL) || type != SNMP_MSG_RESPONSE)
462 return SNMP_ERR_GENERR;
465 asn_parse_int(ptr, &len, &type, &reqid, sizeof(reqid));
466 if ((ptr == NULL) || type != ASN_INTEGER)
467 return SNMP_ERR_GENERR;
470 asn_parse_int(ptr, &len, &type, &errsts,
472 if ((ptr == NULL) || type != ASN_INTEGER)
473 return SNMP_ERR_GENERR;
477 "[var_smux_write] errsts returned\n"));
482 asn_parse_int(ptr, &len, &type, &erridx,
484 if ((ptr == NULL) || type != ASN_INTEGER)
485 return SNMP_ERR_GENERR;
487 reterr = SNMP_ERR_NOERROR;
491 break; /* case Action == RESERVE1 */
494 DEBUGMSGTL(("smux", "[var_smux_write] entering RESERVE2\n"));
495 reterr = SNMP_ERR_NOERROR;
496 break; /* case Action == RESERVE2 */
501 *(ptr++) = (u_char) SMUX_SOUT;
502 *(ptr++) = (u_char) 1;
503 if (action == FREE) {
504 *ptr = (u_char) 1; /* rollback */
506 "[var_smux_write] entering FREE - sending RollBack \n"));
508 *ptr = (u_char) 0; /* commit */
510 "[var_smux_write] entering FREE - sending Commit \n"));
513 if ((send(rptr->sr_fd, sout, 3, 0)) < 0) {
515 "[var_smux_write] send rollback/commit failed\n"));
516 return SNMP_ERR_GENERR;
519 reterr = SNMP_ERR_NOERROR;
520 break; /* case Action == COMMIT */
532 u_char data[SMUXMAXPKTSIZE], *ptr, type;
533 struct sockaddr_in in_socket;
538 alen = sizeof(struct sockaddr_in);
540 * this may be too high
548 DEBUGMSGTL(("smux", "[smux_accept] Calling accept()\n"));
550 if ((fd = accept(sd, (struct sockaddr *) &in_socket, &alen)) < 0) {
551 snmp_log_perror("[smux_accept] accept failed");
554 snmp_log(LOG_INFO, "[smux_accept] accepted fd %d from %s:%d\n",
555 fd, inet_ntoa(in_socket.sin_addr),
556 ntohs(in_socket.sin_port));
557 if (npeers + 1 == SMUXMAXPEERS) {
559 "[smux_accept] denied peer on fd %d, limit %d reached",
566 * now block for an OpenPDU
568 if ((length = recv(fd, (char *) data, SMUXMAXPKTSIZE, 0)) <= 0) {
570 "[smux_accept] peer on fd %d died or timed out\n",
576 * try to authorize him
580 if ((ptr = asn_parse_header(ptr, &len, &type)) == NULL) {
581 smux_send_close(fd, SMUXC_PACKETFORMAT);
583 DEBUGMSGTL(("smux", "[smux_accept] peer on %d sent bad open"));
585 } else if (type != (u_char) SMUX_OPEN) {
586 smux_send_close(fd, SMUXC_PROTOCOLERROR);
589 "[smux_accept] peer on %d did not send open: (%d)\n",
593 ptr = smux_open_process(fd, ptr, &len, &fail);
595 smux_send_close(fd, SMUXC_AUTHENTICATIONFAILURE);
598 "[smux_accept] peer on %d failed authentication\n",
608 (fd, SOL_SOCKET, SO_RCVTIMEO, (void *) &tv, sizeof(tv)) < 0) {
610 "[smux_accept] setsockopt(SO_RCVTIMEO) failed fd %d\n",
612 snmp_log_perror("smux_accept: setsockopt SO_RCVTIMEO");
616 DEBUGMSGTL(("smux", "[smux_accept] fd %d\n", fd));
619 * Process other PDUs already read, e.g. a registerRequest.
621 len = length - (ptr - data);
622 if (smux_pdu_process(fd, ptr, len) < 0) {
624 * Easy come, easy go. Clean-up is already done.
636 u_char data[SMUXMAXPKTSIZE];
638 length = recv(fd, (char *) data, SMUXMAXPKTSIZE, 0);
641 * the peer went away, close this descriptor
642 * * and delete it from the list
645 "[smux_process] peer on fd %d died or timed out\n",
647 smux_peer_cleanup(fd);
651 return smux_pdu_process(fd, data, length);
655 smux_pdu_process(int fd, u_char * data, size_t length)
661 DEBUGMSGTL(("smux", "[smux_pdu_process] Processing %d bytes\n",
666 while (error == 0 && ptr != NULL && ptr < data + length) {
667 len = length - (ptr - data);
668 ptr = asn_parse_header(ptr, &len, &type);
669 DEBUGMSGTL(("smux", "[smux_pdu_process] type is %d\n",
673 smux_send_close(fd, SMUXC_PROTOCOLERROR);
675 "[smux_pdu_process] peer on fd %d sent duplicate open?\n",
677 smux_peer_cleanup(fd);
681 ptr = smux_close_process(fd, ptr, &len);
682 smux_peer_cleanup(fd);
686 ptr = smux_rreq_process(fd, ptr, &len);
690 smux_send_close(fd, SMUXC_PROTOCOLERROR);
691 smux_peer_cleanup(fd);
693 "[smux_pdu_process] peer on fd %d sent RRSP!\n",
698 smux_send_close(fd, SMUXC_PROTOCOLERROR);
699 smux_peer_cleanup(fd);
700 DEBUGMSGTL(("smux", "This shouldn't have happened!\n"));
703 snmp_log(LOG_INFO, "Got trap from peer on fd %d\n", fd);
704 ptr = smux_trap_process(ptr, &len);
706 * watch out for close on top of this...should return correct end
714 smux_send_close(fd, SMUXC_PACKETFORMAT);
715 smux_peer_cleanup(fd);
716 DEBUGMSGTL(("smux", "[smux_pdu_process] Wrong type %d\n",
726 smux_open_process(int fd, u_char * ptr, size_t * len, int *fail)
730 oid oid_name[MAX_OID_LEN];
731 char passwd[SMUXMAXSTRLEN];
732 char descr[SMUXMAXSTRLEN];
733 char oid_print[SMUXMAXSTRLEN];
735 size_t oid_name_len, string_len;
737 if (!(ptr = asn_parse_int(ptr, len, &type, &version, sizeof(version)))) {
738 DEBUGMSGTL(("smux", "[smux_open_process] version parse failed\n"));
740 return ((ptr += *len));
743 "[smux_open_process] version %d, len %d, type %d\n",
744 version, *len, (int) type));
746 oid_name_len = MAX_OID_LEN;
747 if ((ptr = asn_parse_objid(ptr, len, &type, oid_name,
748 &oid_name_len)) == NULL) {
749 DEBUGMSGTL(("smux", "[smux_open_process] oid parse failed\n"));
751 return ((ptr += *len));
753 snprint_objid(oid_print, sizeof(oid_print), oid_name, oid_name_len);
755 if (snmp_get_do_debugging()) {
756 DEBUGMSGTL(("smux", "[smux_open_process] smux peer: %s\n",
758 DEBUGMSGTL(("smux", "[smux_open_process] len %d, type %d\n", *len,
762 string_len = SMUXMAXSTRLEN;
763 if ((ptr = asn_parse_string(ptr, len, &type, (u_char *) descr,
764 &string_len)) == NULL) {
765 DEBUGMSGTL(("smux", "[smux_open_process] descr parse failed\n"));
767 return ((ptr += *len));
770 if (snmp_get_do_debugging()) {
771 DEBUGMSGTL(("smux", "[smux_open_process] smux peer descr: "));
772 for (i = 0; i < (int) string_len; i++)
773 DEBUGMSG(("smux", "%c", descr[i]));
774 DEBUGMSG(("smux", "\n"));
775 DEBUGMSGTL(("smux", "[smux_open_process] len %d, type %d\n", *len,
778 descr[string_len] = 0;
780 string_len = SMUXMAXSTRLEN;
781 if ((ptr = asn_parse_string(ptr, len, &type, (u_char *) passwd,
782 &string_len)) == NULL) {
783 DEBUGMSGTL(("smux", "[smux_open_process] passwd parse failed\n"));
785 return ((ptr += *len));
788 if (snmp_get_do_debugging()) {
789 DEBUGMSGTL(("smux", "[smux_open_process] smux peer passwd: "));
790 for (i = 0; i < (int) string_len; i++)
791 DEBUGMSG(("smux", "%c", passwd[i]));
792 DEBUGMSG(("smux", "\n"));
793 DEBUGMSGTL(("smux", "[smux_open_process] len %d, type %d\n", *len,
796 passwd[string_len] = '\0';
797 if (!smux_auth_peer(oid_name, oid_name_len, passwd, fd)) {
798 snmp_log(LOG_WARNING,
799 "refused smux peer: oid %s, password %s, descr %s\n",
800 oid_print, passwd, descr);
805 "accepted smux peer: oid %s, password %s, descr %s\n",
806 oid_print, passwd, descr);
812 smux_send_close(int fd, int reason)
814 u_char outpacket[3], *ptr;
818 *(ptr++) = (u_char) SMUX_CLOSE;
819 *(ptr++) = (u_char) 1;
820 *ptr = (u_char) (reason & 0xFF);
822 if (snmp_get_do_debugging())
824 "[smux_close] sending close to fd %d, reason %d\n", fd,
828 * send a response back
830 if (send(fd, (char *) outpacket, 3, 0) < 0) {
831 snmp_log_perror("[smux_snmp_close] send failed");
837 smux_auth_peer(oid * name, size_t namelen, char *passwd, int fd)
841 for (i = 0; i < nauths; i++) {
842 if (snmp_oid_compare(Auths[i]->sa_oid, Auths[i]->sa_oid_len,
843 name, namelen) == 0) {
844 if (!(strcmp(Auths[i]->sa_passwd, passwd)) &&
845 (Auths[i]->sa_active_fd == -1)) {
847 * matched, mark the auth
849 Auths[i]->sa_active_fd = fd;
855 * did not match oid and passwd
862 * XXX - Bells and Whistles:
863 * Need to catch signal when snmpd goes down and send close pdu to gated
866 smux_close_process(int fd, u_char * ptr, size_t * len)
872 * This is the integer part of the close pdu
875 down = (down << 8) | (long) *ptr;
880 "[smux_close_process] close from peer on fd %d reason %d\n",
882 smux_peer_cleanup(fd);
888 smux_rreq_process(int sd, u_char * ptr, size_t * len)
890 long priority, rpriority;
892 oid oid_name[MAX_OID_LEN];
896 smux_reg *rptr, *nrptr;
898 oid_name_len = MAX_OID_LEN;
899 ptr = asn_parse_objid(ptr, len, &type, oid_name, &oid_name_len);
901 DEBUGMSGTL(("smux", "[smux_rreq_process] smux subtree: "));
902 DEBUGMSGOID(("smux", oid_name, oid_name_len));
903 DEBUGMSG(("smux", "\n"));
905 if ((ptr = asn_parse_int(ptr, len, &type, &priority,
906 sizeof(priority))) == NULL) {
908 "[smux_rreq_process] priority parse failed\n"));
909 smux_send_rrsp(sd, -1);
912 DEBUGMSGTL(("smux", "[smux_rreq_process] priority %d\n", priority));
914 if ((ptr = asn_parse_int(ptr, len, &type, &operation,
915 sizeof(operation))) == NULL) {
917 "[smux_rreq_process] operation parse failed\n"));
918 smux_send_rrsp(sd, -1);
921 DEBUGMSGTL(("smux", "[smux_rreq_process] operation %d\n", operation));
923 if (operation == SMUX_REGOP_DELETE) {
925 * search the active list for this registration
928 smux_find_match(ActiveRegs, sd, oid_name, oid_name_len,
931 rpriority = rptr->sr_priority;
935 unregister_mib(rptr->sr_name, rptr->sr_name_len);
940 smux_find_replacement(rptr->sr_name, rptr->sr_name_len);
945 smux_replace_active(rptr, nrptr);
948 * no replacement found
950 smux_list_detach(&ActiveRegs, &rptr);
953 smux_send_rrsp(sd, rpriority);
957 * search the passive list for this registration
960 smux_find_match(PassiveRegs, sd, oid_name, oid_name_len,
963 rpriority = rptr->sr_priority;
964 smux_list_detach(&PassiveRegs, &rptr);
966 smux_send_rrsp(sd, rpriority);
970 * This peer cannot unregister the tree, it does not
971 * * belong to him. Send him an error.
973 smux_send_rrsp(sd, -1);
976 } else if ((operation == SMUX_REGOP_REGISTER_RO) ||
977 (operation == SMUX_REGOP_REGISTER_RW)) {
980 "[smux_rreq_process] peer fd %d invalid priority",
982 smux_send_rrsp(sd, -1);
985 if ((nrptr = malloc(sizeof(smux_reg))) == NULL) {
986 snmp_log_perror("[smux_rreq_process] malloc");
987 smux_send_rrsp(sd, -1);
990 nrptr->sr_priority = priority;
991 nrptr->sr_name_len = oid_name_len;
993 for (i = 0; i < (int) oid_name_len; i++)
994 nrptr->sr_name[i] = oid_name[i];
997 * See if this tree matches or scopes any of the
1000 for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) {
1002 snmp_oid_compare(oid_name, oid_name_len, rptr->sr_name,
1005 if ((oid_name_len == rptr->sr_name_len)) {
1006 if ((nrptr->sr_priority == -1)) {
1007 nrptr->sr_priority = rptr->sr_priority;
1009 nrptr->sr_priority++;
1010 } while (smux_list_add(&PassiveRegs, nrptr));
1012 } else if (nrptr->sr_priority < rptr->sr_priority) {
1014 * Better priority. There are no better
1015 * * priorities for this tree in the passive list,
1016 * * so replace the current active tree.
1018 smux_replace_active(rptr, nrptr);
1022 * Equal or worse priority
1025 nrptr->sr_priority++;
1026 } while (smux_list_add(&PassiveRegs, nrptr) == -1);
1029 } else if (oid_name_len < rptr->sr_name_len) {
1031 * This tree scopes a current active
1032 * * tree. Replace the current active tree.
1034 smux_replace_active(rptr, nrptr);
1036 } else { /* oid_name_len > rptr->sr_name_len */
1038 * This tree is scoped by a current
1042 nrptr->sr_priority++;
1043 } while (smux_list_add(&PassiveRegs, nrptr) == -1);
1049 * We didn't find it in the active list. Add it at
1050 * * the requested priority.
1052 if (nrptr->sr_priority == -1)
1053 nrptr->sr_priority = 0;
1054 smux_list_add(&ActiveRegs, nrptr);
1055 register_mib("smux", (struct variable *)
1056 smux_variables, sizeof(struct variable2),
1057 1, nrptr->sr_name, nrptr->sr_name_len);
1059 smux_send_rrsp(sd, nrptr->sr_priority);
1062 DEBUGMSGTL(("smux", "[smux_rreq_process] unknown operation\n"));
1063 smux_send_rrsp(sd, -1);
1069 * Find the registration with a matching descriptor, OID and priority. If
1070 * the priority is -1 then find a registration with a matching descriptor,
1071 * a matching OID, and the highest priority.
1074 smux_find_match(smux_reg * regs, int sd, oid * oid_name,
1075 size_t oid_name_len, long priority)
1077 smux_reg *rptr, *bestrptr;
1080 for (rptr = regs; rptr; rptr = rptr->sr_next) {
1081 if (rptr->sr_fd != sd)
1083 if (snmp_oid_compare
1084 (rptr->sr_name, rptr->sr_name_len, oid_name, oid_name_len))
1086 if (rptr->sr_priority == priority)
1091 if (bestrptr->sr_priority > rptr->sr_priority)
1101 smux_replace_active(smux_reg * actptr, smux_reg * pasptr)
1103 smux_list_detach(&ActiveRegs, &actptr);
1104 unregister_mib(actptr->sr_name, actptr->sr_name_len);
1106 smux_list_detach(&PassiveRegs, &pasptr);
1107 (void) smux_list_add(&ActiveRegs, pasptr);
1109 register_mib("smux", (struct variable *) smux_variables,
1110 sizeof(struct variable2), 1, pasptr->sr_name,
1111 pasptr->sr_name_len);
1116 smux_list_detach(smux_reg ** head, smux_reg ** m_remove)
1118 smux_reg *rptr, *rptr2;
1120 if (*head == NULL) {
1121 DEBUGMSGTL(("smux", "[smux_list_detach] Ouch!"));
1124 if (*head == *m_remove) {
1126 *head = (*head)->sr_next;
1129 for (rptr = *head, rptr2 = rptr->sr_next; rptr2;
1130 rptr2 = rptr2->sr_next, rptr = rptr->sr_next) {
1131 if (rptr2 == *m_remove) {
1133 rptr->sr_next = rptr2->sr_next;
1140 * Attempt to add a registration (in order) to a list. If the
1141 * add fails (because of an existing registration with equal
1142 * priority) return -1.
1145 smux_list_add(smux_reg ** head, smux_reg * add)
1150 if (*head == NULL) {
1152 (*head)->sr_next = NULL;
1155 for (rptr = *head; rptr->sr_next; rptr = rptr->sr_next) {
1156 result = snmp_oid_compare(add->sr_name, add->sr_name_len,
1157 rptr->sr_name, rptr->sr_name_len);
1158 if ((result == 0) && (add->sr_priority == rptr->sr_priority)) {
1160 * same tree, same pri, nope
1163 } else if (result < 0) {
1165 * this can only happen if we go before the head
1167 add->sr_next = *head;
1170 } else if ((snmp_oid_compare(add->sr_name, add->sr_name_len,
1171 rptr->sr_next->sr_name,
1172 rptr->sr_next->sr_name_len)) < 0) {
1176 add->sr_next = rptr->sr_next;
1177 rptr->sr_next = add;
1182 * compare the last one
1184 if ((snmp_oid_compare(add->sr_name, add->sr_name_len, rptr->sr_name,
1185 rptr->sr_name_len) == 0)
1186 && add->sr_priority == rptr->sr_priority)
1189 rptr->sr_next = add;
1190 add->sr_next = NULL;
1196 * Find a replacement for this registration. In order
1199 * - Least difference in subtree length
1200 * - Best (lowest) priority
1202 * For example, if we need to replace .1.3.6.1.69,
1203 * we would pick .1.3.6.1.69.1 instead of .1.3.6.69.1.1
1207 smux_find_replacement(oid * name, size_t name_len)
1209 smux_reg *rptr, *bestptr;
1210 int bestlen, difflen;
1212 bestlen = SMUX_MAX_PRIORITY;
1215 for (rptr = PassiveRegs; rptr; rptr = rptr->sr_next) {
1216 if (!snmp_oidtree_compare(rptr->sr_name, rptr->sr_name_len,
1218 if ((difflen = rptr->sr_name_len - name_len)
1222 } else if ((difflen == bestlen) &&
1223 (rptr->sr_priority < bestptr->sr_priority))
1231 smux_snmp_process(int exact,
1234 size_t * return_len, u_char * return_type, int sd)
1236 u_char packet[SMUXMAXPKTSIZE], *ptr, result[SMUXMAXPKTSIZE];
1237 size_t length = SMUXMAXPKTSIZE;
1242 * Send the query to the peer
1249 type = SMUX_GETNEXT;
1251 if (smux_build(type, smux_reqid, objid, len, 0, NULL,
1252 *len, packet, &length) < 0) {
1253 snmp_log(LOG_ERR, "[smux_snmp_process]: smux_build failed\n");
1256 DEBUGMSGTL(("smux", "[smux_snmp_process] oid from build: "));
1257 DEBUGMSGOID(("smux", objid, *len));
1258 DEBUGMSG(("smux", "\n"));
1260 if (send(sd, (char *) packet, length, 0) < 0) {
1261 snmp_log_perror("[smux_snmp_process] send failed");
1265 "[smux_snmp_process] Sent %d request to peer; %d bytes\n",
1266 (int) type, length));
1270 * peek at what's received
1272 length = recv(sd, (char *) result, SMUXMAXPKTSIZE, MSG_PEEK);
1274 snmp_log_perror("[smux_snmp_process] peek failed");
1275 smux_peer_cleanup(sd);
1279 DEBUGMSGTL(("smux", "[smux_snmp_process] Peeked at %d bytes\n",
1281 DEBUGDUMPSETUP("smux_snmp_process", result, length);
1284 * determine if we received more than one packet
1286 packet_len = length;
1287 ptr = asn_parse_header(result, &packet_len, &type);
1288 packet_len += (ptr - result);
1289 if (length > packet_len) {
1291 * set length to receive only the first packet
1293 length = packet_len;
1297 * receive the first packet
1299 length = recv(sd, (char *) result, length, 0);
1301 snmp_log_perror("[smux_snmp_process] recv failed");
1302 smux_peer_cleanup(sd);
1306 DEBUGMSGTL(("smux", "[smux_snmp_process] Received %d bytes\n",
1309 if (result[0] == SMUX_TRAP) {
1310 DEBUGMSGTL(("smux", "[smux_snmp_process] Received trap\n"));
1311 snmp_log(LOG_INFO, "Got trap from peer on fd %d\n", sd);
1312 ptr = asn_parse_header(result, &length, &type);
1313 smux_trap_process(ptr, &length);
1316 * go and peek at received data again
1319 * we could receive the reply or another trap
1325 ptr = smux_parse(result, objid, len, return_len, return_type);
1327 * ptr will point to query result or NULL if error
1337 smux_parse(u_char * rsp,
1339 size_t * oidlen, size_t * return_len, u_char * return_type)
1341 size_t length = SMUXMAXPKTSIZE;
1343 long reqid, errstat, errindex;
1348 * Return pointer to the snmp/smux return value.
1349 * return_len should contain the number of bytes in the value
1351 * objid is the next object, with len for GETNEXT.
1352 * objid and len are not changed for GET
1354 ptr = asn_parse_header(ptr, &length, &type);
1355 if (ptr == NULL || type != SNMP_MSG_RESPONSE)
1358 if ((ptr = asn_parse_int(ptr, &length, &type, &reqid,
1359 sizeof(reqid))) == NULL) {
1360 DEBUGMSGTL(("smux", "[smux_parse] parse of reqid failed\n"));
1363 if ((ptr = asn_parse_int(ptr, &length, &type, &errstat,
1364 sizeof(errstat))) == NULL) {
1366 "[smux_parse] parse of error status failed\n"));
1369 if ((ptr = asn_parse_int(ptr, &length, &type, &errindex,
1370 sizeof(errindex))) == NULL) {
1371 DEBUGMSGTL(("smux", "[smux_parse] parse of error index failed\n"));
1376 * XXX How to send something intelligent back in case of an error
1379 "[smux_parse] Message type %d, reqid %d, errstat %d, \n\terrindex %d\n",
1380 (int) type, reqid, errstat, errindex));
1381 if (ptr == NULL || errstat != SNMP_ERR_NOERROR)
1387 return (smux_parse_var
1388 (ptr, &length, objid, oidlen, return_len, return_type));
1393 smux_parse_var(u_char * varbind,
1394 size_t * varbindlength,
1396 size_t * oidlen, size_t * varlength, u_char * vartype)
1398 oid var_name[MAX_OID_LEN];
1399 size_t var_name_len;
1402 size_t str_len, objid_len;
1408 len = *varbindlength;
1410 DEBUGMSGTL(("smux", "[smux_parse_var] before any processing: "));
1411 DEBUGMSGOID(("smux", objid, *oidlen));
1412 DEBUGMSG(("smux", "\n"));
1414 ptr = asn_parse_header(ptr, &len, &type);
1415 if (ptr == NULL || type != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
1416 snmp_log(LOG_NOTICE, "[smux_parse_var] Panic: type %d\n",
1422 * get hold of the objid and the asn1 coded value
1424 var_name_len = MAX_OID_LEN;
1425 ptr = snmp_parse_var_op(ptr, var_name, &var_name_len, vartype,
1426 &var_val_len, &var_val, &len);
1428 *oidlen = var_name_len;
1429 memcpy(objid, var_name, var_name_len * sizeof(oid));
1431 DEBUGMSGTL(("smux", "[smux_parse_var] returning oid : "));
1432 DEBUGMSGOID(("smux", objid, *oidlen));
1433 DEBUGMSG(("smux", "\n"));
1437 len = SMUXMAXPKTSIZE;
1439 "[smux_parse_var] Asn coded len of var %d, type %d\n",
1440 var_val_len, (int) *vartype));
1442 switch ((short) *vartype) {
1444 *varlength = sizeof(long);
1445 asn_parse_int(var_val, &len, vartype,
1446 (long *) &smux_long, *varlength);
1447 return (u_char *) & smux_long;
1453 *varlength = sizeof(u_long);
1454 asn_parse_unsigned_int(var_val, &len, vartype,
1455 (u_long *) & smux_ulong, *varlength);
1456 return (u_char *) & smux_ulong;
1459 *varlength = sizeof(smux_counter64);
1460 asn_parse_unsigned_int64(var_val, &len, vartype,
1461 (struct counter64 *) &smux_counter64,
1463 return (u_char *) & smux_counter64;
1468 * consume the tag and length, but just copy here
1469 * because we know it is an ip address
1471 if ((var_val = asn_parse_header(var_val, &len, &type)) == NULL)
1473 memcpy((u_char *) & (smux_sa.sin_addr.s_addr), var_val,
1475 return (u_char *) & (smux_sa.sin_addr.s_addr);
1483 str_len = SMUXMAXSTRLEN;
1484 asn_parse_string(var_val, &len, vartype, smux_str, &str_len);
1485 *varlength = str_len;
1491 objid_len = MAX_OID_LEN;
1492 asn_parse_objid(var_val, &len, vartype, smux_objid, &objid_len);
1493 *varlength = objid_len * sizeof(oid);
1494 return (u_char *) smux_objid;
1496 case SNMP_NOSUCHOBJECT:
1497 case SNMP_NOSUCHINSTANCE:
1498 case SNMP_ENDOFMIBVIEW:
1508 str_len = SMUXMAXSTRLEN;
1509 asn_parse_bitstring(var_val, &len, vartype, smux_str, &str_len);
1510 *varlength = str_len;
1511 return (u_char *) smux_str;
1514 snmp_log(LOG_ERR, "bad type returned (%x)\n", *vartype);
1521 * XXX This is a bad hack - do not want to muck with ucd code
1524 smux_build(u_char type,
1529 u_char * val, size_t val_len, u_char * packet, size_t * length)
1531 u_char *ptr, *save1, *save2;
1537 * leave space for Seq and length
1546 ptr = asn_build_unsigned_int(ptr, &len,
1547 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1548 ASN_INTEGER), &reqid,
1557 ptr = asn_build_int(ptr, &len,
1558 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1559 ASN_INTEGER), &errstat, sizeof(errstat));
1567 ptr = asn_build_int(ptr, &len,
1568 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE |
1569 ASN_INTEGER), &errindex,
1579 if (type != SMUX_SET) {
1580 val_type = ASN_NULL;
1585 * build var list : snmp_build_var_op not liked by gated XXX
1587 ptr = snmp_build_var_op(ptr, objid, oidlen, val_type, val_len,
1594 asn_build_sequence(save1, &len, type, (ptr - save1 - 4));
1597 asn_build_sequence(save2, &len,
1598 (ASN_SEQUENCE | ASN_CONSTRUCTOR),
1601 *length = ptr - packet;
1607 smux_peer_cleanup(int sd)
1609 smux_reg *nrptr, *rptr, *rptr2;
1615 * close the descriptor
1620 * delete all of the passive registrations that this peer owns
1622 for (rptr = PassiveRegs; rptr; rptr = nrptr) {
1623 nrptr = rptr->sr_next;
1624 if (rptr->sr_fd == sd) {
1625 smux_list_detach(&PassiveRegs, &rptr);
1631 * find replacements for all of the active registrations found
1633 for (rptr = ActiveRegs; rptr; rptr = rptr2) {
1634 rptr2 = rptr->sr_next;
1635 if (rptr->sr_fd == sd) {
1636 smux_list_detach(&ActiveRegs, &rptr);
1637 unregister_mib(rptr->sr_name, rptr->sr_name_len);
1638 if ((nrptr = smux_find_replacement(rptr->sr_name,
1639 rptr->sr_name_len)) !=
1641 smux_list_detach(&PassiveRegs, &nrptr);
1642 smux_list_add(&ActiveRegs, nrptr);
1643 register_mib("smux", (struct variable *)
1644 smux_variables, sizeof(struct variable2),
1645 1, nrptr->sr_name, nrptr->sr_name_len);
1652 * decrement the peer count
1657 * make his auth available again
1659 for (i = 0; i < nauths; i++) {
1660 if (Auths[i]->sa_active_fd == sd) {
1662 Auths[i]->sa_active_fd = -1;
1663 snprint_objid(oid_name, sizeof(oid_name), Auths[i]->sa_oid,
1664 Auths[i]->sa_oid_len);
1665 snmp_log(LOG_INFO, "peer disconnected: %s\n", oid_name);
1671 smux_send_rrsp(int sd, int pri)
1673 u_char outdata[2 + sizeof(int)];
1674 u_char *ptr = outdata;
1675 int intsize = sizeof(int);
1676 u_int mask = ((u_int) 0xFF) << (8 * (sizeof(int) - 1));
1678 * e.g. mask is 0xFF000000 on a 32-bit machine
1683 * This is kind of like calling asn_build_int(), but the
1684 * encoding will always be the size of an integer on this
1685 * machine, never shorter.
1687 *ptr++ = (u_char) SMUX_RRSP;
1688 *ptr++ = (u_char) intsize;
1691 * Copy each byte, most significant first.
1694 *ptr++ = (u_char) ((pri & mask) >> (8 * (sizeof(int) - 1)));
1698 sent = send(sd, (char *) outdata, sizeof outdata, 0);
1700 DEBUGMSGTL(("smux", "[smux_send_rrsp] send failed\n"));
1706 smux_trap_process(u_char * rsp, size_t * len)
1708 oid sa_enterpriseoid[MAX_OID_LEN], var_name[MAX_OID_LEN];
1709 size_t datalen, var_name_len, var_val_len, maxlen;
1710 int sa_enterpriseoid_len;
1711 u_char vartype, *ptr, *var_val;
1713 long trap, specific;
1716 netsnmp_variable_list *snmptrap_head, *snmptrap_ptr, *snmptrap_tmp;
1717 snmptrap_head = NULL;
1718 snmptrap_ptr = NULL;
1723 * parse the sub-agent enterprise oid
1725 datalen = MAX_OID_LEN;
1726 if ((ptr = asn_parse_objid(ptr, len,
1727 &vartype, (oid *) & sa_enterpriseoid,
1728 &sa_enterpriseoid_len)) == NULL) {
1730 "[smux_trap_process] asn_parse_objid failed\n"));
1735 * parse the agent-addr ipAddress
1737 datalen = SMUXMAXSTRLEN;
1738 if (((ptr = asn_parse_string(ptr, len,
1740 &datalen)) == NULL) ||
1741 (vartype != (u_char) ASN_IPADDRESS)) {
1743 "[smux_trap_process] asn_parse_string failed\n"));
1748 * parse the generic trap int
1750 datalen = sizeof(long);
1751 if ((ptr = asn_parse_int(ptr, len, &vartype, &trap, datalen)) == NULL) {
1753 "[smux_trap_process] asn_parse_int generic failed\n"));
1758 * parse the specific trap int
1760 datalen = sizeof(long);
1761 if ((ptr = asn_parse_int(ptr, len,
1762 &vartype, &specific, datalen)) == NULL) {
1764 "[smux_trap_process] asn_parse_int specific failed\n"));
1769 * parse the timeticks timestamp
1771 datalen = sizeof(u_long);
1772 if (((ptr = asn_parse_unsigned_int(ptr, len,
1773 &vartype, (u_long *) & timestamp,
1774 datalen)) == NULL) ||
1775 (vartype != (u_char) ASN_TIMETICKS)) {
1777 "[smux_trap_process] asn_parse_unsigned_int (timestamp) failed\n"));
1782 * parse out the overall sequence
1784 ptr = asn_parse_header(ptr, len, &vartype);
1785 if (ptr == NULL || vartype != (ASN_SEQUENCE | ASN_CONSTRUCTOR)) {
1790 * parse the variable bindings
1792 while (ptr && *len) {
1795 * get the objid and the asn1 coded value
1797 var_name_len = MAX_OID_LEN;
1798 ptr = snmp_parse_var_op(ptr, var_name, &var_name_len, &vartype,
1799 &var_val_len, (u_char **) & var_val, len);
1805 maxlen = SMUXMAXPKTSIZE;
1806 switch ((short) vartype) {
1808 var_val_len = sizeof(long);
1809 asn_parse_int(var_val, &maxlen, &vartype,
1810 (long *) &smux_long, var_val_len);
1811 var_val = (u_char *) & smux_long;
1817 var_val_len = sizeof(u_long);
1818 asn_parse_unsigned_int(var_val, &maxlen, &vartype,
1819 (u_long *) & smux_ulong, var_val_len);
1820 var_val = (u_char *) & smux_ulong;
1823 var_val_len = sizeof(smux_counter64);
1824 asn_parse_unsigned_int64(var_val, &maxlen, &vartype,
1825 (struct counter64 *) &smux_counter64,
1827 var_val = (u_char *) & smux_counter64;
1832 * consume the tag and length, but just copy here
1833 * because we know it is an ip address
1836 asn_parse_header(var_val, &maxlen, &vartype)) == NULL)
1838 memcpy((u_char *) & (smux_sa.sin_addr.s_addr), var_val,
1840 var_val = (u_char *) & (smux_sa.sin_addr.s_addr);
1849 var_val_len = SMUXMAXSTRLEN;
1850 asn_parse_string(var_val, &maxlen, &vartype,
1851 smux_str, &var_val_len);
1855 var_val_len = MAX_OID_LEN;
1856 asn_parse_objid(var_val, &maxlen, &vartype,
1857 smux_objid, &var_val_len);
1858 var_val_len *= sizeof(oid);
1859 var_val = (u_char *) smux_objid;
1861 case SNMP_NOSUCHOBJECT:
1862 case SNMP_NOSUCHINSTANCE:
1863 case SNMP_ENDOFMIBVIEW:
1873 var_val_len = SMUXMAXSTRLEN;
1874 asn_parse_bitstring(var_val, &maxlen, &vartype,
1875 smux_str, &var_val_len);
1876 var_val = (u_char *) smux_str;
1880 snmp_log(LOG_ERR, "bad type returned (%x)\n", vartype);
1886 (netsnmp_variable_list *)
1887 malloc(sizeof(netsnmp_variable_list));
1888 if (snmptrap_tmp == NULL)
1890 memset(snmptrap_tmp, 0, sizeof(netsnmp_variable_list));
1891 if (snmptrap_head == NULL) {
1892 snmptrap_head = snmptrap_tmp;
1893 snmptrap_ptr = snmptrap_head;
1895 snmptrap_ptr->next_variable = snmptrap_tmp;
1896 snmptrap_ptr = snmptrap_ptr->next_variable;
1899 snmp_set_var_objid(snmptrap_ptr, var_name, var_name_len);
1900 snmp_set_var_value(snmptrap_ptr, (char *) var_val, var_val_len);
1901 snmptrap_ptr->type = vartype;
1902 snmptrap_ptr->next_variable = NULL;
1909 send_enterprise_trap_vars(trap, specific, (oid *) & sa_enterpriseoid,
1910 sa_enterpriseoid_len, snmptrap_head);
1913 * free trap variables
1915 snmp_free_varbind(snmptrap_head);