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;
162 memset(&hints, 0, sizeof(hints));
163 hints.ai_family = PF_UNSPEC;
164 hints.ai_socktype = SOCK_STREAM;
165 gai = getaddrinfo(NULL, "smux", &hints, &res0);
166 if (gai == EAI_SERVICE)
168 char servbuf[NI_MAXSERV];
169 sprintf(servbuf,"%d",SMUX_PORT_DEFAULT);
170 gai = getaddrinfo(NULL, servbuf, &hints, &res0);
174 DEBUG("Cannot locate loopback service smux");
177 for(res=res0; res; res=res->ai_next)
179 smuxfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
182 setsockopt (smuxfd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
184 setsockopt (smuxfd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
186 ret = connect (smuxfd, res->ai_addr, res->ai_addrlen);
197 DEBUG ("Can't connect to SNMP agent with SMUX");
199 smuxfd = socket (AF_INET, SOCK_STREAM, 0);
202 DEBUG ("Can't make socket for SNMP");
206 memset (&serv, 0, sizeof (struct sockaddr_in));
207 serv.sin_family = AF_INET;
209 serv.sin_len = sizeof (struct sockaddr_in);
210 #endif /* HAVE_SIN_LEN */
212 sp = getservbyname ("smux", "tcp");
214 serv.sin_port = sp->s_port;
216 serv.sin_port = htons (SMUX_PORT_DEFAULT);
218 serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
220 setsockopt (smuxfd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof (on));
222 setsockopt (smuxfd, SOL_SOCKET, SO_REUSEPORT, (void *)&on, sizeof (on));
225 ret = connect (smuxfd, (struct sockaddr *) &serv, sizeof (struct sockaddr_in));
229 DEBUG ("Can't connect to SNMP agent with SMUX");
237 smux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat,
238 long errindex, u_char val_type, void *arg, size_t arg_len)
242 u_char *ptr, *h1, *h1e, *h2, *h2e;
249 DEBUG2("SMUX GETRSP send");
250 DEBUG2("SMUX GETRSP reqid: %d", reqid);
253 /* Place holder h1 for complete sequence */
254 ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0);
257 ptr = asn_build_int (ptr, &len,
258 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
259 &reqid, sizeof (reqid));
261 DEBUG2("SMUX GETRSP errstat: %d", errstat);
263 ptr = asn_build_int (ptr, &len,
264 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
265 &errstat, sizeof (errstat));
266 DEBUG2("SMUX GETRSP errindex: %d", errindex);
268 ptr = asn_build_int (ptr, &len,
269 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
270 &errindex, sizeof (errindex));
273 /* Place holder h2 for one variable */
274 ptr = asn_build_sequence (ptr, &len,
275 (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR),
279 ptr = snmp_build_var_op (ptr, objid, &objid_len,
280 val_type, arg_len, arg, &len);
282 /* Now variable size is known, fill in size */
283 asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e);
285 /* Fill in size of whole sequence */
286 asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e);
288 DEBUG2("SMUX getresp send: %d", ptr - buf);
290 ret = send (smuxfd, buf, (ptr - buf), 0);
294 smux_var (char *ptr, int len, oid objid[], size_t *objid_len,
296 u_char *var_val_type,
304 DEBUG2("SMUX var parse: len %d", len);
307 ptr = asn_parse_header (ptr, &len, &type);
309 DEBUG2("SMUX var parse: type %d len %d", type, len);
310 DEBUG2("SMUX var parse: type must be %d", (ASN_SEQUENCE | ASN_CONSTRUCTOR));
312 /* Parse var option. */
313 *objid_len = MAX_OID_LEN;
314 ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type,
315 &val_len, &val, &len);
318 *var_val_len = val_len;
321 *var_value = (void*) val;
324 *var_val_type = val_type;
326 /* Requested object id length is objid_len. */
327 smux_oid_dump ("Request OID", objid, *objid_len);
329 DEBUG2 ("SMUX val_type: %d", val_type);
331 /* Check request value type. */
335 /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to
341 DEBUG2 ("ASN_INTEGER");
347 DEBUG2 ("ASN_COUNTER");
350 DEBUG2 ("ASN_COUNTER64");
353 DEBUG2 ("ASN_IPADDRESS");
356 DEBUG2 ("ASN_OCTET_STR");
361 DEBUG2 ("ASN_OPAQUE");
363 case SNMP_NOSUCHOBJECT:
364 DEBUG2 ("SNMP_NOSUCHOBJECT");
366 case SNMP_NOSUCHINSTANCE:
367 DEBUG2 ("SNMP_NOSUCHINSTANCE");
369 case SNMP_ENDOFMIBVIEW:
370 DEBUG2 ("SNMP_ENDOFMIBVIEW");
373 DEBUG2 ("ASN_BIT_STR");
376 DEBUG2 ("Unknown type");
382 /* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on ucd-snmp
383 smux and as such suppose, that the peer recieves in the message only one variable */
386 smux_set (oid *reqid, size_t *reqid_len,
387 u_char val_type, void *val, size_t val_len, int action)
390 struct subtree *subtree;
397 u_char *statP = NULL;
398 WriteMethod *write_method = NULL;
401 for (l = treelist; l; l=l->next)
404 subresult = oid_compare_part (reqid, *reqid_len,
405 subtree->name, subtree->name_len);
407 /* Subtree matched. */
410 /* Prepare suffix. */
411 suffix = reqid + subtree->name_len;
412 suffix_len = *reqid_len - subtree->name_len;
415 /* Check variables. */
416 for (j = 0; j < subtree->variables_num; j++)
418 v = &subtree->variables[j];
420 /* Always check suffix */
421 result = oid_compare_part (suffix, suffix_len,
422 v->name, v->namelen);
424 /* This is exact match so result must be zero. */
427 DEBUG2 ("SMUX function call index is %d", v->magic);
429 statP = (*v->findVar) (v, suffix, &suffix_len, 1,
430 &val_len, &write_method);
434 return (*write_method)(action, val, val_type, val_len, statP, suffix, suffix_len);
439 return SNMP_ERR_READONLY;
443 /* If above execution is failed or oid is small (so
444 there is no further match). */
446 return SNMP_NOSUCHOBJECT;
450 return SNMP_NOSUCHOBJECT;
454 smux_get (oid *reqid, size_t *reqid_len, int exact,
455 u_char *val_type,void **val, size_t *val_len)
458 struct subtree *subtree;
465 WriteMethod *write_method=NULL;
468 for (l = treelist; l; l=l->next)
471 subresult = oid_compare_part (reqid, *reqid_len,
472 subtree->name, subtree->name_len);
474 /* Subtree matched. */
477 /* Prepare suffix. */
478 suffix = reqid + subtree->name_len;
479 suffix_len = *reqid_len - subtree->name_len;
482 /* Check variables. */
483 for (j = 0; j < subtree->variables_num; j++)
485 v = &subtree->variables[j];
487 /* Always check suffix */
488 result = oid_compare_part (suffix, suffix_len,
489 v->name, v->namelen);
491 /* This is exact match so result must be zero. */
494 DEBUG2 ("SMUX function call index is %d", v->magic);
496 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
497 val_len, &write_method);
499 /* There is no instance. */
501 return SNMP_NOSUCHINSTANCE;
503 /* Call is suceed. */
509 /* If above execution is failed or oid is small (so
510 there is no further match). */
512 return SNMP_NOSUCHOBJECT;
516 return SNMP_NOSUCHOBJECT;
520 smux_getnext (oid *reqid, size_t *reqid_len, int exact,
521 u_char *val_type,void **val, size_t *val_len)
524 oid save[MAX_OID_LEN];
526 struct subtree *subtree;
533 WriteMethod *write_method=NULL;
535 /* Save incoming request. */
536 oid_copy (save, reqid, *reqid_len);
537 savelen = *reqid_len;
540 for (l = treelist; l; l=l->next)
544 subresult = oid_compare_part (reqid, *reqid_len,
545 subtree->name, subtree->name_len);
547 /* If request is in the tree. The agent has to make sure we
548 only receive requests we have registered for. */
552 /* Prepare suffix. */
553 suffix = reqid + subtree->name_len;
554 suffix_len = *reqid_len - subtree->name_len;
557 for (j = 0; j < subtree->variables_num; j++)
559 v = &subtree->variables[j];
561 /* Next then check result >= 0. */
563 result = oid_compare_part (suffix, suffix_len,
564 v->name, v->namelen);
568 DEBUG2 ("SMUX function call index is %d", v->magic);
571 oid_copy(suffix, v->name, v->namelen);
572 suffix_len = v->namelen;
574 *val = (*v->findVar) (v, suffix, &suffix_len, exact,
575 val_len, &write_method);
576 *reqid_len = suffix_len + subtree->name_len;
586 memcpy (reqid, save, savelen * sizeof(oid));
587 *reqid_len = savelen;
589 return SNMP_NOSUCHOBJECT;
592 /* GET message header. */
594 smux_parse_get_header (char *ptr, size_t *len, long *reqid)
601 ptr = asn_parse_int (ptr, len, &type, reqid, sizeof (*reqid));
603 DEBUG2 ("SMUX GET reqid: %d len: %d", (int) *reqid, (int) *len);
606 ptr = asn_parse_int (ptr, len, &type, &errstat, sizeof (errstat));
608 DEBUG2 ("SMUX GET errstat %d len: %d", errstat, *len);
611 ptr = asn_parse_int (ptr, len, &type, &errindex, sizeof (errindex));
613 DEBUG2 ("SMUX GET errindex %d len: %d", errindex, *len);
619 smux_parse_set (char *ptr, size_t len, int action)
622 oid oid[MAX_OID_LEN];
629 DEBUG2 ("SMUX SET(%s) message parse: len %d",
630 (RESERVE1 == action) ? "RESERVE1" : ((FREE == action) ? "FREE" : "COMMIT"),
633 /* Parse SET message header. */
634 ptr = smux_parse_get_header (ptr, &len, &reqid);
636 /* Parse SET message object ID. */
637 ptr = smux_var (ptr, len, oid, &oid_len, &val_len, &val_type, &val);
639 ret = smux_set (oid, &oid_len, val_type, val, val_len, action);
640 DEBUG2 ("SMUX SET ret %d", ret);
643 if (RESERVE1 == action)
644 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
648 smux_parse_get (char *ptr, size_t len, int exact)
651 oid oid[MAX_OID_LEN];
658 DEBUG2 ("SMUX GET message parse: len %d", len);
660 /* Parse GET message header. */
661 ptr = smux_parse_get_header (ptr, &len, &reqid);
663 /* Parse GET message object ID. We needn't the value come */
664 ptr = smux_var (ptr, len, oid, &oid_len, NULL, NULL, NULL);
666 /* Traditional getstatptr. */
668 ret = smux_get (oid, &oid_len, exact, &val_type, &val, &val_len);
670 ret = smux_getnext (oid, &oid_len, exact, &val_type, &val, &val_len);
674 smux_getresp_send (oid, oid_len, reqid, 0, 0, val_type, val, val_len);
676 smux_getresp_send (oid, oid_len, reqid, ret, 3, ASN_NULL, NULL, 0);
679 /* Parse SMUX_CLOSE message. */
681 smux_parse_close (char *ptr, int len)
687 reason = (reason << 8) | (long) *ptr;
690 DEBUG ("SMUX_CLOSE with reason: %d", reason);
693 /* SMUX_RRSP message. */
695 smux_parse_rrsp (char *ptr, int len)
700 ptr = asn_parse_int (ptr, &len, &val, &errstat, sizeof (errstat));
702 DEBUG2 ("SMUX_RRSP value: %d errstat: %d", val, errstat);
705 /* Parse SMUX message. */
707 smux_parse (char *ptr, int len)
709 /* this buffer we'll use for SOUT message. We could allocate it with malloc and
710 save only static pointer/lenght, but IMHO static buffer is a faster solusion */
711 static u_char sout_save_buff[SMUXMAXPKTSIZE];
712 static int sout_save_len = 0;
714 int len_income = len; /* see note below: YYY */
718 rollback = ptr[2]; /* important only for SMUX_SOUT */
720 process_rest: /* see note below: YYY */
722 /* Parse SMUX message type and subsequent length. */
723 ptr = asn_parse_header (ptr, &len, &type);
725 DEBUG2 ("SMUX message received type: %d rest len: %d", type, len);
730 /* Open must be not send from SNMP agent. */
731 DEBUG ("SMUX_OPEN received: resetting connection.");
735 /* SMUX_RREQ message is invalid for us. */
736 DEBUG ("SMUX_RREQ received: resetting connection.");
740 /* SMUX_SOUT message is now valied for us. */
741 DEBUG2 ("SMUX_SOUT(%s)", rollback ? "rollback" : "commit");
743 if (sout_save_len > 0)
745 smux_parse_set (sout_save_buff, sout_save_len, rollback ? FREE : COMMIT);
749 DEBUG ("SMUX_SOUT sout_save_len=%d - invalid", (int) sout_save_len);
753 /* YYY: this strange code has to solve the "slow peer"
754 problem: When agent sends SMUX_SOUT message it doesn't
755 wait any responce and may send some next message to
756 subagent. Then the peer in 'smux_read()' will recieve
757 from socket the 'concatenated' buffer, contaning both
758 SMUX_SOUT message and the next one
759 (SMUX_GET/SMUX_GETNEXT/SMUX_GET). So we should check: if
760 the buffer is longer than 3 ( length of SMUX_SOUT ), we
761 must process the rest of it. This effect may be observed
762 if DEBUG is set to >1 */
764 len = len_income - 3;
769 /* SMUX_GETRSP message is invalid for us. */
770 DEBUG ("SMUX_GETRSP received: resetting connection.");
774 /* Close SMUX connection. */
775 DEBUG2 ("SMUX_CLOSE");
776 smux_parse_close (ptr, len);
780 /* This is response for register message. */
781 DEBUG2 ("SMUX_RRSP");
782 smux_parse_rrsp (ptr, len);
785 /* Exact request for object id. */
787 smux_parse_get (ptr, len, 1);
790 /* Next request for object id. */
791 DEBUG2 ("SMUX_GETNEXT");
792 smux_parse_get (ptr, len, 0);
795 /* SMUX_SET is supported with some limitations. */
798 /* save the data for future SMUX_SOUT */
799 memcpy (sout_save_buff, ptr, len);
801 smux_parse_set (ptr, len, RESERVE1);
804 DEBUG ("Unknown type: %d", type);
810 /* SMUX message read function. */
815 u_char buf[SMUXMAXPKTSIZE];
818 smux_event=SMUX_NONE;
819 DEBUG2 ("SMUX read start");
821 /* Read message from SMUX socket. */
822 len = recv (smuxfd, buf, SMUXMAXPKTSIZE, 0);
826 DEBUG ("Can't read all SMUX packet: %s", strerror (errno));
829 smux_event=SMUX_CONNECT;
835 DEBUG ("SMUX connection closed: %d", smuxfd);
838 smux_event=SMUX_CONNECT;
842 DEBUG2 ("SMUX read len: %d", len);
844 /* Parse the message. */
845 ret = smux_parse (buf, len);
851 smux_event=SMUX_CONNECT;
855 smux_event=SMUX_READ;
867 u_char progname[] = "radiusd";
869 smux_oid_dump ("SMUX open oid", smux_oid, smux_oid_len);
870 DEBUG2 ("SMUX open progname: %s", progname);
871 DEBUG2 ("SMUX open password: %s", smux_password);
876 /* SMUX Header. As placeholder. */
877 ptr = asn_build_header (ptr, &len, (u_char) SMUX_OPEN, 0);
881 ptr = asn_build_int (ptr, &len,
882 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
883 &version, sizeof (u_long));
885 /* SMUX connection oid. */
886 ptr = asn_build_objid (ptr, &len,
888 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
889 smux_oid, smux_oid_len);
891 /* SMUX connection description. */
892 ptr = asn_build_string (ptr, &len,
894 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
895 progname, strlen (progname));
897 /* SMUX connection password. */
898 ptr = asn_build_string (ptr, &len,
900 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OCTET_STR),
901 smux_password, strlen (smux_password));
903 /* Fill in real SMUX header. We exclude ASN header size (2). */
905 asn_build_header (buf, &len, (u_char) SMUX_OPEN, (ptr - buf) - 2);
907 return send (smuxfd, buf, (ptr - buf), 0);
918 struct subtree *subtree;
923 for (l = treelist; l; l=l->next)
930 /* SMUX RReq Header. */
931 ptr = asn_build_header (ptr, &len, (u_char) SMUX_RREQ, 0);
933 /* Register MIB tree. */
934 ptr = asn_build_objid (ptr, &len,
936 (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
937 subtree->name, subtree->name_len);
941 ptr = asn_build_int (ptr, &len,
942 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
943 &priority, sizeof (u_long));
947 ptr = asn_build_int (ptr, &len,
948 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
949 &operation, sizeof (u_long));
951 smux_oid_dump ("SMUX register oid", subtree->name, subtree->name_len);
952 DEBUG2 ("SMUX register priority: %d", priority);
953 DEBUG2 ("SMUX register operation: %d", operation);
956 asn_build_header (buf, &len, (u_char) SMUX_RREQ, (ptr - buf) - 2);
957 ret = send (smuxfd, buf, (ptr - buf), 0);
964 /* Try to connect to SNMP agent. */
970 smux_event=SMUX_NONE;
971 DEBUG2 ("SMUX connect try %d", fail + 1);
973 /* Make socket. Try to connect. */
977 if (++fail < SMUX_MAX_FAILURE)
978 smux_event=SMUX_CONNECT;
986 DEBUG ("SMUX open message send failed: %s", strerror (errno));
989 smux_event=SMUX_CONNECT;
993 /* Send any outstanding register PDUs. */
994 ret = smux_register ();
997 DEBUG ("SMUX register message send failed: %s", strerror (errno));
1000 smux_event=SMUX_CONNECT;
1004 /* Everything goes fine. */
1005 smux_event=SMUX_READ;
1010 /* Clear all SMUX related resources. */
1014 smux_event=SMUX_NONE;
1021 smux_str2oid (char *str, oid *oid, size_t *oid_len)
1037 if (! isdigit (*str))
1040 while (isdigit (*str))
1043 val += (*str - '0');
1064 smux_oid_dup (oid *objid, size_t objid_len)
1068 new = (oid *)malloc(sizeof (oid) * objid_len);
1069 oid_copy (new, objid, objid_len);
1075 smux_header_generic (struct variable *v, oid *name, size_t *length, int exact,
1076 size_t *var_len, WriteMethod **write_method)
1078 oid fulloid[MAX_OID_LEN];
1081 oid_copy (fulloid, v->name, v->namelen);
1082 fulloid[v->namelen] = 0;
1083 /* Check against full instance. */
1084 ret = oid_compare (name, *length, fulloid, v->namelen + 1);
1086 /* Check single instance. */
1087 if ((exact && (ret != 0)) || (!exact && (ret >= 0)))
1088 return MATCH_FAILED;
1090 /* In case of getnext, fill in full instance. */
1091 memcpy (name, fulloid, (v->namelen + 1) * sizeof (oid));
1092 *length = v->namelen + 1;
1095 *var_len = sizeof(long); /* default to 'long' results */
1097 return MATCH_SUCCEEDED;
1100 /* Initialize some values then schedule first SMUX connection. */
1102 smux_init (oid defoid[], size_t defoid_len)
1105 smux_oid_len = defoid_len;
1108 /* Register subtree to smux master tree. */
1110 smux_register_mib(char *descr, struct variable *var, size_t width, int num,
1111 oid name[], size_t namelen)
1113 struct subtree *tree;
1116 tree = (struct subtree *)malloc(sizeof(struct subtree));
1117 oid_copy (tree->name, name, namelen);
1118 tree->name_len = namelen;
1119 tree->variables = var;
1120 tree->variables_num = num;
1121 tree->variables_width = width;
1122 tree->registered = 0;
1123 l = (struct list *)malloc(sizeof(struct list));
1126 if (treelist == NULL)
1131 for (ll = treelist; ll->next; ll=ll->next);
1139 smux_event=SMUX_CONNECT;
1141 #endif /* WITH_SNMP */