C#通过DotRas实现完美控制VPN和PPPoE(ADSL)

作者: 小古 分类: C# NET技术 发布时间: 2016-11-26 ė8845 次浏览 61 条评论

使用DotRas实现对VPN和PPPoE(ADSL)完美管理和控制

支持增、删、改、查、拨号(连接)、断开、查询实时连接状态、查询IP

完全基于Windows的RAS API操作,功能和效率并非百度到的那些使用CMD进行操作的例子可比的!!

 

无论VPN、PPPoE(ADSL)还是其他神马的拨号连接其实都是基于RAS的,DotRas就是基于Windows原生RAS API包装翻译成C#的库,有兴趣的童鞋可以自己研究研究

DotRas有多个版本,几乎每个不同Win大版本都有对应的RasAPI版本,为了最好的兼容新旧平台使用的是以WinXP API为基础编译的版本。也就是不兼容XP以下的系统,我想应该没谁还在用XP以下版本系统!

DotRas的库和源码可以到他的官网下载,为了方便某些上外网有问题滴童鞋本文在末尾会提供DotRas V1.3的源码

DotRas官网:http://dotras.codeplex.com/

 

为了防止某些童鞋实在弄不懂怎么用这几个类,特意做了个Demo

为了写这个Demo,可是耗费了我2个多小时........

 不过Demo就是Demo,自然会有点BUG(影响不大),我也懒的修复了,反正童鞋们能看懂就行

对了对了,这Demo还加上的自动添加静态路由功能!!相关的静态路由管理类嘛,我会在下篇博文里发出来,或者各位童鞋可以直接到文尾下载Demo看

 

废话不说,直接看代码

 

RAS管理器基类

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using DotRas;

namespace RBTI.Toolbox.RasConnect.Ras
{
    abstract class RasManager : IEnumerable<RasEntry>
    {
        /// <summary>
        /// 所有活动Ras连接
        /// </summary>
        public static IEnumerable<RasConnection> AllActiveRasConnections
        {
            get
            {
                return RasConnection.GetActiveConnections();
            }
        }

        protected RasDeviceType DeciceType { get; private set; }

        /// <summary>
        /// 所有活动连接
        /// </summary>
        public IEnumerable<RasConnection> AllActiveConnections
        {
            get
            {
                return RasConnection.GetActiveConnections().Where(c => c.Device.DeviceType == DeciceType);
            }
        }

        /// <summary>
        /// 电话簿路径
        /// </summary>
        public string PhoneBookPath { get; private set; }

        /// <summary>
        /// 活动连接
        /// </summary>
        public IEnumerable<RasConnection> ActiveConnections
        {
            get
            {
                RasPhoneBook usersPhoneBook = new RasPhoneBook();
                usersPhoneBook.Open(PhoneBookPath);
                return RasConnection.GetActiveConnections().Where(c => c.Device.DeviceType == DeciceType && usersPhoneBook.Entries.Contains(c.EntryName));
            }
        }

        /// <summary>
        /// 获取实体
        /// </summary>
        /// <param name="name">实体名称</param>
        /// <returns></returns>
        public RasEntry this[string name]
        {
            get
            {
                RasPhoneBook usersPhoneBook = new RasPhoneBook();
                usersPhoneBook.Open(PhoneBookPath);
                return usersPhoneBook.Entries[name];
            }
        }

        /// <summary>
        /// Ras管理器
        /// </summary>
        /// <param name="phoneBookPath">电话簿路径</param>
        public RasManager(string phoneBookPath, RasDeviceType deciceType)
        {
            PhoneBookPath = phoneBookPath;
            DeciceType = deciceType;
        }

        /// <summary>
        /// 设置DNS地址(设置首选和备用地址都为0.0.0.0时是自动获取)
        /// </summary>
        /// <param name="name">实体名称</param>
        /// <param name="dnsAddress">首选DNS地址</param>
        /// <param name="dnsAddressAlt">备用DNS地址</param>
        public void SettingDns(string name, IPAddress dnsAddress, IPAddress dnsAddressAlt)
        {
            RasPhoneBook usersPhoneBook = new RasPhoneBook();
            usersPhoneBook.Open(PhoneBookPath);
            if (!usersPhoneBook.Entries.Contains(name))
                return;
            RasEntry entry = usersPhoneBook.Entries[name];
            entry.DnsAddress = dnsAddress;
            entry.DnsAddressAlt = dnsAddressAlt;
            entry.Update();
        }

        /// <summary>
        /// 设置IP地址(设置为0.0.0.0时是自动获取)
        /// </summary>
        /// <param name="name">实体名称</param>
        /// <param name="ipAddress">IP地址</param>
        public void SettingIp(string name, IPAddress ipAddress)
        {
            RasPhoneBook usersPhoneBook = new RasPhoneBook();
            usersPhoneBook.Open(PhoneBookPath);
            if (!usersPhoneBook.Entries.Contains(name))
                return;
            RasEntry entry = usersPhoneBook.Entries[name];
            entry.IPAddress = ipAddress;
            entry.Update();
        }

        /// <summary>
        /// 设置验证信息(设置为null时是清空已保存的验证信息)
        /// </summary>
        /// <param name="name">实体名称</param>
        /// <param name="credentials">身份信息</param>
        public void SettingCredentials(string name, NetworkCredential credentials)
        {
            RasPhoneBook usersPhoneBook = new RasPhoneBook();
            usersPhoneBook.Open(PhoneBookPath);
            if (!usersPhoneBook.Entries.Contains(name))
                return;
            RasEntry entry = usersPhoneBook.Entries[name];
            if (credentials == null)
                entry.ClearCredentials();
            else
                entry.UpdateCredentials(credentials);
        }

        /// <summary>
        /// 设置是否为默认网关
        /// </summary>
        /// <param name="name">实体名称</param>
        /// <param name="remoteDefaultGateway">是否为默认网关</param>
        public void SettingRemoteDefaultGateway(string name, bool remoteDefaultGateway)
        {
            RasPhoneBook usersPhoneBook = new RasPhoneBook();
            usersPhoneBook.Open(PhoneBookPath);
            if (!usersPhoneBook.Entries.Contains(name))
                return;
            RasEntry entry = usersPhoneBook.Entries[name];
            entry.Options.RemoteDefaultGateway = remoteDefaultGateway;
            entry.Update();
        }

        /// <summary>
        /// 删除
        /// 在连接过程中删除不会自动断开,请先执行断开操作
        /// </summary>
        /// <param name="name">实体名称</param>
        public void Remove(string name)
        {
            RasPhoneBook usersPhoneBook = new RasPhoneBook();
            usersPhoneBook.Open(PhoneBookPath);
            if (usersPhoneBook.Entries.Contains(name))
                usersPhoneBook.Entries.Remove(name);
        }

        public IEnumerator<RasEntry> GetEnumerator()
        {
            RasPhoneBook usersPhoneBook = new RasPhoneBook();
            usersPhoneBook.Open(PhoneBookPath);
            return usersPhoneBook.Entries.Where(c => c.Device.DeviceType == DeciceType).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            RasPhoneBook usersPhoneBook = new RasPhoneBook();
            usersPhoneBook.Open(PhoneBookPath);
            return usersPhoneBook.Entries.Where(c => c.Device.DeviceType == DeciceType).GetEnumerator();
        }
    }
}

 

VPN管理器类

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using DotRas;

namespace RBTI.Toolbox.RasConnect.Ras
{
    class VpnManager : RasManager
    {
        /// <summary>
        /// VPN管理器
        /// </summary>
        /// <param name="phoneBookPath">电话簿路径</param>
        public VpnManager(string phoneBookPath) : base(phoneBookPath, RasDeviceType.Vpn)
        {
        }

        /// <summary>
        /// VPN管理器
        /// </summary>
        /// <param name="phoneBookType">电话簿类型</param>
        public VpnManager(RasPhoneBookType phoneBookType) : this(RasPhoneBook.GetPhoneBookPath(phoneBookType))
        {
        }

        /// <summary>
        /// VPN管理器
        /// 打开全局用户电话簿
        /// </summary>
        public VpnManager() : this(RasPhoneBookType.AllUsers)
        {
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="name">实体名称</param>
        /// <param name="serverAddress">服务器地址</param>
        /// <param name="remoteDefaultGateway">是否使用默认网关</param>
        /// <returns></returns>
        public RasEntry Add(string name, string serverAddress, bool remoteDefaultGateway)
        {
            RasPhoneBook usersPhoneBook = new RasPhoneBook();
            usersPhoneBook.Open(PhoneBookPath);
            RasEntry entry = RasEntry.CreateVpnEntry(
                name,
                serverAddress,
                RasVpnStrategy.Default,
                RasDevice.GetDevices().First(o => o.DeviceType == RasDeviceType.Vpn));
            entry.Options.RequireMSChap2 = true;
            entry.Options.RemoteDefaultGateway = remoteDefaultGateway;
            usersPhoneBook.Entries.Add(entry);
            return entry;
        }

        /// <summary>
        /// 更改
        /// </summary>
        /// <param name="name">实体名称</param>
        /// <param name="serverAddress">服务器地址</param>
        /// <param name="remoteDefaultGateway">是否使用默认网关</param>
        public void Update(string name, string serverAddress, bool remoteDefaultGateway)
        {
            RasPhoneBook usersPhoneBook = new RasPhoneBook();
            usersPhoneBook.Open(PhoneBookPath);
            if (!usersPhoneBook.Entries.Contains(name))
                return;
            RasEntry entry = usersPhoneBook.Entries[name];
            entry.PhoneNumber = serverAddress;
            entry.Options.RequireMSChap2 = true;
            entry.Options.RemoteDefaultGateway = remoteDefaultGateway;
            entry.Update();
        }
    }
}

 

拨号宽[PPPoE(ADSL)]管理器类

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using DotRas;

namespace RBTI.Toolbox.RasConnect.Ras
{
    class BroadbandManager : RasManager
    {
        /// <summary>
        /// PPPoE管理器
        /// </summary>
        /// <param name="phoneBookPath">电话簿路径</param>
        public BroadbandManager(string phoneBookPath) : base(phoneBookPath, RasDeviceType.PPPoE)
        {

        }

        /// <summary>
        /// PPPoE管理器
        /// </summary>
        /// <param name="phoneBookType">电话簿类型</param>
        public BroadbandManager(RasPhoneBookType phoneBookType) : this(RasPhoneBook.GetPhoneBookPath(phoneBookType))
        {
        }

        /// <summary>
        /// PPPoE管理器
        /// 打开全局用户电话簿
        /// </summary>
        public BroadbandManager() : this(RasPhoneBookType.AllUsers)
        {
        }

        /// <summary>
        /// 添加宽带
        /// </summary>
        /// <param name="name">宽带名称</param>
        /// <param name="remoteDefaultGateway">是否使用默认网关</param>
        /// <returns></returns>
        public RasEntry Add(string name,bool remoteDefaultGateway = true)
        {
            RasPhoneBook usersPhoneBook = new RasPhoneBook();
            usersPhoneBook.Open(PhoneBookPath);
            RasEntry entry = RasEntry.CreateBroadbandEntry(name, RasDevice.GetDevices().First(o => o.DeviceType == RasDeviceType.PPPoE), remoteDefaultGateway);
            usersPhoneBook.Entries.Add(entry);
            return entry;
        }
    }
}

 

RAS拨号连接类

为了程序结构清晰,拨号连接特意分开一个类

这个类支持对连接状态进行实时检测,包括断线检测

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Net;
using System.Timers;
using DotRas;

namespace RBTI.Toolbox.RasConnect.Ras
{
    class RasDialConnection
    {
        #region 字段
        private RasDialer dialer;
        private RasHandle rasHandle;
        private RasConnection connection;
        private RasConnectionState state;
        private Timer timer;
        #endregion

        #region 事件
        /// <summary>
        /// 拨号完成事件
        /// </summary>
        public event EventHandler<DialCompletedEventArgs> DialCompleted;

        /// <summary>
        /// 状态修改事件
        /// </summary>
        public event EventHandler<StateChangedEventArgs> StateChanged;
        #endregion

        #region 属性
        /// <summary>
        /// 是否可以发布事件
        /// 默认为True
        /// </summary>
        public bool CanRaiseEvents { get; set; }

        /// <summary>
        /// 同步对象
        /// </summary>
        public ISynchronizeInvoke SynchronizingObject { get; set; }

        /// <summary>
        /// 实体名称
        /// </summary>
        public string EntryName
        {
            get
            {
                return dialer.EntryName;
            }
        }

        /// <summary>
        /// IP地址
        /// </summary>
        public IPAddress IPAddress { get; private set; }

        /// <summary>
        /// 服务器IP地址
        /// </summary>
        public IPAddress ServerIPAddress { get; private set; }

        /// <summary>
        /// 实时状态
        /// </summary>
        public RasConnectionState State
        {
            get
            {
                if (rasHandle == null || rasHandle.IsInvalid || rasHandle.IsClosed)
                    return RasConnectionState.Disconnected;
                if (connection == null)
                    return state;
                else
                {
                    try { return connection.GetConnectionStatus().ConnectionState; }
                    catch (InvalidHandleException) { return RasConnectionState.Disconnected; }
                }
            }
        }
        #endregion

        /// <summary>
        /// Ras连接
        /// </summary>
        /// <param name="phoneBookPath">电话簿路径</param>
        /// <param name="entryName">实体名称</param>
        /// <param name="synchronizingObject">同步对象</param>
        public RasDialConnection(string phoneBookPath, string entryName, ISynchronizeInvoke synchronizingObject)
        {
            SynchronizingObject = synchronizingObject;

            CanRaiseEvents = true;

            timer = new Timer(100);
            timer.AutoReset = true;
            timer.Enabled = false;
            timer.Elapsed += Timer_Elapsed;

            dialer = new RasDialer();
            dialer.Credentials = null;
            dialer.EapOptions = new RasEapOptions(false, false, false);
            dialer.HangUpPollingInterval = 0;
            dialer.Options = new RasDialOptions(false, false, false, false, false, false, false, false, false, false);
            //dialer.SynchronizingObject = synchronizingObject;
            dialer.EntryName = entryName;
            dialer.PhoneBookPath = phoneBookPath;
            dialer.StateChanged += Dialer_StateChanged; ;
            dialer.DialCompleted += Dialer_DialCompleted;
        }

        /// <summary>
        /// Ras连接
        /// </summary>
        /// <param name="phoneBookType">电话簿类型</param>
        /// <param name="entryName">实体名称</param>
        /// <param name="synchronizingObject">同步对象</param>
        public RasDialConnection(RasPhoneBookType phoneBookType, string entryName, ISynchronizeInvoke synchronizingObject) :
            this(RasPhoneBook.GetPhoneBookPath(phoneBookType), entryName, synchronizingObject)
        {
        }

        /// <summary>
        /// Ras连接
        /// 使用全局用户电话簿
        /// </summary>
        /// <param name="entryName">实体名称</param>
        /// <param name="synchronizingObject"></param>
        public RasDialConnection(string entryName, ISynchronizeInvoke synchronizingObject) :
            this(RasPhoneBookType.AllUsers, entryName, synchronizingObject)
        {
        }

        /// <summary>
        /// Ras连接
        /// </summary>
        /// <param name="phoneBookPath">电话簿路径</param>
        /// <param name="entryName">实体名称</param>
        public RasDialConnection(string phoneBookPath, string entryName) : this(phoneBookPath, entryName, null)
        {
        }

        /// <summary>
        /// Ras连接
        /// </summary>
        /// <param name="phoneBookType">电话簿类型</param>
        /// <param name="entryName">实体名称</param>
        public RasDialConnection(RasPhoneBookType phoneBookType, string entryName) : this(phoneBookType, entryName, null)
        {
        }

        /// <summary>
        /// Ras连接
        /// 使用全局用户电话簿
        /// </summary>
        /// <param name="entryName">实体名称</param>
        public RasDialConnection(string entryName) : this(entryName, (ISynchronizeInvoke)null)
        {
        }

        protected void RaiseEvent<TEventArgs>(EventHandler<TEventArgs> method, TEventArgs e) where TEventArgs : EventArgs
        {
            if (method != null && this.CanRaiseEvents)
            {
                lock (method)
                {
                    if (SynchronizingObject != null && SynchronizingObject.InvokeRequired)
                    {
                        SynchronizingObject.Invoke(method, new object[] { this, e });
                    }
                    else
                    {
                        method(this, e);
                    }
                }
            }
        }

        private void Timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            timer.Enabled = false;
            if (State == RasConnectionState.Disconnected)
            {
                connection = null;
                rasHandle = null;
                IPAddress = null;
                ServerIPAddress = null;
                state = RasConnectionState.Disconnected;
                RaiseEvent(StateChanged, new StateChangedEventArgs(RasConnectionState.Disconnected));
            }
            else
                timer.Enabled = true;
        }

        private void Dialer_DialCompleted(object sender, DialCompletedEventArgs e)
        {
            var connections = RasConnection.GetActiveConnections();
            if (e.Connected && connections.Any(c => c.Handle == rasHandle))
            {
                connection = connections.First(c => c.Handle == rasHandle);
                RasIPInfo ipAddresses = (RasIPInfo)connection.GetProjectionInfo(RasProjectionType.IP);
                IPAddress = ipAddresses.IPAddress;
                ServerIPAddress = ipAddresses.ServerIPAddress;
                timer.Enabled = true;
            }
            
            RaiseEvent(DialCompleted, e);
        }

        private void Dialer_StateChanged(object sender, DotRas.StateChangedEventArgs e)
        {
            state = e.State;
            RaiseEvent(StateChanged, new StateChangedEventArgs(e.ErrorCode, e.ErrorMessage, e.ExtendedErrorCode, e.State));
        }

        /// <summary>
        /// 拨号
        /// </summary>
        /// <param name="userName">用户名</param>
        /// <param name="password">密码</param>
        public void Dial(string userName, string password)
        {
            state = RasConnectionState.Disconnected;
            dialer.Credentials = new NetworkCredential(userName, password);
            rasHandle = dialer.DialAsync();
        }

        /// <summary>
        /// 拨号
        /// 使用已保存的验证信息
        /// </summary>
        public void Dial()
        {
            RasPhoneBook usersPhoneBook = new RasPhoneBook();
            usersPhoneBook.Open(dialer.PhoneBookPath);
            var entry = usersPhoneBook.Entries[dialer.EntryName];
            var credentials = entry.GetCredentials();

            state = RasConnectionState.Disconnected;
            if (credentials != null)
                dialer.Credentials = credentials;
            rasHandle = dialer.DialAsync();
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        public void Disconnect()
        {
            if (State == RasConnectionState.Disconnected)
                return;
            try
            {
                timer.Enabled = false;
                if (dialer.IsBusy)
                {
                    dialer.DialAsyncCancel();
                }
                else
                {
                    if (connection != null)
                        connection.HangUp();
                    RaiseEvent(StateChanged, new StateChangedEventArgs(RasConnectionState.Disconnected));
                }
            }
            finally
            {
                connection = null;
                rasHandle = null;
                IPAddress = null;
                ServerIPAddress = null;
                state = RasConnectionState.Disconnected;
            }
        }
    }
}

 

连接状态改变事件参数类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DotRas;

namespace RBTI.Toolbox.RasConnect.Ras
{
    class StateChangedEventArgs : EventArgs
    {
        public RasConnectionState State { get; private set; }

        public int ErrorCode { get; private set; }
        public string ErrorMessage { get; private set; }
        public int ExtendedErrorCode { get; private set; }

        public StateChangedEventArgs(RasConnectionState state)
        {
            State = state;
        }

        public StateChangedEventArgs(int errorCode, string errorMessage, int extendedErrorCode, RasConnectionState state)
        {
            ErrorCode = ErrorCode = errorCode;
            ErrorMessage = errorMessage;
            ExtendedErrorCode = extendedErrorCode;
            State = state;
        }
    }
}

 

以上的代码童鞋们能看懂就直接用,看不懂就到下面下个Demo程序源码看看吧

 

DotRas V1.3 库源码:DotRas v1.3 Source.zip

Demo 源码(内有已编译程序可直接运行):RBTI.Toolbox.RasConnect.rar

本文出自 小古Blog,转载时请注明出处及相应链接。

本文永久链接: http://blog.chdz1.com/?post=253

|

1条评论

  1. 知球网 2017-05-26 23:36

    好复杂的说。。。。回复

发表评论:

电子邮件地址不会被公开。 必填项已用*标注

Ɣ回顶部
sitemap