1
#include <net-snmp/net-snmp-config.h>
20
#include <sys/socket.h>
23
#define HAVE_IF_NAMETOINDEX
26
* Windows IPv6 support is part of WinSock2 only
30
typedef unsigned char uint8_t;
31
#undef HAVE_IF_NAMETOINDEX
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;
39
#include <netinet/in.h>
42
#include <arpa/inet.h>
55
#include <net-snmp/types.h>
56
#include <net-snmp/output_api.h>
57
#include <net-snmp/config_api.h>
59
#include <net-snmp/library/snmp_transport.h>
60
#include <net-snmp/library/snmpUDPIPv6Domain.h>
62
oid netsnmp_UDPIPv6Domain[10] = { ENTERPRISE_MIB, 3, 3, 4 };
63
static netsnmp_tdomain udp6Domain;
66
* Return a string representing the address in data, or else the "far end"
67
* address if data is NULL.
71
netsnmp_udp6_fmtaddr(netsnmp_transport *t, void *data, int len)
73
struct sockaddr_in6 *to = NULL;
75
DEBUGMSGTL(("netsnmp_udp6", "fmtaddr: t = %p, data = %p, len = %d\n", t,
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;
83
return strdup("UDP/IPv6: unknown");
85
char addr[INET6_ADDRSTRLEN];
86
char tmp[INET6_ADDRSTRLEN + 8];
88
sprintf(tmp, "[%s]:%hd",
89
inet_ntop(AF_INET6, (void *) &(to->sin6_addr), addr,
90
INET6_ADDRSTRLEN), ntohs(to->sin6_port));
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...
104
netsnmp_udp6_recv(netsnmp_transport *t, void *buf, int size,
105
void **opaque, int *olength)
108
socklen_t fromlen = sizeof(struct sockaddr_in6);
109
struct sockaddr *from;
111
if (t != NULL && t->sock >= 0) {
112
from = (struct sockaddr *) malloc(sizeof(struct sockaddr_in6));
118
memset(from, 0, fromlen);
122
rc = recvfrom(t->sock, buf, size, 0, from, &fromlen);
123
if (rc < 0 && errno != EINTR) {
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,
135
DEBUGMSGTL(("netsnmp_udp6", "recvfrom fd %d err %d (\"%s\")\n",
136
t->sock, errno, strerror(errno)));
138
*opaque = (void *) from;
139
*olength = sizeof(struct sockaddr_in6);
147
netsnmp_udp6_send(netsnmp_transport *t, void *buf, int size,
148
void **opaque, int *olength)
151
struct sockaddr *to = NULL;
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);
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));
168
rc = sendto(t->sock, buf, size, 0, to,sizeof(struct sockaddr_in6));
169
if (rc < 0 && errno != EINTR) {
180
netsnmp_udp6_close(netsnmp_transport *t)
183
if (t != NULL && t->sock >= 0) {
184
DEBUGMSGTL(("netsnmp_udp6", "close fd %d\n", t->sock));
185
#ifndef HAVE_CLOSESOCKET
188
rc = closesocket(t->sock);
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.
204
netsnmp_udp6_transport(struct sockaddr_in6 *addr, int local)
206
netsnmp_transport *t = NULL;
207
int rc = 0, udpbuf = (1 << 17);
210
if (addr == NULL || addr->sin6_family != AF_INET6) {
214
t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
219
string = netsnmp_udp6_fmtaddr(NULL, (void *) addr,
220
sizeof(struct sockaddr_in6));
221
DEBUGMSGTL(("netsnmp_udp6", "open %s %s\n", local ? "local" : "remote",
225
memset(t, 0, sizeof(netsnmp_transport));
227
t->domain = netsnmp_UDPIPv6Domain;
229
sizeof(netsnmp_UDPIPv6Domain) / sizeof(netsnmp_UDPIPv6Domain[0]);
231
t->sock = socket(PF_INET6, SOCK_DGRAM, 0);
233
netsnmp_transport_free(t);
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.
244
setsockopt(t->sock, SOL_SOCKET, SO_BSDCOMPAT, &one, sizeof(one));
246
#endif /*SO_BSDCOMPAT */
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.
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)));
260
#endif /*SO_SNDBUF */
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)));
267
#endif /*SO_RCVBUF */
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.
277
/* Try to restrict PF_INET6 socket to IPv6 communications only. */
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)));
286
rc = bind(t->sock, (struct sockaddr *) addr,
287
sizeof(struct sockaddr_in6));
289
netsnmp_udp6_close(t);
290
netsnmp_transport_free(t);
293
t->local = malloc(18);
294
if (t->local == NULL) {
295
netsnmp_udp6_close(t);
296
netsnmp_transport_free(t);
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;
306
* This is a client session. Save the address in the
307
* transport-specific data pointer for later use by netsnmp_udp6_send.
310
t->data = malloc(sizeof(struct sockaddr_in6));
311
if (t->data == NULL) {
312
netsnmp_transport_free(t);
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);
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;
330
* 16-bit length field, 8 byte UDP header, 40 byte IPv6 header.
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;
338
t->f_fmtaddr = netsnmp_udp6_fmtaddr;
346
netsnmp_sockaddr_in6(struct sockaddr_in6 *addr,
347
const char *inpeername, int remote_port)
349
char *cp = NULL, *peername = NULL;
350
char debug_addr[INET6_ADDRSTRLEN];
352
struct addrinfo *addrs = NULL;
353
struct addrinfo hint;
355
#elif HAVE_GETIPNODEBYNAME
356
struct hostent *hp = NULL;
358
#elif HAVE_GETHOSTBYNAME
359
struct hostent *hp = NULL;
366
DEBUGMSGTL(("netsnmp_sockaddr_in6", "addr %p, peername \"%s\"\n",
367
addr, inpeername ? inpeername : "[NIL]"));
369
memset(addr, 0, sizeof(struct sockaddr_in6));
370
addr->sin6_family = AF_INET6;
371
addr->sin6_addr = in6addr_any;
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));
380
addr->sin6_port = htons(SNMP_PORT);
383
if (inpeername != NULL) {
385
* Duplicate the peername because we might want to mank around with
389
peername = strdup(inpeername);
390
if (peername == NULL) {
394
for (cp = peername; *cp && isdigit((int) *cp); cp++);
395
if (!*cp && atoi(peername) != 0) {
397
* Okay, it looks like JUST a port number.
399
DEBUGMSGTL(("netsnmp_sockaddr_in6", "totally numeric: %d\n",
401
addr->sin6_port = htons(atoi(peername));
406
* See if it is an IPv6 address, which covered with square brankets
407
* with an appended :port.
409
if (*peername == '[') {
410
cp = strchr(peername, ']');
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
420
#ifdef HAVE_IF_NAMETOINDEX
421
unsigned int if_index = 0;
424
scope_id = strchr(peername + 1, '%');
425
if (scope_id != NULL) {
427
#ifdef HAVE_IF_NAMETOINDEX
428
if_index = if_nametoindex(scope_id + 1);
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",
438
addr->sin6_port = htons(atoi(cp + 2));
439
#ifdef HAVE_IF_NAMETOINDEX
440
addr->sin6_scope_id = if_index;
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;
457
if (scope_id != NULL) {
464
cp = strrchr(peername, ':');
467
#ifdef HAVE_IF_NAMETOINDEX
468
unsigned int if_index = 0;
471
scope_id = strchr(peername + 1, '%');
472
if (scope_id != NULL) {
474
#ifdef HAVE_IF_NAMETOINDEX
475
if_index = if_nametoindex(scope_id + 1);
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",
484
addr->sin6_port = htons(atoi(cp + 1));
485
#ifdef HAVE_IF_NAMETOINDEX
486
addr->sin6_scope_id = if_index;
490
if (scope_id != NULL) {
497
* See if it is JUST an IPv6 address.
499
if (inet_pton(AF_INET6, peername, (void *) &(addr->sin6_addr))) {
500
DEBUGMSGTL(("netsnmp_sockaddr_in6", "just IPv6 address\n"));
505
* Well, it must be a hostname then, possibly with an appended :port.
506
* Sort that out first.
509
cp = strrchr(peername, ':');
512
if (atoi(cp + 1) != 0) {
513
DEBUGMSGTL(("netsnmp_sockaddr_in6",
514
"hostname(?) with port suffix :%d\n",
516
addr->sin6_port = htons(atoi(cp + 1));
519
* No idea, looks bogus but we might as well pass the full thing to
520
* the name resolver below.
523
DEBUGMSGTL(("netsnmp_sockaddr_in6",
524
"hostname(?) with embedded ':'?\n"));
531
memset(&hint, 0, sizeof hint);
533
hint.ai_family = PF_INET6;
534
hint.ai_socktype = SOCK_DGRAM;
535
hint.ai_protocol = 0;
537
err = getaddrinfo(peername, NULL, &hint, &addrs);
539
snmp_log(LOG_ERR, "getaddrinfo: %s %s\n", peername,
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);
551
DEBUGMSGTL(("netsnmp_sockaddr_in6",
552
"hostname (couldn't resolve = %d)\n", err));
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);
561
DEBUGMSGTL(("netsnmp_sockaddr_in6",
562
"hostname (couldn't resolve)\n"));
566
if (hp->h_addrtype != AF_INET6) {
567
DEBUGMSGTL(("netsnmp_sockaddr_in6",
568
"hostname (not AF_INET6!)\n"));
572
DEBUGMSGTL(("netsnmp_sockaddr_in6",
573
"hostname (resolved okay)\n"));
574
memcpy(&(addr->sin6_addr), hp->h_addr, hp->h_length);
577
#else /*HAVE_GETHOSTBYNAME */
579
* There is no name resolving function available.
582
"no getaddrinfo()/getipnodebyname()/gethostbyname()\n");
585
#endif /*HAVE_GETHOSTBYNAME */
587
DEBUGMSGTL(("netsnmp_sockaddr_in6", "NULL peername"));
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)));
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.
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.
615
inet_make_mask_addr(int pf, void *dst, int masklength)
618
unsigned long Mask = 0;
619
int maskBit = 0x80000000L;
620
unsigned char mask = 0;
621
unsigned char maskbit = 0x80L;
627
if (masklength < 0 || masklength > 32)
630
((struct in_addr *) dst)->s_addr = 0;
632
while (masklength--) {
636
((struct in_addr *) dst)->s_addr = htonl(Mask);
640
if (masklength < 0 || masklength > 128)
644
for (i = 0; i < 16; i++) {
645
(*(uint8_t *) (&((struct in6_addr *) dst)->s6_addr[i])) = 0x00;
648
j = (int) masklength / 8;
651
for (i = 0; i < j; i++) {
652
(*(uint8_t *) (&((struct in6_addr *) dst)->s6_addr[i])) = 0xff;
658
(*(uint8_t *) (&((struct in6_addr *) dst)->s6_addr[j])) = mask;
661
return -1; /* unsupported protocol family */
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.
673
* 0 if the input data src and dst have the same size
674
* -1 if the the input data wasn't valid.
678
inet_addr_complement(int pf, void *src, void *dst)
683
if (sizeof(src) != sizeof(dst))
688
((struct in_addr *) dst)->s_addr =
689
~((struct in_addr *) src)->s_addr;
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])))
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.
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
715
inet_addr_and(int pf, void *src1, void *src2, void *dst)
719
if (sizeof(src1) != sizeof(src2) || sizeof(src2) != sizeof(dst))
724
((struct in_addr *) dst)->s_addr =
725
((struct in_addr *) src1)->s_addr & ((struct in_addr *) src2)->
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]));
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.
750
* Must spefiey protocol family in pf.
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.
760
inet_addrs_consistence(int pf, void *net, void *mask)
762
struct sockaddr_in *tmp, *dst;
763
struct sockaddr_in6 *tmp6, *dst6;
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()");
777
dst = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in));
778
memset(dst, 0, sizeof(*dst));
779
dst->sin_family = PF_INET;
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()");
788
ret = ((dst->sin_addr.s_addr == INADDR_ANY) ? 0 : -1);
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()");
802
dst6 = (struct sockaddr_in6 *) malloc(sizeof(struct sockaddr_in6));
803
memset(dst6, 0, sizeof(*dst6));
804
dst6->sin6_family = PF_INET6;
806
(PF_INET6, (struct in6_addr *) net, &tmp6->sin6_addr,
808
config_perror("Fail in function of inet_addr_and()");
813
ret = (IN6_IS_ADDR_UNSPECIFIED(&dst6->sin6_addr) == 1 ? 0 : -1);
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.
830
* Must spefiey protocol family in pf.
832
* 0 if address "from" masked by address "mask" is eqaul to
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
844
masked_address_are_equal(int af, struct sockaddr_storage *from,
845
struct sockaddr_storage *mask,
846
struct sockaddr_storage *network)
849
struct sockaddr_storage ss;
850
memset(&ss, 0, sizeof(ss));
854
if (mask->ss_family != PF_INET || network->ss_family != PF_INET) {
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) {
870
if (mask->ss_family != PF_INET6 || network->ss_family != PF_INET6) {
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)
881
if (IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6 *) &ss)->sin6_addr,
882
&((struct sockaddr_in6 *) network)->
895
* The following functions provide the "com2sec6" configuration token
896
* functionality for compatibility.
899
#define EXAMPLE_NETWORK "NETWORK"
900
#define EXAMPLE_COMMUNITY "COMMUNITY"
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;
910
com2Sec6Entry *com2Sec6List = NULL, *com2Sec6ListLast = NULL;
914
memmove_com2Sec6Entry(com2Sec6Entry * c,
917
struct sockaddr_in6 net, struct sockaddr_in6 mask)
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));
928
netsnmp_udp6_parse_security(const char *token, char *param)
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;
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;
945
* Get security, source address/netmask and community strings.
947
secName = strtok(param, "\t\n ");
948
if (secName == NULL) {
949
config_perror("missing NAME parameter");
951
} else if (strlen(secName) > (VACMSTRINGLEN - 1)) {
952
config_perror("security name too long");
955
source = strtok(NULL, "\t\n ");
956
if (source == NULL) {
957
config_perror("missing SOURCE parameter");
959
} else if (strncmp(source, EXAMPLE_NETWORK, strlen(EXAMPLE_NETWORK)) ==
961
config_perror("example config NETWORK not properly configured");
964
community = strtok(NULL, "\t\n ");
965
if (community == NULL) {
966
config_perror("missing COMMUNITY parameter\n");
970
(community, EXAMPLE_COMMUNITY, strlen(EXAMPLE_COMMUNITY))
972
config_perror("example config COMMUNITY not properly configured");
974
} else if (strlen(community) > (VACMSTRINGLEN - 1)) {
975
config_perror("community name too long");
980
* Process the source address/netmask string.
982
cp = strchr(source, '/');
992
* Deal with the network part first.
994
if ((strcmp(source, "default") == 0) || (strcmp(source, "::") == 0)) {
995
strnetwork = strdup("0::0");
996
strmask = strdup("0::0");
998
inet_pton(AF_INET6, strnetwork, &net.sin6_addr);
999
inet_pton(AF_INET6, strmask, &mask.sin6_addr);
1001
e = (com2Sec6Entry *) malloc(sizeof(com2Sec6Entry));
1003
config_perror("memory error");
1007
* Everything is okay. Copy the parameters to the structure allocated
1008
* above and add it to END of the list.
1010
if (strmask != NULL && strnetwork != NULL) {
1011
DEBUGMSGTL(("netsnmp_udp6_parse_security",
1012
"<\"%s\", %s/%s> => \"%s\"\n", community,
1013
strnetwork, strmask, secName));
1017
DEBUGMSGTL(("netsnmp_udp6_parse_security",
1018
"Couldn't allocate enough memory\n"));
1020
memmove_com2Sec6Entry(e, secName, community, net, mask);
1021
if (com2Sec6ListLast != NULL) {
1022
com2Sec6ListLast->next = e;
1023
com2Sec6ListLast = e;
1025
com2Sec6ListLast = com2Sec6List = e;
1030
* Try interpreting as IPv6 address.
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);
1036
if (strchr(strmask, ':')) {
1037
if (inet_pton(PF_INET6, strmask, &net.sin6_addr) != 1) {
1038
config_perror("bad mask");
1042
if (inet_make_mask_addr
1043
(PF_INET6, &mask.sin6_addr, atoi(strmask)) != 0) {
1044
config_perror("bad mask");
1051
* Check that the network and mask are consistent.
1053
if (inet_addrs_consistence
1054
(PF_INET6, &net.sin6_addr, &mask.sin6_addr) != 0) {
1055
config_perror("source/mask mismatch");
1059
e = (com2Sec6Entry *) malloc(sizeof(com2Sec6Entry));
1061
config_perror("memory error");
1066
* Everything is okay. Copy the parameters to the structure allocated
1067
* above and add it to END of the list.
1069
if (strmask != NULL && strnetwork != NULL) {
1070
DEBUGMSGTL(("netsnmp_udp6_parse_security",
1071
"<\"%s\", %s/%s> => \"%s\"\n", community,
1072
strnetwork, strmask, secName));
1076
DEBUGMSGTL(("netsnmp_udp6_parse_security",
1077
"Couldn't allocate enough memory\n"));
1079
memmove_com2Sec6Entry(e, secName, community, net, mask);
1080
if (com2Sec6ListLast != NULL) {
1081
com2Sec6ListLast->next = e;
1082
com2Sec6ListLast = e;
1084
com2Sec6ListLast = com2Sec6List = e;
1089
* Nope, Must be a hostname.
1091
struct addrinfo hints, *ai, *res;
1092
char hbuf[NI_MAXHOST];
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));
1103
for (ai = res; ai != NULL; ai = ai->ai_next) {
1105
(ai->ai_addr, ai->ai_addrlen, hbuf, sizeof(hbuf), NULL,
1106
0, NI_NUMERICHOST)) {
1107
config_perror("getnameinfo failed");
1109
memmove(ai->ai_addr, &net, sizeof(struct sockaddr_in6));
1110
inet_make_mask_addr(AF_INET6, &mask.sin6_addr, 127);
1112
e = (com2Sec6Entry *) malloc(sizeof(com2Sec6Entry));
1114
config_perror("memory error");
1119
* Everything is okay. Copy the parameters to the structure allocated
1120
* above and add it to END of the list.
1122
DEBUGMSGTL(("netsnmp_udp6_parse_security",
1123
"<\"%s\", %s> => \"%s\"\n", community, hbuf,
1125
memmove_com2Sec6Entry(e, secName, community, net, mask);
1126
if (com2Sec6ListLast != NULL) {
1127
com2Sec6ListLast->next = e;
1128
com2Sec6ListLast = e;
1130
com2Sec6ListLast = com2Sec6List = e;
1143
netsnmp_udp6_com2Sec6List_free(void)
1145
com2Sec6Entry *e = com2Sec6List;
1147
com2Sec6Entry *tmp = e;
1151
com2Sec6List = com2Sec6ListLast = NULL;
1156
netsnmp_udp6_agent_config_tokens_register(void)
1158
register_app_config_handler("com2sec6", netsnmp_udp6_parse_security,
1159
netsnmp_udp6_com2Sec6List_free,
1160
"name IPv6-network-address[/netmask] community");
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.
1173
netsnmp_udp6_getSecName(void *opaque, int olength,
1174
const char *community,
1175
int community_len, char **secName)
1178
struct sockaddr_in6 *from = (struct sockaddr_in6 *) opaque;
1179
char *ztcommunity = NULL;
1180
char str6[INET6_ADDRSTRLEN];
1183
* Special case if there are NO entries (as opposed to no MATCHING
1187
if (com2Sec6List == NULL) {
1188
DEBUGMSGTL(("netsnmp_udp6_getSecName", "no com2sec entries\n"));
1189
if (secName != NULL) {
1196
* If there is no IPv6 source address,
1197
* then there can be no valid security name.
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) {
1210
ztcommunity = (char *) malloc(community_len + 1);
1211
if (ztcommunity != NULL) {
1212
memcpy(ztcommunity, community, community_len);
1213
ztcommunity[community_len] = '\0';
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));
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));
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->
1232
DEBUGMSG(("netsnmp_udp6_getSecName", "... SUCCESS\n"));
1233
if (secName != NULL) {
1234
*secName = c->secName;
1238
DEBUGMSG(("netsnmp_udp6_getSecName", "... nope\n"));
1240
if (ztcommunity != NULL) {
1247
netsnmp_udp6_create_tstring(const char *string, int local)
1249
struct sockaddr_in6 addr;
1251
if (netsnmp_sockaddr_in6(&addr, string, 0)) {
1252
return netsnmp_udp6_transport(&addr, local);
1262
* http://www.ietf.org/internet-drafts/draft-ietf-ops-taddress-mib-01.txt
1264
* (or newer equivalent) for details of the TC which we are using for
1269
netsnmp_udp6_create_ostring(const u_char * o, size_t o_len, int local)
1271
struct sockaddr_in6 addr;
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);
1285
netsnmp_udp6_ctor(void)
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";
1297
netsnmp_tdomain_register(&udp6Domain);