Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions DotNetty.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
<s:String x:Key="/Default/CodeStyle/FileHeader/FileHeaderText/@EntryValue">Copyright (c) Microsoft. All rights reserved.&#xD;
Licensed under the MIT license. See LICENSE file in the project root for full license information.</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GC/@EntryIndexedValue">GC</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=IP/@EntryIndexedValue">IP</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/EventHandlerPatternLong/@EntryValue">$object$_On$event$</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=EnumMember/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
Expand Down
1 change: 1 addition & 0 deletions src/DotNetty.Common/DotNetty.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3' ">
<PackageReference Include="System.Diagnostics.Contracts" Version="4.3.0" />
<PackageReference Include="System.Net.NetworkInformation" Version="4.3.0" />
<PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
</ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'net45' ">
<Reference Include="System.Runtime" />
Expand Down
41 changes: 41 additions & 0 deletions src/DotNetty.Common/Internal/SocketUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace DotNetty.Common.Internal
{
using System.Net;
using System.Net.Sockets;

public class SocketUtils
{
public static IPAddress AddressByName(string hostname)
{
if (string.IsNullOrEmpty(hostname))
{
bool isIPv6Supported = Socket.OSSupportsIPv6;
if (isIPv6Supported)
{
return IPAddress.IPv6Loopback;
}
else
{
return IPAddress.Loopback;
}
}
if (hostname == "0.0.0.0")
{
return IPAddress.Any;
}
if (hostname == "::0" || hostname == "::")
{
return IPAddress.IPv6Any;
}
if (IPAddress.TryParse(hostname, out IPAddress parseResult))
{
return parseResult;
}
IPHostEntry hostEntry = Dns.GetHostEntryAsync(hostname).Result;
return hostEntry.AddressList[0];
}
}
}
103 changes: 103 additions & 0 deletions src/DotNetty.Handlers/IPFilter/AbstractRemoteAddressFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace DotNetty.Handlers.IPFilter
{
using System;
using System.Net;
using System.Threading.Tasks;
using DotNetty.Transport.Channels;

/// <summary>
/// This class provides the functionality to either accept or reject new <see cref="IChannel"/>s
/// based on their IP address.
/// You should inherit from this class if you would like to implement your own IP-based filter. Basically you have to
/// implement <see cref="Accept"/> to decided whether you want to accept or reject
/// a connection from the remote address.
/// Furthermore overriding <see cref="ChannelRejected"/> gives you the
/// flexibility to respond to rejected (denied) connections. If you do not want to send a response, just have it return
/// null. Take a look at <see cref="RuleBasedIPFilter"/> for details.
/// </summary>
public abstract class AbstractRemoteAddressFilter<T>: ChannelHandlerAdapter where T:EndPoint
{
public override void ChannelRegistered(IChannelHandlerContext ctx)
{
this.HandleNewChannel(ctx);
ctx.FireChannelRegistered();
}

public override void ChannelActive(IChannelHandlerContext ctx)
{
if (!this.HandleNewChannel(ctx))
{
throw new ArgumentException(nameof(ctx),"cannot determine to accept or reject a channel: " + ctx.Channel);
}
else
{
ctx.FireChannelActive();
}
}

bool HandleNewChannel(IChannelHandlerContext ctx)
{
var remoteAddress = (T)ctx.Channel.RemoteAddress;

// If the remote address is not available yet, defer the decision.
if (remoteAddress == null)
{
return false;
}

// No need to keep this handler in the pipeline anymore because the decision is going to be made now.
// Also, this will prevent the subsequent events from being handled by this handler.
ctx.Pipeline.Remove(this);
if (this.Accept(ctx, remoteAddress))
{
this.ChannelAccepted(ctx, remoteAddress);
}
else
{
Task rejectedTask = this.ChannelRejected(ctx, remoteAddress);
if (rejectedTask != null)
{
rejectedTask.ContinueWith(_ =>
{
ctx.CloseAsync();
});
}
else
{
ctx.CloseAsync();
}
}
return true;
}

/// <summary>
/// This method is called immediately after a <see cref="IChannel"/> gets registered.
/// </summary>
/// <returns>Return true if connections from this IP address and port should be accepted. False otherwise.</returns>
protected abstract bool Accept(IChannelHandlerContext ctx, T remoteAddress);

/// <summary>
/// This method is called if <paramref name="remoteAddress"/> gets accepted by
/// <see cref="Accept"/>. You should override it if you would like to handle
/// (e.g. respond to) accepted addresses.
/// </summary>
protected virtual void ChannelAccepted(IChannelHandlerContext ctx, T remoteAddress) { }


/// <summary>
/// This method is called if <paramref name="remoteAddress"/> gets rejected by
/// <see cref="Accept"/>. You should override it if you would like to handle
/// (e.g. respond to) rejected addresses.
/// <returns>
/// A <see cref="Task"/> if you perform I/O operations, so that
/// the <see cref="IChannel"/> can be closed once it completes. Null otherwise.
/// </returns>
/// </summary>
protected virtual Task ChannelRejected(IChannelHandlerContext ctx, T remoteAddress)
{
return null;
}
}
}
25 changes: 25 additions & 0 deletions src/DotNetty.Handlers/IPFilter/IIPFilterRule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace DotNetty.Handlers.IPFilter
{
using System.Net;

/// <summary>
/// Implement this interface to create new rules.
/// </summary>
public interface IIPFilterRule
{
/// <summary>
/// This method should return true if remoteAddress is valid according to your criteria. False otherwise.
/// </summary>
bool Matches(IPEndPoint remoteAddress);

/// <summary>
/// This method should return <see cref="IPFilterRuleType.Accept"/> if all
/// <see cref="Matches"/> for which <see cref="Matches"/>
/// returns true should the accepted. If you want to exclude all of those IP addresses then
/// <see cref="IPFilterRuleType.Reject"/> should be returned.
/// </summary>
IPFilterRuleType RuleType { get; }
}
}
14 changes: 14 additions & 0 deletions src/DotNetty.Handlers/IPFilter/IPFilterRuleType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

namespace DotNetty.Handlers.IPFilter
{
/// <summary>
/// Used in <see cref="IIPFilterRule"/> to decide if a matching IP Address should be allowed or denied to connect.
/// </summary>
public enum IPFilterRuleType
{
Accept,
Reject
}
}
Loading