aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework/Communications
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework/Communications')
-rw-r--r--OpenSim/Framework/Communications/OutboundUrlFilter.cs256
-rw-r--r--OpenSim/Framework/Communications/Properties/AssemblyInfo.cs2
-rw-r--r--OpenSim/Framework/Communications/RestClient.cs148
3 files changed, 388 insertions, 18 deletions
diff --git a/OpenSim/Framework/Communications/OutboundUrlFilter.cs b/OpenSim/Framework/Communications/OutboundUrlFilter.cs
new file mode 100644
index 0000000..8b572d1
--- /dev/null
+++ b/OpenSim/Framework/Communications/OutboundUrlFilter.cs
@@ -0,0 +1,256 @@
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.Linq;
31using System.Net;
32using System.Reflection;
33using log4net;
34using LukeSkywalker.IPNetwork;
35using Nini.Config;
36
37namespace OpenSim.Framework.Communications
38{
39 public class OutboundUrlFilter
40 {
41 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
42
43 public string Name { get; private set; }
44
45 private List<IPNetwork> m_blacklistNetworks;
46 private List<IPEndPoint> m_blacklistEndPoints;
47
48 private List<IPNetwork> m_blacklistExceptionNetworks;
49 private List<IPEndPoint> m_blacklistExceptionEndPoints;
50
51 public OutboundUrlFilter(
52 string name,
53 List<IPNetwork> blacklistNetworks, List<IPEndPoint> blacklistEndPoints,
54 List<IPNetwork> blacklistExceptionNetworks, List<IPEndPoint> blacklistExceptionEndPoints)
55 {
56 Name = name;
57
58 m_blacklistNetworks = blacklistNetworks;
59 m_blacklistEndPoints = blacklistEndPoints;
60 m_blacklistExceptionNetworks = blacklistExceptionNetworks;
61 m_blacklistExceptionEndPoints = blacklistExceptionEndPoints;
62 }
63
64 /// <summary>
65 /// Initializes a new instance of the <see cref="OpenSim.Framework.Communications.OutboundUrlFilter"/> class.
66 /// </summary>
67 /// <param name="name">Name of the filter for logging purposes.</param>
68 /// <param name="config">Filter configuration</param>
69 public OutboundUrlFilter(string name, IConfigSource config)
70 {
71 Name = name;
72
73 string configBlacklist
74 = "0.0.0.0/8|10.0.0.0/8|100.64.0.0/10|127.0.0.0/8|169.254.0.0/16|172.16.0.0/12|192.0.0.0/24|192.0.2.0/24|192.88.99.0/24|192.168.0.0/16|198.18.0.0/15|198.51.100.0/24|203.0.113.0/24|224.0.0.0/4|240.0.0.0/4|255.255.255.255/32";
75 string configBlacklistExceptions = "";
76
77 IConfig networkConfig = config.Configs["Network"];
78
79 if (networkConfig != null)
80 {
81 configBlacklist = networkConfig.GetString("OutboundDisallowForUserScripts", configBlacklist);
82 configBlacklistExceptions
83 = networkConfig.GetString("OutboundDisallowForUserScriptsExcept", configBlacklistExceptions);
84 }
85
86 m_log.DebugFormat(
87 "[OUTBOUND URL FILTER]: OutboundDisallowForUserScripts for {0} is [{1}]", Name, configBlacklist);
88 m_log.DebugFormat(
89 "[OUTBOUND URL FILTER]: OutboundDisallowForUserScriptsExcept for {0} is [{1}]", Name, configBlacklistExceptions);
90
91 OutboundUrlFilter.ParseConfigList(
92 configBlacklist, Name, out m_blacklistNetworks, out m_blacklistEndPoints);
93 OutboundUrlFilter.ParseConfigList(
94 configBlacklistExceptions, Name, out m_blacklistExceptionNetworks, out m_blacklistExceptionEndPoints);
95 }
96
97 private static void ParseConfigList(
98 string fullConfigEntry, string filterName, out List<IPNetwork> networks, out List<IPEndPoint> endPoints)
99 {
100 // Parse blacklist
101 string[] configBlacklistEntries
102 = fullConfigEntry.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
103
104 configBlacklistEntries = configBlacklistEntries.Select(e => e.Trim()).ToArray();
105
106 networks = new List<IPNetwork>();
107 endPoints = new List<IPEndPoint>();
108
109 foreach (string configEntry in configBlacklistEntries)
110 {
111 if (configEntry.Contains("/"))
112 {
113 IPNetwork network;
114
115 if (!IPNetwork.TryParse(configEntry, out network))
116 {
117 m_log.ErrorFormat(
118 "[OUTBOUND URL FILTER]: Entry [{0}] is invalid network for {1}", configEntry, filterName);
119
120 continue;
121 }
122
123 networks.Add(network);
124 }
125 else
126 {
127 Uri configEntryUri;
128
129 if (!Uri.TryCreate("http://" + configEntry, UriKind.Absolute, out configEntryUri))
130 {
131 m_log.ErrorFormat(
132 "[OUTBOUND URL FILTER]: EndPoint entry [{0}] is invalid endpoint for {1}",
133 configEntry, filterName);
134
135 continue;
136 }
137
138 IPAddress[] addresses = Dns.GetHostAddresses(configEntryUri.Host);
139
140 foreach (IPAddress addr in addresses)
141 {
142 if (addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
143 {
144 // m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}] in config", addr);
145
146 IPEndPoint configEntryEp = new IPEndPoint(addr, configEntryUri.Port);
147 endPoints.Add(configEntryEp);
148
149 // m_log.DebugFormat("[OUTBOUND URL FILTER]: Added blacklist exception [{0}]", configEntryEp);
150 }
151 }
152 }
153 }
154 }
155
156 /// <summary>
157 /// Determines if an url is in a list of networks and endpoints.
158 /// </summary>
159 /// <returns></returns>
160 /// <param name="url">IP address</param>
161 /// <param name="port"></param>
162 /// <param name="networks">Networks.</param>
163 /// <param name="endPoints">End points.</param>
164 /// <param name="filterName">Filter name.</param>
165 private static bool IsInNetwork(
166 IPAddress addr, int port, List<IPNetwork> networks, List<IPEndPoint> endPoints, string filterName)
167 {
168 foreach (IPNetwork ipn in networks)
169 {
170// m_log.DebugFormat(
171// "[OUTBOUND URL FILTER]: Checking [{0}] against network [{1}]", addr, ipn);
172
173 if (IPNetwork.Contains(ipn, addr))
174 {
175// m_log.DebugFormat(
176// "[OUTBOUND URL FILTER]: Found [{0}] in network [{1}]", addr, ipn);
177
178 return true;
179 }
180 }
181
182 // m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}]", addr);
183
184 foreach (IPEndPoint ep in endPoints)
185 {
186// m_log.DebugFormat(
187// "[OUTBOUND URL FILTER]: Checking [{0}:{1}] against endpoint [{2}]",
188// addr, port, ep);
189
190 if (addr.Equals(ep.Address) && port == ep.Port)
191 {
192// m_log.DebugFormat(
193// "[OUTBOUND URL FILTER]: Found [{0}:{1}] in endpoint [{2}]", addr, port, ep);
194
195 return true;
196 }
197 }
198
199// m_log.DebugFormat("[OUTBOUND URL FILTER]: Did not find [{0}:{1}] in list", addr, port);
200
201 return false;
202 }
203
204 /// <summary>
205 /// Checks whether the given url is allowed by the filter.
206 /// </summary>
207 /// <returns></returns>
208 public bool CheckAllowed(Uri url)
209 {
210 bool allowed = true;
211
212 // Check that we are permitted to make calls to this endpoint.
213 bool foundIpv4Address = false;
214
215 IPAddress[] addresses = Dns.GetHostAddresses(url.Host);
216
217 foreach (IPAddress addr in addresses)
218 {
219 if (addr.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
220 {
221// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found address [{0}]", addr);
222
223 foundIpv4Address = true;
224
225 // Check blacklist
226 if (OutboundUrlFilter.IsInNetwork(addr, url.Port, m_blacklistNetworks, m_blacklistEndPoints, Name))
227 {
228// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found [{0}] in blacklist for {1}", url, Name);
229
230 // Check blacklist exceptions
231 allowed
232 = OutboundUrlFilter.IsInNetwork(
233 addr, url.Port, m_blacklistExceptionNetworks, m_blacklistExceptionEndPoints, Name);
234
235// if (allowed)
236// m_log.DebugFormat("[OUTBOUND URL FILTER]: Found [{0}] in whitelist for {1}", url, Name);
237 }
238 }
239
240 // Found at least one address in a blacklist and not a blacklist exception
241 if (!allowed)
242 return false;
243// else
244// m_log.DebugFormat("[OUTBOUND URL FILTER]: URL [{0}] not in blacklist for {1}", url, Name);
245 }
246
247 // We do not know how to handle IPv6 securely yet.
248 if (!foundIpv4Address)
249 return false;
250
251// m_log.DebugFormat("[OUTBOUND URL FILTER]: Allowing request [{0}]", url);
252
253 return allowed;
254 }
255 }
256} \ No newline at end of file
diff --git a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs b/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs
index 09611fa..b398167 100644
--- a/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs
+++ b/OpenSim/Framework/Communications/Properties/AssemblyInfo.cs
@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
61// You can specify all the values or you can default the Revision and Build Numbers 61// You can specify all the values or you can default the Revision and Build Numbers
62// by using the '*' as shown below: 62// by using the '*' as shown below:
63 63
64[assembly : AssemblyVersion("0.8.0.*")] 64[assembly : AssemblyVersion("0.8.2.*")]
65 65
diff --git a/OpenSim/Framework/Communications/RestClient.cs b/OpenSim/Framework/Communications/RestClient.cs
index ce36fbf..4403f40 100644
--- a/OpenSim/Framework/Communications/RestClient.cs
+++ b/OpenSim/Framework/Communications/RestClient.cs
@@ -35,6 +35,8 @@ using System.Threading;
35using System.Web; 35using System.Web;
36using log4net; 36using log4net;
37 37
38using OpenSim.Framework.ServiceAuth;
39
38namespace OpenSim.Framework.Communications 40namespace OpenSim.Framework.Communications
39{ 41{
40 /// <summary> 42 /// <summary>
@@ -54,7 +56,7 @@ namespace OpenSim.Framework.Communications
54 /// other threads to execute, while it waits for a response from the web-service. RestClient itself can be 56 /// other threads to execute, while it waits for a response from the web-service. RestClient itself can be
55 /// invoked by the caller in either synchronous mode or asynchronous modes. 57 /// invoked by the caller in either synchronous mode or asynchronous modes.
56 /// </remarks> 58 /// </remarks>
57 public class RestClient 59 public class RestClient : IDisposable
58 { 60 {
59 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 61 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
60 62
@@ -88,7 +90,7 @@ namespace OpenSim.Framework.Communications
88 private byte[] _readbuf; 90 private byte[] _readbuf;
89 91
90 /// <summary> 92 /// <summary>
91 /// MemoryStream representing the resultiong resource 93 /// MemoryStream representing the resulting resource
92 /// </summary> 94 /// </summary>
93 private Stream _resource; 95 private Stream _resource;
94 96
@@ -146,6 +148,33 @@ namespace OpenSim.Framework.Communications
146 148
147 #endregion constructors 149 #endregion constructors
148 150
151
152 #region Dispose
153
154 private bool disposed = false;
155
156 public void Dispose()
157 {
158 Dispose(true);
159 GC.SuppressFinalize(this);
160 }
161
162 protected virtual void Dispose(bool disposing)
163 {
164 if (disposed)
165 return;
166
167 if (disposing)
168 {
169 _resource.Dispose();
170 }
171
172 disposed = true;
173 }
174
175 #endregion Dispose
176
177
149 /// <summary> 178 /// <summary>
150 /// Add a path element to the query, e.g. assets 179 /// Add a path element to the query, e.g. assets
151 /// </summary> 180 /// </summary>
@@ -299,6 +328,14 @@ namespace OpenSim.Framework.Communications
299 /// </summary> 328 /// </summary>
300 public Stream Request() 329 public Stream Request()
301 { 330 {
331 return Request(null);
332 }
333
334 /// <summary>
335 /// Perform a synchronous request
336 /// </summary>
337 public Stream Request(IServiceAuth auth)
338 {
302 lock (_lock) 339 lock (_lock)
303 { 340 {
304 _request = (HttpWebRequest) WebRequest.Create(buildUri()); 341 _request = (HttpWebRequest) WebRequest.Create(buildUri());
@@ -307,23 +344,49 @@ namespace OpenSim.Framework.Communications
307 _request.Timeout = 200000; 344 _request.Timeout = 200000;
308 _request.Method = RequestMethod; 345 _request.Method = RequestMethod;
309 _asyncException = null; 346 _asyncException = null;
347 if (auth != null)
348 auth.AddAuthorization(_request.Headers);
349
350 int reqnum = WebUtil.RequestNumber++;
351 if (WebUtil.DebugLevel >= 3)
352 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} REST {1} to {2}", reqnum, _request.Method, _request.RequestUri);
310 353
311// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request); 354// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request);
355
312 try 356 try
313 { 357 {
314 _response = (HttpWebResponse) _request.GetResponse(); 358 using (_response = (HttpWebResponse) _request.GetResponse())
359 {
360 using (Stream src = _response.GetResponseStream())
361 {
362 int length = src.Read(_readbuf, 0, BufferSize);
363 while (length > 0)
364 {
365 _resource.Write(_readbuf, 0, length);
366 length = src.Read(_readbuf, 0, BufferSize);
367 }
368
369 // TODO! Implement timeout, without killing the server
370 // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted
371 //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true);
372
373 // _allDone.WaitOne();
374 }
375 }
315 } 376 }
316 catch (WebException e) 377 catch (WebException e)
317 { 378 {
318 HttpWebResponse errorResponse = e.Response as HttpWebResponse; 379 using (HttpWebResponse errorResponse = e.Response as HttpWebResponse)
319 if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode)
320 {
321 m_log.Warn("[REST CLIENT] Resource not found (404)");
322 }
323 else
324 { 380 {
325 m_log.Error("[REST CLIENT] Error fetching resource from server " + _request.Address.ToString()); 381 if (null != errorResponse && HttpStatusCode.NotFound == errorResponse.StatusCode)
326 m_log.Debug(e.ToString()); 382 {
383 // This is often benign. E.g., requesting a missing asset will return 404.
384 m_log.DebugFormat("[REST CLIENT] Resource not found (404): {0}", _request.Address.ToString());
385 }
386 else
387 {
388 m_log.Error(string.Format("[REST CLIENT] Error fetching resource from server: {0} ", _request.Address.ToString()), e);
389 }
327 } 390 }
328 391
329 if (_response != null) 392 if (_response != null)
@@ -332,6 +395,8 @@ namespace OpenSim.Framework.Communications
332 return null; 395 return null;
333 } 396 }
334 397
398<<<<<<< HEAD
399=======
335 using (Stream src = _response.GetResponseStream()) 400 using (Stream src = _response.GetResponseStream())
336 { 401 {
337 int length = src.Read(_readbuf, 0, BufferSize); 402 int length = src.Read(_readbuf, 0, BufferSize);
@@ -349,6 +414,7 @@ namespace OpenSim.Framework.Communications
349// _allDone.WaitOne(); 414// _allDone.WaitOne();
350 if (_response != null) 415 if (_response != null)
351 _response.Close(); 416 _response.Close();
417>>>>>>> avn/ubitvar
352 if (_asyncException != null) 418 if (_asyncException != null)
353 throw _asyncException; 419 throw _asyncException;
354 420
@@ -358,11 +424,14 @@ namespace OpenSim.Framework.Communications
358 _resource.Seek(0, SeekOrigin.Begin); 424 _resource.Seek(0, SeekOrigin.Begin);
359 } 425 }
360 426
427 if (WebUtil.DebugLevel >= 5)
428 WebUtil.LogResponseDetail(reqnum, _resource);
429
361 return _resource; 430 return _resource;
362 } 431 }
363 } 432 }
364 433
365 public Stream Request(Stream src) 434 public Stream Request(Stream src, IServiceAuth auth)
366 { 435 {
367 _request = (HttpWebRequest) WebRequest.Create(buildUri()); 436 _request = (HttpWebRequest) WebRequest.Create(buildUri());
368 _request.KeepAlive = false; 437 _request.KeepAlive = false;
@@ -371,13 +440,28 @@ namespace OpenSim.Framework.Communications
371 _request.Method = RequestMethod; 440 _request.Method = RequestMethod;
372 _asyncException = null; 441 _asyncException = null;
373 _request.ContentLength = src.Length; 442 _request.ContentLength = src.Length;
443 if (auth != null)
444 auth.AddAuthorization(_request.Headers);
374 445
375 m_log.InfoFormat("[REST]: Request Length {0}", _request.ContentLength);
376 m_log.InfoFormat("[REST]: Sending Web Request {0}", buildUri());
377 src.Seek(0, SeekOrigin.Begin); 446 src.Seek(0, SeekOrigin.Begin);
447<<<<<<< HEAD
448
449 int reqnum = WebUtil.RequestNumber++;
450 if (WebUtil.DebugLevel >= 3)
451 m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} REST {1} to {2}", reqnum, _request.Method, _request.RequestUri);
452 if (WebUtil.DebugLevel >= 5)
453 WebUtil.LogOutgoingDetail(string.Format("SEND {0}: ", reqnum), src);
454
455 Stream dst = _request.GetRequestStream();
456
457 byte[] buf = new byte[1024];
458 int length = src.Read(buf, 0, 1024);
459 while (length > 0)
460=======
378 m_log.Info("[REST]: Seek is ok"); 461 m_log.Info("[REST]: Seek is ok");
379 462
380 using (Stream dst = _request.GetRequestStream()) 463 using (Stream dst = _request.GetRequestStream())
464>>>>>>> avn/ubitvar
381 { 465 {
382 m_log.Info("[REST]: GetRequestStream is ok"); 466 m_log.Info("[REST]: GetRequestStream is ok");
383 467
@@ -391,7 +475,37 @@ namespace OpenSim.Framework.Communications
391 } 475 }
392 } 476 }
393 477
394 _response = (HttpWebResponse) _request.GetResponse(); 478 try
479 {
480 _response = (HttpWebResponse)_request.GetResponse();
481 }
482 catch (WebException e)
483 {
484 m_log.WarnFormat("[REST]: Request {0} {1} failed with status {2} and message {3}",
485 RequestMethod, _request.RequestUri, e.Status, e.Message);
486 return null;
487 }
488 catch (Exception e)
489 {
490 m_log.WarnFormat(
491 "[REST]: Request {0} {1} failed with exception {2} {3}",
492 RequestMethod, _request.RequestUri, e.Message, e.StackTrace);
493 return null;
494 }
495
496 if (WebUtil.DebugLevel >= 5)
497 {
498 using (Stream responseStream = _response.GetResponseStream())
499 {
500 using (StreamReader reader = new StreamReader(responseStream))
501 {
502 string responseStr = reader.ReadToEnd();
503 WebUtil.LogResponseDetail(reqnum, responseStr);
504 }
505 }
506 }
507
508 _response.Close();
395 509
396 if (_response != null) 510 if (_response != null)
397 _response.Close(); 511 _response.Close();
@@ -413,7 +527,7 @@ namespace OpenSim.Framework.Communications
413 /// In case, we are invoked asynchroneously this object will keep track of the state 527 /// In case, we are invoked asynchroneously this object will keep track of the state
414 /// </summary> 528 /// </summary>
415 AsyncResult<Stream> ar = new AsyncResult<Stream>(callback, state); 529 AsyncResult<Stream> ar = new AsyncResult<Stream>(callback, state);
416 Util.FireAndForget(RequestHelper, ar); 530 Util.FireAndForget(RequestHelper, ar, "RestClient.BeginRequest");
417 return ar; 531 return ar;
418 } 532 }
419 533
@@ -433,7 +547,7 @@ namespace OpenSim.Framework.Communications
433 try 547 try
434 { 548 {
435 // Perform the operation; if sucessful set the result 549 // Perform the operation; if sucessful set the result
436 Stream s = Request(); 550 Stream s = Request(null);
437 ar.SetAsCompleted(s, false); 551 ar.SetAsCompleted(s, false);
438 } 552 }
439 catch (Exception e) 553 catch (Exception e)