summaryrefslogtreecommitdiff
path: root/snmplib/transports/snmpIPv6BaseDomain.c
diff options
context:
space:
mode:
Diffstat (limited to 'snmplib/transports/snmpIPv6BaseDomain.c')
-rw-r--r--snmplib/transports/snmpIPv6BaseDomain.c426
1 files changed, 426 insertions, 0 deletions
diff --git a/snmplib/transports/snmpIPv6BaseDomain.c b/snmplib/transports/snmpIPv6BaseDomain.c
new file mode 100644
index 0000000..9bad950
--- /dev/null
+++ b/snmplib/transports/snmpIPv6BaseDomain.c
@@ -0,0 +1,426 @@
+/* IPV6 base transport support functions
+ */
+
+#include <net-snmp/net-snmp-config.h>
+
+#ifdef NETSNMP_ENABLE_IPV6
+
+#include <net-snmp/types.h>
+#include <net-snmp/library/snmpIPv6BaseDomain.h>
+#include <net-snmp/library/system.h>
+
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <ctype.h>
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+#if HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#if HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+
+#if HAVE_DMALLOC_H
+#include <dmalloc.h>
+#endif
+
+#include <net-snmp/types.h>
+#include <net-snmp/library/snmp_debug.h>
+#include <net-snmp/library/default_store.h>
+#include <net-snmp/library/snmp_logging.h>
+
+#include "inet_ntop.h"
+#include "inet_pton.h"
+
+
+#if defined(WIN32) && !defined(IF_NAMESIZE)
+#define IF_NAMESIZE 12
+#endif
+
+
+#if defined(HAVE_WINSOCK_H) && !defined(mingw32)
+static const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+#endif
+
+
+static unsigned
+netsnmp_if_nametoindex(const char *ifname)
+{
+#if defined(WIN32)
+ return atoi(ifname);
+#elif defined(HAVE_IF_NAMETOINDEX)
+ return if_nametoindex(ifname);
+#else
+ return 0;
+#endif
+}
+
+static char *
+netsnmp_if_indextoname(unsigned ifindex, char *ifname)
+{
+#if defined(WIN32)
+ snprintf(ifname, IF_NAMESIZE, "%u", ifindex);
+ return ifname;
+#elif defined(HAVE_IF_NAMETOINDEX)
+ return if_indextoname(ifindex, ifname);
+#else
+ return NULL;
+#endif
+}
+
+char *
+netsnmp_ipv6_fmtaddr(const char *prefix, netsnmp_transport *t,
+ void *data, int len)
+{
+ struct sockaddr_in6 *to = NULL;
+ char addr[INET6_ADDRSTRLEN];
+ char tmp[INET6_ADDRSTRLEN + 18];
+
+ DEBUGMSGTL(("netsnmp_ipv6", "fmtaddr: t = %p, data = %p, len = %d\n", t,
+ data, len));
+ if (data != NULL && len == sizeof(struct sockaddr_in6)) {
+ to = (struct sockaddr_in6 *) data;
+ } else if (t != NULL && t->data != NULL) {
+ to = (struct sockaddr_in6 *) t->data;
+ }
+ if (to == NULL) {
+ snprintf(tmp, sizeof(tmp), "%s: unknown", prefix);
+ } else {
+ char scope_id[IF_NAMESIZE + 1] = "";
+
+#if defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID)
+ if (to->sin6_scope_id
+ && netsnmp_if_indextoname(to->sin6_scope_id, &scope_id[1])) {
+ scope_id[0] = '%';
+ }
+#endif
+ snprintf(tmp, sizeof(tmp), "%s: [%s%s]:%hu", prefix,
+ inet_ntop(AF_INET6, (void *) &(to->sin6_addr), addr,
+ INET6_ADDRSTRLEN), scope_id, ntohs(to->sin6_port));
+ }
+ tmp[sizeof(tmp)-1] = '\0';
+ return strdup(tmp);
+}
+
+int
+netsnmp_sockaddr_in6_2(struct sockaddr_in6 *addr,
+ const char *inpeername, const char *default_target)
+{
+ char *cp = NULL, *peername = NULL;
+ char debug_addr[INET6_ADDRSTRLEN];
+#if HAVE_GETADDRINFO
+ struct addrinfo *addrs = NULL;
+ int err;
+#elif HAVE_GETIPNODEBYNAME
+ struct hostent *hp = NULL;
+ int err;
+#elif HAVE_GETHOSTBYNAME
+ struct hostent *hp = NULL;
+#endif
+ int portno;
+
+ if (addr == NULL) {
+ return 0;
+ }
+
+ DEBUGMSGTL(("netsnmp_sockaddr_in6",
+ "addr %p, peername \"%s\", default_target \"%s\"\n",
+ addr, inpeername ? inpeername : "[NIL]",
+ default_target ? default_target : "[NIL]"));
+
+ memset(addr, 0, sizeof(struct sockaddr_in6));
+ addr->sin6_family = AF_INET6;
+ addr->sin6_addr = in6addr_any;
+ addr->sin6_port = htons((u_short)SNMP_PORT);
+
+ {
+ int port = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_DEFAULT_PORT);
+ if (port != 0)
+ addr->sin6_port = htons((u_short)port);
+ else if (default_target != NULL)
+ netsnmp_sockaddr_in6_2(addr, default_target, NULL);
+ }
+
+ if (inpeername != NULL) {
+ /*
+ * Duplicate the peername because we might want to mank around with
+ * it.
+ */
+
+ peername = strdup(inpeername);
+ if (peername == NULL) {
+ return 0;
+ }
+
+ for (cp = peername; *cp && isdigit((unsigned char) *cp); cp++);
+ portno = atoi(peername);
+ if (!*cp && portno != 0) {
+ /*
+ * Okay, it looks like JUST a port number.
+ */
+ DEBUGMSGTL(("netsnmp_sockaddr_in6", "totally numeric: %d\n",
+ portno));
+ addr->sin6_port = htons((u_short)portno);
+ goto resolved;
+ }
+
+ /*
+ * See if it is an IPv6 address covered with square brackets. Also check
+ * for an appended :port.
+ */
+ if (*peername == '[') {
+ cp = strchr(peername, ']');
+ if (cp != NULL) {
+ /*
+ * See if it is an IPv6 link-local address with interface
+ * name as <zone_id>, like fe80::1234%eth0.
+ * Please refer to the internet draft, IPv6 Scoped Address Architecture
+ * http://www.ietf.org/internet-drafts/draft-ietf-ipngwg-scoping-arch-04.txt
+ *
+ */
+ char *scope_id;
+ unsigned int if_index = 0;
+ *cp = '\0';
+ scope_id = strchr(peername + 1, '%');
+ if (scope_id != NULL) {
+ *scope_id = '\0';
+ if_index = netsnmp_if_nametoindex(scope_id + 1);
+ }
+ if (*(cp + 1) == ':') {
+ portno = atoi(cp+2);
+ if (portno != 0 &&
+ inet_pton(AF_INET6, peername + 1,
+ (void *) &(addr->sin6_addr))) {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6",
+ "IPv6 address with port suffix :%d\n",
+ portno));
+ if (portno > 0 && portno < 0xffff) {
+ addr->sin6_port = htons((u_short)portno);
+ } else {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6", "invalid port number: %d", portno));
+ return 0;
+ }
+
+#if defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID)
+ addr->sin6_scope_id = if_index;
+#endif
+ goto resolved;
+ }
+ } else {
+ if (inet_pton
+ (AF_INET6, peername + 1,
+ (void *) &(addr->sin6_addr))) {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6",
+ "IPv6 address with square brackets\n"));
+ portno = netsnmp_ds_get_int(NETSNMP_DS_LIBRARY_ID,
+ NETSNMP_DS_LIB_DEFAULT_PORT);
+ if (portno <= 0)
+ portno = SNMP_PORT;
+ addr->sin6_port = htons((u_short)portno);
+#if defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID)
+ addr->sin6_scope_id = if_index;
+#endif
+ goto resolved;
+ }
+ }
+ if (scope_id != NULL) {
+ *scope_id = '%';
+ }
+ *cp = ']';
+ }
+ }
+
+ cp = strrchr(peername, ':');
+ if (cp != NULL) {
+ char *scope_id;
+ unsigned int if_index = 0;
+ *cp = '\0';
+ scope_id = strchr(peername + 1, '%');
+ if (scope_id != NULL) {
+ *scope_id = '\0';
+ if_index = netsnmp_if_nametoindex(scope_id + 1);
+ }
+ portno = atoi(cp + 1);
+ if (portno != 0 &&
+ inet_pton(AF_INET6, peername,
+ (void *) &(addr->sin6_addr))) {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6",
+ "IPv6 address with port suffix :%d\n",
+ atoi(cp + 1)));
+ if (portno > 0 && portno < 0xffff) {
+ addr->sin6_port = htons((u_short)portno);
+ } else {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6", "invalid port number: %d", portno));
+ return 0;
+ }
+
+#if defined(HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID)
+ addr->sin6_scope_id = if_index;
+#endif
+ goto resolved;
+ }
+ if (scope_id != NULL) {
+ *scope_id = '%';
+ }
+ *cp = ':';
+ }
+
+ /*
+ * See if it is JUST an IPv6 address.
+ */
+ if (inet_pton(AF_INET6, peername, (void *) &(addr->sin6_addr))) {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6", "just IPv6 address\n"));
+ goto resolved;
+ }
+
+ /*
+ * Well, it must be a hostname then, possibly with an appended :port.
+ * Sort that out first.
+ */
+
+ cp = strrchr(peername, ':');
+ if (cp != NULL) {
+ *cp = '\0';
+ portno = atoi(cp + 1);
+ if (portno != 0) {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6",
+ "hostname(?) with port suffix :%d\n",
+ portno));
+ if (portno > 0 && portno < 0xffff) {
+ addr->sin6_port = htons((u_short)portno);
+ } else {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6", "invalid port number: %d", portno));
+ return 0;
+ }
+
+ } else {
+ /*
+ * No idea, looks bogus but we might as well pass the full thing to
+ * the name resolver below.
+ */
+ *cp = ':';
+ DEBUGMSGTL(("netsnmp_sockaddr_in6",
+ "hostname(?) with embedded ':'?\n"));
+ }
+ /*
+ * Fall through.
+ */
+ }
+
+ if (peername[0] == '\0') {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6", "empty hostname\n"));
+ free(peername);
+ return 0;
+ }
+
+#if HAVE_GETADDRINFO
+ {
+ struct addrinfo hint = { 0 };
+ hint.ai_flags = 0;
+ hint.ai_family = PF_INET6;
+ hint.ai_socktype = SOCK_DGRAM;
+ hint.ai_protocol = 0;
+
+ err = netsnmp_getaddrinfo(peername, NULL, &hint, &addrs);
+ }
+ if (err != 0) {
+#if HAVE_GAI_STRERROR
+ snmp_log(LOG_ERR, "getaddrinfo(\"%s\", NULL, ...): %s\n", peername,
+ gai_strerror(err));
+#else
+ snmp_log(LOG_ERR, "getaddrinfo(\"%s\", NULL, ...): (error %d)\n",
+ peername, err);
+#endif
+ free(peername);
+ return 0;
+ }
+ if (addrs != NULL) {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6", "hostname (resolved okay)\n"));
+ memcpy(&addr->sin6_addr,
+ &((struct sockaddr_in6 *) addrs->ai_addr)->sin6_addr,
+ sizeof(struct in6_addr));
+ freeaddrinfo(addrs);
+ }
+ else {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6", "Failed to resolve IPv6 hostname\n"));
+ }
+#elif HAVE_GETIPNODEBYNAME
+ hp = getipnodebyname(peername, AF_INET6, 0, &err);
+ if (hp == NULL) {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6",
+ "hostname (couldn't resolve = %d)\n", err));
+ free(peername);
+ return 0;
+ }
+ DEBUGMSGTL(("netsnmp_sockaddr_in6", "hostname (resolved okay)\n"));
+ memcpy(&(addr->sin6_addr), hp->h_addr, hp->h_length);
+#elif HAVE_GETHOSTBYNAME
+ hp = netsnmp_gethostbyname(peername);
+ if (hp == NULL) {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6",
+ "hostname (couldn't resolve)\n"));
+ free(peername);
+ return 0;
+ } else {
+ if (hp->h_addrtype != AF_INET6) {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6",
+ "hostname (not AF_INET6!)\n"));
+ free(peername);
+ return 0;
+ } else {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6",
+ "hostname (resolved okay)\n"));
+ memcpy(&(addr->sin6_addr), hp->h_addr, hp->h_length);
+ }
+ }
+#else /*HAVE_GETHOSTBYNAME */
+ /*
+ * There is no name resolving function available.
+ */
+ snmp_log(LOG_ERR,
+ "no getaddrinfo()/getipnodebyname()/gethostbyname()\n");
+ free(peername);
+ return 0;
+#endif /*HAVE_GETHOSTBYNAME */
+ } else {
+ DEBUGMSGTL(("netsnmp_sockaddr_in6", "NULL peername"));
+ return 0;
+ }
+
+ resolved:
+ DEBUGMSGTL(("netsnmp_sockaddr_in6", "return { AF_INET6, [%s]:%hu }\n",
+ inet_ntop(AF_INET6, &addr->sin6_addr, debug_addr,
+ sizeof(debug_addr)), ntohs(addr->sin6_port)));
+ free(peername);
+ return 1;
+}
+
+
+int
+netsnmp_sockaddr_in6(struct sockaddr_in6 *addr,
+ const char *inpeername, int remote_port)
+{
+ char buf[sizeof(remote_port) * 3 + 2];
+ sprintf(buf, ":%u", remote_port);
+ return netsnmp_sockaddr_in6_2(addr, inpeername, remote_port ? buf : NULL);
+}
+
+#endif /* NETSNMP_ENABLE_IPV6 */