net-snmp
5.4.1
|
00001 #include <net-snmp/net-snmp-config.h> 00002 00003 #include <stdio.h> 00004 #include <sys/types.h> 00005 #include <ctype.h> 00006 #include <errno.h> 00007 00008 #if HAVE_STRING_H 00009 #include <string.h> 00010 #else 00011 #include <strings.h> 00012 #endif 00013 #if HAVE_STDLIB_H 00014 #include <stdlib.h> 00015 #endif 00016 #if HAVE_UNISTD_H 00017 #include <unistd.h> 00018 #endif 00019 #if HAVE_SYS_SOCKET_H 00020 #include <sys/socket.h> 00021 #endif 00022 #if HAVE_NETINET_IN_H 00023 #include <netinet/in.h> 00024 #endif 00025 00026 #if HAVE_DMALLOC_H 00027 #include <dmalloc.h> 00028 #endif 00029 00030 #include <net-snmp/types.h> 00031 #include <net-snmp/output_api.h> 00032 #include <net-snmp/config_api.h> 00033 00034 #include <net-snmp/library/snmp_transport.h> 00035 #include <net-snmp/library/snmpIPXDomain.h> 00036 00037 #define SNMP_IPX_DEFAULT_PORT 36879 /* Specified in RFC 1420. */ 00038 static netsnmp_tdomain ipxDomain; 00039 00040 /* 00041 * Return a string representing the address in data, or else the "far end" 00042 * address if data is NULL. 00043 */ 00044 00045 static char * 00046 netsnmp_ipx_fmtaddr(netsnmp_transport *t, void *data, int len) 00047 { 00048 struct sockaddr_ipx *to = NULL; 00049 00050 if (data != NULL && len == sizeof(struct sockaddr_ipx)) { 00051 to = (struct sockaddr_ipx *) data; 00052 } else if (t != NULL && t->data != NULL) { 00053 to = (struct sockaddr_ipx *) t->data; 00054 } 00055 if (to == NULL) { 00056 return strdup("IPX: unknown"); 00057 } else { 00058 char tmp[64]; 00059 sprintf(tmp, "IPX: %08X:%02X%02X%02X%02X%02X%02X/%hu", 00060 ntohl(to->sipx_network), to->sipx_node[0], 00061 to->sipx_node[1], to->sipx_node[2], to->sipx_node[3], 00062 to->sipx_node[4], to->sipx_node[5], ntohs(to->sipx_port)); 00063 return strdup(tmp); 00064 } 00065 } 00066 00067 00068 00069 /* 00070 * You can write something into opaque that will subsequently get passed back 00071 * to your send function if you like. For instance, you might want to 00072 * remember where a PDU came from, so that you can send a reply there... 00073 */ 00074 00075 static int 00076 netsnmp_ipx_recv(netsnmp_transport *t, void *buf, int size, 00077 void **opaque, int *olength) 00078 { 00079 int rc = -1; 00080 socklen_t fromlen = sizeof(struct sockaddr); 00081 struct sockaddr *from; 00082 00083 if (t != NULL && t->sock >= 0) { 00084 from = (struct sockaddr *)malloc(sizeof(struct sockaddr_ipx)); 00085 if (from == NULL) { 00086 *opaque = NULL; 00087 *olength = 0; 00088 return -1; 00089 } else { 00090 memset(from, 0, fromlen); 00091 } 00092 00093 while (rc < 0) { 00094 rc = recvfrom(t->sock, buf, size, 0, from, &fromlen); 00095 if (rc < 0 && errno != EINTR) { 00096 break; 00097 } 00098 } 00099 00100 if (rc >= 0) { 00101 char *str = netsnmp_ipx_fmtaddr(NULL, from, fromlen); 00102 DEBUGMSGTL(("netsnmp_ipx","recvfrom fd %d got %d bytes(from %s)\n", 00103 t->sock, rc, str)); 00104 free(str); 00105 } else { 00106 DEBUGMSGTL(("netsnmp_ipx", "recvfrom fd %d err %d (\"%s\")\n", 00107 t->sock, errno, strerror(errno))); 00108 } 00109 *opaque = (void *) from; 00110 *olength = sizeof(struct sockaddr_ipx); 00111 } 00112 return rc; 00113 } 00114 00115 00116 00117 static int 00118 netsnmp_ipx_send(netsnmp_transport *t, void *buf, int size, 00119 void **opaque, int *olength) 00120 { 00121 int rc = -1; 00122 struct sockaddr *to = NULL; 00123 00124 if (opaque != NULL && *opaque != NULL && 00125 *olength == sizeof(struct sockaddr_ipx)) { 00126 to = (struct sockaddr *) (*opaque); 00127 } else if (t != NULL && t->data != NULL && 00128 t->data_length == sizeof(struct sockaddr_ipx)) { 00129 to = (struct sockaddr *) (t->data); 00130 } 00131 00132 if (to != NULL && t != NULL && t->sock >= 0) { 00133 char *str = netsnmp_ipx_fmtaddr(NULL, (void *)to, 00134 sizeof(struct sockaddr_ipx)); 00135 DEBUGMSGTL(("netsnmp_ipx", "send %d bytes from %p to %s on fd %d\n", 00136 size, buf, str, t->sock)); 00137 free(str); 00138 while (rc < 0) { 00139 rc = sendto(t->sock, buf, size, 0, to, sizeof(struct sockaddr)); 00140 if (rc < 0 && errno != EINTR) { 00141 break; 00142 } 00143 } 00144 } 00145 return rc; 00146 } 00147 00148 00149 00150 static int 00151 netsnmp_ipx_close(netsnmp_transport *t) 00152 { 00153 int rc = -1; 00154 if (t->sock >= 0) { 00155 #ifndef HAVE_CLOSESOCKET 00156 rc = close(t->sock); 00157 #else 00158 rc = closesocket(t->sock); 00159 #endif 00160 t->sock = -1; 00161 } 00162 return rc; 00163 } 00164 00165 00166 00167 /* 00168 * Open a IPX-based transport for SNMP. Local is TRUE if addr is the local 00169 * address to bind to (i.e. this is a server-type session); otherwise addr is 00170 * the remote address to send things to. 00171 */ 00172 00173 netsnmp_transport * 00174 netsnmp_ipx_transport(struct sockaddr_ipx *addr, int local) 00175 { 00176 netsnmp_transport *t = NULL; 00177 int rc = 0; 00178 char *str = NULL; 00179 00180 if (addr == NULL || addr->sipx_family != AF_IPX) { 00181 return NULL; 00182 } 00183 00184 t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport)); 00185 if (t == NULL) { 00186 return NULL; 00187 } 00188 00189 str = netsnmp_ipx_fmtaddr(NULL, (void *)addr, 00190 sizeof(struct sockaddr_ipx)); 00191 DEBUGMSGTL(("netsnmp_ipx", "open %s %s\n", local ? "local" : "remote", 00192 str)); 00193 free(str); 00194 00195 memset(t, 0, sizeof(netsnmp_transport)); 00196 00197 t->domain = netsnmpIPXDomain; 00198 t->domain_length = netsnmpIPXDomain_len; 00199 00200 t->sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX); 00201 if (t->sock < 0) { 00202 netsnmp_transport_free(t); 00203 return NULL; 00204 } 00205 00206 if (local) { 00207 t->local = (unsigned char*)malloc(12); 00208 if (t->local == NULL) { 00209 netsnmp_transport_free(t); 00210 return NULL; 00211 } 00212 memcpy(&(t->local[00]), (u_char *) & (addr->sipx_network), 4); 00213 memcpy(&(t->local[04]), (u_char *) & (addr->sipx_node), 6); 00214 memcpy(&(t->local[10]), (u_char *) & (addr->sipx_port), 2); 00215 t->local_length = 12; 00216 00217 /* 00218 * This session is inteneded as a server, so we must bind on to the 00219 * given address (which may include a particular network and/or node 00220 * address, but definitely includes a port number). 00221 */ 00222 00223 rc = bind(t->sock, (struct sockaddr *) addr, 00224 sizeof(struct sockaddr)); 00225 if (rc != 0) { 00226 netsnmp_ipx_close(t); 00227 netsnmp_transport_free(t); 00228 return NULL; 00229 } 00230 t->data = NULL; 00231 t->data_length = 0; 00232 } else { 00233 t->remote = (unsigned char*)malloc(12); 00234 if (t->remote == NULL) { 00235 netsnmp_transport_free(t); 00236 return NULL; 00237 } 00238 memcpy(&(t->remote[00]), (u_char *) & (addr->sipx_network), 4); 00239 memcpy(&(t->remote[04]), (u_char *) & (addr->sipx_node), 6); 00240 memcpy(&(t->remote[10]), (u_char *) & (addr->sipx_port), 2); 00241 t->remote_length = 12; 00242 00243 /* 00244 * This is a client session. Save the address in the 00245 * transport-specific data pointer for later use by snmp_ipx_send. 00246 */ 00247 00248 t->data = malloc(sizeof(struct sockaddr_ipx)); 00249 if (t->data == NULL) { 00250 netsnmp_transport_free(t); 00251 return NULL; 00252 } 00253 memcpy(t->data, addr, sizeof(struct sockaddr_ipx)); 00254 t->data_length = sizeof(struct sockaddr_ipx); 00255 } 00256 00257 /* 00258 * Maximum size of an IPX PDU is 576 bytes including a 30-byte header. 00259 * Ridiculous! 00260 */ 00261 00262 t->msgMaxSize = 576 - 30; 00263 t->f_recv = netsnmp_ipx_recv; 00264 t->f_send = netsnmp_ipx_send; 00265 t->f_close = netsnmp_ipx_close; 00266 t->f_accept = NULL; 00267 t->f_fmtaddr = netsnmp_ipx_fmtaddr; 00268 00269 return t; 00270 } 00271 00272 00273 00274 /* 00275 * Attempt to parse a string of the form [%08x]:%12x[/%d] where the parts 00276 * are the network number, the node address and the port in that order. 00277 */ 00278 00279 int 00280 netsnmp_sockaddr_ipx2(struct sockaddr_ipx *addr, const char *peername, 00281 const char *default_target) 00282 { 00283 char *input = NULL, *def = NULL; 00284 const char *network, *node, *port; 00285 char *tmp; 00286 unsigned long i; 00287 00288 if (addr == NULL) { 00289 return 0; 00290 } 00291 memset(addr, 0, sizeof(struct sockaddr_ipx)); 00292 00293 DEBUGMSGTL(("netsnmp_sockaddr_ipx", 00294 "addr %p, peername \"%s\" default_target \"%s\"\n", 00295 addr, peername ? peername : "[NIL]", 00296 default_target ? default_target : "[NIL]")); 00297 00298 addr->sipx_family = AF_IPX; 00299 addr->sipx_type = 4; /* Specified in RFC 1420. */ 00300 00301 network = input = strdup(peername ? peername : ""); 00302 tmp = strchr(network, ':'); 00303 if (tmp != NULL) { 00304 DEBUGMSGTL(("netsnmp_sockaddr_ipx", "Node identified\n")); 00305 *tmp++ = '\0'; 00306 node = tmp; 00307 tmp = strchr(tmp, '/'); 00308 } else { 00309 node = NULL; 00310 tmp = strchr(network, '/'); 00311 } 00312 if (tmp != NULL) { 00313 DEBUGMSGTL(("netsnmp_sockaddr_ipx", "Port identified\n")); 00314 *tmp++ = '\0'; 00315 port = tmp; 00316 } else 00317 port = NULL; 00318 00319 DEBUGMSGTL(("netsnmp_sockaddr_ipx", "Address: %s:%s/%s\n", 00320 network ? network : "[NIL]", node ? node : "[NIL]", 00321 port ? port : "[NIL]")); 00322 00323 def = strdup(default_target ? default_target : ""); 00324 if (network == NULL || *network == '\0') 00325 network = def; 00326 tmp = strchr(def, ':'); 00327 if (tmp != NULL) { 00328 *tmp++ = '\0'; 00329 if (node == NULL || *node == '\0') 00330 node = tmp; 00331 tmp = strchr(tmp, '/'); 00332 } else 00333 tmp = strchr(def, '/'); 00334 if (tmp != NULL) { 00335 *tmp++ = '\0'; 00336 if (port == NULL || *port == '\0') 00337 port = tmp; 00338 } 00339 00340 DEBUGMSGTL(("netsnmp_sockaddr_ipx", "Address: %s:%s/%s\n", 00341 network ? network : "[NIL]", node ? node : "[NIL]", 00342 port ? port : "[NIL]")); 00343 00344 if (network == NULL || *network == '\0') 00345 network = "0"; 00346 00347 if (node == NULL || *node == '\0') 00348 node = "000000000000"; 00349 00350 if (port == NULL || *port == '\0') 00351 #define val(x) __STRING(x) 00352 port = val(SNMP_IPX_DEFAULT_PORT); 00353 #undef val 00354 00355 DEBUGMSGTL(("netsnmp_sockaddr_ipx", "Address: %s:%s/%s\n", 00356 network ? network : "[NIL]", node ? node : "[NIL]", 00357 port ? port : "[NIL]")); 00358 00359 if(sscanf(network, "%8lx%*c", &i) == 1) { 00360 DEBUGMSGTL(("netsnmp_sockaddr_ipx", "network parsed okay\n")); 00361 addr->sipx_network = htonl(i); 00362 } else { 00363 DEBUGMSGTL(("netsnmp_sockaddr_ipx", 00364 "failed to parse network part of address\n")); 00365 free(def); 00366 free(input); 00367 return 0; 00368 } 00369 00370 if(sscanf(node, "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%*c", 00371 &addr->sipx_node[0], &addr->sipx_node[1], 00372 &addr->sipx_node[2], &addr->sipx_node[3], 00373 &addr->sipx_node[4], &addr->sipx_node[5]) == 6) { 00374 DEBUGMSGTL(("netsnmp_sockaddr_ipx", "node parsed okay\n")); 00375 } else { 00376 DEBUGMSGTL(("netsnmp_sockaddr_ipx", 00377 "failed to parse node part of address\n")); 00378 free(def); 00379 free(input); 00380 return 0; 00381 } 00382 00383 if(sscanf(port, "%lu%*c", &i) == 1) { 00384 DEBUGMSGTL(("netsnmp_sockaddr_ipx", "port parsed okay\n")); 00385 addr->sipx_port = htons(i); 00386 } else { 00387 DEBUGMSGTL(("netsnmp_sockaddr_ipx", 00388 "failed to parse port part of address\n")); 00389 free(def); 00390 free(input); 00391 return 0; 00392 } 00393 00394 free(def); 00395 free(input); 00396 return 1; 00397 } 00398 00399 00400 00401 int 00402 netsnmp_sockaddr_ipx(struct sockaddr_ipx *addr, const char *peername) 00403 { 00404 return netsnmp_sockaddr_ipx2(addr, peername, NULL); 00405 } 00406 00407 00408 00409 netsnmp_transport * 00410 netsnmp_ipx_create_tstring(const char *str, int local, 00411 const char *default_target) 00412 { 00413 struct sockaddr_ipx addr; 00414 00415 if (netsnmp_sockaddr_ipx2(&addr, str, default_target)) { 00416 return netsnmp_ipx_transport(&addr, local); 00417 } else { 00418 return NULL; 00419 } 00420 } 00421 00422 00423 00424 netsnmp_transport * 00425 netsnmp_ipx_create_ostring(const u_char * o, size_t o_len, int local) 00426 { 00427 struct sockaddr_ipx addr; 00428 00429 if (o_len == 12) { 00430 addr.sipx_family = AF_IPX; 00431 memcpy((u_char *) & (addr.sipx_network), &(o[00]), 4); 00432 memcpy((u_char *) & (addr.sipx_node), &(o[04]), 6); 00433 memcpy((u_char *) & (addr.sipx_port), &(o[10]), 2); 00434 return netsnmp_ipx_transport(&addr, local); 00435 } 00436 return NULL; 00437 } 00438 00439 00440 00441 void 00442 netsnmp_ipx_ctor(void) 00443 { 00444 ipxDomain.name = netsnmpIPXDomain; 00445 ipxDomain.name_length = netsnmpIPXDomain_len; 00446 ipxDomain.prefix = (const char**)calloc(2, sizeof(char *)); 00447 ipxDomain.prefix[0] = "ipx"; 00448 00449 ipxDomain.f_create_from_tstring_new = netsnmp_ipx_create_tstring; 00450 ipxDomain.f_create_from_ostring = netsnmp_ipx_create_ostring; 00451 00452 netsnmp_tdomain_register(&ipxDomain); 00453 }