OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
NetworkUtil.cs
Go to the documentation of this file.
1 /*
2  * Copyright (c) Contributors, http://opensimulator.org/
3  * See CONTRIBUTORS.TXT for a full list of copyright holders.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of the OpenSimulator Project nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 using System;
29 using System.Collections.Generic;
30 using System.Net.Sockets;
31 using System.Net;
32 using System.Net.NetworkInformation;
33 using System.Reflection;
34 using System.Text;
35 using log4net;
36 
37 namespace OpenSim.Framework
38 {
47  public static class NetworkUtil
48  {
49  // Logger
50  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
51 
52  private static bool m_disabled = true;
53 
54  public static bool Enabled
55  {
56  set { m_disabled = value; }
57  get { return m_disabled; }
58  }
59 
60  // IPv4Address, Subnet
61  static readonly Dictionary<IPAddress,IPAddress> m_subnets = new Dictionary<IPAddress, IPAddress>();
62 
63  public static IPAddress GetIPFor(IPAddress user, IPAddress simulator)
64  {
65  if (m_disabled)
66  return simulator;
67 
68  // Check if we're accessing localhost.
69  foreach (IPAddress host in Dns.GetHostAddresses(Dns.GetHostName()))
70  {
71  if (host.Equals(user) && host.AddressFamily == AddressFamily.InterNetwork)
72  {
73  m_log.Info("[NetworkUtil] Localhost user detected, sending them '" + host + "' instead of '" + simulator + "'");
74  return host;
75  }
76  }
77 
78  // Check for same LAN segment
79  foreach (KeyValuePair<IPAddress, IPAddress> subnet in m_subnets)
80  {
81  byte[] subnetBytes = subnet.Value.GetAddressBytes();
82  byte[] localBytes = subnet.Key.GetAddressBytes();
83  byte[] destBytes = user.GetAddressBytes();
84 
85  if (subnetBytes.Length != destBytes.Length || subnetBytes.Length != localBytes.Length)
86  return null;
87 
88  bool valid = true;
89 
90  for (int i = 0; i < subnetBytes.Length; i++)
91  {
92  if ((localBytes[i] & subnetBytes[i]) != (destBytes[i] & subnetBytes[i]))
93  {
94  valid = false;
95  break;
96  }
97  }
98 
99  if (subnet.Key.AddressFamily != AddressFamily.InterNetwork)
100  valid = false;
101 
102  if (valid)
103  {
104  m_log.Info("[NetworkUtil] Local LAN user detected, sending them '" + subnet.Key + "' instead of '" + simulator + "'");
105  return subnet.Key;
106  }
107  }
108 
109  // Otherwise, return outside address
110  return simulator;
111  }
112 
113  private static IPAddress GetExternalIPFor(IPAddress destination, string defaultHostname)
114  {
115  // Adds IPv6 Support (Not that any of the major protocols supports it...)
116  if (destination.AddressFamily == AddressFamily.InterNetworkV6)
117  {
118  foreach (IPAddress host in Dns.GetHostAddresses(defaultHostname))
119  {
120  if (host.AddressFamily == AddressFamily.InterNetworkV6)
121  {
122  m_log.Info("[NetworkUtil] Localhost user detected, sending them '" + host + "' instead of '" + defaultHostname + "'");
123  return host;
124  }
125  }
126  }
127 
128  if (destination.AddressFamily != AddressFamily.InterNetwork)
129  return null;
130 
131  // Check if we're accessing localhost.
132  foreach (KeyValuePair<IPAddress, IPAddress> pair in m_subnets)
133  {
134  IPAddress host = pair.Value;
135  if (host.Equals(destination) && host.AddressFamily == AddressFamily.InterNetwork)
136  {
137  m_log.Info("[NATROUTING] Localhost user detected, sending them '" + host + "' instead of '" + defaultHostname + "'");
138  return destination;
139  }
140  }
141 
142  // Check for same LAN segment
143  foreach (KeyValuePair<IPAddress, IPAddress> subnet in m_subnets)
144  {
145  byte[] subnetBytes = subnet.Value.GetAddressBytes();
146  byte[] localBytes = subnet.Key.GetAddressBytes();
147  byte[] destBytes = destination.GetAddressBytes();
148 
149  if (subnetBytes.Length != destBytes.Length || subnetBytes.Length != localBytes.Length)
150  return null;
151 
152  bool valid = true;
153 
154  for (int i=0;i<subnetBytes.Length;i++)
155  {
156  if ((localBytes[i] & subnetBytes[i]) != (destBytes[i] & subnetBytes[i]))
157  {
158  valid = false;
159  break;
160  }
161  }
162 
163  if (subnet.Key.AddressFamily != AddressFamily.InterNetwork)
164  valid = false;
165 
166  if (valid)
167  {
168  m_log.Info("[NetworkUtil] Local LAN user detected, sending them '" + subnet.Key + "' instead of '" + defaultHostname + "'");
169  return subnet.Key;
170  }
171  }
172 
173  // Check to see if we can find a IPv4 address.
174  foreach (IPAddress host in Dns.GetHostAddresses(defaultHostname))
175  {
176  if (host.AddressFamily == AddressFamily.InterNetwork)
177  return host;
178  }
179 
180  // Unable to find anything.
181  throw new ArgumentException("[NetworkUtil] Unable to resolve defaultHostname to an IPv4 address for an IPv4 client");
182  }
183 
184  static NetworkUtil()
185  {
186  try
187  {
188  foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces())
189  {
190  foreach (UnicastIPAddressInformation address in ni.GetIPProperties().UnicastAddresses)
191  {
192  if (address.Address.AddressFamily == AddressFamily.InterNetwork)
193  {
194  if (address.IPv4Mask != null)
195  {
196  m_subnets.Add(address.Address, address.IPv4Mask);
197  }
198  }
199  }
200  }
201  }
202  catch (NotImplementedException)
203  {
204  // Mono Sucks.
205  }
206  }
207 
208  public static IPAddress GetIPFor(IPEndPoint user, string defaultHostname)
209  {
210  if (!m_disabled)
211  {
212  // Try subnet matching
213  IPAddress rtn = GetExternalIPFor(user.Address, defaultHostname);
214  if (rtn != null)
215  return rtn;
216  }
217 
218  // Otherwise use the old algorithm
219  IPAddress ia;
220 
221  if (IPAddress.TryParse(defaultHostname, out ia))
222  return ia;
223 
224  ia = null;
225 
226  foreach (IPAddress Adr in Dns.GetHostAddresses(defaultHostname))
227  {
228  if (Adr.AddressFamily == AddressFamily.InterNetwork)
229  {
230  ia = Adr;
231  break;
232  }
233  }
234 
235  return ia;
236  }
237 
238  public static string GetHostFor(IPAddress user, string defaultHostname)
239  {
240  if (!m_disabled)
241  {
242  IPAddress rtn = GetExternalIPFor(user, defaultHostname);
243  if (rtn != null)
244  return rtn.ToString();
245  }
246  return defaultHostname;
247  }
248 
249  }
250 }