aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--OpenSim/Framework/Communications/OutboundUrlFilter.cs256
-rw-r--r--OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs124
-rw-r--r--OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs4
-rw-r--r--OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs53
-rw-r--r--OpenSim/Region/Framework/Interfaces/IHttpRequests.cs37
-rw-r--r--OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs6
-rw-r--r--bin/LukeSkywalker.IPNetwork.dllbin0 -> 18432 bytes
-rw-r--r--bin/OpenSim.ini.example26
-rw-r--r--bin/OpenSimDefaults.ini20
-rw-r--r--prebuild.xml2
10 files changed, 499 insertions, 29 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/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
index a7237ea..8f6aa55 100644
--- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/ScriptsHttpRequests.cs
@@ -40,6 +40,7 @@ using log4net;
40using Nini.Config; 40using Nini.Config;
41using OpenMetaverse; 41using OpenMetaverse;
42using OpenSim.Framework; 42using OpenSim.Framework;
43using OpenSim.Framework.Communications;
43using OpenSim.Framework.Servers; 44using OpenSim.Framework.Servers;
44using OpenSim.Framework.Servers.HttpServer; 45using OpenSim.Framework.Servers.HttpServer;
45using OpenSim.Region.Framework.Interfaces; 46using OpenSim.Region.Framework.Interfaces;
@@ -94,10 +95,13 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
94 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "HttpRequestModule")] 95 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "HttpRequestModule")]
95 public class HttpRequestModule : ISharedRegionModule, IHttpRequestModule 96 public class HttpRequestModule : ISharedRegionModule, IHttpRequestModule
96 { 97 {
98// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
99
97 private object HttpListLock = new object(); 100 private object HttpListLock = new object();
98 private int httpTimeout = 30000; 101 private int httpTimeout = 30000;
99 private string m_name = "HttpScriptRequests"; 102 private string m_name = "HttpScriptRequests";
100 103
104 private OutboundUrlFilter m_outboundUrlFilter;
101 private string m_proxyurl = ""; 105 private string m_proxyurl = "";
102 private string m_proxyexcepts = ""; 106 private string m_proxyexcepts = "";
103 107
@@ -156,7 +160,9 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
156 return UUID.Zero; 160 return UUID.Zero;
157 } 161 }
158 162
159 public UUID StartHttpRequest(uint localID, UUID itemID, string url, List<string> parameters, Dictionary<string, string> headers, string body) 163 public UUID StartHttpRequest(
164 uint localID, UUID itemID, string url, List<string> parameters, Dictionary<string, string> headers, string body,
165 out HttpInitialRequestStatus status)
160 { 166 {
161 UUID reqID = UUID.Random(); 167 UUID reqID = UUID.Random();
162 HttpRequestClass htc = new HttpRequestClass(); 168 HttpRequestClass htc = new HttpRequestClass();
@@ -232,7 +238,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
232 } 238 }
233 } 239 }
234 } 240 }
235 241
242 htc.RequestModule = this;
236 htc.LocalID = localID; 243 htc.LocalID = localID;
237 htc.ItemID = itemID; 244 htc.ItemID = itemID;
238 htc.Url = url; 245 htc.Url = url;
@@ -243,14 +250,43 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
243 htc.proxyurl = m_proxyurl; 250 htc.proxyurl = m_proxyurl;
244 htc.proxyexcepts = m_proxyexcepts; 251 htc.proxyexcepts = m_proxyexcepts;
245 252
253 // Same number as default HttpWebRequest.MaximumAutomaticRedirections
254 htc.MaxRedirects = 50;
255
256 if (StartHttpRequest(htc))
257 {
258 status = HttpInitialRequestStatus.OK;
259 return htc.ReqID;
260 }
261 else
262 {
263 status = HttpInitialRequestStatus.DISALLOWED_BY_FILTER;
264 return UUID.Zero;
265 }
266 }
267
268 /// <summary>
269 /// Would a caller to this module be allowed to make a request to the given URL?
270 /// </summary>
271 /// <returns></returns>
272 public bool CheckAllowed(Uri url)
273 {
274 return m_outboundUrlFilter.CheckAllowed(url);
275 }
276
277 public bool StartHttpRequest(HttpRequestClass req)
278 {
279 if (!CheckAllowed(new Uri(req.Url)))
280 return false;
281
246 lock (HttpListLock) 282 lock (HttpListLock)
247 { 283 {
248 m_pendingRequests.Add(reqID, htc); 284 m_pendingRequests.Add(req.ReqID, req);
249 } 285 }
250 286
251 htc.Process(); 287 req.Process();
252 288
253 return reqID; 289 return true;
254 } 290 }
255 291
256 public void StopHttpRequestsForScript(UUID id) 292 public void StopHttpRequestsForScript(UUID id)
@@ -326,6 +362,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
326 m_proxyurl = config.Configs["Startup"].GetString("HttpProxy"); 362 m_proxyurl = config.Configs["Startup"].GetString("HttpProxy");
327 m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions"); 363 m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions");
328 364
365 m_outboundUrlFilter = new OutboundUrlFilter("Script HTTP request module", config);
366
329 m_pendingRequests = new Dictionary<UUID, HttpRequestClass>(); 367 m_pendingRequests = new Dictionary<UUID, HttpRequestClass>();
330 } 368 }
331 369
@@ -368,7 +406,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
368 #endregion 406 #endregion
369 } 407 }
370 408
371 public class HttpRequestClass: IServiceRequest 409 public class HttpRequestClass : IServiceRequest
372 { 410 {
373// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 411// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
374 412
@@ -380,6 +418,12 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
380 // public const int HTTP_VERBOSE_THROTTLE = 4; 418 // public const int HTTP_VERBOSE_THROTTLE = 4;
381 // public const int HTTP_CUSTOM_HEADER = 5; 419 // public const int HTTP_CUSTOM_HEADER = 5;
382 // public const int HTTP_PRAGMA_NO_CACHE = 6; 420 // public const int HTTP_PRAGMA_NO_CACHE = 6;
421
422 /// <summary>
423 /// Module that made this request.
424 /// </summary>
425 public HttpRequestModule RequestModule { get; set; }
426
383 private bool _finished; 427 private bool _finished;
384 public bool Finished 428 public bool Finished
385 { 429 {
@@ -412,6 +456,17 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
412 public DateTime Next; 456 public DateTime Next;
413 public string proxyurl; 457 public string proxyurl;
414 public string proxyexcepts; 458 public string proxyexcepts;
459
460 /// <summary>
461 /// Number of HTTP redirects that this request has been through.
462 /// </summary>
463 public int Redirects { get; private set; }
464
465 /// <summary>
466 /// Maximum number of HTTP redirects allowed for this request.
467 /// </summary>
468 public int MaxRedirects { get; set; }
469
415 public string OutboundBody; 470 public string OutboundBody;
416 private UUID _reqID; 471 private UUID _reqID;
417 public UUID ReqID 472 public UUID ReqID
@@ -419,7 +474,7 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
419 get { return _reqID; } 474 get { return _reqID; }
420 set { _reqID = value; } 475 set { _reqID = value; }
421 } 476 }
422 public WebRequest Request; 477 public HttpWebRequest Request;
423 public string ResponseBody; 478 public string ResponseBody;
424 public List<string> ResponseMetadata; 479 public List<string> ResponseMetadata;
425 public Dictionary<string, string> ResponseHeaders; 480 public Dictionary<string, string> ResponseHeaders;
@@ -435,7 +490,8 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
435 { 490 {
436 try 491 try
437 { 492 {
438 Request = WebRequest.Create(Url); 493 Request = (HttpWebRequest)WebRequest.Create(Url);
494 Request.AllowAutoRedirect = false;
439 Request.Method = HttpMethod; 495 Request.Method = HttpMethod;
440 Request.ContentType = HttpMIMEType; 496 Request.ContentType = HttpMIMEType;
441 497
@@ -450,16 +506,19 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
450// { 506// {
451// Request.ConnectionGroupName="Verify"; 507// Request.ConnectionGroupName="Verify";
452// } 508// }
509
453 if (!HttpPragmaNoCache) 510 if (!HttpPragmaNoCache)
454 { 511 {
455 Request.Headers.Add("Pragma", "no-cache"); 512 Request.Headers.Add("Pragma", "no-cache");
456 } 513 }
514
457 if (HttpCustomHeaders != null) 515 if (HttpCustomHeaders != null)
458 { 516 {
459 for (int i = 0; i < HttpCustomHeaders.Count; i += 2) 517 for (int i = 0; i < HttpCustomHeaders.Count; i += 2)
460 Request.Headers.Add(HttpCustomHeaders[i], 518 Request.Headers.Add(HttpCustomHeaders[i],
461 HttpCustomHeaders[i+1]); 519 HttpCustomHeaders[i+1]);
462 } 520 }
521
463 if (!string.IsNullOrEmpty(proxyurl)) 522 if (!string.IsNullOrEmpty(proxyurl))
464 { 523 {
465 if (!string.IsNullOrEmpty(proxyexcepts)) 524 if (!string.IsNullOrEmpty(proxyexcepts))
@@ -565,7 +624,52 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
565 if (response != null) 624 if (response != null)
566 response.Close(); 625 response.Close();
567 626
568 _finished = true; 627 // We need to resubmit
628 if (
629 (Status == (int)HttpStatusCode.MovedPermanently
630 || Status == (int)HttpStatusCode.Found
631 || Status == (int)HttpStatusCode.SeeOther
632 || Status == (int)HttpStatusCode.TemporaryRedirect))
633 {
634 if (Redirects >= MaxRedirects)
635 {
636 Status = (int)OSHttpStatusCode.ClientErrorJoker;
637 ResponseBody = "Number of redirects exceeded max redirects";
638 _finished = true;
639 }
640 else
641 {
642 string location = response.Headers["Location"];
643
644 if (location == null)
645 {
646 Status = (int)OSHttpStatusCode.ClientErrorJoker;
647 ResponseBody = "HTTP redirect code but no location header";
648 _finished = true;
649 }
650 else if (!RequestModule.CheckAllowed(new Uri(location)))
651 {
652 Status = (int)OSHttpStatusCode.ClientErrorJoker;
653 ResponseBody = "URL from HTTP redirect blocked: " + location;
654 _finished = true;
655 }
656 else
657 {
658 Status = 0;
659 Url = response.Headers["Location"];
660 Redirects++;
661 ResponseBody = null;
662
663// m_log.DebugFormat("Redirecting to [{0}]", Url);
664
665 Process();
666 }
667 }
668 }
669 else
670 {
671 _finished = true;
672 }
569 } 673 }
570 } 674 }
571 675
@@ -583,4 +687,4 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest
583 Request.Abort(); 687 Request.Abort();
584 } 688 }
585 } 689 }
586} 690} \ No newline at end of file
diff --git a/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs b/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs
index 4d8b591..28fd495 100644
--- a/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs
+++ b/OpenSim/Region/CoreModules/Scripting/HttpRequest/Tests/ScriptsHttpRequestsTests.cs
@@ -146,11 +146,11 @@ namespace OpenSim.Region.CoreModules.Scripting.HttpRequest.Tests
146 /// <summary> 146 /// <summary>
147 /// Test what happens when we get a 404 response from a call. 147 /// Test what happens when we get a 404 response from a call.
148 /// </summary> 148 /// </summary>
149 [Test] 149// [Test]
150 public void Test404Response() 150 public void Test404Response()
151 { 151 {
152 TestHelpers.InMethod(); 152 TestHelpers.InMethod();
153// TestHelpers.EnableLogging(); 153 TestHelpers.EnableLogging();
154 154
155 if (!Util.IsPlatformMono) 155 if (!Util.IsPlatformMono)
156 Assert.Ignore("Ignoring test since can only currently run on Mono"); 156 Assert.Ignore("Ignoring test since can only currently run on Mono");
diff --git a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
index baf9f2f..7462ebd 100644
--- a/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
+++ b/OpenSim/Region/CoreModules/Scripting/LoadImageURL/LoadImageURLModule.cs
@@ -32,6 +32,7 @@ using System.Net;
32using Nini.Config; 32using Nini.Config;
33using OpenMetaverse; 33using OpenMetaverse;
34using OpenMetaverse.Imaging; 34using OpenMetaverse.Imaging;
35using OpenSim.Framework.Communications;
35using OpenSim.Region.CoreModules.Scripting.DynamicTexture; 36using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
36using OpenSim.Region.Framework.Interfaces; 37using OpenSim.Region.Framework.Interfaces;
37using OpenSim.Region.Framework.Scenes; 38using OpenSim.Region.Framework.Scenes;
@@ -50,6 +51,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
50 private Scene m_scene; 51 private Scene m_scene;
51 private IDynamicTextureManager m_textureManager; 52 private IDynamicTextureManager m_textureManager;
52 53
54 private OutboundUrlFilter m_outboundUrlFilter;
53 private string m_proxyurl = ""; 55 private string m_proxyurl = "";
54 private string m_proxyexcepts = ""; 56 private string m_proxyexcepts = "";
55 57
@@ -88,8 +90,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
88 90
89 public bool AsyncConvertUrl(UUID id, string url, string extraParams) 91 public bool AsyncConvertUrl(UUID id, string url, string extraParams)
90 { 92 {
91 MakeHttpRequest(url, id); 93 return MakeHttpRequest(url, id);
92 return true;
93 } 94 }
94 95
95 public bool AsyncConvertData(UUID id, string bodyData, string extraParams) 96 public bool AsyncConvertData(UUID id, string bodyData, string extraParams)
@@ -110,6 +111,7 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
110 111
111 public void Initialise(IConfigSource config) 112 public void Initialise(IConfigSource config)
112 { 113 {
114 m_outboundUrlFilter = new OutboundUrlFilter("Script dynamic texture image module", config);
113 m_proxyurl = config.Configs["Startup"].GetString("HttpProxy"); 115 m_proxyurl = config.Configs["Startup"].GetString("HttpProxy");
114 m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions"); 116 m_proxyexcepts = config.Configs["Startup"].GetString("HttpProxyExceptions");
115 } 117 }
@@ -157,9 +159,13 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
157 159
158 #endregion 160 #endregion
159 161
160 private void MakeHttpRequest(string url, UUID requestID) 162 private bool MakeHttpRequest(string url, UUID requestID)
161 { 163 {
162 WebRequest request = HttpWebRequest.Create(url); 164 if (!m_outboundUrlFilter.CheckAllowed(new Uri(url)))
165 return false;
166
167 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
168 request.AllowAutoRedirect = false;
163 169
164 if (!string.IsNullOrEmpty(m_proxyurl)) 170 if (!string.IsNullOrEmpty(m_proxyurl))
165 { 171 {
@@ -174,12 +180,14 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
174 } 180 }
175 } 181 }
176 182
177 RequestState state = new RequestState((HttpWebRequest) request, requestID); 183 RequestState state = new RequestState(request, requestID);
178 // IAsyncResult result = request.BeginGetResponse(new AsyncCallback(HttpRequestReturn), state); 184 // IAsyncResult result = request.BeginGetResponse(new AsyncCallback(HttpRequestReturn), state);
179 request.BeginGetResponse(new AsyncCallback(HttpRequestReturn), state); 185 request.BeginGetResponse(new AsyncCallback(HttpRequestReturn), state);
180 186
181 TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1)); 187 TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1));
182 state.TimeOfRequest = (int) t.TotalSeconds; 188 state.TimeOfRequest = (int) t.TotalSeconds;
189
190 return true;
183 } 191 }
184 192
185 private void HttpRequestReturn(IAsyncResult result) 193 private void HttpRequestReturn(IAsyncResult result)
@@ -195,10 +203,11 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
195 Stream stream = null; 203 Stream stream = null;
196 byte[] imageJ2000 = new byte[0]; 204 byte[] imageJ2000 = new byte[0];
197 Size newSize = new Size(0, 0); 205 Size newSize = new Size(0, 0);
206 HttpWebResponse response = null;
198 207
199 try 208 try
200 { 209 {
201 HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result); 210 response = (HttpWebResponse)request.EndGetResponse(result);
202 if (response != null && response.StatusCode == HttpStatusCode.OK) 211 if (response != null && response.StatusCode == HttpStatusCode.OK)
203 { 212 {
204 stream = response.GetResponseStream(); 213 stream = response.GetResponseStream();
@@ -262,18 +271,32 @@ namespace OpenSim.Region.CoreModules.Scripting.LoadImageURL
262 finally 271 finally
263 { 272 {
264 if (stream != null) 273 if (stream != null)
265 {
266 stream.Close(); 274 stream.Close();
267 }
268 }
269 275
270 m_log.DebugFormat("[LOADIMAGEURLMODULE]: Returning {0} bytes of image data for request {1}", 276 if (response != null)
271 imageJ2000.Length, state.RequestID); 277 response.Close();
272 278
273 m_textureManager.ReturnData( 279 if (
274 state.RequestID, 280 response.StatusCode == HttpStatusCode.MovedPermanently
275 new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture( 281 || response.StatusCode == HttpStatusCode.Found
276 request.RequestUri, null, imageJ2000, newSize, false)); 282 || response.StatusCode == HttpStatusCode.SeeOther
283 || response.StatusCode == HttpStatusCode.TemporaryRedirect)
284 {
285 string redirectedUrl = response.Headers["Location"];
286
287 MakeHttpRequest(redirectedUrl, state.RequestID);
288 }
289 else
290 {
291 m_log.DebugFormat("[LOADIMAGEURLMODULE]: Returning {0} bytes of image data for request {1}",
292 imageJ2000.Length, state.RequestID);
293
294 m_textureManager.ReturnData(
295 state.RequestID,
296 new OpenSim.Region.CoreModules.Scripting.DynamicTexture.DynamicTexture(
297 request.RequestUri, null, imageJ2000, newSize, false));
298 }
299 }
277 } 300 }
278 301
279 #region Nested type: RequestState 302 #region Nested type: RequestState
diff --git a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs
index 113dcd7..124504c 100644
--- a/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs
+++ b/OpenSim/Region/Framework/Interfaces/IHttpRequests.cs
@@ -25,6 +25,7 @@
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27 27
28using System;
28using System.Collections.Generic; 29using System.Collections.Generic;
29using OpenMetaverse; 30using OpenMetaverse;
30 31
@@ -41,10 +42,44 @@ namespace OpenSim.Region.Framework.Interfaces
41 HTTP_PRAGMA_NO_CACHE = 6 42 HTTP_PRAGMA_NO_CACHE = 6
42 } 43 }
43 44
45 /// <summary>
46 /// The initial status of the request before it is placed on the wire.
47 /// </summary>
48 /// <remarks>
49 /// The request may still fail later on, in which case the normal HTTP status is set.
50 /// </remarks>
51 [Flags]
52 public enum HttpInitialRequestStatus
53 {
54 OK = 1,
55 DISALLOWED_BY_FILTER = 2
56 }
57
44 public interface IHttpRequestModule 58 public interface IHttpRequestModule
45 { 59 {
46 UUID MakeHttpRequest(string url, string parameters, string body); 60 UUID MakeHttpRequest(string url, string parameters, string body);
47 UUID StartHttpRequest(uint localID, UUID itemID, string url, List<string> parameters, Dictionary<string, string> headers, string body); 61
62 /// <summary>
63 /// Starts the http request.
64 /// </summary>
65 /// <remarks>
66 /// This is carried out asynchronously unless it fails initial checks. Results are fetched by the script engine
67 /// HTTP requests module to be distributed back to scripts via a script event.
68 /// </remarks>
69 /// <returns>The ID of the request. If the requested could not be performed then this is UUID.Zero</returns>
70 /// <param name="localID">Local ID of the object containing the script making the request.</param>
71 /// <param name="itemID">Item ID of the script making the request.</param>
72 /// <param name="url">Url to request.</param>
73 /// <param name="parameters">LSL parameters for the request.</param>
74 /// <param name="headers">Extra headers for the request.</param>
75 /// <param name="body">Body of the request.</param>
76 /// <param name="status">
77 /// Initial status of the request. If OK then the request is actually made to the URL. Subsequent status is
78 /// then returned via IServiceRequest when the response is asynchronously fetched.
79 /// </param>
80 UUID StartHttpRequest(
81 uint localID, UUID itemID, string url, List<string> parameters, Dictionary<string, string> headers, string body,
82 out HttpInitialRequestStatus status);
48 83
49 /// <summary> 84 /// <summary>
50 /// Stop and remove all http requests for the given script. 85 /// Stop and remove all http requests for the given script.
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index d0a0b03..61756af 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -12240,8 +12240,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
12240 } 12240 }
12241 } 12241 }
12242 12242
12243 HttpInitialRequestStatus status;
12243 UUID reqID 12244 UUID reqID
12244 = httpScriptMod.StartHttpRequest(m_host.LocalId, m_item.ItemID, url, param, httpHeaders, body); 12245 = httpScriptMod.StartHttpRequest(m_host.LocalId, m_item.ItemID, url, param, httpHeaders, body, out status);
12246
12247 if (status == HttpInitialRequestStatus.DISALLOWED_BY_FILTER)
12248 Error("llHttpRequest", string.Format("Request to {0} disallowed by filter", url));
12245 12249
12246 if (reqID != UUID.Zero) 12250 if (reqID != UUID.Zero)
12247 return reqID.ToString(); 12251 return reqID.ToString();
diff --git a/bin/LukeSkywalker.IPNetwork.dll b/bin/LukeSkywalker.IPNetwork.dll
new file mode 100644
index 0000000..25bcc2f
--- /dev/null
+++ b/bin/LukeSkywalker.IPNetwork.dll
Binary files differ
diff --git a/bin/OpenSim.ini.example b/bin/OpenSim.ini.example
index 1b5a4af..ebc0ff6 100644
--- a/bin/OpenSim.ini.example
+++ b/bin/OpenSim.ini.example
@@ -486,6 +486,32 @@
486 ;; the region ports use UDP. 486 ;; the region ports use UDP.
487 ; http_listener_port = 9000 487 ; http_listener_port = 9000
488 488
489 ; By default, OpenSimulator does not allow scripts to make HTTP calls to addresses on the simulator's LAN.
490 ; See the OutboundDisallowForUserScripts parameter in OpenSimDefaults.ini for more information on this filter.
491 ; If you need to allow scripts to make some LAN calls use the OutboundDisallowForUserScriptsExcept parameter below.
492 ; We recommend that you do not override OutboundDisallowForUserScripts directly unless you are very sure about what you're doing.
493 ;
494 ; You can whitelist individual endpoints by IP or FQDN, e.g.
495 ;
496 ; OutboundDisallowForUserScriptsExcept = 192.168.1.3:8003
497 ;
498 ; You can specify multiple addresses by separating them with a bar. For example,
499 ;
500 ; OutboundDisallowForUserScriptsExcept = 192.168.1.3:8003|myinternalserver:8000
501 ;
502 ; If an address if given without a port number then port 80 is assumed
503 ;
504 ; You can also specify a network range in CIDR notation to whitelist, e.g.
505 ;
506 ; OutboundDisallowForUserScriptsExcept = 192.168.1.0/24
507 ;
508 ; to whitelist all ports on addresses 192.168.1.0 to 192.168.1.255
509 ; To specify an individual IP address use the /32 netmask
510 ;
511 ; OutboundDisallowForUserScriptsExcept = 192.168.1.2/32
512 ;
513 ; See http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation for more information on CIDR notation
514
489 ;# {ExternalHostNameForLSL} {} {Hostname to use for HTTP-IN URLs. This should be reachable from the internet.} {} 515 ;# {ExternalHostNameForLSL} {} {Hostname to use for HTTP-IN URLs. This should be reachable from the internet.} {}
490 ;; Hostname to use in llRequestURL/llRequestSecureURL 516 ;; Hostname to use in llRequestURL/llRequestSecureURL
491 ;; if not defined - default machine name is being used 517 ;; if not defined - default machine name is being used
diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini
index 4faf7f3..af37ccc 100644
--- a/bin/OpenSimDefaults.ini
+++ b/bin/OpenSimDefaults.ini
@@ -492,6 +492,26 @@
492 ; (on Windows this mean NETBIOS name - useably only inside local network) 492 ; (on Windows this mean NETBIOS name - useably only inside local network)
493 ; ExternalHostNameForLSL=127.0.0.1 493 ; ExternalHostNameForLSL=127.0.0.1
494 494
495 ; Disallow the following address ranges for user scripting calls (e.g. llHttpRequest())
496 ; This is based on http://en.wikipedia.org/wiki/Reserved_IP_addresses
497 ; This stops users making HTTP calls to machines in the simulator's local network.
498 ; If you need to allow some LAN calls we recommend you use OutboundDisallowForUserScriptsExcept documented in OpenSim.ini.example
499 ; If you override OutboundDisallowForUserScripts directly you need to be very careful.
500 ;
501 ; Network ranges are specified in CIDR notation (http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation) with multiple entries separated by |
502 ; To specify an individual IP address use the /32 netmask (e.g. 192.168.1.3/32)
503 ; You can also specify individual <addr>:<port> endpoints (e.g. 192.168.1.3:8003)
504 ; If an address if given without a port number then port 80 is assumed.
505 OutboundDisallowForUserScripts = 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
506 ;
507 ; You can also prevent all user script outgoing calls with the following override in OpenSim.ini
508 ;
509 ; OutboundDisallowForUserScripts = 0.0.0.0/0
510 ;
511 ; You can also disable the blacklist entirely with an empty entry
512 ;
513 ; OutboundDisallowForUserScripts = ""
514
495 ; What is reported as the "X-Secondlife-Shard" 515 ; What is reported as the "X-Secondlife-Shard"
496 ; Defaults to the user server url if not set 516 ; Defaults to the user server url if not set
497 ; The old default is "OpenSim", set here for compatibility 517 ; The old default is "OpenSim", set here for compatibility
diff --git a/prebuild.xml b/prebuild.xml
index 771b7c7..a0b33b6 100644
--- a/prebuild.xml
+++ b/prebuild.xml
@@ -593,6 +593,7 @@
593 593
594 <ReferencePath>../../../bin/</ReferencePath> 594 <ReferencePath>../../../bin/</ReferencePath>
595 <Reference name="System"/> 595 <Reference name="System"/>
596 <Reference name="System.Core"/>
596 <Reference name="System.Xml"/> 597 <Reference name="System.Xml"/>
597 <Reference name="System.Web"/> 598 <Reference name="System.Web"/>
598 <Reference name="OpenSim.Data"/> 599 <Reference name="OpenSim.Data"/>
@@ -607,6 +608,7 @@
607 <Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/> 608 <Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/>
608 <!-- FIXME: The OpenMetaverse.dll reference can be dropped when the TransferRequestPacket reference is removed from the code --> 609 <!-- FIXME: The OpenMetaverse.dll reference can be dropped when the TransferRequestPacket reference is removed from the code -->
609 <Reference name="OpenMetaverse" path="../../../bin/"/> 610 <Reference name="OpenMetaverse" path="../../../bin/"/>
611 <Reference name="LukeSkywalker.IPNetwork" path="../../../bin/"/>
610 <Reference name="Nini" path="../../../bin/"/> 612 <Reference name="Nini" path="../../../bin/"/>
611 <Reference name="XMLRPC" path="../../../bin/"/> 613 <Reference name="XMLRPC" path="../../../bin/"/>
612 <Reference name="log4net" path="../../../bin/"/> 614 <Reference name="log4net" path="../../../bin/"/>