我正在开发UWP VPN插件。在稍后阶段,它应该处理OpenVPN。在第一步中,我试图了解VpnPlugin,以使其以最简单的方式工作。为了进行测试,我在Debian VM(https://android.googlesource.com/platform/development/+/master/samples/ToyVpn/server/linux)上使用了Android的ToyVpn测试服务器。不幸的是,VpnPlugin的性能很差,文档记录很烂,没有指南-没有。 Github示例是无用的,也不起作用,即使https://github.com/ysc3839/UWPToyVpn也仅给出粗糙的方向。我能够与响应参数链的服务器成功地进行握手。当开始连接时,会引发一个异常,即设备未连接。我用完了Option,我们将不胜感激。
公共密封类ToyVpnPlugin:IVpnPlugIn
{
DatagramSocket _datagramSocket;
公共异步无效连接(VpnChannel通道)
{
// string参数=默认值;
字符串serverPort =“ 8000”;
字符串secret =“ test”;
_datagramSocket = new DatagramSocket();
_datagramSocket.MessageReceived += (s, e) =>
{
DataReader dataReader = e.GetDataReader();
if (dataReader.UnconsumedBufferLength > 0 && dataReader.ReadByte() == 0)
{
var parameters = dataReader.ReadString(dataReader.UnconsumedBufferLength);
ConfigureAndConnect(channel, parameters);
}
};
var serverHostName = channel.Configuration.ServerHostNameList[0];
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(channel.Configuration.CustomField);
var firstChild = xmlDocument.FirstChild;
if (firstChild.Name.Equals("ToyVpnConfig"))
{
foreach (XmlNode childNode in firstChild.ChildNodes)
{
if (childNode.Name.Equals("ServerPort")) serverPort = childNode.InnerText;
else if (childNode.Name.Equals("Secret")) secret = childNode.InnerText;
}
}
await _datagramSocket.ConnectAsync(serverHostName, serverPort);
await HandShake(_datagramSocket, secret);
}
public void Disconnect(VpnChannel channel)
{
channel.Stop();
}
public void GetKeepAlivePayload(VpnChannel channel, out VpnPacketBuffer keepAlivePacket)
{
keepAlivePacket = null;
}
public void Encapsulate(VpnChannel channel, VpnPacketBufferList packets, VpnPacketBufferList encapulatedPackets)
{
while (packets.Size > 0)
{
VpnPacketBuffer vpnPacketBuffer = packets.RemoveAtBegin();
var buffer = vpnPacketBuffer.Buffer;
VpnPacketBufferStatus vpnPacketBufferStatus = vpnPacketBuffer.Status;
encapulatedPackets.Append(vpnPacketBuffer);
}
}
public void Decapsulate(VpnChannel channel, VpnPacketBuffer encapBuffer, VpnPacketBufferList decapsulatedPackets, VpnPacketBufferList controlPacketsToSend)
{
while (encapBuffer != null)
{
decapsulatedPackets.Append(encapBuffer);
}
}
async Task HandShake(DatagramSocket datagramSocket, string secret)
{
for (int i = 0; i < 3; i++)
{
var dataWriter = new DataWriter(datagramSocket.OutputStream)
{
UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8
};
dataWriter.WriteByte(0);
dataWriter.WriteString(secret);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
}
void ConfigureAndConnect(VpnChannel vpnChannel, string parameters)
{
parameters = parameters.TrimEnd();
uint mtu = 1500;
List<HostName> ipv4InclusionHostNames = new List<HostName>();
List<HostName> dnsServerHostNames = new List<HostName>();
VpnRouteAssignment vpnRouteAssignment = new VpnRouteAssignment();
var ipv4InclusionRoutes = vpnRouteAssignment.Ipv4InclusionRoutes;
foreach (var parameter in parameters.Split(null))
{
var fields = parameter.Split(",");
try
{
switch (fields[0])
{
case "m":
mtu = uint.Parse(fields[1]);
break;
case "a":
ipv4InclusionHostNames.Add(new HostName(fields[1]));
break;
case "r":
ipv4InclusionRoutes.Add(new VpnRoute(new HostName(fields[1]), (byte)uint.Parse(fields[2])));
break;
case "d":
dnsServerHostNames.Add(new HostName(fields[1]));
break;
case "s":
//TODO "SearchDomain"
break;
default:
break;
}
}
catch (Exception)
{
throw;
}
}
VpnDomainNameAssignment vpnDomainNameAssignment = new VpnDomainNameAssignment();
vpnDomainNameAssignment.DomainNameList.Add(new VpnDomainNameInfo(".", VpnDomainNameType.Suffix, dnsServerHostNames, null));
try
{
vpnChannel.AssociateTransport(_datagramSocket, null);
vpnChannel.StartExistingTransports(ipv4InclusionHostNames, null, null, vpnRouteAssignment, vpnDomainNameAssignment, mtu, 65535, false);
}
catch (Exception e)
{
vpnChannel.TerminateConnection(e.Message);
}
}
}
答案 0 :(得分:0)
这似乎尚未得到证实,任何更好的想法或建议都会受到赞赏,因为我通过或多或少的“钓鱼”发现了这一点……
namespace Background
{
public enum HandshakeState { Waiting, Received, Canceled };
public sealed class SecurepointVpnPlugin : IVpnPlugIn
{
DatagramSocket _datagramSocket;
HandshakeState _handshakeState;
public void Connect(VpnChannel channel)
{
string serverPort = "8000";
string secret = "test";
string parameters = null;
_datagramSocket = new DatagramSocket();
channel.AssociateTransport(_datagramSocket, null);
_datagramSocket.MessageReceived += (s, e) =>
{
DataReader dataReader = e.GetDataReader();
if (dataReader.UnconsumedBufferLength > 0 && dataReader.ReadByte() == 0)
{
parameters = dataReader.ReadString(dataReader.UnconsumedBufferLength);
_handshakeState = HandshakeState.Received;
}
};
var serverHostName = channel.Configuration.ServerHostNameList[0];
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.LoadXml(channel.Configuration.CustomField);
var firstChild = xmlDocument.FirstChild;
if (firstChild.Name.Equals("ToyVpnConfig"))
{
foreach (XmlNode childNode in firstChild.ChildNodes)
{
if (childNode.Name.Equals("ServerPort")) serverPort = childNode.InnerText;
else if (childNode.Name.Equals("Secret")) secret = childNode.InnerText;
}
}
_datagramSocket.ConnectAsync(serverHostName, serverPort).AsTask().GetAwaiter().GetResult();
_handshakeState = HandshakeState.Waiting;
HandShake(_datagramSocket, secret).AsTask().GetAwaiter().GetResult();
if (_handshakeState == HandshakeState.Received) ConfigureAndConnect(channel, parameters);
else channel.Stop();
}
public void Disconnect(VpnChannel channel)
{
channel.Stop();
}
public void GetKeepAlivePayload(VpnChannel channel, out VpnPacketBuffer keepAlivePacket)
{
keepAlivePacket = null;
}
public void Encapsulate(VpnChannel channel, VpnPacketBufferList packets, VpnPacketBufferList encapulatedPackets)
{
while (packets.Size > 0) encapulatedPackets.Append(packets.RemoveAtBegin());
}
public void Decapsulate(VpnChannel channel, VpnPacketBuffer encapBuffer, VpnPacketBufferList decapsulatedPackets, VpnPacketBufferList controlPacketsToSend)
{
decapsulatedPackets.Append(encapBuffer);
}
IAsyncAction HandShake(DatagramSocket datagramSocket, string secret)
{
return Task.Run(async () =>
{
for (int i = 0; i < 3; i++)
{
var dataWriter = new DataWriter(datagramSocket.OutputStream)
{
UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8
};
dataWriter.WriteByte(0);
dataWriter.WriteString(secret);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
for (int i = 0; i < 50; i++)
{
await Task.Delay(100);
switch (_handshakeState)
{
case HandshakeState.Waiting:
break;
case HandshakeState.Received:
return;
case HandshakeState.Canceled:
throw new OperationCanceledException();
default:
break;
}
}
}).AsAsyncAction();
}
void ConfigureAndConnect(VpnChannel vpnChannel, string parameters)
{
parameters = parameters.TrimEnd();
uint mtuSize = 68;
var assignedClientIPv4list = new List<HostName>();
var dnsServerList = new List<HostName>();
VpnRouteAssignment assignedRoutes = new VpnRouteAssignment();
VpnDomainNameAssignment assignedDomainName = new VpnDomainNameAssignment();
var ipv4InclusionRoutes = assignedRoutes.Ipv4InclusionRoutes;
foreach (var parameter in parameters.Split(null))
{
var fields = parameter.Split(",");
switch (fields[0])
{
case "m":
mtuSize = uint.Parse(fields[1]);
break;
case "a":
assignedClientIPv4list.Add(new HostName(fields[1]));
break;
case "r":
ipv4InclusionRoutes.Add(new VpnRoute(new HostName(fields[1]), (byte)(int.Parse(fields[2]))));
break;
case "d":
dnsServerList.Add(new HostName(fields[1]));
break;
default:
break;
}
}
assignedRoutes.Ipv4InclusionRoutes = ipv4InclusionRoutes;
assignedDomainName.DomainNameList.Add(new VpnDomainNameInfo(".", VpnDomainNameType.Suffix, dnsServerList, null));
try
{
vpnChannel.StartExistingTransports(assignedClientIPv4list, null, null, assignedRoutes, assignedDomainName, mtuSize, mtuSize + 18, false);
}
catch (Exception e)
{
vpnChannel.TerminateConnection(e.Message);
}
}
}
}