src/snmp_core.cc
Go to the documentation of this file.
00001 /* 00002 * DEBUG: section 49 SNMP support 00003 * AUTHOR: Glenn Chisholm 00004 * 00005 * SQUID Web Proxy Cache http://www.squid-cache.org/ 00006 * ---------------------------------------------------------- 00007 * 00008 * Squid is the result of efforts by numerous individuals from 00009 * the Internet community; see the CONTRIBUTORS file for full 00010 * details. Many organizations have provided support for Squid's 00011 * development; see the SPONSORS file for full details. Squid is 00012 * Copyrighted (C) 2001 by the Regents of the University of 00013 * California; see the COPYRIGHT file for full details. Squid 00014 * incorporates software developed and/or copyrighted by other 00015 * sources; see the CREDITS file for full details. 00016 * 00017 * This program is free software; you can redistribute it and/or modify 00018 * it under the terms of the GNU General Public License as published by 00019 * the Free Software Foundation; either version 2 of the License, or 00020 * (at your option) any later version. 00021 * 00022 * This program is distributed in the hope that it will be useful, 00023 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00024 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00025 * GNU General Public License for more details. 00026 * 00027 * You should have received a copy of the GNU General Public License 00028 * along with this program; if not, write to the Free Software 00029 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. 00030 * 00031 */ 00032 #include "squid.h" 00033 #include "acl/FilledChecklist.h" 00034 #include "cache_snmp.h" 00035 #include "comm.h" 00036 #include "ipc/StartListening.h" 00037 #include "ip/Address.h" 00038 #include "ip/tools.h" 00039 00040 #define SNMP_REQUEST_SIZE 4096 00041 #define MAX_PROTOSTAT 5 00042 00044 class SnmpListeningStartedDialer: public CallDialer, 00045 public Ipc::StartListeningCb 00046 { 00047 public: 00048 typedef void (*Handler)(int fd, int errNo); 00049 SnmpListeningStartedDialer(Handler aHandler): handler(aHandler) {} 00050 00051 virtual void print(std::ostream &os) const { startPrint(os) << ')'; } 00052 00053 virtual bool canDial(AsyncCall &) const { return true; } 00054 virtual void dial(AsyncCall &) { (handler)(fd, errNo); } 00055 00056 public: 00057 Handler handler; 00058 }; 00059 00060 00061 Ip::Address theOutSNMPAddr; 00062 00063 typedef struct _mib_tree_entry mib_tree_entry; 00064 typedef oid *(instance_Fn) (oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); 00065 00066 struct _mib_tree_entry { 00067 oid *name; 00068 int len; 00069 oid_ParseFn *parsefunction; 00070 instance_Fn *instancefunction; 00071 int children; 00072 00073 struct _mib_tree_entry **leaves; 00074 00075 struct _mib_tree_entry *parent; 00076 }; 00077 00078 mib_tree_entry *mib_tree_head; 00079 mib_tree_entry *mib_tree_last; 00080 00081 static void snmpIncomingConnectionOpened(int fd, int errNo); 00082 static void snmpOutgoingConnectionOpened(int fd, int errNo); 00083 00084 static mib_tree_entry * snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction); 00085 static mib_tree_entry *snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, int children,...); 00086 static oid *snmpCreateOid(int length,...); 00087 mib_tree_entry * snmpLookupNodeStr(mib_tree_entry *entry, const char *str); 00088 int snmpCreateOidFromStr(const char *str, oid **name, int *nl); 00089 SQUIDCEXTERN void (*snmplib_debug_hook) (int, char *); 00090 static oid *static_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); 00091 static oid *time_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); 00092 static oid *peer_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); 00093 static oid *client_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn); 00094 static void snmpDecodePacket(snmp_request_t * rq); 00095 static void snmpConstructReponse(snmp_request_t * rq); 00096 00097 static struct snmp_pdu *snmpAgentResponse(struct snmp_pdu *PDU); 00098 static oid_ParseFn *snmpTreeNext(oid * Current, snint CurrentLen, oid ** Next, snint * NextLen); 00099 static oid_ParseFn *snmpTreeGet(oid * Current, snint CurrentLen); 00100 static mib_tree_entry *snmpTreeEntry(oid entry, snint len, mib_tree_entry * current); 00101 static mib_tree_entry *snmpTreeSiblingEntry(oid entry, snint len, mib_tree_entry * current); 00102 static void snmpSnmplibDebug(int lvl, char *buf); 00103 00104 /* 00105 * The functions used during startup: 00106 * snmpInit 00107 * snmpConnectionOpen 00108 * snmpConnectionShutdown 00109 * snmpConnectionClose 00110 */ 00111 00112 /* 00113 * Turns the MIB into a Tree structure. Called during the startup process. 00114 */ 00115 void 00116 snmpInit(void) 00117 { 00118 debugs(49, 5, "snmpInit: Building SNMP mib tree structure"); 00119 00120 snmplib_debug_hook = snmpSnmplibDebug; 00121 00122 /* 00123 * This following bit of evil is to get the final node in the "squid" mib 00124 * without having a "search" function. A search function should be written 00125 * to make this and the other code much less evil. 00126 */ 00127 mib_tree_head = snmpAddNode(snmpCreateOid(1, 1), 1, NULL, NULL, 0); 00128 00129 assert(mib_tree_head); 00130 debugs(49, 5, "snmpInit: root is " << mib_tree_head); 00131 snmpAddNodeStr("1", 3, NULL, NULL); 00132 00133 snmpAddNodeStr("1.3", 6, NULL, NULL); 00134 00135 snmpAddNodeStr("1.3.6", 1, NULL, NULL); 00136 snmpAddNodeStr("1.3.6.1", 4, NULL, NULL); 00137 snmpAddNodeStr("1.3.6.1.4", 1, NULL, NULL); 00138 snmpAddNodeStr("1.3.6.1.4.1", 3495, NULL, NULL); 00139 mib_tree_entry *m2 = snmpAddNodeStr("1.3.6.1.4.1.3495", 1, NULL, NULL); 00140 00141 mib_tree_entry *n = snmpLookupNodeStr(NULL, "1.3.6.1.4.1.3495.1"); 00142 assert(m2 == n); 00143 00144 /* SQ_SYS - 1.3.6.1.4.1.3495.1.1 */ 00145 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 1, NULL, NULL); 00146 snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSVMSIZ, snmp_sysFn, static_Inst); 00147 snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYSSTOR, snmp_sysFn, static_Inst); 00148 snmpAddNodeStr("1.3.6.1.4.1.3495.1.1", SYS_UPTIME, snmp_sysFn, static_Inst); 00149 00150 /* SQ_CONF - 1.3.6.1.4.1.3495.1.2 */ 00151 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 2, NULL, NULL); 00152 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_ADMIN, snmp_confFn, static_Inst); 00153 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_VERSION, snmp_confFn, static_Inst); 00154 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_VERSION_ID, snmp_confFn, static_Inst); 00155 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_LOG_FAC, snmp_confFn, static_Inst); 00156 00157 /* SQ_CONF + CONF_STORAGE - 1.3.6.1.4.1.3495.1.5 */ 00158 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_STORAGE, NULL, NULL); 00159 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_MMAXSZ, snmp_confFn, static_Inst); 00160 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWMAXSZ, snmp_confFn, static_Inst); 00161 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWHIWM, snmp_confFn, static_Inst); 00162 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2.5", CONF_ST_SWLOWM, snmp_confFn, static_Inst); 00163 00164 snmpAddNodeStr("1.3.6.1.4.1.3495.1.2", CONF_UNIQNAME, snmp_confFn, static_Inst); 00165 00166 /* SQ_PRF - 1.3.6.1.4.1.3495.1.3 */ 00167 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 3, NULL, NULL); /* SQ_PRF */ 00168 00169 /* PERF_SYS - 1.3.6.1.4.1.3495.1.3.1 */ 00170 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3", PERF_SYS, NULL, NULL); 00171 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_PF, snmp_prfSysFn, static_Inst); 00172 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMR, snmp_prfSysFn, static_Inst); 00173 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MEMUSAGE, snmp_prfSysFn, static_Inst); 00174 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUTIME, snmp_prfSysFn, static_Inst); 00175 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CPUUSAGE, snmp_prfSysFn, static_Inst); 00176 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_MAXRESSZ, snmp_prfSysFn, static_Inst); 00177 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_NUMOBJCNT, snmp_prfSysFn, static_Inst); 00178 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURLRUEXP, snmp_prfSysFn, static_Inst); 00179 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUNLREQ, snmp_prfSysFn, static_Inst); 00180 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUNUSED_FD, snmp_prfSysFn, static_Inst); 00181 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURRESERVED_FD, snmp_prfSysFn, static_Inst); 00182 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURUSED_FD, snmp_prfSysFn, static_Inst); 00183 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.1", PERF_SYS_CURMAX_FD, snmp_prfSysFn, static_Inst); 00184 00185 /* PERF_PROTO - 1.3.6.1.4.1.3495.1.3.2 */ 00186 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3", PERF_PROTO, NULL, NULL); 00187 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2", PERF_PROTOSTAT_AGGR, NULL, NULL); 00188 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_REQ, snmp_prfProtoFn, static_Inst); 00189 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_HITS, snmp_prfProtoFn, static_Inst); 00190 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_ERRORS, snmp_prfProtoFn, static_Inst); 00191 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_KBYTES_IN, snmp_prfProtoFn, static_Inst); 00192 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_HTTP_KBYTES_OUT, snmp_prfProtoFn, static_Inst); 00193 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_S, snmp_prfProtoFn, static_Inst); 00194 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_R, snmp_prfProtoFn, static_Inst); 00195 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_SKB, snmp_prfProtoFn, static_Inst); 00196 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ICP_RKB, snmp_prfProtoFn, static_Inst); 00197 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_REQ, snmp_prfProtoFn, static_Inst); 00198 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_ERRORS, snmp_prfProtoFn, static_Inst); 00199 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_KBYTES_IN, snmp_prfProtoFn, static_Inst); 00200 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_KBYTES_OUT, snmp_prfProtoFn, static_Inst); 00201 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_CURSWAP, snmp_prfProtoFn, static_Inst); 00202 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.1", PERF_PROTOSTAT_AGGR_CLIENTS, snmp_prfProtoFn, static_Inst); 00203 00204 /* Note this is time-series rather than 'static' */ 00205 /* cacheMedianSvcTable */ 00206 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2", PERF_PROTOSTAT_MEDIAN, NULL, NULL); 00207 00208 /* cacheMedianSvcEntry */ 00209 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2", 1, NULL, NULL); 00210 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_TIME, snmp_prfProtoFn, time_Inst); 00211 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_ALL, snmp_prfProtoFn, time_Inst); 00212 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_MISS, snmp_prfProtoFn, time_Inst); 00213 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NM, snmp_prfProtoFn, time_Inst); 00214 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_HIT, snmp_prfProtoFn, time_Inst); 00215 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_QUERY, snmp_prfProtoFn, time_Inst); 00216 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_ICP_REPLY, snmp_prfProtoFn, time_Inst); 00217 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_DNS, snmp_prfProtoFn, time_Inst); 00218 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_RHR, snmp_prfProtoFn, time_Inst); 00219 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_BHR, snmp_prfProtoFn, time_Inst); 00220 snmpAddNodeStr("1.3.6.1.4.1.3495.1.3.2.2.1", PERF_MEDIAN_HTTP_NH, snmp_prfProtoFn, time_Inst); 00221 00222 /* SQ_NET - 1.3.6.1.4.1.3495.1.4 */ 00223 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 4, NULL, NULL); 00224 00225 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_IP_CACHE, NULL, NULL); 00226 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_ENT, snmp_netIpFn, static_Inst); 00227 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_REQ, snmp_netIpFn, static_Inst); 00228 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_HITS, snmp_netIpFn, static_Inst); 00229 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_PENDHIT, snmp_netIpFn, static_Inst); 00230 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_NEGHIT, snmp_netIpFn, static_Inst); 00231 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_MISS, snmp_netIpFn, static_Inst); 00232 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_GHBN, snmp_netIpFn, static_Inst); 00233 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.1", IP_LOC, snmp_netIpFn, static_Inst); 00234 00235 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_FQDN_CACHE, NULL, NULL); 00236 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_ENT, snmp_netFqdnFn, static_Inst); 00237 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_REQ, snmp_netFqdnFn, static_Inst); 00238 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_HITS, snmp_netFqdnFn, static_Inst); 00239 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_PENDHIT, snmp_netFqdnFn, static_Inst); 00240 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_NEGHIT, snmp_netFqdnFn, static_Inst); 00241 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_MISS, snmp_netFqdnFn, static_Inst); 00242 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.2", FQDN_GHBN, snmp_netFqdnFn, static_Inst); 00243 00244 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4", NET_DNS_CACHE, NULL, NULL); 00245 #if USE_DNSSERVERS 00246 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REQ, snmp_netDnsFn, static_Inst); 00247 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REP, snmp_netDnsFn, static_Inst); 00248 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_SERVERS, snmp_netDnsFn, static_Inst); 00249 #else 00250 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REQ, snmp_netIdnsFn, static_Inst); 00251 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_REP, snmp_netIdnsFn, static_Inst); 00252 snmpAddNodeStr("1.3.6.1.4.1.3495.1.4.3", DNS_SERVERS, snmp_netIdnsFn, static_Inst); 00253 #endif 00254 00255 /* SQ_MESH - 1.3.6.1.4.1.3495.1.5 */ 00256 snmpAddNodeStr("1.3.6.1.4.1.3495.1", 5, NULL, NULL); 00257 00258 /* cachePeerTable - 1.3.6.1.4.1.3495.1.5.1 */ 00259 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5", MESH_PTBL, NULL, NULL); 00260 00261 /* CachePeerTableEntry (version 3) - 1.3.6.1.4.1.3495.1.5.1.3 */ 00262 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1", 3, NULL, NULL); 00263 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_INDEX, snmp_meshPtblFn, peer_Inst); 00264 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_NAME, snmp_meshPtblFn, peer_Inst); 00265 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ADDR_TYPE, snmp_meshPtblFn, peer_Inst); 00266 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ADDR, snmp_meshPtblFn, peer_Inst); 00267 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_HTTP, snmp_meshPtblFn, peer_Inst); 00268 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_ICP, snmp_meshPtblFn, peer_Inst); 00269 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_TYPE, snmp_meshPtblFn, peer_Inst); 00270 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_STATE, snmp_meshPtblFn, peer_Inst); 00271 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_SENT, snmp_meshPtblFn, peer_Inst); 00272 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_PACKED, snmp_meshPtblFn, peer_Inst); 00273 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_FETCHES, snmp_meshPtblFn, peer_Inst); 00274 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_RTT, snmp_meshPtblFn, peer_Inst); 00275 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_IGN, snmp_meshPtblFn, peer_Inst); 00276 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_KEEPAL_S, snmp_meshPtblFn, peer_Inst); 00277 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.1.3", MESH_PTBL_KEEPAL_R, snmp_meshPtblFn, peer_Inst); 00278 00279 /* cacheClientTable - 1.3.6.1.4.1.3495.1.5.2 */ 00280 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5", MESH_CTBL, NULL, NULL); 00281 00282 /* BUG 2811: we NEED to create a reliable index for the client DB and make version 3 of the table. */ 00283 /* for now we have version 2 table with OID capable of mixed IPv4 / IPv6 clients and upgraded address text format. */ 00284 00285 /* cacheClientEntry - 1.3.6.1.4.1.3495.1.5.2.2 */ 00286 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2", 2, NULL, NULL); 00287 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ADDR_TYPE, snmp_meshCtblFn, client_Inst); 00288 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ADDR, snmp_meshCtblFn, client_Inst); 00289 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTREQ, snmp_meshCtblFn, client_Inst); 00290 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTBYTES, snmp_meshCtblFn, client_Inst); 00291 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTHITS, snmp_meshCtblFn, client_Inst); 00292 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_HTHITBYTES, snmp_meshCtblFn, client_Inst); 00293 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPREQ, snmp_meshCtblFn, client_Inst); 00294 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPBYTES, snmp_meshCtblFn, client_Inst); 00295 snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPHITS, snmp_meshCtblFn, client_Inst); 00296 mib_tree_last = snmpAddNodeStr("1.3.6.1.4.1.3495.1.5.2.2", MESH_CTBL_ICPHITBYTES, snmp_meshCtblFn, client_Inst); 00297 00298 debugs(49, 9, "snmpInit: Completed SNMP mib tree structure"); 00299 } 00300 00301 void 00302 snmpConnectionOpen(void) 00303 { 00304 debugs(49, 5, "snmpConnectionOpen: Called"); 00305 00306 if (Config.Port.snmp > 0) { 00307 Config.Addrs.snmp_incoming.SetPort(Config.Port.snmp); 00308 00309 if (!Ip::EnableIpv6 && !Config.Addrs.snmp_incoming.SetIPv4()) { 00310 debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << Config.Addrs.snmp_incoming << " is not an IPv4 address."); 00311 fatal("SNMP port cannot be opened."); 00312 } 00313 /* split-stack for now requires IPv4-only SNMP */ 00314 if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && Config.Addrs.snmp_incoming.IsAnyAddr()) { 00315 Config.Addrs.snmp_incoming.SetIPv4(); 00316 } 00317 00318 AsyncCall::Pointer call = asyncCall(49, 2, 00319 "snmpIncomingConnectionOpened", 00320 SnmpListeningStartedDialer(&snmpIncomingConnectionOpened)); 00321 00322 Ipc::StartListening(SOCK_DGRAM, 00323 IPPROTO_UDP, 00324 Config.Addrs.snmp_incoming, 00325 COMM_NONBLOCKING, 00326 Ipc::fdnInSnmpSocket, call); 00327 00328 if (!Config.Addrs.snmp_outgoing.IsNoAddr()) { 00329 Config.Addrs.snmp_outgoing.SetPort(Config.Port.snmp); 00330 00331 if (!Ip::EnableIpv6 && !Config.Addrs.snmp_outgoing.SetIPv4()) { 00332 debugs(49, DBG_CRITICAL, "ERROR: IPv6 is disabled. " << Config.Addrs.snmp_outgoing << " is not an IPv4 address."); 00333 fatal("SNMP port cannot be opened."); 00334 } 00335 /* split-stack for now requires IPv4-only SNMP */ 00336 if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && Config.Addrs.snmp_outgoing.IsAnyAddr()) { 00337 Config.Addrs.snmp_outgoing.SetIPv4(); 00338 } 00339 AsyncCall::Pointer call = asyncCall(49, 2, 00340 "snmpOutgoingConnectionOpened", 00341 SnmpListeningStartedDialer(&snmpOutgoingConnectionOpened)); 00342 00343 Ipc::StartListening(SOCK_DGRAM, 00344 IPPROTO_UDP, 00345 Config.Addrs.snmp_outgoing, 00346 COMM_NONBLOCKING, 00347 Ipc::fdnOutSnmpSocket, call); 00348 } 00349 } 00350 } 00351 00352 static void 00353 snmpIncomingConnectionOpened(int fd, int errNo) 00354 { 00355 theInSnmpConnection = fd; 00356 if (theInSnmpConnection < 0) 00357 fatal("Cannot open Incoming SNMP Port"); 00358 00359 commSetSelect(theInSnmpConnection, COMM_SELECT_READ, snmpHandleUdp, NULL, 00360 0); 00361 00362 debugs(1, 1, "Accepting SNMP messages on " << Config.Addrs.snmp_incoming << 00363 ", FD " << theInSnmpConnection << "."); 00364 00365 if (Config.Addrs.snmp_outgoing.IsNoAddr()) 00366 theOutSnmpConnection = theInSnmpConnection; 00367 } 00368 00369 static void 00370 snmpOutgoingConnectionOpened(int fd, int errNo) 00371 { 00372 theOutSnmpConnection = fd; 00373 if (theOutSnmpConnection < 0) 00374 fatal("Cannot open Outgoing SNMP Port"); 00375 00376 commSetSelect(theOutSnmpConnection, COMM_SELECT_READ, snmpHandleUdp, NULL, 00377 0); 00378 00379 debugs(1, 1, "Outgoing SNMP messages on " << Config.Addrs.snmp_outgoing << 00380 ", FD " << theOutSnmpConnection << "."); 00381 00382 { 00383 struct addrinfo *xaddr = NULL; 00384 int x; 00385 00386 00387 theOutSNMPAddr.SetEmpty(); 00388 00389 theOutSNMPAddr.InitAddrInfo(xaddr); 00390 00391 x = getsockname(theOutSnmpConnection, xaddr->ai_addr, &xaddr->ai_addrlen); 00392 00393 if (x < 0) 00394 debugs(51, 1, "theOutSnmpConnection FD " << theOutSnmpConnection << ": getsockname: " << xstrerror()); 00395 else 00396 theOutSNMPAddr = *xaddr; 00397 00398 theOutSNMPAddr.FreeAddrInfo(xaddr); 00399 } 00400 } 00401 00402 void 00403 snmpConnectionShutdown(void) 00404 { 00405 if (theInSnmpConnection < 0) 00406 return; 00407 00408 if (theInSnmpConnection != theOutSnmpConnection) { 00409 debugs(49, 1, "FD " << theInSnmpConnection << " Closing SNMP socket"); 00410 comm_close(theInSnmpConnection); 00411 } 00412 00413 /* 00414 * Here we set 'theInSnmpConnection' to -1 even though the SNMP 'in' 00415 * and 'out' sockets might be just one FD. This prevents this 00416 * function from executing repeatedly. When we are really ready to 00417 * exit or restart, main will comm_close the 'out' descriptor. 00418 */ 00419 theInSnmpConnection = -1; 00420 00421 /* 00422 * Normally we only write to the outgoing SNMP socket, but we 00423 * also have a read handler there to catch messages sent to that 00424 * specific interface. During shutdown, we must disable reading 00425 * on the outgoing socket. 00426 */ 00427 assert(theOutSnmpConnection > -1); 00428 00429 commSetSelect(theOutSnmpConnection, COMM_SELECT_READ, NULL, NULL, 0); 00430 } 00431 00432 void 00433 snmpConnectionClose(void) 00434 { 00435 snmpConnectionShutdown(); 00436 00437 if (theOutSnmpConnection > -1) { 00438 debugs(49, 1, "FD " << theOutSnmpConnection << " Closing SNMP socket"); 00439 comm_close(theOutSnmpConnection); 00440 /* make sure the SNMP out connection is unset */ 00441 theOutSnmpConnection = -1; 00442 } 00443 } 00444 00445 /* 00446 * Functions for handling the requests. 00447 */ 00448 00449 /* 00450 * Accept the UDP packet 00451 */ 00452 void 00453 snmpHandleUdp(int sock, void *not_used) 00454 { 00455 LOCAL_ARRAY(char, buf, SNMP_REQUEST_SIZE); 00456 Ip::Address from; 00457 snmp_request_t *snmp_rq; 00458 int len; 00459 00460 debugs(49, 5, "snmpHandleUdp: Called."); 00461 00462 commSetSelect(sock, COMM_SELECT_READ, snmpHandleUdp, NULL, 0); 00463 00464 memset(buf, '\0', SNMP_REQUEST_SIZE); 00465 00466 len = comm_udp_recvfrom(sock, 00467 buf, 00468 SNMP_REQUEST_SIZE, 00469 0, 00470 from); 00471 00472 if (len > 0) { 00473 buf[len] = '\0'; 00474 debugs(49, 3, "snmpHandleUdp: FD " << sock << ": received " << len << " bytes from " << from << "."); 00475 00476 snmp_rq = (snmp_request_t *)xcalloc(1, sizeof(snmp_request_t)); 00477 snmp_rq->buf = (u_char *) buf; 00478 snmp_rq->len = len; 00479 snmp_rq->sock = sock; 00480 snmp_rq->outbuf = (unsigned char *)xmalloc(snmp_rq->outlen = SNMP_REQUEST_SIZE); 00481 snmp_rq->from = from; 00482 snmpDecodePacket(snmp_rq); 00483 xfree(snmp_rq->outbuf); 00484 xfree(snmp_rq); 00485 } else { 00486 debugs(49, 1, "snmpHandleUdp: FD " << sock << " recvfrom: " << xstrerror()); 00487 } 00488 } 00489 00490 /* 00491 * Turn SNMP packet into a PDU, check available ACL's 00492 */ 00493 static void 00494 snmpDecodePacket(snmp_request_t * rq) 00495 { 00496 struct snmp_pdu *PDU; 00497 u_char *Community; 00498 u_char *buf = rq->buf; 00499 int len = rq->len; 00500 int allow = 0; 00501 00502 debugs(49, 5, HERE << "Called."); 00503 PDU = snmp_pdu_create(0); 00504 /* Allways answer on SNMPv1 */ 00505 rq->session.Version = SNMP_VERSION_1; 00506 Community = snmp_parse(&rq->session, PDU, buf, len); 00507 00508 /* Check if we have explicit permission to access SNMP data. 00509 * default (set above) is to deny all */ 00510 if (Community && Config.accessList.snmp) { 00511 ACLFilledChecklist checklist(Config.accessList.snmp, NULL, NULL); 00512 checklist.src_addr = rq->from; 00513 checklist.snmp_community = (char *) Community; 00514 allow = checklist.fastCheck(); 00515 } 00516 00517 if ((snmp_coexist_V2toV1(PDU)) && (Community) && (allow)) { 00518 rq->community = Community; 00519 rq->PDU = PDU; 00520 debugs(49, 5, "snmpAgentParse: reqid=[" << PDU->reqid << "]"); 00521 snmpConstructReponse(rq); 00522 } else { 00523 debugs(49, 1, HERE << "Failed SNMP agent query from : " << rq->from); 00524 snmp_free_pdu(PDU); 00525 } 00526 00527 if (Community) 00528 xfree(Community); 00529 } 00530 00531 /* 00532 * Packet OK, ACL Check OK, Create reponse. 00533 */ 00534 static void 00535 snmpConstructReponse(snmp_request_t * rq) 00536 { 00537 00538 struct snmp_pdu *RespPDU; 00539 00540 debugs(49, 5, "snmpConstructReponse: Called."); 00541 RespPDU = snmpAgentResponse(rq->PDU); 00542 snmp_free_pdu(rq->PDU); 00543 00544 if (RespPDU != NULL) { 00545 snmp_build(&rq->session, RespPDU, rq->outbuf, &rq->outlen); 00546 comm_udp_sendto(rq->sock, rq->from, rq->outbuf, rq->outlen); 00547 snmp_free_pdu(RespPDU); 00548 } 00549 } 00550 00551 /* 00552 * Decide how to respond to the request, construct a response and 00553 * return the response to the requester. 00554 */ 00555 00556 static struct snmp_pdu * 00557 snmpAgentResponse(struct snmp_pdu *PDU) { 00558 00559 struct snmp_pdu *Answer = NULL; 00560 00561 debugs(49, 5, "snmpAgentResponse: Called."); 00562 00563 if ((Answer = snmp_pdu_create(SNMP_PDU_RESPONSE))) { 00564 Answer->reqid = PDU->reqid; 00565 Answer->errindex = 0; 00566 00567 if (PDU->command == SNMP_PDU_GET || PDU->command == SNMP_PDU_GETNEXT) { 00568 /* Indirect way */ 00569 int get_next = (PDU->command == SNMP_PDU_GETNEXT); 00570 variable_list *VarPtr_; 00571 variable_list **RespVars = &(Answer->variables); 00572 oid_ParseFn *ParseFn; 00573 int index = 0; 00574 /* Loop through all variables */ 00575 00576 for (VarPtr_ = PDU->variables; VarPtr_; VarPtr_ = VarPtr_->next_variable) { 00577 variable_list *VarPtr = VarPtr_; 00578 variable_list *VarNew = NULL; 00579 oid *NextOidName = NULL; 00580 snint NextOidNameLen = 0; 00581 00582 index++; 00583 00584 if (get_next) 00585 ParseFn = snmpTreeNext(VarPtr->name, VarPtr->name_length, &NextOidName, &NextOidNameLen); 00586 else 00587 ParseFn = snmpTreeGet(VarPtr->name, VarPtr->name_length); 00588 00589 if (ParseFn == NULL) { 00590 Answer->errstat = SNMP_ERR_NOSUCHNAME; 00591 debugs(49, 5, "snmpAgentResponse: No such oid. "); 00592 } else { 00593 if (get_next) { 00594 VarPtr = snmp_var_new(NextOidName, NextOidNameLen); 00595 xfree(NextOidName); 00596 } 00597 00598 int * errstatTmp = &(Answer->errstat); 00599 00600 VarNew = (*ParseFn) (VarPtr, (snint *) errstatTmp); 00601 00602 if (get_next) 00603 snmp_var_free(VarPtr); 00604 } 00605 00606 if ((Answer->errstat != SNMP_ERR_NOERROR) || (VarNew == NULL)) { 00607 Answer->errindex = index; 00608 debugs(49, 5, "snmpAgentResponse: error."); 00609 00610 if (VarNew) 00611 snmp_var_free(VarNew); 00612 00613 while ((VarPtr = Answer->variables) != NULL) { 00614 Answer->variables = VarPtr->next_variable; 00615 snmp_var_free(VarPtr); 00616 } 00617 00618 /* Steal the original PDU list of variables for the error response */ 00619 Answer->variables = PDU->variables; 00620 00621 PDU->variables = NULL; 00622 00623 return (Answer); 00624 } 00625 00626 /* No error. Insert this var at the end, and move on to the next. 00627 */ 00628 *RespVars = VarNew; 00629 00630 RespVars = &(VarNew->next_variable); 00631 } 00632 } 00633 } 00634 00635 return (Answer); 00636 } 00637 00638 static oid_ParseFn * 00639 snmpTreeGet(oid * Current, snint CurrentLen) 00640 { 00641 oid_ParseFn *Fn = NULL; 00642 mib_tree_entry *mibTreeEntry = NULL; 00643 int count = 0; 00644 00645 debugs(49, 5, "snmpTreeGet: Called"); 00646 00647 MemBuf tmp; 00648 debugs(49, 6, "snmpTreeGet: Current : " << snmpDebugOid(Current, CurrentLen, tmp) ); 00649 00650 mibTreeEntry = mib_tree_head; 00651 00652 if (Current[count] == mibTreeEntry->name[count]) { 00653 count++; 00654 00655 while ((mibTreeEntry) && (count < CurrentLen) && (!mibTreeEntry->parsefunction)) { 00656 mibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry); 00657 count++; 00658 } 00659 } 00660 00661 if (mibTreeEntry && mibTreeEntry->parsefunction) 00662 Fn = mibTreeEntry->parsefunction; 00663 00664 debugs(49, 5, "snmpTreeGet: return"); 00665 00666 return (Fn); 00667 } 00668 00669 static oid_ParseFn * 00670 snmpTreeNext(oid * Current, snint CurrentLen, oid ** Next, snint * NextLen) 00671 { 00672 oid_ParseFn *Fn = NULL; 00673 mib_tree_entry *mibTreeEntry = NULL, *nextoid = NULL; 00674 int count = 0; 00675 00676 debugs(49, 5, "snmpTreeNext: Called"); 00677 00678 MemBuf tmp; 00679 debugs(49, 6, "snmpTreeNext: Current : " << snmpDebugOid(Current, CurrentLen, tmp)); 00680 00681 mibTreeEntry = mib_tree_head; 00682 00683 if (Current[count] == mibTreeEntry->name[count]) { 00684 count++; 00685 00686 while ((mibTreeEntry) && (count < CurrentLen) && (!mibTreeEntry->parsefunction)) { 00687 mib_tree_entry *nextmibTreeEntry = snmpTreeEntry(Current[count], count, mibTreeEntry); 00688 00689 if (!nextmibTreeEntry) 00690 break; 00691 else 00692 mibTreeEntry = nextmibTreeEntry; 00693 00694 count++; 00695 } 00696 debugs(49, 5, "snmpTreeNext: Recursed down to requested object"); 00697 } else { 00698 return NULL; 00699 } 00700 00701 if (mibTreeEntry == mib_tree_last) 00702 return (Fn); 00703 00704 00705 if ((mibTreeEntry) && (mibTreeEntry->parsefunction)) { 00706 *NextLen = CurrentLen; 00707 *Next = (*mibTreeEntry->instancefunction) (Current, NextLen, mibTreeEntry, &Fn); 00708 if (*Next) { 00709 MemBuf tmp; 00710 debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next, *NextLen, tmp)); 00711 return (Fn); 00712 } 00713 } 00714 00715 if ((mibTreeEntry) && (mibTreeEntry->parsefunction)) { 00716 count--; 00717 nextoid = snmpTreeSiblingEntry(Current[count], count, mibTreeEntry->parent); 00718 if (nextoid) { 00719 debugs(49, 5, "snmpTreeNext: Next OID found for sibling" << nextoid ); 00720 mibTreeEntry = nextoid; 00721 count++; 00722 } else { 00723 debugs(49, 5, "snmpTreeNext: Attempting to recurse up for next object"); 00724 00725 while (!nextoid) { 00726 count--; 00727 00728 if (mibTreeEntry->parent->parent) { 00729 nextoid = mibTreeEntry->parent; 00730 mibTreeEntry = snmpTreeEntry(Current[count] + 1, count, nextoid->parent); 00731 00732 if (!mibTreeEntry) { 00733 mibTreeEntry = nextoid; 00734 nextoid = NULL; 00735 } 00736 } else { 00737 nextoid = mibTreeEntry; 00738 mibTreeEntry = NULL; 00739 } 00740 } 00741 } 00742 } 00743 while ((mibTreeEntry) && (!mibTreeEntry->parsefunction)) { 00744 mibTreeEntry = mibTreeEntry->leaves[0]; 00745 } 00746 00747 if (mibTreeEntry) { 00748 *NextLen = mibTreeEntry->len; 00749 *Next = (*mibTreeEntry->instancefunction) (mibTreeEntry->name, NextLen, mibTreeEntry, &Fn); 00750 } 00751 00752 if (*Next) { 00753 MemBuf tmp; 00754 debugs(49, 6, "snmpTreeNext: Next : " << snmpDebugOid(*Next, *NextLen, tmp)); 00755 return (Fn); 00756 } else 00757 return NULL; 00758 } 00759 00760 static oid * 00761 static_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn) 00762 { 00763 oid *instance = NULL; 00764 if (*len <= current->len) { 00765 instance = (oid *)xmalloc(sizeof(name) * (*len + 1)); 00766 xmemcpy(instance, name, (sizeof(name) * *len)); 00767 instance[*len] = 0; 00768 *len += 1; 00769 } 00770 *Fn = current->parsefunction; 00771 return (instance); 00772 } 00773 00774 static oid * 00775 time_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn) 00776 { 00777 oid *instance = NULL; 00778 int identifier = 0, loop = 0; 00779 int index[TIME_INDEX_LEN] = {TIME_INDEX}; 00780 00781 if (*len <= current->len) { 00782 instance = (oid *)xmalloc(sizeof(name) * (*len + 1)); 00783 xmemcpy(instance, name, (sizeof(name) * *len)); 00784 instance[*len] = *index; 00785 *len += 1; 00786 } else { 00787 identifier = name[*len - 1]; 00788 00789 while ((loop < TIME_INDEX_LEN) && (identifier != index[loop])) 00790 loop++; 00791 00792 if (loop < (TIME_INDEX_LEN - 1)) { 00793 instance = (oid *)xmalloc(sizeof(name) * (*len)); 00794 xmemcpy(instance, name, (sizeof(name) * *len)); 00795 instance[*len - 1] = index[++loop]; 00796 } 00797 } 00798 00799 *Fn = current->parsefunction; 00800 return (instance); 00801 } 00802 00803 00804 static oid * 00805 peer_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn) 00806 { 00807 oid *instance = NULL; 00808 peer *peers = Config.peers; 00809 00810 if (peers == NULL) { 00811 debugs(49, 6, "snmp peer_Inst: No Peers."); 00812 current = current->parent->parent->parent->leaves[1]; 00813 while ((current) && (!current->parsefunction)) 00814 current = current->leaves[0]; 00815 00816 instance = client_Inst(current->name, len, current, Fn); 00817 } else if (*len <= current->len) { 00818 debugs(49, 6, "snmp peer_Inst: *len <= current->len ???"); 00819 instance = (oid *)xmalloc(sizeof(name) * ( *len + 1)); 00820 xmemcpy(instance, name, (sizeof(name) * *len)); 00821 instance[*len] = 1 ; 00822 *len += 1; 00823 } else { 00824 int no = name[current->len] ; 00825 int i; 00826 // Note: This works because the Config.peers keeps its index according to its position. 00827 for ( i=0 ; peers && (i < no) ; peers = peers->next , i++ ) ; 00828 00829 if (peers) { 00830 debugs(49, 6, "snmp peer_Inst: Encode peer #" << i); 00831 instance = (oid *)xmalloc(sizeof(name) * (current->len + 1 )); 00832 xmemcpy(instance, name, (sizeof(name) * current->len )); 00833 instance[current->len] = no + 1 ; // i.e. the next index on cache_peeer table. 00834 } else { 00835 debugs(49, 6, "snmp peer_Inst: We have " << i << " peers. Can't find #" << no); 00836 return (instance); 00837 } 00838 } 00839 *Fn = current->parsefunction; 00840 return (instance); 00841 } 00842 00843 static oid * 00844 client_Inst(oid * name, snint * len, mib_tree_entry * current, oid_ParseFn ** Fn) 00845 { 00846 oid *instance = NULL; 00847 Ip::Address laddr; 00848 Ip::Address *aux; 00849 int size = 0; 00850 int newshift = 0; 00851 00852 if (*len <= current->len) { 00853 aux = client_entry(NULL); 00854 if (aux) 00855 laddr = *aux; 00856 else 00857 laddr.SetAnyAddr(); 00858 00859 if (laddr.IsIPv4()) 00860 size = sizeof(in_addr); 00861 else 00862 size = sizeof(in6_addr); 00863 00864 debugs(49, 6, HERE << "len" << *len << ", current-len" << current->len << ", addr=" << laddr << ", size=" << size); 00865 00866 instance = (oid *)xmalloc(sizeof(name) * (*len + size )); 00867 xmemcpy(instance, name, (sizeof(name) * (*len))); 00868 00869 if ( !laddr.IsAnyAddr() ) { 00870 addr2oid(laddr, &instance[ *len]); // the addr 00871 *len += size ; 00872 } 00873 } else { 00874 int shift = *len - current->len ; // i.e 4 or 16 00875 oid2addr(&name[*len - shift], laddr,shift); 00876 aux = client_entry(&laddr); 00877 if (aux) 00878 laddr = *aux; 00879 else 00880 laddr.SetAnyAddr(); 00881 00882 if (!laddr.IsAnyAddr()) { 00883 if (laddr.IsIPv4()) 00884 newshift = sizeof(in_addr); 00885 else 00886 newshift = sizeof(in6_addr); 00887 00888 debugs(49, 6, HERE << "len" << *len << ", current-len" << current->len << ", addr=" << laddr << ", newshift=" << newshift); 00889 00890 instance = (oid *)xmalloc(sizeof(name) * (current->len + newshift)); 00891 xmemcpy(instance, name, (sizeof(name) * (current->len))); 00892 addr2oid(laddr, &instance[current->len]); // the addr. 00893 *len = current->len + newshift ; 00894 } 00895 } 00896 00897 *Fn = current->parsefunction; 00898 return (instance); 00899 } 00900 00901 /* 00902 * Utility functions 00903 */ 00904 00905 /* 00906 * Tree utility functions. 00907 */ 00908 00909 /* 00910 * Returns a sibling object for the requested child object or NULL 00911 * if it does not exit 00912 */ 00913 static mib_tree_entry * 00914 snmpTreeSiblingEntry(oid entry, snint len, mib_tree_entry * current) 00915 { 00916 mib_tree_entry *next = NULL; 00917 int count = 0; 00918 00919 while ((!next) && (count < current->children)) { 00920 if (current->leaves[count]->name[len] == entry) { 00921 next = current->leaves[count]; 00922 } 00923 00924 count++; 00925 } 00926 00927 /* Exactly the sibling on right */ 00928 if (count < current->children) { 00929 next = current->leaves[count]; 00930 } else { 00931 next = NULL; 00932 } 00933 00934 return (next); 00935 } 00936 00937 /* 00938 * Returns the requested child object or NULL if it does not exist 00939 */ 00940 static mib_tree_entry * 00941 snmpTreeEntry(oid entry, snint len, mib_tree_entry * current) 00942 { 00943 mib_tree_entry *next = NULL; 00944 int count = 0; 00945 00946 while ((!next) && current && (count < current->children)) { 00947 if (current->leaves[count]->name[len] == entry) { 00948 next = current->leaves[count]; 00949 } 00950 00951 count++; 00952 } 00953 00954 return (next); 00955 } 00956 00957 void 00958 snmpAddNodeChild(mib_tree_entry *entry, mib_tree_entry *child) 00959 { 00960 debugs(49, 5, "snmpAddNodeChild: assigning " << child << " to parent " << entry); 00961 entry->leaves = (mib_tree_entry **)xrealloc(entry->leaves, sizeof(mib_tree_entry *) * (entry->children + 1)); 00962 entry->leaves[entry->children] = child; 00963 entry->leaves[entry->children]->parent = entry; 00964 entry->children++; 00965 } 00966 00967 mib_tree_entry * 00968 snmpLookupNodeStr(mib_tree_entry *root, const char *str) 00969 { 00970 oid *name; 00971 int namelen; 00972 mib_tree_entry *e; 00973 00974 if (root) 00975 e = root; 00976 else 00977 e = mib_tree_head; 00978 00979 if (! snmpCreateOidFromStr(str, &name, &namelen)) 00980 return NULL; 00981 00982 /* I wish there were some kind of sensible existing tree traversal 00983 * routine to use. I'll worry about that later */ 00984 if (namelen <= 1) { 00985 xfree(name); 00986 return e; /* XXX it should only be this? */ 00987 } 00988 00989 int i, r = 1; 00990 while (r < namelen) { 00991 00992 /* Find the child node which matches this */ 00993 for (i = 0; i < e->children && e->leaves[i]->name[r] != name[r]; i++) ; // seek-loop 00994 00995 /* Are we pointing to that node? */ 00996 if (i >= e->children) 00997 break; 00998 assert(e->leaves[i]->name[r] == name[r]); 00999 01000 /* Skip to that node! */ 01001 e = e->leaves[i]; 01002 r++; 01003 } 01004 01005 xfree(name); 01006 return e; 01007 } 01008 01009 int 01010 snmpCreateOidFromStr(const char *str, oid **name, int *nl) 01011 { 01012 char const *delim = "."; 01013 char *p; 01014 01015 *name = NULL; 01016 *nl = 0; 01017 char *s = xstrdup(str); 01018 char *s_ = s; 01019 01020 /* Parse the OID string into oid bits */ 01021 while ( (p = strsep(&s_, delim)) != NULL) { 01022 *name = (oid*)xrealloc(*name, sizeof(oid) * ((*nl) + 1)); 01023 (*name)[*nl] = atoi(p); 01024 (*nl)++; 01025 } 01026 01027 xfree(s); 01028 return 1; 01029 } 01030 01031 /* 01032 * Create an entry. Return a pointer to the newly created node, or NULL 01033 * on failure. 01034 */ 01035 static mib_tree_entry * 01036 snmpAddNodeStr(const char *base_str, int o, oid_ParseFn * parsefunction, instance_Fn * instancefunction) 01037 { 01038 mib_tree_entry *m, *b; 01039 oid *n; 01040 int nl; 01041 char s[1024]; 01042 01043 /* Find base node */ 01044 b = snmpLookupNodeStr(mib_tree_head, base_str); 01045 if (! b) 01046 return NULL; 01047 debugs(49, 5, "snmpAddNodeStr: " << base_str << ": -> " << b); 01048 01049 /* Create OID string for new entry */ 01050 snprintf(s, 1024, "%s.%d", base_str, o); 01051 if (! snmpCreateOidFromStr(s, &n, &nl)) 01052 return NULL; 01053 01054 /* Create a node */ 01055 m = snmpAddNode(n, nl, parsefunction, instancefunction, 0); 01056 01057 /* Link it into the existing tree */ 01058 snmpAddNodeChild(b, m); 01059 01060 /* Return the node */ 01061 return m; 01062 } 01063 01064 01065 /* 01066 * Adds a node to the MIB tree structure and adds the appropriate children 01067 */ 01068 static mib_tree_entry * 01069 snmpAddNode(oid * name, int len, oid_ParseFn * parsefunction, instance_Fn * instancefunction, int children,...) 01070 { 01071 va_list args; 01072 int loop; 01073 mib_tree_entry *entry = NULL; 01074 va_start(args, children); 01075 01076 MemBuf tmp; 01077 debugs(49, 6, "snmpAddNode: Children : " << children << ", Oid : " << snmpDebugOid(name, len, tmp)); 01078 01079 va_start(args, children); 01080 entry = (mib_tree_entry *)xmalloc(sizeof(mib_tree_entry)); 01081 entry->name = name; 01082 entry->len = len; 01083 entry->parsefunction = parsefunction; 01084 entry->instancefunction = instancefunction; 01085 entry->children = children; 01086 entry->leaves = NULL; 01087 01088 if (children > 0) { 01089 entry->leaves = (mib_tree_entry **)xmalloc(sizeof(mib_tree_entry *) * children); 01090 01091 for (loop = 0; loop < children; loop++) { 01092 entry->leaves[loop] = va_arg(args, mib_tree_entry *); 01093 entry->leaves[loop]->parent = entry; 01094 } 01095 } 01096 01097 return (entry); 01098 } 01099 /* End of tree utility functions */ 01100 01101 /* 01102 * Returns the list of parameters in an oid 01103 */ 01104 static oid * 01105 snmpCreateOid(int length,...) 01106 { 01107 va_list args; 01108 oid *new_oid; 01109 int loop; 01110 va_start(args, length); 01111 01112 new_oid = (oid *)xmalloc(sizeof(oid) * length); 01113 01114 if (length > 0) { 01115 for (loop = 0; loop < length; loop++) { 01116 new_oid[loop] = va_arg(args, int); 01117 } 01118 } 01119 01120 return (new_oid); 01121 } 01122 01123 /* 01124 * Debug calls, prints out the OID for debugging purposes. 01125 */ 01126 const char * 01127 snmpDebugOid(oid * Name, snint Len, MemBuf &outbuf) 01128 { 01129 char mbuf[16]; 01130 int x; 01131 if (outbuf.isNull()) 01132 outbuf.init(16, MAX_IPSTRLEN); 01133 01134 for (x = 0; x < Len; x++) { 01135 size_t bytes = snprintf(mbuf, sizeof(mbuf), ".%u", (unsigned int) Name[x]); 01136 outbuf.append(mbuf, bytes); 01137 } 01138 return outbuf.content(); 01139 } 01140 01141 static void 01142 snmpSnmplibDebug(int lvl, char *buf) 01143 { 01144 debugs(49, lvl, buf); 01145 } 01146 01147 01148 01149 /* 01150 IPv4 address: 10.10.0.9 ==> 01151 oid == 10.10.0.9 01152 IPv6 adress : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01 ==> 01153 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1 01154 */ 01155 void 01156 addr2oid(Ip::Address &addr, oid * Dest) 01157 { 01158 u_int i ; 01159 u_char *cp = NULL; 01160 struct in_addr i4addr; 01161 struct in6_addr i6addr; 01162 oid code = addr.IsIPv6()? INETADDRESSTYPE_IPV6 : INETADDRESSTYPE_IPV4 ; 01163 u_int size = (code == INETADDRESSTYPE_IPV4) ? sizeof(struct in_addr):sizeof(struct in6_addr); 01164 // Dest[0] = code ; 01165 if ( code == INETADDRESSTYPE_IPV4 ) { 01166 addr.GetInAddr(i4addr); 01167 cp = (u_char *) &(i4addr.s_addr); 01168 } else { 01169 addr.GetInAddr(i6addr); 01170 cp = (u_char *) &i6addr; 01171 } 01172 for ( i=0 ; i < size ; i++) { 01173 // OID's are in network order 01174 Dest[i] = *cp++; 01175 } 01176 MemBuf tmp; 01177 debugs(49, 7, "addr2oid: Dest : " << snmpDebugOid(Dest, size, tmp)); 01178 } 01179 01180 /* 01181 oid == 10.10.0.9 ==> 01182 IPv4 address: 10.10.0.9 01183 oid == 32.1.50.239.162.33.251.20.50.0.0.0.0.0.0.0.0.0.1 ==> 01184 IPv6 adress : 20:01:32:ef:a2:21:fb:32:00:00:00:00:00:00:00:00:OO:01 01185 */ 01186 void 01187 oid2addr(oid * id, Ip::Address &addr, u_int size) 01188 { 01189 struct in_addr i4addr; 01190 struct in6_addr i6addr; 01191 u_int i; 01192 u_char *cp; 01193 if ( size == sizeof(struct in_addr) ) 01194 cp = (u_char *) &(i4addr.s_addr); 01195 else 01196 cp = (u_char *) &(i6addr); 01197 MemBuf tmp; 01198 debugs(49, 7, "oid2addr: id : " << snmpDebugOid(id, size, tmp) ); 01199 for (i=0 ; i<size; i++) { 01200 cp[i] = id[i]; 01201 } 01202 if ( size == sizeof(struct in_addr) ) 01203 addr = i4addr; 01204 else 01205 addr = i6addr; 01206 } 01207 01208 /* SNMP checklists */ 01209 #include "acl/Strategy.h" 01210 #include "acl/Strategised.h" 01211 #include "acl/StringData.h" 01212 01213 class ACLSNMPCommunityStrategy : public ACLStrategy<char const *> 01214 { 01215 01216 public: 01217 virtual int match (ACLData<MatchType> * &, ACLFilledChecklist *); 01218 static ACLSNMPCommunityStrategy *Instance(); 01219 /* Not implemented to prevent copies of the instance. */ 01220 /* Not private to prevent brain dead g+++ warnings about 01221 * private constructors with no friends */ 01222 ACLSNMPCommunityStrategy(ACLSNMPCommunityStrategy const &); 01223 01224 private: 01225 static ACLSNMPCommunityStrategy Instance_; 01226 ACLSNMPCommunityStrategy() {} 01227 01228 ACLSNMPCommunityStrategy&operator=(ACLSNMPCommunityStrategy const &); 01229 }; 01230 01231 class ACLSNMPCommunity 01232 { 01233 01234 private: 01235 static ACL::Prototype RegistryProtoype; 01236 static ACLStrategised<char const *> RegistryEntry_; 01237 }; 01238 01239 ACL::Prototype ACLSNMPCommunity::RegistryProtoype(&ACLSNMPCommunity::RegistryEntry_, "snmp_community"); 01240 ACLStrategised<char const *> ACLSNMPCommunity::RegistryEntry_(new ACLStringData, ACLSNMPCommunityStrategy::Instance(), "snmp_community"); 01241 01242 int 01243 ACLSNMPCommunityStrategy::match (ACLData<MatchType> * &data, ACLFilledChecklist *checklist) 01244 { 01245 return data->match (checklist->snmp_community); 01246 } 01247 01248 ACLSNMPCommunityStrategy * 01249 ACLSNMPCommunityStrategy::Instance() 01250 { 01251 return &Instance_; 01252 } 01253 01254 ACLSNMPCommunityStrategy ACLSNMPCommunityStrategy::Instance_;
Search
Introduction
- About Squid
- Why Squid?
- Squid Developers
- How to Help Out
- Getting Squid
- Donate
- Squid Deployment Case-Studies
Documentation
- FAQ | Wiki | Book
- Configuration Reference
- Configuration Guide - Visolve
- Configuration Examples
- Users guide
- Non-English
- Security Advisories
- More...
Support
- Bugzilla Database
- Mailing lists
- Contacting us
- Commercial services
- Project Sponsors
- Squid-based products
