-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
217978b
commit 08e600c
Showing
7 changed files
with
437 additions
and
0 deletions.
There are no files selected for viewing
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
using System; | ||
using System.Buffers; | ||
using System.Net; | ||
|
||
namespace SuperSocket.ProtoBase.ProxyProtocol | ||
{ | ||
public enum ProxyCommand | ||
{ | ||
/// <summary> | ||
/// the connection was established on purpose by the proxy | ||
/// without being relayed. The connection endpoints are the sender and the | ||
/// receiver. Such connections exist when the proxy sends health-checks to the | ||
/// server. The receiver must accept this connection as valid and must use the | ||
/// real connection endpoints and discard the protocol block including the | ||
/// family which is ignored. | ||
/// </summary> | ||
LOCAL, | ||
|
||
/// <summary> | ||
/// the connection was established on behalf of another node, | ||
/// and reflects the original connection endpoints. The receiver must then use | ||
/// the information provided in the protocol block to get original the address. | ||
/// </summary> | ||
PROXY | ||
} | ||
} |
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
using System; | ||
using System.Buffers; | ||
using System.Net; | ||
using System.Net.Sockets; | ||
|
||
namespace SuperSocket.ProtoBase.ProxyProtocol | ||
{ | ||
public class ProxyInfo | ||
{ | ||
public IPAddress SourceIPAddress { get; internal set; } | ||
|
||
public int SourcePort { get; internal set; } | ||
|
||
public IPAddress DestinationIPAddress { get; internal set; } | ||
|
||
public int DestinationPort { get; internal set; } | ||
|
||
public ProxyCommand Command { get; internal set; } | ||
|
||
public int Version { get; internal set; } | ||
|
||
public AddressFamily AddressFamily { get; internal set; } | ||
|
||
public ProtocolType ProtocolType { get; internal set; } | ||
|
||
internal int AddressLength { get; set; } | ||
|
||
public ProxyInfo() | ||
{ | ||
} | ||
} | ||
} |
22 changes: 22 additions & 0 deletions
22
src/SuperSocket.ProtoBase/ProxyProtocol/ProxyProtocolPackagePartReader.cs
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
using System; | ||
using System.Buffers; | ||
|
||
namespace SuperSocket.ProtoBase.ProxyProtocol | ||
{ | ||
abstract class ProxyProtocolPackagePartReader<TPackageInfo> : IPackagePartReader<TPackageInfo> | ||
{ | ||
static ProxyProtocolPackagePartReader() | ||
{ | ||
ProxyProtocolSwitch = new ProxyProtocolSwitchPartReader<TPackageInfo>(); | ||
ProxyProtocolV1Reader = new ProxyProtocolV1PartReader<TPackageInfo>(); | ||
} | ||
|
||
public abstract bool Process(TPackageInfo package, object filterContext, SequenceReader<byte> reader, out IPackagePartReader<TPackageInfo> nextPartReader, out bool needMoreData); | ||
|
||
internal static IPackagePartReader<TPackageInfo> ProxyProtocolSwitch { get; } | ||
|
||
internal static IPackagePartReader<TPackageInfo> ProxyProtocolV1Reader { get; } | ||
|
||
internal static IPackagePartReader<TPackageInfo> ProxyProtocolV2Reader { get; } | ||
} | ||
} |
49 changes: 49 additions & 0 deletions
49
src/SuperSocket.ProtoBase/ProxyProtocol/ProxyProtocolPipelineFilter.cs
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
using System; | ||
using System.Buffers; | ||
|
||
namespace SuperSocket.ProtoBase.ProxyProtocol | ||
{ | ||
public class ProxyProtocolPipelineFilter<TPackageInfo> : PackagePartsPipelineFilter<TPackageInfo> | ||
where TPackageInfo : class | ||
{ | ||
private readonly IPipelineFilter<TPackageInfo> _applicationPipelineFilter; | ||
|
||
private object _originalFilterContext; | ||
|
||
public ProxyInfo ProxyInfo { get; private set; } | ||
|
||
public ProxyProtocolPipelineFilter(IPipelineFilter<TPackageInfo> applicationPipelineFilter) | ||
{ | ||
_applicationPipelineFilter = applicationPipelineFilter; | ||
} | ||
|
||
protected override TPackageInfo CreatePackage() | ||
{ | ||
return default; | ||
} | ||
|
||
protected override IPackagePartReader<TPackageInfo> GetFirstPartReader() | ||
{ | ||
return ProxyProtocolPackagePartReader<TPackageInfo>.ProxyProtocolSwitch; | ||
} | ||
|
||
public override void Reset() | ||
{ | ||
// This method will be called when the proxy package handling finishes | ||
NextFilter = _applicationPipelineFilter; | ||
base.Reset(); | ||
Context = _originalFilterContext; | ||
} | ||
|
||
public override TPackageInfo Filter(SequenceReader<byte> reader) | ||
{ | ||
if (ProxyInfo == null) | ||
{ | ||
_originalFilterContext = Context; | ||
Context = ProxyInfo = new ProxyInfo(); | ||
} | ||
|
||
return base.Filter(reader); | ||
} | ||
} | ||
} |
85 changes: 85 additions & 0 deletions
85
src/SuperSocket.ProtoBase/ProxyProtocol/ProxyProtocolSwitchPartReader.cs
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
using System; | ||
using System.Buffers; | ||
using System.Text; | ||
|
||
namespace SuperSocket.ProtoBase.ProxyProtocol | ||
{ | ||
class ProxyProtocolSwitchPartReader<TPackageInfo> : ProxyProtocolPackagePartReader<TPackageInfo> | ||
{ | ||
private const int SWITCH_PART_SIZE = 12; | ||
|
||
private static readonly byte[] PROXYPROTOCOL_V2_SIGNATURE = new byte[] { 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A }; | ||
|
||
private static readonly byte[] PROXY_TAG = Encoding.ASCII.GetBytes("PROXY TCP"); | ||
|
||
public override bool Process(TPackageInfo package, object filterContext, SequenceReader<byte> reader, out IPackagePartReader<TPackageInfo> nextPartReader, out bool needMoreData) | ||
{ | ||
nextPartReader = null; | ||
|
||
if (reader.Length < SWITCH_PART_SIZE) | ||
{ | ||
needMoreData = true; | ||
return false; | ||
} | ||
|
||
needMoreData = false; | ||
|
||
if (reader.IsNext(PROXYPROTOCOL_V2_SIGNATURE, true)) | ||
{ | ||
nextPartReader = ProxyProtocolV2Reader; | ||
return false; | ||
} | ||
|
||
int read = 0; | ||
|
||
try | ||
{ | ||
if (TryReadProxyProtocolV1Tag(reader, out read)) | ||
{ | ||
nextPartReader = ProxyProtocolV1Reader; | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
finally | ||
{ | ||
if (read > 0) | ||
reader.Rewind(read); | ||
} | ||
} | ||
|
||
private bool TryReadProxyProtocolV1Tag(SequenceReader<byte> reader, out int read) | ||
{ | ||
read = 0; | ||
|
||
if (!reader.IsNext(PROXY_TAG, true)) | ||
{ | ||
return false; | ||
} | ||
|
||
read += PROXY_TAG.Length; | ||
|
||
if (!reader.TryRead(out var ver)) | ||
{ | ||
return false; | ||
} | ||
|
||
read++; | ||
|
||
if (ver != '4' && ver != '6') | ||
{ | ||
return false; | ||
} | ||
|
||
if (!reader.TryRead(out var space)) | ||
{ | ||
return false; | ||
} | ||
|
||
read++; | ||
|
||
return space == ' '; | ||
} | ||
} | ||
} |
102 changes: 102 additions & 0 deletions
102
src/SuperSocket.ProtoBase/ProxyProtocol/ProxyProtocolV1PartReader.cs
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
using System; | ||
using System.Buffers; | ||
using System.Collections; | ||
using System.Collections.Generic; | ||
using System.Net; | ||
using System.Text; | ||
using Microsoft.VisualBasic; | ||
|
||
namespace SuperSocket.ProtoBase.ProxyProtocol | ||
{ | ||
class ProxyProtocolV1PartReader<TPackageInfo> : ProxyProtocolPackagePartReader<TPackageInfo> | ||
{ | ||
private static readonly byte[] PROXY_DELIMITER = Encoding.ASCII.GetBytes("\r\n"); | ||
|
||
private static readonly IProxySgementProcessor[] PROXY_SEGMENT_PARSERS = new IProxySgementProcessor[] | ||
{ | ||
new SourceIPAddressProcessor(), | ||
new DestinationIPAddressProcessor(), | ||
new SourcePortProcessor(), | ||
new DestinationPortProcessor() | ||
}; | ||
|
||
public override bool Process(TPackageInfo package, object filterContext, SequenceReader<byte> reader, out IPackagePartReader<TPackageInfo> nextPartReader, out bool needMoreData) | ||
{ | ||
if (!reader.TryReadTo(out ReadOnlySequence<byte> proxyLineSequence, PROXY_DELIMITER, true)) | ||
{ | ||
needMoreData = true; | ||
nextPartReader = null; | ||
return false; | ||
} | ||
|
||
needMoreData = false; | ||
nextPartReader = null; | ||
|
||
var proxyLineReader = new SequenceReader<byte>(proxyLineSequence); | ||
|
||
var proxyLine = proxyLineReader.ReadString(); | ||
|
||
LoadProxyInfo(filterContext as ProxyInfo, proxyLine, 12, 13); | ||
|
||
return true; | ||
} | ||
|
||
private void LoadProxyInfo(ProxyInfo proxyInfo, string line, int startPos, int lookForOffet) | ||
{ | ||
var span = line.AsSpan(); | ||
var segmentIndex = 0; | ||
|
||
while (lookForOffet < line.Length) | ||
{ | ||
var spacePos = line.IndexOf(' ', lookForOffet); | ||
|
||
if (spacePos < 0) | ||
break; | ||
|
||
startPos = spacePos + 1; | ||
lookForOffet = startPos + 1; | ||
|
||
var segment = span.Slice(startPos, spacePos - startPos); | ||
|
||
PROXY_SEGMENT_PARSERS[segmentIndex++].Process(segment, proxyInfo); | ||
} | ||
} | ||
|
||
interface IProxySgementProcessor | ||
{ | ||
void Process(ReadOnlySpan<char> segment, ProxyInfo proxyInfo); | ||
} | ||
|
||
class SourceIPAddressProcessor : IProxySgementProcessor | ||
{ | ||
public void Process(ReadOnlySpan<char> segment, ProxyInfo proxyInfo) | ||
{ | ||
proxyInfo.SourceIPAddress = IPAddress.Parse(segment); | ||
} | ||
} | ||
|
||
class DestinationIPAddressProcessor : IProxySgementProcessor | ||
{ | ||
public void Process(ReadOnlySpan<char> segment, ProxyInfo proxyInfo) | ||
{ | ||
proxyInfo.DestinationIPAddress = IPAddress.Parse(segment); | ||
} | ||
} | ||
|
||
class SourcePortProcessor : IProxySgementProcessor | ||
{ | ||
public void Process(ReadOnlySpan<char> segment, ProxyInfo proxyInfo) | ||
{ | ||
proxyInfo.SourcePort = int.Parse(segment); | ||
} | ||
} | ||
|
||
class DestinationPortProcessor : IProxySgementProcessor | ||
{ | ||
public void Process(ReadOnlySpan<char> segment, ProxyInfo proxyInfo) | ||
{ | ||
proxyInfo.SourcePort = int.Parse(segment); | ||
} | ||
} | ||
} | ||
} |
Oops, something went wrong.