Coverage Report

Created: 2023-09-25 06:12

/src/net-snmp/snmplib/transports/snmpIPv6BaseDomain.c
Line
Count
Source (jump to first uncovered line)
1
/* IPV6 base transport support functions
2
 *
3
 * Portions of this file are subject to the following copyright(s).  See
4
 * the Net-SNMP's COPYING file for more details and other copyrights
5
 * that may apply:
6
 *
7
 * Portions of this file are copyrighted by:
8
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
9
 * Use is subject to license terms specified in the COPYING file
10
 * distributed with the Net-SNMP package.
11
 */
12
13
#include <net-snmp/net-snmp-config.h>
14
15
#ifdef NETSNMP_ENABLE_IPV6
16
17
#include <net-snmp/types.h>
18
#include "snmpIPBaseDomain.h"
19
#include <net-snmp/library/snmpIPv6BaseDomain.h>
20
#include <net-snmp/library/system.h>
21
#include <net-snmp/library/snmp_assert.h>
22
23
#include <stddef.h>
24
#include <stdio.h>
25
#include <sys/types.h>
26
#include <ctype.h>
27
#ifdef HAVE_STDLIB_H
28
#include <stdlib.h>
29
#endif
30
#ifdef HAVE_STRING_H
31
#include <string.h>
32
#else
33
#include <strings.h>
34
#endif
35
#ifdef HAVE_SYS_SOCKET_H
36
#include <sys/socket.h>
37
#endif
38
#ifdef HAVE_NETINET_IN_H
39
#include <netinet/in.h>
40
#endif
41
#ifdef HAVE_ARPA_INET_H
42
#include <arpa/inet.h>
43
#endif
44
#ifdef HAVE_NETDB_H
45
#include <netdb.h>
46
#endif
47
#ifdef HAVE_NET_IF_H
48
#include <net/if.h>
49
#endif
50
51
#include <net-snmp/types.h>
52
#include <net-snmp/library/snmp.h>
53
#include <net-snmp/library/snmp_debug.h>
54
#include <net-snmp/library/default_store.h>
55
#include <net-snmp/library/snmp_logging.h>
56
57
#include "inet_ntop.h"
58
#include "inet_pton.h"
59
60
61
#if defined(WIN32) && !defined(IF_NAMESIZE)
62
#define IF_NAMESIZE 12
63
#endif
64
65
66
#if defined(HAVE_WINSOCK_H) && !defined(mingw32)
67
static const struct in6_addr in6addr_any; /*IN6ADDR_ANY_INIT*/
68
#endif
69
70
71
#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
72
static unsigned
73
netsnmp_if_nametoindex(const char *ifname)
74
3
{
75
#if defined(WIN32)
76
    return atoi(ifname);
77
#elif defined(HAVE_IF_NAMETOINDEX)
78
3
    int res;
79
80
3
    res = if_nametoindex(ifname);
81
3
    if (res == 0)
82
2
        res = atoi(ifname);
83
84
3
    return res;
85
#else
86
    return 0;
87
#endif
88
3
}
89
90
static char *
91
netsnmp_if_indextoname(unsigned ifindex, char *ifname)
92
0
{
93
#if defined(WIN32)
94
    snprintf(ifname, IF_NAMESIZE, "%u", ifindex);
95
    return ifname;
96
#elif defined(HAVE_IF_NAMETOINDEX)
97
0
    return if_indextoname(ifindex, ifname);
98
#else
99
    return NULL;
100
#endif
101
0
}
102
#endif /* HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID */
103
104
char *
105
netsnmp_ipv6_fmtaddr(const char *prefix, netsnmp_transport *t,
106
                     const void *data, int len)
107
774
{
108
774
    const struct sockaddr_in6 *to;
109
774
    char scope_id[IF_NAMESIZE + 1] = "";
110
774
    char addr[INET6_ADDRSTRLEN];
111
774
    char *tmp;
112
113
774
    DEBUGMSGTL(("netsnmp_ipv6", "fmtaddr: t = %p, data = %p, len = %d\n", t,
114
774
                data, len));
115
116
774
    if (t && !data) {
117
0
        data = t->data;
118
0
        len = t->data_length;
119
0
    }
120
121
774
    switch (data ? len : 0) {
122
32
    case sizeof(struct sockaddr_in6):
123
32
        to = data;
124
32
        break;
125
11
    case sizeof(netsnmp_indexed_addr_pair): {
126
11
        const netsnmp_indexed_addr_pair *addr_pair = data;
127
128
11
        to = (const struct sockaddr_in6 *)&addr_pair->remote_addr;
129
11
        break;
130
0
    }
131
731
    default:
132
731
        if (asprintf(&tmp, "%s: unknown", prefix) < 0)
133
0
            tmp = NULL;
134
731
        return tmp;
135
774
    }
136
137
43
    if (to->sin6_family != AF_INET6)
138
43
        return strdup("unsupported address family");
139
140
0
    if (t && t->flags & NETSNMP_TRANSPORT_FLAG_HOSTNAME) {
141
0
  struct hostent *host;
142
0
  host = netsnmp_gethostbyaddr(&to->sin6_addr, sizeof(struct in6_addr), AF_INET6);
143
0
  return (host ? strdup(host->h_name) : NULL);
144
0
    } else {
145
0
#if defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID)
146
0
  if (to->sin6_scope_id &&
147
0
            netsnmp_if_indextoname(to->sin6_scope_id, &scope_id[1]))
148
0
            scope_id[0] = '%';
149
0
#endif
150
0
        inet_ntop(AF_INET6, &to->sin6_addr, addr, sizeof(addr));
151
0
        if (asprintf(&tmp, "%s: [%s%s]:%hu", prefix, addr, scope_id,
152
0
         ntohs(to->sin6_port)) < 0)
153
0
            tmp = NULL;
154
0
    }
155
0
    return tmp;
156
0
}
157
158
void netsnmp_ipv6_get_taddr(struct netsnmp_transport_s *t, void **addr,
159
                            size_t *addr_len)
160
0
{
161
0
    struct sockaddr_in6 *sin6 = t->remote;
162
163
0
    netsnmp_assert(t->remote_length == sizeof(*sin6));
164
165
0
    *addr_len = 18;
166
0
    if ((*addr = malloc(*addr_len))) {
167
0
        unsigned char *p = *addr;
168
169
0
        memcpy(p,      &sin6->sin6_addr, 16);
170
0
        memcpy(p + 16, &sin6->sin6_port, 2);
171
0
    }
172
0
}
173
174
int netsnmp_ipv6_ostring_to_sockaddr(struct sockaddr_in6 *sin6, const void *o,
175
                                     size_t o_len)
176
0
{
177
0
    const char *p = o;
178
179
0
    if (o_len != 18)
180
0
        return 0;
181
182
0
    memset(sin6, 0, sizeof(*sin6));
183
0
    sin6->sin6_family = AF_INET6;
184
0
    memcpy(&sin6->sin6_addr, p + 0,  16);
185
0
    memcpy(&sin6->sin6_port, p + 16, 2);
186
0
    return 1;
187
0
}
188
189
static int netsnmp_resolve_v6_hostname(struct in6_addr *addr,
190
                                       const char *hostname)
191
9
{
192
9
#ifdef HAVE_GETADDRINFO
193
9
    struct addrinfo hint = { 0 };
194
9
    struct addrinfo *addrs;
195
9
    int             err;
196
197
9
    hint.ai_family = PF_INET6;
198
9
    hint.ai_socktype = SOCK_DGRAM;
199
9
    err = netsnmp_getaddrinfo(hostname, NULL, &hint, &addrs);
200
9
    if (err)
201
9
        return 0;
202
203
0
    if (addrs) {
204
0
        DEBUGMSGTL(("netsnmp_sockaddr_in6", "hostname (resolved okay)\n"));
205
0
        *addr = ((struct sockaddr_in6 *)addrs->ai_addr)->sin6_addr;
206
0
        freeaddrinfo(addrs);
207
0
    } else {
208
0
        DEBUGMSGTL(("netsnmp_sockaddr_in6", "Failed to resolve IPv6 hostname\n"));
209
0
    }
210
0
    return 1;
211
#elif defined(HAVE_GETIPNODEBYNAME)
212
    struct hostent *hp;
213
    int             err;
214
215
    hp = getipnodebyname(hostname, AF_INET6, 0, &err);
216
    if (hp == NULL) {
217
        DEBUGMSGTL(("netsnmp_sockaddr_in6",
218
                    "hostname (couldn't resolve = %d)\n", err));
219
        return 0;
220
    }
221
    DEBUGMSGTL(("netsnmp_sockaddr_in6", "hostname (resolved okay)\n"));
222
    memcpy(addr, hp->h_addr, hp->h_length);
223
    return 1;
224
#elif defined(HAVE_GETHOSTBYNAME)
225
    struct hostent *hp;
226
227
    hp = netsnmp_gethostbyname(hostname);
228
    if (hp == NULL) {
229
        DEBUGMSGTL(("netsnmp_sockaddr_in6",
230
                    "hostname (couldn't resolve)\n"));
231
        return 0;
232
    }
233
    if (hp->h_addrtype != AF_INET6) {
234
        DEBUGMSGTL(("netsnmp_sockaddr_in6", "hostname (not AF_INET6!)\n"));
235
        return 0;
236
    }
237
    DEBUGMSGTL(("netsnmp_sockaddr_in6", "hostname (resolved okay)\n"));
238
    memcpy(addr, hp->h_addr, hp->h_length);
239
    return 1;
240
#else                           /*HAVE_GETHOSTBYNAME */
241
    /*
242
     * There is no name resolving function available.
243
     */
244
    snmp_log(LOG_ERR,
245
             "no getaddrinfo()/getipnodebyname()/gethostbyname()\n");
246
    return 0;
247
#endif                          /*HAVE_GETHOSTBYNAME */
248
9
}
249
250
int
251
netsnmp_sockaddr_in6_2(struct sockaddr_in6 *addr,
252
                       const char *inpeername, const char *default_target)
253
774
{
254
774
    struct netsnmp_ep ep;
255
774
    int ret;
256
257
774
    ret = netsnmp_sockaddr_in6_3(&ep, inpeername, default_target);
258
774
    if (ret == 0)
259
11
        return 0;
260
763
    *addr = ep.a.sin6;
261
763
    return ret;
262
774
}
263
264
int
265
netsnmp_sockaddr_in6_3(struct netsnmp_ep *ep,
266
                       const char *inpeername, const char *default_target)
267
774
{
268
774
    struct sockaddr_in6 *addr = &ep->a.sin6;
269
774
    struct netsnmp_ep_str ep_str;
270
774
    char            debug_addr[INET6_ADDRSTRLEN];
271
774
    int             port;
272
273
774
    if (!ep)
274
0
        return 0;
275
276
774
    DEBUGMSGTL(("netsnmp_sockaddr_in6",
277
774
    "ep %p, peername \"%s\", default_target \"%s\"\n",
278
774
                ep, inpeername ? inpeername : "[NIL]",
279
774
    default_target ? default_target : "[NIL]"));
280
281
774
    memset(ep, 0, sizeof(*ep));
282
774
    addr->sin6_family = AF_INET6;
283
774
    addr->sin6_addr = in6addr_any;
284
774
    addr->sin6_port = htons(SNMP_PORT);
285
286
774
    memset(&ep_str, 0, sizeof(ep_str));
287
774
    port = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
288
774
                              NETSNMP_DS_LIB_DEFAULT_PORT);
289
774
    if (port != 0)
290
0
        snprintf(ep_str.port, sizeof(ep_str.port), "%d", port);
291
774
    else if (default_target &&
292
774
             !netsnmp_parse_ep_str(&ep_str, default_target))
293
0
            snmp_log(LOG_ERR, "Invalid default target %s\n",
294
0
                     default_target);
295
296
774
    if (!inpeername || !netsnmp_parse_ep_str(&ep_str, inpeername))
297
2
        return 0;
298
299
772
    if (ep_str.port[0])
300
772
        addr->sin6_port = htons(atoi(ep_str.port));
301
772
    if (ep_str.iface[0])
302
95
        strlcpy(ep->iface, ep_str.iface, sizeof(ep->iface));
303
772
    if (ep_str.addr && ep_str.addr[0]) {
304
15
        char *scope_id;
305
306
15
        scope_id = strchr(ep_str.addr, '%');
307
15
        if (scope_id) {
308
3
            *scope_id = '\0';
309
3
#if defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID)
310
3
            addr->sin6_scope_id = netsnmp_if_nametoindex(scope_id + 1);
311
3
#endif
312
3
        }
313
15
        if (!inet_pton(AF_INET6, ep_str.addr, &addr->sin6_addr) &&
314
15
            !netsnmp_resolve_v6_hostname(&addr->sin6_addr, ep_str.addr)) {
315
9
            DEBUGMSGTL(("netsnmp_sockaddr_in6", "failed to parse %s\n",
316
9
                        ep_str.addr));
317
9
            free(ep_str.addr);
318
9
            return 0;
319
9
        }
320
15
    }
321
322
763
    DEBUGMSGTL(("netsnmp_sockaddr_in6", "return { AF_INET6, [%s%%%d]:%hu }\n",
323
763
                inet_ntop(AF_INET6, &addr->sin6_addr, debug_addr,
324
763
                          sizeof(debug_addr)), (int)addr->sin6_scope_id,
325
763
                ntohs(addr->sin6_port)));
326
763
    free(ep_str.addr);
327
763
    return 1;
328
772
}
329
330
331
int
332
netsnmp_sockaddr_in6(struct sockaddr_in6 *addr,
333
                     const char *inpeername, int remote_port)
334
774
{
335
774
    char buf[sizeof(remote_port) * 3 + 2];
336
774
    sprintf(buf, ":%u", remote_port);
337
774
    return netsnmp_sockaddr_in6_2(addr, inpeername, remote_port ? buf : NULL);
338
774
}
339
340
#endif /* NETSNMP_ENABLE_IPV6 */