Created
December 23, 2021 12:20
-
-
Save badeend/b5740b0d86388422e838d4f76cf9aa70 to your computer and use it in GitHub Desktop.
Domainname based firewall for WASI Sockets
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Net; | |
DemoWasiHost.main(); | |
// EXAMPLE: | |
class DemoWasiHost | |
{ | |
public static void main() | |
{ | |
// Set up networking capabilities: | |
var network = new NetworkingCapability( | |
new FirewallRule[] | |
{ | |
new("webassembly.org", 443), | |
new("smtp.example.com", 25), | |
} | |
); | |
// Run demo module: | |
DemoUntrustedWasiModule.main(network); | |
} | |
} | |
class DemoUntrustedWasiModule | |
{ | |
public static void main(NetworkingCapability network) | |
{ | |
// Example 1: | |
var ip1 = network.resolve_host("webassembly.org"); | |
var sock1 = network.open_socket(); | |
sock1.connect(ip1, 443); | |
// Example 2: (fails) | |
// var ip2 = IPAddress.Parse("104.21.85.250"); // Hardcoded IP of: webassembly.org | |
// var sock2 = network.open_socket(); | |
// sock2.connect(ip2, 443); // Error: notcapable | |
// Example 3: (fails) | |
// var ip3 = network.resolve_host("evil.com"); // Error: notcapable | |
Console.WriteLine("Done"); | |
} | |
} | |
// IMPLEMENTATION: | |
public record FirewallRule(string Host, int Port); | |
public class NetworkingCapability | |
{ | |
internal IReadOnlyList<FirewallRule> FirewallRules { get; } | |
internal Dictionary<IPAddress, HashSet<string>> AssociatedHostNamesByIp { get; } = new(); | |
internal NetworkingCapability(FirewallRule[] firewallRules) | |
{ | |
this.FirewallRules = firewallRules; | |
} | |
public IPAddress resolve_host(string hostName /* ... */) | |
{ | |
// Validate: | |
if (this.FirewallRules.Where(rule => rule.Host == hostName).Count() == 0) | |
{ | |
throw new Exception("notcapable: Capabilities insufficient."); | |
} | |
// Perform actual lookup: | |
var ipAddress = Dns.GetHostEntry(hostName).AddressList.First(); | |
// Store association: | |
this.AssociatedHostNamesByIp.GetOrAdd(ipAddress, _ => new()).Add(hostName); | |
return ipAddress; | |
} | |
public Socket open_socket(/* ... */) | |
{ | |
return new Socket(this); | |
} | |
} | |
public class Socket | |
{ | |
internal NetworkingCapability NetworkingCapability { get; } | |
internal Socket(NetworkingCapability networkingCapability) | |
{ | |
this.NetworkingCapability = networkingCapability; | |
} | |
public void connect(IPAddress host, int port) | |
{ | |
// Get known associated domain names with this IP: | |
var associatedHostNames = this.NetworkingCapability.AssociatedHostNamesByIp.GetValueOrDefault(host, new()); | |
if (associatedHostNames.Count == 0) | |
{ | |
throw new Exception("notcapable: Capabilities insufficient."); | |
} | |
// Check to see if any firewall rules allow this connection: | |
var matchingRules = this.NetworkingCapability.FirewallRules.Where(rule => associatedHostNames.Contains(rule.Host) && rule.Port == port); | |
if (matchingRules.Count() == 0) | |
{ | |
throw new Exception("notcapable: Capabilities insufficient."); | |
} | |
// Perform actual connection: | |
// NOT IMPLEMENTED | |
} | |
} | |
public static class Utils | |
{ | |
public static TValue GetOrAdd<TKey, TValue>(this IDictionary<TKey, TValue> dictionary, TKey key, Func<TKey, TValue> valueFactory) | |
{ | |
if (dictionary.TryGetValue(key, out var existingValue)) | |
{ | |
return existingValue; | |
} | |
var newValue = valueFactory(key); | |
dictionary.Add(key, newValue); | |
return newValue; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Project Sdk="Microsoft.NET.Sdk"> | |
<PropertyGroup> | |
<OutputType>Exe</OutputType> | |
<TargetFramework>net6.0</TargetFramework> | |
<ImplicitUsings>enable</ImplicitUsings> | |
<Nullable>enable</Nullable> | |
</PropertyGroup> | |
</Project> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment