使用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 库源码: