RAS是Remote Access Service的缩写,意为:远程访问服务,主要用来配置企业的远程用户对企业内部网络访问,包括拨号访问和vpn方式。微软的所有Windows平台中都有RAS客户机,它允许我们将自己的计算机与另一个地方的远程计算机(其特色是一个远程访问服务器组件)相连,一般情况下, RAS客户机利用连接了电话线的一个调制解调器,通过拨号的方式呼叫远程计算机。服务器这方面,必须有一项等候DUN连接的服务,RAS客户机和服务器之间的连接建立之后,网络协议堆栈(与所用的分帧协议有关)就通过这个RAS连接,与远程计算机通信,就象通过LAN连接的一样。如今,许多调制解调器的数据通信速率明显比直接的LAN连接慢。RAS连接通过电话簿条目中可用的选项,经过验证后,RAS便可自动进入一台机器,登录到一个域。
VPN开发经常使用的API
RAS有四个函数,允许通过程序对电话簿RASENTRY结构进行管理。它们是:RasSet Entry、RasGetEntryProperties、RasRenameEntry和RasDeleteEntry。如要建立一个新条目或对一个现成的条目进行修改,可使用RasSetEntryProperties函数
RasGetEntryProperties 此函数检索并返回一个电话簿条目的属性
RasSetEntryProperties 修改或者创建一个电话本中的链接条目信息,通俗的说就是修改或创建一个VPN链接属性。
DWORD RasGetEntryProperties(
LPWSTR lpszPhoneBook,
LPWSTR szEntry,
LPRASENTRY lpbEntry,
LPDWORD lpdwEntrySize,
LPBYTE lpb,
LPDWORD lpdwSize
);
lpszPhoneBook:常被忽略并被设置为空值,电话薄条目存储在注册表中,而不是在电话本中。
szEntry:一个包含条目名称,空字符结尾字符串的指针。如果指定一个空字符串,该函数返回的默认值在lpbEntry 和 lpb 参数指向的缓冲区。
lpbEntry:指定新的连接数据,要与由 lpszEntry 参数指示的电话簿条目关联的 RASENTRY 结构的指针。
RasDeleteEntry
删除电话薄中条目,一般用来删除VPN连接
RasDial:拨号API
DWORD RasDial(
__in
LPRASDIALEXTENSIONS lpRasDialExtensions,
__in
LPCTSTR lpszPhonebook,
__in
LPRASDIALPARAMS lpRasDialParams,
__in
DWORD dwNotifierType,
__in
LPVOID lpvNotifier,
__in
LPHRASCONN lphRasConn
);
lpRasDialExtensions:参数是一个可选指针,指向一个RASDIALEXTENSIONS结构,有了
这个结构,你的应用程序便可使用RasDial函数的扩展特性了,
可忽略,设为NULL
pszPhonebook:用于识别到一个电话簿文件的路径。设为NULL,表示使用当前默认电话簿文件
lpRasDialParams:定义了拨号和用户身份验证参数
dwNotifierType,
lpvNotifier:可同步调用还是异步调用。
lphRasConn:
第一个参数lpRasDialExtensions
typedef struct
tagRASDIALEXTENSIONS {
DWORD
dwSize;
DWORD
dwfOptions;
HWND
hwndParent;
ULONG_PTR reserved;
#if (WINVER >=
0x500)
ULONG_PTR reserved1;
RASEAPINFO RasEapInfo;
#endif
} RASDIALEXTENSIONS
第三个参数lpRasDialParams
typedef struct
_RASDIALPARAMS {
DWORD
dwSize;
TCHAR
szEntryName[RAS_MaxEntryName + 1];
TCHAR
szPhoneNumber[RAS_MaxPhoneNumber + 1];
TCHAR
szCallbackNumber[RAS_MaxCallbackNumber + 1];
TCHAR
szUserName[UNLEN + 1];
TCHAR
szPassword[PWLEN + 1];
TCHAR
szDomain[DNLEN + 1] ;
#if (WINVER >=
0x401)
DWORD
dwSubEntry;
ULONG_PTR dwCallbackId;
#endif
}
RASDIALPARAMS;
第四个第五个参数:
如果lpvNotifier参数设为NULL,RasDial就会置入同步模式。dwNotifierType参数就会被忽略。同步调用RasDial是使用该函数的最简单的作用;美中不足的是,同步模式下不能对连接进行监视,如果lpvNotifier
参数不为NULL,就会进入异步模式,
意味着进行连接的同时,函数调用会立即返回。可以对连接进程进行监视
dwNotifierType:
0: lpvNotifier参数使用RasDialFunc函数指针管理连接事件
1: lpvNotifier参数利用RasDialFunc1函数指针管理连接事件
2: lpvNotifier参数利用RasDialFunc2函数指针管理连接事件
0xFFFFFFF: lpvNotifier参数令RasDial在连接事件期间发送一个窗口消息
RasHangUp挂断VPN
DWORD RasHangUp(
__in
HRASCONN hrasconn
);
hrasconn:RasDial返回的一个连接句柄
注意:连接在利用一个调制解调器端口时,如果连接关闭,这个端口需要花时间重新设置这个连接。因此,你应该一直等下去,直到端口连接完全关闭为止。要做到这一点,在重新设置自己的连接时,可调用
RasGetConnectionStatus:获取VPN链接状态来判断连接是否完全关闭。
DWORD
RasGetConnectStatus(
__in
HRASCONN hrasconn,
__in_out
LPRASCONNSTATUS lprasconnstatus
);
hrasconn:RasDial返回的一个连接句柄
lprasconnstatus:取得当前的连接状态
typedef struct
_RASCONNSTATUS {
DWORD
dwSize;
RASCONNSTATE
rasconnstate;
DWORD
dwError;
TCHAR
szDeviceType[RAS_MaxDeviceType + 1];
TCHAR
szDeviceName[RAS_MaxDeviceName + 1];
#if (WINVER >=
0x401)
TCHAR
szPhoneNumber[ RAS_MaxPhoneNumber + 1 ];
#endif // (WINVER
>= 0x401)
} RASCONNSTATUS;
dwSize:必须设为RASCONNSTATUS结构的长度(按字节算)。
rasconnstate:RAS连接活动状态
dwError:若RasGetConnectStatus没有返回0,就取得一个具体的R
A S错误代码
szDeviceType:取得一个字串,该字串代表连接所用的设备类型
szDeviceName:取得当前的设备名
szPhoneNumber:电话号码,如*99#之类的字符串
RasEnumDevices:获得所有具有RAS能力的设备名及类型
DWORD RasEnumDevices(
__in
LPRASDEVINFO lpRasDevInfo,
__in_out
LPDWORD lpcb,
__out
LPDWORD lpcDevices
);
RasValidateEntryName:判断名字的格式是否正确,是否已包含在电话簿中
DWORD
RasValidateEntryName(
__in
LPCTSTR lpszPhonebook,
__in
LPCTSTR lpszEntry
);
lpszPhonebook:用于识别到一个电话簿文件的路径。设为NULL,表示使用当前默认电话簿文件
lpszEntry:电话簿中没有这个名字,但该名字格式无误时,便返回ERROR_SUCCESS。若名字格式有错,这个函数就会失败,返回ERROR_INVALIDNAME;
如果电话簿中有这个名字,就会返回ERROR_ALREAD_YEXIST
可以用RasGetEntryDialParams和RasSetEntryDialParams函数来管理与具体电话簿条目相关的用户安全凭据
通过对RasDial的成功调用,本函数调用后返回连接信息被保存为电话簿入口。
RasEnumConnections:返回一个RASCONN结构数组的缓存的长指针,指向每一个RAS连接。
在调用本函数之前,必须设置缓存中RASCONN结构的第一个成员dwSize的值,即RASCONN的大小,为了在不同系统版本中通过,请用sizeof(RASCONN)取得大小。
本函数列出所有活动RAS连接,返回每一个连接句柄和电话簿入口名
函数原型:
DWORD
RasEnumConnections(
LPRASCONN
lprasconn,
LPDWORD
lpcb,
LPDWORD
lpcConnections
);
下面我们来了解一个很重要的数据结构RASENTRY
typedef_struct_RASENTRY
{
DWORD dwSize;
DWORD dwfOptions;
DWORD dwCountryID;
DWORD dwCountryCode;
TCHAR szAreaCode[ RAS_MaxAreaCode + 1
];
TCHAR szLocalPhoneNumber[
RAS_MaxPhoneNumber + 1 ];
DWORD dwAlternatesOffset;
RASIPADDR ipaddr;
RASIPADDR ipaddrDns;
RASIPADDR ipaddrDnsAlt;
RASIPADDR ipaddrWins;
RASIPADDR ipaddrWinsAlt;
DWORD dwFrameSize;
DWORD dwfNetProtocols;
DWORD dwFramingProtocol;
TCHAR szScript[ MAX_PATH ];
TCHAR szAutoDialDll[ MAX_PATH
];
TCHAR szAutoDialFunc[ MAX_PATH
];
TCHAR szDeviceType[ RAS_MaxDeviceType +
1 ];
TCHAR szDeviceName[ RAS_MaxDeviceName +
1 ];
TCHAR szX25PadType[ RAS_MaxPadType + 1
];
TCHAR szX25Address[ RAS_MaxX25Address +
1 ];
TCHAR szX25Facilities[
RAS_MaxFacilities + 1 ];
TCHAR szX25UserData[ RAS_MaxUserData +
1 ];
DWORD dwChannels;
DWORD dwReserved1;
DWORD dwReserved2;
DWORD dwCustomAuthKey;
} RASENTRY;
RASENTRY 赋值:
RasOptions =
RASEO_SpecificNameServers | RASEO_RemoteDefaultGateway;
//RASEO_UseCountryAndAreaCodes (是否使用区号与拨号属性)
//RASEO_SpecificIpAddr (服务类型-> TCP/IP设置-> 是否指定IP地址项)
//RASEO_SpecificNameServers (设置DNS是否选用)
//RASEO_IpHeaderCompression (是否选用IP头指针压缩)
//RASEO_RemoteDefaultGateway (是否选用远程网上默认网关)
//RASEO_DisableLcpExtensions (是否决定在PPP里不使用LCP,一般不使用这个选项)
//RASEO_TerminalAfterDial (是否拨号后出现终端窗口 <常规-> 连接方式-> 设置-> 选项-> 连接控制> )
//RASEO_ModemLights (此选项只对WIN2K有效,选用后在任务栏出现一个状态监测器)
//RASEO_SwCompression (是否选用软件压缩 <服务器类型-> 高级选项> )
//RASEO_RequireEncryptedPw (是否选用需要加密的密码 <作用是PPP使用PAP明文> )
//RASEO_RequireMsEncryptedPw (是否选用需要微软加密的密码)
//RASEO_RequireDataEncryption (是否选用需要数据加密)
//RASEO_NetworkLogon (此选项对NT/2K没有影响,是否选用登陆网络)
//RASEO_UseLogonCredentials (是否当前用户采用用户名、密码、域等信息进行拨号连接)
//RASEO_PromoteAlternates (是否选用交替号码)
VpnStrategy = VS_Default;
strcpy(mName , "GPRSHY ");
// rasEntry Num
values
rasEntry.dwSize = sizeof
(RASENTRY);
rasEntry.dwfOptions = RasOptions;
rasEntry.dwAlternateOffset = 0;
rasEntry.dwCountryID = 86;//china
rasEntry.dwCountryCode = 86;//china
rasEntry.dwFrameSize = 0;
rasEntry.dwfNetProtocols = RASNP_Ip;
// TCP/IP
rasEntry.dwFramingProtocol =
RASFP_Ppp; //PPP
rasEntry.dwChannels = 0;
rasEntry.dwReserved1 = 0;
rasEntry.dwReserved2 = 0;
if(WINVER > = 0X400)//
WIN98系统
{
rasEntry.dwDialMode =
RASEDM_DialAsNeeded;
rasEntry.dwIdleDisconnectSeconds=0;
rasEntry.dwSubEntries=0;
rasEntry.dwDialExtraPercent=0;
rasEntry.dwDialExtraSampleSeconds=0;
rasEntry.dwHangUpExtraPercent=0;
rasEntry.dwHangUpExtraSampleSeconds=0;
if(WINVER > = 0x500)//
WIN2K系统
{
rasEntry.dwType
= RASET_Vpn;
rasEntry.dwVpnStrategy=VpnStrategy;
rasEntry.dwCustomAuthKey=600;
GUID guid;
CoCreateGuid(&guid);
rasEntry.guidId=guid;
rasEntry.dwEncryptionType=0;
strcpy(rasEntry.szCustomDialDll,
" ");
//
rasEntry.dwfOptions2=0;
//
rasEntry.dwfOptions3=0;
if(WINVER > = 0x501)
{
//
rasEntry.dwfOptions2=0;
//
rasEntry.dwfOptions3=0;
}
}
}
// Strings values
char strPhoneNumber[20];
char strDevType[50];
char strDevName[50];
strcpy (strPhoneNumber,
"*99***1# ");
strcpy (strDevType,
"RASDT_Modem ");
strcpy (strDevName,
"Hawsna Wireless Modem ");
strcpy (rasEntry.szAreaCode,
" ");
strcpy (rasEntry.szLocalPhoneNumber,
strPhoneNumber);
strcpy (rasEntry.szScript,
" ");
strcpy (rasEntry.szAutodialDll,
" ");
strcpy (rasEntry.szAutodialFunc,
" ");
strcpy (rasEntry.szX25PadType,
" ");
strcpy (rasEntry.szX25Address,
" ");
strcpy (rasEntry.szX25Facilities,
" ");
strcpy (rasEntry.szX25UserData,
" ");
strcpy (rasEntry.szDeviceType,
strDevType);
strcpy (rasEntry.szDeviceName,
strDevName);
// IP addresses
RASIPADDR
struipaddrDns,struipaddrDnsAlt,struipaddrWins,struipaddrWinsAlt;
struipaddrDns.a = 211;
struipaddrDns.b = 136;
struipaddrDns.c = 20;
struipaddrDns.d = 203;
struipaddrDnsAlt.a = 202;
struipaddrDnsAlt.b = 96;
struipaddrDnsAlt.c = 128;
struipaddrDnsAlt.d = 68;
struipaddrWins.a = 0;
struipaddrWins.b = 0;
struipaddrWins.c = 0;
struipaddrWins.d = 0;
struipaddrWinsAlt.a = 0;
struipaddrWinsAlt.b = 0;
struipaddrWinsAlt.c = 0;
struipaddrWinsAlt.d = 0;
rasEntry.ipaddrDns =
struipaddrDns;
rasEntry.ipaddrDnsAlt =
struipaddrDnsAlt;
rasEntry.ipaddrWins =
struipaddrWins;
rasEntry.ipaddrWinsAlt =
struipaddrWinsAlt;
一个简单的示例:
// Call RAS DWORD dwRet=RasSetEntryProperties (NULL, mName, &rasEntry, sizeof(RASENTRY), NULL, 0); if (dwRet)//ERROR_INVALID_PARAMETER == dwRet) { CString str; str.Format( "RasSetEntryProperties failed %s\n The error code: %d\n ", mName,dwRet); AfxMessageBox(str); // return FALSE; }