453 lines
12 KiB
C++
453 lines
12 KiB
C++
#include "config.h"
|
||
#include <string.h>
|
||
#include <stdio.h>
|
||
#include <errno.h>
|
||
#include <iostream>
|
||
#include <iomanip>
|
||
#include <signal.h>
|
||
|
||
|
||
#if WIN32
|
||
#include <windows.h>
|
||
#else
|
||
#if DEBUG
|
||
#include "segment.h"
|
||
#endif
|
||
#include <sys/select.h>
|
||
#include <sys/types.h>
|
||
#include <sys/stat.h>
|
||
#include <unistd.h>
|
||
#include <sys/time.h>
|
||
#include <fcntl.h>
|
||
#include <netinet/in.h>
|
||
#include <netdb.h>
|
||
#include <arpa/inet.h>
|
||
#include <stdlib.h>
|
||
#endif
|
||
|
||
#include "cJSON.h"
|
||
#include "mytime.h"
|
||
#include "bytestool.h"
|
||
#include "ngrok.h"
|
||
#include "sslbio.h"
|
||
#include "nonblocking.h"
|
||
#include "param.h"
|
||
#if UDPTUNNEL
|
||
#include "udp.h"
|
||
#endif
|
||
using namespace std;
|
||
//string VER = "1.35-(2016/5/13)";
|
||
char VER[24]= "1.55-(2021/8/30)";
|
||
|
||
|
||
ssl_info *mainsslinfo=NULL;
|
||
|
||
#if UDPCMD
|
||
int udpsocket=0;
|
||
int udpport=1885;
|
||
#endif
|
||
|
||
void* proxy( );
|
||
|
||
|
||
void cs( int n )
|
||
{
|
||
if(n == SIGINT )
|
||
{
|
||
printf( "key down ctrl+c\r\n" );
|
||
exit( 0 );
|
||
}
|
||
}
|
||
|
||
|
||
|
||
int CheckStatus()
|
||
{
|
||
|
||
//判断是否存在
|
||
if (G_SockList.count(mainInfo.mainsock)==0||mainInfo.mainsock==0)
|
||
{
|
||
if(mainInfo.lasterrtime==0||(mainInfo.lasterrtime+60)<getUnixTime()){
|
||
//连接失败
|
||
if(ConnectMain(&mainInfo.mainsock,mainInfo.saddr,&mainsslinfo)==-1)
|
||
{
|
||
mainInfo.mainsockstatus=0;
|
||
printf("link err\r\n");
|
||
mainInfo.lasterrtime=getUnixTime();
|
||
return -1;
|
||
}
|
||
}
|
||
}
|
||
return(0);
|
||
}
|
||
/*检测ping*/
|
||
int checkping(){
|
||
if(mainInfo.pingtime+mainInfo.ping<getUnixTime()&&G_SockList.count(mainInfo.mainsock)!=0&&mainInfo.mainsock!=0)
|
||
{
|
||
#if OPENSSL
|
||
int sendlen = SendPing(mainInfo.mainsock, mainsslinfo->ssl );
|
||
#else
|
||
int sendlen = SendPing(mainInfo.mainsock, &mainsslinfo->ssl );
|
||
#endif
|
||
|
||
//发送失败断开连接
|
||
if(sendlen<1)
|
||
{
|
||
mainInfo.mainsockstatus=0;
|
||
}
|
||
mainInfo.pingtime = getUnixTime();
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
int main( int argc, char **argv )
|
||
{
|
||
//rand
|
||
srand(time(0));
|
||
InitMainInfo();//初始化结构体
|
||
printf("ngrokc v%s \r\n",VER);
|
||
loadargs( argc, argv);
|
||
#if WIN32
|
||
signal( SIGINT, cs );
|
||
#else
|
||
/* socket close hui fa song xing hao dao zhi tui chu */
|
||
signal( SIGPIPE, SIG_IGN );
|
||
struct sigaction sigIntHandler;
|
||
sigIntHandler.sa_handler = cs;
|
||
sigemptyset( &sigIntHandler.sa_mask );
|
||
sigIntHandler.sa_flags = 0;
|
||
sigaction( SIGINT, &sigIntHandler, NULL );
|
||
#endif
|
||
|
||
|
||
#if WIN32
|
||
WSADATA wsaData = { 0 };
|
||
if ( 0 != WSAStartup( MAKEWORD( 2, 2 ), &wsaData ) )
|
||
{
|
||
printf( "WSAStartup failed. errno=[%d]\n", WSAGetLastError() );
|
||
return(-1);
|
||
}
|
||
#endif
|
||
|
||
#if OPENSSL
|
||
ssl_lib_init();
|
||
#else
|
||
init_ssl_session();
|
||
#endif // OPENSSL
|
||
|
||
/* init addr */
|
||
mainInfo.lastdnsback = net_dns( &mainInfo.saddr, mainInfo.shost, mainInfo.sport );
|
||
mainInfo.lastdnstime = getUnixTime();
|
||
#if UDPCMD
|
||
udpsocket=ControlUdp(udpport);
|
||
#endif // UDPCMD
|
||
#if UDPTUNNEL
|
||
initUdp();
|
||
#endif // UDPTUNNEL
|
||
proxy();
|
||
return(0);
|
||
}
|
||
|
||
|
||
void* proxy( )
|
||
{
|
||
|
||
fd_set writeSet;
|
||
fd_set readSet;
|
||
int maxfd = 0;
|
||
//unsigned char buf[MAXBUF];
|
||
struct timeval timeout;
|
||
|
||
int maxfdp = 0;
|
||
int ret=0;
|
||
Sockinfo *tempinfo ;
|
||
Sockinfo *tempinfo1;
|
||
map<int, Sockinfo*>::iterator it;
|
||
map<int, Sockinfo*>::iterator it1;
|
||
map<int, Sockinfo*>::iterator it3;
|
||
list<TunnelInfo*>::iterator listit;
|
||
TunnelInfo *tunnelinfo;
|
||
// char ReqId[20]={0};
|
||
int backcode=0;
|
||
|
||
while ( true )
|
||
{
|
||
//ping
|
||
checkping();//ping
|
||
|
||
#if UDPTUNNEL
|
||
//login
|
||
CheckUdpAuth(udpInfo.msock);
|
||
//reg tunnel
|
||
CheckRegTunnel(udpInfo.msock);
|
||
CheckUdpPing(udpInfo.msock);//ping
|
||
#endif // UDPTUNNEL
|
||
|
||
//控制链接断开,关闭所有连接
|
||
if(mainInfo.mainsockstatus==0){
|
||
shutdown( mainInfo.mainsock,2);
|
||
//释放所有连接
|
||
for ( it3 = G_SockList.begin(); it3 != G_SockList.end(); )
|
||
{
|
||
clearsock(it3->second);
|
||
it3++;
|
||
}
|
||
G_SockList.clear();
|
||
mainInfo.mainsock = 0;
|
||
//改回状态
|
||
mainInfo.mainsockstatus=1;
|
||
//初始化通道
|
||
InitTunnelList();
|
||
}
|
||
|
||
if (mainInfo.lastdnsback == -1 ||(mainInfo.lastdnstime + 600) < getUnixTime())
|
||
{
|
||
mainInfo.lastdnsback = net_dns( &mainInfo.saddr, mainInfo.shost, mainInfo.sport );
|
||
mainInfo.lastdnstime = getUnixTime();
|
||
printf( "update dns\r\n" );
|
||
}
|
||
//dns解析成功
|
||
if (mainInfo.lastdnsback != -1)
|
||
{
|
||
CheckStatus();
|
||
}
|
||
|
||
//注册端口
|
||
if(G_SockList.count(mainInfo.mainsock)!=0&&mainInfo.mainsock!=0){
|
||
|
||
tempinfo=G_SockList[mainInfo.mainsock];
|
||
if(tempinfo->isauth==1&&mainInfo.regtunneltime+60<getUnixTime()){
|
||
mainInfo.regtunneltime=getUnixTime();
|
||
for ( listit =G_TunnelList.begin(); listit != G_TunnelList.end(); ++listit )
|
||
{
|
||
tunnelinfo =(TunnelInfo *)*listit;//udp不在这里注册
|
||
if(tunnelinfo->regstate==0&&strcasecmp(tunnelinfo->protocol,"udp")!=0){
|
||
#if OPENSSL
|
||
SendReqTunnel(mainInfo.mainsock,mainsslinfo->ssl,tunnelinfo);
|
||
#else
|
||
SendReqTunnel(mainInfo.mainsock,&mainsslinfo->ssl,tunnelinfo);
|
||
#endif
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
timeout.tv_sec = 0;
|
||
timeout.tv_usec = 5000;
|
||
FD_ZERO( &readSet );
|
||
maxfd = 0;
|
||
maxfdp = 0;
|
||
FD_ZERO( &writeSet );
|
||
|
||
/* 遍历添加 */
|
||
//map<int, sockinfo*>::iterator it;
|
||
for ( it = G_SockList.begin(); it != G_SockList.end(); )
|
||
{
|
||
|
||
tempinfo = it->second;
|
||
/* 如果未连接才添加,写入监听 */
|
||
if ( tempinfo->isconnect == 0 )
|
||
{
|
||
// printf("wit->first:%d\r\n",it->first);
|
||
FD_SET( it->first, &writeSet );
|
||
}
|
||
else{
|
||
// printf("rit->first:%d\r\n",it->first);
|
||
FD_SET( it->first, &readSet );
|
||
}
|
||
maxfdp = it->first > maxfdp ? it->first : maxfdp;
|
||
maxfd++;
|
||
//继续遍历
|
||
sleeps(1);
|
||
++it;
|
||
}
|
||
|
||
#if UDPCMD
|
||
if(udpsocket>0){
|
||
maxfdp = udpsocket > maxfdp ? udpsocket : maxfdp;
|
||
FD_SET(udpsocket,&readSet );
|
||
}
|
||
#endif //
|
||
|
||
#if UDPTUNNEL
|
||
if(udpInfo.msock>0){
|
||
maxfdp = udpInfo.msock > maxfdp ? udpInfo.msock : maxfdp;
|
||
FD_SET(udpInfo.msock,&readSet );
|
||
maxfdp = udpInfo.lsock > maxfdp ? udpInfo.lsock : maxfdp;
|
||
FD_SET(udpInfo.lsock,&readSet );
|
||
}
|
||
#endif // UDPTUNNEL
|
||
|
||
if(maxfd==0)
|
||
{
|
||
sleeps( 500 );
|
||
}
|
||
|
||
/* printf("add ok \r\n"); */
|
||
ret = select( maxfdp + 1, &readSet, &writeSet, NULL, &timeout ); /* 为等待时间传入NULL,则永久等待。传入0立即返回。不要勿用。 */
|
||
if ( ret == -1 && maxfd != 0 )
|
||
{
|
||
echo("select error\r\n");
|
||
continue;
|
||
}
|
||
|
||
if ( ret > 0 )
|
||
{
|
||
|
||
|
||
#if UDPCMD
|
||
if(FD_ISSET(udpsocket,&readSet))
|
||
{
|
||
UdpCmd(udpsocket);
|
||
}
|
||
#endif
|
||
#if UDPTUNNEL
|
||
UdpRecv(&readSet);
|
||
#endif // UDPTUNNEL
|
||
|
||
|
||
for ( it1 = G_SockList.begin(); it1 != G_SockList.end(); )
|
||
{
|
||
tempinfo = it1->second;
|
||
//ping
|
||
checkping();//这里添加个ping避免超时
|
||
//判断连接超时sock
|
||
if((tempinfo->linktime+10)<getUnixTime()&&tempinfo->isconnect==0)
|
||
{
|
||
//关闭远程连接
|
||
if(tempinfo->istype==2){
|
||
echo("connect local fail\r\n");
|
||
shutdown( tempinfo->tosock, 2 );
|
||
}
|
||
clearsock(tempinfo);
|
||
G_SockList.erase(it1++);
|
||
continue;
|
||
}
|
||
|
||
/*等于1才是添加到 readSet的*/
|
||
if (FD_ISSET( it1->first, &readSet )&&tempinfo->isconnect==1 )
|
||
{
|
||
/* 远程的转发给本地 */
|
||
if ( tempinfo->istype == 1 )
|
||
{
|
||
//未连接本地
|
||
if ( tempinfo->isconnectlocal == 0 )
|
||
{
|
||
backcode=ConnectLocal(tempinfo);
|
||
if(backcode==-1)
|
||
{
|
||
G_SockList.erase(it1++);
|
||
continue;
|
||
}
|
||
}
|
||
//等待本地连接完成
|
||
if( tempinfo->isconnectlocal == 1 )
|
||
{
|
||
sleeps( 1 );//避免频繁触发cpu过高
|
||
}
|
||
//本地连接完成转发
|
||
if( tempinfo->isconnectlocal == 2 )
|
||
{
|
||
backcode=RemoteToLocal(tempinfo);
|
||
if(backcode==-1)
|
||
{
|
||
G_SockList.erase(it1++);
|
||
continue;
|
||
}
|
||
}
|
||
}
|
||
/* 本地的转发给远程 */
|
||
else if(tempinfo->istype == 2){
|
||
backcode=LocalToRemote(tempinfo);
|
||
if(backcode==-1)
|
||
{
|
||
G_SockList.erase(it1++);
|
||
continue;
|
||
}
|
||
}
|
||
//控制连接
|
||
else if(tempinfo->istype ==3){
|
||
backcode=CmdSock(&mainInfo.mainsock,tempinfo,mainInfo.saddr);
|
||
if(backcode==-1)
|
||
{
|
||
//控制链接断开,标记清空
|
||
mainInfo.mainsockstatus=0;
|
||
mainInfo.lasterrtime=getUnixTime();
|
||
break;
|
||
}
|
||
}
|
||
|
||
|
||
}
|
||
//可写,表示连接上了
|
||
if ( FD_ISSET( it1->first, &writeSet )&&tempinfo->isconnect==0 )
|
||
{
|
||
if ( tempinfo->isconnect == 0 )
|
||
{
|
||
//检测连接是否可用
|
||
if (check_sock(it1->first)!= 0 )
|
||
{
|
||
//关闭远程连接
|
||
if(tempinfo->istype==2){
|
||
echo("连接本地失败");
|
||
shutdown( tempinfo->tosock, 2 );
|
||
}
|
||
clearsock(tempinfo);
|
||
G_SockList.erase(it1++);
|
||
continue;
|
||
}
|
||
|
||
|
||
/* 为远程连接 */
|
||
if ( tempinfo->istype == 1 )
|
||
{
|
||
//初始化远程连接
|
||
backcode=RemoteSslInit(tempinfo);
|
||
if(backcode==-1)
|
||
{
|
||
G_SockList.erase(it1++);
|
||
continue;
|
||
}
|
||
/* 置为1 */
|
||
tempinfo->isconnect = 1;
|
||
}
|
||
|
||
//本地连接
|
||
if ( tempinfo->istype == 2 )
|
||
{
|
||
|
||
if(tempinfo->tunnelreq->localtls==1){
|
||
//初始化远程连接
|
||
backcode=LocalSslInit(tempinfo);
|
||
if(backcode==-1)
|
||
{
|
||
G_SockList.erase(it1++);
|
||
continue;
|
||
}
|
||
}
|
||
|
||
if(G_SockList.count(tempinfo->tosock)>0)
|
||
{
|
||
tempinfo1 = G_SockList[tempinfo->tosock];
|
||
tempinfo1->isconnectlocal=2;
|
||
if(tempinfo->tunnelreq->localtls==1){
|
||
tempinfo1->localSslinfo=tempinfo->localSslinfo;
|
||
}
|
||
}
|
||
/* 置为1 */
|
||
tempinfo->isconnect = 1;
|
||
}
|
||
|
||
}
|
||
}
|
||
//继续遍历
|
||
++it1;
|
||
}
|
||
}
|
||
//睡1豪秒,避免CPU过高
|
||
sleeps(2);
|
||
}
|
||
return(0);
|
||
}
|