2011-08-29 13:21:18 +00:00
|
|
|
/* IPXWrapper - Interface functions
|
|
|
|
* Copyright (C) 2011 Daniel Collins <solemnwarning@solemnwarning.net>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License version 2 as published by
|
|
|
|
* the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
|
|
* more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along with
|
|
|
|
* this program; if not, write to the Free Software Foundation, Inc., 51
|
|
|
|
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <windows.h>
|
|
|
|
#include <iphlpapi.h>
|
2012-11-02 20:45:10 +00:00
|
|
|
#include <utlist.h>
|
2011-08-29 13:21:18 +00:00
|
|
|
|
|
|
|
#include "interface.h"
|
|
|
|
#include "common.h"
|
|
|
|
#include "config.h"
|
|
|
|
|
2012-10-21 10:26:52 +00:00
|
|
|
/* Fetch a list of network interfaces available on the system.
|
|
|
|
*
|
|
|
|
* Returns a linked list of IP_ADAPTER_INFO structures, all allocated within a
|
|
|
|
* single memory block beginning at the first node.
|
2011-08-29 13:21:18 +00:00
|
|
|
*/
|
2012-10-21 10:26:52 +00:00
|
|
|
IP_ADAPTER_INFO *get_sys_interfaces(void)
|
|
|
|
{
|
|
|
|
IP_ADAPTER_INFO *ifroot = NULL, *ifptr;
|
|
|
|
ULONG bufsize = sizeof(IP_ADAPTER_INFO) * 8;
|
2011-08-29 13:21:18 +00:00
|
|
|
|
2012-10-21 10:26:52 +00:00
|
|
|
int err = ERROR_BUFFER_OVERFLOW;
|
2011-08-29 13:21:18 +00:00
|
|
|
|
2012-10-21 10:26:52 +00:00
|
|
|
while(err == ERROR_BUFFER_OVERFLOW)
|
|
|
|
{
|
|
|
|
if(!(ifptr = realloc(ifroot, bufsize)))
|
|
|
|
{
|
|
|
|
log_printf(LOG_ERROR, "Couldn't allocate IP_ADAPTER_INFO structures!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifroot = ifptr;
|
|
|
|
|
|
|
|
err = GetAdaptersInfo(ifroot, &bufsize);
|
|
|
|
|
|
|
|
if(err == ERROR_NO_DATA)
|
|
|
|
{
|
|
|
|
log_printf(LOG_WARNING, "No network interfaces detected!");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if(err != ERROR_SUCCESS && err != ERROR_BUFFER_OVERFLOW)
|
|
|
|
{
|
|
|
|
log_printf(LOG_ERROR, "Error fetching network interfaces: %s", w32_error(err));
|
|
|
|
break;
|
|
|
|
}
|
2011-08-29 13:21:18 +00:00
|
|
|
}
|
|
|
|
|
2012-10-21 10:26:52 +00:00
|
|
|
if(err != ERROR_SUCCESS)
|
|
|
|
{
|
2011-08-29 13:21:18 +00:00
|
|
|
free(ifroot);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-10-21 10:26:52 +00:00
|
|
|
return ifroot;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get virtual IPX interfaces
|
|
|
|
* Select a single interface by setting ifnum >= 0
|
|
|
|
*/
|
|
|
|
ipx_interface_t *get_interfaces(int ifnum)
|
|
|
|
{
|
|
|
|
IP_ADAPTER_INFO *ifroot = get_sys_interfaces(), *ifptr;
|
2011-08-29 13:21:18 +00:00
|
|
|
|
2012-10-21 10:26:52 +00:00
|
|
|
addr48_t primary = get_primary_iface();
|
2011-08-29 13:21:18 +00:00
|
|
|
|
2012-10-21 10:26:52 +00:00
|
|
|
ipx_interface_t *nics = NULL;
|
|
|
|
|
|
|
|
for(ifptr = ifroot; ifptr; ifptr = ifptr->Next)
|
|
|
|
{
|
|
|
|
addr48_t hwaddr = addr48_in(ifptr->Address);
|
2011-08-29 13:21:18 +00:00
|
|
|
|
2012-10-21 10:26:52 +00:00
|
|
|
iface_config_t config = get_iface_config(hwaddr);
|
2011-08-29 13:21:18 +00:00
|
|
|
|
2012-10-21 10:26:52 +00:00
|
|
|
if(!config.enabled)
|
|
|
|
{
|
2011-08-29 13:21:18 +00:00
|
|
|
/* Interface has been disabled, don't add it */
|
2012-10-21 10:26:52 +00:00
|
|
|
|
2011-08-29 13:21:18 +00:00
|
|
|
ifptr = ifptr->Next;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2012-11-02 20:45:10 +00:00
|
|
|
ipx_interface_t *iface = malloc(sizeof(ipx_interface_t));
|
|
|
|
if(!iface)
|
2012-10-21 10:26:52 +00:00
|
|
|
{
|
|
|
|
log_printf(LOG_ERROR, "Couldn't allocate ipx_interface!");
|
2011-08-29 13:21:18 +00:00
|
|
|
|
2012-11-02 20:45:10 +00:00
|
|
|
free_ipx_interfaces(&nics);
|
2011-08-29 13:21:18 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2012-11-02 20:45:10 +00:00
|
|
|
iface->ipaddr = NULL;
|
2011-08-29 13:21:18 +00:00
|
|
|
|
2012-11-02 20:45:10 +00:00
|
|
|
IP_ADDR_STRING *ip_ptr = &(ifptr->IpAddressList);
|
2011-08-29 13:21:18 +00:00
|
|
|
|
2012-11-02 20:45:10 +00:00
|
|
|
for(; ip_ptr; ip_ptr = ip_ptr->Next)
|
|
|
|
{
|
|
|
|
uint32_t ipaddr = inet_addr(ip_ptr->IpAddress.String);
|
|
|
|
uint32_t netmask = inet_addr(ip_ptr->IpMask.String);
|
|
|
|
|
|
|
|
if(ipaddr == 0)
|
|
|
|
{
|
|
|
|
/* No IP address.
|
|
|
|
* Because an empty linked list would be silly.
|
|
|
|
*/
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
ipx_interface_ip_t *addr = malloc(sizeof(ipx_interface_ip_t));
|
|
|
|
if(!addr)
|
|
|
|
{
|
|
|
|
log_printf(LOG_ERROR, "Couldn't allocate ipx_interface_ip!");
|
|
|
|
|
|
|
|
free_ipx_interface(iface);
|
|
|
|
free_ipx_interfaces(&nics);
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr->ipaddr = ipaddr;
|
|
|
|
addr->netmask = netmask;
|
|
|
|
addr->bcast = ipaddr | (~netmask);
|
|
|
|
|
|
|
|
DL_APPEND(iface->ipaddr, addr);
|
|
|
|
}
|
|
|
|
|
|
|
|
iface->hwaddr = hwaddr;
|
|
|
|
|
|
|
|
iface->ipx_net = config.netnum;
|
|
|
|
iface->ipx_node = config.nodenum;
|
2011-08-29 13:21:18 +00:00
|
|
|
|
2011-11-05 20:22:16 +00:00
|
|
|
/* Workaround for buggy versions of Hamachi that don't initialise
|
|
|
|
* the interface hardware address correctly.
|
|
|
|
*/
|
|
|
|
|
2012-10-21 10:26:52 +00:00
|
|
|
unsigned char hamachi_bug[] = {0x7A, 0x79, 0x00, 0x00, 0x00, 0x00};
|
2011-11-05 20:22:16 +00:00
|
|
|
|
2012-11-02 20:45:10 +00:00
|
|
|
if(iface->ipx_node == addr48_in(hamachi_bug) && iface->ipaddr)
|
2012-10-21 10:26:52 +00:00
|
|
|
{
|
2011-11-16 21:32:59 +00:00
|
|
|
log_printf(LOG_WARNING, "Invalid Hamachi interface detected, correcting node number");
|
2011-08-29 13:21:18 +00:00
|
|
|
|
2012-11-02 20:45:10 +00:00
|
|
|
addr32_out(hamachi_bug + 2, iface->ipaddr->ipaddr);
|
|
|
|
iface->ipx_node = addr48_in(hamachi_bug);
|
2011-08-29 13:21:18 +00:00
|
|
|
}
|
|
|
|
|
2012-11-02 20:45:10 +00:00
|
|
|
if(iface->hwaddr == primary)
|
2012-10-21 10:26:52 +00:00
|
|
|
{
|
|
|
|
/* Primary interface, insert at the start of the list */
|
2012-11-02 20:45:10 +00:00
|
|
|
DL_PREPEND(nics, iface);
|
2012-10-21 10:26:52 +00:00
|
|
|
}
|
|
|
|
else{
|
2012-11-02 20:45:10 +00:00
|
|
|
DL_APPEND(nics, iface);
|
2012-10-21 10:26:52 +00:00
|
|
|
}
|
2011-08-29 13:21:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
free(ifroot);
|
|
|
|
|
2012-11-02 20:45:10 +00:00
|
|
|
/* Delete every entry in the NIC list except the requested one.
|
|
|
|
*
|
|
|
|
* This is done here rather than when building the list as the primary
|
|
|
|
* interface may change the indexes if it isn't the first.
|
|
|
|
*/
|
2012-10-21 10:26:52 +00:00
|
|
|
|
|
|
|
if(ifnum >= 0)
|
|
|
|
{
|
2012-07-22 18:57:06 +00:00
|
|
|
int this_ifnum = 0;
|
2012-10-21 10:26:52 +00:00
|
|
|
ipx_interface_t *iface, *tmp;
|
|
|
|
|
|
|
|
DL_FOREACH_SAFE(nics, iface, tmp)
|
|
|
|
{
|
|
|
|
if(this_ifnum++ != ifnum)
|
|
|
|
{
|
|
|
|
DL_DELETE(nics, iface);
|
2012-11-02 20:45:10 +00:00
|
|
|
free_ipx_interface(iface);
|
2012-10-21 10:26:52 +00:00
|
|
|
}
|
2012-07-22 18:57:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-29 13:21:18 +00:00
|
|
|
return nics;
|
|
|
|
}
|
|
|
|
|
2012-11-02 20:45:10 +00:00
|
|
|
/* Free an ipx_interface structure and any memory allocated within. */
|
|
|
|
void free_ipx_interface(ipx_interface_t *iface)
|
|
|
|
{
|
|
|
|
ipx_interface_ip_t *a, *a_tmp;
|
|
|
|
|
|
|
|
DL_FOREACH_SAFE(iface->ipaddr, a, a_tmp)
|
|
|
|
{
|
|
|
|
DL_DELETE(iface->ipaddr, a);
|
|
|
|
free(a);
|
|
|
|
}
|
|
|
|
|
|
|
|
free(iface);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Free a list of ipx_interface structures */
|
|
|
|
void free_ipx_interfaces(ipx_interface_t **list)
|
2012-10-21 10:26:52 +00:00
|
|
|
{
|
|
|
|
ipx_interface_t *iface, *tmp;
|
|
|
|
|
2012-11-02 20:45:10 +00:00
|
|
|
DL_FOREACH_SAFE(*list, iface, tmp)
|
2012-10-21 10:26:52 +00:00
|
|
|
{
|
2012-11-02 20:45:10 +00:00
|
|
|
DL_DELETE(*list, iface);
|
|
|
|
free_ipx_interface(iface);
|
2011-08-29 13:21:18 +00:00
|
|
|
}
|
|
|
|
}
|