diff --git a/dlls/wpcap/unixlib.h b/dlls/wpcap/unixlib.h index 8cd64ef0210..18854e0b86b 100644 --- a/dlls/wpcap/unixlib.h +++ b/dlls/wpcap/unixlib.h @@ -17,18 +17,13 @@ * 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 *next; - struct sockaddr_hdr *addr; - struct sockaddr_hdr *netmask; - struct sockaddr_hdr *broadaddr; - struct sockaddr_hdr *dstaddr; + struct sockaddr *addr; + struct sockaddr *netmask; + struct sockaddr *broadaddr; + struct sockaddr *dstaddr; }; struct pcap_interface @@ -57,7 +52,6 @@ struct pcap struct pcap_pkthdr_win32 hdr; }; - struct compile_params { struct pcap *pcap; diff --git a/dlls/wpcap/wpcap.c b/dlls/wpcap/wpcap.c index bc4cb63c623..4d8a115b0ea 100644 --- a/dlls/wpcap/wpcap.c +++ b/dlls/wpcap/wpcap.c @@ -26,6 +26,7 @@ #include "winsock2.h" #include "ws2ipdef.h" #include "iphlpapi.h" +#include "netioapi.h" #include "wine/unixlib.h" #include "wine/debug.h" @@ -236,59 +237,109 @@ static char *build_win32_description( const struct pcap_interface *unix_dev ) 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: { - struct sockaddr_in *dst, *src = (struct sockaddr_in *)addr; - if (!(dst = calloc( 1, sizeof(*dst) ))) return NULL; - dst->sin_family = src->sin_family; - dst->sin_port = src->sin_port; - dst->sin_addr = src->sin_addr; - ret = (struct sockaddr_hdr *)dst; + struct sockaddr_in *netmask_addr_in; + + if (!(netmask_addr_in = calloc( 1, sizeof(*netmask_addr_in) ))) return NULL; + netmask_addr_in->sin_family = AF_INET; + ConvertLengthToIpv4Mask( addr->OnLinkPrefixLength, &netmask_addr_in->sin_addr.S_un.S_addr ); + ret = (struct sockaddr *)netmask_addr_in; break; } case AF_INET6: { - struct sockaddr_in6 *dst, *src = (struct sockaddr_in6 *)addr; - if (!(dst = malloc( sizeof(*dst) ))) return NULL; - dst->sin6_family = src->sin6_family; - dst->sin6_port = src->sin6_port; - dst->sin6_flowinfo = src->sin6_flowinfo; - dst->sin6_addr = src->sin6_addr; - dst->sin6_scope_id = src->sin6_scope_id; - ret = (struct sockaddr_hdr *)dst; + struct sockaddr_in6 *netmask_addr_in6; + + if (!(netmask_addr_in6 = calloc( 1, sizeof(*netmask_addr_in6) ))) return NULL; + netmask_addr_in6->sin6_family = AF_INET6; + convert_length_to_ipv6_mask( addr->OnLinkPrefixLength, &netmask_addr_in6->sin6_addr ); + ret = (struct sockaddr *)netmask_addr_in6; break; } 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 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; - if (src->addr && !(dst->addr = dup_sockaddr( src->addr ))) goto err; - if (src->netmask && !(dst->netmask = dup_sockaddr( src->netmask ))) goto err; - if (src->broadaddr && !(dst->broadaddr = dup_sockaddr( src->broadaddr ))) goto err; - if (src->dstaddr && !(dst->dstaddr = dup_sockaddr( src->dstaddr ))) goto err; - return dst; + switch (addr->Address.lpSockaddr->sa_family) + { + case AF_INET: + { + struct sockaddr_in *broadcast_addr_in, *addr_in = (struct sockaddr_in *)addr->Address.lpSockaddr; + 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: - free( dst->addr ); - free( dst->netmask ); - free( dst->broadaddr ); - free( dst->dstaddr ); - free( dst ); + free( ret->addr ); + free( ret->netmask ); + free( ret->broadaddr ); + free( ret ); 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; - src = addrs; + struct pcap_address *dst, *ret = NULL; + IP_ADAPTER_UNICAST_ADDRESS *src = adapter->FirstUnicastAddress; while (src) { if ((dst = build_win32_address( src ))) add_win32_address( &ret, dst ); - src = src->next; + src = src->Next; } return ret; } 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; 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; - ret->addresses = build_win32_addresses( unix_dev->addresses ); + ret->addresses = build_win32_addresses( adapter ); ret->flags = unix_dev->flags; return ret; @@ -364,7 +415,7 @@ static int find_all_devices( const char *source, struct pcap_interface **devs, c cur = unix_devs; 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 ); }