1
mirror of https://github.com/rapid7/metasploit-framework synced 2024-10-29 18:07:27 +01:00

Merge branch 'feature/6476-list-all-ifaces'

Conflicts:
	modules/auxiliary/scanner/afp/afp_server_info.rb
This commit is contained in:
James Lee 2012-03-13 13:55:45 -06:00
commit 6a6dd06103
14 changed files with 464 additions and 232 deletions

Binary file not shown.

BIN
data/meterpreter/msflinker_linux_x86.bin Executable file → Normal file

Binary file not shown.

View File

@ -37,16 +37,26 @@ typedef struct ___u128 {
__u32 a4;
}__u128;
struct iface_address {
int family;
union {
__u32 addr;
__u128 addr6;
} ip;
union {
__u32 netmask;
__u128 netmask6;
} nm;
};
struct iface_entry {
unsigned char name[IFNAMSIZ+1];
__u32 addr;
__u32 netmask;
unsigned char hwaddr[6];
__u128 addr6;
__u128 netmask6;
uint32_t mtu;
uint32_t index;
unsigned char flags[FLAGS_LEN+1];
int addr_count;
struct iface_address *addr_list;
};
struct ifaces_list {

View File

@ -1528,4 +1528,4 @@ DWORD packet_receive_via_http(Remote *remote, Packet **packet)
return 0;
}
#endif
#endif

View File

@ -1,15 +1,15 @@
#include "precomp.h"
/*
* Returns zero or more local interfaces to the requestor
*/
DWORD request_net_config_get_interfaces(Remote *remote, Packet *packet)
#ifdef _WIN32
#include <ws2ipdef.h>
#endif
#ifdef _WIN32
DWORD get_interfaces_windows_mib(Remote *remote, Packet *response)
{
Packet *response = packet_create_response(packet);
DWORD result = ERROR_SUCCESS;
DWORD entryCount;
#ifdef _WIN32
Tlv entries[6];
PMIB_IPADDRTABLE table = NULL;
DWORD tableSize = sizeof(MIB_IPADDRROW) * 33;
@ -35,26 +35,24 @@ DWORD request_net_config_get_interfaces(Remote *remote, Packet *packet)
}
// Enumerate the entries
for (index = 0;
index < table->dwNumEntries;
index++)
for (index = 0; index < table->dwNumEntries; index++)
{
entryCount = 0;
interface_index_bigendian = htonl(table->table[index].dwIndex);
entries[entryCount].header.length = sizeof(DWORD);
entries[entryCount].header.type = TLV_TYPE_INTERFACE_INDEX;
entries[entryCount].buffer = (PUCHAR)&interface_index_bigendian;
entries[entryCount].header.type = TLV_TYPE_INTERFACE_INDEX;
entries[entryCount].buffer = (PUCHAR)&interface_index_bigendian;
entryCount++;
entries[entryCount].header.length = sizeof(DWORD);
entries[entryCount].header.type = TLV_TYPE_IP;
entries[entryCount].buffer = (PUCHAR)&table->table[index].dwAddr;
entries[entryCount].header.type = TLV_TYPE_IP;
entries[entryCount].buffer = (PUCHAR)&table->table[index].dwAddr;
entryCount++;
entries[entryCount].header.length = sizeof(DWORD);
entries[entryCount].header.type = TLV_TYPE_NETMASK;
entries[entryCount].buffer = (PUCHAR)&table->table[index].dwMask;
entries[entryCount].header.type = TLV_TYPE_NETMASK;
entries[entryCount].buffer = (PUCHAR)&table->table[index].dwMask;
entryCount++;
iface.dwIndex = table->table[index].dwIndex;
@ -63,28 +61,28 @@ DWORD request_net_config_get_interfaces(Remote *remote, Packet *packet)
if (GetIfEntry(&iface) == NO_ERROR)
{
entries[entryCount].header.length = iface.dwPhysAddrLen;
entries[entryCount].header.type = TLV_TYPE_MAC_ADDR;
entries[entryCount].buffer = (PUCHAR)iface.bPhysAddr;
entries[entryCount].header.type = TLV_TYPE_MAC_ADDR;
entries[entryCount].buffer = (PUCHAR)iface.bPhysAddr;
entryCount++;
mtu_bigendian = htonl(iface.dwMtu);
entries[entryCount].header.length = sizeof(DWORD);
entries[entryCount].header.type = TLV_TYPE_INTERFACE_MTU;
entries[entryCount].buffer = (PUCHAR)&mtu_bigendian;
entries[entryCount].header.type = TLV_TYPE_INTERFACE_MTU;
entries[entryCount].buffer = (PUCHAR)&mtu_bigendian;
entryCount++;
if (iface.bDescr)
{
entries[entryCount].header.length = iface.dwDescrLen + 1;
entries[entryCount].header.type = TLV_TYPE_MAC_NAME;
entries[entryCount].buffer = (PUCHAR)iface.bDescr;
entries[entryCount].header.type = TLV_TYPE_MAC_NAME;
entries[entryCount].buffer = (PUCHAR)iface.bDescr;
entryCount++;
}
}
// Add the interface group
packet_add_tlv_group(response, TLV_TYPE_NETWORK_INTERFACE,
entries, entryCount);
entries, entryCount);
}
} while (0);
@ -92,64 +90,249 @@ DWORD request_net_config_get_interfaces(Remote *remote, Packet *packet)
if (table)
free(table);
return result;
}
DWORD get_interfaces_windows(Remote *remote, Packet *response) {
DWORD result = ERROR_SUCCESS;
DWORD entryCount;
// Most of the time we'll need:
// 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 mtu_bigendian;
DWORD interface_index_bigendian;
ULONG flags = GAA_FLAG_INCLUDE_PREFIX | GAA_FLAG_SKIP_DNS_SERVER;
LPSOCKADDR sockaddr;
ULONG family = AF_UNSPEC;
IP_ADAPTER_ADDRESSES *pAdapters = NULL;
IP_ADAPTER_ADDRESSES *pCurr = NULL;
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;
do
{
gaa = (DWORD (WINAPI *)(DWORD,DWORD,void*,void*,void*))GetProcAddress(
GetModuleHandle("iphlpapi"), "GetAdaptersAddresses"
);
if (!gaa) {
result = get_interfaces_windows_mib(remote, response);
// --- DEBUG ---
packet_add_tlv_uint(response, TLV_TYPE_EXIT_CODE, 666);
// --- END DEBUG ---
break;
}
gaa(family, flags, NULL, pAdapters, &outBufLen);
if (!(pAdapters = (IP_ADAPTER_ADDRESSES *)malloc(outBufLen)))
{
result = ERROR_NOT_ENOUGH_MEMORY;
break;
}
if (gaa(family, flags, NULL, pAdapters, &outBufLen))
{
result = GetLastError();
break;
}
// Enumerate the entries
for (pCurr = pAdapters; pCurr; pCurr = pCurr->Next)
{
entryCount = 0;
interface_index_bigendian = htonl(pCurr->IfIndex);
entries[entryCount].header.length = sizeof(DWORD);
entries[entryCount].header.type = TLV_TYPE_INTERFACE_INDEX;
entries[entryCount].buffer = (PUCHAR)&interface_index_bigendian;
entryCount++;
entries[entryCount].header.length = pCurr->PhysicalAddressLength;
entries[entryCount].header.type = TLV_TYPE_MAC_ADDR;
entries[entryCount].buffer = (PUCHAR)pCurr->PhysicalAddress;
entryCount++;
entries[entryCount].header.length = wcslen(pCurr->Description)*2 + 1;
entries[entryCount].header.type = TLV_TYPE_MAC_NAME;
entries[entryCount].buffer = (PUCHAR)pCurr->Description;
entryCount++;
mtu_bigendian = htonl(pCurr->Mtu);
entries[entryCount].header.length = sizeof(DWORD);
entries[entryCount].header.type = TLV_TYPE_INTERFACE_MTU;
entries[entryCount].buffer = (PUCHAR)&mtu_bigendian;
entryCount++;
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.
if (allocd_entries < entryCount+3) {
entries = realloc(entries, sizeof(Tlv) * (entryCount+3));
allocd_entries += 3;
}
sockaddr = pAddr->Address.lpSockaddr;
if (sockaddr->sa_family == AF_INET) {
entries[entryCount].header.length = 4;
entries[entryCount].header.type = TLV_TYPE_IP;
entries[entryCount].buffer = (PUCHAR)&(((struct sockaddr_in *)sockaddr)->sin_addr);
if (pCurr->Length > 68) {
// --- DEBUG ---
packet_add_tlv_uint(response, TLV_TYPE_EXIT_CODE, 1337);
// --- END DEBUG ---
entryCount++;
entries[entryCount].header.length = 4;
entries[entryCount].header.type = TLV_TYPE_NETMASK;
entries[entryCount].buffer = (PUCHAR)&(((struct sockaddr_in *)sockaddr)->sin_addr);
}
} else {
entries[entryCount].header.length = 16;
entries[entryCount].header.type = TLV_TYPE_IP;
entries[entryCount].buffer = (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_addr);
entryCount++;
entries[entryCount].header.length = sizeof(DWORD);
entries[entryCount].header.type = TLV_TYPE_IP6_SCOPE;
entries[entryCount].buffer = (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_scope_id);
if (pCurr->Length > 68) {
entryCount++;
entries[entryCount].header.length = 16;
entries[entryCount].header.type = TLV_TYPE_NETMASK;
entries[entryCount].buffer = (PUCHAR)&(((struct sockaddr_in6 *)sockaddr)->sin6_addr);
}
}
entryCount++;
}
// Add the interface group
packet_add_tlv_group(response, TLV_TYPE_NETWORK_INTERFACE,
entries, entryCount);
}
} while (0);
if (entries)
free(entries);
return result;
}
#else
int get_interfaces_linux(Remote *remote, Packet *response) {
struct ifaces_list *ifaces = NULL;
int i;
int if_error;
int result;
uint32_t interface_index_bigendian, mtu_bigendian;
Tlv entries[9];
// wild guess, should probably malloc
Tlv entries[39];
if_error = netlink_get_interfaces(&ifaces);
dprintf("Grabbing interfaces");
result = netlink_get_interfaces(&ifaces);
dprintf("Got 'em");
if (if_error) {
result = if_error;
} else {
if (!result) {
for (i = 0; i < ifaces->entries; i++) {
int tlv_cnt = 0;
int j = 0;
dprintf("Building TLV for iface %d", i);
entries[0].header.length = strlen(ifaces->ifaces[i].name)+1;
entries[0].header.type = TLV_TYPE_MAC_NAME;
entries[0].buffer = (PUCHAR)ifaces->ifaces[i].name;
entries[tlv_cnt].header.length = strlen(ifaces->ifaces[i].name)+1;
entries[tlv_cnt].header.type = TLV_TYPE_MAC_NAME;
entries[tlv_cnt].buffer = (PUCHAR)ifaces->ifaces[i].name;
tlv_cnt++;
entries[1].header.length = 6;
entries[1].header.type = TLV_TYPE_MAC_ADDR;
entries[1].buffer = (PUCHAR)ifaces->ifaces[i].hwaddr;
entries[tlv_cnt].header.length = 6;
entries[tlv_cnt].header.type = TLV_TYPE_MAC_ADDR;
entries[tlv_cnt].buffer = (PUCHAR)ifaces->ifaces[i].hwaddr;
tlv_cnt++;
entries[2].header.length = sizeof(__u32);
entries[2].header.type = TLV_TYPE_IP;
entries[2].buffer = (PUCHAR)&ifaces->ifaces[i].addr;
for (j = 0; j < ifaces->ifaces[i].addr_count; j++) {
if (ifaces->ifaces[i].addr_list[j].family == AF_INET) {
dprintf("ip addr for %s", ifaces->ifaces[i].name);
entries[tlv_cnt].header.length = sizeof(__u32);
entries[tlv_cnt].header.type = TLV_TYPE_IP;
entries[tlv_cnt].buffer = (PUCHAR)&ifaces->ifaces[i].addr_list[j].ip.addr;
tlv_cnt++;
entries[3].header.length = sizeof(__u32);
entries[3].header.type = TLV_TYPE_NETMASK;
entries[3].buffer = (PUCHAR)&ifaces->ifaces[i].netmask;
//dprintf("netmask for %s", ifaces->ifaces[i].name);
entries[tlv_cnt].header.length = sizeof(__u32);
entries[tlv_cnt].header.type = TLV_TYPE_NETMASK;
entries[tlv_cnt].buffer = (PUCHAR)&ifaces->ifaces[i].addr_list[j].nm.netmask;
tlv_cnt++;
} else {
dprintf("-- ip six addr for %s", ifaces->ifaces[i].name);
entries[tlv_cnt].header.length = sizeof(__u128);
entries[tlv_cnt].header.type = TLV_TYPE_IP;
entries[tlv_cnt].buffer = (PUCHAR)&ifaces->ifaces[i].addr_list[j].ip.addr6;
tlv_cnt++;
entries[4].header.length = sizeof(__u128);
entries[4].header.type = TLV_TYPE_IP6;
entries[4].buffer = (PUCHAR)&ifaces->ifaces[i].addr6;
entries[5].header.length = sizeof(__u128);
entries[5].header.type = TLV_TYPE_NETMASK6;
entries[5].buffer = (PUCHAR)&ifaces->ifaces[i].netmask6;
//dprintf("netmask6 for %s", ifaces->ifaces[i].name);
entries[tlv_cnt].header.length = sizeof(__u128);
entries[tlv_cnt].header.type = TLV_TYPE_NETMASK;
entries[tlv_cnt].buffer = (PUCHAR)&ifaces->ifaces[i].addr_list[j].nm.netmask6;
tlv_cnt++;
}
}
mtu_bigendian = htonl(ifaces->ifaces[i].mtu);
entries[6].header.length = sizeof(uint32_t);
entries[6].header.type = TLV_TYPE_INTERFACE_MTU;
entries[6].buffer = (PUCHAR)&mtu_bigendian;
entries[tlv_cnt].header.length = sizeof(uint32_t);
entries[tlv_cnt].header.type = TLV_TYPE_INTERFACE_MTU;
entries[tlv_cnt].buffer = (PUCHAR)&mtu_bigendian;
tlv_cnt++;
entries[7].header.length = strlen(ifaces->ifaces[i].flags)+1;
entries[7].header.type = TLV_TYPE_INTERFACE_FLAGS;
entries[7].buffer = (PUCHAR)ifaces->ifaces[i].flags;
entries[tlv_cnt].header.length = strlen(ifaces->ifaces[i].flags)+1;
entries[tlv_cnt].header.type = TLV_TYPE_INTERFACE_FLAGS;
entries[tlv_cnt].buffer = (PUCHAR)ifaces->ifaces[i].flags;
tlv_cnt++;
interface_index_bigendian = htonl(ifaces->ifaces[i].index);
entries[8].header.length = sizeof(uint32_t);
entries[8].header.type = TLV_TYPE_INTERFACE_INDEX;
entries[8].buffer = (PUCHAR)&interface_index_bigendian;
packet_add_tlv_group(response, TLV_TYPE_NETWORK_INTERFACE, entries, 9);
entries[tlv_cnt].header.length = sizeof(uint32_t);
entries[tlv_cnt].header.type = TLV_TYPE_INTERFACE_INDEX;
entries[tlv_cnt].buffer = (PUCHAR)&interface_index_bigendian;
tlv_cnt++;
dprintf("Adding TLV to group");
packet_add_tlv_group(response, TLV_TYPE_NETWORK_INTERFACE, entries, tlv_cnt);
dprintf("done Adding TLV to group");
}
}
if (ifaces)
free(ifaces);
return result;
}
#endif
/*
* Returns zero or more local interfaces to the requestor
*/
DWORD request_net_config_get_interfaces(Remote *remote, Packet *packet)
{
Packet *response = packet_create_response(packet);
DWORD result = ERROR_SUCCESS;
#ifdef _WIN32
result = get_interfaces_windows(remote, response);
#else
result = get_interfaces_linux(remote, response);
#endif
// Transmit the response if valid
@ -159,5 +342,3 @@ DWORD request_net_config_get_interfaces(Remote *remote, Packet *packet)
}

View File

@ -355,26 +355,6 @@
TLV_META_TYPE_GROUP, \
TLV_TYPE_EXTENSION_STDAPI, \
1423)
#define TLV_TYPE_SUBNET6 \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_RAW, \
TLV_TYPE_EXTENSION_STDAPI, \
1424)
#define TLV_TYPE_NETMASK6 \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_RAW, \
TLV_TYPE_EXTENSION_STDAPI, \
1425)
#define TLV_TYPE_GATEWAY6 \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_RAW, \
TLV_TYPE_EXTENSION_STDAPI, \
1426)
#define TLV_TYPE_NETWORK_ROUTE6 \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_GROUP, \
TLV_TYPE_EXTENSION_STDAPI, \
1427)
#define TLV_TYPE_IP \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_RAW, \
@ -395,9 +375,9 @@
TLV_META_TYPE_GROUP, \
TLV_TYPE_EXTENSION_STDAPI, \
1433)
#define TLV_TYPE_IP6 \
#define TLV_TYPE_IP6_SCOPE \
MAKE_CUSTOM_TLV( \
TLV_META_TYPE_RAW, \
TLV_META_TYPE_RAW, \
TLV_TYPE_EXTENSION_STDAPI, \
1434)

View File

@ -158,8 +158,8 @@ int netlink_parse(int fd, int seq, netlink_cb_t callback, void *data)
}
for(nh = (struct nlmsghdr *)(buf); NLMSG_OK(nh, len); nh = (struct nlmsghdr *) NLMSG_NEXT(nh, len)) {
dprintf("buf = %p, nh = %p", buf, nh);
dprintf("nh->nlmsg_type = %d", nh->nlmsg_type);
//dprintf("buf = %p, nh = %p", buf, nh);
//dprintf("nh->nlmsg_type = %d", nh->nlmsg_type);
if(nh->nlmsg_type == NLMSG_DONE) {
end = 1;
@ -168,12 +168,12 @@ int netlink_parse(int fd, int seq, netlink_cb_t callback, void *data)
if(nh->nlmsg_type == NLMSG_ERROR) {
struct nlmsgerr *me = (struct nlmsgerr *) NLMSG_DATA (nh);
dprintf("in NLMSG_ERROR handling.. me = %p");
dprintf("me->error = %d", me->error);
//dprintf("in NLMSG_ERROR handling.. me = %p", me);
//dprintf("me->error = %d", me->error);
if(me->error) {
dprintf("so, we have: nlmsg_len: %d, nlmsg_type: %d, nlmsg_flags: %d, nlmsg_seq: %d, nlmsg_pid: %d",
me->msg.nlmsg_len, me->msg.nlmsg_type, me->msg.nlmsg_flags,
me->msg.nlmsg_seq, me->msg.nlmsg_pid);
//dprintf("so, we have: nlmsg_len: %d, nlmsg_type: %d, nlmsg_flags: %d, nlmsg_seq: %d, nlmsg_pid: %d",
// me->msg.nlmsg_len, me->msg.nlmsg_type, me->msg.nlmsg_flags,
// me->msg.nlmsg_seq, me->msg.nlmsg_pid);
if(me->msg.nlmsg_seq == seq) {
dprintf("Hum. kernel doesn't like our message :~(");
@ -188,7 +188,7 @@ int netlink_parse(int fd, int seq, netlink_cb_t callback, void *data)
//
dprintf("[%s] dispatching into callback", __FUNCTION__);
dprintf("dispatching into callback");
status = callback(nh, data);
@ -262,7 +262,7 @@ int netlink_parse_routing_table(struct nlmsghdr *nh, void *data)
dprintf("Adjusted rm at +4");
}
dprintf("rtm_family : 0x%x , rtm_dst_len : 0x%x, rtm_src_len : 0x%x",rm->rtm_family, rm->rtm_dst_len, rm->rtm_src_len);
//dprintf("rtm_family : 0x%x , rtm_dst_len : 0x%x, rtm_src_len : 0x%x",rm->rtm_family, rm->rtm_dst_len, rm->rtm_src_len);
// print directly connected routes
if(rm->rtm_type != RTN_UNICAST && rm->rtm_type != RTN_LOCAL) {
dprintf("got %d instead of RTN_UNICAST (%d) or RTN_LOCAL (%d)", rm->rtm_type, RTN_UNICAST,RTN_LOCAL);
@ -289,7 +289,7 @@ int netlink_parse_routing_table(struct nlmsghdr *nh, void *data)
else
is_ipv6 = 1;
dprintf("nh->nlmsg_len: %d, NLMSG_LENGTH(sizeof(..)): %d, is_ipv6 : %d", nh->nlmsg_len, NLMSG_LENGTH(sizeof(struct rtmsg)),is_ipv6);
//dprintf("nh->nlmsg_len: %d, NLMSG_LENGTH(sizeof(..)): %d, is_ipv6 : %d", nh->nlmsg_len, NLMSG_LENGTH(sizeof(struct rtmsg)),is_ipv6);
len = nh->nlmsg_len - NLMSG_LENGTH (sizeof(struct rtmsg));
if(len <= 0) {
@ -297,12 +297,12 @@ int netlink_parse_routing_table(struct nlmsghdr *nh, void *data)
return 0;
}
dprintf("RTA_DST=%d, RTA_SRC=%d, RTA_GATEWAY=%d, RTA_PREFSRC=%d, RTA_OIF=%d, RTA_PRIORITY=%d", RTA_DST, RTA_SRC, RTA_GATEWAY, RTA_PREFSRC,RTA_OIF, RTA_PRIORITY);
//dprintf("RTA_DST=%d, RTA_SRC=%d, RTA_GATEWAY=%d, RTA_PREFSRC=%d, RTA_OIF=%d, RTA_PRIORITY=%d", RTA_DST, RTA_SRC, RTA_GATEWAY, RTA_PREFSRC,RTA_OIF, RTA_PRIORITY);
dprintf("rtm_table : %d, RT_TABLE_UNSPEC=%d, RT_TABLE_DEFAULT =%d, RT_TABLE_MAIN=%d,RT_TABLE_LOCAL=%d", rm->rtm_table,RT_TABLE_UNSPEC, RT_TABLE_DEFAULT , RT_TABLE_MAIN, RT_TABLE_LOCAL);
//dprintf("rtm_table : %d, RT_TABLE_UNSPEC=%d, RT_TABLE_DEFAULT =%d, RT_TABLE_MAIN=%d,RT_TABLE_LOCAL=%d", rm->rtm_table,RT_TABLE_UNSPEC, RT_TABLE_DEFAULT , RT_TABLE_MAIN, RT_TABLE_LOCAL);
dprintf("rtm_type : %d, RTN_UNICAST=%d, RTN_LOCAL=%d", rm->rtm_type,RTN_UNICAST, RTN_LOCAL);
//dprintf("rtm_type : %d, RTN_UNICAST=%d, RTN_LOCAL=%d", rm->rtm_type,RTN_UNICAST, RTN_LOCAL);
// okay, so.
//
@ -310,11 +310,11 @@ int netlink_parse_routing_table(struct nlmsghdr *nh, void *data)
{
if (is_ipv6) {
what6 = (unsigned char *) RTA_DATA(ra);
dprintf("ra @ %p, type = %d, length = %d, payload = %d, payload data = %08x %08x %08x %08x", ra, ra->rta_type, ra->rta_len, RTA_PAYLOAD(ra), *(__u32 *)what6, *(__u32 *)(what6+4), *(__u32 *)(what6+8), *(__u32 *)(what6+12));
//dprintf("ra @ %p, type = %d, length = %d, payload = %d, payload data = %08x %08x %08x %08x", ra, ra->rta_type, ra->rta_len, RTA_PAYLOAD(ra), *(__u32 *)what6, *(__u32 *)(what6+4), *(__u32 *)(what6+8), *(__u32 *)(what6+12));
}
else {
what = (__u32 *) RTA_DATA(ra);
dprintf("ra @ %p, type = %d, length = %d, payload = %d, payload data = %08x", ra, ra->rta_type, ra->rta_len, RTA_PAYLOAD(ra), *what);
//dprintf("ra @ %p, type = %d, length = %d, payload = %d, payload data = %08x", ra, ra->rta_type, ra->rta_len, RTA_PAYLOAD(ra), *what);
}
switch(ra->rta_type) {
@ -341,7 +341,7 @@ int netlink_parse_routing_table(struct nlmsghdr *nh, void *data)
}
}
dprintf("and while you're here, rtm_dst_len = %d", rm->rtm_dst_len);
//dprintf("and while you're here, rtm_dst_len = %d", rm->rtm_dst_len);
if (is_ipv6) {
// if netmask is FFFFFFFF FFFFFFFF 00000000 00000000 (/64), netmask6.a1 and netmask6.a2 == 0xffffffff, and nestmask6.a3 and .a4 == 0
@ -387,11 +387,11 @@ int netlink_parse_routing_table(struct nlmsghdr *nh, void *data)
strncpy(re6->interface, int_name, IFNAMSIZ);
re6->metric = metric;
dprintf("re6->dest6 = %08x %08x %08x %08x, re6->netmask6 = %08x %08x %08x %08x, re6->nexthop6 = %08x %08x %08x %08x, interface = %s, metric = %d",
re6->dest6.a1,re6->dest6.a2,re6->dest6.a3,re6->dest6.a4,
re6->netmask6.a1,re6->netmask6.a2,re6->netmask6.a3,re6->netmask6.a4,
re6->nexthop6.a1,re6->nexthop6.a2,re6->nexthop6.a3,re6->nexthop6.a4,
re6->interface,re6->metric);
//dprintf("re6->dest6 = %08x %08x %08x %08x, re6->netmask6 = %08x %08x %08x %08x, re6->nexthop6 = %08x %08x %08x %08x, interface = %s, metric = %d",
// re6->dest6.a1,re6->dest6.a2,re6->dest6.a3,re6->dest6.a4,
// re6->netmask6.a1,re6->netmask6.a2,re6->netmask6.a3,re6->netmask6.a4,
// re6->nexthop6.a1,re6->nexthop6.a2,re6->nexthop6.a3,re6->nexthop6.a4,
// re6->interface,re6->metric);
tmp6->entries++;
*table_v6 = tmp6;
@ -414,7 +414,7 @@ int netlink_parse_routing_table(struct nlmsghdr *nh, void *data)
strncpy(re->interface, int_name, IFNAMSIZ);
re->metric = metric;
dprintf("re->dest = %08x, re->netmask = %08x, re->nexthop = %08x, interface = %s, metric = %d", re->dest, re->netmask, re->nexthop,re->interface,re->metric);
//dprintf("re->dest = %08x, re->netmask = %08x, re->nexthop = %08x, interface = %s, metric = %d", re->dest, re->netmask, re->nexthop,re->interface,re->metric);
tmp->entries++;
*table_v4 = tmp;
@ -531,7 +531,7 @@ int netlink_parse_interface_link(struct nlmsghdr *nh, void *data)
iface = (unsigned char *)iface + 4;
dprintf("Adjusted iface at +4");
}
dprintf("ifi_family : 0x%x , ifi_type : 0x%x, ifi_index : 0x%x",iface->ifi_family, iface->ifi_type, iface->ifi_index);
//dprintf("ifi_family : 0x%x , ifi_type : 0x%x, ifi_index : 0x%x",iface->ifi_family, iface->ifi_type, iface->ifi_index);
len = nh->nlmsg_len - NLMSG_LENGTH(sizeof(*iface));
memset(&iface_tmp, 0, sizeof(iface_tmp));
@ -642,8 +642,7 @@ int netlink_parse_interface_address(struct nlmsghdr *nh, void *data)
{
struct ifaces_list ** iface_list = ( struct ifaces_list **) data;
struct iface_entry * iff;
struct iface_entry * iff_tmp;
struct ifaces_list *tmp;
struct ifaces_list * iface_list_tmp;
struct iface_entry iface_tmp;
struct ifaddrmsg *iaddr;
@ -652,6 +651,11 @@ int netlink_parse_interface_address(struct nlmsghdr *nh, void *data)
uint32_t newsize;
unsigned char is_ipv6;
struct iface_address *addr_tmp;
// strictly for debugging
char addr_str[64];
iaddr = NLMSG_DATA(nh);
// stumbled upon an old system with 4 bytes padding between nlmsghdr and ifaddrmsg, try to detect it
if (!likely_ifaddrmsg(iaddr)) {
@ -659,7 +663,6 @@ int netlink_parse_interface_address(struct nlmsghdr *nh, void *data)
dprintf("Adjusted iaddr at +4");
}
dprintf("ifa_family : 0x%x , ifa_prefixlen : 0x%x, ifa_flags : 0x%x, ifa_scope : 0x%x",iaddr->ifa_family, iaddr->ifa_prefixlen, iaddr->ifa_flags, iaddr->ifa_scope);
len = nh->nlmsg_len - NLMSG_LENGTH(sizeof(*iaddr));
if (iaddr->ifa_family == AF_INET6)
@ -667,127 +670,111 @@ int netlink_parse_interface_address(struct nlmsghdr *nh, void *data)
else if (iaddr->ifa_family == AF_INET)
is_ipv6 = 0;
else {
dprintf("Got iaddr->ifa_family : %d which is unknown (iaddr->ifa_index : %d)", iaddr->ifa_family, iaddr->ifa_index);
//dprintf("Got iaddr->ifa_family : %d which is unknown (iaddr->ifa_index : %d)", iaddr->ifa_family, iaddr->ifa_index);
return 0;
}
memset(&iface_tmp, 0, sizeof(iface_tmp));
iface_tmp.index = iaddr->ifa_index;
dprintf("-------------------------------------");
for (attribute = IFA_RTA(iaddr); RTA_OK(attribute, len); attribute = RTA_NEXT(attribute, len))
{
dprintf("Start of loop, attribute->rta_type = %d", attribute->rta_type);
switch(attribute->rta_type)
{
case IFA_ADDRESS:
// Make room for a new address
iface_tmp.addr_count++;
iface_tmp.addr_list = realloc(iface_tmp.addr_list, sizeof(struct iface_address) * iface_tmp.addr_count);
addr_tmp = &iface_tmp.addr_list[iface_tmp.addr_count-1];
if (is_ipv6)
memcpy(&iface_tmp.addr6, (unsigned char *) RTA_DATA(attribute), sizeof(__u128));
else
iface_tmp.addr = *(__u32 *) RTA_DATA(attribute);
{
addr_tmp->family = AF_INET6;
memcpy(&addr_tmp->ip.addr6, (unsigned char *) RTA_DATA(attribute), sizeof(__u128));
} else {
addr_tmp->family = AF_INET;
addr_tmp->ip.addr = *(__u32 *) RTA_DATA(attribute);
}
address_calculate_netmask(addr_tmp, iaddr->ifa_prefixlen);
inet_ntop(addr_tmp->family, &addr_tmp->ip, addr_str, sizeof(addr_str));
dprintf("Interface: %s", addr_str);
inet_ntop(addr_tmp->family, &addr_tmp->nm, addr_str, sizeof(addr_str));
dprintf("Netmask: %s", addr_str);
break;
case IFA_LABEL:
strncpy(iface_tmp.name, (unsigned char *) RTA_DATA(attribute), IFNAMSIZ);
dprintf("Copied name %s", iface_tmp.name);
break;
default:
break;
}
dprintf("-------------------------------------");
}
dprintf("and while you're here, iaddr->ifa_prefixlen = %d", iaddr->ifa_prefixlen);
if (is_ipv6) {
// if netmask is FFFFFFFF FFFFFFFF 00000000 00000000 (/64), netmask6.a1 and netmask6.a2 == 0xffffffff, and nestmask6.a3 and .a4 == 0
// netmask6 is set to 0 at the beginning of the function, no need to reset the values to 0 if it is needed
// XXX really ugly, but works
if (iaddr->ifa_prefixlen >= 96) {
iface_tmp.netmask6.a4 = (1 << (iaddr->ifa_prefixlen-96))-1;
iface_tmp.netmask6.a1 = iface_tmp.netmask6.a2 = iface_tmp.netmask6.a3 = 0xffffffff;
}
else if (iaddr->ifa_prefixlen >= 64) {
iface_tmp.netmask6.a3 = (1 << (iaddr->ifa_prefixlen-64))-1;
iface_tmp.netmask6.a1 = iface_tmp.netmask6.a2 = 0xffffffff;
}
else if (iaddr->ifa_prefixlen >= 32) {
iface_tmp.netmask6.a2 = (1 << (iaddr->ifa_prefixlen-32))-1;
iface_tmp.netmask6.a1 = 0xffffffff;
}
else
iface_tmp.netmask6.a1 = (1 << iaddr->ifa_prefixlen)-1;
}
else {
if (iaddr->ifa_prefixlen == 32)
iface_tmp.netmask = 0xffffffff;
else
iface_tmp.netmask = ((1 << iaddr->ifa_prefixlen) - 1);
}
dprintf("Exited loop");
/*
* try to find the iface by index and name
* an IP alias (eth0:0 for instance) will have the same index but not the same name/label
* no alias when getting IPv6 address, so just search using the index
* An IP alias (eth0:0 for instance) will have the same index but not the
* same name/label. There are no aliases when getting IPv6 address, so
* just search using the index.
*/
if (is_ipv6) {
iff = find_iface_by_index(*iface_list, iaddr->ifa_index);
iff = find_iface_by_index(*iface_list, iface_tmp.index);
if (iff == NULL) {
dprintf("Cannot find iface with index %d", iaddr->ifa_index);
dprintf("Cannot find iface with index %d", iface_tmp.index);
return 0;
}
}
else
iff = find_iface_by_index_and_name(*iface_list, iaddr->ifa_index, iface_tmp.name);
iff = find_iface_by_index_and_name(*iface_list, iface_tmp.index, iface_tmp.name);
if (iff == NULL) {
dprintf("[%s] %s an alias?", __FUNCTION__, iface_tmp.name);
// didn't find this name, probably an alias such as eth0:0
iff = find_iface_by_index(*iface_list, iaddr->ifa_index);
/* Now we're dealing with an IPv4 alias such as eth0:0. With a regular
* interface, the mac address, mtu, flags, etc. would already have been
* initialized when we did the RTM_GETLINK request. Since an alias
* doesn't count as a physical interface, that didn't happen, so copy
* all of the parent interface's info to this one.
*/
dprintf("%s an alias?", iface_tmp.name);
iff = find_iface_by_index(*iface_list, iface_tmp.index);
if (iff == NULL) {
dprintf("Cannot find iface with index %d", iaddr->ifa_index);
dprintf("Cannot find iface with index %d", iface_tmp.index);
return 0;
}
// found it, copy the data to save it
// old MAC addr and MTU
memcpy(iface_tmp.hwaddr, iff->hwaddr, 6);
iface_tmp.mtu = iff->mtu;
iface_tmp.index = iff->index;
memcpy(&iface_tmp.addr6, &iff->addr6, sizeof(__u128));
memcpy(&iface_tmp.netmask6, &iff->netmask6, sizeof(__u128));
strncpy(iface_tmp.flags, iff->flags, FLAGS_LEN);
// allocate new one
// expand the list to accomodate the new one
newsize = sizeof(struct ifaces_list);
newsize += ((*iface_list)->entries + 1) * sizeof(struct iface_entry);
iface_list_tmp = realloc(*iface_list, newsize);
tmp = realloc(*iface_list, newsize);
if(tmp == NULL) {
if(iface_list_tmp == NULL) {
return ENOMEM;
}
iff = &(tmp->ifaces[tmp->entries]);
iff = &(iface_list_tmp->ifaces[iface_list_tmp->entries]);
memset(iff, 0, sizeof(struct iface_entry));
// copy back saved data in new iface_entry
memcpy(iff->hwaddr, iface_tmp.hwaddr, 6);
iff->mtu = iface_tmp.mtu;
iff->index = iface_tmp.index;
memcpy(&iff->addr6, &iface_tmp.addr6, sizeof(__u128));
memcpy(&iff->netmask6, &iface_tmp.netmask6, sizeof(__u128));
strncpy(iff->flags, iface_tmp.flags, FLAGS_LEN);
// copy new name
strncpy(iff->name, iface_tmp.name, IFNAMSIZ);
tmp->entries++;
*iface_list = tmp;
}
//now, iff points to a iface_entry, just copy add/addr6 and netmask/netmask6
if (is_ipv6) {
memcpy(&iff->addr6, &iface_tmp.addr6, sizeof(__u128));
memcpy(&iff->netmask6, &iface_tmp.netmask6, sizeof(__u128));
}
else {
iff->addr = iface_tmp.addr;
iff->netmask = iface_tmp.netmask;
iface_list_tmp->entries++;
*iface_list = iface_list_tmp;
}
dprintf("iff->index = %d, iff->name = %s, iff->addr = %08x, iff->netmask = %08x, iff->addr6 = %08x %08x %08x %08x, iff->netmask6 = %08x %08x %08x %08x",
iff->index, iff->name, iff->addr, iff->netmask,
iff->addr6.a1,iff->addr6.a2,iff->addr6.a3,iff->addr6.a4, iff->netmask6.a1,iff->netmask6.a2,iff->netmask6.a3,iff->netmask6.a4);
inet_ntop(addr_tmp->family, &addr_tmp->ip, addr_str, sizeof(addr_str));
dprintf("Appending: %s", addr_str);
iface_entry_append_address(iff, &iface_tmp.addr_list[0]);
dprintf("iff->addr_count = %d; iface_tmp.addr_count = %d", iff->addr_count, iface_tmp.addr_count);
return 0;
}
@ -836,7 +823,7 @@ int netlink_get_interfaces(struct ifaces_list **iface_list)
return ERROR_NOT_SUPPORTED;
}
// for each interface created before, will get the IPv4 / IPv6 addr
status = netlink_parse(fd, seq, netlink_parse_interface_address, iface_list);
status = netlink_parse(fd, seq, netlink_parse_interface_address, iface_list);
close(fd);
if(status != 0) {
if (*iface_list)
@ -848,3 +835,42 @@ int netlink_get_interfaces(struct ifaces_list **iface_list)
return status;
}
void address_calculate_netmask(struct iface_address *address, int ifa_prefixlen) {
if (address->family == AF_INET6) {
// if netmask is FFFFFFFF FFFFFFFF 00000000 00000000 (/64), netmask6.a1 and netmask6.a2 == 0xffffffff, and nestmask6.a3 and .a4 == 0
// netmask6 is set to 0 at the beginning of the function, no need to reset the values to 0 if it is needed
// XXX really ugly, but works
if (ifa_prefixlen >= 96) {
address->nm.netmask6.a4 = (1 << (ifa_prefixlen-96))-1;
address->nm.netmask6.a1 = address->nm.netmask6.a2 = address->nm.netmask6.a3 = 0xffffffff;
}
else if (ifa_prefixlen >= 64) {
address->nm.netmask6.a3 = (1 << (ifa_prefixlen-64))-1;
address->nm.netmask6.a1 = address->nm.netmask6.a2 = 0xffffffff;
}
else if (ifa_prefixlen >= 32) {
address->nm.netmask6.a2 = (1 << (ifa_prefixlen-32))-1;
address->nm.netmask6.a1 = 0xffffffff;
}
else
address->nm.netmask6.a1 = (1 << ifa_prefixlen)-1;
}
else {
if (ifa_prefixlen == 32)
address->nm.netmask = 0xffffffff;
else
address->nm.netmask = ((1 << ifa_prefixlen) - 1);
}
}
void iface_entry_append_address(struct iface_entry *iface, struct iface_address *address) {
iface->addr_count++;
iface->addr_list = realloc(iface->addr_list, sizeof(struct iface_address) * iface->addr_count);
dprintf("Realloc'd %p", iface->addr_list);
memcpy(&iface->addr_list[iface->addr_count-1], address, sizeof(struct iface_address));
}

View File

@ -312,18 +312,18 @@ class Meterpreter < Rex::Post::Meterpreter::Client
# Try to match our visible IP to a real interface
# TODO: Deal with IPv6 addresses
found = ifaces.find {|i| i.ip == shost }
found = !!(ifaces.find {|i| i.addrs.find {|a| p a; a == shost } })
nhost = nil
hobj = nil
if Rex::Socket.is_ipv4?(shost) and not found
# Try to find an interface with a default route
default_routes = routes.select{ |r| r.subnet == "0.0.0.0" }
default_routes = routes.select{ |r| r.subnet == "0.0.0.0" || r.subnet == "::" }
default_routes.each do |r|
ifaces.each do |i|
cidr = Rex::Socket.net2bitmask( i.netmask ) rescue "/32"
rang = Rex::Socket::RangeWalker.new( "#{i.ip}/#{cidr}" ) rescue nil
bits = Rex::Socket.net2bitmask( i.netmask ) rescue 32
rang = Rex::Socket::RangeWalker.new( "#{i.ip}/#{bits}" ) rescue nil
if rang and rang.include?( r.gateway )
nhost = i.ip
break

View File

@ -58,16 +58,27 @@ class Config
response = client.send_request(request)
response.each(TLV_TYPE_NETWORK_INTERFACE) { |iface|
addrs = []
netmasks = []
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
# match up. This could be done better by creating another
# GroupTlv type for addresses containing an address, a netmask,
# and possibly a scope.
n = iface.get_tlv_value(TLV_TYPE_NETMASK, addrs.length)
addrs << Rex::Socket.addr_ntoa(a)
netmasks << Rex::Socket.addr_ntoa(n) if n
end
ifaces << Interface.new(
iface.get_tlv_value(TLV_TYPE_INTERFACE_INDEX),
iface.get_tlv_value(TLV_TYPE_IP),
iface.get_tlv_value(TLV_TYPE_NETMASK),
iface.get_tlv_value(TLV_TYPE_MAC_ADDRESS),
iface.get_tlv_value(TLV_TYPE_MAC_NAME),
iface.get_tlv_value(TLV_TYPE_IP6),
iface.get_tlv_value(TLV_TYPE_NETMASK6),
iface.get_tlv_value(TLV_TYPE_INTERFACE_MTU),
iface.get_tlv_value(TLV_TYPE_INTERFACE_FLAGS))
:index => iface.get_tlv_value(TLV_TYPE_INTERFACE_INDEX),
:mac_addr => iface.get_tlv_value(TLV_TYPE_MAC_ADDRESS),
:mac_name => iface.get_tlv_value(TLV_TYPE_MAC_NAME),
:mtu => iface.get_tlv_value(TLV_TYPE_INTERFACE_MTU),
:flags => iface.get_tlv_value(TLV_TYPE_INTERFACE_FLAGS),
:addrs => addrs,
:netmasks => netmasks
)
}
return ifaces

View File

@ -27,16 +27,14 @@ class Interface
# Returns a logical interface and initializes it to the supplied
# parameters.
#
def initialize(index, ip, netmask, mac_addr, mac_name, ip6=nil, netmask6=nil, mtu=nil, flags=nil)
self.index = index || -1
self.ip = (ip ? IPAddr.ntop(ip) : nil)
self.netmask = (netmask ? IPAddr.ntop(netmask) : nil)
self.mac_addr = mac_addr
self.mac_name = mac_name
self.ip6 = (ip6 ? IPAddr.new_ntoh(ip6).to_s : nil)
self.netmask6 = (netmask6 ? IPAddr.new_ntoh(netmask6).to_s : nil)
self.mtu = mtu
self.flags = flags
def initialize(opts={})
self.index = opts[:index] || -1
self.mac_addr = opts[:mac_addr]
self.mac_name = opts[:mac_name]
self.mtu = opts[:mtu]
self.flags = opts[:flags]
self.addrs = opts[:addrs]
self.netmasks = opts[:netmasks]
end
#
@ -54,11 +52,22 @@ class Interface
macocts[3], macocts[4], macocts[5])],
["MTU" , mtu ],
["Flags" , flags ],
["IPv4 Address" , ((ip and ip != "0.0.0.0") ? ip : nil) ],
["IPv4 Netmask" , netmask ],
["IPv6 Address" , ((ip6 and ip6 != "::") ? ip6 : nil) ],
["IPv6 Netmask" , ((netmask6 and netmask6 != "::") ? netmask6 : nil) ],
]
# If all went as planned, addrs and netmasks will have the same number
# of elements and be properly ordered such that they match up
# correctly.
addr_masks = addrs.zip(netmasks)
addr_masks.select { |a| Rex::Socket.is_ipv4?(a[0]) }.each { |a|
info << [ "IPv4 Address", a[0] ]
info << [ "IPv4 Netmask", a[1] ]
}
addr_masks.select { |a| Rex::Socket.is_ipv6?(a[0]) }.each { |a|
info << [ "IPv6 Address", a[0] ]
info << [ "IPv6 Netmask", a[1] ]
}
pad = info.map{|i| i[0] }.max_by{|k|k.length}.length
ret = sprintf(
@ -76,17 +85,20 @@ class Interface
end
#
# The indedx of the interface.
# The first address associated with this Interface
#
def ip
addrs.first
end
#
# The index of the interface.
#
attr_accessor :index
#
# The IP address bound to the interface.
# An Array of IP addresses bound to the Interface.
#
attr_accessor :ip
#
# The subnet mask associated with the interface.
#
attr_accessor :netmask
attr_accessor :addrs
#
# The physical (MAC) address of the NIC.
#
@ -96,10 +108,6 @@ class Interface
#
attr_accessor :mac_name
#
# The IPv6 address bound to the interface.
#
attr_accessor :ip6
#
# The subnet mask associated with the IPv6 interface.
#
attr_accessor :netmask6
@ -111,6 +119,7 @@ class Interface
# The flags associated with the interface.
#
attr_accessor :flags
attr_accessor :netmasks
end
end; end; end; end; end; end

View File

@ -51,17 +51,12 @@ 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_SUBNET6 = TLV_META_TYPE_RAW | 1424
TLV_TYPE_NETMASK6 = TLV_META_TYPE_RAW | 1425
TLV_TYPE_GATEWAY6 = TLV_META_TYPE_RAW | 1426
TLV_TYPE_NETWORK_ROUTE6 = TLV_META_TYPE_GROUP | 1427
TLV_TYPE_IP = TLV_META_TYPE_RAW | 1430
TLV_TYPE_MAC_ADDRESS = TLV_META_TYPE_RAW | 1431
TLV_TYPE_MAC_NAME = TLV_META_TYPE_STRING | 1432
TLV_TYPE_NETWORK_INTERFACE = TLV_META_TYPE_GROUP | 1433
TLV_TYPE_IP6 = TLV_META_TYPE_RAW | 1434
TLV_TYPE_IP6_SCOPE = TLV_META_TYPE_RAW | 1434
TLV_TYPE_SUBNET_STRING = TLV_META_TYPE_STRING | 1440
TLV_TYPE_NETMASK_STRING = TLV_META_TYPE_STRING | 1441

View File

@ -1,5 +1,7 @@
#!/usr/bin/env ruby
require 'rex/post/meterpreter/extensions/stdapi/tlv'
module Rex
module Post
module Meterpreter
@ -129,13 +131,14 @@ class Tlv
def inspect
utype = type ^ TLV_META_TYPE_COMPRESSED
group = false
meta = case (utype & TLV_META_MASK)
when TLV_META_TYPE_STRING; "STRING"
when TLV_META_TYPE_UINT; "INT"
when TLV_META_TYPE_RAW; "RAW"
when TLV_META_TYPE_BOOL; "BOOL"
when TLV_META_TYPE_QWORD; "QWORD"
when TLV_META_TYPE_GROUP; "GROUP"
when TLV_META_TYPE_GROUP; group=true; "GROUP"
when TLV_META_TYPE_COMPLEX; "COMPLEX"
else; 'unknown-meta-type'
end
@ -175,16 +178,33 @@ class Tlv
when TLV_TYPE_MIGRATE_PAYLOAD; "MIGRATE-PAYLOAD"
when TLV_TYPE_MIGRATE_ARCH; "MIGRATE-ARCH"
# Extension classes don't exist yet, so can't use their constants
# here.
#when Extensions::Stdapi::TLV_TYPE_IP; 'ip-address'
when Extensions::Stdapi::TLV_TYPE_NETWORK_INTERFACE; 'network-interface'
when Extensions::Stdapi::TLV_TYPE_IP; 'ip-address'
when Extensions::Stdapi::TLV_TYPE_NETMASK; 'netmask'
when Extensions::Stdapi::TLV_TYPE_MAC_ADDRESS; 'mac-address'
when Extensions::Stdapi::TLV_TYPE_MAC_NAME; 'interface-name'
when Extensions::Stdapi::TLV_TYPE_IP6_SCOPE; 'address-scope'
when Extensions::Stdapi::TLV_TYPE_INTERFACE_MTU; 'interface-mtu'
when Extensions::Stdapi::TLV_TYPE_INTERFACE_FLAGS; 'interface-flags'
when Extensions::Stdapi::TLV_TYPE_INTERFACE_INDEX; 'interface-index'
else; "unknown-#{type}"
end
val = value.inspect
if val.length > 50
val = val[0,50] + ' ..."'
end
"#<#{self.class} type=#{stype} #{self.class.to_s =~ /Packet/ ? "tlvs=#{@tlvs.inspect}" : "meta=#{meta} value=#{val}"} >"
group ||= (self.class.to_s =~ /Packet/)
if group
tlvs_inspect = "tlvs=[\n"
@tlvs.each { |t|
tlvs_inspect << " #{t.inspect}\n"
}
tlvs_inspect << "]"
else
tlvs_inspect = "meta=#{meta} value=#{val}"
end
"#<#{self.class} type=#{stype} #{tlvs_inspect}>"
end
##