aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/NetworkUtil.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/NetworkUtil.cs')
-rw-r--r--OpenSim/Framework/NetworkUtil.cs250
1 files changed, 250 insertions, 0 deletions
diff --git a/OpenSim/Framework/NetworkUtil.cs b/OpenSim/Framework/NetworkUtil.cs
new file mode 100644
index 0000000..2e94b0d
--- /dev/null
+++ b/OpenSim/Framework/NetworkUtil.cs
@@ -0,0 +1,250 @@
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
28using System;
29using System.Collections.Generic;
30using System.Net.Sockets;
31using System.Net;
32using System.Net.NetworkInformation;
33using System.Reflection;
34using System.Text;
35using log4net;
36
37namespace OpenSim.Framework
38{
39 /// <summary>
40 /// Handles NAT translation in a 'manner of speaking'
41 /// Allows you to return multiple different external
42 /// hostnames depending on the requestors network
43 ///
44 /// This enables standard port forwarding techniques
45 /// to work correctly with OpenSim.
46 /// </summary>
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}