【问题标题】:Windows 10 UWP VpnPlugin Connection FailuresWindows 10 UWP VpnPlugin 连接失败
【发布时间】:2019-05-06 17:17:35
【问题描述】:

我正在开发一个 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 也只给出了粗略的方向。我能够成功地与使用参数链响应的服务器进行握手。启动Connection时,抛出设备未连接的异常。我的选项快用完了,任何帮助都将不胜感激。

公共密封类 ToyVpnPlugin : IVpnPlugIn { 数据报套接字_datagramSocket; 公共异步无效连接(VpnChannel 通道) {
//字符串参数=默认值; 字符串服务器端口 = “8000”; 字符串秘密 = “测试”;

        _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);
        }
    }
}

【问题讨论】:

  • 我会尝试看看是否可以让某人参与这个问题。
  • 谢谢巴里...与此同时,我能够弄清楚为什么我总是丢失设备。异步和任务的东西有问题。我对 Handshake 进行了一些更改:IAsyncAction HandShake(... 并以 AsyncAction 的形式返回了一个任务。然后使用 .AsTask().GetAwaiter().GetResult(); 调用 Handshake 有很多文档和指南留给 Microsoft没有任何信息如何在第一个视图“简单 api”上正确处理。
  • +1 几乎完全缺乏文档。我正在努力让 VPNClient 也能正常工作,并且已经碰到了这里提到的许多相同的墙壁。 SO上有几篇讨论这个话题的帖子。你愿意将你的代码发布到 github 上以便其他人可以从你的辛勤工作中受益吗?我有兴趣试一试
  • 当然,给我一些时间准备一个测试项目并上传到 Github。我会及时通知你...
  • 在这里找到它:github.com/marcusrunge/ToyVpn(有时间我会写几行文档)

标签: c# uwp vpn


【解决方案1】:

这似乎是未经证实的工作,任何更好的想法或建议都非常感谢,因为我或多或少地通过“钓鱼”来解决这个问题......:

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);
        }
    }
}

}

【讨论】:

  • 它不工作,它只是连接,甚至没有一个字节到达服务器
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-31
  • 2018-09-21
  • 2016-07-04
  • 2017-05-13
  • 2020-09-14
  • 2017-03-26
  • 1970-01-01
相关资源
最近更新 更多