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" #include "precomp.h"
#ifdef _WIN32 #ifdef _WIN32
#include <iptypes.h>
#include <ws2ipdef.h> #include <ws2ipdef.h>
#endif #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 // 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 // In some cases, the interface will have multiple addresses, so we'll realloc
// this when necessary, but this will cover the common case. // this when necessary, but this will cover the common case.
DWORD allocd_entries = 10; DWORD allocd_entries = 20;
Tlv *entries = (Tlv *)malloc(sizeof(Tlv) * 10); Tlv *entries = (Tlv *)malloc(sizeof(Tlv) * 20);
int prefixes[30];
int prefixes_cnt = 0;
DWORD mtu_bigendian; DWORD mtu_bigendian;
DWORD interface_index_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; LPSOCKADDR sockaddr;
@ -117,9 +123,15 @@ DWORD get_interfaces_windows(Remote *remote, Packet *response) {
ULONG outBufLen = 0; ULONG outBufLen = 0;
DWORD (WINAPI *gaa)(DWORD, DWORD, void *, void *, void *); DWORD (WINAPI *gaa)(DWORD, DWORD, void *, void *, void *);
// Use the larger version so we're guaranteed to have a large enough struct // Use the newer version so we're guaranteed to have a large enough struct.
IP_ADAPTER_UNICAST_ADDRESS_LH *pAddr; // 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 do
{ {
@ -170,46 +182,74 @@ DWORD get_interfaces_windows(Remote *remote, Packet *response) {
entries[tlv_cnt].buffer = (PUCHAR)&mtu_bigendian; entries[tlv_cnt].buffer = (PUCHAR)&mtu_bigendian;
tlv_cnt++; 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) 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. sockaddr = pAddr->Address.lpSockaddr;
// Go ahead and allocate enough room for all of them. 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) { if (allocd_entries < tlv_cnt+3) {
entries = realloc(entries, sizeof(Tlv) * (tlv_cnt+3)); entries = realloc(entries, sizeof(Tlv) * (tlv_cnt+3));
allocd_entries += 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) { if (sockaddr->sa_family == AF_INET) {
entries[tlv_cnt].header.length = 4; entries[tlv_cnt].header.length = 4;
entries[tlv_cnt].header.type = TLV_TYPE_IP; entries[tlv_cnt].header.type = TLV_TYPE_IP;
entries[tlv_cnt].buffer = (PUCHAR)&(((struct sockaddr_in *)sockaddr)->sin_addr); entries[tlv_cnt].buffer = (PUCHAR)&(((struct sockaddr_in *)sockaddr)->sin_addr);
if (pCurr->Length > 68) { tlv_cnt++;
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 { } else {
entries[tlv_cnt].header.length = 16; entries[tlv_cnt].header.length = 16;
entries[tlv_cnt].header.type = TLV_TYPE_IP; entries[tlv_cnt].header.type = TLV_TYPE_IP;
entries[tlv_cnt].buffer = (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_addr); entries[tlv_cnt].buffer = (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_addr);
tlv_cnt++; tlv_cnt++;
entries[tlv_cnt].header.length = sizeof(DWORD); entries[tlv_cnt].header.length = sizeof(DWORD);
entries[tlv_cnt].header.type = TLV_TYPE_IP6_SCOPE; entries[tlv_cnt].header.type = TLV_TYPE_IP6_SCOPE;
entries[tlv_cnt].buffer = (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_scope_id); entries[tlv_cnt].buffer = (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_scope_id);
tlv_cnt++;
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 // Add the interface group
packet_add_tlv_group(response, TLV_TYPE_NETWORK_INTERFACE, packet_add_tlv_group(response, TLV_TYPE_NETWORK_INTERFACE,
@ -225,7 +265,7 @@ DWORD get_interfaces_windows(Remote *remote, Packet *response) {
return result; return result;
} }
#else #else /* _WIN32 */
int get_interfaces_linux(Remote *remote, Packet *response) { int get_interfaces_linux(Remote *remote, Packet *response) {
struct ifaces_list *ifaces = NULL; struct ifaces_list *ifaces = NULL;
int i; 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_META_TYPE_GROUP, \
TLV_TYPE_EXTENSION_STDAPI, \ TLV_TYPE_EXTENSION_STDAPI, \
1423) 1423)
#define TLV_TYPE_IP_PREFIX \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_UINT, \
TLV_TYPE_EXTENSION_STDAPI, \
1424)
#define TLV_TYPE_IP \ #define TLV_TYPE_IP \
MAKE_CUSTOM_TLV( \ MAKE_CUSTOM_TLV( \
TLV_META_TYPE_RAW, \ TLV_META_TYPE_RAW, \

View File

@ -60,6 +60,7 @@ class Config
response.each(TLV_TYPE_NETWORK_INTERFACE) { |iface| response.each(TLV_TYPE_NETWORK_INTERFACE) { |iface|
addrs = [] addrs = []
netmasks = [] netmasks = []
scopes = []
while (a = iface.get_tlv_value(TLV_TYPE_IP, addrs.length)) while (a = iface.get_tlv_value(TLV_TYPE_IP, addrs.length))
# Netmasks aren't tightly associated with addresses, they're # Netmasks aren't tightly associated with addresses, they're
# just thrown all together in the interface TLV ordered to # 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, # GroupTlv type for addresses containing an address, a netmask,
# and possibly a scope. # and possibly a scope.
n = iface.get_tlv_value(TLV_TYPE_NETMASK, addrs.length) 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) addrs << Rex::Socket.addr_ntoa(a)
netmasks << Rex::Socket.addr_ntoa(n) if n
end end
ifaces << Interface.new( ifaces << Interface.new(
:index => iface.get_tlv_value(TLV_TYPE_INTERFACE_INDEX), :index => iface.get_tlv_value(TLV_TYPE_INTERFACE_INDEX),
@ -77,7 +90,8 @@ class Config
:mtu => iface.get_tlv_value(TLV_TYPE_INTERFACE_MTU), :mtu => iface.get_tlv_value(TLV_TYPE_INTERFACE_MTU),
:flags => iface.get_tlv_value(TLV_TYPE_INTERFACE_FLAGS), :flags => iface.get_tlv_value(TLV_TYPE_INTERFACE_FLAGS),
:addrs => addrs, :addrs => addrs,
:netmasks => netmasks :netmasks => netmasks,
:scopes => scopes
) )
} }

View File

@ -35,6 +35,7 @@ class Interface
self.flags = opts[:flags] self.flags = opts[:flags]
self.addrs = opts[:addrs] self.addrs = opts[:addrs]
self.netmasks = opts[:netmasks] self.netmasks = opts[:netmasks]
self.scopes = opts[:scopes]
end end
# #
@ -108,10 +109,6 @@ class Interface
# #
attr_accessor :mac_name attr_accessor :mac_name
# #
# The subnet mask associated with the IPv6 interface.
#
attr_accessor :netmask6
#
# The MTU associated with the interface. # The MTU associated with the interface.
# #
attr_accessor :mtu attr_accessor :mtu
@ -119,7 +116,14 @@ class Interface
# The flags associated with the interface. # The flags associated with the interface.
# #
attr_accessor :flags attr_accessor :flags
#
# An Array of netmasks. This will have the same number of elements as #addrs
#
attr_accessor :netmasks 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; 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_NETMASK = TLV_META_TYPE_RAW | 1421
TLV_TYPE_GATEWAY = TLV_META_TYPE_RAW | 1422 TLV_TYPE_GATEWAY = TLV_META_TYPE_RAW | 1422
TLV_TYPE_NETWORK_ROUTE = TLV_META_TYPE_GROUP | 1423 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_IP = TLV_META_TYPE_RAW | 1430
TLV_TYPE_MAC_ADDRESS = TLV_META_TYPE_RAW | 1431 TLV_TYPE_MAC_ADDRESS = TLV_META_TYPE_RAW | 1431