//---------------------------------------------------------------------------- // If returned status is NO_ERROR, then pIpRouteTab points to a routing // table. //---------------------------------------------------------------------------- DWORD MyGetIpForwardTable(PMIB_IPFORWARDTABLE& pIpRouteTab, BOOL fOrder) { DWORD status = NO_ERROR; DWORD statusRetry = NO_ERROR; DWORD dwActualSize = 0; // query for buffer size needed status = GetIpForwardTable(pIpRouteTab, &dwActualSize, fOrder); if (status == NO_ERROR) { printf("No error\n"); return status; } else if (status == ERROR_INSUFFICIENT_BUFFER) { // need more space pIpRouteTab = (PMIB_IPFORWARDTABLE) malloc(dwActualSize); assert(pIpRouteTab); statusRetry = GetIpForwardTable(pIpRouteTab, &dwActualSize, fOrder); return statusRetry; } else { return status; } }
int DHCPMultiSend (struct sockaddr_in *pTo, struct dhcp_packet *pDhcpPkt, int nSize) { int Rc; DWORD Ark; char sFrom[64]; ADDRINFO Hints, *res; MIB_IPFORWARDTABLE *pForwardTable; MIB_IPFORWARDROW *pRow; ULONG forwardTableSize=0; // get info for bind memset (& Hints, 0, sizeof Hints); Hints.ai_family = AF_INET; Hints.ai_socktype = SOCK_DGRAM; strncpy (sFrom, inet_ntoa (pDhcpPkt->siaddr), sizeof sFrom); sFrom[sizeof sFrom -1]=0; //Rc = getaddrinfo (bUniCast ? NULL : sFrom, "bootps", & Hints, & res ); Rc = getaddrinfo (NULL , "bootps", & Hints, & res ); if (Rc==-1) { Rc = WSAGetLastError (); return FALSE; } // now it is necessary to parse the routing table to check all 255.255.255.255 entries // and send the datagram on all of them Rc = GetIpForwardTable(NULL, &forwardTableSize, FALSE); if (Rc!=ERROR_INSUFFICIENT_BUFFER) { Rc = WSAGetLastError (); freeaddrinfo (res); return FALSE; } pForwardTable = (MIB_IPFORWARDTABLE *) malloc (forwardTableSize); Rc = GetIpForwardTable(pForwardTable, &forwardTableSize, FALSE); for (Ark=0; Ark < pForwardTable->dwNumEntries; Ark++) { pRow = &pForwardTable->table[Ark]; if ( pRow->dwForwardDest == htonl (INADDR_NONE) && pRow->dwForwardMask == ULONG_MAX && pRow->dwForwardType == MIB_IPROUTE_TYPE_DIRECT && ((struct in_addr *) &pRow->dwForwardNextHop)->S_un.S_un_b.s_b1 != CLASS_A_LOOPBACK ) { (* (struct sockaddr_in *) res->ai_addr).sin_addr.S_un.S_addr = pRow->dwForwardNextHop; DHCPSendFrom ((struct sockaddr_in *) res->ai_addr, pTo, pDhcpPkt, nSize); } } // for all broadcast routing entries free (pForwardTable); freeaddrinfo (res); return Rc; } // DHCP Send
static void mib2IpRouteInit(void) { DWORD size = 0, ret = GetIpForwardTable(NULL, &size, TRUE); if (ret == ERROR_INSUFFICIENT_BUFFER) { ipRouteTable = HeapAlloc(GetProcessHeap(), 0, size); if (ipRouteTable) GetIpForwardTable(ipRouteTable, &size, TRUE); } }
static void mib2IpRouteInit(void) { DWORD size = 0, ret = GetIpForwardTable(NULL, &size, TRUE); if (ret == ERROR_INSUFFICIENT_BUFFER) { MIB_IPFORWARDTABLE *table = HeapAlloc(GetProcessHeap(), 0, size); if (table) { if (!GetIpForwardTable(table, &size, TRUE)) ipRouteTable = table; else HeapFree(GetProcessHeap(), 0, table ); } } }
int route_loop(route_t *r, route_handler callback, void *arg) { struct route_entry entry; ULONG len; int i, ret; for (len = sizeof(r->ipftable[0]); ; ) { if (r->ipftable) free(r->ipftable); r->ipftable = malloc(len); ret = GetIpForwardTable(r->ipftable, &len, FALSE); if (ret == NO_ERROR) break; else if (ret != ERROR_INSUFFICIENT_BUFFER) return (-1); } entry.route_dst.addr_type = ADDR_TYPE_IP; entry.route_dst.addr_bits = IP_ADDR_BITS; entry.route_gw.addr_type = ADDR_TYPE_IP; entry.route_gw.addr_bits = IP_ADDR_BITS; for (i = 0; i < (int)r->ipftable->dwNumEntries; i++) { entry.route_dst.addr_ip = r->ipftable->table[i].dwForwardDest; addr_mtob(&r->ipftable->table[i].dwForwardMask, IP_ADDR_LEN, &entry.route_dst.addr_bits); entry.route_gw.addr_ip = r->ipftable->table[i].dwForwardNextHop; if ((ret = (*callback)(&entry, arg)) != 0) return (ret); } return (0); }
bool DefaultRoute(int32_t *if_index, IPV4Address *default_gateway) { *default_gateway = IPV4Address(); *if_index = Interface::DEFAULT_INDEX; #ifdef USE_SYSCTL_FOR_DEFAULT_ROUTE return GetDefaultRouteWithSysctl(if_index, default_gateway); #elif defined(USE_NETLINK_FOR_DEFAULT_ROUTE) return GetDefaultRouteWithNetlink(if_index, default_gateway); #elif defined(_WIN32) ULONG size = 4096; PMIB_IPFORWARDTABLE forward_table = reinterpret_cast<PMIB_IPFORWARDTABLE>(malloc(size)); DWORD result = GetIpForwardTable(forward_table, &size, TRUE); if (result == NO_ERROR) { for (unsigned int i = 0; i < forward_table->dwNumEntries; ++i) { if (forward_table->table[i].dwForwardDest == 0) { *default_gateway = IPV4Address(forward_table->table[i].dwForwardNextHop); *if_index = forward_table->table[i].dwForwardIfIndex; } } free(forward_table); return true; } else { OLA_WARN << "GetIpForwardTable failed with " << GetLastError(); return false; } #else #error "DefaultRoute not implemented for this platform, please report this." // TODO(Peter): Do something else on machines without Netlink // No Netlink, can't do anything return false; #endif }
JNIEXPORT jobjectArray JNICALL Java_org_krakenapps_winapi_RoutingTable_getRoutingEntries(JNIEnv *env, jobject obj) { jclass clzRoutingEntry = (*env)->FindClass(env, "org/krakenapps/winapi/RoutingEntry"); jobjectArray entries = NULL; PMIB_IPFORWARDTABLE pIpForwardTable = NULL; ULONG dwSize = 0; DWORD error = 0; DWORD i; pIpForwardTable = (PMIB_IPFORWARDTABLE)malloc(sizeof(MIB_IPFORWARDTABLE)); if((error = GetIpForwardTable(pIpForwardTable, &dwSize, TRUE)) != NO_ERROR) { LPTSTR errorMsg = L"Error in GetIpForwardTable"; free(pIpForwardTable); switch(error) { case ERROR_INSUFFICIENT_BUFFER: pIpForwardTable = (PMIB_IPFORWARDTABLE)malloc(dwSize); if((error = GetIpForwardTable(pIpForwardTable, &dwSize, TRUE)) == NO_ERROR) { break; } case ERROR_INVALID_PARAMETER: errorMsg = L"Invalid parameter error in GetIpForwardTable"; case ERROR_NO_DATA: errorMsg = L"No data error in GetIpForwardTable"; case ERROR_NOT_SUPPORTED: errorMsg = L"Not supported error in GetIpForwardTable"; default: fwprintf(stderr, L"%s\n", errorMsg); return NULL; } } entries = (*env)->NewObjectArray(env, pIpForwardTable->dwNumEntries, clzRoutingEntry, NULL); for(i=0; i<pIpForwardTable->dwNumEntries; i++) { (*env)->SetObjectArrayElement(env, entries, i, getForwardRow(env, pIpForwardTable->table[i])); } free(pIpForwardTable); return entries; }
/* * Returns zero or more routes to the requestor from the active routing table */ DWORD request_net_config_get_routes(Remote *remote, Packet *packet) { Packet *response = packet_create_response(packet); DWORD result = ERROR_SUCCESS; PMIB_IPFORWARDTABLE table = NULL; DWORD tableSize = sizeof(MIB_IPFORWARDROW) * 96; DWORD index; do { // Allocate storage for the routing table if (!(table = (PMIB_IPFORWARDTABLE)malloc(tableSize))) { result = ERROR_NOT_ENOUGH_MEMORY; break; } // Get the routing table if (GetIpForwardTable(table, &tableSize, TRUE) != NO_ERROR) { result = GetLastError(); break; } // Enumerate it for (index = 0; index < table->dwNumEntries; index++) { Tlv route[3]; route[0].header.type = TLV_TYPE_SUBNET; route[0].header.length = sizeof(DWORD); route[0].buffer = (PUCHAR)&table->table[index].dwForwardDest; route[1].header.type = TLV_TYPE_NETMASK; route[1].header.length = sizeof(DWORD); route[1].buffer = (PUCHAR)&table->table[index].dwForwardMask; route[2].header.type = TLV_TYPE_GATEWAY; route[2].header.length = sizeof(DWORD); route[2].buffer = (PUCHAR)&table->table[index].dwForwardNextHop; packet_add_tlv_group(response, TLV_TYPE_NETWORK_ROUTE, route, 3); } } while (0); if (table) free(table); packet_transmit_response(result, remote, response); return ERROR_SUCCESS; }
ULONG route_ip(ULONG remote_ip) { ULONG size, i, bestmetric, result; MIB_IPFORWARDTABLE *buf; // get route table size = 0; if (GetIpForwardTable(NULL, &size, FALSE) != ERROR_INSUFFICIENT_BUFFER) return (ULONG)-1; buf = (MIB_IPFORWARDTABLE *)malloc(size); if (buf == NULL) return (ULONG)-1; if (GetIpForwardTable(buf, &size, FALSE) != NO_ERROR) { free(buf); return (ULONG)-1; } // find optimal route bestmetric = (ULONG)-1; result = (ULONG)-1; for (i = 0; i < buf->dwNumEntries; i++) { if ((remote_ip & buf->table[i].dwForwardMask) == (buf->table[i].dwForwardDest & buf->table[i].dwForwardMask)) { if (bestmetric == (ULONG)-1 || buf->table[i].dwForwardMetric1 > bestmetric) { bestmetric = buf->table[i].dwForwardMetric1; result = buf->table[i].dwForwardIfIndex; } } } free(buf); return result; }
static MIB_IPFORWARDTABLE * ssh_ip_route_get_ipforwardtable(void) { MIB_IPFORWARDTABLE *data = NULL; DWORD error; ULONG size; size = 0; error = GetIpForwardTable(NULL, &size, FALSE); if (error != ERROR_INSUFFICIENT_BUFFER) { if (error == ERROR_NO_DATA) { SSH_DEBUG(SSH_D_FAIL, ("No IP routes")); return NULL; } SSH_DEBUG(SSH_D_FAIL, ("GetIpForwardTable: error 0x%08X", (unsigned)error)); return NULL; } if (!(data = ssh_malloc(size))) { SSH_DEBUG(SSH_D_FAIL, ("out of memory allocating IP route table")); return NULL; } error = GetIpForwardTable(data, &size, FALSE); if (error != NO_ERROR) { SSH_DEBUG(SSH_D_FAIL, ("GetIpForwardTable: error 0x%08X", (unsigned)error)); ssh_free(data); return NULL; } return data; }
GenericRoutingTable::ROUTING_TABLE GenericRoutingTable::detail::getRoutingTableWin32 () { ROUTING_TABLE retTable; #ifdef WIN32 PMIB_IPFORWARDTABLE table = NULL; ULONG size = 0; DWORD ret = 0; BOOL order = TRUE; do { if (size > 0) { if (table != NULL) free (table); table = (PMIB_IPFORWARDTABLE) malloc (size); } ret = GetIpForwardTable (table, &size, order); } while (ret == ERROR_INSUFFICIENT_BUFFER); if (ret != NO_ERROR) return retTable; if (table == NULL) return retTable; for (DWORD i = 0; i<table->dwNumEntries; i++) { MIB_IPFORWARDROW item = table->table[i]; IP_ADDR addr (item.dwForwardDest); IP_ADDR mask (item.dwForwardMask); retTable.push_back (ROUTING_ENTRY (addr, mask)); } free (table); #endif // WIN32 return retTable; }
int eXosip_guess_ip_for_via (int family, char *address, int size) { /* w2000 and W95/98 */ unsigned long best_interface_index; DWORD hr; /* NT4 (sp4 only?) */ PMIB_IPFORWARDTABLE ipfwdt; DWORD siz_ipfwd_table = 0; unsigned int ipf_cnt; address[0] = '\0'; best_interface_index = -1; /* w2000 and W95/98 only */ hr = GetBestInterface(inet_addr("217.12.3.11"),&best_interface_index); if (hr) { LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &lpMsgBuf, 0, NULL); OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO4, NULL, "GetBestInterface: %s\r\n", lpMsgBuf)); best_interface_index = -1; } if (best_interface_index != -1) { /* probably W2000 or W95/W98 */ char *servername; char *serverip; char *netmask; OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO4, NULL, "Default Interface found %i\r\n", best_interface_index)); if (0 == ppl_dns_get_local_fqdn(&servername, &serverip, &netmask, best_interface_index)) { osip_strncpy(address, serverip, size); osip_free(servername); osip_free(serverip); osip_free(netmask); return 0; } return -1; } if (!GetIpForwardTable(NULL, &siz_ipfwd_table, FALSE) == ERROR_INSUFFICIENT_BUFFER || !(ipfwdt = (PMIB_IPFORWARDTABLE) alloca (siz_ipfwd_table))) { OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO4, NULL, "Allocation error\r\n")); return -1; } /* NT4 (sp4 support only?) */ if (!GetIpForwardTable(ipfwdt, &siz_ipfwd_table, FALSE)) { for (ipf_cnt = 0; ipf_cnt < ipfwdt->dwNumEntries; ++ipf_cnt) { if (ipfwdt->table[ipf_cnt].dwForwardDest == 0) { /* default gateway found */ char *servername; char *serverip; char *netmask; OSIP_TRACE (osip_trace (__FILE__, __LINE__, OSIP_INFO4, NULL, "Default Interface found %i\r\n", ipfwdt->table[ipf_cnt].dwForwardIfIndex)); if (0 == ppl_dns_get_local_fqdn(&servername, &serverip, &netmask, ipfwdt->table[ipf_cnt].dwForwardIfIndex)) { osip_strncpy(address, serverip, size); osip_free(servername); osip_free(serverip); osip_free(netmask); return 0; } return -1; } } } /* no default gateway interface found */ return -1; }
DWORD WINAPI WsControl(DWORD protocol, DWORD action, LPVOID pRequestInfo, LPDWORD pcbRequestInfoLen, LPVOID pResponseInfo, LPDWORD pcbResponseInfoLen) { /* Get the command structure into a pointer we can use, rather than void */ TDIObjectID *pcommand = pRequestInfo; /* validate input parameters. Error codes are from winerror.h, not from * winsock.h. pcbResponseInfoLen is apparently allowed to be NULL for some * commands, since winipcfg.exe fails if we ensure it's non-NULL in every * case. */ if (protocol != IPPROTO_TCP) return ERROR_INVALID_PARAMETER; if (!pcommand) return ERROR_INVALID_PARAMETER; if (!pcbRequestInfoLen) return ERROR_INVALID_ACCESS; if (*pcbRequestInfoLen < sizeof(TDIObjectID)) return ERROR_INVALID_ACCESS; if (!pResponseInfo) return ERROR_INVALID_PARAMETER; if (pcommand->toi_type != INFO_TYPE_PROVIDER) return ERROR_INVALID_PARAMETER; TRACE (" WsControl TOI_ID=>0x%lx<, {TEI_ENTITY=0x%lx, TEI_INSTANCE=0x%lx}, TOI_CLASS=0x%lx, TOI_TYPE=0x%lx\n", pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance, pcommand->toi_class, pcommand->toi_type ); switch (action) { case WSCNTL_TCPIP_QUERY_INFO: { if (pcommand->toi_class != INFO_CLASS_GENERIC && pcommand->toi_class != INFO_CLASS_PROTOCOL) { ERR("Unexpected class %ld for WSCNTL_TCPIP_QUERY_INFO\n", pcommand->toi_class); return ERROR_BAD_ENVIRONMENT; } switch (pcommand->toi_id) { /* ENTITY_LIST_ID gets the list of "entity IDs", where an entity may represent an interface, or a datagram service, or address translation, or other fun things. Typically an entity ID represents a class of service, which is further queried for what type it is. Different types will then have more specific queries defined. */ case ENTITY_LIST_ID: { TDIEntityID *baseptr = pResponseInfo; DWORD numInt, i, ifTable, spaceNeeded; PMIB_IFTABLE table; if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; if (pcommand->toi_class != INFO_CLASS_GENERIC) { FIXME ("Unexpected Option for ENTITY_LIST_ID request -> toi_class=0x%lx\n", pcommand->toi_class); return (ERROR_BAD_ENVIRONMENT); } GetNumberOfInterfaces(&numInt); spaceNeeded = sizeof(TDIEntityID) * (numInt * 2 + 3); if (*pcbResponseInfoLen < spaceNeeded) return (ERROR_LOCK_VIOLATION); ifTable = 0; GetIfTable(NULL, &ifTable, FALSE); table = HeapAlloc( GetProcessHeap(), 0, ifTable ); if (!table) return ERROR_NOT_ENOUGH_MEMORY; GetIfTable(table, &ifTable, FALSE); spaceNeeded = sizeof(TDIEntityID) * (table->dwNumEntries + 4); if (*pcbResponseInfoLen < spaceNeeded) { HeapFree( GetProcessHeap(), 0, table ); return ERROR_LOCK_VIOLATION; } memset(baseptr, 0, spaceNeeded); for (i = 0; i < table->dwNumEntries; i++) { /* Return IF_GENERIC and CL_NL_ENTITY on every interface, and * AT_ENTITY, CL_TL_ENTITY, and CO_TL_ENTITY on the first * interface. MS returns them only on the loopback interface, * but it doesn't seem to matter. */ if (i == 0) { baseptr->tei_entity = CO_TL_ENTITY; baseptr->tei_instance = table->table[i].dwIndex; baseptr++; baseptr->tei_entity = CL_TL_ENTITY; baseptr->tei_instance = table->table[i].dwIndex; baseptr++; baseptr->tei_entity = AT_ENTITY; baseptr->tei_instance = table->table[i].dwIndex; baseptr++; } baseptr->tei_entity = CL_NL_ENTITY; baseptr->tei_instance = table->table[i].dwIndex; baseptr++; baseptr->tei_entity = IF_GENERIC; baseptr->tei_instance = table->table[i].dwIndex; baseptr++; } *pcbResponseInfoLen = spaceNeeded; HeapFree( GetProcessHeap(), 0, table ); break; } /* Returns MIB-II statistics for an interface */ case ENTITY_TYPE_ID: switch (pcommand->toi_entity.tei_entity) { case IF_GENERIC: if (pcommand->toi_class == INFO_CLASS_GENERIC) { if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; *((ULONG *)pResponseInfo) = IF_MIB; *pcbResponseInfoLen = sizeof(ULONG); } else if (pcommand->toi_class == INFO_CLASS_PROTOCOL) { MIB_IFROW row; DWORD index = pcommand->toi_entity.tei_instance, ret; DWORD size = sizeof(row) - sizeof(row.wszName) - sizeof(row.bDescr); if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; if (*pcbResponseInfoLen < size) return (ERROR_LOCK_VIOLATION); row.dwIndex = index; ret = GetIfEntry(&row); if (ret != NO_ERROR) { /* FIXME: Win98's arp.exe insists on querying index 1 for * its MIB-II stats, regardless of the tei_instances * returned in the ENTITY_LIST query above. If the query * fails, arp.exe fails. So, I do this hack return value * if index is 1 and the query failed just to get arp.exe * to continue. */ if (index == 1) return NO_ERROR; ERR ("Error retrieving data for interface index %u\n", index); return ret; } size = sizeof(row) - sizeof(row.wszName) - sizeof(row.bDescr) + row.dwDescrLen; if (*pcbResponseInfoLen < size) return (ERROR_LOCK_VIOLATION); memcpy(pResponseInfo, &row.dwIndex, size); *pcbResponseInfoLen = size; } break; /* Returns address-translation related data. In our case, this is * ARP. */ case AT_ENTITY: if (pcommand->toi_class == INFO_CLASS_GENERIC) { if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; *((ULONG *)pResponseInfo) = AT_ARP; *pcbResponseInfoLen = sizeof(ULONG); } else if (pcommand->toi_class == INFO_CLASS_PROTOCOL) { PMIB_IPNETTABLE table; DWORD size; PULONG output = pResponseInfo; if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; if (*pcbResponseInfoLen < sizeof(ULONG) * 2) return (ERROR_LOCK_VIOLATION); GetIpNetTable(NULL, &size, FALSE); table = HeapAlloc( GetProcessHeap(), 0, size ); if (!table) return ERROR_NOT_ENOUGH_MEMORY; GetIpNetTable(table, &size, FALSE); /* FIXME: I don't understand the meaning of the ARP output * very well, but it seems to indicate how many ARP entries * exist. I don't know whether this should reflect the * number per interface, as I'm only testing with a single * interface. So, I lie and say all ARP entries exist on * a single interface--the first one that appears in the * ARP table. */ *(output++) = table->dwNumEntries; *output = table->table[0].dwIndex; HeapFree( GetProcessHeap(), 0, table ); *pcbResponseInfoLen = sizeof(ULONG) * 2; } break; /* Returns connectionless network layer statistics--in our case, * this is IP. */ case CL_NL_ENTITY: if (pcommand->toi_class == INFO_CLASS_GENERIC) { if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; *((ULONG *)pResponseInfo) = CL_NL_IP; *pcbResponseInfoLen = sizeof(ULONG); } else if (pcommand->toi_class == INFO_CLASS_PROTOCOL) { if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; if (*pcbResponseInfoLen < sizeof(MIB_IPSTATS)) return ERROR_LOCK_VIOLATION; GetIpStatistics(pResponseInfo); *pcbResponseInfoLen = sizeof(MIB_IPSTATS); } break; /* Returns connectionless transport layer statistics--in our case, * this is UDP. */ case CL_TL_ENTITY: if (pcommand->toi_class == INFO_CLASS_GENERIC) { if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; *((ULONG *)pResponseInfo) = CL_TL_UDP; *pcbResponseInfoLen = sizeof(ULONG); } else if (pcommand->toi_class == INFO_CLASS_PROTOCOL) { if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; if (*pcbResponseInfoLen < sizeof(MIB_UDPSTATS)) return ERROR_LOCK_VIOLATION; GetUdpStatistics(pResponseInfo); *pcbResponseInfoLen = sizeof(MIB_UDPSTATS); } break; /* Returns connection-oriented transport layer statistics--in our * case, this is TCP. */ case CO_TL_ENTITY: if (pcommand->toi_class == INFO_CLASS_GENERIC) { if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; *((ULONG *)pResponseInfo) = CO_TL_TCP; *pcbResponseInfoLen = sizeof(ULONG); } else if (pcommand->toi_class == INFO_CLASS_PROTOCOL) { if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; if (*pcbResponseInfoLen < sizeof(MIB_TCPSTATS)) return ERROR_LOCK_VIOLATION; GetTcpStatistics(pResponseInfo); *pcbResponseInfoLen = sizeof(MIB_TCPSTATS); } break; default: ERR("Unknown entity %ld for ENTITY_TYPE_ID query\n", pcommand->toi_entity.tei_entity); } break; /* This call returns the IP address, subnet mask, and broadcast * address for an interface. If there are multiple IP addresses for * the interface with the given index, returns the "first" one. */ case IP_MIB_ADDRTABLE_ENTRY_ID: { DWORD index = pcommand->toi_entity.tei_instance; PMIB_IPADDRROW baseIPInfo = pResponseInfo; PMIB_IPADDRTABLE table; DWORD tableSize, i; if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; if (*pcbResponseInfoLen < sizeof(MIB_IPADDRROW)) return (ERROR_LOCK_VIOLATION); /* get entire table, because there isn't an exported function that gets just one entry. */ tableSize = 0; GetIpAddrTable(NULL, &tableSize, FALSE); table = HeapAlloc( GetProcessHeap(), 0, tableSize ); if (!table) return ERROR_NOT_ENOUGH_MEMORY; GetIpAddrTable(table, &tableSize, FALSE); for (i = 0; i < table->dwNumEntries; i++) { if (table->table[i].dwIndex == index) { TRACE("Found IP info for tei_instance 0x%x:\n", index); TRACE("IP 0x%08x, mask 0x%08x\n", table->table[i].dwAddr, table->table[i].dwMask); *baseIPInfo = table->table[i]; break; } } HeapFree( GetProcessHeap(), 0, table ); *pcbResponseInfoLen = sizeof(MIB_IPADDRROW); break; } case IP_MIB_TABLE_ENTRY_ID: { switch (pcommand->toi_entity.tei_entity) { /* This call returns the routing table. * No official documentation found, even the name of the command is unknown. * Work is based on * http://www.cyberport.com/~tangent/programming/winsock/articles/wscontrol.html * and testings done with winipcfg.exe, route.exe and ipconfig.exe. * pcommand->toi_entity.tei_instance seems to be the interface number * but route.exe outputs only the information for the last interface * if only the routes for the pcommand->toi_entity.tei_instance * interface are returned. */ case CL_NL_ENTITY: { DWORD routeTableSize, numRoutes, ndx, ret; PMIB_IPFORWARDTABLE table; IPRouteEntry *winRouteTable = pResponseInfo; if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; ret = GetIpForwardTable(NULL, &routeTableSize, FALSE); if (ret != ERROR_INSUFFICIENT_BUFFER) return ret; numRoutes = (routeTableSize - sizeof(MIB_IPFORWARDTABLE)) / sizeof(MIB_IPFORWARDROW) + 1; if (*pcbResponseInfoLen < sizeof(IPRouteEntry) * numRoutes) return (ERROR_LOCK_VIOLATION); table = HeapAlloc( GetProcessHeap(), 0, routeTableSize ); if (!table) return ERROR_NOT_ENOUGH_MEMORY; ret = GetIpForwardTable(table, &routeTableSize, FALSE); if (ret != NO_ERROR) { HeapFree( GetProcessHeap(), 0, table ); return ret; } memset(pResponseInfo, 0, sizeof(IPRouteEntry) * numRoutes); for (ndx = 0; ndx < table->dwNumEntries; ndx++) { winRouteTable->ire_addr = table->table[ndx].dwForwardDest; winRouteTable->ire_index = table->table[ndx].dwForwardIfIndex; winRouteTable->ire_metric = table->table[ndx].dwForwardMetric1; /* winRouteTable->ire_option4 = winRouteTable->ire_option5 = winRouteTable->ire_option6 = */ winRouteTable->ire_gw = table->table[ndx].dwForwardNextHop; /* winRouteTable->ire_option8 = winRouteTable->ire_option9 = winRouteTable->ire_option10 = */ winRouteTable->ire_mask = table->table[ndx].dwForwardMask; /* winRouteTable->ire_option12 = */ winRouteTable++; } /* calculate the length of the data in the output buffer */ *pcbResponseInfoLen = sizeof(IPRouteEntry) * table->dwNumEntries; HeapFree( GetProcessHeap(), 0, table ); } break; case AT_ARP: { DWORD arpTableSize, numEntries, ret; PMIB_IPNETTABLE table; if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; ret = GetIpNetTable(NULL, &arpTableSize, FALSE); if (ret != ERROR_INSUFFICIENT_BUFFER) return ret; numEntries = (arpTableSize - sizeof(MIB_IPNETTABLE)) / sizeof(MIB_IPNETROW) + 1; if (*pcbResponseInfoLen < sizeof(MIB_IPNETROW) * numEntries) return (ERROR_LOCK_VIOLATION); table = HeapAlloc( GetProcessHeap(), 0, arpTableSize ); if (!table) return ERROR_NOT_ENOUGH_MEMORY; ret = GetIpNetTable(table, &arpTableSize, FALSE); if (ret != NO_ERROR) { HeapFree( GetProcessHeap(), 0, table ); return ret; } if (*pcbResponseInfoLen < sizeof(MIB_IPNETROW) * table->dwNumEntries) { HeapFree( GetProcessHeap(), 0, table ); return ERROR_LOCK_VIOLATION; } memcpy(pResponseInfo, table->table, sizeof(MIB_IPNETROW) * table->dwNumEntries); /* calculate the length of the data in the output buffer */ *pcbResponseInfoLen = sizeof(MIB_IPNETROW) * table->dwNumEntries; HeapFree( GetProcessHeap(), 0, table ); } break; case CO_TL_ENTITY: { DWORD tcpTableSize, numEntries, ret; PMIB_TCPTABLE table; DWORD i; if (!pcbResponseInfoLen) return ERROR_BAD_ENVIRONMENT; ret = GetTcpTable(NULL, &tcpTableSize, FALSE); if (ret != ERROR_INSUFFICIENT_BUFFER) return ret; numEntries = (tcpTableSize - sizeof(MIB_TCPTABLE)) / sizeof(MIB_TCPROW) + 1; if (*pcbResponseInfoLen < sizeof(MIB_TCPROW) * numEntries) return (ERROR_LOCK_VIOLATION); table = HeapAlloc( GetProcessHeap(), 0, tcpTableSize ); if (!table) return ERROR_NOT_ENOUGH_MEMORY; ret = GetTcpTable(table, &tcpTableSize, FALSE); if (ret != NO_ERROR) { HeapFree( GetProcessHeap(), 0, table ); return ret; } if (*pcbResponseInfoLen < sizeof(MIB_TCPROW) * table->dwNumEntries) { HeapFree( GetProcessHeap(), 0, table ); return ERROR_LOCK_VIOLATION; } for (i = 0; i < table->dwNumEntries; i++) { USHORT sPort; sPort = ntohs((USHORT)table->table[i].dwLocalPort); table->table[i].dwLocalPort = (DWORD)sPort; sPort = ntohs((USHORT)table->table[i].dwRemotePort); table->table[i].dwRemotePort = (DWORD)sPort; } memcpy(pResponseInfo, table->table, sizeof(MIB_TCPROW) * table->dwNumEntries); /* calculate the length of the data in the output buffer */ *pcbResponseInfoLen = sizeof(MIB_TCPROW) * table->dwNumEntries; HeapFree( GetProcessHeap(), 0, table ); } break; default: { FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx\n", pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance, pcommand->toi_class); return (ERROR_BAD_ENVIRONMENT); } } } break; default: { FIXME ("Command ID Not Supported -> toi_id=0x%lx, toi_entity={tei_entity=0x%lx, tei_instance=0x%lx}, toi_class=0x%lx\n", pcommand->toi_id, pcommand->toi_entity.tei_entity, pcommand->toi_entity.tei_instance, pcommand->toi_class); return (ERROR_BAD_ENVIRONMENT); } } break; } case WSCNTL_TCPIP_ICMP_ECHO: { unsigned int addr = *(unsigned int*)pRequestInfo; #if 0 int timeout= *(unsigned int*)(inbuf+4); short x1 = *(unsigned short*)(inbuf+8); short sendbufsize = *(unsigned short*)(inbuf+10); char x2 = *(unsigned char*)(inbuf+12); char ttl = *(unsigned char*)(inbuf+13); char service = *(unsigned char*)(inbuf+14); char type= *(unsigned char*)(inbuf+15); /* 0x2: don't fragment*/ #endif FIXME("(ICMP_ECHO) to 0x%08x stub\n", addr); break; } default: FIXME("Protocol Not Supported -> protocol=0x%x, action=0x%x, Request=%p, RequestLen=%p, Response=%p, ResponseLen=%p\n", protocol, action, pRequestInfo, pcbRequestInfoLen, pResponseInfo, pcbResponseInfoLen); return (WSAEOPNOTSUPP); } return (WSCTL_SUCCESS); }
bool NetworkObserver::canConnect() { #if defined(WIN32) /* w2000 and W95/98 */ unsigned long best_interface_index; DWORD hr; /* NT4 (sp4 only?) */ PMIB_IPFORWARDTABLE ipfwdt; DWORD siz_ipfwd_table = 0; unsigned int ipf_cnt; best_interface_index = -1; /* w2000 and W95/98 only */ hr = GetBestInterface(inet_addr("216.151.151.59"),&best_interface_index); // VOXOX -ASV- 07-09-2009: we ping voxox.com to know if voxox has internet if (hr) { LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR) &lpMsgBuf, 0, NULL); best_interface_index = -1; } if (best_interface_index != -1) { /* probably W2000 or W95/W98 */ char *servername; char *serverip; char *netmask; if (ppl_dns_get_local_fqdn(&servername, &serverip, &netmask, best_interface_index)) { /*if(servername) delete servername; if(serverip) delete serverip; if(netmask) delete netmask;*/ return true; } return false; } if (!GetIpForwardTable(NULL, &siz_ipfwd_table, FALSE) == ERROR_INSUFFICIENT_BUFFER || !(ipfwdt = (PMIB_IPFORWARDTABLE) alloca (siz_ipfwd_table))) { return false; } /* NT4 (sp4 support only?) */ if (!GetIpForwardTable(ipfwdt, &siz_ipfwd_table, FALSE)) { for (ipf_cnt = 0; ipf_cnt < ipfwdt->dwNumEntries; ++ipf_cnt) { if (ipfwdt->table[ipf_cnt].dwForwardDest == 0) { /* default gateway found */ char *servername; char *serverip; char *netmask; if (ppl_dns_get_local_fqdn(&servername, &serverip, &netmask, ipfwdt->table[ipf_cnt].dwForwardIfIndex)) { delete servername; delete serverip; delete netmask; return true; } return false; } } } /* no default gateway interface found */ return true; #else #if defined(OS_MACOSX) socklen_t len; #else unsigned int len; #endif int sock_rt, on=1; struct sockaddr_in iface_out; struct sockaddr_in remote; memset(&remote, 0, sizeof(struct sockaddr_in)); remote.sin_family = AF_INET; remote.sin_addr.s_addr = inet_addr("216.151.151.59");// VOXOX -ASV- 07-09-2009: we ping voxox.com to know if voxox has internet remote.sin_port = htons(80); memset(&iface_out, 0, sizeof(iface_out)); sock_rt = socket(AF_INET, SOCK_DGRAM, 0 ); if (setsockopt(sock_rt, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1) { close(sock_rt); return false; } if (::connect(sock_rt, (struct sockaddr*)&remote, sizeof(struct sockaddr_in)) == -1 ) { close(sock_rt); return false; } len = sizeof(iface_out); if (getsockname(sock_rt, (struct sockaddr *)&iface_out, &len) == -1 ) { close(sock_rt); return false; } close(sock_rt); if (iface_out.sin_addr.s_addr == 0) { /* what is this case?? */ return false; } return true; #endif }
IPCCommandResult NetIPTop::IOCtl(const IOCtlRequest& request) { if (Core::g_want_determinism) { return GetDefaultReply(IPC_EACCES); } s32 return_value = 0; switch (request.request) { case IOCTL_SO_STARTUP: { request.Log(GetDeviceName(), LogTypes::IOS_WC24); break; } case IOCTL_SO_SOCKET: { u32 af = Memory::Read_U32(request.buffer_in); u32 type = Memory::Read_U32(request.buffer_in + 4); u32 prot = Memory::Read_U32(request.buffer_in + 8); WiiSockMan& sm = WiiSockMan::GetInstance(); return_value = sm.NewSocket(af, type, prot); INFO_LOG(IOS_NET, "IOCTL_SO_SOCKET " "Socket: %08x (%d,%d,%d), BufferIn: (%08x, %i), BufferOut: (%08x, %i)", return_value, af, type, prot, request.buffer_in, request.buffer_in_size, request.buffer_out, request.buffer_out_size); break; } case IOCTL_SO_ICMPSOCKET: { u32 pf = Memory::Read_U32(request.buffer_in); WiiSockMan& sm = WiiSockMan::GetInstance(); return_value = sm.NewSocket(pf, SOCK_RAW, IPPROTO_ICMP); INFO_LOG(IOS_NET, "IOCTL_SO_ICMPSOCKET(%x) %d", pf, return_value); break; } case IOCTL_SO_CLOSE: case IOCTL_SO_ICMPCLOSE: { u32 fd = Memory::Read_U32(request.buffer_in); WiiSockMan& sm = WiiSockMan::GetInstance(); return_value = sm.DeleteSocket(fd); INFO_LOG(IOS_NET, "%s(%x) %x", request.request == IOCTL_SO_ICMPCLOSE ? "IOCTL_SO_ICMPCLOSE" : "IOCTL_SO_CLOSE", fd, return_value); break; } case IOCTL_SO_ACCEPT: case IOCTL_SO_BIND: case IOCTL_SO_CONNECT: case IOCTL_SO_FCNTL: { u32 fd = Memory::Read_U32(request.buffer_in); WiiSockMan& sm = WiiSockMan::GetInstance(); sm.DoSock(fd, request, static_cast<NET_IOCTL>(request.request)); return GetNoReply(); } ///////////////////////////////////////////////////////////// // TODO: Tidy all below // ///////////////////////////////////////////////////////////// case IOCTL_SO_SHUTDOWN: { request.Log(GetDeviceName(), LogTypes::IOS_WC24); u32 fd = Memory::Read_U32(request.buffer_in); u32 how = Memory::Read_U32(request.buffer_in + 4); int ret = shutdown(fd, how); return_value = WiiSockMan::GetNetErrorCode(ret, "SO_SHUTDOWN", false); break; } case IOCTL_SO_LISTEN: { u32 fd = Memory::Read_U32(request.buffer_in); u32 BACKLOG = Memory::Read_U32(request.buffer_in + 0x04); u32 ret = listen(fd, BACKLOG); return_value = WiiSockMan::GetNetErrorCode(ret, "SO_LISTEN", false); request.Log(GetDeviceName(), LogTypes::IOS_WC24); break; } case IOCTL_SO_GETSOCKOPT: { u32 fd = Memory::Read_U32(request.buffer_out); u32 level = Memory::Read_U32(request.buffer_out + 4); u32 optname = Memory::Read_U32(request.buffer_out + 8); request.Log(GetDeviceName(), LogTypes::IOS_WC24); // Do the level/optname translation int nat_level = -1, nat_optname = -1; for (auto& map : opt_level_mapping) if (level == map[1]) nat_level = map[0]; for (auto& map : opt_name_mapping) if (optname == map[1]) nat_optname = map[0]; u8 optval[20]; u32 optlen = 4; int ret = getsockopt(fd, nat_level, nat_optname, (char*)&optval, (socklen_t*)&optlen); return_value = WiiSockMan::GetNetErrorCode(ret, "SO_GETSOCKOPT", false); Memory::Write_U32(optlen, request.buffer_out + 0xC); Memory::CopyToEmu(request.buffer_out + 0x10, optval, optlen); if (optname == SO_ERROR) { s32 last_error = WiiSockMan::GetInstance().GetLastNetError(); Memory::Write_U32(sizeof(s32), request.buffer_out + 0xC); Memory::Write_U32(last_error, request.buffer_out + 0x10); } break; } case IOCTL_SO_SETSOCKOPT: { u32 fd = Memory::Read_U32(request.buffer_in); u32 level = Memory::Read_U32(request.buffer_in + 4); u32 optname = Memory::Read_U32(request.buffer_in + 8); u32 optlen = Memory::Read_U32(request.buffer_in + 0xc); u8 optval[20]; optlen = std::min(optlen, (u32)sizeof(optval)); Memory::CopyFromEmu(optval, request.buffer_in + 0x10, optlen); INFO_LOG(IOS_NET, "IOCTL_SO_SETSOCKOPT(%08x, %08x, %08x, %08x) " "BufferIn: (%08x, %i), BufferOut: (%08x, %i)" "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx " "%02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx %02hhx", fd, level, optname, optlen, request.buffer_in, request.buffer_in_size, request.buffer_out, request.buffer_out_size, optval[0], optval[1], optval[2], optval[3], optval[4], optval[5], optval[6], optval[7], optval[8], optval[9], optval[10], optval[11], optval[12], optval[13], optval[14], optval[15], optval[16], optval[17], optval[18], optval[19]); // TODO: bug booto about this, 0x2005 most likely timeout related, default value on Wii is , // 0x2001 is most likely tcpnodelay if (level == 6 && (optname == 0x2005 || optname == 0x2001)) { return_value = 0; break; } // Do the level/optname translation int nat_level = -1, nat_optname = -1; for (auto& map : opt_level_mapping) if (level == map[1]) nat_level = map[0]; for (auto& map : opt_name_mapping) if (optname == map[1]) nat_optname = map[0]; if (nat_level == -1 || nat_optname == -1) { INFO_LOG(IOS_NET, "SO_SETSOCKOPT: unknown level %d or optname %d", level, optname); // Default to the given level/optname. They match on Windows... nat_level = level; nat_optname = optname; } int ret = setsockopt(fd, nat_level, nat_optname, (char*)optval, optlen); return_value = WiiSockMan::GetNetErrorCode(ret, "SO_SETSOCKOPT", false); break; } case IOCTL_SO_GETSOCKNAME: { u32 fd = Memory::Read_U32(request.buffer_in); request.Log(GetDeviceName(), LogTypes::IOS_WC24); sockaddr sa; socklen_t sa_len; sa_len = sizeof(sa); int ret = getsockname(fd, &sa, &sa_len); if (request.buffer_out_size < 2 + sizeof(sa.sa_data)) WARN_LOG(IOS_NET, "IOCTL_SO_GETSOCKNAME output buffer is too small. Truncating"); if (request.buffer_out_size > 0) Memory::Write_U8(request.buffer_out_size, request.buffer_out); if (request.buffer_out_size > 1) Memory::Write_U8(sa.sa_family & 0xFF, request.buffer_out + 1); if (request.buffer_out_size > 2) Memory::CopyToEmu(request.buffer_out + 2, &sa.sa_data, std::min<size_t>(sizeof(sa.sa_data), request.buffer_out_size - 2)); return_value = ret; break; } case IOCTL_SO_GETPEERNAME: { u32 fd = Memory::Read_U32(request.buffer_in); sockaddr sa; socklen_t sa_len; sa_len = sizeof(sa); int ret = getpeername(fd, &sa, &sa_len); if (request.buffer_out_size < 2 + sizeof(sa.sa_data)) WARN_LOG(IOS_NET, "IOCTL_SO_GETPEERNAME output buffer is too small. Truncating"); if (request.buffer_out_size > 0) Memory::Write_U8(request.buffer_out_size, request.buffer_out); if (request.buffer_out_size > 1) Memory::Write_U8(AF_INET, request.buffer_out + 1); if (request.buffer_out_size > 2) Memory::CopyToEmu(request.buffer_out + 2, &sa.sa_data, std::min<size_t>(sizeof(sa.sa_data), request.buffer_out_size - 2)); INFO_LOG(IOS_NET, "IOCTL_SO_GETPEERNAME(%x)", fd); return_value = ret; break; } case IOCTL_SO_GETHOSTID: { request.Log(GetDeviceName(), LogTypes::IOS_WC24); #ifdef _WIN32 DWORD forwardTableSize, ipTableSize, result; DWORD ifIndex = -1; std::unique_ptr<MIB_IPFORWARDTABLE> forwardTable; std::unique_ptr<MIB_IPADDRTABLE> ipTable; forwardTableSize = 0; if (GetIpForwardTable(nullptr, &forwardTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) { forwardTable = std::unique_ptr<MIB_IPFORWARDTABLE>((PMIB_IPFORWARDTABLE) operator new(forwardTableSize)); } ipTableSize = 0; if (GetIpAddrTable(nullptr, &ipTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) { ipTable = std::unique_ptr<MIB_IPADDRTABLE>((PMIB_IPADDRTABLE) operator new(ipTableSize)); } // find the interface IP used for the default route and use that result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE); while (result == NO_ERROR || result == ERROR_MORE_DATA) // can return ERROR_MORE_DATA on XP even after the first call { for (DWORD i = 0; i < forwardTable->dwNumEntries; ++i) { if (forwardTable->table[i].dwForwardDest == 0) { ifIndex = forwardTable->table[i].dwForwardIfIndex; break; } } if (result == NO_ERROR || ifIndex != -1) break; result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE); } if (ifIndex != -1 && GetIpAddrTable(ipTable.get(), &ipTableSize, FALSE) == NO_ERROR) { for (DWORD i = 0; i < ipTable->dwNumEntries; ++i) { if (ipTable->table[i].dwIndex == ifIndex) { return_value = Common::swap32(ipTable->table[i].dwAddr); break; } } } #endif // default placeholder, in case of failure if (return_value == 0) return_value = 192 << 24 | 168 << 16 | 1 << 8 | 150; break; } case IOCTL_SO_INETATON: { std::string hostname = Memory::GetString(request.buffer_in); struct hostent* remoteHost = gethostbyname(hostname.c_str()); if (remoteHost == nullptr || remoteHost->h_addr_list == nullptr || remoteHost->h_addr_list[0] == nullptr) { INFO_LOG(IOS_NET, "IOCTL_SO_INETATON = -1 " "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: None", hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out, request.buffer_out_size); return_value = 0; } else { Memory::Write_U32(Common::swap32(*(u32*)remoteHost->h_addr_list[0]), request.buffer_out); INFO_LOG(IOS_NET, "IOCTL_SO_INETATON = 0 " "%s, BufferIn: (%08x, %i), BufferOut: (%08x, %i), IP Found: %08X", hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out, request.buffer_out_size, Common::swap32(*(u32*)remoteHost->h_addr_list[0])); return_value = 1; } break; } case IOCTL_SO_INETPTON: { std::string address = Memory::GetString(request.buffer_in); INFO_LOG(IOS_NET, "IOCTL_SO_INETPTON " "(Translating: %s)", address.c_str()); return_value = inet_pton(address.c_str(), Memory::GetPointer(request.buffer_out + 4)); break; } case IOCTL_SO_INETNTOP: { // u32 af = Memory::Read_U32(BufferIn); // u32 validAddress = Memory::Read_U32(request.buffer_in + 4); // u32 src = Memory::Read_U32(request.buffer_in + 8); char ip_s[16]; sprintf(ip_s, "%i.%i.%i.%i", Memory::Read_U8(request.buffer_in + 8), Memory::Read_U8(request.buffer_in + 8 + 1), Memory::Read_U8(request.buffer_in + 8 + 2), Memory::Read_U8(request.buffer_in + 8 + 3)); INFO_LOG(IOS_NET, "IOCTL_SO_INETNTOP %s", ip_s); Memory::CopyToEmu(request.buffer_out, (u8*)ip_s, strlen(ip_s)); break; } case IOCTL_SO_POLL: { // Map Wii/native poll events types struct { int native; int wii; } mapping[] = { {POLLRDNORM, 0x0001}, {POLLRDBAND, 0x0002}, {POLLPRI, 0x0004}, {POLLWRNORM, 0x0008}, {POLLWRBAND, 0x0010}, {POLLERR, 0x0020}, {POLLHUP, 0x0040}, {POLLNVAL, 0x0080}, }; u32 unknown = Memory::Read_U32(request.buffer_in); u32 timeout = Memory::Read_U32(request.buffer_in + 4); int nfds = request.buffer_out_size / 0xc; if (nfds == 0) ERROR_LOG(IOS_NET, "Hidden POLL"); std::vector<pollfd_t> ufds(nfds); for (int i = 0; i < nfds; ++i) { ufds[i].fd = Memory::Read_U32(request.buffer_out + 0xc * i); // fd int events = Memory::Read_U32(request.buffer_out + 0xc * i + 4); // events ufds[i].revents = Memory::Read_U32(request.buffer_out + 0xc * i + 8); // revents // Translate Wii to native events int unhandled_events = events; ufds[i].events = 0; for (auto& map : mapping) { if (events & map.wii) ufds[i].events |= map.native; unhandled_events &= ~map.wii; } DEBUG_LOG(IOS_NET, "IOCTL_SO_POLL(%d) " "Sock: %08x, Unknown: %08x, Events: %08x, " "NativeEvents: %08x", i, ufds[i].fd, unknown, events, ufds[i].events); // Do not pass return-only events to the native poll ufds[i].events &= ~(POLLERR | POLLHUP | POLLNVAL | UNSUPPORTED_WSAPOLL); if (unhandled_events) ERROR_LOG(IOS_NET, "SO_POLL: unhandled Wii event types: %04x", unhandled_events); } int ret = poll(ufds.data(), nfds, timeout); ret = WiiSockMan::GetNetErrorCode(ret, "SO_POLL", false); for (int i = 0; i < nfds; ++i) { // Translate native to Wii events int revents = 0; for (auto& map : mapping) { if (ufds[i].revents & map.native) revents |= map.wii; } // No need to change fd or events as they are input only. // Memory::Write_U32(ufds[i].fd, request.buffer_out + 0xc*i); //fd // Memory::Write_U32(events, request.buffer_out + 0xc*i + 4); //events Memory::Write_U32(revents, request.buffer_out + 0xc * i + 8); // revents DEBUG_LOG(IOS_NET, "IOCTL_SO_POLL socket %d wevents %08X events %08X revents %08X", i, revents, ufds[i].events, ufds[i].revents); } return_value = ret; break; } case IOCTL_SO_GETHOSTBYNAME: { if (request.buffer_out_size != 0x460) { ERROR_LOG(IOS_NET, "Bad buffer size for IOCTL_SO_GETHOSTBYNAME"); return_value = -1; break; } std::string hostname = Memory::GetString(request.buffer_in); hostent* remoteHost = gethostbyname(hostname.c_str()); INFO_LOG(IOS_NET, "IOCTL_SO_GETHOSTBYNAME " "Address: %s, BufferIn: (%08x, %i), BufferOut: (%08x, %i)", hostname.c_str(), request.buffer_in, request.buffer_in_size, request.buffer_out, request.buffer_out_size); if (remoteHost) { for (int i = 0; remoteHost->h_aliases[i]; ++i) { DEBUG_LOG(IOS_NET, "alias%i:%s", i, remoteHost->h_aliases[i]); } for (int i = 0; remoteHost->h_addr_list[i]; ++i) { u32 ip = Common::swap32(*(u32*)(remoteHost->h_addr_list[i])); std::string ip_s = StringFromFormat("%i.%i.%i.%i", ip >> 24, (ip >> 16) & 0xff, (ip >> 8) & 0xff, ip & 0xff); DEBUG_LOG(IOS_NET, "addr%i:%s", i, ip_s.c_str()); } // Host name; located immediately after struct static const u32 GETHOSTBYNAME_STRUCT_SIZE = 0x10; static const u32 GETHOSTBYNAME_IP_LIST_OFFSET = 0x110; // Limit host name length to avoid buffer overflow. u32 name_length = (u32)strlen(remoteHost->h_name) + 1; if (name_length > (GETHOSTBYNAME_IP_LIST_OFFSET - GETHOSTBYNAME_STRUCT_SIZE)) { ERROR_LOG(IOS_NET, "Hostname too long in IOCTL_SO_GETHOSTBYNAME"); return_value = -1; break; } Memory::CopyToEmu(request.buffer_out + GETHOSTBYNAME_STRUCT_SIZE, remoteHost->h_name, name_length); Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_STRUCT_SIZE, request.buffer_out); // IP address list; located at offset 0x110. u32 num_ip_addr = 0; while (remoteHost->h_addr_list[num_ip_addr]) num_ip_addr++; // Limit number of IP addresses to avoid buffer overflow. // (0x460 - 0x340) / sizeof(pointer) == 72 static const u32 GETHOSTBYNAME_MAX_ADDRESSES = 71; num_ip_addr = std::min(num_ip_addr, GETHOSTBYNAME_MAX_ADDRESSES); for (u32 i = 0; i < num_ip_addr; ++i) { u32 addr = request.buffer_out + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4; Memory::Write_U32_Swap(*(u32*)(remoteHost->h_addr_list[i]), addr); } // List of pointers to IP addresses; located at offset 0x340. // This must be exact: PPC code to convert the struct hardcodes // this offset. static const u32 GETHOSTBYNAME_IP_PTR_LIST_OFFSET = 0x340; Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET, request.buffer_out + 12); for (u32 i = 0; i < num_ip_addr; ++i) { u32 addr = request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + i * 4; Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_LIST_OFFSET + i * 4, addr); } Memory::Write_U32(0, request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4); // Aliases - empty. (Hardware doesn't return anything.) Memory::Write_U32(request.buffer_out + GETHOSTBYNAME_IP_PTR_LIST_OFFSET + num_ip_addr * 4, request.buffer_out + 4); // Returned struct must be ipv4. _assert_msg_(IOS_NET, remoteHost->h_addrtype == AF_INET && remoteHost->h_length == sizeof(u32), "returned host info is not IPv4"); Memory::Write_U16(AF_INET, request.buffer_out + 8); Memory::Write_U16(sizeof(u32), request.buffer_out + 10); return_value = 0; } else { return_value = -1; } break; } case IOCTL_SO_ICMPCANCEL: ERROR_LOG(IOS_NET, "IOCTL_SO_ICMPCANCEL"); default: request.DumpUnknown(GetDeviceName(), LogTypes::IOS_NET); }
IPCCommandResult NetIPTop::HandleGetHostIDRequest(const IOCtlRequest& request) { request.Log(GetDeviceName(), LogTypes::IOS_WC24); s32 return_value = 0; #ifdef _WIN32 DWORD forwardTableSize, ipTableSize, result; NET_IFINDEX ifIndex = NET_IFINDEX_UNSPECIFIED; std::unique_ptr<MIB_IPFORWARDTABLE> forwardTable; std::unique_ptr<MIB_IPADDRTABLE> ipTable; forwardTableSize = 0; if (GetIpForwardTable(nullptr, &forwardTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) { forwardTable = std::unique_ptr<MIB_IPFORWARDTABLE>((PMIB_IPFORWARDTABLE) operator new(forwardTableSize)); } ipTableSize = 0; if (GetIpAddrTable(nullptr, &ipTableSize, FALSE) == ERROR_INSUFFICIENT_BUFFER) { ipTable = std::unique_ptr<MIB_IPADDRTABLE>((PMIB_IPADDRTABLE) operator new(ipTableSize)); } // find the interface IP used for the default route and use that result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE); // can return ERROR_MORE_DATA on XP even after the first call while (result == NO_ERROR || result == ERROR_MORE_DATA) { for (DWORD i = 0; i < forwardTable->dwNumEntries; ++i) { if (forwardTable->table[i].dwForwardDest == 0) { ifIndex = forwardTable->table[i].dwForwardIfIndex; break; } } if (result == NO_ERROR || ifIndex != NET_IFINDEX_UNSPECIFIED) break; result = GetIpForwardTable(forwardTable.get(), &forwardTableSize, FALSE); } if (ifIndex != NET_IFINDEX_UNSPECIFIED && GetIpAddrTable(ipTable.get(), &ipTableSize, FALSE) == NO_ERROR) { for (DWORD i = 0; i < ipTable->dwNumEntries; ++i) { if (ipTable->table[i].dwIndex == ifIndex) { return_value = Common::swap32(ipTable->table[i].dwAddr); break; } } } #endif // default placeholder, in case of failure if (return_value == 0) return_value = 192 << 24 | 168 << 16 | 1 << 8 | 150; return GetDefaultReply(return_value); }