2019-07-19 16:46

WCF IP Filter

  1. <!-- Web.config --> 
  2. <system.serviceModel> 
  3.  <extensions> 
  4.    <behaviorExtensions> 
  5.      <add name="ipFilter" type="XXX.XXX.IpFilterElement, XXX.XXX" /> 
  6.    </behaviorExtensions> 
  7.  </extensions> 
  8.  
  9.  <!-- .... --> 
  10.  
  11.  <behaviors> 
  12.    <serviceBehaviors> 
  13.      <behavior> 
  14.        <serviceMetadata httpGetEnabled="true" httpsGetEnabled="true" /> 
  15.        <serviceDebug includeExceptionDetailInFaults="true" /> 
  16.        <ipFilter allow="192.168.1.0/24, 127.0.0.1" /> 
  17.      </behavior> 
  18.    </serviceBehaviors> 
  19.  </behaviors> 
  20. </system.serviceModel> 

  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Collections.ObjectModel; 
  4. using System.Configuration; 
  5. using System.Linq; 
  6. using System.Net; 
  7. using System.Net.Sockets; 
  8. using System.Runtime.Serialization; 
  9. using System.Security.Authentication; 
  10. using System.ServiceModel; 
  11. using System.ServiceModel.Channels; 
  12. using System.ServiceModel.Configuration; 
  13. using System.ServiceModel.Description; 
  14. using System.ServiceModel.Dispatcher; 
  15. using JustWin.API.Extensions; 
  16.  
  17.  
  18. public class IpFilterElement : BehaviorExtensionElement 
  19. { 
  20.    [ConfigurationProperty("allow", IsRequired = true)] 
  21.    public virtual string Allow 
  22.    { 
  23.        get { return this["allow"] as string; } 
  24.        set { this["allow"] = value; } 
  25.    } 
  26.  
  27.    public override Type BehaviorType 
  28.    { 
  29.        get { return typeof(IpFilterBehaviour); } 
  30.    } 
  31.  
  32.    protected override object CreateBehavior() 
  33.    { 
  34.        return new IpFilterBehaviour(Allow); 
  35.    } 
  36. } 
  37.  
  38.  
  39.  
  40.  
  41. public class IpFilterBehaviour : IDispatchMessageInspector, IServiceBehavior 
  42. { 
  43.    private readonly List<IPAddressRange> _allowList; 
  44.  
  45.    public IpFilterBehaviour(string allow) 
  46.    { 
  47.        _allowList = allow.Split(',').Select(x => new IPAddressRange(x)).ToList(); 
  48.    } 
  49.  
  50.  
  51.    void IServiceBehavior.Validate(ServiceDescription service, ServiceHostBase host) 
  52.    { 
  53.    } 
  54.  
  55.    void IServiceBehavior.AddBindingParameters(ServiceDescription service, ServiceHostBase host, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters) 
  56.    { 
  57.    } 
  58.  
  59.    void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription service, ServiceHostBase host) 
  60.    { 
  61.        foreach (ChannelDispatcher dispatcher in host.ChannelDispatchers) 
  62.        foreach (EndpointDispatcher endpoint in dispatcher.Endpoints) 
  63.        { 
  64.            endpoint.DispatchRuntime.MessageInspectors.Add(this); 
  65.        } 
  66.    } 
  67.  
  68.  
  69.  
  70.    object IDispatchMessageInspector.AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 
  71.    { 
  72.        var remoteEndpoint = request.Properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty; 
  73.  
  74.        var address = IPAddress.Parse(remoteEndpoint.Address); 
  75.        if(_allowList.Any(x => x.IsMatch(address))) { return null; } 
  76.  
  77.        request = null; 
  78.        return new AuthenticationException($"IP address ({remoteEndpoint.Address}) is not allowed."); 
  79.    } 
  80.  
  81.  
  82.    void IDispatchMessageInspector.BeforeSendReply(ref Message reply, object correlationState) 
  83.    { 
  84.        var ex = correlationState as Exception; 
  85.        if (ex == null) { return; } 
  86.  
  87.        MessageFault messageFault = MessageFault.CreateFault( 
  88.            new FaultCode("Sender"), 
  89.            new FaultReason(ex.Message), 
  90.            ex, 
  91.            new NetDataContractSerializer() 
  92.        ); 
  93.  
  94.        reply = Message.CreateMessage(reply.Version, messageFault, null); 
  95.    } 
  96.  
  97. } 
  98.  
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105. public class IPAddressRange 
  106. { 
  107.    private readonly byte[] _rangeAddress; 
  108.    private readonly byte[] _rangeMask; 
  109.  
  110.    public IPAddressRange(string ipAndMask) 
  111.    { 
  112.        string[] split = (ipAndMask + "/128").Split('/'); 
  113.  
  114.        var ip = IPAddress.Parse(split[0].Trim()); 
  115.  
  116.        int maskLength = int.Parse(split[1].Trim()); 
  117.        if (ip.AddressFamily == AddressFamily.InterNetwork) { maskLength += 96; } 
  118.  
  119.        _rangeMask = createMask(maskLength); 
  120.  
  121.        _rangeAddress = ip.MapToIPv6().GetAddressBytes() 
  122.            .Select((x, i) => x & _rangeMask[i]) 
  123.            .Select(x => (byte)x) 
  124.            .ToArray(); 
  125.    } 
  126.  
  127.  
  128.    public bool IsMatch(IPAddress ip) 
  129.    { 
  130.        byte[] address = ip.MapToIPv6().GetAddressBytes(); 
  131.  
  132.        for (int i = 0; i < 16; i++) 
  133.        { 
  134.            if ((address[i] & _rangeMask[i]) != _rangeAddress[i]) { return false; } 
  135.        } 
  136.  
  137.        return true; 
  138.    } 
  139.  
  140.  
  141.  
  142.    private byte[] createMask(int length) 
  143.    { 
  144.        var mask = new byte[16]; 
  145.  
  146.        for (int i = 0; i < 16; i++) 
  147.        { 
  148.            mask[i] = 0xff; 
  149.            if (length > -8) { length -= 8; } 
  150.            if (length < 0) { mask[i] = (byte)(mask[i] << -length); } 
  151.        } 
  152.        return mask; 
  153.    } 
  154. } 

0 回應: