//----------------------------------------------------------------------------
// 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;
    }

}
Exemple #2
0
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
Exemple #3
0
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);
    }
}
Exemple #4
0
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);
}
Exemple #6
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
}
Exemple #7
0
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;
}
Exemple #9
0
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;
}
Exemple #12
0
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;
}
Exemple #13
0
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);
}
Exemple #14
0
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
}
Exemple #15
0
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);
  }
Exemple #16
0
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);
}