Return network prefixes when available

Solves #6525 on Vista+.  Win2k still works using the old MIB method
(which doesn't support ipv6).  Win2k3 and XP are still busted for
unknown reasons.
unstable
James Lee 2012-03-16 01:46:41 -06:00
parent 916f23fe4e
commit 9aaf6af072
6 changed files with 105 additions and 38 deletions

View File

@ -1,6 +1,7 @@
#include "precomp.h"
#ifdef _WIN32
#include <iptypes.h>
#include <ws2ipdef.h>
#endif
@ -101,13 +102,18 @@ DWORD get_interfaces_windows(Remote *remote, Packet *response) {
// index, name (description), MAC addr, mtu, flags, IP addr, netmask, maybe scope id
// In some cases, the interface will have multiple addresses, so we'll realloc
// this when necessary, but this will cover the common case.
DWORD allocd_entries = 10;
Tlv *entries = (Tlv *)malloc(sizeof(Tlv) * 10);
DWORD allocd_entries = 20;
Tlv *entries = (Tlv *)malloc(sizeof(Tlv) * 20);
int prefixes[30];
int prefixes_cnt = 0;
DWORD mtu_bigendian;
DWORD interface_index_bigendian;
ULONG flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_DNS_SERVER;
ULONG flags = GAA_FLAG_INCLUDE_PREFIX
| GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_MULTICAST
| GAA_FLAG_SKIP_ANYCAST;
LPSOCKADDR sockaddr;
@ -117,9 +123,15 @@ DWORD get_interfaces_windows(Remote *remote, Packet *response) {
ULONG outBufLen = 0;
DWORD (WINAPI *gaa)(DWORD, DWORD, void *, void *, void *);
// Use the larger version so we're guaranteed to have a large enough struct
IP_ADAPTER_UNICAST_ADDRESS_LH *pAddr;
// Use the newer version so we're guaranteed to have a large enough struct.
// Unfortunately, using these probably means it won't compile on older
// versions of Visual Studio. =(
IP_ADAPTER_UNICAST_ADDRESS_LH *pAddr = NULL;
IP_ADAPTER_UNICAST_ADDRESS_LH *pPref = NULL;
// IP_ADAPTER_PREFIX is only defined if NTDDI_VERSION > NTDDI_WINXP
// Since we request older versions of things, we have to be explicit
// when using newer structs.
IP_ADAPTER_PREFIX_XP *pPrefix = NULL;
do
{
@ -170,47 +182,75 @@ DWORD get_interfaces_windows(Remote *remote, Packet *response) {
entries[tlv_cnt].buffer = (PUCHAR)&mtu_bigendian;
tlv_cnt++;
if (pCurr->Length > 68) {
// Then this is a Longhorn struct version and it contains the
// FirstPrefix member, save it for later in case we don't have
// an OnLinkPrefixLength
pPrefix = pCurr->FirstPrefix;
}
for (pAddr = (void*)pCurr->FirstUnicastAddress; pAddr; pAddr = (void*)pAddr->Next)
{
// This loop can add up to three Tlv's - one for address, one for scope_id, one for netmask.
// Go ahead and allocate enough room for all of them.
sockaddr = pAddr->Address.lpSockaddr;
if (AF_INET != sockaddr->sa_family && AF_INET6 != sockaddr->sa_family) {
// Skip interfaces that aren't IP
continue;
}
// This loop can add up to three Tlv's - one for address, one
// for scope_id, one for netmask. Go ahead and allocate enough
// room for all of them.
if (allocd_entries < tlv_cnt+3) {
entries = realloc(entries, sizeof(Tlv) * (tlv_cnt+3));
allocd_entries += 3;
}
sockaddr = pAddr->Address.lpSockaddr;
if (pAddr->Length > 44) {
// Then this is Vista+ and the OnLinkPrefixLength member
// will be populated
pPrefix = NULL;
prefixes[prefixes_cnt] = htonl(pAddr->OnLinkPrefixLength);
} else if (pPrefix) {
// Otherwise, we have to walk the FirstPrefix linked list
prefixes[prefixes_cnt] = htonl(pPrefix->PrefixLength);
pPrefix = pPrefix->Next;
} else {
// This is XP SP0 and as far as I can tell, we have no way
// of determining the netmask short of bailing on
// this method and falling back to MIB, which doesn't
// return IPv6 addresses. Older versions (e.g. NT4, 2k)
// don't have GetAdapterAddresses, so they will have fallen
// through earlier to the MIB implementation.
}
packet_add_tlv_uint(response, TLV_TYPE_EXIT_CODE, prefixes[prefixes_cnt]);
if (prefixes[prefixes_cnt]) {
entries[tlv_cnt].header.length = 4;
entries[tlv_cnt].header.type = TLV_TYPE_IP_PREFIX;
entries[tlv_cnt].buffer = (PUCHAR)&prefixes[prefixes_cnt];
tlv_cnt++;
prefixes_cnt++;
}
if (sockaddr->sa_family == AF_INET) {
entries[tlv_cnt].header.length = 4;
entries[tlv_cnt].header.type = TLV_TYPE_IP;
entries[tlv_cnt].buffer = (PUCHAR)&(((struct sockaddr_in *)sockaddr)->sin_addr);
if (pCurr->Length > 68) {
tlv_cnt++;
entries[tlv_cnt].header.length = 4;
entries[tlv_cnt].header.type = TLV_TYPE_NETMASK;
entries[tlv_cnt].buffer = (PUCHAR)&(((struct sockaddr_in *)sockaddr)->sin_addr);
}
} else {
entries[tlv_cnt].header.length = 16;
entries[tlv_cnt].header.type = TLV_TYPE_IP;
entries[tlv_cnt].buffer = (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_addr);
tlv_cnt++;
entries[tlv_cnt].header.length = sizeof(DWORD);
entries[tlv_cnt].header.type = TLV_TYPE_IP6_SCOPE;
entries[tlv_cnt].buffer = (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_scope_id);
if (pCurr->Length > 68) {
tlv_cnt++;
entries[tlv_cnt].header.length = 16;
entries[tlv_cnt].header.type = TLV_TYPE_NETMASK;
entries[tlv_cnt].buffer = (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_addr);
}
}
tlv_cnt++;
}
// Add the interface group
packet_add_tlv_group(response, TLV_TYPE_NETWORK_INTERFACE,
entries, tlv_cnt);
@ -225,7 +265,7 @@ DWORD get_interfaces_windows(Remote *remote, Packet *response) {
return result;
}
#else
#else /* _WIN32 */
int get_interfaces_linux(Remote *remote, Packet *response) {
struct ifaces_list *ifaces = NULL;
int i;
@ -341,3 +381,5 @@ DWORD request_net_config_get_interfaces(Remote *remote, Packet *packet)
}

View File

@ -355,6 +355,12 @@
TLV_META_TYPE_GROUP, \
TLV_TYPE_EXTENSION_STDAPI, \
1423)
#define TLV_TYPE_IP_PREFIX \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_UINT, \
TLV_TYPE_EXTENSION_STDAPI, \
1424)
#define TLV_TYPE_IP \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_RAW, \

View File

@ -60,6 +60,7 @@ class Config
response.each(TLV_TYPE_NETWORK_INTERFACE) { |iface|
addrs = []
netmasks = []
scopes = []
while (a = iface.get_tlv_value(TLV_TYPE_IP, addrs.length))
# Netmasks aren't tightly associated with addresses, they're
# just thrown all together in the interface TLV ordered to
@ -67,8 +68,20 @@ class Config
# GroupTlv type for addresses containing an address, a netmask,
# and possibly a scope.
n = iface.get_tlv_value(TLV_TYPE_NETMASK, addrs.length)
if (n.nil?)
# Some systems can't report a netmask, only a network
# prefix, so figure out the netmask from that.
n = iface.get_tlv_value(TLV_TYPE_IP_PREFIX, addrs.length)
if n
n = Rex::Socket.bit2netmask(n, !!(a.length == 16))
end
else
n = Rex::Socket.addr_ntoa(n)
end
s = iface.get_tlv_value(TLV_TYPE_IP6_SCOPE, addrs.length)
scopes[addrs.length] = s if s
netmasks[addrs.length] = n if n
addrs << Rex::Socket.addr_ntoa(a)
netmasks << Rex::Socket.addr_ntoa(n) if n
end
ifaces << Interface.new(
:index => iface.get_tlv_value(TLV_TYPE_INTERFACE_INDEX),
@ -77,7 +90,8 @@ class Config
:mtu => iface.get_tlv_value(TLV_TYPE_INTERFACE_MTU),
:flags => iface.get_tlv_value(TLV_TYPE_INTERFACE_FLAGS),
:addrs => addrs,
:netmasks => netmasks
:netmasks => netmasks,
:scopes => scopes
)
}

View File

@ -35,6 +35,7 @@ class Interface
self.flags = opts[:flags]
self.addrs = opts[:addrs]
self.netmasks = opts[:netmasks]
self.scopes = opts[:scopes]
end
#
@ -108,10 +109,6 @@ class Interface
#
attr_accessor :mac_name
#
# The subnet mask associated with the IPv6 interface.
#
attr_accessor :netmask6
#
# The MTU associated with the interface.
#
attr_accessor :mtu
@ -119,7 +116,14 @@ class Interface
# The flags associated with the interface.
#
attr_accessor :flags
#
# An Array of netmasks. This will have the same number of elements as #addrs
#
attr_accessor :netmasks
#
# An Array of IPv6 address scopes. This will have the same number of elements as #addrs
#
attr_accessor :scopes
end
end; end; end; end; end; end

View File

@ -51,6 +51,7 @@ TLV_TYPE_SUBNET = TLV_META_TYPE_RAW | 1420
TLV_TYPE_NETMASK = TLV_META_TYPE_RAW | 1421
TLV_TYPE_GATEWAY = TLV_META_TYPE_RAW | 1422
TLV_TYPE_NETWORK_ROUTE = TLV_META_TYPE_GROUP | 1423
TLV_TYPE_IP_PREFIX = TLV_META_TYPE_UINT | 1424
TLV_TYPE_IP = TLV_META_TYPE_RAW | 1430
TLV_TYPE_MAC_ADDRESS = TLV_META_TYPE_RAW | 1431