Coverage Report

Created: 2025-12-27 06:45

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/transports/snmpUDPIPv6Domain.c
Line
Count
Source
1
/*
2
 * Portions of this file are copyrighted by:
3
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
4
 * Use is subject to license terms specified in the COPYING file
5
 * distributed with the Net-SNMP package.
6
 */
7
#include <net-snmp/net-snmp-config.h>
8
9
#include "snmpIPBaseDomain.h"
10
#include <net-snmp/library/snmpUDPIPv6Domain.h>
11
#include <net-snmp/library/system.h>
12
13
#include <net-snmp/types.h>
14
15
#ifdef NETSNMP_TRANSPORT_UDPIPV6_DOMAIN
16
17
#include <stdio.h>
18
#include <sys/types.h>
19
#include <ctype.h>
20
#include <errno.h>
21
22
#ifdef HAVE_STRING_H
23
#include <string.h>
24
#else
25
#include <strings.h>
26
#endif
27
#include <stddef.h>
28
#ifdef HAVE_STDLIB_H
29
#include <stdlib.h>
30
#endif
31
#ifdef HAVE_UNISTD_H
32
#include <unistd.h>
33
#endif
34
#ifdef HAVE_SYS_SOCKET_H
35
#include <sys/socket.h>
36
#endif
37
#ifdef HAVE_NETINET_IN_H
38
#include <netinet/in.h>
39
#endif
40
#ifdef HAVE_ARPA_INET_H
41
#include <arpa/inet.h>
42
#endif
43
#ifdef HAVE_NETDB_H
44
#include <netdb.h>
45
#endif
46
#ifdef HAVE_NET_IF_H
47
#include <net/if.h>
48
#endif
49
50
#ifdef HAVE_STRUCT_SOCKADDR_STORAGE_SS_FAMILY
51
#define SS_FAMILY ss_family
52
#elif defined(HAVE_STRUCT_SOCKADDR_STORAGE___SS_FAMILY)
53
#define SS_FAMILY __ss_family
54
#endif
55
56
#include <net-snmp/types.h>
57
#include <net-snmp/output_api.h>
58
#include <net-snmp/config_api.h>
59
60
#include <net-snmp/library/snmp_impl.h>
61
#include <net-snmp/library/snmp_transport.h>
62
#include <net-snmp/library/snmpSocketBaseDomain.h>
63
#include <net-snmp/library/tools.h>
64
#include <net-snmp/library/snmp_assert.h>
65
66
#ifndef NETSNMP_NO_SYSTEMD
67
#include <net-snmp/library/sd-daemon.h>
68
#endif
69
70
#include "inet_ntop.h"
71
#include "inet_pton.h"
72
73
const oid netsnmp_UDPIPv6Domain[] = { TRANSPORT_DOMAIN_UDP_IPV6 };
74
static netsnmp_tdomain udp6Domain;
75
76
/*
77
 * needs to be in sync with the definitions in snmplib/snmpTCPDomain.c
78
 * and perl/agent/agent.xs
79
 */
80
typedef netsnmp_indexed_addr_pair netsnmp_udp_addr_pair;
81
82
/*
83
 * Return a string representing the address in data, or else the "far end"
84
 * address if data is NULL.  
85
 */
86
87
static char *
88
netsnmp_udp6_fmtaddr(netsnmp_transport *t, const void *data, int len)
89
0
{
90
0
    return netsnmp_ipv6_fmtaddr("UDP/IPv6", t, data, len);
91
0
}
92
93
#if defined(HAVE_IPV6_RECVPKTINFO) && !defined(WIN32)
94
95
#define netsnmp_udp6_recvfrom_sendto_defined
96
97
enum {
98
    cmsg_data_size = sizeof(struct in6_pktinfo)
99
};
100
101
int
102
netsnmp_udp6_recvfrom(int s, void *buf, int len, struct sockaddr *from,
103
                      socklen_t *fromlen, struct sockaddr *dstip,
104
                      socklen_t *dstlen, int *if_index)
105
0
{
106
0
    int r;
107
0
    struct iovec iov;
108
0
    char cmsg[CMSG_SPACE(cmsg_data_size)];
109
0
    struct cmsghdr *cm;
110
0
    struct msghdr msg;
111
112
0
    iov.iov_base = buf;
113
0
    iov.iov_len = len;
114
115
0
    memset(&msg, 0, sizeof msg);
116
0
    msg.msg_name = from;
117
0
    msg.msg_namelen = *fromlen;
118
0
    msg.msg_iov = &iov;
119
0
    msg.msg_iovlen = 1;
120
0
    msg.msg_control = &cmsg;
121
0
    msg.msg_controllen = sizeof(cmsg);
122
123
0
    r = recvmsg(s, &msg, MSG_DONTWAIT);
124
125
0
    if (r == -1) {
126
0
        return -1;
127
0
    }
128
129
0
    {
130
0
        char buf[INET6_ADDRSTRLEN];
131
0
        DEBUGMSGTL(("udp6:recv", "got source addr: %s\n", inet_ntop(AF_INET6,
132
0
                    &(((struct sockaddr_in6 *)from)->sin6_addr), buf,
133
0
                    sizeof(struct sockaddr_in6))));
134
0
    }
135
136
0
    {
137
        /* Get the local port number for use in diagnostic messages */
138
0
        int r2 = getsockname(s, dstip, dstlen);
139
0
        netsnmp_assert(r2 == 0);
140
0
    }
141
142
0
    for (cm = CMSG_FIRSTHDR(&msg); cm != NULL; cm = CMSG_NXTHDR(&msg, cm)) {
143
0
        if (cm->cmsg_level == IPPROTO_IPV6 && cm->cmsg_type == IPV6_PKTINFO) {
144
0
            struct in6_pktinfo* src = (struct in6_pktinfo *)CMSG_DATA(cm);
145
146
0
            netsnmp_assert(dstip->sa_family == AF_INET6);
147
0
            ((struct sockaddr_in6*)dstip)->sin6_addr = src->ipi6_addr;
148
0
            *if_index = src->ipi6_ifindex;
149
150
0
            {
151
0
                char buf[INET6_ADDRSTRLEN];
152
0
                DEBUGMSGTL(("udp6:recv",
153
0
                            "got destination (local) addr %s, iface %d\n",
154
0
                            inet_ntop(AF_INET6,
155
0
                            &(((struct sockaddr_in6 *)dstip)->sin6_addr), buf,
156
0
                            sizeof(struct sockaddr_in6)), *if_index));
157
0
            }
158
0
        }
159
0
    }
160
161
0
    return r;
162
0
}
163
164
int netsnmp_udp6_sendto(int fd, const struct in6_addr *srcip, int if_index,
165
                        const struct sockaddr *remote, const void *data,
166
                        int len)
167
0
{
168
0
    struct iovec iov;
169
0
    struct msghdr m = { NULL };
170
0
    char          cmsg[CMSG_SPACE(cmsg_data_size)];
171
0
    int           rc;
172
0
#ifdef HAVE_SO_BINDTODEVICE
173
0
    char          iface[IFNAMSIZ];
174
0
    socklen_t     ifacelen = IFNAMSIZ;
175
0
#endif
176
177
0
    iov.iov_base = NETSNMP_REMOVE_CONST(void *, data);
178
0
    iov.iov_len  = len;
179
180
0
    m.msg_name      = NETSNMP_REMOVE_CONST(void *, remote);
181
0
    m.msg_namelen   = sizeof(struct sockaddr_in6);
182
0
    m.msg_iov       = &iov;
183
0
    m.msg_iovlen    = 1;
184
0
    m.msg_flags     = 0;
185
186
0
    if (srcip && memcmp(&srcip->s6_addr, &in6addr_any, sizeof(struct in6_addr)) != 0) {
187
0
        struct cmsghdr *cm;
188
0
        struct in6_pktinfo ipi;
189
0
        int use_sendto = FALSE;
190
191
0
        memset(cmsg, 0, sizeof(cmsg));
192
193
0
        m.msg_control    = &cmsg;
194
0
        m.msg_controllen = sizeof(cmsg);
195
196
0
        cm = CMSG_FIRSTHDR(&m);
197
0
        cm->cmsg_len = CMSG_LEN(cmsg_data_size);
198
199
0
        cm->cmsg_level = IPPROTO_IPV6;
200
0
        cm->cmsg_type = IPV6_PKTINFO;
201
202
0
        memset(&ipi, 0, sizeof(ipi));
203
204
0
#ifdef HAVE_SO_BINDTODEVICE
205
        /*
206
         * For asymmetric multihomed users, we only set ifindex to 0 to
207
         * let kernel handle return if there was no iface bound to the
208
         * socket.
209
         */
210
0
        if (getsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, iface,
211
0
                       &ifacelen) != 0)  {
212
0
            DEBUGMSGTL(("udp6:sendto",
213
0
                        "getsockopt SO_BINDTODEVICE failed: %s\n",
214
0
                        strerror(errno)));
215
0
        } else if (ifacelen == 0) {
216
0
            DEBUGMSGTL(("udp6:sendto",
217
0
                        "sendto: SO_BINDTODEVICE not set\n"));
218
0
        } else {
219
0
            DEBUGMSGTL(("udp6:sendto",
220
0
                        "sendto: SO_BINDTODEVICE dev=%s using ifindex=%d\n",
221
0
                        iface, if_index));
222
0
            use_sendto = TRUE;
223
0
        }
224
0
#endif /* HAVE_SO_BINDTODEVICE */
225
226
0
        ipi.ipi6_addr = *srcip;
227
0
        memcpy(CMSG_DATA(cm), &ipi, sizeof(ipi));
228
229
0
        {
230
0
            char buf[INET6_ADDRSTRLEN];
231
0
            DEBUGMSGTL(("udp6:sendto", "sending from %s\n",
232
0
                        inet_ntop(AF_INET6, srcip, buf, INET6_ADDRSTRLEN)));
233
0
        }
234
235
        /*
236
         * For Linux and VRF, use sendto() instead of sendmsg(). Do not pass a
237
         * cmsg with IP_PKTINFO set because that would override the bind to
238
         * VRF which is set by 'vrf exec' command. That would break VRF.
239
         */
240
0
        if (use_sendto) {
241
0
            rc = sendto(fd, data, len, MSG_DONTWAIT, remote,
242
0
                        sizeof(struct sockaddr));
243
0
        } else {
244
0
            rc = sendmsg(fd, &m, MSG_DONTWAIT);
245
0
        }
246
0
        if (rc >= 0 || errno != EINVAL)
247
0
            return rc;
248
249
        /*
250
         * The error might be caused by broadcast srcip (i.e. we're responding
251
         * to a broadcast request) - sendmsg does not like it. Try to resend it
252
         * using the interface on which it was received
253
         */
254
255
0
        DEBUGMSGTL(("udp6:sendto", "re-sending on iface %d\n", if_index));
256
257
0
        {
258
0
            struct in6_pktinfo ipi;
259
0
            memset(&ipi, 0, sizeof(ipi));
260
0
            ipi.ipi6_addr = in6addr_any;
261
0
            ipi.ipi6_ifindex = if_index;
262
0
            memcpy(CMSG_DATA(cm), &ipi, sizeof(ipi));
263
0
        }
264
265
0
        rc = sendmsg(fd, &m, MSG_DONTWAIT);
266
0
        if (rc >= 0 || errno != EINVAL)
267
0
            return rc;
268
269
0
        DEBUGMSGTL(("udp6:sendto", "re-sending without source address\n"));
270
0
        m.msg_control = NULL;
271
0
        m.msg_controllen = 0;
272
0
    }
273
274
0
    return sendmsg(fd, &m, MSG_DONTWAIT);
275
0
}
276
277
#endif /* HAVE_IPV6_RECVPKTINFO || !WIN32 */
278
279
/*
280
 * You can write something into opaque that will subsequently get passed back 
281
 * to your send function if you like.  For instance, you might want to
282
 * remember where a PDU came from, so that you can send a reply there...  
283
 */
284
285
static int
286
netsnmp_udp6_recv(netsnmp_transport *t, void *buf, int size,
287
      void **opaque, int *olength)
288
0
{
289
0
    int             rc = -1;
290
0
    socklen_t       fromlen = sizeof(struct sockaddr_in6);
291
0
    netsnmp_indexed_addr_pair *addr_pair = NULL;
292
0
    struct sockaddr *from;
293
294
0
    if (t != NULL && t->sock >= 0) {
295
0
        addr_pair = SNMP_MALLOC_TYPEDEF(netsnmp_indexed_addr_pair);
296
0
        if (addr_pair == NULL) {
297
0
            *opaque = NULL;
298
0
            *olength = 0;
299
0
            return -1;
300
0
        } else {
301
0
            from = &addr_pair->remote_addr.sa;
302
0
        }
303
304
0
        while (rc < 0) {
305
0
#ifdef netsnmp_udp6_recvfrom_sendto_defined
306
0
            socklen_t local_addr_len = sizeof(addr_pair->local_addr);
307
0
            rc = netsnmp_udp6_recvfrom(t->sock, buf, size, from, &fromlen,
308
0
                                      &addr_pair->local_addr.sa,
309
0
                                      &local_addr_len, &(addr_pair->if_index));
310
#else
311
            rc = recvfrom(t->sock, buf, size, 0, from, &fromlen);
312
#endif /* netsnmp_udp6_recvfrom_sendto_defined */
313
0
            if (rc < 0 && errno != EINTR) {
314
0
                break;
315
0
            }
316
0
        }
317
318
0
        if (rc >= 0) {
319
0
            DEBUGIF("netsnmp_udp6") {
320
0
                char *str = netsnmp_udp6_fmtaddr(NULL, from, fromlen);
321
0
                DEBUGMSGTL(("netsnmp_udp6",
322
0
                            "recvfrom fd %d got %d bytes (from %s)\n", t->sock,
323
0
                            rc, str));
324
0
                free(str);
325
0
            }
326
0
        } else {
327
0
            DEBUGMSGTL(("netsnmp_udp6", "recvfrom fd %d err %d (\"%s\")\n",
328
0
      t->sock, errno, strerror(errno)));
329
0
        }
330
0
        *opaque = (void *) addr_pair;
331
0
        *olength = sizeof(netsnmp_indexed_addr_pair);
332
0
    }
333
0
    return rc;
334
0
}
335
336
337
338
static int
339
netsnmp_udp6_send(netsnmp_transport *t, const void *buf, int size,
340
      void **opaque, int *olength)
341
0
{
342
0
    int rc = -1;
343
0
    const netsnmp_indexed_addr_pair *addr_pair = NULL;
344
0
    const struct sockaddr *to = NULL;
345
346
0
    if (opaque != NULL && *opaque != NULL && NULL != olength &&
347
0
        (*olength == sizeof(netsnmp_indexed_addr_pair) ||
348
0
         *olength == sizeof(struct sockaddr_in6))) {
349
0
        addr_pair = (const netsnmp_indexed_addr_pair *) (*opaque);
350
0
    } else if (t != NULL && t->data != NULL &&
351
0
                t->data_length == sizeof(netsnmp_indexed_addr_pair)) {
352
0
        addr_pair = (netsnmp_indexed_addr_pair *) (t->data);
353
0
    } else {
354
0
        int len = -1;
355
0
        if (opaque != NULL && *opaque != NULL && NULL != olength)
356
0
            len = *olength;
357
0
        else if (t != NULL && t->data != NULL)
358
0
            len = t->data_length;
359
0
        snmp_log(LOG_ERR, "unknown addr type of size %d\n", len);
360
0
        return SNMPERR_GENERR;
361
0
    }
362
363
0
    to = &addr_pair->remote_addr.sa;
364
365
0
    if (to != NULL && t != NULL && t->sock >= 0) {
366
0
        DEBUGIF("netsnmp_udp6") {
367
0
            char *str = netsnmp_udp6_fmtaddr(NULL, addr_pair,
368
0
                                             sizeof(netsnmp_indexed_addr_pair));
369
0
            DEBUGMSGTL(("netsnmp_udp6",
370
0
                        "send %d bytes from %p to %s on fd %d\n",
371
0
                        size, buf, str, t->sock));
372
0
            free(str);
373
0
        }
374
375
0
        while (rc < 0) {
376
0
#ifdef netsnmp_udp6_recvfrom_sendto_defined
377
0
            rc = netsnmp_udp6_sendto(t->sock,
378
0
                    addr_pair ? &(addr_pair->local_addr.sin6.sin6_addr) : NULL,
379
0
                    addr_pair ? addr_pair->if_index : 0, to, buf, size);
380
#else
381
            rc = sendto(t->sock, buf, size, 0, to, sizeof(struct sockaddr_in6));
382
#endif /* netsnmp_udp6_recvfrom_sendto_defined */
383
0
            if (rc < 0 && errno != EINTR) {
384
0
                DEBUGMSGTL(("netsnmp_udp6", "sendto error, rc %d (errno %d)\n",
385
0
                            rc, errno));
386
0
                break;
387
0
            }
388
0
        }
389
0
    }
390
0
    return rc;
391
0
}
392
393
394
/*
395
 * Initialize a UDP/IPv6-based transport for SNMP.  Local is TRUE if addr is the
396
 * local address to bind to (i.e. this is a server-type session); otherwise
397
 * addr is the remote address to send things to.  
398
 */
399
400
netsnmp_transport *
401
netsnmp_udp6_transport_init(const struct netsnmp_ep *ep, int flags)
402
0
{
403
0
    const struct sockaddr_in6 *addr = &ep->a.sin6;
404
0
    netsnmp_transport *t = NULL;
405
0
    int             local = flags & NETSNMP_TSPEC_LOCAL;
406
0
    u_char         *addr_ptr;
407
408
#ifdef NETSNMP_NO_LISTEN_SUPPORT
409
    if (local)
410
        return NULL;
411
#endif /* NETSNMP_NO_LISTEN_SUPPORT */
412
413
0
    if (addr == NULL || addr->sin6_family != AF_INET6) {
414
0
        return NULL;
415
0
    }
416
417
0
    t = SNMP_MALLOC_TYPEDEF(netsnmp_transport);
418
0
    if (t == NULL) {
419
0
        return NULL;
420
0
    }
421
422
0
    t->sock = -1;
423
424
0
    addr_ptr = netsnmp_memdup(addr, sizeof(*addr));
425
0
    if (addr_ptr == NULL) {
426
0
        free(t);
427
0
        return NULL;
428
0
    }
429
0
    if (local) {
430
        /** This is a server session. */
431
0
        t->local_length = sizeof(*addr);
432
0
        t->local = addr_ptr;
433
0
    } else {
434
        /** This is a client session. */
435
0
        t->remote = addr_ptr;
436
0
        t->remote_length = sizeof(*addr);
437
0
    }
438
439
0
    DEBUGIF("netsnmp_udp6") {
440
0
        char *str = netsnmp_udp6_fmtaddr(NULL, addr, sizeof(*addr));
441
0
        DEBUGMSGTL(("netsnmp_udp6", "open %s %s\n", local ? "local" : "remote",
442
0
                    str));
443
0
        free(str);
444
0
    }
445
446
0
    if (!local) {
447
0
        netsnmp_indexed_addr_pair *addr_pair;
448
449
        /*
450
         * allocate space to save the (remote) address in the
451
         * transport-specific data pointer for later use by netsnmp_udp_send.
452
         */
453
0
        t->data = calloc(1, sizeof(netsnmp_indexed_addr_pair));
454
0
        if (NULL == t->data) {
455
0
            netsnmp_transport_free(t);
456
0
            return NULL;
457
0
        }
458
0
        t->data_length = sizeof(netsnmp_indexed_addr_pair);
459
460
0
        addr_pair = (netsnmp_indexed_addr_pair *)t->data;
461
0
        memcpy(&addr_pair->remote_addr, addr, sizeof(*addr));
462
0
    }
463
464
    /*
465
     * 16-bit length field, 8 byte UDP header, 40 byte IPv6 header.
466
     */
467
468
0
    t->msgMaxSize = 0xffff - 8 - 40;
469
0
    t->f_recv     = netsnmp_udp6_recv;
470
0
    t->f_send     = netsnmp_udp6_send;
471
0
    t->f_close    = netsnmp_socketbase_close;
472
0
    t->f_accept   = NULL;
473
0
    t->f_setup_session = netsnmp_ipbase_session_init;
474
0
    t->f_fmtaddr  = netsnmp_udp6_fmtaddr;
475
0
    t->f_get_taddr = netsnmp_ipv6_get_taddr;
476
477
0
    t->domain = netsnmp_UDPIPv6Domain;
478
0
    t->domain_length =
479
0
        sizeof(netsnmp_UDPIPv6Domain) / sizeof(netsnmp_UDPIPv6Domain[0]);
480
481
0
    return t;
482
0
}
483
484
static void set_ipv6_v6only_sockopt(int sd)
485
0
{
486
0
#ifdef IPV6_V6ONLY
487
    /* Try to restrict PF_INET6 socket to IPv6 communications only. */
488
0
    int optval = 1;
489
490
0
    if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&optval,
491
0
                   sizeof(optval)) != 0) {
492
0
        DEBUGMSGTL(("netsnmp_udp6", "couldn't set IPV6_V6ONLY: %s\n",
493
0
                    strerror(errno)));
494
0
    }
495
0
#endif
496
0
}
497
498
static void set_ipv6_recvpktinfo_sockopt(int sd)
499
0
{
500
0
#if defined(HAVE_IPV6_RECVPKTINFO) && !defined(WIN32)
501
0
    int sockopt = 1;
502
503
0
    if (setsockopt(sd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &sockopt,
504
0
                   sizeof(sockopt)) == -1) {
505
0
        DEBUGMSGTL(("netsnmp_udp6", "couldn't set IPV6_RECVPKTINFO: %s\n",
506
0
                    strerror(errno)));
507
0
    } else {
508
0
        DEBUGMSGTL(("netsnmp_udp6", "set IPV6_RECVPKTINFO\n"));
509
0
    }
510
0
#endif
511
0
}
512
513
int
514
netsnmp_udp6_transport_bind(netsnmp_transport *t,
515
                            const struct netsnmp_ep *ep,
516
                            int flags)
517
0
{
518
0
    const struct sockaddr_in6 *addr = &ep->a.sin6;
519
0
    int             local = flags & NETSNMP_TSPEC_LOCAL;
520
0
    int             rc = 0;
521
522
0
    if (local) {
523
0
#ifndef NETSNMP_NO_LISTEN_SUPPORT
524
        /*
525
         * This session is intended as a server, so we must bind on to the
526
         * given IP address, which may include an interface address, or could
527
         * be INADDR_ANY, but certainly includes a port number.
528
         */
529
530
0
        set_ipv6_v6only_sockopt(t->sock);
531
0
        set_ipv6_recvpktinfo_sockopt(t->sock);
532
#else /* NETSNMP_NO_LISTEN_SUPPORT */
533
        return -1;
534
#endif /* NETSNMP_NO_LISTEN_SUPPORT */
535
0
    }
536
537
0
    DEBUGIF("netsnmp_udp6") {
538
0
        char *str;
539
0
        str = netsnmp_udp6_fmtaddr(NULL, addr, sizeof(*addr));
540
0
        DEBUGMSGTL(("netsnmp_udp6", "binding socket: %d to %s\n",
541
0
                    t->sock, str));
542
0
        free(str);
543
0
    }
544
0
    if (flags & NETSNMP_TSPEC_PREBOUND) {
545
0
        DEBUGMSGTL(("netsnmp_udp6", "socket %d is prebound, nothing to do\n",
546
0
                    t->sock));
547
0
        return 0;
548
0
    }
549
0
    rc = netsnmp_bindtodevice(t->sock, ep->iface);
550
0
    if (rc != 0) {
551
0
        DEBUGMSGTL(("netsnmp_udp6", "failed to bind to iface %s: %s\n",
552
0
                    ep->iface, strerror(errno)));
553
0
        goto err;
554
0
    }
555
0
    rc = bind(t->sock, (const struct sockaddr *)addr, sizeof(*addr));
556
0
    if (rc != 0) {
557
0
        DEBUGMSGTL(("netsnmp_udp6", "failed to bind for clientaddr: %d %s\n",
558
0
                    errno, strerror(errno)));
559
0
        goto err;
560
0
    }
561
562
0
    return 0;
563
564
0
err:
565
0
    netsnmp_socketbase_close(t);
566
0
    return -1;
567
0
}
568
569
int
570
netsnmp_udp6_transport_socket(int flags)
571
0
{
572
0
    int local = flags & NETSNMP_TSPEC_LOCAL;
573
0
    int sock = socket(PF_INET6, SOCK_DGRAM, 0);
574
575
0
    DEBUGMSGTL(("UDPBase", "opened socket %d as local=%d\n", sock, local));
576
0
    if (sock < 0)
577
0
        return -1;
578
579
0
    _netsnmp_udp_sockopt_set(sock, local);
580
581
0
    return sock;
582
0
}
583
584
void
585
netsnmp_udp6_transport_get_bound_addr(netsnmp_transport *t)
586
0
{
587
0
    netsnmp_indexed_addr_pair *addr_pair;
588
0
    socklen_t                  local_addr_len = sizeof(addr_pair->local_addr);
589
0
    int                        rc;
590
591
    /** only for client transports: must have data and not local */
592
0
    if (NULL == t || NULL != t->local || NULL == t->data ||
593
0
        t->data_length < local_addr_len) {
594
0
        snmp_log(LOG_ERR, "bad parameters for get bound addr\n");
595
0
        return;
596
0
    }
597
598
0
    addr_pair = (netsnmp_indexed_addr_pair *)t->data;
599
600
    /** get local socket address for client session */
601
0
    local_addr_len = sizeof(addr_pair->local_addr);
602
0
    rc = getsockname(t->sock, (struct sockaddr*)&addr_pair->local_addr,
603
0
                     &local_addr_len);
604
0
    netsnmp_assert(rc == 0);
605
0
    DEBUGIF("netsnmp_udpbase") {
606
0
        char *str = netsnmp_udp6_fmtaddr(NULL, (void *)&addr_pair->local_addr,
607
0
                                         sizeof(addr_pair->local_addr));
608
0
        DEBUGMSGTL(("netsnmp_udpbase", "socket %d bound to %s\n",
609
0
                    t->sock, str));
610
0
        free(str);
611
0
    }
612
0
}
613
614
netsnmp_transport *
615
netsnmp_udpipv6base_tspec_transport(netsnmp_tdomain_spec *tspec)
616
0
{
617
0
    struct netsnmp_ep ep;
618
0
    int local;
619
620
0
    if (NULL == tspec)
621
0
        return NULL;
622
623
0
    local = tspec->flags & NETSNMP_TSPEC_LOCAL;
624
625
    /** get address from target */
626
0
    if (!netsnmp_sockaddr_in6_3(&ep, tspec->target, tspec->default_target))
627
0
        return NULL;
628
629
0
    if (NULL != tspec->source) {
630
0
        struct netsnmp_ep src_addr;
631
632
        /** get sockaddr from source */
633
0
        if (!netsnmp_sockaddr_in6_3(&src_addr, tspec->source, ":0"))
634
0
            return NULL;
635
0
        return netsnmp_udp6_transport_with_source(&ep, local, &src_addr);
636
0
    }
637
638
    /** no source and default client address ok */
639
0
    return netsnmp_udp6_transport(&ep, local);
640
0
}
641
642
netsnmp_transport *
643
netsnmp_udp6_transport_with_source(const struct netsnmp_ep *ep,
644
              int local, const struct netsnmp_ep *src_addr)
645
0
{
646
0
    netsnmp_transport         *t = NULL;
647
0
    const struct netsnmp_ep   *bind_addr;
648
0
    int                        rc, flags = 0;
649
650
0
    t = netsnmp_udp6_transport_init(ep, local);
651
0
    if (NULL == t)
652
0
        return NULL;
653
654
0
    if (local) {
655
0
        bind_addr = ep;
656
0
        flags |= NETSNMP_TSPEC_LOCAL;
657
658
0
#ifndef NETSNMP_NO_SYSTEMD
659
        /*
660
         * Maybe the socket was already provided by systemd...
661
         */
662
0
        t->sock = netsnmp_sd_find_inet_socket(PF_INET6, SOCK_DGRAM, -1,
663
0
                                              ntohs(ep->a.sin6.sin6_port));
664
0
        if (t->sock >= 0)
665
0
            flags |= NETSNMP_TSPEC_PREBOUND;
666
0
#endif
667
0
    }
668
0
    else
669
0
        bind_addr = src_addr;
670
671
0
    if (-1 == t->sock)
672
0
        t->sock = netsnmp_udp6_transport_socket(flags);
673
0
    if (t->sock < 0) {
674
0
        netsnmp_transport_free(t);
675
0
        return NULL;
676
0
    }
677
678
    /*
679
     * If we've been given an address to bind to, then bind to it.
680
     * Otherwise the OS will use "something sensible".
681
     */
682
0
    if (NULL == bind_addr)
683
0
        return t;
684
685
0
    rc = netsnmp_udp6_transport_bind(t, bind_addr, flags);
686
0
    if (rc) {
687
0
        netsnmp_transport_free(t);
688
0
        t = NULL;
689
0
    }
690
0
    else if (!local)
691
0
        netsnmp_udp6_transport_get_bound_addr(t);
692
693
0
    return t;
694
0
}
695
696
/*
697
 * Open a UDP/IPv6-based transport for SNMP.  Local is TRUE if addr is the
698
 * local address to bind to (i.e. this is a server-type session); otherwise
699
 * addr is the remote address to send things to.
700
 */
701
702
netsnmp_transport *
703
netsnmp_udp6_transport(const struct netsnmp_ep *ep, int local)
704
0
{
705
0
    struct netsnmp_ep client_ep;
706
0
    const char *client_addr;
707
708
0
    memset(&client_ep, 0, sizeof(client_ep));
709
0
    client_ep.a.sin6.sin6_family = AF_INET6;
710
711
0
    if (local)
712
0
        goto out;
713
714
0
    client_addr = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
715
0
                                        NETSNMP_DS_LIB_CLIENT_ADDR);
716
0
    if (!client_addr)
717
0
        goto out;
718
719
0
    if (netsnmp_sockaddr_in6_3(&client_ep, client_addr, ":0") < 0)
720
0
        snmp_log(LOG_ERR, "Parsing clientaddr %s failed\n", client_addr);
721
722
0
out:
723
0
    return netsnmp_udp6_transport_with_source(ep, local, &client_ep);
724
0
}
725
726
727
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
728
/*
729
 * The following functions provide the "com2sec6" configuration token
730
 * functionality for compatibility.
731
 */
732
733
1.08k
#define EXAMPLE_NETWORK       "NETWORK"
734
636
#define EXAMPLE_COMMUNITY     "COMMUNITY"
735
736
typedef struct com2Sec6Entry_s {
737
    const char     *secName;
738
    const char     *contextName;
739
    struct com2Sec6Entry_s *next;
740
    struct in6_addr network;
741
    struct in6_addr mask;
742
    int             negate;
743
    const char      community[1];
744
} com2Sec6Entry;
745
746
static com2Sec6Entry  *com2Sec6List = NULL, *com2Sec6ListLast = NULL;
747
748
749
NETSNMP_STATIC_INLINE int
750
create_com2Sec6Entry(const struct addrinfo* const run,
751
                     const struct in6_addr* const mask,
752
                     const char* const secName,
753
                     const size_t secNameLen,
754
                     const char* const contextName,
755
                     const size_t contextNameLen,
756
                     const char* const community,
757
                     const size_t communityLen,
758
                     int negate,
759
                     com2Sec6Entry** const begin,
760
                     com2Sec6Entry** const end)
761
28
{
762
28
    const struct sockaddr_in6 * const run_addr =
763
28
        (const struct sockaddr_in6*)run->ai_addr;
764
28
    int i;
765
766
    /* Check that the network and mask are consistent. */
767
312
    for (i = 0; i < 16; ++i) {
768
301
        if (run_addr->sin6_addr.s6_addr[i] & ~mask->s6_addr[i]) {
769
17
            config_perror("source/mask mismatch");
770
17
            return 1;
771
17
        }
772
301
    }
773
774
11
    {
775
11
        char buf1[INET6_ADDRSTRLEN];
776
11
        char buf2[INET6_ADDRSTRLEN];
777
11
        DEBUGMSGTL(("netsnmp_udp6_parse_security",
778
11
                    "<\"%s\", %s/%s> => \"%s\"\n",
779
11
                    community,
780
11
                    inet_ntop(AF_INET6, &run_addr->sin6_addr,
781
11
                              buf1, sizeof(buf1)),
782
11
                    inet_ntop(AF_INET6, mask, buf2, sizeof(buf2)),
783
11
                    secName));
784
11
    }
785
786
11
    {
787
        /* Allocate all the needed chunks */
788
11
        void * const v =
789
11
            malloc(offsetof(com2Sec6Entry, community) + communityLen +
790
11
                   secNameLen + contextNameLen);
791
792
11
        com2Sec6Entry* const e = (com2Sec6Entry*)v;
793
11
        char *last = ((char*)v) + offsetof(com2Sec6Entry, community);
794
795
11
        if (v == NULL) {
796
0
            config_perror("memory error");
797
0
            return 1;
798
0
        }
799
800
11
        memcpy(last, community, communityLen);
801
11
        last += communityLen;
802
803
11
        memcpy(last, secName, secNameLen);
804
11
        e->secName = last;
805
11
        last += secNameLen;
806
807
11
        if (contextNameLen) {
808
6
            memcpy(last, contextName, contextNameLen);
809
6
            e->contextName = last;
810
6
        } else
811
5
            e->contextName = last - 1;
812
813
11
        memcpy(&e->network, &run_addr->sin6_addr, sizeof(struct in6_addr));
814
11
        memcpy(&e->mask, mask, sizeof(struct in6_addr));
815
816
11
        e->negate = negate;
817
11
        e->next = NULL;
818
11
        if (*end != NULL) {
819
0
            (*end)->next = e;
820
0
            *end = e;
821
11
        } else {
822
11
            *end = *begin = e;
823
11
        }
824
11
    }
825
0
    return 0;
826
11
}
827
828
void
829
netsnmp_udp6_parse_security(const char *token, char *param)
830
747
{
831
    /** copy_nword does null term, so we need vars of max size + 2. */
832
    /** (one for null, one to detect param too long */
833
747
    char            secName[VACMSTRINGLEN]; /* == VACM_MAX_STRING + 2 */
834
747
    size_t          secNameLen;
835
747
    char            contextName[VACMSTRINGLEN];
836
747
    size_t          contextNameLen;
837
747
    char            community[COMMUNITY_MAX_LEN + 2];/* overflow + null char */
838
747
    size_t          communityLen;
839
747
    char            source[301]; /* !(1)+dns-name(253)+/(1)+mask(45)+\0(1) */
840
747
    char            *sourcep;
841
747
    struct in6_addr mask;
842
747
    int             negate;
843
844
    /*
845
     * Get security, source address/netmask and community strings.
846
     */
847
848
747
    param = copy_nword( param, secName, sizeof(secName));
849
747
    if (strcmp(secName, "-Cn") == 0) {
850
22
        if (!param) {
851
2
            config_perror("missing CONTEXT_NAME parameter");
852
2
            return;
853
2
        }
854
20
        param = copy_nword( param, contextName, sizeof(contextName));
855
20
        contextNameLen = strlen(contextName);
856
20
        if (contextNameLen > VACM_MAX_STRING) {
857
4
            config_perror("context name too long");
858
4
            return;
859
4
        }
860
16
        if (!param) {
861
3
            config_perror("missing NAME parameter");
862
3
            return;
863
3
        }
864
13
        ++contextNameLen; /* null termination */
865
13
        param = copy_nword( param, secName, sizeof(secName));
866
725
    } else {
867
725
        contextNameLen = 0;
868
725
    }
869
870
738
    secNameLen = strlen(secName);
871
738
    if (secNameLen == 0) {
872
55
        config_perror("empty NAME parameter");
873
55
        return;
874
683
    } else if (secNameLen > VACM_MAX_STRING) {
875
57
        config_perror("security name too long");
876
57
        return;
877
57
    }
878
626
    ++secNameLen; /* null termination */
879
880
626
    if (!param) {
881
76
        config_perror("missing SOURCE parameter");
882
76
        return;
883
76
    }
884
550
    param = copy_nword( param, source, sizeof(source));
885
550
    if (source[0] == '\0') {
886
7
        config_perror("empty SOURCE parameter");
887
7
        return;
888
7
    }
889
543
    if (strncmp(source, EXAMPLE_NETWORK, strlen(EXAMPLE_NETWORK)) == 0) {
890
7
        config_perror("example config NETWORK not properly configured");
891
7
        return;
892
7
    }
893
894
536
    if (!param) {
895
63
        config_perror("missing COMMUNITY parameter");
896
63
        return;
897
63
    }
898
473
    param = copy_nword( param, community, sizeof(community));
899
473
    if (community[0] == '\0') {
900
7
        config_perror("empty COMMUNITY parameter");
901
7
        return;
902
7
    }
903
466
    communityLen = strlen(community);
904
466
    if (communityLen > COMMUNITY_MAX_LEN) {
905
0
        config_perror("community name too long");
906
0
        return;
907
0
    }
908
466
    ++communityLen; /* null termination */
909
466
    if (communityLen == sizeof(EXAMPLE_COMMUNITY) &&
910
85
        memcmp(community, EXAMPLE_COMMUNITY, sizeof(EXAMPLE_COMMUNITY)) == 0) {
911
5
        config_perror("example config COMMUNITY not properly configured");
912
5
        return;
913
5
    }
914
915
    /* Possible mask cases
916
     * "default" <=> 0::0/0
917
     * <hostname>[/] <=> <hostname>/128
918
     * <hostname>/number <=> <hostname>/number
919
     * <hostname>/<mask> <=> <hostname>/<mask>
920
     */
921
461
    {
922
        /* Deal with the "default" case first. */
923
461
        const int isdefault = strcmp(source, "default") == 0;
924
925
461
        if (isdefault) {
926
11
            memset(mask.s6_addr, '\0', sizeof(mask.s6_addr));
927
11
            negate = 0;
928
11
            sourcep = NULL;    /* gcc gets confused about sourcep being used */
929
450
        } else {
930
450
            char *strmask;
931
450
            if (*source == '!') {
932
17
               negate = 1;
933
17
               sourcep = source + 1;
934
433
            } else {
935
433
               negate = 0;
936
433
               sourcep = source;
937
433
            }
938
939
            /* Split the source/netmask parts */
940
450
            strmask = strchr(sourcep, '/');
941
450
            if (strmask != NULL)
942
                /* Mask given. */
943
271
                *strmask++ = '\0';
944
945
            /* Try to interpret the mask */
946
450
            if (strmask == NULL || *strmask == '\0') {
947
                /* No mask was given. Assume /128 */
948
185
                memset(mask.s6_addr, 0xff, sizeof(mask.s6_addr));
949
265
            } else {
950
                /* Try to interpret mask as a "number of 1 bits". */
951
265
                char* cp;
952
265
                long masklength = strtol(strmask, &cp, 10);
953
265
                if (*cp == '\0') {
954
220
                    if (0 <= masklength && masklength <= 128) {
955
33
                        const int j = masklength / 8;
956
33
                        const int jj = masklength % 8;
957
958
33
                        memset(mask.s6_addr, 0xff, j);
959
33
                        if (j < 16) {
960
30
                            mask.s6_addr[j] = (0xffu << (8 - jj));
961
30
                            memset(mask.s6_addr + j + 1, '\0', 15 - j);
962
30
                        }
963
187
                    } else {
964
187
                        config_perror("bad mask length");
965
187
                        return;
966
187
                    }
967
220
                }
968
                /* Try to interpret mask numerically. */
969
45
                else if (inet_pton(AF_INET6, strmask, &mask) != 1) {
970
42
                    config_perror("bad mask");
971
42
                    return;
972
42
                }
973
265
            }
974
450
        }
975
976
232
        {
977
232
            struct sockaddr_in6 pton_addr;
978
232
            struct addrinfo hints, *res = NULL;
979
232
            memset(&hints, '\0', sizeof(hints));
980
981
            /* First check if default, otherwise try to parse as a numeric
982
             * address, if that also fails try to lookup the address */
983
232
            if (isdefault) {
984
11
                memset(&pton_addr.sin6_addr.s6_addr, '\0',
985
11
                       sizeof(struct in6_addr));
986
221
            } else if (inet_pton(AF_INET6, sourcep, &pton_addr.sin6_addr) != 1) {
987
                /* Nope, wasn't a numeric IPv6 address. Must be IPv4 or a hostname. */
988
989
                /* Try interpreting as dotted quad - IPv4 */
990
213
                struct in_addr network;
991
213
                if (inet_pton(AF_INET, sourcep, &network) > 0){
992
                    /* Yes, it's IPv4 - so it's already parsed and we can return. */
993
2
                    DEBUGMSGTL(("com2sec6", "IPv4 detected for IPv6 parser. Skipping.\n"));
994
2
                    return;
995
2
                }
996
211
#ifdef HAVE_GETADDRINFO
997
211
                {
998
211
                    int             gai_error;
999
1000
211
                    hints.ai_family = AF_INET6;
1001
211
                    hints.ai_socktype = SOCK_DGRAM;
1002
211
                    gai_error = netsnmp_getaddrinfo(sourcep, NULL, &hints,
1003
211
                                                    &res);
1004
211
                    if (gai_error != 0) {
1005
202
                        config_perror(gai_strerror(gai_error));
1006
202
                        return;
1007
202
                    }
1008
211
                }
1009
#else
1010
                config_perror("getaddrinfo() not available");
1011
                return;
1012
#endif
1013
211
            }
1014
28
            if (res == NULL) {
1015
19
                hints.ai_addrlen = sizeof(pton_addr);
1016
19
                hints.ai_addr = (struct sockaddr*)&pton_addr;
1017
19
                hints.ai_next = NULL;
1018
19
                res = &hints;
1019
19
            }
1020
1021
28
            {
1022
28
                struct addrinfo *run;
1023
28
                int    failed = 0;
1024
28
                com2Sec6Entry *begin = NULL, *end = NULL;
1025
1026
56
                for (run = res; run && !failed; run = run->ai_next)
1027
28
                    failed =
1028
28
                        create_com2Sec6Entry(run, &mask,
1029
28
                                             secName, secNameLen,
1030
28
                                             contextName, contextNameLen,
1031
28
                                             community, communityLen, negate,
1032
28
                                             &begin, &end);
1033
1034
28
                if (failed) {
1035
                    /* Free eventually allocated chunks */
1036
17
                    while (begin) {
1037
0
                        end = begin;
1038
0
                        begin = begin->next;
1039
0
                        free(end);
1040
0
                    }
1041
17
                } else if (com2Sec6ListLast != NULL) {
1042
10
                    com2Sec6ListLast->next = begin;
1043
10
                    com2Sec6ListLast = end;
1044
10
                } else {
1045
1
                    com2Sec6List = begin;
1046
1
                    com2Sec6ListLast = end;
1047
1
                }
1048
28
            }
1049
28
#ifdef HAVE_GETADDRINFO
1050
28
            if (res != &hints)
1051
9
                freeaddrinfo(res);
1052
28
#endif
1053
28
        }
1054
28
    }
1055
28
}
1056
1057
void
1058
netsnmp_udp6_com2Sec6List_free(void)
1059
6.98k
{
1060
6.98k
    com2Sec6Entry  *e = com2Sec6List;
1061
6.98k
    while (e != NULL) {
1062
0
        com2Sec6Entry  *tmp = e;
1063
0
        e = e->next;
1064
0
        free(tmp);
1065
0
    }
1066
6.98k
    com2Sec6List = com2Sec6ListLast = NULL;
1067
6.98k
}
1068
1069
#endif /* support for community based SNMP */
1070
1071
void
1072
netsnmp_udp6_agent_config_tokens_register(void)
1073
3.49k
{
1074
3.49k
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1075
3.49k
    register_app_config_handler("com2sec6", netsnmp_udp6_parse_security,
1076
3.49k
                                netsnmp_udp6_com2Sec6List_free,
1077
3.49k
                                "[-Cn CONTEXT] secName IPv6-network-address[/netmask] community");
1078
3.49k
#endif /* support for community based SNMP */
1079
3.49k
}
1080
1081
1082
1083
#if !defined(NETSNMP_DISABLE_SNMPV1) || !defined(NETSNMP_DISABLE_SNMPV2C)
1084
1085
/*
1086
 * Return 0 if there are no com2sec entries, or return 1 if there ARE com2sec
1087
 * entries.  On return, if a com2sec entry matched the passed parameters,
1088
 * then *secName points at the appropriate security name, or is NULL if the
1089
 * parameters did not match any com2sec entry.
1090
 */
1091
1092
int
1093
netsnmp_udp6_getSecName(void *opaque, int olength,
1094
                        const char *community,
1095
                        int community_len,
1096
                        const char **secName, const char **contextName)
1097
0
{
1098
0
    const com2Sec6Entry *c;
1099
0
    netsnmp_udp_addr_pair *addr_pair = (netsnmp_udp_addr_pair *) opaque;
1100
0
    struct sockaddr_in6 *from = (struct sockaddr_in6 *) &(addr_pair->remote_addr);
1101
0
    char           *ztcommunity = NULL;
1102
0
    char            str6[INET6_ADDRSTRLEN];
1103
1104
0
    if (secName != NULL) {
1105
0
        *secName = NULL;  /* Haven't found anything yet */
1106
0
    }
1107
1108
    /*
1109
     * Special case if there are NO entries (as opposed to no MATCHING
1110
     * entries).
1111
     */
1112
1113
0
    if (com2Sec6List == NULL) {
1114
0
        DEBUGMSGTL(("netsnmp_udp6_getSecName", "no com2sec entries\n"));
1115
0
        return 0;
1116
0
    }
1117
1118
    /*
1119
     * If there is no IPv6 source address, then there can be no valid security
1120
     * name.
1121
     */
1122
1123
0
    DEBUGMSGTL(("netsnmp_udp_getSecName", "opaque = %p (len = %d), sizeof = %d, family = %d (%d)\n",
1124
0
                opaque, olength, (int)sizeof(netsnmp_udp_addr_pair),
1125
0
                from->sin6_family, AF_INET6));
1126
0
    if (opaque == NULL || olength != sizeof(netsnmp_udp_addr_pair) ||
1127
0
        from->sin6_family != PF_INET6) {
1128
0
        DEBUGMSGTL(("netsnmp_udp6_getSecName",
1129
0
                    "no IPv6 source address in PDU?\n"));
1130
0
        return 1;
1131
0
    }
1132
1133
0
    ztcommunity = (char *) malloc(community_len + 1);
1134
0
    if (ztcommunity != NULL) {
1135
0
        memcpy(ztcommunity, community, community_len);
1136
0
        ztcommunity[community_len] = '\0';
1137
0
    }
1138
1139
0
    inet_ntop(AF_INET6, &from->sin6_addr, str6, sizeof(str6));
1140
0
    DEBUGMSGTL(("netsnmp_udp6_getSecName", "resolve <\"%s\", %s>\n",
1141
0
                ztcommunity ? ztcommunity : "<malloc error>", str6));
1142
1143
0
    for (c = com2Sec6List; c != NULL; c = c->next) {
1144
0
        {
1145
0
            char buf1[INET6_ADDRSTRLEN];
1146
0
            char buf2[INET6_ADDRSTRLEN];
1147
0
            DEBUGMSGTL(("netsnmp_udp6_getSecName",
1148
0
                        "compare <\"%s\", %s/%s>", c->community,
1149
0
                        inet_ntop(AF_INET6, &c->network, buf1, sizeof(buf1)),
1150
0
                        inet_ntop(AF_INET6, &c->mask, buf2, sizeof(buf2))));
1151
0
        }
1152
0
        if ((community_len == (int)strlen(c->community)) &&
1153
0
            (memcmp(community, c->community, community_len) == 0)) {
1154
0
            int i, ok = 1;
1155
0
            for (i = 0; ok && i < 16; ++i)
1156
0
                if ((from->sin6_addr.s6_addr[i] & c->mask.s6_addr[i]) !=
1157
0
                    c->network.s6_addr[i])
1158
0
                    ok = 0;
1159
0
            if (ok) {
1160
0
                DEBUGMSG(("netsnmp_udp6_getSecName", "... SUCCESS\n"));
1161
0
                if (c->negate) {
1162
                   /*
1163
                    * If we matched a negative entry, then we are done - claim that we
1164
                    * matched nothing.
1165
                    */
1166
0
                   DEBUGMSG(("netsnmp_udp6_getSecName", "... <negative entry>\n"));
1167
0
                   break;
1168
0
                }
1169
0
                if (secName != NULL) {
1170
0
                    *secName = c->secName;
1171
0
                    *contextName = c->contextName;
1172
0
                }
1173
0
                break;
1174
0
            }
1175
0
        }
1176
0
        else {
1177
0
            DEBUGMSG(("netsnmp_udp6_getSecName", "... nope\n"));
1178
0
        }
1179
0
    }
1180
1181
0
    if (ztcommunity != NULL) {
1182
0
        free(ztcommunity);
1183
0
    }
1184
0
    return 1;
1185
0
}
1186
#endif /* support for community based SNMP */
1187
1188
netsnmp_transport *
1189
netsnmp_udp6_create_tstring(const char *str, int local,
1190
          const char *default_target)
1191
0
{
1192
0
    struct netsnmp_ep ep;
1193
1194
0
    if (netsnmp_sockaddr_in6_3(&ep, str, default_target)) {
1195
0
        return netsnmp_udp6_transport(&ep, local);
1196
0
    } else {
1197
0
        return NULL;
1198
0
    }
1199
0
}
1200
1201
netsnmp_transport *
1202
netsnmp_udp6_create_tspec(netsnmp_tdomain_spec *tspec)
1203
0
{
1204
0
    netsnmp_transport *t = netsnmp_udpipv6base_tspec_transport(tspec);
1205
0
    return t;
1206
1207
0
}
1208
1209
1210
/*
1211
 * See:
1212
 * 
1213
 * http://www.ietf.org/internet-drafts/draft-ietf-ops-taddress-mib-01.txt
1214
 * 
1215
 * (or newer equivalent) for details of the TC which we are using for
1216
 * the mapping here.  
1217
 */
1218
1219
netsnmp_transport *
1220
netsnmp_udp6_create_ostring(const void *o, size_t o_len, int local)
1221
0
{
1222
0
    struct netsnmp_ep ep;
1223
1224
0
    memset(&ep, 0, sizeof(ep));
1225
0
    if (netsnmp_ipv6_ostring_to_sockaddr(&ep.a.sin6, o, o_len))
1226
0
        return netsnmp_udp6_transport(&ep, local);
1227
0
    return NULL;
1228
0
}
1229
1230
1231
void
1232
netsnmp_udpipv6_ctor(void)
1233
4.30k
{
1234
4.30k
    udp6Domain.name = netsnmp_UDPIPv6Domain;
1235
4.30k
    udp6Domain.name_length = OID_LENGTH(netsnmp_UDPIPv6Domain);
1236
4.30k
    udp6Domain.f_create_from_tstring_new = netsnmp_udp6_create_tstring;
1237
4.30k
    udp6Domain.f_create_from_tspec       = netsnmp_udp6_create_tspec;
1238
4.30k
    udp6Domain.f_create_from_ostring     = netsnmp_udp6_create_ostring;
1239
4.30k
    udp6Domain.prefix = calloc(5, sizeof(char *));
1240
4.30k
    if (!udp6Domain.prefix) {
1241
0
        snmp_log(LOG_ERR, "calloc() failed - out of memory\n");
1242
0
        return;
1243
0
    }
1244
4.30k
    udp6Domain.prefix[0] = "udp6";
1245
4.30k
    udp6Domain.prefix[1] = "ipv6";
1246
4.30k
    udp6Domain.prefix[2] = "udpv6";
1247
4.30k
    udp6Domain.prefix[3] = "udpipv6";
1248
1249
4.30k
    netsnmp_tdomain_register(&udp6Domain);
1250
4.30k
}
1251
1252
#else
1253
1254
#ifdef NETSNMP_DLL
1255
/* need this hook for win32 MSVC++ DLL build */
1256
void
1257
netsnmp_udp6_agent_config_tokens_register(void)
1258
{ }
1259
#endif
1260
1261
#endif /* NETSNMP_TRANSPORT_UDPIPV6_DOMAIN */
1262