HostDev: Add IPv6 support for Windows hosts

This commit is contained in:
Srivats P 2018-08-15 10:51:04 +05:30
parent e2a11bfa4e
commit f58c4e309c
3 changed files with 99 additions and 11 deletions

View File

@ -62,8 +62,13 @@ void DeviceManager::createHostDevices(void)
NullDevice bcastDevice(this);
bcastDevice.setMac(kBcastMac);
int count = ifInfo->ip4.size(); // FIXME: IPv6
int count = ifInfo->ip4.size();
for (int i = 0; i < count; i++) {
// FIXME: Since we can't support multiple IPs with same mac,
// skip link-local IP - unless it is the only one
if (((ifInfo->ip4.at(i).address & 0xffff0000) == 0xa9fe0000)
&& (count > 1))
continue;
Device *device = HostDevice::create(port_->name(), this);
device->setMac(ifInfo->mac);
device->setIp4(ifInfo->ip4.at(i).address,
@ -82,7 +87,41 @@ void DeviceManager::createHostDevices(void)
bcastList_.insert(bcastDevice.key(), device);
qDebug("host(add): %s", qPrintable(device->config()));
break;
break; // FIXME: support multiple IPs with same mac
}
count = ifInfo->ip6.size();
for (int i = 0; i < count; i++) {
// FIXME: Since we can't support multiple IPs with same mac,
// skip link-local IP - unless it is the only one
if (((ifInfo->ip6.at(i).address.hi64() >> 48) == 0xfe80)
&& (count > 1))
continue;
NullDevice dk(this);
dk.setMac(ifInfo->mac);
Device *device = deviceList_.value(dk.key());
if (!device) {
device = HostDevice::create(port_->name(), this);
device->setMac(ifInfo->mac);
device->setIp6(ifInfo->ip6.at(i).address,
ifInfo->ip6.at(i).prefixLength,
ifInfo->ip6.at(i).gateway);
hostDeviceList_.append(device);
deviceList_.insert(device->key(), device);
sortedDeviceList_.insert(device->key(), device);
bcastList_.insert(bcastDevice.key(), device);
qDebug("host(add): %s", qPrintable(device->config()));
}
else {
device->setIp6(ifInfo->ip6.at(i).address,
ifInfo->ip6.at(i).prefixLength,
ifInfo->ip6.at(i).gateway);
qDebug("host(update): %s", qPrintable(device->config()));
}
break; // FIXME: support multiple IPs with same mac
}
}

View File

@ -92,12 +92,20 @@ void WindowsHostDevice::getNeighbors(OstEmul::DeviceNeighborList *neighbors)
if (nbrs->Table[i].Address.si_family == AF_INET) {
OstEmul::ArpEntry *arp = neighbors->add_arp();
arp->set_ip4(qToBigEndian(quint32(
nbrs->Table[i].Address.Ipv4.sin_addr.s_addr)));
arp->set_ip4(qFromBigEndian<quint32>(
nbrs->Table[i].Address.Ipv4.sin_addr.s_addr));
arp->set_mac(qFromBigEndian<quint64>(
nbrs->Table[i].PhysicalAddress) >> 16);
}
// TODO: IPv6
else if (nbrs->Table[i].Address.si_family == AF_INET6) {
OstEmul::NdpEntry *ndp = neighbors->add_ndp();
ndp->mutable_ip6()->set_hi(qFromBigEndian<quint64>(
nbrs->Table[i].Address.Ipv6.sin6_addr.u.Byte));
ndp->mutable_ip6()->set_lo(qFromBigEndian<quint64>(
nbrs->Table[i].Address.Ipv6.sin6_addr.u.Byte+8));
ndp->set_mac(qFromBigEndian<quint64>(
nbrs->Table[i].PhysicalAddress) >> 16);
}
}
FreeMibTable(nbrs);
@ -121,12 +129,22 @@ quint64 WindowsHostDevice::arpLookup(quint32 ip)
return 0;
}
quint64 WindowsHostDevice::ndpLookup(UInt128 /*ip*/)
quint64 WindowsHostDevice::ndpLookup(UInt128 ip)
{
if (!luid_.Value)
return 0;
return 0; // TODO
MIB_IPNET_ROW2 ndpEntry;
ndpEntry.InterfaceLuid = luid_;
ndpEntry.Address.si_family = AF_INET6;
memcpy(&ndpEntry.Address.Ipv6.sin6_addr.u, ip.toArray(), 16);
if ((GetIpNetEntry2(&ndpEntry) == NO_ERROR)
&& (ndpEntry.PhysicalAddressLength == 6)) {
return qFromBigEndian<quint64>(ndpEntry.PhysicalAddress) >> 16;
}
else
return 0;
}
void WindowsHostDevice::sendArpRequest(quint32 tgtIp)
@ -145,9 +163,20 @@ void WindowsHostDevice::sendArpRequest(quint32 tgtIp)
luid_.Value, errMsg(status));
}
void WindowsHostDevice::sendNeighborSolicit(UInt128 /*tgtIp*/)
void WindowsHostDevice::sendNeighborSolicit(UInt128 tgtIp)
{
// TODO
SOCKADDR_INET src;
memcpy(&src.Ipv6.sin6_addr.u, ip6_.toArray(), 16);
MIB_IPNET_ROW2 ndpEntry;
ndpEntry.InterfaceLuid = luid_;
ndpEntry.Address.si_family = AF_INET6;
memcpy(&ndpEntry.Address.Ipv6.sin6_addr.u, tgtIp.toArray(), 16);
ulong status = ResolveIpNetEntry2(&ndpEntry, &src);
if (ResolveIpNetEntry2(&ndpEntry, &src) != NO_ERROR)
qWarning("Resolve ndp failed for LUID %llx: %s",
luid_.Value, errMsg(status));
}
#endif

View File

@ -26,6 +26,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#ifdef Q_OS_WIN32
#include <ws2ipdef.h>
PIP_ADAPTER_ADDRESSES WinPcapPort::adapterList_ = NULL;
const uint OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114;
@ -261,6 +263,9 @@ void WinPcapPort::populateInterfaceInfo()
#define SOCKET_ADDRESS_IP4(x) \
(qFromBigEndian<quint32>(((sockaddr_in*)(x.lpSockaddr))->sin_addr.S_un.S_addr));
#define SOCKET_ADDRESS_IP6(x) \
(UInt128(((PSOCKADDR_IN6)(x.lpSockaddr))->sin6_addr.u.Byte));
// We may have multiple gateways - use the first for each family
quint32 ip4Gateway = 0;
PIP_ADAPTER_GATEWAY_ADDRESS gateway = adapter->FirstGatewayAddress;
@ -271,7 +276,15 @@ void WinPcapPort::populateInterfaceInfo()
}
gateway = gateway->Next;
}
// TODO: IPv6 Gateway
UInt128 ip6Gateway(0, 0);
gateway = adapter->FirstGatewayAddress;
while (gateway) {
if (SOCKET_ADDRESS_FAMILY(gateway->Address) == AF_INET6) {
ip6Gateway = SOCKET_ADDRESS_IP6(gateway->Address);
break;
}
gateway = gateway->Next;
}
PIP_ADAPTER_UNICAST_ADDRESS ucast = adapter->FirstUnicastAddress;
while (ucast) {
@ -282,11 +295,18 @@ void WinPcapPort::populateInterfaceInfo()
ip.gateway = ip4Gateway;
interfaceInfo_->ip4.append(ip);
}
// TODO: IPv6
else if (SOCKET_ADDRESS_FAMILY(ucast->Address) == AF_INET6) {
Ip6Config ip;
ip.address = SOCKET_ADDRESS_IP6(ucast->Address);
ip.prefixLength = ucast->OnLinkPrefixLength;
ip.gateway = ip6Gateway;
interfaceInfo_->ip6.append(ip);
}
ucast = ucast->Next;
}
#undef SOCKET_ADDRESS_FAMILY
#undef SOCKET_ADDRESS_IP4
#undef SOCKET_ADDRESS_IP6
}
void WinPcapPort::populateAdapterList()