@@ -2,16 +2,88 @@ use std::{
22 convert:: { TryFrom , TryInto } ,
33 ffi:: CStr ,
44 ffi:: OsString ,
5+ net:: IpAddr ,
56 os:: windows:: ffi:: OsStringExt ,
67 ptr, slice,
78} ;
8- use winapi:: shared:: { ntdef:: ULONG , winerror:: ERROR_SUCCESS , ws2def:: AF_UNSPEC } ;
9+ use winapi:: shared:: {
10+ ntdef:: ULONG ,
11+ winerror:: ERROR_SUCCESS ,
12+ ws2def:: { AF_INET , AF_INET6 , AF_UNSPEC , SOCKADDR_IN } ,
13+ ws2ipdef:: SOCKADDR_IN6 ,
14+ } ;
915use winapi:: um:: { iphlpapi:: GetAdaptersAddresses , iptypes:: IP_ADAPTER_ADDRESSES_LH } ;
1016
1117use crate :: MacAddressError ;
1218
1319const GAA_FLAG_NONE : ULONG = 0x0000 ;
1420
21+ /// Similar to get_mac(); walk this list of adapters and in each
22+ /// adapter, walk the list of UnicastIpAddresses and return the mac address
23+ /// of the first one that matches the given IP
24+ pub ( crate ) fn get_mac_address_by_ip ( ip : & IpAddr ) -> Result < Option < [ u8 ; 6 ] > , MacAddressError > {
25+ let adapters = get_adapters ( ) ?;
26+ // Safety: We don't use the pointer after `adapters` is dropped
27+ let mut ptr = unsafe { adapters. ptr ( ) } ;
28+
29+ // for each adapter on the machine
30+ while !ptr. is_null ( ) {
31+ let bytes = unsafe { convert_mac_bytes ( ptr) } ;
32+
33+ let mut ip_ptr = unsafe { ( * ptr) . FirstUnicastAddress } ;
34+ // for each IP on the adapter
35+ while !ip_ptr. is_null ( ) {
36+ let sock_addr = unsafe { ( * ip_ptr) . Address . lpSockaddr } ;
37+ let adapter_ip = match unsafe { ( * sock_addr) . sa_family } as i32 {
38+ AF_INET => unsafe {
39+ let addr = ( * ( sock_addr as * mut SOCKADDR_IN ) ) . sin_addr ;
40+ Some ( IpAddr :: from ( [
41+ addr. S_un . S_un_b ( ) . s_b1 ,
42+ addr. S_un . S_un_b ( ) . s_b2 ,
43+ addr. S_un . S_un_b ( ) . s_b3 ,
44+ addr. S_un . S_un_b ( ) . s_b4 ,
45+ ] ) )
46+ } ,
47+ AF_INET6 => unsafe {
48+ let addr = ( * ( sock_addr as * mut SOCKADDR_IN6 ) ) . sin6_addr ;
49+ Some ( IpAddr :: from ( addr. u . Byte ( ) . clone ( ) ) )
50+ } ,
51+ _ => {
52+ // ignore unknown address families; only support IPv4/IPv6
53+ None
54+ }
55+ } ;
56+ if let Some ( adapter_ip) = adapter_ip {
57+ if adapter_ip == * ip {
58+ return Ok ( Some ( bytes) ) ;
59+ }
60+ }
61+ // Otherwise check the next IP on the adapter
62+ #[ cfg( target_pointer_width = "32" ) ]
63+ {
64+ ip_ptr = unsafe { ip_ptr. read_unaligned ( ) . Next } ;
65+ }
66+
67+ #[ cfg( not( target_pointer_width = "32" ) ) ]
68+ {
69+ ip_ptr = unsafe { ( * ip_ptr) . Next } ;
70+ }
71+ }
72+
73+ // Otherwise go to the next adapter
74+ #[ cfg( target_pointer_width = "32" ) ]
75+ {
76+ ptr = unsafe { ptr. read_unaligned ( ) . Next } ;
77+ }
78+
79+ #[ cfg( not( target_pointer_width = "32" ) ) ]
80+ {
81+ ptr = unsafe { ( * ptr) . Next } ;
82+ }
83+ }
84+ // All of the calls succeeded, just didn't find it...
85+ Ok ( None )
86+ }
1587/// Uses bindings to the `Iphlpapi.h` Windows header to fetch the interface
1688/// devices list with
1789/// [GetAdaptersAddresses][https://msdn.microsoft.com/en-us/library/windows/desktop/aa365915(v=vs.85).aspx]
0 commit comments