wpcap: Build pcap_address structure from IP_ADAPTER_UNICAST_ADDRESS.

This commit is contained in:
Hans Leidekker 2022-10-27 13:23:46 +02:00 committed by Alexandre Julliard
parent 6d01d01455
commit 382dbe77f6
2 changed files with 94 additions and 49 deletions

View file

@ -17,18 +17,13 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/ */
struct sockaddr_hdr
{
unsigned short sa_family;
};
struct pcap_address struct pcap_address
{ {
struct pcap_address *next; struct pcap_address *next;
struct sockaddr_hdr *addr; struct sockaddr *addr;
struct sockaddr_hdr *netmask; struct sockaddr *netmask;
struct sockaddr_hdr *broadaddr; struct sockaddr *broadaddr;
struct sockaddr_hdr *dstaddr; struct sockaddr *dstaddr;
}; };
struct pcap_interface struct pcap_interface
@ -57,7 +52,6 @@ struct pcap
struct pcap_pkthdr_win32 hdr; struct pcap_pkthdr_win32 hdr;
}; };
struct compile_params struct compile_params
{ {
struct pcap *pcap; struct pcap *pcap;

View file

@ -26,6 +26,7 @@
#include "winsock2.h" #include "winsock2.h"
#include "ws2ipdef.h" #include "ws2ipdef.h"
#include "iphlpapi.h" #include "iphlpapi.h"
#include "netioapi.h"
#include "wine/unixlib.h" #include "wine/unixlib.h"
#include "wine/debug.h" #include "wine/debug.h"
@ -236,59 +237,109 @@ static char *build_win32_description( const struct pcap_interface *unix_dev )
return ret; return ret;
} }
static struct sockaddr_hdr *dup_sockaddr( const struct sockaddr_hdr *addr ) static struct sockaddr *get_address( const IP_ADAPTER_UNICAST_ADDRESS *addr )
{ {
struct sockaddr_hdr *ret; struct sockaddr *ret;
if (!(ret = malloc( addr->Address.iSockaddrLength ))) return NULL;
memcpy( ret, addr->Address.lpSockaddr, addr->Address.iSockaddrLength );
return ret;
}
switch (addr->sa_family) static void convert_length_to_ipv6_mask( ULONG length, IN6_ADDR *mask )
{
unsigned int i;
for (i = 0; i < length / 8; i++) mask->u.Byte[i] = 0xff;
mask->u.Byte[i] = 0xff << (8 - length % 8);
}
static struct sockaddr *get_netmask( const IP_ADAPTER_UNICAST_ADDRESS *addr )
{
struct sockaddr *ret;
switch (addr->Address.lpSockaddr->sa_family)
{ {
case AF_INET: case AF_INET:
{ {
struct sockaddr_in *dst, *src = (struct sockaddr_in *)addr; struct sockaddr_in *netmask_addr_in;
if (!(dst = calloc( 1, sizeof(*dst) ))) return NULL;
dst->sin_family = src->sin_family; if (!(netmask_addr_in = calloc( 1, sizeof(*netmask_addr_in) ))) return NULL;
dst->sin_port = src->sin_port; netmask_addr_in->sin_family = AF_INET;
dst->sin_addr = src->sin_addr; ConvertLengthToIpv4Mask( addr->OnLinkPrefixLength, &netmask_addr_in->sin_addr.S_un.S_addr );
ret = (struct sockaddr_hdr *)dst; ret = (struct sockaddr *)netmask_addr_in;
break; break;
} }
case AF_INET6: case AF_INET6:
{ {
struct sockaddr_in6 *dst, *src = (struct sockaddr_in6 *)addr; struct sockaddr_in6 *netmask_addr_in6;
if (!(dst = malloc( sizeof(*dst) ))) return NULL;
dst->sin6_family = src->sin6_family; if (!(netmask_addr_in6 = calloc( 1, sizeof(*netmask_addr_in6) ))) return NULL;
dst->sin6_port = src->sin6_port; netmask_addr_in6->sin6_family = AF_INET6;
dst->sin6_flowinfo = src->sin6_flowinfo; convert_length_to_ipv6_mask( addr->OnLinkPrefixLength, &netmask_addr_in6->sin6_addr );
dst->sin6_addr = src->sin6_addr; ret = (struct sockaddr *)netmask_addr_in6;
dst->sin6_scope_id = src->sin6_scope_id;
ret = (struct sockaddr_hdr *)dst;
break; break;
} }
default: default:
FIXME( "address family %u not supported\n", addr->sa_family ); FIXME( "address family %u not supported\n", addr->Address.lpSockaddr->sa_family );
return NULL; return NULL;
} }
return ret; return ret;
} }
static struct pcap_address *build_win32_address( struct pcap_address *src ) static struct sockaddr *get_broadcast( const IP_ADAPTER_UNICAST_ADDRESS *addr )
{ {
struct pcap_address *dst; struct sockaddr *ret;
if (!(dst = calloc( 1, sizeof(*dst) ))) return NULL; switch (addr->Address.lpSockaddr->sa_family)
if (src->addr && !(dst->addr = dup_sockaddr( src->addr ))) goto err; {
if (src->netmask && !(dst->netmask = dup_sockaddr( src->netmask ))) goto err; case AF_INET:
if (src->broadaddr && !(dst->broadaddr = dup_sockaddr( src->broadaddr ))) goto err; {
if (src->dstaddr && !(dst->dstaddr = dup_sockaddr( src->dstaddr ))) goto err; struct sockaddr_in *broadcast_addr_in, *addr_in = (struct sockaddr_in *)addr->Address.lpSockaddr;
return dst; ULONG netmask;
if (!(broadcast_addr_in = calloc( 1, sizeof(*broadcast_addr_in) ))) return FALSE;
broadcast_addr_in->sin_family = AF_INET;
ConvertLengthToIpv4Mask( addr->OnLinkPrefixLength, &netmask );
broadcast_addr_in->sin_addr.S_un.S_addr = addr_in->sin_addr.S_un.S_addr | ~netmask;
ret = (struct sockaddr *)broadcast_addr_in;
break;
}
case AF_INET6:
{
struct sockaddr_in6 *broadcast_addr_in6, *addr_in6 = (struct sockaddr_in6 *)addr->Address.lpSockaddr;
IN6_ADDR netmask, *address = (IN6_ADDR *)&addr_in6->sin6_addr;
unsigned int i;
if (!(broadcast_addr_in6 = calloc( 1, sizeof(*broadcast_addr_in6) ))) return NULL;
broadcast_addr_in6->sin6_family = AF_INET6;
convert_length_to_ipv6_mask( addr->OnLinkPrefixLength, &netmask );
for (i = 0; i < 8; i++) broadcast_addr_in6->sin6_addr.u.Word[i] = address->u.Word[i] | ~netmask.u.Word[i];
ret = (struct sockaddr *)broadcast_addr_in6;
break;
}
default:
FIXME( "address family %u not supported\n", addr->Address.lpSockaddr->sa_family );
return NULL;
}
return ret;
}
static struct pcap_address *build_win32_address( const IP_ADAPTER_UNICAST_ADDRESS *addr )
{
struct pcap_address *ret;
if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL;
if (!(ret->addr = get_address( addr ))) goto err;
if (!(ret->netmask = get_netmask( addr ))) goto err;
if (!(ret->broadaddr = get_broadcast( addr ))) goto err;
return ret;
err: err:
free( dst->addr ); free( ret->addr );
free( dst->netmask ); free( ret->netmask );
free( dst->broadaddr ); free( ret->broadaddr );
free( dst->dstaddr ); free( ret );
free( dst );
return NULL; return NULL;
} }
@ -303,27 +354,27 @@ static void add_win32_address( struct pcap_address **list, struct pcap_address *
} }
} }
static struct pcap_address *build_win32_addresses( struct pcap_address *addrs ) static struct pcap_address *build_win32_addresses( const IP_ADAPTER_ADDRESSES *adapter )
{ {
struct pcap_address *src, *dst, *ret = NULL; struct pcap_address *dst, *ret = NULL;
src = addrs; IP_ADAPTER_UNICAST_ADDRESS *src = adapter->FirstUnicastAddress;
while (src) while (src)
{ {
if ((dst = build_win32_address( src ))) add_win32_address( &ret, dst ); if ((dst = build_win32_address( src ))) add_win32_address( &ret, dst );
src = src->next; src = src->Next;
} }
return ret; return ret;
} }
static struct pcap_interface *build_win32_device( const struct pcap_interface *unix_dev, const char *source, static struct pcap_interface *build_win32_device( const struct pcap_interface *unix_dev, const char *source,
const char *adapter_name ) const IP_ADAPTER_ADDRESSES *adapter )
{ {
struct pcap_interface *ret; struct pcap_interface *ret;
if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL; if (!(ret = calloc( 1, sizeof(*ret) ))) return NULL;
if (!(ret->name = build_win32_name( source, adapter_name ))) goto err; if (!(ret->name = build_win32_name( source, adapter->AdapterName ))) goto err;
if (!(ret->description = build_win32_description( unix_dev ))) goto err; if (!(ret->description = build_win32_description( unix_dev ))) goto err;
ret->addresses = build_win32_addresses( unix_dev->addresses ); ret->addresses = build_win32_addresses( adapter );
ret->flags = unix_dev->flags; ret->flags = unix_dev->flags;
return ret; return ret;
@ -364,7 +415,7 @@ static int find_all_devices( const char *source, struct pcap_interface **devs, c
cur = unix_devs; cur = unix_devs;
while (cur) while (cur)
{ {
if ((ptr = find_adapter( adapters, cur->name )) && (dev = build_win32_device( cur, source, ptr->AdapterName ))) if ((ptr = find_adapter( adapters, cur->name )) && (dev = build_win32_device( cur, source, ptr )))
{ {
add_win32_device( &win32_devs, dev ); add_win32_device( &win32_devs, dev );
} }