1 | #Region "Microsoft.VisualBasic::ac6fa9843f259d583fe5a375834efa04, Microsoft.VisualBasic.Core\Net\Tcp\IPTools\LAN.vb" |
2 | |
3 | ' Author: |
4 | ' |
5 | ' asuka (amethyst.asuka@gcmodeller.org) |
6 | ' xie (genetics@smrucc.org) |
7 | ' xieguigang (xie.guigang@live.com) |
8 | ' |
9 | ' Copyright (c) 2018 GPL3 Licensed |
10 | ' |
11 | ' |
12 | ' GNU GENERAL PUBLIC LICENSE (GPL3) |
13 | ' |
14 | ' |
15 | ' This program is free software: you can redistribute it and/or modify |
16 | ' it under the terms of the GNU General Public License as published by |
17 | ' the Free Software Foundation, either version 3 of the License, or |
18 | ' (at your option) any later version. |
19 | ' |
20 | ' This program is distributed in the hope that it will be useful, |
21 | ' but WITHOUT ANY WARRANTY; without even the implied warranty of |
22 | ' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
23 | ' GNU General Public License for more details. |
24 | ' |
25 | ' You should have received a copy of the GNU General Public License |
26 | ' along with this program. If not, see <http://www.gnu.org/licenses/>. |
27 | |
28 | |
29 | |
30 | ' /********************************************************************************/ |
31 | |
32 | ' Summaries: |
33 | |
34 | ' Module LANTools |
35 | ' |
36 | ' Function: GetAllDevicesOnLAN, GetIPAddress, GetIpNetTable, GetMacAddress, IsMulticast |
37 | ' Structure MIB_IPNETROW |
38 | ' |
39 | ' |
40 | ' |
41 | ' |
42 | ' |
43 | ' |
44 | ' /********************************************************************************/ |
45 | |
46 | #End Region |
47 | |
48 | Imports System.Net |
49 | Imports System.Net.NetworkInformation |
50 | Imports System.Runtime.InteropServices |
51 | Imports System.Runtime.InteropServices.Marshal |
52 | |
53 | Namespace Net |
54 | |
55 | ''' <summary> |
56 | ''' http://www.codeproject.com/Tips/358946/Retrieving-IP-and-MAC-addresses-for-a-LAN |
57 | ''' </summary> |
58 | ''' <code> |
59 | ''' ' Get my PC IP address |
60 | ''' Call Console.WriteLine("My IP : {0}", GetIPAddress()) |
61 | ''' |
62 | ''' ' Get My PC MAC address |
63 | ''' Call Console.WriteLine("My MAC: {0}", GetMacAddress()) |
64 | ''' |
65 | ''' ' Get all devices on network |
66 | ''' Dim all As Dictionary(Of IPAddress, PhysicalAddress) = GetAllDevicesOnLAN() |
67 | ''' For Each kvp As KeyValuePair(Of IPAddress, PhysicalAddress) In all |
68 | ''' Console.WriteLine("IP : {0}" & vbLf & " MAC {1}", kvp.Key, kvp.Value) |
69 | ''' Next |
70 | ''' </code> |
71 | Public Module LANTools |
72 | |
73 | ''' <summary> |
74 | ''' MIB_IPNETROW structure returned by GetIpNetTable |
75 | ''' DO NOT MODIFY THIS STRUCTURE. |
76 | ''' </summary> |
77 | <StructLayout(LayoutKind.Sequential)> |
78 | Private Structure MIB_IPNETROW |
79 | <MarshalAs(UnmanagedType.U4)> |
80 | Public dwIndex As Integer |
81 | <MarshalAs(UnmanagedType.U4)> |
82 | Public dwPhysAddrLen As Integer |
83 | <MarshalAs(UnmanagedType.U1)> |
84 | Public mac0 As Byte |
85 | <MarshalAs(UnmanagedType.U1)> |
86 | Public mac1 As Byte |
87 | <MarshalAs(UnmanagedType.U1)> |
88 | Public mac2 As Byte |
89 | <MarshalAs(UnmanagedType.U1)> |
90 | Public mac3 As Byte |
91 | <MarshalAs(UnmanagedType.U1)> |
92 | Public mac4 As Byte |
93 | <MarshalAs(UnmanagedType.U1)> |
94 | Public mac5 As Byte |
95 | <MarshalAs(UnmanagedType.U1)> |
96 | Public mac6 As Byte |
97 | <MarshalAs(UnmanagedType.U1)> |
98 | Public mac7 As Byte |
99 | <MarshalAs(UnmanagedType.U4)> |
100 | Public dwAddr As Integer |
101 | <MarshalAs(UnmanagedType.U4)> |
102 | Public dwType As Integer |
103 | End Structure |
104 | |
105 | ''' <summary> |
106 | ''' GetIpNetTable external method |
107 | ''' </summary> |
108 | ''' <param name="pIpNetTable"></param> |
109 | ''' <param name="pdwSize"></param> |
110 | ''' <param name="bOrder"></param> |
111 | ''' <returns></returns> |
112 | <DllImport("IpHlpApi.dll")> |
113 | Private Function GetIpNetTable(pIpNetTable As IntPtr, <MarshalAs(UnmanagedType.U4)> ByRef pdwSize As Integer, bOrder As Boolean) As <MarshalAs(UnmanagedType.U4)> Integer |
114 | End Function |
115 | |
116 | ''' <summary> |
117 | ''' Error codes GetIpNetTable returns that we recognise |
118 | ''' </summary> |
119 | Const ERROR_INSUFFICIENT_BUFFER As Integer = 122 |
120 | |
121 | ''' <summary> |
122 | ''' Get the IP and MAC addresses of all known devices on the LAN |
123 | ''' </summary> |
124 | ''' <remarks> |
125 | ''' 1) This table is not updated often - it can take some human-scale time |
126 | ''' to notice that a device has dropped off the network, or a new device |
127 | ''' has connected. |
128 | ''' 2) This discards non-local devices if they are found - these are multicast |
129 | ''' and can be discarded by IP address range. |
130 | ''' </remarks> |
131 | ''' <returns></returns> |
132 | Public Function GetAllDevicesOnLAN() As Dictionary(Of IPAddress, PhysicalAddress) |
133 | Dim all As New Dictionary(Of IPAddress, PhysicalAddress)() |
134 | ' Add this PC to the list... |
135 | all.Add(GetIPAddress(), GetMacAddress()) |
136 | Dim spaceForNetTable As Integer = 0 |
137 | ' Get the space needed |
138 | ' We do that by requesting the table, but not giving any space at all. |
139 | ' The return value will tell us how much we actually need. |
140 | GetIpNetTable(IntPtr.Zero, spaceForNetTable, False) |
141 | ' Allocate the space |
142 | ' We use a try-finally block to ensure release. |
143 | Dim rawTable As IntPtr = IntPtr.Zero |
144 | Try |
145 | rawTable = AllocCoTaskMem(spaceForNetTable) |
146 | ' Get the actual data |
147 | Dim errorCode As Integer = GetIpNetTable(rawTable, spaceForNetTable, False) |
148 | If errorCode <> 0 Then |
149 | ' Failed for some reason - can do no more here. |
150 | Throw New Exception(String.Format("Unable to retrieve network table. Error code {0}", errorCode)) |
151 | End If |
152 | ' Get the rows count |
153 | Dim rowsCount As Integer = ReadInt32(rawTable) |
154 | Dim currentBuffer As New IntPtr(rawTable.ToInt64() + SizeOf(GetType(Int32))) |
155 | ' Convert the raw table to individual entries |
156 | Dim rows As MIB_IPNETROW() = New MIB_IPNETROW(rowsCount - 1) {} |
157 | For index As Integer = 0 To rowsCount - 1 |
158 | rows(index) = CType(PtrToStructure(New IntPtr(currentBuffer.ToInt64() + (index * SizeOf(GetType(MIB_IPNETROW)))), GetType(MIB_IPNETROW)), MIB_IPNETROW) |
159 | Next |
160 | ' Define the dummy entries list (we can discard these) |
161 | Dim virtualMAC As New PhysicalAddress(New Byte() {0, 0, 0, 0, 0, 0}) |
162 | Dim broadcastMAC As New PhysicalAddress(New Byte() {255, 255, 255, 255, 255, 255}) |
163 | For Each row As MIB_IPNETROW In rows |
164 | Dim ip As New IPAddress(BitConverter.GetBytes(row.dwAddr)) |
165 | Dim rawMAC As Byte() = New Byte() {row.mac0, row.mac1, row.mac2, row.mac3, row.mac4, row.mac5} |
166 | Dim pa As New PhysicalAddress(rawMAC) |
167 | If Not pa.Equals(virtualMAC) AndAlso Not pa.Equals(broadcastMAC) AndAlso Not IsMulticast(ip) Then |
168 | 'Console.WriteLine("IP: {0}\t\tMAC: {1}", ip.ToString(), pa.ToString()); |
169 | If Not all.ContainsKey(ip) Then |
170 | all.Add(ip, pa) |
171 | End If |
172 | End If |
173 | Next |
174 | Finally |
175 | ' Release the memory. |
176 | FreeCoTaskMem(rawTable) |
177 | End Try |
178 | Return all |
179 | End Function |
180 | |
181 | ''' <summary> |
182 | ''' Gets the IP address of the current PC |
183 | ''' </summary> |
184 | ''' <returns></returns> |
185 | Public Function GetIPAddress() As IPAddress |
186 | Dim strHostName As String = Dns.GetHostName() |
187 | Dim ipEntry As IPHostEntry = Dns.GetHostEntry(strHostName) |
188 | Dim addr As IPAddress() = ipEntry.AddressList |
189 | For Each ip As IPAddress In addr |
190 | If Not ip.IsIPv6LinkLocal Then |
191 | Return (ip) |
192 | End If |
193 | Next |
194 | Return If(addr.Length > 0, addr(0), Nothing) |
195 | End Function |
196 | |
197 | ''' <summary> |
198 | ''' Gets the MAC address of the current PC. |
199 | ''' </summary> |
200 | ''' <returns></returns> |
201 | Public Function GetMacAddress() As PhysicalAddress |
202 | For Each nic As NetworkInterface In NetworkInterface.GetAllNetworkInterfaces() |
203 | ' Only consider Ethernet network interfaces |
204 | If nic.NetworkInterfaceType = NetworkInterfaceType.Ethernet AndAlso nic.OperationalStatus = OperationalStatus.Up Then |
205 | Return nic.GetPhysicalAddress() |
206 | End If |
207 | Next |
208 | Return Nothing |
209 | End Function |
210 | |
211 | ''' <summary> |
212 | ''' Returns true if the specified IP address is a multicast address |
213 | ''' </summary> |
214 | ''' <param name="ip"></param> |
215 | ''' <returns></returns> |
216 | Public Function IsMulticast(ip As IPAddress) As Boolean |
217 | Dim result As Boolean = True |
218 | If Not ip.IsIPv6Multicast Then |
219 | Dim highIP As Byte = ip.GetAddressBytes()(0) |
220 | If highIP < 224 OrElse highIP > 239 Then |
221 | result = False |
222 | End If |
223 | End If |
224 | Return result |
225 | End Function |
226 | End Module |
227 | End Namespace |