net-snmp  5.4.1
snmpIPXDomain.c
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 }