Coverage Report

Created: 2023-06-07 06:43

/src/net-snmp/snmplib/transports/snmpIPXDomain.c
Line
Count
Source (jump to first uncovered line)
1
#include <net-snmp/net-snmp-config.h>
2
3
#include <net-snmp/library/snmpIPXDomain.h>
4
5
#include <stdio.h>
6
#include <sys/types.h>
7
#include <ctype.h>
8
#include <errno.h>
9
10
#ifdef HAVE_STRING_H
11
#include <string.h>
12
#else
13
#include <strings.h>
14
#endif
15
#ifdef HAVE_STDLIB_H
16
#include <stdlib.h>
17
#endif
18
#ifdef HAVE_UNISTD_H
19
#include <unistd.h>
20
#endif
21
#ifdef HAVE_SYS_SOCKET_H
22
#include <sys/socket.h>
23
#endif
24
#ifdef HAVE_NETINET_IN_H
25
#include <netinet/in.h>
26
#endif
27
28
#include <net-snmp/types.h>
29
#include <net-snmp/output_api.h>
30
#include <net-snmp/config_api.h>
31
32
#include <net-snmp/library/snmp_assert.h>
33
#include <net-snmp/library/snmp_transport.h>
34
#include <net-snmp/library/tools.h>
35
36
#define SNMP_IPX_DEFAULT_PORT 36879   /*  Specified in RFC 1420.  */
37
static netsnmp_tdomain ipxDomain;
38
39
/*
40
 * Return a string representing the address in data, or else the "far end"
41
 * address if data is NULL.  
42
 */
43
44
static char *
45
netsnmp_ipx_fmtaddr(netsnmp_transport *t, const void *data, int len)
46
0
{
47
0
    const struct sockaddr_ipx *to = NULL;
48
49
0
    if (data != NULL && len == sizeof(struct sockaddr_ipx)) {
50
0
        to = (const struct sockaddr_ipx *) data;
51
0
    } else if (t != NULL && t->data != NULL) {
52
0
        to = (const struct sockaddr_ipx *) t->data;
53
0
    }
54
0
    if (to == NULL) {
55
0
        return strdup("IPX: unknown");
56
0
    } else {
57
0
        char *tmp;
58
59
0
        if (asprintf(&tmp, "IPX: %08X:%02X%02X%02X%02X%02X%02X/%hu",
60
0
         ntohl(to->sipx_network), to->sipx_node[0],
61
0
         to->sipx_node[1], to->sipx_node[2], to->sipx_node[3],
62
0
         to->sipx_node[4], to->sipx_node[5], ntohs(to->sipx_port))
63
0
      < 0)
64
0
            tmp = NULL;
65
0
        return tmp;
66
0
    }
67
0
}
68
69
static void netsnmp_ipx_get_taddr(struct netsnmp_transport_s *t,
70
                                  void **addr, size_t *addr_len)
71
0
{
72
0
    struct sockaddr_ipx *sa = t->remote;
73
74
0
    netsnmp_assert(t->remote_length == sizeof(*sa));
75
0
    *addr_len = 12;
76
0
    if ((*addr = malloc(*addr_len))) {
77
0
        unsigned char *p = *addr;
78
79
0
        memcpy(p + 0,  &sa->sipx_network, 4);
80
0
        memcpy(p + 4,  &sa->sipx_node,    6);
81
0
        memcpy(p + 10, &sa->sipx_port,    2);
82
0
    }
83
0
}
84
85
/*
86
 * You can write something into opaque that will subsequently get passed back 
87
 * to your send function if you like.  For instance, you might want to
88
 * remember where a PDU came from, so that you can send a reply there...  
89
 */
90
91
static int
92
netsnmp_ipx_recv(netsnmp_transport *t, void *buf, int size,
93
     void **opaque, int *olength)
94
0
{
95
0
    int        rc = -1;
96
0
    socklen_t      fromlen = sizeof(struct sockaddr);
97
0
    struct sockaddr *from;
98
99
0
    if (t != NULL && t->sock >= 0) {
100
0
        from = (struct sockaddr *)malloc(sizeof(struct sockaddr_ipx));
101
0
        if (from == NULL) {
102
0
            *opaque = NULL;
103
0
            *olength = 0;
104
0
            return -1;
105
0
        } else {
106
0
            memset(from, 0, fromlen);
107
0
        }
108
109
0
  while (rc < 0) {
110
0
    rc = recvfrom(t->sock, buf, size, 0, from, &fromlen);
111
0
    if (rc < 0 && errno != EINTR) {
112
0
      break;
113
0
    }
114
0
  }
115
116
0
        if (rc >= 0) {
117
0
            DEBUGIF("netsnmp_ipx") {
118
0
                char *str = netsnmp_ipx_fmtaddr(NULL, from, fromlen);
119
0
                DEBUGMSGTL(("netsnmp_ipx",
120
0
                            "recvfrom fd %d got %d bytes(from %s)\n",
121
0
                            t->sock, rc, str));
122
0
                free(str);
123
0
            }
124
0
        } else {
125
0
            DEBUGMSGTL(("netsnmp_ipx", "recvfrom fd %d err %d (\"%s\")\n",
126
0
                        t->sock, errno, strerror(errno)));
127
0
        }
128
0
        *opaque = (void *) from;
129
0
        *olength = sizeof(struct sockaddr_ipx);
130
0
    }
131
0
    return rc;
132
0
}
133
134
135
136
static int
137
netsnmp_ipx_send(netsnmp_transport *t, const void *buf, int size,
138
     void **opaque, int *olength)
139
0
{
140
0
    int rc = -1;
141
0
    const struct sockaddr *to = NULL;
142
143
0
    if (opaque != NULL && *opaque != NULL &&
144
0
  *olength == sizeof(struct sockaddr_ipx)) {
145
0
        to = (const struct sockaddr *) (*opaque);
146
0
    } else if (t != NULL && t->data != NULL &&
147
0
               t->data_length == sizeof(struct sockaddr_ipx)) {
148
0
        to = (const struct sockaddr *) (t->data);
149
0
    }
150
151
0
    if (to != NULL && t != NULL && t->sock >= 0) {
152
0
        DEBUGIF("netsnmp_ipx") {
153
0
            char *str = netsnmp_ipx_fmtaddr(NULL, to,
154
0
                                            sizeof(struct sockaddr_ipx));
155
0
            DEBUGMSGTL(("netsnmp_ipx", "send %d bytes from %p to %s on fd %d\n",
156
0
                        size, buf, str, t->sock));
157
0
            free(str);
158
0
        }
159
0
  while (rc < 0) {
160
0
      rc = sendto(t->sock, buf, size, 0, to, sizeof(struct sockaddr));
161
0
      if (rc < 0 && errno != EINTR) {
162
0
    break;
163
0
      }
164
0
  }
165
0
    }
166
0
    return rc;
167
0
}
168
169
170
171
static int
172
netsnmp_ipx_close(netsnmp_transport *t)
173
0
{
174
0
    int rc = -1;
175
0
    if (t->sock >= 0) {
176
0
#ifndef HAVE_CLOSESOCKET
177
0
        rc = close(t->sock);
178
#else
179
        rc = closesocket(t->sock);
180
#endif
181
0
        t->sock = -1;
182
0
    }
183
0
    return rc;
184
0
}
185
186
187
188
/*
189
 * Open a IPX-based transport for SNMP.  Local is TRUE if addr is the local
190
 * address to bind to (i.e. this is a server-type session); otherwise addr is 
191
 * the remote address to send things to.  
192
 */
193
194
netsnmp_transport *
195
netsnmp_ipx_transport(const struct sockaddr_ipx *addr, int local)
196
0
{
197
0
    netsnmp_transport *t = NULL;
198
0
    int             rc = 0;
199
200
#ifdef NETSNMP_NO_LISTEN_SUPPORT
201
    if (local)
202
        return NULL;
203
#endif /* NETSNMP_NO_LISTEN_SUPPORT */
204
205
0
    if (addr == NULL || addr->sipx_family != AF_IPX) {
206
0
        return NULL;
207
0
    }
208
209
0
    t = SNMP_MALLOC_TYPEDEF(netsnmp_transport);
210
0
    if (t == NULL) {
211
0
        return NULL;
212
0
    }
213
214
0
    DEBUGIF("netsnmp_ipx") {
215
0
        char *str = netsnmp_ipx_fmtaddr(NULL, addr,
216
0
                                  sizeof(struct sockaddr_ipx));
217
0
        DEBUGMSGTL(("netsnmp_ipx", "open %s %s\n", local ? "local" : "remote",
218
0
                    str));
219
0
        free(str);
220
0
    }
221
222
0
    t->domain = netsnmpIPXDomain;
223
0
    t->domain_length = netsnmpIPXDomain_len;
224
225
0
    t->sock = socket(AF_IPX, SOCK_DGRAM, AF_IPX);
226
0
    if (t->sock < 0) {
227
0
        netsnmp_transport_free(t);
228
0
        return NULL;
229
0
    }
230
231
0
    if (local) {
232
0
#ifndef NETSNMP_NO_LISTEN_SUPPORT
233
0
        t->local_length = sizeof(*addr);
234
0
        t->local = netsnmp_memdup(addr, sizeof(*addr));
235
0
        if (t->local == NULL) {
236
0
            netsnmp_transport_free(t);
237
0
            return NULL;
238
0
        }
239
240
        /*
241
         * This session is inteneded as a server, so we must bind on to the
242
         * given address (which may include a particular network and/or node
243
         * address, but definitely includes a port number).
244
         */
245
246
0
        rc = bind(t->sock, addr, sizeof(struct sockaddr));
247
0
        if (rc != 0) {
248
0
            netsnmp_ipx_close(t);
249
0
            netsnmp_transport_free(t);
250
0
            return NULL;
251
0
        }
252
0
        t->data = NULL;
253
0
        t->data_length = 0;
254
#else /* NETSNMP_NO_LISTEN_SUPPORT */
255
        return NULL;
256
#endif /* NETSNMP_NO_LISTEN_SUPPORT */
257
0
    } else {
258
0
        t->remote_length = sizeof(*addr);
259
0
        t->remote = netsnmp_memdup(addr, sizeof(*addr));
260
0
        if (t->remote == NULL) {
261
0
            netsnmp_transport_free(t);
262
0
            return NULL;
263
0
        }
264
265
        /*
266
         * This is a client session.  Save the address in the
267
         * transport-specific data pointer for later use by snmp_ipx_send.
268
         */
269
270
0
        t->data = malloc(sizeof(struct sockaddr_ipx));
271
0
        if (t->data == NULL) {
272
0
            netsnmp_transport_free(t);
273
0
            return NULL;
274
0
        }
275
0
        memcpy(t->data, addr, sizeof(struct sockaddr_ipx));
276
0
        t->data_length = sizeof(struct sockaddr_ipx);
277
0
    }
278
279
    /*
280
     * Maximum size of an IPX PDU is 576 bytes including a 30-byte header.
281
     * Ridiculous!  
282
     */
283
284
0
    t->msgMaxSize = 576 - 30;
285
0
    t->f_recv     = netsnmp_ipx_recv;
286
0
    t->f_send     = netsnmp_ipx_send;
287
0
    t->f_close    = netsnmp_ipx_close;
288
0
    t->f_accept   = NULL;
289
0
    t->f_fmtaddr  = netsnmp_ipx_fmtaddr;
290
0
    t->f_get_taddr = netsnmp_ipx_get_taddr;
291
292
0
    return t;
293
0
}
294
295
296
297
/*
298
 * Attempt to parse a string of the form [%08x]:%12x[/%d] where the parts
299
 * are the network number, the node address and the port in that order.  
300
 */
301
302
int
303
netsnmp_sockaddr_ipx2(struct sockaddr_ipx *addr, const char *peername,
304
          const char *default_target)
305
0
{
306
0
    char           *input = NULL, *def = NULL;
307
0
    const char     *network, *node, *port;
308
0
    char           *tmp;
309
0
    unsigned long   i;
310
311
0
    if (addr == NULL) {
312
0
        return 0;
313
0
    }
314
0
    memset(addr, 0, sizeof(struct sockaddr_ipx));
315
316
0
    DEBUGMSGTL(("netsnmp_sockaddr_ipx",
317
0
    "addr %p, peername \"%s\" default_target \"%s\"\n",
318
0
                addr, peername ? peername : "[NIL]",
319
0
    default_target ? default_target : "[NIL]"));
320
321
0
    addr->sipx_family = AF_IPX;
322
0
    addr->sipx_type = 4;        /*  Specified in RFC 1420.  */
323
324
0
    network = input = strdup(peername ? peername : "");
325
0
    tmp = strchr(input, ':');
326
0
    if (tmp != NULL) {
327
0
        DEBUGMSGTL(("netsnmp_sockaddr_ipx", "Node identified\n"));
328
0
        *tmp++ = '\0';
329
0
  node = tmp;
330
0
        tmp = strchr(tmp, '/');
331
0
    } else {
332
0
        node = NULL;
333
0
        tmp = strchr(input, '/');
334
0
    }
335
0
    if (tmp != NULL) {
336
0
        DEBUGMSGTL(("netsnmp_sockaddr_ipx", "Port identified\n"));
337
0
        *tmp++ = '\0';
338
0
        port = tmp;
339
0
    } else
340
0
        port = NULL;
341
342
0
    DEBUGMSGTL(("netsnmp_sockaddr_ipx", "Address: %s:%s/%s\n",
343
0
                network ? network : "[NIL]", node ? node : "[NIL]",
344
0
                port ? port : "[NIL]"));
345
346
0
    def = strdup(default_target ? default_target : "");
347
0
    if (network == NULL || *network == '\0')
348
0
        network = def;
349
0
    tmp = strchr(def, ':');
350
0
    if (tmp != NULL) {
351
0
        *tmp++ = '\0';
352
0
  if (node == NULL || *node == '\0')
353
0
            node = tmp;
354
0
        tmp = strchr(tmp, '/');
355
0
    } else
356
0
        tmp = strchr(def, '/');
357
0
    if (tmp != NULL) {
358
0
        *tmp++ = '\0';
359
0
        if (port == NULL || *port == '\0')
360
0
            port = tmp;
361
0
    }
362
363
0
    DEBUGMSGTL(("netsnmp_sockaddr_ipx", "Address: %s:%s/%s\n",
364
0
                network ? network : "[NIL]", node ? node : "[NIL]",
365
0
                port ? port : "[NIL]"));
366
367
0
    if (network == NULL || *network == '\0')
368
0
        network = "0";
369
370
0
    if (node == NULL || *node == '\0')
371
0
        node = "000000000000";
372
373
0
    if (port == NULL || *port == '\0')
374
0
#define val(x) __STRING(x)
375
0
        port = val(SNMP_IPX_DEFAULT_PORT);
376
0
#undef val
377
378
0
    DEBUGMSGTL(("netsnmp_sockaddr_ipx", "Address: %s:%s/%s\n",
379
0
                network ? network : "[NIL]", node ? node : "[NIL]",
380
0
                port ? port : "[NIL]"));
381
382
0
    if(sscanf(network, "%8lx%*c", &i) == 1) {
383
0
        DEBUGMSGTL(("netsnmp_sockaddr_ipx", "network parsed okay\n"));
384
0
        addr->sipx_network = htonl(i);
385
0
    } else {
386
0
        DEBUGMSGTL(("netsnmp_sockaddr_ipx",
387
0
                    "failed to parse network part of address\n"));
388
0
        free(def);
389
0
        free(input);
390
0
        return 0;
391
0
    }
392
393
0
    if(sscanf(node, "%2hhx%2hhx%2hhx%2hhx%2hhx%2hhx%*c",
394
0
              &addr->sipx_node[0], &addr->sipx_node[1],
395
0
              &addr->sipx_node[2], &addr->sipx_node[3],
396
0
              &addr->sipx_node[4], &addr->sipx_node[5]) == 6) {
397
0
        DEBUGMSGTL(("netsnmp_sockaddr_ipx", "node parsed okay\n"));
398
0
    } else {
399
0
        DEBUGMSGTL(("netsnmp_sockaddr_ipx",
400
0
                    "failed to parse node part of address\n"));
401
0
        free(def);
402
0
        free(input);
403
0
        return 0;
404
0
    }
405
406
0
    if(sscanf(port, "%lu%*c", &i) == 1) {
407
0
        DEBUGMSGTL(("netsnmp_sockaddr_ipx", "port parsed okay\n"));
408
0
        addr->sipx_port = htons(i);
409
0
    } else {
410
0
        DEBUGMSGTL(("netsnmp_sockaddr_ipx",
411
0
                    "failed to parse port part of address\n"));
412
0
        free(def);
413
0
        free(input);
414
0
        return 0;
415
0
    }
416
417
0
    free(def);
418
0
    free(input);
419
0
    return 1;
420
0
}
421
422
423
424
int
425
netsnmp_sockaddr_ipx(struct sockaddr_ipx *addr, const char *peername)
426
0
{
427
0
    return netsnmp_sockaddr_ipx2(addr, peername, NULL);
428
0
}
429
430
431
432
netsnmp_transport *
433
netsnmp_ipx_create_tstring(const char *str, int local,
434
         const char *default_target)
435
0
{
436
0
    struct sockaddr_ipx addr;
437
438
0
    if (netsnmp_sockaddr_ipx2(&addr, str, default_target)) {
439
0
        return netsnmp_ipx_transport(&addr, local);
440
0
    } else {
441
0
        return NULL;
442
0
    }
443
0
}
444
445
static int netsnmp_ipx_ostring_to_sockaddr(struct sockaddr_ipx *sa,
446
                                           const void *o, size_t o_len)
447
0
{
448
0
    const char *p = o;
449
450
0
    if (o_len != 12)
451
0
        return 0;
452
453
0
    memset(sa, 0, sizeof(*sa));
454
0
    sa->sipx_family = AF_IPX;
455
0
    memcpy(&sa->sipx_network, p + 0, 4);
456
0
    memcpy(&sa->sipx_node,    p + 4, 6);
457
0
    memcpy(&sa->sipx_port,    p + 10, 2);
458
0
    return 1;
459
0
}
460
461
netsnmp_transport *
462
netsnmp_ipx_create_ostring(const void *o, size_t o_len, int local)
463
0
{
464
0
    struct sockaddr_ipx sa;
465
466
0
    if (netsnmp_ipx_ostring_to_sockaddr(&sa, o, o_len))
467
0
        return netsnmp_ipx_transport(&sa, local);
468
469
0
    return NULL;
470
0
}
471
472
473
474
void
475
netsnmp_ipx_ctor(void)
476
3.81k
{
477
3.81k
    ipxDomain.name = netsnmpIPXDomain;
478
3.81k
    ipxDomain.name_length = netsnmpIPXDomain_len;
479
3.81k
    ipxDomain.prefix = calloc(2, sizeof(char *));
480
3.81k
    if (!ipxDomain.prefix) {
481
0
        snmp_log(LOG_ERR, "calloc() failed - out of memory\n");
482
0
        return;
483
0
    }
484
3.81k
    ipxDomain.prefix[0] = "ipx";
485
486
3.81k
    ipxDomain.f_create_from_tstring_new = netsnmp_ipx_create_tstring;
487
3.81k
    ipxDomain.f_create_from_ostring     = netsnmp_ipx_create_ostring;
488
489
3.81k
    netsnmp_tdomain_register(&ipxDomain);
490
3.81k
}