~ubuntu-branches/ubuntu/gutsy/net-snmp/gutsy-security

« back to all changes in this revision

Viewing changes to snmplib/snmpUDPIPv6Domain.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2004-09-13 12:06:21 UTC
  • Revision ID: james.westby@ubuntu.com-20040913120621-g952ntonlleihcvm
Tags: upstream-5.1.1
ImportĀ upstreamĀ versionĀ 5.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include <net-snmp/net-snmp-config.h>
 
2
 
 
3
#include <stdio.h>
 
4
#include <sys/types.h>
 
5
#include <ctype.h>
 
6
#include <errno.h>
 
7
 
 
8
#if HAVE_STRING_H
 
9
#include <string.h>
 
10
#else
 
11
#include <strings.h>
 
12
#endif
 
13
#if HAVE_STDLIB_H
 
14
#include <stdlib.h>
 
15
#endif
 
16
#if HAVE_UNISTD_H
 
17
#include <unistd.h>
 
18
#endif
 
19
#if HAVE_SYS_SOCKET_H
 
20
#include <sys/socket.h>
 
21
#endif
 
22
 
 
23
#define HAVE_IF_NAMETOINDEX
 
24
#if HAVE_WINSOCK_H
 
25
    /*
 
26
     *  Windows IPv6 support is part of WinSock2 only
 
27
     */
 
28
#include <winsock2.h>
 
29
#include <ws2tcpip.h>
 
30
typedef unsigned char uint8_t;
 
31
#undef  HAVE_IF_NAMETOINDEX
 
32
 
 
33
extern int         inet_pton(int, const char*, void*);
 
34
extern const char *inet_ntop(int, const void*, char*, size_t);
 
35
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
 
36
#endif
 
37
 
 
38
#if HAVE_NETINET_IN_H
 
39
#include <netinet/in.h>
 
40
#endif
 
41
#if HAVE_ARPA_INET_H
 
42
#include <arpa/inet.h>
 
43
#endif
 
44
#if HAVE_NETDB_H
 
45
#include <netdb.h>
 
46
#endif
 
47
#if HAVE_NET_IF_H
 
48
#include <net/if.h>
 
49
#endif
 
50
 
 
51
#if HAVE_DMALLOC_H
 
52
#include <dmalloc.h>
 
53
#endif
 
54
 
 
55
#include <net-snmp/types.h>
 
56
#include <net-snmp/output_api.h>
 
57
#include <net-snmp/config_api.h>
 
58
 
 
59
#include <net-snmp/library/snmp_transport.h>
 
60
#include <net-snmp/library/snmpUDPIPv6Domain.h>
 
61
 
 
62
oid netsnmp_UDPIPv6Domain[10] = { ENTERPRISE_MIB, 3, 3, 4 };
 
63
static netsnmp_tdomain udp6Domain;
 
64
 
 
65
/*
 
66
 * Return a string representing the address in data, or else the "far end"
 
67
 * address if data is NULL.  
 
68
 */
 
69
 
 
70
static char *
 
71
netsnmp_udp6_fmtaddr(netsnmp_transport *t, void *data, int len)
 
72
{
 
73
    struct sockaddr_in6 *to = NULL;
 
74
 
 
75
    DEBUGMSGTL(("netsnmp_udp6", "fmtaddr: t = %p, data = %p, len = %d\n", t,
 
76
                data, len));
 
77
    if (data != NULL && len == sizeof(struct sockaddr_in6)) {
 
78
        to = (struct sockaddr_in6 *) data;
 
79
    } else if (t != NULL && t->data != NULL) {
 
80
        to = (struct sockaddr_in6 *) t->data;
 
81
    }
 
82
    if (to == NULL) {
 
83
        return strdup("UDP/IPv6: unknown");
 
84
    } else {
 
85
        char addr[INET6_ADDRSTRLEN];
 
86
        char tmp[INET6_ADDRSTRLEN + 8];
 
87
 
 
88
        sprintf(tmp, "[%s]:%hd",
 
89
                inet_ntop(AF_INET6, (void *) &(to->sin6_addr), addr,
 
90
                          INET6_ADDRSTRLEN), ntohs(to->sin6_port));
 
91
        return strdup(tmp);
 
92
    }
 
93
}
 
94
 
 
95
 
 
96
 
 
97
/*
 
98
 * You can write something into opaque that will subsequently get passed back 
 
99
 * to your send function if you like.  For instance, you might want to
 
100
 * remember where a PDU came from, so that you can send a reply there...  
 
101
 */
 
102
 
 
103
static int
 
104
netsnmp_udp6_recv(netsnmp_transport *t, void *buf, int size,
 
105
                  void **opaque, int *olength)
 
106
{
 
107
    int             rc = -1;
 
108
    socklen_t       fromlen = sizeof(struct sockaddr_in6);
 
109
    struct sockaddr *from;
 
110
 
 
111
    if (t != NULL && t->sock >= 0) {
 
112
        from = (struct sockaddr *) malloc(sizeof(struct sockaddr_in6));
 
113
        if (from == NULL) {
 
114
            *opaque = NULL;
 
115
            *olength = 0;
 
116
            return -1;
 
117
        } else {
 
118
            memset(from, 0, fromlen);
 
119
        }
 
120
 
 
121
        while (rc < 0) {
 
122
          rc = recvfrom(t->sock, buf, size, 0, from, &fromlen);
 
123
          if (rc < 0 && errno != EINTR) {
 
124
            break;
 
125
          }
 
126
        }
 
127
 
 
128
        if (rc >= 0) {
 
129
            char *string = netsnmp_udp6_fmtaddr(NULL, from, fromlen);
 
130
            DEBUGMSGTL(("netsnmp_udp6",
 
131
                        "recvfrom fd %d got %d bytes (from %s)\n", t->sock,
 
132
                        rc, string));
 
133
            free(string);
 
134
        } else {
 
135
            DEBUGMSGTL(("netsnmp_udp6", "recvfrom fd %d err %d (\"%s\")\n",
 
136
                        t->sock, errno, strerror(errno)));
 
137
        }
 
138
        *opaque = (void *) from;
 
139
        *olength = sizeof(struct sockaddr_in6);
 
140
    }
 
141
    return rc;
 
142
}
 
143
 
 
144
 
 
145
 
 
146
static int
 
147
netsnmp_udp6_send(netsnmp_transport *t, void *buf, int size,
 
148
                  void **opaque, int *olength)
 
149
{
 
150
    int rc = -1;
 
151
    struct sockaddr *to = NULL;
 
152
 
 
153
    if (opaque != NULL && *opaque != NULL &&
 
154
        *olength == sizeof(struct sockaddr_in6)) {
 
155
        to = (struct sockaddr *) (*opaque);
 
156
    } else if (t != NULL && t->data != NULL &&
 
157
               t->data_length == sizeof(struct sockaddr_in6)) {
 
158
        to = (struct sockaddr *) (t->data);
 
159
    }
 
160
 
 
161
    if (to != NULL && t != NULL && t->sock >= 0) {
 
162
        char *string = netsnmp_udp6_fmtaddr(NULL, (void *)to,
 
163
                                            sizeof(struct sockaddr_in6));
 
164
        DEBUGMSGTL(("netsnmp_udp6", "send %d bytes from %p to %s on fd %d\n",
 
165
                    size, buf, string, t->sock));
 
166
        free(string);
 
167
        while (rc < 0) {
 
168
            rc = sendto(t->sock, buf, size, 0, to,sizeof(struct sockaddr_in6));
 
169
            if (rc < 0 && errno != EINTR) {
 
170
                break;
 
171
            }
 
172
        }
 
173
    }
 
174
    return rc;
 
175
}
 
176
 
 
177
 
 
178
 
 
179
static int
 
180
netsnmp_udp6_close(netsnmp_transport *t)
 
181
{
 
182
    int rc = -1;
 
183
    if (t != NULL && t->sock >= 0) {
 
184
        DEBUGMSGTL(("netsnmp_udp6", "close fd %d\n", t->sock));
 
185
#ifndef HAVE_CLOSESOCKET
 
186
        rc = close(t->sock);
 
187
#else
 
188
        rc = closesocket(t->sock);
 
189
#endif
 
190
        t->sock = -1;
 
191
    }
 
192
    return rc;
 
193
}
 
194
 
 
195
 
 
196
 
 
197
/*
 
198
 * Open a UDP/IPv6-based transport for SNMP.  Local is TRUE if addr is the
 
199
 * local address to bind to (i.e. this is a server-type session); otherwise
 
200
 * addr is the remote address to send things to.  
 
201
 */
 
202
 
 
203
netsnmp_transport *
 
204
netsnmp_udp6_transport(struct sockaddr_in6 *addr, int local)
 
205
{
 
206
    netsnmp_transport *t = NULL;
 
207
    int             rc = 0, udpbuf = (1 << 17);
 
208
    char           *string = NULL;
 
209
 
 
210
    if (addr == NULL || addr->sin6_family != AF_INET6) {
 
211
        return NULL;
 
212
    }
 
213
 
 
214
    t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
 
215
    if (t == NULL) {
 
216
        return NULL;
 
217
    }
 
218
 
 
219
    string = netsnmp_udp6_fmtaddr(NULL, (void *) addr,
 
220
                                  sizeof(struct sockaddr_in6));
 
221
    DEBUGMSGTL(("netsnmp_udp6", "open %s %s\n", local ? "local" : "remote",
 
222
                string));
 
223
    free(string);
 
224
 
 
225
    memset(t, 0, sizeof(netsnmp_transport));
 
226
 
 
227
    t->domain = netsnmp_UDPIPv6Domain;
 
228
    t->domain_length =
 
229
        sizeof(netsnmp_UDPIPv6Domain) / sizeof(netsnmp_UDPIPv6Domain[0]);
 
230
 
 
231
    t->sock = socket(PF_INET6, SOCK_DGRAM, 0);
 
232
    if (t->sock < 0) {
 
233
        netsnmp_transport_free(t);
 
234
        return NULL;
 
235
    }
 
236
#ifdef  SO_BSDCOMPAT
 
237
    /*
 
238
     * Patch for Linux.  Without this, UDP packets that fail get an ICMP
 
239
     * response.  Linux turns the failed ICMP response into an error message
 
240
     * and return value, unlike all other OS's.  
 
241
     */
 
242
    {
 
243
        int             one = 1;
 
244
        setsockopt(t->sock, SOL_SOCKET, SO_BSDCOMPAT, &one, sizeof(one));
 
245
    }
 
246
#endif                          /*SO_BSDCOMPAT */
 
247
 
 
248
    /*
 
249
     * Try to set the send and receive buffers to a reasonably large value, so
 
250
     * that we can send and receive big PDUs (defaults to 8192 bytes (!) on
 
251
     * Solaris, for instance).  Don't worry too much about errors -- just
 
252
     * plough on regardless.  
 
253
     */
 
254
 
 
255
#ifdef  SO_SNDBUF
 
256
    if (setsockopt(t->sock, SOL_SOCKET, SO_SNDBUF, (void *)&udpbuf, sizeof(int)) != 0){
 
257
        DEBUGMSGTL(("netsnmp_udp6", "couldn't set SO_SNDBUF to %d bytes: %s\n",
 
258
                    udpbuf, strerror(errno)));
 
259
    }
 
260
#endif                          /*SO_SNDBUF */
 
261
 
 
262
#ifdef  SO_RCVBUF
 
263
    if (setsockopt(t->sock, SOL_SOCKET, SO_RCVBUF, (void *)&udpbuf, sizeof(int)) != 0){
 
264
        DEBUGMSGTL(("netsnmp_udp6", "couldn't set SO_RCVBUF to %d bytes: %s\n",
 
265
                    udpbuf, strerror(errno)));
 
266
    }
 
267
#endif                          /*SO_RCVBUF */
 
268
 
 
269
    if (local) {
 
270
        /*
 
271
         * This session is inteneded as a server, so we must bind on to the
 
272
         * given IP address, which may include an interface address, or could
 
273
         * be INADDR_ANY, but certainly includes a port number.
 
274
         */
 
275
 
 
276
#ifdef IPV6_V6ONLY
 
277
        /* Try to restrict PF_INET6 socket to IPv6 communications only. */
 
278
        {
 
279
          int one=1;
 
280
          if (setsockopt(t->sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) != 0) {
 
281
            DEBUGMSGTL(("netsnmp_udp6", "couldn't set IPV6_V6ONLY to %d bytes: %s\n", one, strerror(errno)));
 
282
          } 
 
283
        }
 
284
#endif
 
285
 
 
286
        rc = bind(t->sock, (struct sockaddr *) addr,
 
287
                  sizeof(struct sockaddr_in6));
 
288
        if (rc != 0) {
 
289
            netsnmp_udp6_close(t);
 
290
            netsnmp_transport_free(t);
 
291
            return NULL;
 
292
        }
 
293
        t->local = malloc(18);
 
294
        if (t->local == NULL) {
 
295
            netsnmp_udp6_close(t);
 
296
            netsnmp_transport_free(t);
 
297
        }
 
298
        memcpy(t->local, addr->sin6_addr.s6_addr, 16);
 
299
        t->local[16] = (addr->sin6_port & 0xff00) >> 8;
 
300
        t->local[17] = (addr->sin6_port & 0x00ff) >> 0;
 
301
        t->local_length = 18;
 
302
        t->data = NULL;
 
303
        t->data_length = 0;
 
304
    } else {
 
305
        /*
 
306
         * This is a client session.  Save the address in the
 
307
         * transport-specific data pointer for later use by netsnmp_udp6_send.
 
308
         */
 
309
 
 
310
        t->data = malloc(sizeof(struct sockaddr_in6));
 
311
        if (t->data == NULL) {
 
312
            netsnmp_transport_free(t);
 
313
            return NULL;
 
314
        }
 
315
        memcpy(t->data, addr, sizeof(struct sockaddr_in6));
 
316
        t->data_length = sizeof(struct sockaddr_in6);
 
317
        t->remote = malloc(18);
 
318
        if (t->remote == NULL) {
 
319
            netsnmp_udp6_close(t);
 
320
            netsnmp_transport_free(t);
 
321
            return NULL;
 
322
        }
 
323
        memcpy(t->remote, addr->sin6_addr.s6_addr, 16);
 
324
        t->remote[16] = (addr->sin6_port & 0xff00) >> 8;
 
325
        t->remote[17] = (addr->sin6_port & 0x00ff) >> 0;
 
326
        t->remote_length = 18;
 
327
    }
 
328
 
 
329
    /*
 
330
     * 16-bit length field, 8 byte UDP header, 40 byte IPv6 header.  
 
331
     */
 
332
 
 
333
    t->msgMaxSize = 0xffff - 8 - 40;
 
334
    t->f_recv     = netsnmp_udp6_recv;
 
335
    t->f_send     = netsnmp_udp6_send;
 
336
    t->f_close    = netsnmp_udp6_close;
 
337
    t->f_accept   = NULL;
 
338
    t->f_fmtaddr  = netsnmp_udp6_fmtaddr;
 
339
 
 
340
    return t;
 
341
}
 
342
 
 
343
 
 
344
 
 
345
int
 
346
netsnmp_sockaddr_in6(struct sockaddr_in6 *addr,
 
347
                     const char *inpeername, int remote_port)
 
348
{
 
349
    char           *cp = NULL, *peername = NULL;
 
350
    char            debug_addr[INET6_ADDRSTRLEN];
 
351
#if HAVE_GETADDRINFO
 
352
    struct addrinfo *addrs = NULL;
 
353
    struct addrinfo hint;
 
354
    int             err;
 
355
#elif HAVE_GETIPNODEBYNAME
 
356
    struct hostent *hp = NULL;
 
357
    int             err;
 
358
#elif HAVE_GETHOSTBYNAME
 
359
    struct hostent *hp = NULL;
 
360
#endif
 
361
 
 
362
    if (addr == NULL) {
 
363
        return 0;
 
364
    }
 
365
 
 
366
    DEBUGMSGTL(("netsnmp_sockaddr_in6", "addr %p, peername \"%s\"\n",
 
367
                addr, inpeername ? inpeername : "[NIL]"));
 
368
 
 
369
    memset(addr, 0, sizeof(struct sockaddr_in6));
 
370
    addr->sin6_family = AF_INET6;
 
371
    addr->sin6_addr = in6addr_any;
 
372
 
 
373
    if (remote_port > 0) {
 
374
        addr->sin6_port = htons(remote_port);
 
375
    } else if (netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
 
376
                                  NETSNMP_DS_LIB_DEFAULT_PORT) > 0) {
 
377
        addr->sin6_port = htons(netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID, 
 
378
                                                 NETSNMP_DS_LIB_DEFAULT_PORT));
 
379
    } else {
 
380
        addr->sin6_port = htons(SNMP_PORT);
 
381
    }
 
382
 
 
383
    if (inpeername != NULL) {
 
384
        /*
 
385
         * Duplicate the peername because we might want to mank around with
 
386
         * it.  
 
387
         */
 
388
 
 
389
        peername = strdup(inpeername);
 
390
        if (peername == NULL) {
 
391
            return 0;
 
392
        }
 
393
 
 
394
        for (cp = peername; *cp && isdigit((int) *cp); cp++);
 
395
        if (!*cp && atoi(peername) != 0) {
 
396
            /*
 
397
             * Okay, it looks like JUST a port number.  
 
398
             */
 
399
            DEBUGMSGTL(("netsnmp_sockaddr_in6", "totally numeric: %d\n",
 
400
                        atoi(peername)));
 
401
            addr->sin6_port = htons(atoi(peername));
 
402
            goto resolved;
 
403
        }
 
404
 
 
405
        /*
 
406
         * See if it is an IPv6 address, which covered with square brankets
 
407
         * with an appended :port.  
 
408
         */
 
409
        if (*peername == '[') {
 
410
            cp = strchr(peername, ']');
 
411
            if (cp != NULL) {
 
412
              /*
 
413
               * See if it is an IPv6 link-local address with interface
 
414
               * name as <zone_id>, like fe80::1234%eth0.
 
415
               * Please refer to the internet draft, IPv6 Scoped Address Architecture
 
416
               * http://www.ietf.org/internet-drafts/draft-ietf-ipngwg-scoping-arch-04.txt
 
417
               *
 
418
               */
 
419
                char *scope_id;
 
420
#ifdef HAVE_IF_NAMETOINDEX
 
421
                unsigned int if_index = 0;
 
422
#endif
 
423
                *cp = '\0';
 
424
                scope_id = strchr(peername + 1, '%');
 
425
                if (scope_id != NULL) {
 
426
                    *scope_id = '\0';
 
427
#ifdef HAVE_IF_NAMETOINDEX
 
428
                    if_index = if_nametoindex(scope_id + 1);
 
429
#endif
 
430
                }
 
431
                if (*(cp + 1) == ':') {
 
432
                    if (atoi(cp + 2) != 0 &&
 
433
                        inet_pton(AF_INET6, peername + 1,
 
434
                                  (void *) &(addr->sin6_addr))) {
 
435
                        DEBUGMSGTL(("netsnmp_sockaddr_in6",
 
436
                                    "IPv6 address with port suffix :%d\n",
 
437
                                    atoi(cp + 2)));
 
438
                        addr->sin6_port = htons(atoi(cp + 2));
 
439
#ifdef HAVE_IF_NAMETOINDEX
 
440
                        addr->sin6_scope_id = if_index;
 
441
#endif
 
442
                        goto resolved;
 
443
                    }
 
444
                } else {
 
445
                    if (inet_pton
 
446
                        (AF_INET6, peername + 1,
 
447
                         (void *) &(addr->sin6_addr))) {
 
448
                        DEBUGMSGTL(("netsnmp_sockaddr_in6",
 
449
                                    "IPv6 address with square brankets\n"));
 
450
                        addr->sin6_port = htons(SNMP_PORT);
 
451
#ifdef HAVE_IF_NAMETOINDEX
 
452
                        addr->sin6_scope_id = if_index;
 
453
#endif
 
454
                        goto resolved;
 
455
                    }
 
456
                }
 
457
                if (scope_id != NULL) {
 
458
                  *scope_id = '%';
 
459
                }
 
460
                *cp = ']';
 
461
            }
 
462
        }
 
463
 
 
464
        cp = strrchr(peername, ':');
 
465
        if (cp != NULL) {
 
466
            char *scope_id;
 
467
#ifdef HAVE_IF_NAMETOINDEX
 
468
            unsigned int if_index = 0;
 
469
#endif
 
470
            *cp = '\0';
 
471
            scope_id = strchr(peername + 1, '%');
 
472
            if (scope_id != NULL) {
 
473
                *scope_id = '\0';
 
474
#ifdef HAVE_IF_NAMETOINDEX
 
475
                if_index = if_nametoindex(scope_id + 1);
 
476
#endif
 
477
            }
 
478
            if (atoi(cp + 1) != 0 &&
 
479
                inet_pton(AF_INET6, peername,
 
480
                          (void *) &(addr->sin6_addr))) {
 
481
                DEBUGMSGTL(("netsnmp_sockaddr_in6",
 
482
                            "IPv6 address with port suffix :%d\n",
 
483
                            atoi(cp + 1)));
 
484
                addr->sin6_port = htons(atoi(cp + 1));
 
485
#ifdef HAVE_IF_NAMETOINDEX
 
486
                addr->sin6_scope_id = if_index;
 
487
#endif
 
488
                goto resolved;
 
489
            }
 
490
            if (scope_id != NULL) {
 
491
              *scope_id = '%';
 
492
            }
 
493
            *cp = ':';
 
494
        }
 
495
 
 
496
        /*
 
497
         * See if it is JUST an IPv6 address.  
 
498
         */
 
499
        if (inet_pton(AF_INET6, peername, (void *) &(addr->sin6_addr))) {
 
500
            DEBUGMSGTL(("netsnmp_sockaddr_in6", "just IPv6 address\n"));
 
501
            goto resolved;
 
502
        }
 
503
 
 
504
        /*
 
505
         * Well, it must be a hostname then, possibly with an appended :port.
 
506
         * Sort that out first.  
 
507
         */
 
508
 
 
509
        cp = strrchr(peername, ':');
 
510
        if (cp != NULL) {
 
511
            *cp = '\0';
 
512
            if (atoi(cp + 1) != 0) {
 
513
                DEBUGMSGTL(("netsnmp_sockaddr_in6",
 
514
                            "hostname(?) with port suffix :%d\n",
 
515
                            atoi(cp + 1)));
 
516
                addr->sin6_port = htons(atoi(cp + 1));
 
517
            } else {
 
518
                /*
 
519
                 * No idea, looks bogus but we might as well pass the full thing to
 
520
                 * the name resolver below.  
 
521
                 */
 
522
                *cp = ':';
 
523
                DEBUGMSGTL(("netsnmp_sockaddr_in6",
 
524
                            "hostname(?) with embedded ':'?\n"));
 
525
            }
 
526
            /*
 
527
             * Fall through.  
 
528
             */
 
529
        }
 
530
#if HAVE_GETADDRINFO
 
531
        memset(&hint, 0, sizeof hint);
 
532
        hint.ai_flags = 0;
 
533
        hint.ai_family = PF_INET6;
 
534
        hint.ai_socktype = SOCK_DGRAM;
 
535
        hint.ai_protocol = 0;
 
536
 
 
537
        err = getaddrinfo(peername, NULL, &hint, &addrs);
 
538
        if (err != 0) {
 
539
            snmp_log(LOG_ERR, "getaddrinfo: %s %s\n", peername,
 
540
                     gai_strerror(err));
 
541
            free(peername);
 
542
            return 0;
 
543
        }
 
544
        DEBUGMSGTL(("netsnmp_sockaddr_in6", "hostname (resolved okay)\n"));
 
545
        memcpy(&addr->sin6_addr,
 
546
               &((struct sockaddr_in6 *) addrs->ai_addr)->sin6_addr,
 
547
               sizeof(struct in6_addr));
 
548
#elif HAVE_GETIPNODEBYNAME
 
549
        hp = getipnodebyname(peername, AF_INET6, 0, &err);
 
550
        if (hp == NULL) {
 
551
            DEBUGMSGTL(("netsnmp_sockaddr_in6",
 
552
                        "hostname (couldn't resolve = %d)\n", err));
 
553
            free(peername);
 
554
            return 0;
 
555
        }
 
556
        DEBUGMSGTL(("netsnmp_sockaddr_in6", "hostname (resolved okay)\n"));
 
557
        memcpy(&(addr->sin6_addr), hp->h_addr, hp->h_length);
 
558
#elif HAVE_GETHOSTBYNAME
 
559
        hp = gethostbyname(peername);
 
560
        if (hp == NULL) {
 
561
            DEBUGMSGTL(("netsnmp_sockaddr_in6",
 
562
                        "hostname (couldn't resolve)\n"));
 
563
            free(peername);
 
564
            return 0;
 
565
        } else {
 
566
            if (hp->h_addrtype != AF_INET6) {
 
567
                DEBUGMSGTL(("netsnmp_sockaddr_in6",
 
568
                            "hostname (not AF_INET6!)\n"));
 
569
                free(peername);
 
570
                return 0;
 
571
            } else {
 
572
                DEBUGMSGTL(("netsnmp_sockaddr_in6",
 
573
                            "hostname (resolved okay)\n"));
 
574
                memcpy(&(addr->sin6_addr), hp->h_addr, hp->h_length);
 
575
            }
 
576
        }
 
577
#else                           /*HAVE_GETHOSTBYNAME */
 
578
        /*
 
579
         * There is no name resolving function available.  
 
580
         */
 
581
        snmp_log(LOG_ERR,
 
582
                 "no getaddrinfo()/getipnodebyname()/gethostbyname()\n");
 
583
        free(peername);
 
584
        return 0;
 
585
#endif                          /*HAVE_GETHOSTBYNAME */
 
586
    } else {
 
587
        DEBUGMSGTL(("netsnmp_sockaddr_in6", "NULL peername"));
 
588
        return 0;
 
589
    }
 
590
 
 
591
  resolved:
 
592
    DEBUGMSGTL(("netsnmp_sockaddr_in6", "return { AF_INET6, [%s]:%hu }\n",
 
593
                inet_ntop(AF_INET6, &addr->sin6_addr, debug_addr,
 
594
                          sizeof(debug_addr)), ntohs(addr->sin6_port)));
 
595
    free(peername);
 
596
    return 1;
 
597
}
 
598
 
 
599
 
 
600
/*
 
601
 * int
 
602
 * inet_make_mask_addr( int pf, void *dst, int masklength )
 
603
 *      convert from bit length specified masklength to network format, 
 
604
 *      which fills 1 from until specified bit length.
 
605
 *      dst is usally the structer of sockaddr_in or sockaddr_in6. 
 
606
 *      makelength must be an interger from 0 to 32 if pf is PF_INET,
 
607
 *      or from 0 to 128 if pf is PF_INET6.
 
608
 * return:
 
609
 *      0 if the input data, masklength was valid for 
 
610
 *      the specified protocol family.
 
611
 *      -1 if the the input data wasn't valid.
 
612
 */
 
613
 
 
614
int
 
615
inet_make_mask_addr(int pf, void *dst, int masklength)
 
616
{
 
617
 
 
618
    unsigned long   Mask = 0;
 
619
    int             maskBit = 0x80000000L;
 
620
    unsigned char   mask = 0;
 
621
    unsigned char   maskbit = 0x80L;
 
622
    int             i, j, jj;
 
623
 
 
624
 
 
625
    switch (pf) {
 
626
    case PF_INET:
 
627
        if (masklength < 0 || masklength > 32)
 
628
            return -1;
 
629
 
 
630
        ((struct in_addr *) dst)->s_addr = 0;
 
631
 
 
632
        while (masklength--) {
 
633
            Mask |= maskBit;
 
634
            maskBit >>= 1;
 
635
        }
 
636
        ((struct in_addr *) dst)->s_addr = htonl(Mask);
 
637
        break;
 
638
 
 
639
    case PF_INET6:
 
640
        if (masklength < 0 || masklength > 128)
 
641
            return -1;
 
642
 
 
643
 
 
644
        for (i = 0; i < 16; i++) {
 
645
            (*(uint8_t *) (&((struct in6_addr *) dst)->s6_addr[i])) = 0x00;
 
646
        }
 
647
 
 
648
        j = (int) masklength / 8;
 
649
        jj = masklength % 8;
 
650
 
 
651
        for (i = 0; i < j; i++) {
 
652
            (*(uint8_t *) (&((struct in6_addr *) dst)->s6_addr[i])) = 0xff;
 
653
        }
 
654
        while (jj--) {
 
655
            mask |= maskbit;
 
656
            maskbit >>= 1;
 
657
        }
 
658
        (*(uint8_t *) (&((struct in6_addr *) dst)->s6_addr[j])) = mask;
 
659
        break;
 
660
    default:
 
661
        return -1;              /* unsupported protocol family */
 
662
    }
 
663
    return 0;
 
664
}
 
665
 
 
666
/*
 
667
 * int
 
668
 * inet_addr_complement( int pf, void *src, void *dst )
 
669
 *      convert from src to dst, which all bits 
 
670
 *      are bit-compliment of src.
 
671
 *      Src, dst are ususally sockaddr_in or sockaddr_in6.  
 
672
 * return:
 
673
 *      0 if the input data src and dst have the same size
 
674
 *      -1 if the the input data wasn't valid.
 
675
 */
 
676
 
 
677
int
 
678
inet_addr_complement(int pf, void *src, void *dst)
 
679
{
 
680
 
 
681
    int             i;
 
682
 
 
683
    if (sizeof(src) != sizeof(dst))
 
684
        return -1;
 
685
 
 
686
    switch (pf) {
 
687
    case PF_INET:
 
688
        ((struct in_addr *) dst)->s_addr =
 
689
            ~((struct in_addr *) src)->s_addr;
 
690
        break;
 
691
    case PF_INET6:
 
692
        for (i = 0; i < 16; i++) {
 
693
            (*(uint8_t *) (&((struct in6_addr *) dst)->s6_addr[i])) =
 
694
                (~(*(uint8_t *) (&((struct in6_addr *) src)->s6_addr[i])))
 
695
                & 0xff;
 
696
        }
 
697
        break;
 
698
    default:
 
699
        return -1;
 
700
    }
 
701
    return 0;
 
702
}
 
703
 
 
704
/*
 
705
 * int
 
706
 * inet_addr_and( int pf, void *src1, void *src2, void *dst) 
 
707
 *      take AND operation on src1 and src2, and output the result to dst.
 
708
 *      Src1, src2, and dst are ususally sockaddr_in or sockaddr_in6.  
 
709
 * return:
 
710
 *      0 if the input data src and dst have the same size
 
711
 *      -1 if the the input data are not the same size
 
712
 */
 
713
 
 
714
int
 
715
inet_addr_and(int pf, void *src1, void *src2, void *dst)
 
716
{
 
717
    int             i;
 
718
 
 
719
    if (sizeof(src1) != sizeof(src2) || sizeof(src2) != sizeof(dst))
 
720
        return -1;
 
721
 
 
722
    switch (pf) {
 
723
    case PF_INET:
 
724
        ((struct in_addr *) dst)->s_addr =
 
725
            ((struct in_addr *) src1)->s_addr & ((struct in_addr *) src2)->
 
726
            s_addr;
 
727
        break;
 
728
 
 
729
    case PF_INET6:
 
730
        for (i = 0; i < 16; i++) {
 
731
            (*(uint8_t *) (&((struct in6_addr *) dst)->s6_addr[i])) =
 
732
                (*(uint8_t *) (&((struct in6_addr *) src1)->s6_addr[i])) &
 
733
                (*(uint8_t *) (&((struct in6_addr *) src2)->s6_addr[i]));
 
734
        }
 
735
        break;
 
736
    default:
 
737
        return -1;
 
738
    }
 
739
    return 0;
 
740
}
 
741
 
 
742
 
 
743
/*
 
744
 * int
 
745
 * inet_addrs_consistence (int pf, void *net, void *mask ) 
 
746
 *      This function checks if the network address net is consistent
 
747
 *      with the netmask address, mask.
 
748
 *      Net and mask are ususally sockaddr_in or sockaddr_in6.  
 
749
 * Note:
 
750
 *      Must spefiey protocol family in pf.
 
751
 * return:
 
752
 *      0 if there is no consistence with address "net" and "mask".
 
753
 *      -1 if network address is inconsistent with netmask address, for 
 
754
 *      instance, network address is 192.168.0.128 in spite of netmask, 
 
755
 *      which is 255.255.255.0. 
 
756
 *      The case that the size of net and mask are different also returns -1.
 
757
 */
 
758
 
 
759
int
 
760
inet_addrs_consistence(int pf, void *net, void *mask)
 
761
{
 
762
    struct sockaddr_in *tmp, *dst;
 
763
    struct sockaddr_in6 *tmp6, *dst6;
 
764
    int             ret;
 
765
 
 
766
    switch (pf) {
 
767
    case PF_INET:
 
768
        tmp = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in));
 
769
        memset(tmp, 0, sizeof(*tmp));
 
770
        tmp->sin_family = PF_INET;
 
771
        if (inet_addr_complement
 
772
            (PF_INET, (struct in_addr *) mask, &tmp->sin_addr) != 0) {
 
773
            config_perror("Fail in function of inet_addr_complement()");
 
774
            free(tmp);
 
775
            return -1;
 
776
        }
 
777
        dst = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in));
 
778
        memset(dst, 0, sizeof(*dst));
 
779
        dst->sin_family = PF_INET;
 
780
        if (inet_addr_and
 
781
            (PF_INET, (struct in_addr *) net, &tmp->sin_addr,
 
782
             &dst->sin_addr) != 0) {
 
783
            config_perror("Fail in function of inet_addr_and()");
 
784
            free(dst);
 
785
            free(tmp);
 
786
            return -1;
 
787
        }
 
788
        ret = ((dst->sin_addr.s_addr == INADDR_ANY) ? 0 : -1);
 
789
        free(dst);
 
790
        free(tmp);
 
791
        break;
 
792
    case PF_INET6:
 
793
        tmp6 = (struct sockaddr_in6 *) malloc(sizeof(struct sockaddr_in6));
 
794
        memset(tmp6, 0, sizeof(*tmp6));
 
795
        tmp6->sin6_family = PF_INET6;
 
796
        if (inet_addr_complement
 
797
            (PF_INET6, (struct in6_addr *) mask, &tmp6->sin6_addr) != 0) {
 
798
            config_perror("Fail in function of inet_addr_complement()");
 
799
            free(tmp6);
 
800
            return -1;
 
801
        }
 
802
        dst6 = (struct sockaddr_in6 *) malloc(sizeof(struct sockaddr_in6));
 
803
        memset(dst6, 0, sizeof(*dst6));
 
804
        dst6->sin6_family = PF_INET6;
 
805
        if (inet_addr_and
 
806
            (PF_INET6, (struct in6_addr *) net, &tmp6->sin6_addr,
 
807
             &dst6->sin6_addr)) {
 
808
            config_perror("Fail in function of inet_addr_and()");
 
809
            free(dst6);
 
810
            free(tmp6);
 
811
            return -1;
 
812
        }
 
813
        ret = (IN6_IS_ADDR_UNSPECIFIED(&dst6->sin6_addr) == 1 ? 0 : -1);
 
814
        free(dst6);
 
815
        free(tmp6);
 
816
        break;
 
817
    default:
 
818
        return -1;
 
819
    }
 
820
    return ret;
 
821
}
 
822
 
 
823
/*
 
824
 * int
 
825
 * masked_address_are_equal (pf, from, mask, network) 
 
826
 *      This function takes AND operation on address "from" and "mask",
 
827
 *      and check the result is equal to address "network". 
 
828
 *      From, net and mask are ususally sockaddr_in or sockaddr_in6.  
 
829
 * Note:
 
830
 *      Must spefiey protocol family in pf.
 
831
 * return:
 
832
 *      0 if address "from" masked by address "mask" is eqaul to 
 
833
 *      address "network". 
 
834
 *      -1 if address "from" masked by address "mask" isn't eqaul to 
 
835
 *      address "network". For instance, address "from" is 
 
836
 *       192.168.0.129 and "mask" is 255.255.255.128. Then, masked 
 
837
 *      address is 192.168.0.128. If address "network" is 192.168.0.128,
 
838
 *      return 0, otherwise -1.
 
839
 *      Also retunn -1 if each address family of from, mask, network
 
840
 *      isn't the same.
 
841
 */
 
842
 
 
843
int
 
844
masked_address_are_equal(int af, struct sockaddr_storage *from,
 
845
                         struct sockaddr_storage *mask,
 
846
                         struct sockaddr_storage *network)
 
847
{
 
848
 
 
849
    struct sockaddr_storage ss;
 
850
    memset(&ss, 0, sizeof(ss));
 
851
 
 
852
    switch (af) {
 
853
    case PF_INET:
 
854
        if (mask->ss_family != PF_INET || network->ss_family != PF_INET) {
 
855
            return -1;
 
856
        }
 
857
        ss.ss_family = PF_INET;
 
858
        inet_addr_and(PF_INET,
 
859
                      &((struct sockaddr_in *) from)->sin_addr,
 
860
                      &((struct sockaddr_in *) mask)->sin_addr,
 
861
                      &((struct sockaddr_in *) &ss)->sin_addr);
 
862
        if (((struct sockaddr_in *) &ss)->sin_addr.s_addr ==
 
863
            ((struct sockaddr_in *) network)->sin_addr.s_addr) {
 
864
            return 0;
 
865
        } else {
 
866
            return -1;
 
867
        }
 
868
        break;
 
869
    case PF_INET6:
 
870
        if (mask->ss_family != PF_INET6 || network->ss_family != PF_INET6) {
 
871
            return -1;
 
872
        }
 
873
        ss.ss_family = PF_INET6;
 
874
        inet_addr_and(PF_INET6,
 
875
                      &((struct sockaddr_in6 *) from)->sin6_addr,
 
876
                      &((struct sockaddr_in6 *) mask)->sin6_addr,
 
877
                      &((struct sockaddr_in6 *) &ss)->sin6_addr);
 
878
#ifndef IN6_ARE_ADDR_EQUAL
 
879
#define IN6_ARE_ADDR_EQUAL(a,b) IN6_ADDR_EQUAL(a,b)
 
880
#endif
 
881
        if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *) &ss)->sin6_addr,
 
882
                               &((struct sockaddr_in6 *) network)->
 
883
                               sin6_addr) == 1) {
 
884
            return 0;
 
885
        } else {
 
886
            return -1;
 
887
        }
 
888
        break;
 
889
    default:
 
890
        return -1;
 
891
    }
 
892
}
 
893
 
 
894
/*
 
895
 * The following functions provide the "com2sec6" configuration token
 
896
 * functionality for compatibility.  
 
897
 */
 
898
 
 
899
#define EXAMPLE_NETWORK       "NETWORK"
 
900
#define EXAMPLE_COMMUNITY     "COMMUNITY"
 
901
 
 
902
typedef struct _com2Sec6Entry {
 
903
    char            community[VACMSTRINGLEN];
 
904
    struct sockaddr_in6 network;
 
905
    struct sockaddr_in6 mask;
 
906
    char            secName[VACMSTRINGLEN];
 
907
    struct _com2Sec6Entry *next;
 
908
} com2Sec6Entry;
 
909
 
 
910
com2Sec6Entry  *com2Sec6List = NULL, *com2Sec6ListLast = NULL;
 
911
 
 
912
 
 
913
void
 
914
memmove_com2Sec6Entry(com2Sec6Entry * c,
 
915
                      char *secName,
 
916
                      char *community,
 
917
                      struct sockaddr_in6 net, struct sockaddr_in6 mask)
 
918
{
 
919
    snprintf(c->secName, strlen(secName) + 1, "%s", secName);
 
920
    snprintf(c->community, strlen(community) + 1, "%s", community);
 
921
    memmove(&c->network, &net, sizeof(net));
 
922
    memmove(&c->mask, &mask, sizeof(mask));
 
923
    c->next = NULL;
 
924
}
 
925
 
 
926
 
 
927
void
 
928
netsnmp_udp6_parse_security(const char *token, char *param)
 
929
{
 
930
    char           *secName = NULL, *community = NULL, *source = NULL;
 
931
    char           *cp = NULL, *strnetwork = NULL, *strmask = NULL;
 
932
    com2Sec6Entry  *e = NULL;
 
933
    struct sockaddr_in6 net, mask;
 
934
    struct sockaddr_in tmp;
 
935
 
 
936
    memset(&net, 0, sizeof(net));
 
937
    memset(&mask, 0, sizeof(mask));
 
938
    memset(&tmp, 0, sizeof(tmp));
 
939
    net.sin6_family = AF_INET6;
 
940
    mask.sin6_family = AF_INET6;
 
941
    tmp.sin_family = AF_INET;
 
942
 
 
943
 
 
944
    /*
 
945
     * Get security, source address/netmask and community strings.  
 
946
     */
 
947
    secName = strtok(param, "\t\n ");
 
948
    if (secName == NULL) {
 
949
        config_perror("missing NAME parameter");
 
950
        return;
 
951
    } else if (strlen(secName) > (VACMSTRINGLEN - 1)) {
 
952
        config_perror("security name too long");
 
953
        return;
 
954
    }
 
955
    source = strtok(NULL, "\t\n ");
 
956
    if (source == NULL) {
 
957
        config_perror("missing SOURCE parameter");
 
958
        return;
 
959
    } else if (strncmp(source, EXAMPLE_NETWORK, strlen(EXAMPLE_NETWORK)) ==
 
960
               0) {
 
961
        config_perror("example config NETWORK not properly configured");
 
962
        return;
 
963
    }
 
964
    community = strtok(NULL, "\t\n ");
 
965
    if (community == NULL) {
 
966
        config_perror("missing COMMUNITY parameter\n");
 
967
        return;
 
968
    } else
 
969
        if (strncmp
 
970
            (community, EXAMPLE_COMMUNITY, strlen(EXAMPLE_COMMUNITY))
 
971
            == 0) {
 
972
        config_perror("example config COMMUNITY not properly configured");
 
973
        return;
 
974
    } else if (strlen(community) > (VACMSTRINGLEN - 1)) {
 
975
        config_perror("community name too long");
 
976
        return;
 
977
    }
 
978
 
 
979
    /*
 
980
     * Process the source address/netmask string.  
 
981
     */
 
982
    cp = strchr(source, '/');
 
983
    if (cp != NULL) {
 
984
        /*
 
985
         * Mask given.  
 
986
         */
 
987
        *cp = '\0';
 
988
        strmask = cp + 1;
 
989
    }
 
990
 
 
991
    /*
 
992
     * Deal with the network part first.  
 
993
     */
 
994
    if ((strcmp(source, "default") == 0) || (strcmp(source, "::") == 0)) {
 
995
        strnetwork = strdup("0::0");
 
996
        strmask = strdup("0::0");
 
997
 
 
998
        inet_pton(AF_INET6, strnetwork, &net.sin6_addr);
 
999
        inet_pton(AF_INET6, strmask, &mask.sin6_addr);
 
1000
 
 
1001
        e = (com2Sec6Entry *) malloc(sizeof(com2Sec6Entry));
 
1002
        if (e == NULL) {
 
1003
            config_perror("memory error");
 
1004
            return;
 
1005
        }
 
1006
        /*
 
1007
         * Everything is okay.  Copy the parameters to the structure allocated
 
1008
         * above and add it to END of the list.  
 
1009
         */
 
1010
        if (strmask != NULL && strnetwork != NULL) {
 
1011
            DEBUGMSGTL(("netsnmp_udp6_parse_security",
 
1012
                        "<\"%s\", %s/%s> => \"%s\"\n", community,
 
1013
                        strnetwork, strmask, secName));
 
1014
            free(strmask);
 
1015
            free(strnetwork);
 
1016
        } else {
 
1017
            DEBUGMSGTL(("netsnmp_udp6_parse_security",
 
1018
                        "Couldn't allocate enough memory\n"));
 
1019
        }
 
1020
        memmove_com2Sec6Entry(e, secName, community, net, mask);
 
1021
        if (com2Sec6ListLast != NULL) {
 
1022
            com2Sec6ListLast->next = e;
 
1023
            com2Sec6ListLast = e;
 
1024
        } else {
 
1025
            com2Sec6ListLast = com2Sec6List = e;
 
1026
        }
 
1027
 
 
1028
    } else {
 
1029
        /*
 
1030
         * Try interpreting as IPv6 address.  
 
1031
         */
 
1032
        if (inet_pton(AF_INET6, source, &net.sin6_addr) == 1) {
 
1033
            if (strmask == NULL || *strmask == '\0') {
 
1034
                inet_make_mask_addr(PF_INET6, &mask.sin6_addr, 128);
 
1035
            } else {
 
1036
                if (strchr(strmask, ':')) {
 
1037
                    if (inet_pton(PF_INET6, strmask, &net.sin6_addr) != 1) {
 
1038
                        config_perror("bad mask");
 
1039
                        return;
 
1040
                    }
 
1041
                } else {
 
1042
                    if (inet_make_mask_addr
 
1043
                        (PF_INET6, &mask.sin6_addr, atoi(strmask)) != 0) {
 
1044
                        config_perror("bad mask");
 
1045
                        return;
 
1046
 
 
1047
                    }
 
1048
                }
 
1049
            }
 
1050
            /*
 
1051
             * Check that the network and mask are consistent.  
 
1052
             */
 
1053
            if (inet_addrs_consistence
 
1054
                (PF_INET6, &net.sin6_addr, &mask.sin6_addr) != 0) {
 
1055
                config_perror("source/mask mismatch");
 
1056
                return;
 
1057
            }
 
1058
 
 
1059
            e = (com2Sec6Entry *) malloc(sizeof(com2Sec6Entry));
 
1060
            if (e == NULL) {
 
1061
                config_perror("memory error");
 
1062
                return;
 
1063
            }
 
1064
 
 
1065
            /*
 
1066
             * Everything is okay.  Copy the parameters to the structure allocated
 
1067
             * above and add it to END of the list.  
 
1068
             */
 
1069
            if (strmask != NULL && strnetwork != NULL) {
 
1070
                DEBUGMSGTL(("netsnmp_udp6_parse_security",
 
1071
                            "<\"%s\", %s/%s> => \"%s\"\n", community,
 
1072
                            strnetwork, strmask, secName));
 
1073
                free(strmask);
 
1074
                free(strnetwork);
 
1075
            } else {
 
1076
                DEBUGMSGTL(("netsnmp_udp6_parse_security",
 
1077
                            "Couldn't allocate enough memory\n"));
 
1078
            }
 
1079
            memmove_com2Sec6Entry(e, secName, community, net, mask);
 
1080
            if (com2Sec6ListLast != NULL) {
 
1081
                com2Sec6ListLast->next = e;
 
1082
                com2Sec6ListLast = e;
 
1083
            } else {
 
1084
                com2Sec6ListLast = com2Sec6List = e;
 
1085
            }
 
1086
 
 
1087
        } else {
 
1088
            /*
 
1089
             * Nope, Must be a hostname.  
 
1090
             */
 
1091
            struct addrinfo hints, *ai, *res;
 
1092
            char            hbuf[NI_MAXHOST];
 
1093
            int             gai_error;
 
1094
 
 
1095
            memset(&hints, 0, sizeof(hints));
 
1096
            hints.ai_family = PF_INET6;
 
1097
            hints.ai_socktype = SOCK_DGRAM;
 
1098
            if ((gai_error = getaddrinfo(source, NULL, &hints, &res)) != 0) {
 
1099
                config_perror(gai_strerror(gai_error));
 
1100
                return;
 
1101
            }
 
1102
 
 
1103
            for (ai = res; ai != NULL; ai = ai->ai_next) {
 
1104
                if (getnameinfo
 
1105
                    (ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), NULL,
 
1106
                     0, NI_NUMERICHOST)) {
 
1107
                    config_perror("getnameinfo failed");
 
1108
                }
 
1109
                memmove(ai->ai_addr, &net, sizeof(struct sockaddr_in6));
 
1110
                inet_make_mask_addr(AF_INET6, &mask.sin6_addr, 127);
 
1111
 
 
1112
                e = (com2Sec6Entry *) malloc(sizeof(com2Sec6Entry));
 
1113
                if (e == NULL) {
 
1114
                    config_perror("memory error");
 
1115
                    return;
 
1116
                }
 
1117
 
 
1118
                /*
 
1119
                 * Everything is okay.  Copy the parameters to the structure allocated
 
1120
                 * above and add it to END of the list.  
 
1121
                 */
 
1122
                DEBUGMSGTL(("netsnmp_udp6_parse_security",
 
1123
                            "<\"%s\", %s> => \"%s\"\n", community, hbuf,
 
1124
                            secName));
 
1125
                memmove_com2Sec6Entry(e, secName, community, net, mask);
 
1126
                if (com2Sec6ListLast != NULL) {
 
1127
                    com2Sec6ListLast->next = e;
 
1128
                    com2Sec6ListLast = e;
 
1129
                } else {
 
1130
                    com2Sec6ListLast = com2Sec6List = e;
 
1131
                }
 
1132
            }
 
1133
            if (res != NULL)
 
1134
                freeaddrinfo(res);
 
1135
        }
 
1136
        /*
 
1137
         * free(strnetwork); 
 
1138
         */
 
1139
    }
 
1140
}
 
1141
 
 
1142
void
 
1143
netsnmp_udp6_com2Sec6List_free(void)
 
1144
{
 
1145
    com2Sec6Entry  *e = com2Sec6List;
 
1146
    while (e != NULL) {
 
1147
        com2Sec6Entry  *tmp = e;
 
1148
        e = e->next;
 
1149
        free(tmp);
 
1150
    }
 
1151
    com2Sec6List = com2Sec6ListLast = NULL;
 
1152
}
 
1153
 
 
1154
 
 
1155
void
 
1156
netsnmp_udp6_agent_config_tokens_register(void)
 
1157
{
 
1158
    register_app_config_handler("com2sec6", netsnmp_udp6_parse_security,
 
1159
                                netsnmp_udp6_com2Sec6List_free,
 
1160
                                "name IPv6-network-address[/netmask] community");
 
1161
}
 
1162
 
 
1163
 
 
1164
 
 
1165
/*
 
1166
 * Return 0 if there are no com2sec entries, or return 1 if there ARE com2sec 
 
1167
 * entries.  On return, if a com2sec entry matched the passed parameters,
 
1168
 * then *secName points at the appropriate security name, or is NULL if the
 
1169
 * parameters did not match any com2sec entry.  
 
1170
 */
 
1171
 
 
1172
int
 
1173
netsnmp_udp6_getSecName(void *opaque, int olength,
 
1174
                        const char *community,
 
1175
                        int community_len, char **secName)
 
1176
{
 
1177
    com2Sec6Entry  *c;
 
1178
    struct sockaddr_in6 *from = (struct sockaddr_in6 *) opaque;
 
1179
    char           *ztcommunity = NULL;
 
1180
    char            str6[INET6_ADDRSTRLEN];
 
1181
 
 
1182
    /*
 
1183
     * Special case if there are NO entries (as opposed to no MATCHING
 
1184
     * entries).  
 
1185
     */
 
1186
 
 
1187
    if (com2Sec6List == NULL) {
 
1188
        DEBUGMSGTL(("netsnmp_udp6_getSecName", "no com2sec entries\n"));
 
1189
        if (secName != NULL) {
 
1190
            *secName = NULL;
 
1191
        }
 
1192
        return 0;
 
1193
    }
 
1194
 
 
1195
    /*
 
1196
     * If there is no IPv6 source address, 
 
1197
     * then there can be no valid security name.  
 
1198
     */
 
1199
 
 
1200
    if (opaque == NULL || olength != sizeof(struct sockaddr_in6)
 
1201
        || from->sin6_family != PF_INET6) {
 
1202
        DEBUGMSGTL(("netsnmp_udp6_getSecName",
 
1203
                    "no IPv6 source address in PDU?\n"));
 
1204
        if (secName != NULL) {
 
1205
            *secName = NULL;
 
1206
        }
 
1207
        return 1;
 
1208
    }
 
1209
 
 
1210
    ztcommunity = (char *) malloc(community_len + 1);
 
1211
    if (ztcommunity != NULL) {
 
1212
        memcpy(ztcommunity, community, community_len);
 
1213
        ztcommunity[community_len] = '\0';
 
1214
    }
 
1215
 
 
1216
    inet_ntop(AF_INET6, &from->sin6_addr, str6, sizeof(str6));
 
1217
    DEBUGMSGTL(("netsnmp_udp6_getSecName", "resolve <\"%s\", %s>\n",
 
1218
                ztcommunity ? ztcommunity : "<malloc error>", str6));
 
1219
 
 
1220
    for (c = com2Sec6List; c != NULL; c = c->next) {
 
1221
        DEBUGMSGTL(("netsnmp_udp6_getSecName",
 
1222
                    "compare <\"%s\", 0x%032/0x%032x>", c->community,
 
1223
                    c->network, c->mask));
 
1224
 
 
1225
        if ((community_len == strlen(c->community)) &&
 
1226
            (memcmp(community, c->community, community_len) == 0) &&
 
1227
            (masked_address_are_equal(from->sin6_family,
 
1228
                                      (struct sockaddr_storage *) from,
 
1229
                                      (struct sockaddr_storage *) &c->mask,
 
1230
                                      (struct sockaddr_storage *) &c->
 
1231
                                      network) == 0)) {
 
1232
            DEBUGMSG(("netsnmp_udp6_getSecName", "... SUCCESS\n"));
 
1233
            if (secName != NULL) {
 
1234
                *secName = c->secName;
 
1235
            }
 
1236
            break;
 
1237
        }
 
1238
        DEBUGMSG(("netsnmp_udp6_getSecName", "... nope\n"));
 
1239
    }
 
1240
    if (ztcommunity != NULL) {
 
1241
        free(ztcommunity);
 
1242
    }
 
1243
    return 1;
 
1244
}
 
1245
 
 
1246
netsnmp_transport *
 
1247
netsnmp_udp6_create_tstring(const char *string, int local)
 
1248
{
 
1249
    struct sockaddr_in6 addr;
 
1250
 
 
1251
    if (netsnmp_sockaddr_in6(&addr, string, 0)) {
 
1252
        return netsnmp_udp6_transport(&addr, local);
 
1253
    } else {
 
1254
        return NULL;
 
1255
    }
 
1256
}
 
1257
 
 
1258
 
 
1259
/*
 
1260
 * See:
 
1261
 * 
 
1262
 * http://www.ietf.org/internet-drafts/draft-ietf-ops-taddress-mib-01.txt
 
1263
 * 
 
1264
 * (or newer equivalent) for details of the TC which we are using for
 
1265
 * the mapping here.  
 
1266
 */
 
1267
 
 
1268
netsnmp_transport *
 
1269
netsnmp_udp6_create_ostring(const u_char * o, size_t o_len, int local)
 
1270
{
 
1271
    struct sockaddr_in6 addr;
 
1272
 
 
1273
    if (o_len == 18) {
 
1274
        memset((u_char *) & addr, 0, sizeof(struct sockaddr_in6));
 
1275
        addr.sin6_family = AF_INET6;
 
1276
        memcpy((u_char *) & (addr.sin6_addr.s6_addr), o, 16);
 
1277
        addr.sin6_port = (o[16] << 8) + o[17];
 
1278
        return netsnmp_udp6_transport(&addr, local);
 
1279
    }
 
1280
    return NULL;
 
1281
}
 
1282
 
 
1283
 
 
1284
void
 
1285
netsnmp_udp6_ctor(void)
 
1286
{
 
1287
    udp6Domain.name = netsnmp_UDPIPv6Domain;
 
1288
    udp6Domain.name_length = sizeof(netsnmp_UDPIPv6Domain) / sizeof(oid);
 
1289
    udp6Domain.f_create_from_tstring = netsnmp_udp6_create_tstring;
 
1290
    udp6Domain.f_create_from_ostring = netsnmp_udp6_create_ostring;
 
1291
    udp6Domain.prefix = calloc(5, sizeof(char *));
 
1292
    udp6Domain.prefix[0] = "udp6";
 
1293
    udp6Domain.prefix[1] = "ipv6";
 
1294
    udp6Domain.prefix[2] = "udpv6";
 
1295
    udp6Domain.prefix[3] = "udpipv6";
 
1296
 
 
1297
    netsnmp_tdomain_register(&udp6Domain);
 
1298
}