diff --git a/bindings/SigarWrapper.pm b/bindings/SigarWrapper.pm index abbe5942..3151c2fd 100644 --- a/bindings/SigarWrapper.pm +++ b/bindings/SigarWrapper.pm @@ -1039,6 +1039,18 @@ use vars qw(%classes %cmds); desc => '', plat => '*' }, + { + name => 'address6', type => 'NetAddress', + desc => '', + }, + { + name => 'prefix6_length', type => 'Int', + desc => '', + }, + { + name => 'scope6', type => 'Int', + desc => '', + }, { name => 'destination', type => 'NetAddress', desc => '', diff --git a/bindings/java/src/org/hyperic/sigar/cmd/Ifconfig.java b/bindings/java/src/org/hyperic/sigar/cmd/Ifconfig.java index 0ca7a775..215e6e53 100644 --- a/bindings/java/src/org/hyperic/sigar/cmd/Ifconfig.java +++ b/bindings/java/src/org/hyperic/sigar/cmd/Ifconfig.java @@ -117,6 +117,13 @@ public class Ifconfig extends SigarCommandBase { bcast + " Mask:" + ifconfig.getNetmask()); + if (ifconfig.getPrefix6Length() != 0) { + println("\t" + + "inet6 addr: " + ifconfig.getAddress6() + "/" + + ifconfig.getPrefix6Length() + + " Scope:" + ifconfig.getScope6()); + } + println("\t" + NetFlags.getIfFlagsString(flags) + " MTU:" + ifconfig.getMtu() + diff --git a/bindings/java/src/org/hyperic/sigar/test/TestNetIf.java b/bindings/java/src/org/hyperic/sigar/test/TestNetIf.java index f84edfa4..7e7117ce 100644 --- a/bindings/java/src/org/hyperic/sigar/test/TestNetIf.java +++ b/bindings/java/src/org/hyperic/sigar/test/TestNetIf.java @@ -18,6 +18,9 @@ package org.hyperic.sigar.test; +import java.net.InetAddress; +import java.net.Inet6Address; + import org.hyperic.sigar.Sigar; import org.hyperic.sigar.SigarException; import org.hyperic.sigar.SigarNotImplementedException; @@ -44,6 +47,14 @@ public class TestNetIf extends SigarTestCase { assertTrueTrace("Address", ifconfig.getAddress()); assertTrueTrace("Netmask", ifconfig.getNetmask()); + if (ifconfig.getPrefix6Length() != 0) { + assertTrueTrace("Address6", ifconfig.getAddress6()); + InetAddress in6 = + InetAddress.getByName(ifconfig.getAddress6()); + assertTrue(in6 instanceof Inet6Address); + traceln("Link=" + in6.isLinkLocalAddress()); + } + if (!getStats) { continue; } diff --git a/bindings/ruby/examples/ifconfig.rb b/bindings/ruby/examples/ifconfig.rb index b8b87eaa..2e3181e4 100644 --- a/bindings/ruby/examples/ifconfig.rb +++ b/bindings/ruby/examples/ifconfig.rb @@ -32,6 +32,11 @@ iflist.each do |ifname| puts "\t" + "inet addr:" + ifconfig.address + ptp + bcast + " Mask:" + ifconfig.netmask + if ifconfig.prefix6_length != 0 + puts "\t" + "inet6 addr: " + ifconfig.address6 + "/" + + ifconfig.prefix6_length.to_s + " Scope:" + ifconfig.scope6.to_s + end + puts "\t" + Sigar.net_interface_flags_to_s(flags) + " MTU:" + ifconfig.mtu.to_s + diff --git a/include/sigar.h b/include/sigar.h index a8c62364..1de9dba5 100644 --- a/include/sigar.h +++ b/include/sigar.h @@ -587,6 +587,15 @@ SIGAR_DECLARE(int) sigar_net_route_list_destroy(sigar_t *sigar, #define SIGAR_NULL_HWADDR "00:00:00:00:00:00" +/* scope values from linux-2.6/include/net/ipv6.h */ +#define SIGAR_IPV6_ADDR_ANY 0x0000 +#define SIGAR_IPV6_ADDR_UNICAST 0x0001 +#define SIGAR_IPV6_ADDR_MULTICAST 0x0002 +#define SIGAR_IPV6_ADDR_LOOPBACK 0x0010 +#define SIGAR_IPV6_ADDR_LINKLOCAL 0x0020 +#define SIGAR_IPV6_ADDR_SITELOCAL 0x0040 +#define SIGAR_IPV6_ADDR_COMPATv4 0x0080 + typedef struct { char name[16]; char type[64]; @@ -596,6 +605,9 @@ typedef struct { sigar_net_address_t destination; sigar_net_address_t broadcast; sigar_net_address_t netmask; + sigar_net_address_t address6; + int prefix6_length; + int scope6; sigar_uint64_t flags, mtu, diff --git a/include/sigar_private.h b/include/sigar_private.h index ad5ba4b7..fde2465f 100644 --- a/include/sigar_private.h +++ b/include/sigar_private.h @@ -291,6 +291,30 @@ int sigar_net_connection_list_grow(sigar_net_connection_list_t *connlist); SIGAR_ZERO(&ifconfig->hwaddr.addr.mac); \ ifconfig->hwaddr.family = SIGAR_AF_LINK +int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig); + +#define sigar_net_interface_ipv6_config_init(ifconfig) \ + ifconfig->address6.family = SIGAR_AF_INET6; \ + ifconfig->prefix6_length = 0; \ + ifconfig->scope6 = 0 + +#define SIGAR_SIN6(s) ((struct sockaddr_in6 *)(s)) + +#define SIGAR_SIN6_ADDR(s) &SIGAR_SIN6(s)->sin6_addr + +#define sigar_net_interface_scope6_set(ifconfig, addr) \ + if (IN6_IS_ADDR_LINKLOCAL(addr)) \ + ifconfig->scope6 = SIGAR_IPV6_ADDR_LINKLOCAL; \ + else if (IN6_IS_ADDR_SITELOCAL(addr)) \ + ifconfig->scope6 = SIGAR_IPV6_ADDR_SITELOCAL; \ + else if (IN6_IS_ADDR_V4COMPAT(addr)) \ + ifconfig->scope6 = SIGAR_IPV6_ADDR_COMPATv4; \ + else if (IN6_IS_ADDR_LOOPBACK(addr)) \ + ifconfig->scope6 = SIGAR_IPV6_ADDR_LOOPBACK; \ + else \ + ifconfig->scope6 = SIGAR_IPV6_ADDR_ANY + int sigar_tcp_curr_estab(sigar_t *sigar, sigar_tcp_t *tcp); int sigar_who_list_create(sigar_who_list_t *wholist); diff --git a/src/os/aix/aix_sigar.c b/src/os/aix/aix_sigar.c index bac4491f..7fee1775 100644 --- a/src/os/aix/aix_sigar.c +++ b/src/os/aix/aix_sigar.c @@ -1507,6 +1507,12 @@ int sigar_net_interface_stat_get(sigar_t *sigar, } } +int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig) +{ + return SIGAR_ENOTIMPL; +} + #define IS_TCP_SERVER(state, flags) \ ((flags & SIGAR_NETCONN_SERVER) && (state == TCPS_LISTEN)) diff --git a/src/os/darwin/darwin_sigar.c b/src/os/darwin/darwin_sigar.c index b60e0af1..eff6e1d1 100644 --- a/src/os/darwin/darwin_sigar.c +++ b/src/os/darwin/darwin_sigar.c @@ -2593,6 +2593,76 @@ int sigar_net_interface_list_get(sigar_t *sigar, return sigar_ifmsg_iter(sigar, &iter); } +#include + +/* in6_prefixlen derived from freebsd/sbin/ifconfig/af_inet6.c */ +static int sigar_in6_prefixlen(struct sockaddr *netmask) +{ + struct in6_addr *addr = SIGAR_SIN6_ADDR(netmask); + u_char *name = (u_char *)addr; + int size = sizeof(*addr); + int byte, bit, plen = 0; + + for (byte = 0; byte < size; byte++, plen += 8) { + if (name[byte] != 0xff) { + break; + } + } + if (byte == size) { + return plen; + } + for (bit = 7; bit != 0; bit--, plen++) { + if (!(name[byte] & (1 << bit))) { + break; + } + } + for (; bit != 0; bit--) { + if (name[byte] & (1 << bit)) { + return 0; + } + } + byte++; + for (; byte < size; byte++) { + if (name[byte]) { + return 0; + } + } + return plen; +} + +int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig) +{ + int status = SIGAR_ENOENT; + struct ifaddrs *addrs, *ifa; + + if (getifaddrs(&addrs) != 0) { + return errno; + } + + for (ifa=addrs; ifa; ifa=ifa->ifa_next) { + if (ifa->ifa_addr && + (ifa->ifa_addr->sa_family == AF_INET6) && + strEQ(ifa->ifa_name, name)) + { + status = SIGAR_OK; + break; + } + } + + if (status == SIGAR_OK) { + struct in6_addr *addr = SIGAR_SIN6_ADDR(ifa->ifa_addr); + + sigar_net_address6_set(ifconfig->address6, addr); + sigar_net_interface_scope6_set(ifconfig, addr); + ifconfig->prefix6_length = sigar_in6_prefixlen(ifa->ifa_netmask); + } + + freeifaddrs(addrs); + + return status; +} + int sigar_net_interface_config_get(sigar_t *sigar, const char *name, sigar_net_interface_config_t *ifconfig) { @@ -2682,6 +2752,9 @@ int sigar_net_interface_config_get(sigar_t *sigar, const char *name, SIGAR_SSTRCPY(ifconfig->description, ifconfig->name); + sigar_net_interface_ipv6_config_init(ifconfig); + sigar_net_interface_ipv6_config_get(sigar, name, ifconfig); + return SIGAR_OK; } diff --git a/src/os/hpux/hpux_sigar.c b/src/os/hpux/hpux_sigar.c index 26fb314a..db1c0c5b 100644 --- a/src/os/hpux/hpux_sigar.c +++ b/src/os/hpux/hpux_sigar.c @@ -872,6 +872,12 @@ int sigar_net_interface_stat_get(sigar_t *sigar, const char *name, return SIGAR_OK; } +int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig) +{ + return SIGAR_ENOTIMPL; +} + static int net_conn_get_udp_listen(sigar_net_connection_walker_t *walker) { sigar_t *sigar = walker->sigar; diff --git a/src/os/linux/linux_sigar.c b/src/os/linux/linux_sigar.c index a9325953..1d3a9e1e 100644 --- a/src/os/linux/linux_sigar.c +++ b/src/os/linux/linux_sigar.c @@ -2092,6 +2092,45 @@ static int sigar_net_connection_get(sigar_t *sigar, return status; } +int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig) +{ + FILE *fp; + char addr[32+1], ifname[8+1]; + int status = SIGAR_ENOENT; + int idx, prefix, scope, flags; + + if (!(fp = fopen(PROC_FS_ROOT "net/if_inet6", "r"))) { + return errno; + } + + while (fscanf(fp, "%32s %02x %02x %02x %02x %8s\n", + addr, &idx, &prefix, &scope, &flags, ifname) != EOF) + { + if (strEQ(name, ifname)) { + status = SIGAR_OK; + break; + } + } + + fclose(fp); + + if (status == SIGAR_OK) { + int i=0; + unsigned char *addr6 = (unsigned char *)&(ifconfig->address6.addr.in6); + char *ptr = addr; + + for (i=0; i<16; i++, ptr+=2) { + addr6[i] = (unsigned char)hex2int(ptr, 2); + } + + ifconfig->prefix6_length = prefix; + ifconfig->scope6 = scope; + } + + return status; +} + #define SNMP_TCP_PREFIX "Tcp: " SIGAR_DECLARE(int) diff --git a/src/os/solaris/solaris_sigar.c b/src/os/solaris/solaris_sigar.c index ca159ae6..17912d04 100644 --- a/src/os/solaris/solaris_sigar.c +++ b/src/os/solaris/solaris_sigar.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -2083,6 +2084,30 @@ int sigar_net_interface_stat_get(sigar_t *sigar, const char *name, } } +int sigar_net_interface_ipv6_config_get(sigar_t *sigar, const char *name, + sigar_net_interface_config_t *ifconfig) +{ + int sock; + struct lifreq lifr; + + if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { + return errno; + } + + SIGAR_SSTRCPY(lifr.lifr_name, name); + + if (ioctl(sock, SIOCGLIFADDR, &lifr) == 0) { + struct in6_addr *addr = SIGAR_SIN6_ADDR(&lifr.lifr_addr); + + sigar_net_address6_set(ifconfig->address6, addr); + sigar_net_interface_scope6_set(ifconfig, addr); + ifconfig->prefix6_length = lifr.lifr_addrlen; + } + + close(sock); + return SIGAR_OK; +} + #define TCPQ_SIZE(s) ((s) >= 0 ? (s) : 0) static int tcp_connection_get(sigar_net_connection_walker_t *walker, diff --git a/src/os/win32/win32_sigar.c b/src/os/win32/win32_sigar.c index d395afe7..5eaeb274 100644 --- a/src/os/win32/win32_sigar.c +++ b/src/os/win32/win32_sigar.c @@ -21,6 +21,7 @@ #include "sigar_pdh.h" #include "sigar_os.h" #include "sigar_util.h" +#include "sigar_format.h" #include #define USING_WIDE_S(s) (s)->using_wide @@ -2219,12 +2220,11 @@ static int sigar_get_adapter_info(sigar_t *sigar, } static int sigar_get_adapters_addresses(sigar_t *sigar, + ULONG family, ULONG flags, PIP_ADAPTER_ADDRESSES *addrs) { ULONG size = sigar->ifconf_len; ULONG rc; - ULONG flags = - GAA_FLAG_SKIP_DNS_SERVER|GAA_FLAG_SKIP_MULTICAST; DLLMOD_INIT(iphlpapi, FALSE); @@ -2233,7 +2233,7 @@ static int sigar_get_adapters_addresses(sigar_t *sigar, } *addrs = (PIP_ADAPTER_ADDRESSES)sigar->ifconf_buf; - rc = sigar_GetAdaptersAddresses(AF_UNSPEC, + rc = sigar_GetAdaptersAddresses(family, flags, NULL, *addrs, @@ -2249,7 +2249,7 @@ static int sigar_get_adapters_addresses(sigar_t *sigar, sigar->ifconf_len); *addrs = (PIP_ADAPTER_ADDRESSES)sigar->ifconf_buf; - rc = sigar_GetAdaptersAddresses(AF_UNSPEC, + rc = sigar_GetAdaptersAddresses(family, flags, NULL, *addrs, @@ -2637,6 +2637,42 @@ sigar_net_interface_list_get(sigar_t *sigar, return SIGAR_OK; } +static int sigar_net_interface_ipv6_config_find(sigar_t *sigar, int index, + sigar_net_interface_config_t *ifconfig) +{ + int status; + PIP_ADAPTER_ADDRESSES aa, addrs; + ULONG flags = GAA_FLAG_INCLUDE_PREFIX; + + status = sigar_get_adapters_addresses(sigar, AF_UNSPEC, flags, &aa); + + if (status != SIGAR_OK) { + return status; + } + + for (addrs = aa; addrs; addrs = addrs->Next) { + PIP_ADAPTER_UNICAST_ADDRESS addr; + if (addrs->IfIndex != index) { + continue; + } + for (addr = addrs->FirstUnicastAddress; addr; addr = addr->Next) { + struct sockaddr *sa = addr->Address.lpSockaddr; + + if (sa->sa_family == AF_INET6) { + struct in6_addr *inet6 = SIGAR_SIN6_ADDR(sa); + + sigar_net_address6_set(ifconfig->address6, inet6); + sigar_net_interface_scope6_set(ifconfig, inet6); + if (addrs->FirstPrefix) { + ifconfig->prefix6_length = addrs->FirstPrefix->PrefixLength; + } + return SIGAR_OK; + } + } + } + return SIGAR_ENOENT; +} + SIGAR_DECLARE(int) sigar_net_interface_config_get(sigar_t *sigar, const char *name, @@ -2717,6 +2753,9 @@ sigar_net_interface_config_get(sigar_t *sigar, SIGAR_NIC_ETHERNET); } + sigar_net_interface_ipv6_config_init(ifconfig); + sigar_net_interface_ipv6_config_find(sigar, ifr->dwIndex, ifconfig); + return SIGAR_OK; } diff --git a/src/sigar.c b/src/sigar.c index 46f09b15..114c98b5 100644 --- a/src/sigar.c +++ b/src/sigar.c @@ -1642,6 +1642,9 @@ int sigar_net_interface_config_get(sigar_t *sigar, const char *name, SIGAR_SSTRCPY(ifconfig->description, ifconfig->name); + sigar_net_interface_ipv6_config_init(ifconfig); + sigar_net_interface_ipv6_config_get(sigar, name, ifconfig); + return SIGAR_OK; } diff --git a/src/sigar_format.c b/src/sigar_format.c index f7642c4a..5aab7eb2 100644 --- a/src/sigar_format.c +++ b/src/sigar_format.c @@ -353,7 +353,26 @@ SIGAR_DECLARE(int) sigar_net_address_equals(sigar_net_address_t *addr1, } } -#if !defined(WIN32) && !defined(NETWARE) && !defined(__hpux) +#if defined(WIN32) +static char *sigar_inet_ntop(int af, const void *src, char *dst, int cnt) +{ + struct sockaddr_in6 sa; /* note only using this for AF_INET6 */ + + memset(&sa, '\0', sizeof(sa)); + sa.sin6_family = af; + memcpy(&sa.sin6_addr, src, sizeof(sa.sin6_addr)); + + if (getnameinfo((struct sockaddr *)&sa, sizeof(sa), + dst, cnt, NULL, 0, NI_NUMERICHOST)) + { + return NULL; + } + else { + return dst; + } +} +#define sigar_inet_ntop_errno GetLastError() +#elif !defined(NETWARE) && !defined(__hpux) #define sigar_inet_ntop inet_ntop #define sigar_inet_ntop_errno errno #else @@ -365,6 +384,7 @@ SIGAR_DECLARE(int) sigar_net_address_to_string(sigar_t *sigar, sigar_net_address_t *address, char *addr_str) { + *addr_str = '\0'; switch (address->family) { case SIGAR_AF_INET6: if (sigar_inet_ntop(AF_INET6, (const void *)&address->addr.in6,