1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.fourthline.cling.transport.impl;
17
18 import org.fourthline.cling.model.Constants;
19 import org.fourthline.cling.transport.spi.InitializationException;
20 import org.fourthline.cling.transport.spi.NetworkAddressFactory;
21 import org.fourthline.cling.transport.spi.NoNetworkException;
22 import org.seamless.util.Iterators;
23
24 import java.net.Inet4Address;
25 import java.net.Inet6Address;
26 import java.net.InetAddress;
27 import java.net.InterfaceAddress;
28 import java.net.NetworkInterface;
29 import java.net.SocketException;
30 import java.net.UnknownHostException;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.Enumeration;
35 import java.util.HashSet;
36 import java.util.Iterator;
37 import java.util.List;
38 import java.util.Set;
39 import java.util.Locale;
40 import java.util.logging.Level;
41 import java.util.logging.Logger;
42
43
44
45
46
47
48
49
50
51
52 public class NetworkAddressFactoryImpl implements NetworkAddressFactory {
53
54
55 public static final int DEFAULT_TCP_HTTP_LISTEN_PORT = 0;
56
57 private static Logger log = Logger.getLogger(NetworkAddressFactoryImpl.class.getName());
58
59 final protected Set<String> useInterfaces = new HashSet<>();
60 final protected Set<String> useAddresses = new HashSet<>();
61
62 final protected List<NetworkInterface> networkInterfaces = new ArrayList<>();
63 final protected List<InetAddress> bindAddresses = new ArrayList<>();
64
65 protected int streamListenPort;
66
67
68
69
70 public NetworkAddressFactoryImpl() throws InitializationException {
71 this(DEFAULT_TCP_HTTP_LISTEN_PORT);
72 }
73
74 public NetworkAddressFactoryImpl(int streamListenPort) throws InitializationException {
75
76 System.setProperty("java.net.preferIPv4Stack", "true");
77
78 String useInterfacesString = System.getProperty(SYSTEM_PROPERTY_NET_IFACES);
79 if (useInterfacesString != null) {
80 String[] userInterfacesStrings = useInterfacesString.split(",");
81 useInterfaces.addAll(Arrays.asList(userInterfacesStrings));
82 }
83
84 String useAddressesString = System.getProperty(SYSTEM_PROPERTY_NET_ADDRESSES);
85 if (useAddressesString != null) {
86 String[] useAddressesStrings = useAddressesString.split(",");
87 useAddresses.addAll(Arrays.asList(useAddressesStrings));
88 }
89
90 discoverNetworkInterfaces();
91 discoverBindAddresses();
92
93 if ((networkInterfaces.size() == 0 || bindAddresses.size() == 0)) {
94 log.warning("No usable network interface or addresses found");
95 if(requiresNetworkInterface()) {
96 throw new NoNetworkException(
97 "Could not discover any usable network interfaces and/or addresses"
98 );
99 }
100 }
101
102 this.streamListenPort = streamListenPort;
103 }
104
105
106
107
108 protected boolean requiresNetworkInterface() {
109 return true;
110 }
111
112 public void logInterfaceInformation() {
113 synchronized (networkInterfaces) {
114 if(networkInterfaces.isEmpty()) {
115 log.info("No network interface to display!");
116 return ;
117 }
118 for(NetworkInterface networkInterface : networkInterfaces) {
119 try {
120 logInterfaceInformation(networkInterface);
121 } catch (SocketException ex) {
122 log.log(Level.WARNING, "Exception while logging network interface information", ex);
123 }
124 }
125 }
126 }
127
128 public InetAddress getMulticastGroup() {
129 try {
130 return InetAddress.getByName(Constants.IPV4_UPNP_MULTICAST_GROUP);
131 } catch (UnknownHostException ex) {
132 throw new RuntimeException(ex);
133 }
134 }
135
136 public int getMulticastPort() {
137 return Constants.UPNP_MULTICAST_PORT;
138 }
139
140 public int getStreamListenPort() {
141 return streamListenPort;
142 }
143
144 public Iterator<NetworkInterface> getNetworkInterfaces() {
145 return new Iterators.Synchronized<NetworkInterface>(networkInterfaces) {
146 @Override
147 protected void synchronizedRemove(int index) {
148 synchronized (networkInterfaces) {
149 networkInterfaces.remove(index);
150 }
151 }
152 };
153 }
154
155 public Iterator<InetAddress> getBindAddresses() {
156 return new Iterators.Synchronized<InetAddress>(bindAddresses) {
157 @Override
158 protected void synchronizedRemove(int index) {
159 synchronized (bindAddresses) {
160 bindAddresses.remove(index);
161 }
162 }
163 };
164 }
165
166 public boolean hasUsableNetwork() {
167 return networkInterfaces.size() > 0 && bindAddresses.size() > 0;
168 }
169
170 public byte[] getHardwareAddress(InetAddress inetAddress) {
171 try {
172 NetworkInterface iface = NetworkInterface.getByInetAddress(inetAddress);
173 return iface != null ? iface.getHardwareAddress() : null;
174 } catch (Throwable ex) {
175 log.log(Level.WARNING, "Cannot get hardware address for: " + inetAddress, ex);
176
177
178
179
180
181
182 return null;
183 }
184 }
185
186 public InetAddress getBroadcastAddress(InetAddress inetAddress) {
187 synchronized (networkInterfaces) {
188 for (NetworkInterface iface : networkInterfaces) {
189 for (InterfaceAddress interfaceAddress : getInterfaceAddresses(iface)) {
190 if (interfaceAddress != null && interfaceAddress.getAddress().equals(inetAddress)) {
191 return interfaceAddress.getBroadcast();
192 }
193 }
194 }
195 }
196 return null;
197 }
198
199 public Short getAddressNetworkPrefixLength(InetAddress inetAddress) {
200 synchronized (networkInterfaces) {
201 for (NetworkInterface iface : networkInterfaces) {
202 for (InterfaceAddress interfaceAddress : getInterfaceAddresses(iface)) {
203 if (interfaceAddress != null && interfaceAddress.getAddress().equals(inetAddress)) {
204 short prefix = interfaceAddress.getNetworkPrefixLength();
205 if(prefix > 0 && prefix < 32) return prefix;
206 return null;
207 }
208 }
209 }
210 }
211 return null;
212 }
213
214 public InetAddress getLocalAddress(NetworkInterface networkInterface, boolean isIPv6, InetAddress remoteAddress) {
215
216
217 InetAddress localIPInSubnet = getBindAddressInSubnetOf(remoteAddress);
218 if (localIPInSubnet != null) return localIPInSubnet;
219
220
221
222
223
224
225
226
227 log.finer("Could not find local bind address in same subnet as: " + remoteAddress.getHostAddress());
228
229
230 for (InetAddress interfaceAddress: getInetAddresses(networkInterface)) {
231 if (isIPv6 && interfaceAddress instanceof Inet6Address)
232 return interfaceAddress;
233 if (!isIPv6 && interfaceAddress instanceof Inet4Address)
234 return interfaceAddress;
235 }
236 throw new IllegalStateException("Can't find any IPv4 or IPv6 address on interface: " + networkInterface.getDisplayName());
237 }
238
239 protected List<InterfaceAddress> getInterfaceAddresses(NetworkInterface networkInterface) {
240 return networkInterface.getInterfaceAddresses();
241 }
242
243 protected List<InetAddress> getInetAddresses(NetworkInterface networkInterface) {
244 return Collections.list(networkInterface.getInetAddresses());
245 }
246
247 protected InetAddress getBindAddressInSubnetOf(InetAddress inetAddress) {
248 synchronized (networkInterfaces) {
249 for (NetworkInterface iface : networkInterfaces) {
250 for (InterfaceAddress ifaceAddress : getInterfaceAddresses(iface)) {
251
252 synchronized (bindAddresses) {
253 if (ifaceAddress == null || !bindAddresses.contains(ifaceAddress.getAddress())) {
254 continue;
255 }
256 }
257
258 if (isInSubnet(
259 inetAddress.getAddress(),
260 ifaceAddress.getAddress().getAddress(),
261 ifaceAddress.getNetworkPrefixLength())
262 ) {
263 return ifaceAddress.getAddress();
264 }
265 }
266
267 }
268 }
269 return null;
270 }
271
272 protected boolean isInSubnet(byte[] ip, byte[] network, short prefix) {
273 if (ip.length != network.length) {
274 return false;
275 }
276
277 if (prefix / 8 > ip.length) {
278 return false;
279 }
280
281 int i = 0;
282 while (prefix >= 8 && i < ip.length) {
283 if (ip[i] != network[i]) {
284 return false;
285 }
286 i++;
287 prefix -= 8;
288 }
289 if(i == ip.length) return true;
290 final byte mask = (byte) ~((1 << 8 - prefix) - 1);
291
292 return (ip[i] & mask) == (network[i] & mask);
293 }
294
295 protected void discoverNetworkInterfaces() throws InitializationException {
296 try {
297
298 Enumeration<NetworkInterface> interfaceEnumeration = NetworkInterface.getNetworkInterfaces();
299 for (NetworkInterface iface : Collections.list(interfaceEnumeration)) {
300
301
302 log.finer("Analyzing network interface: " + iface.getDisplayName());
303 if (isUsableNetworkInterface(iface)) {
304 log.fine("Discovered usable network interface: " + iface.getDisplayName());
305 synchronized (networkInterfaces) {
306 networkInterfaces.add(iface);
307 }
308 } else {
309 log.finer("Ignoring non-usable network interface: " + iface.getDisplayName());
310 }
311 }
312
313 } catch (Exception ex) {
314 throw new InitializationException("Could not not analyze local network interfaces: " + ex, ex);
315 }
316 }
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341 protected boolean isUsableNetworkInterface(NetworkInterface iface) throws Exception {
342 if (!iface.isUp()) {
343 log.finer("Skipping network interface (down): " + iface.getDisplayName());
344 return false;
345 }
346
347 if (getInetAddresses(iface).size() == 0) {
348 log.finer("Skipping network interface without bound IP addresses: " + iface.getDisplayName());
349 return false;
350 }
351
352 if (iface.getName().toLowerCase(Locale.ROOT).startsWith("vmnet") ||
353 (iface.getDisplayName() != null && iface.getDisplayName().toLowerCase(Locale.ROOT).contains("vmnet"))) {
354 log.finer("Skipping network interface (VMWare): " + iface.getDisplayName());
355 return false;
356 }
357
358 if (iface.getName().toLowerCase(Locale.ROOT).startsWith("vnic")) {
359 log.finer("Skipping network interface (Parallels): " + iface.getDisplayName());
360 return false;
361 }
362
363 if (iface.getName().toLowerCase(Locale.ROOT).startsWith("vboxnet")) {
364 log.finer("Skipping network interface (Virtual Box): " + iface.getDisplayName());
365 return false;
366 }
367
368 if (iface.getName().toLowerCase(Locale.ROOT).contains("virtual")) {
369 log.finer("Skipping network interface (named '*virtual*'): " + iface.getDisplayName());
370 return false;
371 }
372
373 if (iface.getName().toLowerCase(Locale.ROOT).startsWith("ppp")) {
374 log.finer("Skipping network interface (PPP): " + iface.getDisplayName());
375 return false;
376 }
377
378 if (iface.isLoopback()) {
379 log.finer("Skipping network interface (ignoring loopback): " + iface.getDisplayName());
380 return false;
381 }
382
383 if (useInterfaces.size() > 0 && !useInterfaces.contains(iface.getName())) {
384 log.finer("Skipping unwanted network interface (-D" + SYSTEM_PROPERTY_NET_IFACES + "): " + iface.getName());
385 return false;
386 }
387
388 if (!iface.supportsMulticast())
389 log.warning("Network interface may not be multicast capable: " + iface.getDisplayName());
390
391 return true;
392 }
393
394 protected void discoverBindAddresses() throws InitializationException {
395 try {
396
397 synchronized (networkInterfaces) {
398 Iterator<NetworkInterface> it = networkInterfaces.iterator();
399 while (it.hasNext()) {
400 NetworkInterface networkInterface = it.next();
401
402 log.finer("Discovering addresses of interface: " + networkInterface.getDisplayName());
403 int usableAddresses = 0;
404 for (InetAddress inetAddress : getInetAddresses(networkInterface)) {
405 if (inetAddress == null) {
406 log.warning("Network has a null address: " + networkInterface.getDisplayName());
407 continue;
408 }
409
410 if (isUsableAddress(networkInterface, inetAddress)) {
411 log.fine("Discovered usable network interface address: " + inetAddress.getHostAddress());
412 usableAddresses++;
413 synchronized (bindAddresses) {
414 bindAddresses.add(inetAddress);
415 }
416 } else {
417 log.finer("Ignoring non-usable network interface address: " + inetAddress.getHostAddress());
418 }
419 }
420
421 if (usableAddresses == 0) {
422 log.finer("Network interface has no usable addresses, removing: " + networkInterface.getDisplayName());
423 it.remove();
424 }
425 }
426 }
427
428 } catch (Exception ex) {
429 throw new InitializationException("Could not not analyze local network interfaces: " + ex, ex);
430 }
431 }
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450 protected boolean isUsableAddress(NetworkInterface networkInterface, InetAddress address) {
451 if (!(address instanceof Inet4Address)) {
452 log.finer("Skipping unsupported non-IPv4 address: " + address);
453 return false;
454 }
455
456 if (address.isLoopbackAddress()) {
457 log.finer("Skipping loopback address: " + address);
458 return false;
459 }
460
461 if (useAddresses.size() > 0 && !useAddresses.contains(address.getHostAddress())) {
462 log.finer("Skipping unwanted address: " + address);
463 return false;
464 }
465
466 return true;
467 }
468
469 protected void logInterfaceInformation(NetworkInterface networkInterface) throws SocketException {
470 log.info("---------------------------------------------------------------------------------");
471 log.info(String.format("Interface display name: %s", networkInterface.getDisplayName()));
472 if (networkInterface.getParent() != null)
473 log.info(String.format("Parent Info: %s", networkInterface.getParent()));
474 log.info(String.format("Name: %s", networkInterface.getName()));
475
476 Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
477
478 for (InetAddress inetAddress : Collections.list(inetAddresses)) {
479 log.info(String.format("InetAddress: %s", inetAddress));
480 }
481
482 List<InterfaceAddress> interfaceAddresses = networkInterface.getInterfaceAddresses();
483
484 for (InterfaceAddress interfaceAddress : interfaceAddresses) {
485 if (interfaceAddress == null) {
486 log.warning("Skipping null InterfaceAddress!");
487 continue;
488 }
489 log.info(" Interface Address");
490 log.info(" Address: " + interfaceAddress.getAddress());
491 log.info(" Broadcast: " + interfaceAddress.getBroadcast());
492 log.info(" Prefix length: " + interfaceAddress.getNetworkPrefixLength());
493 }
494
495 Enumeration<NetworkInterface> subIfs = networkInterface.getSubInterfaces();
496
497 for (NetworkInterface subIf : Collections.list(subIfs)) {
498 if (subIf == null) {
499 log.warning("Skipping null NetworkInterface sub-interface");
500 continue;
501 }
502 log.info(String.format("\tSub Interface Display name: %s", subIf.getDisplayName()));
503 log.info(String.format("\tSub Interface Name: %s", subIf.getName()));
504 }
505 log.info(String.format("Up? %s", networkInterface.isUp()));
506 log.info(String.format("Loopback? %s", networkInterface.isLoopback()));
507 log.info(String.format("PointToPoint? %s", networkInterface.isPointToPoint()));
508 log.info(String.format("Supports multicast? %s", networkInterface.supportsMulticast()));
509 log.info(String.format("Virtual? %s", networkInterface.isVirtual()));
510 log.info(String.format("Hardware address: %s", Arrays.toString(networkInterface.getHardwareAddress())));
511 log.info(String.format("MTU: %s", networkInterface.getMTU()));
512 }
513 }