📄 smux.c
字号:
/* SNMP support * Copyright (C) 1999 Kunihiro Ishiguro <kunihiro@zebra.org> * * This file is part of GNU Zebra. * * GNU Zebra is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * GNU Zebra is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with GNU Zebra; see the file COPYING. If not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */#include <zebra.h>#ifdef HAVE_SNMP#include <asn1.h>#include <snmp.h>#include <snmp_impl.h>#include "smux.h"#include "log.h"#include "thread.h"#include "linklist.h"#include "command.h"#include "version.h"#include "memory.h"#include "sockunion.h"#define min(A,B) ((A) < (B) ? (A) : (B))enum smux_event {SMUX_SCHEDULE, SMUX_CONNECT, SMUX_READ};void smux_event (enum smux_event, int);/* SMUX socket. */int smux_sock = -1;/* SMUX subtree list. */struct list *treelist;/* SMUX oid. */oid *smux_oid;size_t smux_oid_len;/* SMUX default oid. */oid *smux_default_oid;size_t smux_default_oid_len;/* SMUX password. */char *smux_passwd;char *smux_default_passwd = "";/* SMUX read threads. */struct thread *smux_read_thread;/* SMUX connect thrads. */struct thread *smux_connect_thread;/* SMUX debug flag. */int debug_smux = 0;/* SMUX failure count. */int fail = 0;/* SMUX node. */struct cmd_node smux_node ={ SMUX_NODE, "" /* SMUX has no interface. */};void *oid_copy (void *dest, void *src, size_t size){ return memcpy (dest, src, size * sizeof (oid));}voidoid2in_addr (oid oid[], int len, struct in_addr *addr){ int i; u_char *pnt; if (len == 0) return; pnt = (u_char *) addr; for (i = 0; i < len; i++) *pnt++ = oid[i];}voidoid_copy_addr (oid oid[], struct in_addr *addr, int len){ int i; u_char *pnt; if (len == 0) return; pnt = (u_char *) addr; for (i = 0; i < len; i++) oid[i] = *pnt++;}intoid_compare (oid *o1, int o1_len, oid *o2, int o2_len){ int i; for (i = 0; i < min (o1_len, o2_len); i++) { if (o1[i] < o2[i]) return -1; else if (o1[i] > o2[i]) return 1; } if (o1_len < o2_len) return -1; if (o1_len > o2_len) return 1; return 0;}intoid_compare_part (oid *o1, int o1_len, oid *o2, int o2_len){ int i; for (i = 0; i < min (o1_len, o2_len); i++) { if (o1[i] < o2[i]) return -1; else if (o1[i] > o2[i]) return 1; } if (o1_len < o2_len) return -1; return 0;}voidsmux_oid_dump (char *prefix, oid *oid, size_t oid_len){ int i; int first = 1; char buf[MAX_OID_LEN * 3]; buf[0] = '\0'; for (i = 0; i < oid_len; i++) { sprintf (buf + strlen (buf), "%s%d", first ? "" : ".", (int) oid[i]); first = 0; } zlog_info ("%s: %s", prefix, buf);}intsmux_socket (){ int ret;#ifdef HAVE_IPV6 struct addrinfo hints, *res0, *res; int gai;#else struct sockaddr_in serv; struct servent *sp;#endif int sock = 0;#ifdef HAVE_IPV6 memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; gai = getaddrinfo(NULL, "smux", &hints, &res0); if (gai == EAI_SERVICE) { char servbuf[NI_MAXSERV]; sprintf(servbuf,"%d",SMUX_PORT_DEFAULT); servbuf[sizeof (servbuf) - 1] = '\0'; gai = getaddrinfo(NULL, servbuf, &hints, &res0); } if (gai) { zlog_warn("Cannot locate loopback service smux"); return -1; } for(res=res0; res; res=res->ai_next) { if (res->ai_family != AF_INET #ifdef HAVE_IPV6 && res->ai_family != AF_INET6#endif /* HAVE_IPV6 */ ) continue; sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sock < 0) continue; sockopt_reuseaddr (sock); sockopt_reuseport (sock); ret = connect (sock, res->ai_addr, res->ai_addrlen); if (ret < 0) { close(sock); sock = -1; continue; } break; } freeaddrinfo(res0); if (sock < 0) zlog_warn ("Can't connect to SNMP agent with SMUX");#else sock = socket (AF_INET, SOCK_STREAM, 0); if (sock < 0) { zlog_warn ("Can't make socket for SNMP"); return -1; } memset (&serv, 0, sizeof (struct sockaddr_in)); serv.sin_family = AF_INET;#ifdef HAVE_SIN_LEN serv.sin_len = sizeof (struct sockaddr_in);#endif /* HAVE_SIN_LEN */ sp = getservbyname ("smux", "tcp"); if (sp != NULL) serv.sin_port = sp->s_port; else serv.sin_port = htons (SMUX_PORT_DEFAULT); serv.sin_addr.s_addr = htonl (INADDR_LOOPBACK); sockopt_reuseaddr (sock); sockopt_reuseport (sock); ret = connect (sock, (struct sockaddr *) &serv, sizeof (struct sockaddr_in)); if (ret < 0) { close (sock); smux_sock = -1; zlog_warn ("Can't connect to SNMP agent with SMUX"); return -1; }#endif return sock;}voidsmux_getresp_send (oid objid[], size_t objid_len, long reqid, long errstat, long errindex, u_char val_type, void *arg, size_t arg_len){ int ret; u_char buf[BUFSIZ]; u_char *ptr, *h1, *h1e, *h2, *h2e; int len, length; ptr = buf; len = BUFSIZ; length = len; if (debug_smux) { zlog_info ("SMUX GETRSP send"); zlog_info ("SMUX GETRSP reqid: %ld", reqid); } h1 = ptr; /* Place holder h1 for complete sequence */ ptr = asn_build_sequence (ptr, &len, (u_char) SMUX_GETRSP, 0); h1e = ptr; ptr = asn_build_int (ptr, &len, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), &reqid, sizeof (reqid)); if (debug_smux) zlog_info ("SMUX GETRSP errstat: %ld", errstat); ptr = asn_build_int (ptr, &len, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), &errstat, sizeof (errstat)); if (debug_smux) zlog_info ("SMUX GETRSP errindex: %ld", errindex); ptr = asn_build_int (ptr, &len, (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER), &errindex, sizeof (errindex)); h2 = ptr; /* Place holder h2 for one variable */ ptr = asn_build_sequence (ptr, &len, (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR), 0); h2e = ptr; ptr = snmp_build_var_op (ptr, objid, &objid_len, val_type, arg_len, arg, &len); /* Now variable size is known, fill in size */ asn_build_sequence(h2,&length,(u_char)(ASN_SEQUENCE|ASN_CONSTRUCTOR),ptr-h2e); /* Fill in size of whole sequence */ asn_build_sequence(h1,&length,(u_char)SMUX_GETRSP,ptr-h1e); if (debug_smux) zlog_info ("SMUX getresp send: %d", ptr - buf); ret = send (smux_sock, buf, (ptr - buf), 0);}char *smux_var (char *ptr, int len, oid objid[], size_t *objid_len, size_t *var_val_len, u_char *var_val_type, void **var_value){ u_char type; u_char val_type; size_t val_len; u_char *val; if (debug_smux) zlog_info ("SMUX var parse: len %d", len); /* Parse header. */ ptr = asn_parse_header (ptr, &len, &type); if (debug_smux) { zlog_info ("SMUX var parse: type %d len %d", type, len); zlog_info ("SMUX var parse: type must be %d", (ASN_SEQUENCE | ASN_CONSTRUCTOR)); } /* Parse var option. */ *objid_len = MAX_OID_LEN; ptr = snmp_parse_var_op(ptr, objid, objid_len, &val_type, &val_len, &val, &len); if (var_val_len) *var_val_len = val_len; if (var_value) *var_value = (void*) val; if (var_val_type) *var_val_type = val_type; /* Requested object id length is objid_len. */ if (debug_smux) smux_oid_dump ("Request OID", objid, *objid_len); if (debug_smux) zlog_info ("SMUX val_type: %d", val_type); /* Check request value type. */ if (debug_smux) switch (val_type) { case ASN_NULL: /* In case of SMUX_GET or SMUX_GET_NEXT val_type is set to ASN_NULL. */ zlog_info ("ASN_NULL"); break; case ASN_INTEGER: zlog_info ("ASN_INTEGER"); break; case ASN_COUNTER: case ASN_GAUGE: case ASN_TIMETICKS: case ASN_UINTEGER: zlog_info ("ASN_COUNTER"); break; case ASN_COUNTER64: zlog_info ("ASN_COUNTER64"); break; case ASN_IPADDRESS: zlog_info ("ASN_IPADDRESS"); break; case ASN_OCTET_STR: zlog_info ("ASN_OCTET_STR"); break; case ASN_OPAQUE: case ASN_NSAP: case ASN_OBJECT_ID: zlog_info ("ASN_OPAQUE"); break; case SNMP_NOSUCHOBJECT: zlog_info ("SNMP_NOSUCHOBJECT"); break; case SNMP_NOSUCHINSTANCE: zlog_info ("SNMP_NOSUCHINSTANCE"); break; case SNMP_ENDOFMIBVIEW: zlog_info ("SNMP_ENDOFMIBVIEW"); break; case ASN_BIT_STR: zlog_info ("ASN_BIT_STR"); break; default: zlog_info ("Unknown type"); break; } return ptr;}/* NOTE: all 3 functions (smux_set, smux_get & smux_getnext) are based on ucd-snmp smux and as such suppose, that the peer receives in the message only one variable. Fortunately, IBM seems to do the same in AIX. */intsmux_set (oid *reqid, size_t *reqid_len, u_char val_type, void *val, size_t val_len, int action){ int j; struct subtree *subtree; struct variable *v; int subresult; oid *suffix; int suffix_len; int result; u_char *statP = NULL; WriteMethod *write_method = NULL; struct listnode *node; /* Check */ for (node = treelist->head; node; node = node->next) { subtree = node->data; subresult = oid_compare_part (reqid, *reqid_len, subtree->name, subtree->name_len); /* Subtree matched. */ if (subresult == 0) { /* Prepare suffix. */ suffix = reqid + subtree->name_len; suffix_len = *reqid_len - subtree->name_len; result = subresult; /* Check variables. */ for (j = 0; j < subtree->variables_num; j++) { v = &subtree->variables[j]; /* Always check suffix */ result = oid_compare_part (suffix, suffix_len, v->name, v->namelen); /* This is exact match so result must be zero. */ if (result == 0) { if (debug_smux) zlog_info ("SMUX function call index is %d", v->magic); statP = (*v->findVar) (v, suffix, &suffix_len, 1, &val_len, &write_method); if (write_method) { return (*write_method)(action, val, val_type, val_len, statP, suffix, suffix_len, v); } else { return SNMP_ERR_READONLY; } } /* If above execution is failed or oid is small (so there is no further match). */ if (result < 0) return SNMP_ERR_NOSUCHNAME; } } } return SNMP_ERR_NOSUCHNAME;}intsmux_get (oid *reqid, size_t *reqid_len, int exact,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -