2 * Copyright (C) 2000 Jochen Friedrich <jochen@scram.de>
3 * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org>
5 * You should have received a copy of the GNU General Public License
6 * along with GNU Zebra; see the file COPYING. If not, write to the Free
7 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
15 #include <sys/types.h>
16 #include <sys/socket.h>
18 #include <netinet/in.h>
31 #include <snmp_impl.h>
36 #define min(A,B) ((A) < (B) ? (A) : (B))
38 extern enum smux_event smux_event;
41 /* SMUX subtree vector. */
42 struct list *treelist = NULL;
49 extern char *smux_password;
54 /* SMUX failure count. */
58 oid_copy (void *dest, void *src, size_t size)
60 return memcpy (dest, src, size * sizeof (oid));
64 oid2in_addr (oid oid[], int len, struct in_addr *addr)
72 pnt = (u_char *) addr;
74 for (i = 0; i < len; i++)
79 oid_copy_addr (oid oid[], struct in_addr *addr, int len)
87 pnt = (u_char *) addr;
89 for (i = 0; i < len; i++)
94 oid_compare (oid *o1, int o1_len, oid *o2, int o2_len)
98 for (i = 0; i < min (o1_len, o2_len); i++)
102 else if (o1[i] > o2[i])
114 oid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len)
118 for (i = 0; i < min (o1_len, o2_len); i++)
122 else if (o1[i] > o2[i])
132 smux_oid_dump (char *prefix, oid *oid, size_t oid_len)
136 char buf[MAX_OID_LEN * 3];
140 for (i = 0; i < oid_len; i++)
142 sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]);
145 DEBUG2 ("%s: %s", prefix, buf);
154 struct addrinfo hints, *res0, *res;
157 struct sockaddr_in serv;
163 memset(&hints, 0, sizeof(hints));
164 hints.ai_family = PF_UNSPEC;
165 hints.ai_socktype = SOCK_STREAM;
166 gai = getaddrinfo(NULL, "smux", &hints, &res0);
167 if (gai == EAI_SERVICE)
169 char servbuf[NI_MAXSERV];
170 sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
171 gai = getaddrinfo(NULL, servbuf, &hints, &res0);
175 DEBUG("Cannot locate loopback service smux");
178 for(res=res0; res; res=res->ai_next)
180 fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
183 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
185 setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
187 ret = connect (fd, res->ai_addr, res->ai_addrlen);
198 DEBUG ("Can't connect to SNMP agent with SMUX");
200 fd = socket (AF_INET, SOCK_STREAM, 0);
203 DEBUG ("Can't make socket for SNMP");
207 memset (&serv, 0, sizeof (struct sockaddr_in));
208 serv.sin_family = AF_INET;
210 serv.sin_len = sizeof (struct sockaddr_in);
211 #endif /* HAVE_SIN_LEN */
213 sp = getservbyname ("smux", "tcp");
215 serv.sin_port = sp->s_port;
217 serv.sin_port = htons (SMUX_PORT_DEFAULT);
219 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
221 setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
223 setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
226 ret = connect (fd, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
230 DEBUG ("Can't connect to SNMP agent with SMUX: %s", strerror(errno));
238 smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
239 long errindex, u_char val_type, void *arg, size_t arg_len)
243 u_char *ptr, *h1, *h1e, *h2, *h2e;
250 DEBUG2("SMUX GETRSP send");
251 DEBUG2("SMUX GETRSP reqid: %d", reqid);
254 /* Place holder h1 for complete sequence */
255 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
258 ptr = asn_build_int (ptr, &len,
259 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
260 &reqid, sizeof (reqid));
262 DEBUG2("SMUX GETRSP errstat: %d", errstat);
264 ptr = asn_build_int (ptr, &len,
265 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
266 &errstat, sizeof (errstat));
267 DEBUG2("SMUX GETRSP errindex: %d", errindex);
269 ptr = asn_build_int (ptr, &len,
270 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
271 &errindex, sizeof (errindex));
274 /* Place holder h2 for one variable */
275 ptr = asn_build_sequence (ptr, &len,
276 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
280 ptr = snmp_build_var_op (ptr, objid, &objid_len,
281 val_type, arg_len, arg, &len);
283 /* Now variable size is known, fill in size */
284 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
286 /* Fill in size of whole sequence */
287 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
289 DEBUG2("SMUX getresp send: %d", ptr - buf);
291 ret = send (smuxfd, buf, (ptr - buf), 0);
295 smux_var (char *ptr, int len, oid objid[], size_t *objid_len,
297 u_char *var_val_type,
305 DEBUG2("SMUX var parse: len %d", len);
308 ptr = asn_parse_header (ptr, &len, &type);
310 DEBUG2("SMUX var parse: type %d len %d", type, len);
311 DEBUG2("SMUX var parse: type must be %d", (ASN_SEQUENCE | ASN_CONSTRUCTOR));
313 /* Parse var option. */
314 *objid_len = MAX_OID_LEN;
315 ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
316 &val_len, &val, &len);
319 *var_val_len = val_len;
322 *var_value = (void*) val;
325 *var_val_type = val_type;
327 /* Requested object id length is objid_len. */
328 smux_oid_dump ("Request OID", objid, *objid_len);
330 DEBUG2 ("SMUX val_type: %d", val_type);
332 /* Check request value type. */
336 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
342 DEBUG2 ("ASN_INTEGER");
348 DEBUG2 ("ASN_COUNTER");
351 DEBUG2 ("ASN_COUNTER64");
354 DEBUG2 ("ASN_IPADDRESS");
357 DEBUG2 ("ASN_OCTET_STR");
362 DEBUG2 ("ASN_OPAQUE");
364 case SNMP_NOSUCHOBJECT:
365 DEBUG2 ("SNMP_NOSUCHOBJECT");
367 case SNMP_NOSUCHINSTANCE:
368 DEBUG2 ("SNMP_NOSUCHINSTANCE");
370 case SNMP_ENDOFMIBVIEW:
371 DEBUG2 ("SNMP_ENDOFMIBVIEW");
374 DEBUG2 ("ASN_BIT_STR");
377 DEBUG2 ("Unknown type");
383 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on ucd-snmp
384 smux and as such suppose, that the peer recieves in the message only one variable */
387 smux_set (oid *reqid, size_t *reqid_len,
388 u_char val_type, void *val, size_t val_len, int action)
391 struct subtree *subtree;
398 u_char *statP = NULL;
399 WriteMethod *write_method = NULL;
402 for (l = treelist; l; l=l->next)
405 subresult = oid_compare_part (reqid, *reqid_len,
406 subtree->name, subtree->name_len);
408 /* Subtree matched. */
411 /* Prepare suffix. */
412 suffix = reqid + subtree->name_len;
413 suffix_len = *reqid_len - subtree->name_len;
416 /* Check variables. */
417 for (j = 0; j < subtree->variables_num; j++)
419 v = &subtree->variables[j];
421 /* Always check suffix */
422 result = oid_compare_part (suffix, suffix_len,
423 v->name, v->namelen);
425 /* This is exact match so result must be zero. */
428 DEBUG2 ("SMUX function call index is %d", v->magic);
430 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
431 &val_len, &write_method);
435 return (*write_method)(action, val, val_type, val_len, statP, suffix, suffix_len);
440 return SNMP_ERR_READONLY;
444 /* If above execution is failed or oid is small (so
445 there is no further match). */
447 return SNMP_NOSUCHOBJECT;
451 return SNMP_NOSUCHOBJECT;
455 smux_get (oid *reqid, size_t *reqid_len, int exact,
456 u_char *val_type,void **val, size_t *val_len)
459 struct subtree *subtree;
466 WriteMethod *write_method=NULL;
469 for (l = treelist; l; l=l->next)
472 subresult = oid_compare_part (reqid, *reqid_len,
473 subtree->name, subtree->name_len);
475 /* Subtree matched. */
478 /* Prepare suffix. */
479 suffix = reqid + subtree->name_len;
480 suffix_len = *reqid_len - subtree->name_len;
483 /* Check variables. */
484 for (j = 0; j < subtree->variables_num; j++)
486 v = &subtree->variables[j];
488 /* Always check suffix */
489 result = oid_compare_part (suffix, suffix_len,
490 v->name, v->namelen);
492 /* This is exact match so result must be zero. */
495 DEBUG2 ("SMUX function call index is %d", v->magic);
497 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
498 val_len, &write_method);
500 /* There is no instance. */
502 return SNMP_NOSUCHINSTANCE;
504 /* Call is suceed. */
510 /* If above execution is failed or oid is small (so
511 there is no further match). */
513 return SNMP_NOSUCHOBJECT;
517 return SNMP_NOSUCHOBJECT;
521 smux_getnext (oid *reqid, size_t *reqid_len, int exact,
522 u_char *val_type,void **val, size_t *val_len)
525 oid save[MAX_OID_LEN];
527 struct subtree *subtree;
534 WriteMethod *write_method=NULL;
536 /* Save incoming request. */
537 oid_copy (save, reqid, *reqid_len);
538 savelen = *reqid_len;
541 for (l = treelist; l; l=l->next)
545 subresult = oid_compare_part (reqid, *reqid_len,
546 subtree->name, subtree->name_len);
548 /* If request is in the tree. The agent has to make sure we
549 only receive requests we have registered for. */
553 /* Prepare suffix. */
554 suffix = reqid + subtree->name_len;
555 suffix_len = *reqid_len - subtree->name_len;
558 for (j = 0; j < subtree->variables_num; j++)
560 v = &subtree->variables[j];
562 /* Next then check result >= 0. */
564 result = oid_compare_part (suffix, suffix_len,
565 v->name, v->namelen);
569 DEBUG2 ("SMUX function call index is %d", v->magic);
572 oid_copy(suffix, v->name, v->namelen);
573 suffix_len = v->namelen;
575 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
576 val_len, &write_method);
577 *reqid_len = suffix_len + subtree->name_len;
587 memcpy (reqid, save, savelen * sizeof(oid));
588 *reqid_len = savelen;
590 return SNMP_NOSUCHOBJECT;
593 /* GET message header. */
595 smux_parse_get_header (char *ptr, size_t *len, long *reqid)
602 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
604 DEBUG2 ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
607 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
609 DEBUG2 ("SMUX GET errstat %d len: %d", errstat, *len);
612 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
614 DEBUG2 ("SMUX GET errindex %d len: %d", errindex, *len);
620 smux_parse_set (char *ptr, size_t len, int action)
623 oid oid[MAX_OID_LEN];
630 DEBUG2 ("SMUX SET(%s) message parse: len %d",
631 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
634 /* Parse SET message header. */
635 ptr = smux_parse_get_header (ptr, &len, &reqid);
637 /* Parse SET message object ID. */
638 ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
640 ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
641 DEBUG2 ("SMUX SET ret %d", ret);
644 if (RESERVE1 == action)
645 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
649 smux_parse_get (char *ptr, size_t len, int exact)
652 oid oid[MAX_OID_LEN];
659 DEBUG2 ("SMUX GET message parse: len %d", len);
661 /* Parse GET message header. */
662 ptr = smux_parse_get_header (ptr, &len, &reqid);
664 /* Parse GET message object ID. We needn't the value come */
665 ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
667 /* Traditional getstatptr. */
669 ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len);
671 ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len);
675 smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len);
677 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
680 /* Parse SMUX_CLOSE message. */
682 smux_parse_close (char *ptr, int len)
688 reason = (reason << 8) | (long) *ptr;
691 DEBUG ("SMUX_CLOSE with reason: %d", reason);
694 /* SMUX_RRSP message. */
696 smux_parse_rrsp (char *ptr, int len)
701 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
703 DEBUG2 ("SMUX_RRSP value: %d errstat: %d", val, errstat);
706 /* Parse SMUX message. */
708 smux_parse (char *ptr, int len)
710 /* this buffer we'll use for SOUT message. We could allocate it with malloc and
711 save only static pointer/lenght, but IMHO static buffer is a faster solusion */
712 static u_char sout_save_buff[SMUXMAXPKTSIZE];
713 static int sout_save_len = 0;
715 int len_income = len; /* see note below: YYY */
719 rollback = ptr[2]; /* important only for SMUX_SOUT */
721 process_rest: /* see note below: YYY */
723 /* Parse SMUX message type and subsequent length. */
724 ptr = asn_parse_header (ptr, &len, &type);
726 DEBUG2 ("SMUX message received type: %d rest len: %d", type, len);
731 /* Open must be not send from SNMP agent. */
732 DEBUG ("SMUX_OPEN received: resetting connection.");
736 /* SMUX_RREQ message is invalid for us. */
737 DEBUG ("SMUX_RREQ received: resetting connection.");
741 /* SMUX_SOUT message is now valied for us. */
742 DEBUG2 ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
744 if (sout_save_len > 0)
746 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
750 DEBUG ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
754 /* YYY: this strange code has to solve the "slow peer"
755 problem: When agent sends SMUX_SOUT message it doesn't
756 wait any responce and may send some next message to
757 subagent. Then the peer in 'smux_read()' will recieve
758 from socket the 'concatenated' buffer, contaning both
759 SMUX_SOUT message and the next one
760 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
761 the buffer is longer than 3 ( length of SMUX_SOUT ), we
762 must process the rest of it. This effect may be observed
763 if DEBUG is set to >1 */
765 len = len_income - 3;
770 /* SMUX_GETRSP message is invalid for us. */
771 DEBUG ("SMUX_GETRSP received: resetting connection.");
775 /* Close SMUX connection. */
776 DEBUG2 ("SMUX_CLOSE");
777 smux_parse_close (ptr, len);
781 /* This is response for register message. */
782 DEBUG2 ("SMUX_RRSP");
783 smux_parse_rrsp (ptr, len);
786 /* Exact request for object id. */
788 smux_parse_get (ptr, len, 1);
791 /* Next request for object id. */
792 DEBUG2 ("SMUX_GETNEXT");
793 smux_parse_get (ptr, len, 0);
796 /* SMUX_SET is supported with some limitations. */
799 /* save the data for future SMUX_SOUT */
800 memcpy (sout_save_buff, ptr, len);
802 smux_parse_set (ptr, len, RESERVE1);
805 DEBUG ("Unknown type: %d", type);
811 /* SMUX message read function. */
816 u_char buf[SMUXMAXPKTSIZE];
819 smux_event=SMUX_NONE;
820 DEBUG2 ("SMUX read start");
822 /* Read message from SMUX socket. */
823 len = recv (smuxfd, buf, SMUXMAXPKTSIZE, 0);
827 DEBUG ("Can't read all SMUX packet: %s", strerror (errno));
830 smux_event=SMUX_CONNECT;
836 DEBUG ("SMUX connection closed: %d", smuxfd);
839 smux_event=SMUX_CONNECT;
843 DEBUG2 ("SMUX read len: %d", len);
845 /* Parse the message. */
846 ret = smux_parse (buf, len);
852 smux_event=SMUX_CONNECT;
856 smux_event=SMUX_READ;
868 u_char progname[] = "radiusd";
870 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
871 DEBUG2 ("SMUX open progname: %s", progname);
872 DEBUG2 ("SMUX open password: %s", smux_password);
877 /* SMUX Header. As placeholder. */
878 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
882 ptr = asn_build_int (ptr, &len,
883 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
884 &version, sizeof (u_long));
886 /* SMUX connection oid. */
887 ptr = asn_build_objid (ptr, &len,
889 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
890 smux_oid, smux_oid_len);
892 /* SMUX connection description. */
893 ptr = asn_build_string (ptr, &len,
895 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
896 progname, strlen (progname));
898 /* SMUX connection password. */
899 ptr = asn_build_string (ptr, &len,
901 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
902 smux_password, strlen (smux_password));
904 /* Fill in real SMUX header. We exclude ASN header size (2). */
906 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
908 return send (smuxfd, buf, (ptr - buf), 0);
919 struct subtree *subtree;
924 for (l = treelist; l; l=l->next)
931 /* SMUX RReq Header. */
932 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
934 /* Register MIB tree. */
935 ptr = asn_build_objid (ptr, &len,
937 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
938 subtree->name, subtree->name_len);
942 ptr = asn_build_int (ptr, &len,
943 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
944 &priority, sizeof (u_long));
948 ptr = asn_build_int (ptr, &len,
949 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
950 &operation, sizeof (u_long));
952 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
953 DEBUG2 ("SMUX register priority: %d", priority);
954 DEBUG2 ("SMUX register operation: %d", operation);
957 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
958 ret = send (smuxfd, buf, (ptr - buf), 0);
965 /* Try to connect to SNMP agent. */
971 smux_event=SMUX_NONE;
972 DEBUG2 ("SMUX connect try %d", fail + 1);
974 /* Make socket. Try to connect. */
975 smux_fd = smux_sock ();
978 if (++fail < SMUX_MAX_FAILURE)
979 smux_event=SMUX_CONNECT;
987 DEBUG ("SMUX open message send failed: %s", strerror (errno));
990 smux_event=SMUX_CONNECT;
994 /* Send any outstanding register PDUs. */
995 ret = smux_register ();
998 DEBUG ("SMUX register message send failed: %s", strerror (errno));
1001 smux_event=SMUX_CONNECT;
1005 /* Everything goes fine. */
1006 smux_event=SMUX_READ;
1011 /* Clear all SMUX related resources. */
1015 smux_event=SMUX_NONE;
1022 smux_str2oid (char *str, oid *oid, size_t *oid_len)
1038 if (! isdigit (*str))
1041 while (isdigit (*str))
1044 val += (*str - '0');
1065 smux_oid_dup (oid *objid, size_t objid_len)
1069 new = (oid *)malloc(sizeof (oid) * objid_len);
1070 oid_copy (new, objid, objid_len);
1076 smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
1077 size_t *var_len, WriteMethod **write_method)
1079 oid fulloid[MAX_OID_LEN];
1082 oid_copy (fulloid, v->name, v->namelen);
1083 fulloid[v->namelen] = 0;
1084 /* Check against full instance. */
1085 ret = oid_compare (name, *length, fulloid, v->namelen + 1);
1087 /* Check single instance. */
1088 if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
1089 return MATCH_FAILED;
1091 /* In case of getnext, fill in full instance. */
1092 memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
1093 *length = v->namelen + 1;
1096 *var_len = sizeof(long); /* default to 'long' results */
1098 return MATCH_SUCCEEDED;
1101 /* Initialize some values then schedule first SMUX connection. */
1103 smux_init (oid defoid[], size_t defoid_len)
1106 smux_oid_len = defoid_len;
1109 /* Register subtree to smux master tree. */
1111 smux_register_mib(char *descr, struct variable *var, size_t width, int num,
1112 oid name[], size_t namelen)
1114 struct subtree *tree;
1117 tree = (struct subtree *)malloc(sizeof(struct subtree));
1118 oid_copy (tree->name, name, namelen);
1119 tree->name_len = namelen;
1120 tree->variables = var;
1121 tree->variables_num = num;
1122 tree->variables_width = width;
1123 tree->registered = 0;
1124 l = (struct list *)malloc(sizeof(struct list));
1127 if (treelist == NULL)
1132 for (ll = treelist; ll->next; ll=ll->next);
1140 smux_event=SMUX_CONNECT;
1143 #endif /* WITH_SNMP */