C++实现VPN工具之常用API函数

发布于 2019-09-26 作者 风铃 215次 浏览 版块 前端

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;

}



收藏
暂无回复