opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 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 {
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 }