📄 smux.c
字号:
/* * Smux module authored by Rohit Dube. * Rewritten by Nick Amato <naamato@merit.net>. */#include <config.h>#include <sys/types.h>#include <ctype.h>#if HAVE_IO_H /* win32 */#include <io.h>#endif#include <stdio.h>#if HAVE_STDLIB_H#include <stdlib.h>#endif#if HAVE_STRING_H#include <string.h>#else#include <strings.h>#endif#if HAVE_UNISTD_H#include <unistd.h>#endif#if HAVE_ERR_H#include <err.h>#endif#if TIME_WITH_SYS_TIME# ifdef WIN32# include <sys/timeb.h># else# include <sys/time.h># endif# include <time.h>#else# if HAVE_SYS_TIME_H# include <sys/time.h># else# include <time.h># endif#endif#include <errno.h>#if HAVE_NETDB_H#include <netdb.h>#endif#include <sys/stat.h>#if HAVE_SYS_SOCKET_H#include <sys/socket.h>#elif HAVE_WINSOCK_H#include <winsock.h>#endif#if HAVE_SYS_FILIO_H#include <sys/filio.h>#endif#if HAVE_NETINET_IN_H#include <netinet/in.h>#endif#if HAVE_SYS_IOCTL_H#include <sys/ioctl.h>#endif#include "../../../snmplib/system.h"#include "asn1.h"#include "mibincl.h"#include "mib.h"#include "read_config.h"#include "snmp.h"#include "snmp_api.h"#include "snmp_client.h"#include "snmp_impl.h"#include "smux.h"#include "var_struct.h"#include "util_funcs.h"#include "mibdefs.h"long smux_long;u_long smux_ulong;struct sockaddr_in smux_sa;struct counter64 smux_counter64;oid smux_objid[MAX_OID_LEN];u_char smux_str[SMUXMAXSTRLEN];extern int smux_listen_sd;static struct timeval smux_rcv_timeout;static u_long smux_reqid;void init_smux (void);static u_char *smux_open_process (int, u_char *, size_t *, int *);static u_char *smux_rreq_process (int, u_char *, size_t *);static u_char *smux_close_process (int, u_char *, size_t *);static u_char *smux_trap_process (u_char *, size_t *);static u_char *smux_parse (u_char *, oid *, size_t *, size_t *, u_char *);static u_char *smux_parse_var (u_char *, size_t *, oid *, size_t *, size_t *, u_char *);static void smux_send_close (int, int);static void smux_list_detach (smux_reg **, smux_reg **);static void smux_replace_active (smux_reg *, smux_reg *);static void smux_peer_cleanup (int);static int smux_auth_peer (oid *, size_t, char *, int);static int smux_build (u_char, u_long, oid *, size_t *, u_char, u_char *, size_t, u_char *, size_t *);static int smux_list_add (smux_reg **, smux_reg *);static int smux_pdu_process(int, u_char *, size_t);static int smux_send_rrsp (int, int);static smux_reg *smux_find_match(smux_reg *, int, oid *, size_t, long);static smux_reg *smux_find_replacement (oid *, size_t);u_char *var_smux (struct variable *, oid *, size_t *, int, size_t *, WriteMethod **write_method);int var_smux_write (int, u_char *, u_char, size_t, u_char *, oid *, size_t);static smux_reg *ActiveRegs; /* Active registrations */static smux_reg *PassiveRegs; /* Currently unused registrations */static smux_peer_auth *Auths[SMUX_MAX_PEERS]; /* Configured peers */static int nauths, npeers = 0;struct variable2 smux_variables[] = { /* bogus entry, as in pass.c */ {MIBINDEX, ASN_PRIV_DELEGATED, RWRITE, var_smux, 0, {MIBINDEX}},};voidsmux_parse_peer_auth(const char *token, char *cptr){ smux_peer_auth *aptr; if ((aptr = (smux_peer_auth *)calloc(1, sizeof(smux_peer_auth))) == NULL) { snmp_log_perror("smux_parse_peer_auth: malloc"); return; } aptr->sa_active_fd = -1; if (!cptr) { /* null passwords OK */ Auths[nauths++] = aptr; DEBUGMSGTL(("smux_conf", "null password\n")); return; } if(*cptr == '.') cptr++; if (!isdigit(*cptr)) { config_perror("second token is not an OID"); free((char *)aptr); return; } /* oid */ aptr->sa_oid_len = parse_miboid(cptr, aptr->sa_oid); DEBUGMSGTL(("smux_conf", "parsing registration for: %s\n", cptr)); while (isdigit(*cptr) || *cptr == '.') cptr++; cptr = skip_white(cptr); /* password */ if (cptr) strcpy(aptr->sa_passwd, cptr); Auths[nauths++] = aptr;}voidsmux_free_peer_auth(void){ int i; for(i = 0; i < nauths; i++) { free(Auths[i]); Auths[i] = NULL; }}voidinit_smux(void){ struct sockaddr_in lo_socket; int one = 1; snmpd_register_config_handler("smuxpeer", smux_parse_peer_auth, smux_free_peer_auth, "OID-IDENTITY PASSWORD"); /* Reqid */ smux_reqid = 0; smux_listen_sd = -1; /* Receive timeout */ smux_rcv_timeout.tv_sec = 0; smux_rcv_timeout.tv_usec = 500000; /* Get ready to listen on the SMUX port*/ memset (&lo_socket,(0), sizeof (lo_socket)); lo_socket.sin_family = AF_INET; lo_socket.sin_port = htons((u_short) SMUXPORT); if ((smux_listen_sd = socket (AF_INET, SOCK_STREAM, 0)) < 0) { snmp_log_perror("[init_smux] socket failed"); return; } if (bind (smux_listen_sd, (struct sockaddr *) &lo_socket, sizeof (lo_socket)) < 0) { snmp_log_perror("[init_smux] bind failed"); close(smux_listen_sd); smux_listen_sd = -1; return; }#ifdef SO_KEEPALIVE if (setsockopt (smux_listen_sd, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof (one)) < 0) { snmp_log_perror("[init_smux] setsockopt(SO_KEEPALIVE) failed"); close(smux_listen_sd); smux_listen_sd = -1; return; }#endif /* SO_KEEPALIVE */ if(listen(smux_listen_sd, SOMAXCONN) == -1) { snmp_log_perror("[init_smux] listen failed"); close(smux_listen_sd); smux_listen_sd = -1; return; } DEBUGMSGTL(("smux_init", "[smux_init] done; smux listen sd is %d, smux port is %d\n", smux_listen_sd, ntohs(lo_socket.sin_port)));}u_char *var_smux(struct variable *vp, oid *name, size_t *length, int exact, size_t *var_len, WriteMethod **write_method){ u_char *valptr, val_type; smux_reg *rptr; *write_method = NULL; /* search the active registration list */ for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) { if (!compare_tree(name, *length, rptr->sr_name, rptr->sr_name_len)) break; } if (rptr == NULL) return NULL; else if (exact && (*length < rptr->sr_name_len)) return NULL; *write_method = var_smux_write; valptr = smux_snmp_process(exact, name, length, var_len, &val_type, rptr->sr_fd); if (valptr == NULL) return NULL; if ((compare_tree(name, *length, rptr->sr_name, rptr->sr_name_len)) != 0) { /* the peer has returned a value outside * of the registered tree */ return NULL; } else { /* set the type and return the value */ vp->type = val_type; return valptr; }}int var_smux_write( int action, u_char *var_val, u_char var_val_type, size_t var_val_len, u_char *statP, oid *name, size_t name_len){ smux_reg *rptr; u_char buf[SMUXMAXPKTSIZE], *ptr, sout[3], type; int reterr; size_t len, var_len, datalen, name_length; long reqid, errsts, erridx; u_char var_type, *dataptr; DEBUGMSGTL (("smux","[var_smux_write] entering var_smux_write\n")); len = SMUXMAXPKTSIZE; reterr = SNMP_ERR_NOERROR; var_len = var_val_len; var_type = var_val_type; name_length = name_len; /* XXX find the descriptor again */ for (rptr = ActiveRegs; rptr; rptr = rptr->sr_next) { if (!compare_tree(name, name_len, rptr->sr_name, rptr->sr_name_len)) break; } switch (action) { case RESERVE1: DEBUGMSGTL (("smux","[var_smux_write] entering RESERVE1\n")); /* length might be long */ var_len += (*(var_val + 1) & ASN_LONG_LEN) ? var_len + ((*(var_val + 1) & 0x7F) + 2) : 2; switch (var_val_type) { case ASN_INTEGER: case ASN_OCTET_STR: case ASN_COUNTER: case ASN_GAUGE: case ASN_TIMETICKS: case ASN_UINTEGER: case ASN_COUNTER64: case ASN_IPADDRESS: case ASN_OPAQUE: case ASN_NSAP: case ASN_OBJECT_ID: case ASN_BIT_STR: datalen = var_val_len; dataptr = var_val; break; case SNMP_NOSUCHOBJECT: case SNMP_NOSUCHINSTANCE: case SNMP_ENDOFMIBVIEW: case ASN_NULL: default: DEBUGMSGTL (("smux","[var_smux_write] variable not supported\n")); return SNMP_ERR_GENERR; break; } if ((smux_build((u_char)SMUX_SET, smux_reqid, name, &name_length, var_val_type, dataptr, datalen, buf, &len)) < 0) { DEBUGMSGTL (("smux","[var_smux_write] smux build failed\n")); return SNMP_ERR_GENERR; } if (send(rptr->sr_fd, buf, len, 0) < 0) { DEBUGMSGTL (("smux","[var_smux_write] send failed\n")); return SNMP_ERR_GENERR; } if ((len = recv(rptr->sr_fd, buf, SMUXMAXPKTSIZE, 0)) <= 0) { DEBUGMSGTL (("smux","[var_smux_write] recv failed or timed out\n")); /* do we need to do a peer cleanup in this case?? */ smux_peer_cleanup(rptr->sr_fd); return SNMP_ERR_GENERR; } ptr = buf; ptr = asn_parse_header(ptr, &len, &type); if ((ptr == NULL) || type != SNMP_MSG_RESPONSE) return SNMP_ERR_GENERR; ptr = asn_parse_int(ptr, &len, &type, &reqid, sizeof(reqid)); if ((ptr == NULL) || type != ASN_INTEGER) return SNMP_ERR_GENERR; ptr = asn_parse_int(ptr, &len, &type, &errsts, sizeof(errsts)); if ((ptr == NULL) || type != ASN_INTEGER) return SNMP_ERR_GENERR; if (errsts) { DEBUGMSGTL (("smux","[var_smux_write] errsts returned\n")); return (errsts); } ptr = asn_parse_int(ptr, &len, &type, &erridx, sizeof(erridx)); if ((ptr == NULL) || type != ASN_INTEGER) return SNMP_ERR_GENERR; reterr = SNMP_ERR_NOERROR; break; /* case Action == RESERVE1 */ case RESERVE2: DEBUGMSGTL (("smux","[var_smux_write] entering RESERVE2\n")); reterr = SNMP_ERR_NOERROR; break; /* case Action == RESERVE2 */ case FREE: case COMMIT: ptr = sout; *(ptr++) = (u_char)SMUX_SOUT; *(ptr++) = (u_char)1; if (action==FREE) { *ptr = (u_char)1; /* rollback */ DEBUGMSGTL (("smux","[var_smux_write] entering FREE - sending RollBack \n")); } else { *ptr = (u_char)0; /* commit */ DEBUGMSGTL (("smux","[var_smux_write] entering FREE - sending Commit \n")); } if ((send(rptr->sr_fd, sout, 3, 0)) < 0) { DEBUGMSGTL (("smux","[var_smux_write] send rollback/commit failed\n")); return SNMP_ERR_GENERR; } reterr = SNMP_ERR_NOERROR; break; /* case Action == COMMIT */ default: break; } return reterr;}intsmux_accept(int sd){ u_char data[SMUXMAXPKTSIZE], *ptr, type; struct sockaddr_in in_socket; struct timeval tv; int fail, fd, alen; size_t length, len; alen = sizeof(struct sockaddr_in); /* this may be too high */ tv.tv_sec = 5; tv.tv_usec = 0; /* connection request */ DEBUGMSGTL (("smux","[smux_accept] Calling accept()\n")); errno = 0; if((fd = accept(sd, (struct sockaddr *)&in_socket, &alen)) < 0) { snmp_log_perror("[smux_accept] accept failed"); return -1; } else { snmp_log(LOG_ERR, "[smux_accept] accepted fd %d - errno %d\n", fd, errno); if (npeers + 1 == SMUXMAXPEERS) { DEBUGMSGTL (("smux","[smux_accept] denied peer on fd %d, limit reached", fd)); close(sd); return -1; } /* now block for an OpenPDU */ if ((length = recv(fd, (char *)data, SMUXMAXPKTSIZE, 0)) <= 0) { DEBUGMSGTL (("smux","[smux_accept] peer on fd %d died or timed out\n", fd)); close(fd); return -1; } /* try to authorize him */ ptr = data; len = length; if ((ptr = asn_parse_header(ptr, &len, &type)) == NULL) { smux_send_close(fd, SMUXC_PACKETFORMAT); close(fd); DEBUGMSGTL (("smux","[smux_accept] peer on %d sent bad open")); return -1; } else if (type != (u_char)SMUX_OPEN) { smux_send_close(fd, SMUXC_PROTOCOLERROR); close(fd); DEBUGMSGTL (("smux","[smux_accept] peer on %d did not send open: (%d)\n", type)); return -1; } ptr = smux_open_process(fd, ptr, &len, &fail); if (fail) { smux_send_close(fd, SMUXC_AUTHENTICATIONFAILURE); close(fd); DEBUGMSGTL (("smux","[smux_accept] peer on %d failed authentication\n", fd)); return -1; } /* he's OK */#ifdef SO_RCVTIMEO if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (void *)&tv, sizeof(tv)) < 0) { DEBUGMSGTL (("smux","[smux_accept] setsockopt(SO_RCVTIMEO) failed fd %d\n", fd)); snmp_log_perror("smux/setsockopt"); }#endif npeers++; DEBUGMSGTL (("smux","[smux_accept] fd %d\n", fd)); /* Process other PDUs already read, e.g. a registerRequest. */ len = length - (ptr - data); if (smux_pdu_process(fd, ptr, len) < 0) { /* Easy come, easy go. Clean-up is already done. */ return -1; } } return fd;}intsmux_process(int fd){ size_t length; u_char data[SMUXMAXPKTSIZE]; length = recv(fd, (char *)data, SMUXMAXPKTSIZE, 0); if (length <= 0) { /* the peer went away, close this descriptor * and delete it from the list */ DEBUGMSGTL (("smux","[smux_process] peer on fd %d died or timed out\n", fd)); smux_peer_cleanup(fd); return -1; } return smux_pdu_process(fd, data, length);}static intsmux_pdu_process(int fd, u_char *data, size_t length){ int error; size_t len; u_char *ptr, type; DEBUGMSGTL (("smux","[smux_pdu_process] Processing %d bytes\n", length)); error = 0; ptr = data; while (error == 0 && ptr != NULL && ptr < data + length) { len = length - (ptr - data); ptr = asn_parse_header(ptr, &len, &type);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -