mirror of
https://github.com/solemnwarning/ipxwrapper
synced 2024-12-30 16:45:37 +01:00
Implemented (virtual) interface address cache and ipx_interface utility functions.
This commit is contained in:
parent
bee68d52b9
commit
57e4f27bb8
226
src/interface.c
226
src/interface.c
@ -18,17 +18,25 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <iphlpapi.h>
|
#include <iphlpapi.h>
|
||||||
#include <utlist.h>
|
#include <utlist.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#include "interface.h"
|
#include "interface.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
|
#define INTERFACE_CACHE_TTL 5
|
||||||
|
|
||||||
|
static CRITICAL_SECTION interface_cache_cs;
|
||||||
|
|
||||||
|
static ipx_interface_t *interface_cache = NULL;
|
||||||
|
static time_t interface_cache_ctime = 0;
|
||||||
|
|
||||||
/* Fetch a list of network interfaces available on the system.
|
/* Fetch a list of network interfaces available on the system.
|
||||||
*
|
*
|
||||||
* Returns a linked list of IP_ADAPTER_INFO structures, all allocated within a
|
* Returns a linked list of IP_ADAPTER_INFO structures, all allocated within a
|
||||||
* single memory block beginning at the first node.
|
* single memory block beginning at the first node.
|
||||||
*/
|
*/
|
||||||
IP_ADAPTER_INFO *get_sys_interfaces(void)
|
IP_ADAPTER_INFO *load_sys_interfaces(void)
|
||||||
{
|
{
|
||||||
IP_ADAPTER_INFO *ifroot = NULL, *ifptr;
|
IP_ADAPTER_INFO *ifroot = NULL, *ifptr;
|
||||||
ULONG bufsize = sizeof(IP_ADAPTER_INFO) * 8;
|
ULONG bufsize = sizeof(IP_ADAPTER_INFO) * 8;
|
||||||
@ -68,12 +76,10 @@ IP_ADAPTER_INFO *get_sys_interfaces(void)
|
|||||||
return ifroot;
|
return ifroot;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get virtual IPX interfaces
|
/* Load a list of virtual IPX interfaces. */
|
||||||
* Select a single interface by setting ifnum >= 0
|
ipx_interface_t *load_ipx_interfaces(void)
|
||||||
*/
|
|
||||||
ipx_interface_t *get_interfaces(int ifnum)
|
|
||||||
{
|
{
|
||||||
IP_ADAPTER_INFO *ifroot = get_sys_interfaces(), *ifptr;
|
IP_ADAPTER_INFO *ifroot = load_sys_interfaces(), *ifptr;
|
||||||
|
|
||||||
addr48_t primary = get_primary_iface();
|
addr48_t primary = get_primary_iface();
|
||||||
|
|
||||||
@ -98,7 +104,7 @@ ipx_interface_t *get_interfaces(int ifnum)
|
|||||||
{
|
{
|
||||||
log_printf(LOG_ERROR, "Couldn't allocate ipx_interface!");
|
log_printf(LOG_ERROR, "Couldn't allocate ipx_interface!");
|
||||||
|
|
||||||
free_ipx_interfaces(&nics);
|
free_ipx_interface_list(&nics);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +132,7 @@ ipx_interface_t *get_interfaces(int ifnum)
|
|||||||
log_printf(LOG_ERROR, "Couldn't allocate ipx_interface_ip!");
|
log_printf(LOG_ERROR, "Couldn't allocate ipx_interface_ip!");
|
||||||
|
|
||||||
free_ipx_interface(iface);
|
free_ipx_interface(iface);
|
||||||
free_ipx_interfaces(&nics);
|
free_ipx_interface_list(&nics);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -169,28 +175,46 @@ ipx_interface_t *get_interfaces(int ifnum)
|
|||||||
|
|
||||||
free(ifroot);
|
free(ifroot);
|
||||||
|
|
||||||
/* Delete every entry in the NIC list except the requested one.
|
return nics;
|
||||||
*
|
}
|
||||||
* This is done here rather than when building the list as the primary
|
|
||||||
* interface may change the indexes if it isn't the first.
|
/* Deep copy an ipx_interface structure.
|
||||||
*/
|
* Returns NULL on malloc failure.
|
||||||
|
*/
|
||||||
if(ifnum >= 0)
|
ipx_interface_t *copy_ipx_interface(const ipx_interface_t *src)
|
||||||
|
{
|
||||||
|
ipx_interface_t *dest = malloc(sizeof(ipx_interface_t));
|
||||||
|
if(!dest)
|
||||||
{
|
{
|
||||||
int this_ifnum = 0;
|
log_printf(LOG_ERROR, "Cannot allocate ipx_interface!");
|
||||||
ipx_interface_t *iface, *tmp;
|
return NULL;
|
||||||
|
|
||||||
DL_FOREACH_SAFE(nics, iface, tmp)
|
|
||||||
{
|
|
||||||
if(this_ifnum++ != ifnum)
|
|
||||||
{
|
|
||||||
DL_DELETE(nics, iface);
|
|
||||||
free_ipx_interface(iface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nics;
|
*dest = *src;
|
||||||
|
|
||||||
|
dest->ipaddr = NULL;
|
||||||
|
dest->prev = NULL;
|
||||||
|
dest->next = NULL;
|
||||||
|
|
||||||
|
ipx_interface_ip_t *ip;
|
||||||
|
|
||||||
|
DL_FOREACH(src->ipaddr, ip)
|
||||||
|
{
|
||||||
|
ipx_interface_ip_t *new_ip = malloc(sizeof(ipx_interface_ip_t));
|
||||||
|
if(!new_ip)
|
||||||
|
{
|
||||||
|
log_printf(LOG_ERROR, "Cannot allocate ipx_interface_ip!");
|
||||||
|
|
||||||
|
free_ipx_interface(dest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*new_ip = *ip;
|
||||||
|
|
||||||
|
DL_APPEND(dest->ipaddr, new_ip);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free an ipx_interface structure and any memory allocated within. */
|
/* Free an ipx_interface structure and any memory allocated within. */
|
||||||
@ -207,8 +231,32 @@ void free_ipx_interface(ipx_interface_t *iface)
|
|||||||
free(iface);
|
free(iface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Deep copy an entire list of ipx_interface structures.
|
||||||
|
* Returns NULL on malloc failure.
|
||||||
|
*/
|
||||||
|
ipx_interface_t *copy_ipx_interface_list(const ipx_interface_t *src)
|
||||||
|
{
|
||||||
|
ipx_interface_t *dest = NULL;
|
||||||
|
|
||||||
|
const ipx_interface_t *s;
|
||||||
|
|
||||||
|
DL_FOREACH(src, s)
|
||||||
|
{
|
||||||
|
ipx_interface_t *d = copy_ipx_interface(s);
|
||||||
|
if(!d)
|
||||||
|
{
|
||||||
|
free_ipx_interface_list(&dest);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
DL_APPEND(dest, d);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
/* Free a list of ipx_interface structures */
|
/* Free a list of ipx_interface structures */
|
||||||
void free_ipx_interfaces(ipx_interface_t **list)
|
void free_ipx_interface_list(ipx_interface_t **list)
|
||||||
{
|
{
|
||||||
ipx_interface_t *iface, *tmp;
|
ipx_interface_t *iface, *tmp;
|
||||||
|
|
||||||
@ -218,3 +266,125 @@ void free_ipx_interfaces(ipx_interface_t **list)
|
|||||||
free_ipx_interface(iface);
|
free_ipx_interface(iface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Initialise the IPX interface cache. */
|
||||||
|
void ipx_interfaces_init(void)
|
||||||
|
{
|
||||||
|
interface_cache = NULL;
|
||||||
|
interface_cache_ctime = 0;
|
||||||
|
|
||||||
|
if(!InitializeCriticalSectionAndSpinCount(&interface_cache_cs, 0x80000000))
|
||||||
|
{
|
||||||
|
log_printf(LOG_ERROR, "Failed to initialise critical section: %s", w32_error(GetLastError()));
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release any resources used by the IPX interface cache. */
|
||||||
|
void ipx_interfaces_cleanup(void)
|
||||||
|
{
|
||||||
|
DeleteCriticalSection(&interface_cache_cs);
|
||||||
|
|
||||||
|
free_ipx_interface_list(&interface_cache);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the age of the IPX interface cache and reload it if necessary.
|
||||||
|
* Ensure you hold interface_cache_cs before calling.
|
||||||
|
*/
|
||||||
|
static void renew_interface_cache(void)
|
||||||
|
{
|
||||||
|
if(time(NULL) - interface_cache_ctime > INTERFACE_CACHE_TTL)
|
||||||
|
{
|
||||||
|
free_ipx_interface_list(&interface_cache);
|
||||||
|
|
||||||
|
interface_cache = load_ipx_interfaces();
|
||||||
|
interface_cache_ctime = time(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return a copy of the IPX interface cache. The cache will be reloaded before
|
||||||
|
* copying if too old.
|
||||||
|
*/
|
||||||
|
ipx_interface_t *get_ipx_interfaces(void)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&interface_cache_cs);
|
||||||
|
|
||||||
|
renew_interface_cache();
|
||||||
|
|
||||||
|
ipx_interface_t *copy = copy_ipx_interface_list(interface_cache);
|
||||||
|
|
||||||
|
LeaveCriticalSection(&interface_cache_cs);
|
||||||
|
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search for an IPX interface by address.
|
||||||
|
* Returns NULL if the interface doesn't exist or malloc failure.
|
||||||
|
*/
|
||||||
|
ipx_interface_t *ipx_interface_by_addr(addr32_t net, addr48_t node)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&interface_cache_cs);
|
||||||
|
|
||||||
|
renew_interface_cache();
|
||||||
|
|
||||||
|
ipx_interface_t *iface;
|
||||||
|
|
||||||
|
DL_FOREACH(interface_cache, iface)
|
||||||
|
{
|
||||||
|
if(iface->ipx_net == net && iface->ipx_node == node)
|
||||||
|
{
|
||||||
|
iface = copy_ipx_interface(iface);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(&interface_cache_cs);
|
||||||
|
|
||||||
|
return iface;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search for an IPX interface by index.
|
||||||
|
* Returns NULL if the interface doesn't exist or malloc failure.
|
||||||
|
*/
|
||||||
|
ipx_interface_t *ipx_interface_by_index(int index)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&interface_cache_cs);
|
||||||
|
|
||||||
|
renew_interface_cache();
|
||||||
|
|
||||||
|
int iface_index = 0;
|
||||||
|
ipx_interface_t *iface;
|
||||||
|
|
||||||
|
DL_FOREACH(interface_cache, iface)
|
||||||
|
{
|
||||||
|
if(iface_index++ == index)
|
||||||
|
{
|
||||||
|
iface = copy_ipx_interface(iface);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(&interface_cache_cs);
|
||||||
|
|
||||||
|
return iface;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returns the number of IPX interfaces. */
|
||||||
|
int ipx_interface_count(void)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&interface_cache_cs);
|
||||||
|
|
||||||
|
renew_interface_cache();
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
ipx_interface_t *iface;
|
||||||
|
|
||||||
|
DL_FOREACH(interface_cache, iface)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(&interface_cache_cs);
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
@ -52,12 +52,22 @@ struct ipx_interface {
|
|||||||
ipx_interface_t *next;
|
ipx_interface_t *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
IP_ADAPTER_INFO *get_sys_interfaces(void);
|
IP_ADAPTER_INFO *load_sys_interfaces(void);
|
||||||
|
ipx_interface_t *load_ipx_interfaces(void);
|
||||||
ipx_interface_t *get_interfaces(int ifnum);
|
|
||||||
|
|
||||||
|
ipx_interface_t *copy_ipx_interface(const ipx_interface_t *src);
|
||||||
void free_ipx_interface(ipx_interface_t *iface);
|
void free_ipx_interface(ipx_interface_t *iface);
|
||||||
void free_ipx_interfaces(ipx_interface_t **list);
|
|
||||||
|
ipx_interface_t *copy_ipx_interface_list(const ipx_interface_t *src);
|
||||||
|
void free_ipx_interface_list(ipx_interface_t **list);
|
||||||
|
|
||||||
|
void ipx_interfaces_init(void);
|
||||||
|
void ipx_interfaces_cleanup(void);
|
||||||
|
|
||||||
|
ipx_interface_t *get_ipx_interfaces(void);
|
||||||
|
ipx_interface_t *ipx_interface_by_addr(addr32_t net, addr48_t node);
|
||||||
|
ipx_interface_t *ipx_interface_by_index(int index);
|
||||||
|
int ipx_interface_count(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -86,6 +86,8 @@ BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res) {
|
|||||||
|
|
||||||
addr_cache_init();
|
addr_cache_init();
|
||||||
|
|
||||||
|
ipx_interfaces_init();
|
||||||
|
|
||||||
if(!rclient_init(&g_rclient)) {
|
if(!rclient_init(&g_rclient)) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@ -140,6 +142,8 @@ BOOL WINAPI DllMain(HINSTANCE me, DWORD why, LPVOID res) {
|
|||||||
DeleteCriticalSection(&addrs_cs);
|
DeleteCriticalSection(&addrs_cs);
|
||||||
DeleteCriticalSection(&sockets_cs);
|
DeleteCriticalSection(&sockets_cs);
|
||||||
|
|
||||||
|
ipx_interfaces_cleanup();
|
||||||
|
|
||||||
addr_cache_cleanup();
|
addr_cache_cleanup();
|
||||||
|
|
||||||
unload_dlls();
|
unload_dlls();
|
||||||
@ -192,7 +196,7 @@ BOOL ip_is_local(uint32_t ipaddr) {
|
|||||||
if(local_updated + main_config.iface_ttl < time(NULL)) {
|
if(local_updated + main_config.iface_ttl < time(NULL)) {
|
||||||
/* TODO: Use all local IPs rather than just the ones with associated IPX addresses? */
|
/* TODO: Use all local IPs rather than just the ones with associated IPX addresses? */
|
||||||
|
|
||||||
struct ipx_interface *ifaces = get_interfaces(-1);
|
struct ipx_interface *ifaces = get_ipx_interfaces();
|
||||||
struct ipx_interface *i = ifaces;
|
struct ipx_interface *i = ifaces;
|
||||||
|
|
||||||
while(i) {
|
while(i) {
|
||||||
@ -215,7 +219,7 @@ BOOL ip_is_local(uint32_t ipaddr) {
|
|||||||
i = i->next;
|
i = i->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
free_ipx_interfaces(&ifaces);
|
free_ipx_interface_list(&ifaces);
|
||||||
|
|
||||||
local_updated = time(NULL);
|
local_updated = time(NULL);
|
||||||
}
|
}
|
||||||
|
@ -336,7 +336,7 @@ static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock,
|
|||||||
* PLEASE email me with corrections!
|
* PLEASE email me with corrections!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct ipx_interface *ifaces = get_interfaces(-1), *iface;
|
struct ipx_interface *ifaces = get_ipx_interfaces(), *iface;
|
||||||
|
|
||||||
addr32_t sa_netnum = addr32_in(addr->sa_netnum);
|
addr32_t sa_netnum = addr32_in(addr->sa_netnum);
|
||||||
addr48_t sa_nodenum = addr48_in(addr->sa_nodenum);
|
addr48_t sa_nodenum = addr48_in(addr->sa_nodenum);
|
||||||
@ -356,7 +356,7 @@ static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock,
|
|||||||
if(!iface) {
|
if(!iface) {
|
||||||
log_printf(LOG_ERROR, "bind failed: no such address");
|
log_printf(LOG_ERROR, "bind failed: no such address");
|
||||||
|
|
||||||
free_ipx_interfaces(&ifaces);
|
free_ipx_interface_list(&ifaces);
|
||||||
|
|
||||||
WSASetLastError(WSAEADDRNOTAVAIL);
|
WSASetLastError(WSAEADDRNOTAVAIL);
|
||||||
return -1;
|
return -1;
|
||||||
@ -372,7 +372,7 @@ static int router_bind(struct router_vars *router, SOCKET control, SOCKET sock,
|
|||||||
uint32_t iface_ipaddr = iface->ipaddr->ipaddr;
|
uint32_t iface_ipaddr = iface->ipaddr->ipaddr;
|
||||||
uint32_t iface_netmask = iface->ipaddr->netmask;
|
uint32_t iface_netmask = iface->ipaddr->netmask;
|
||||||
|
|
||||||
free_ipx_interfaces(&ifaces);
|
free_ipx_interface_list(&ifaces);
|
||||||
|
|
||||||
EnterCriticalSection(&(router->crit_sec));
|
EnterCriticalSection(&(router->crit_sec));
|
||||||
|
|
||||||
|
@ -524,7 +524,7 @@ int WSAAPI getsockopt(SOCKET fd, int level, int optname, char FAR *optval, int F
|
|||||||
|
|
||||||
IPX_ADDRESS_DATA *ipxdata = (IPX_ADDRESS_DATA*)optval;
|
IPX_ADDRESS_DATA *ipxdata = (IPX_ADDRESS_DATA*)optval;
|
||||||
|
|
||||||
struct ipx_interface *nic = get_interfaces(ipxdata->adapternum);
|
struct ipx_interface *nic = ipx_interface_by_index(ipxdata->adapternum);
|
||||||
|
|
||||||
if(!nic) {
|
if(!nic) {
|
||||||
RETURN_WSA(ERROR_NO_DATA, -1);
|
RETURN_WSA(ERROR_NO_DATA, -1);
|
||||||
@ -552,16 +552,7 @@ int WSAAPI getsockopt(SOCKET fd, int level, int optname, char FAR *optval, int F
|
|||||||
if(optname == IPX_MAX_ADAPTER_NUM) {
|
if(optname == IPX_MAX_ADAPTER_NUM) {
|
||||||
CHECK_OPTLEN(sizeof(int));
|
CHECK_OPTLEN(sizeof(int));
|
||||||
|
|
||||||
*intval = 0;
|
*intval = ipx_interface_count();
|
||||||
|
|
||||||
struct ipx_interface *ifaces = get_interfaces(-1), *nic;
|
|
||||||
|
|
||||||
for(nic = ifaces; nic;) {
|
|
||||||
(*intval)++;
|
|
||||||
nic = nic->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
free_ipx_interfaces(&ifaces);
|
|
||||||
|
|
||||||
RETURN(0);
|
RETURN(0);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user