/*************************************************
Opengate server
- module for communication with client prgram (java/javascript)
+ module for communication with client program (java/javascript)
Copyright (C) 1999 Opengate Project Team
Written by Yoshiaki Watanabe 1999-2006
void SendReplyToGetHello(void);
void SendHttpKeepPage(char *userid, char *sessionId, char *language, int port);
int SelectAccept(void);
+void AcceptHttpReConnect(void);
+int MacAddrCheck(int ipStatus,char *clientAddr4, char *clientAddr6, char *macAddr4, char *macAddr6);
+int IsRightKey(char *pNowKey, char *sessionId);
+void SendHttpReply(char *reply);
+void CheckAjaxAbility(char *buff, char *sessionId);
void OnUsageTimeLimitAlarm(int signo);
void OnCheckBasicAlarm(int signo);
int helloWait=FALSE; /* hello reply waiting mode */
int readHelloTime=0; /* the time of reading hello */
+int sendHelloTime=0; /* the time of sending hello */
int noReplyCount=0; /* count up the no reply to hello message */
}
/* set read wait alarm */
- AddAlarm("ReadWaitAlarm",COMMWAITTIMEOUT, TRUE, OnReadWaitAlarm);
+ AddAlarm("ReadWaitAlarm",atoi(GetConfValue("CommWaitTimeout")),
+ TRUE, OnReadWaitAlarm);
EnableAlarm();
/* get string from connection */
if(readln(connfd, buff, BUFFMAXLN) <0){
ReadHttpHeaders();
SendHttpKeepPage(userid, sessionId, language, port);
- /* to check the ajax ablility of the client, wait ajax request */
- AddAlarm("AjaxWaitAlarm",COMMWAITTIMEOUT, TRUE, OnAjaxWaitAlarm);
- EnableAlarm();
- /* read wait for ajax request in the connection */
- if(readln(connfd, buff, BUFFMAXLN) <0){
- /* if timeout, no ajax ability */
- connectMode=NOCONNECT;
- Close(connfd);
- continue;
- }
- /* recieve request */
- RemoveAlarm("AjaxWaitAlarm");
- ReadHttpHeaders();
+ /* to check ajax ability, wait XMLHttpRequest for a while */
+ CheckAjaxAbility(buff, sessionId);
- /* enter to the Http watch mode on the connection */
- connectMode=HTTPCONNECT;
break;
}
-
+
/* is it the terminate request */
/* the request is [GET /terminate-<pid> ..] */
snprintf(httpStr, BUFFMAXLN, "GET /terminate-%d", pid);
/* some other unknown request */
err_msg("ERR at %s#%d: unknown request [%s] sent from client",
- __FILE__,__LINE__);
+ __FILE__,__LINE__,buff);
connectMode=NOCONNECT;
Close(connfd);
+
continue;
}
/* stop all alarms */
RemoveAlarm(NULL);
-
- Close(listenfd[0]);
- Close(listenfd[1]);
-
+
return connectMode;
}
+/***************************************/
+/* check ajax ability */
+/* read hello sent by XMLhttpRequest */
+/* (reply is delayed) */
+/* check result is set in connectMode */
+/***************************************/
+void checkAjaxAbility(char *buff, char *sessionId)
+{
+
+ /* to check the ajax ablility of the client, wait ajax request */
+ AddAlarm("AjaxWaitAlarm",atoi(GetConfValue("CommWaitTimeout")),
+ TRUE, OnAjaxWaitAlarm);
+ EnableAlarm();
+
+ /* read wait for ajax request in the connection */
+ while(1){
+ if(readln(connfd, buff, BUFFMAXLN) <0){
+
+ /* if timeout, no ajax ability */
+ /* java might be connected */
+ connectMode=NOCONNECT;
+ Close(connfd);
+ break;
+ }
+
+ /* recieved normal request */
+ RemoveAlarm("AjaxWaitAlarm");
+ ReadHttpHeaders();
+
+ /* usually, hello request is recieve */
+ if(strstr(buff, "GET /hello-")==buff){
+
+ /* if received hello-key is incorrect, exit */
+ /* [GET /hello-key1-key2 ..] */
+ if( IsRightKey(buff+strlen("GET /hello-"), sessionId)==FALSE){
+ connectMode=ENDCONNECT;
+ Close(connfd);
+ break;
+ }
+
+ /* enter to the Http watch mode on the connection */
+ connectMode=HTTPCONNECT;
+ break;
+ }
+ /* or some request might be inserted. eg:[GET /favicon.ico] */
+ /* ignore it */
+ else{
+ SendHttpReply("");
+ continue;
+ }
+ }
+}
+
/****************************/
/* wait for TCP connection */
/****************************/
if(listenfd[0]>listenfd[1]) smax=listenfd[0]+1;
else smax=listenfd[1]+1;
- //if((n = select(smax, &rfd0, NULL, NULL, &timeout)) > 0){
if((n = select(smax, &rfd0, NULL, NULL, NULL)) > 0){
/* wait connection */
+
if(FD_ISSET(listenfd[0], &rfd0)){
+
if((connfd=accept(listenfd[0], (struct sockaddr *)&cliaddr, &len)) >= 0){
+
/* connect by ipv4 */
ipType=IPV4;
}
}
if(FD_ISSET(listenfd[1], &rfd0)){
+
if((connfd=accept(listenfd[1], (struct sockaddr *)&cliaddr, &len)) >= 0){
+
/* connect by ipv6 */
ipType=IPV6;
}
void onReadWaitAlarm(int signo)
{
connectMode=ENDCONNECT;
- err_msg("ERR at %s#%d: read request timeout",__FILE__,__LINE__);
}
/***************************************/
static int packetCountPrev=0; /* packet count at previous check */
int packetCountNow=0; /* packet count at now */
static int noPacketPeriod=0; /* no packet period count in check loop */
- char macAddrNow[ADDRMAXLN]; /* MAC address at now */
/* search new IPv6 addresses */
ScanNdpEntry(alarmArg.pClientAddr, alarmArg.userid,
alarmArg.macAddr6, alarmArg.userProperty);
+ /* mac address check */
+ if(MacAddrCheck(alarmArg.ipStatus,
+ alarmArg.clientAddr4, alarmArg.clientAddr6,
+ alarmArg.macAddr4, alarmArg.macAddr6)==FALSE){
+ connectMode=ENDCONNECT;
+ return;
+ }
+
/* packet flow check */
packetCountNow=GetPacketCount(alarmArg.pClientAddr);
if(packetCountNow==packetCountPrev){ /* no packet between checks */
connectMode=ENDCONNECT;
return;
}
-
- /* mac address check */
- if(alarmArg.ipStatus!=IPV6ONLY){
- GetMacAddrFromArp(alarmArg.clientAddr4, macAddrNow);
- if(strcmp(alarmArg.macAddr4, macAddrNow)!=0){
+ /* set the alarm for next periodic keep alive check */
+ AddAlarm("CheckBasicAlarm", alarmArg.checkInterval, FALSE, OnCheckBasicAlarm); /* EnableAlarm is called automatically in alarm function */
+}
+
+/***************************************/
+/* check mac address change */
+/***************************************/
+int macAddrCheck(int ipStatus, char *clientAddr4, char *clientAddr6, char *macAddr4, char *macAddr6)
+{
+ char macAddrNow[ADDRMAXLN]; /* MAC address at now */
+
+ if(ipStatus!=IPV6ONLY){
+ /* check mac address from arp */
+ GetMacAddrFromArp(clientAddr4, macAddrNow);
+ if(*macAddrNow!='?' && strcmp(macAddr4, macAddrNow)!=0){
err_msg("ERR at %s#%d: mac address is changed",__FILE__,__LINE__);
connectMode=ENDCONNECT;
- return;
+ return FALSE;
}
}else{
- GetMacAddrFromNdp(alarmArg.clientAddr6, macAddrNow);
- if(strcmp(alarmArg.macAddr6, macAddrNow)!=0){
+ /* check mac address from ndp */
+ GetMacAddrFromNdp(clientAddr6, macAddrNow);
+ if(*macAddrNow!='?' && strcmp(macAddr6, macAddrNow)!=0){
err_msg("ERR at %s#%d: mac address is changed",__FILE__,__LINE__);
connectMode=ENDCONNECT;
- return;
+ return FALSE;
}
}
-
- /* set the alarm for next periodic keep alive check */
- AddAlarm("CheckBasicAlarm", alarmArg.checkInterval, FALSE, OnCheckBasicAlarm); /* EnableAlarm is called automatically in alarm function */
+ return TRUE;
}
/***************************************/
/***************************************/
void onCheckJavaAlarm(int signo)
{
- char macAddrNow[ADDRMAXLN]; /* MAC address at now */
-
/* search new IPv6 addresses */
ScanNdpEntry(alarmArg.pClientAddr, alarmArg.userid,
alarmArg.macAddr6, alarmArg.userProperty);
helloWait=TRUE;
/* mac address check */
- if(alarmArg.ipStatus!=IPV6ONLY){
- GetMacAddrFromArp(alarmArg.clientAddr4, macAddrNow);
- if(strcmp(alarmArg.macAddr4, macAddrNow)!=0){
- err_msg("ERR at %s#%d: mac address is changed",__FILE__,__LINE__);
- connectMode=ENDCONNECT;
- return;
- }
- }else{
- GetMacAddrFromNdp(alarmArg.clientAddr6, macAddrNow);
- if(strcmp(alarmArg.macAddr6, macAddrNow)!=0){
- err_msg("ERR at %s#%d: mac address is changed",__FILE__,__LINE__);
- connectMode=ENDCONNECT;
- return;
- }
+ if(MacAddrCheck(alarmArg.ipStatus,
+ alarmArg.clientAddr4, alarmArg.clientAddr6,
+ alarmArg.macAddr4, alarmArg.macAddr6)==FALSE){
+ connectMode=ENDCONNECT;
+ return;
}
/* set the alarm for next periodic check */
/***************************************************/
/* wait for close connection of HTTP connection */
/***************************************************/
-void waitHttpClose(struct clientAddr *pClientAddr, char *userid, char *userProperty, char *macAddr4, char *macAddr6, int ipStatus)
+void waitHttpClose(struct clientAddr *pClientAddr, char *userid, char *userProperty, char *macAddr4, char *macAddr6, int ipStatus, char *sessionId, int port)
{
char buff[BUFFMAXLN];
int ret;
/* save time to read hello */
readHelloTime = time(NULL);
+ /* send first reply to hello */
SendReplyToGetHello();
+ sendHelloTime = time(NULL);
+
+ /* set the hello wait mode ON */
+ helloWait=TRUE;
/* TCP read/write loop */
/* this loop implement following logic */
EnableAlarm();
while(1){
+
/* set default to terminate */
connectMode=ENDCONNECT;
/* normal read */
connectMode=HTTPCONNECT;
- /* read [GET /terminate], then quit */
- if(strstr(buff,"GET /terminate") == buff){
- connectMode=ENDCONNECT;
- break;
- }
-
- /* read [GET /hello], then reply */
- else if(strstr(buff,"GET /hello") == buff){
+ /* read [GET /hello] */
+ if(strstr(buff,"GET /hello") == buff){
/* save time to read hello */
readHelloTime = time(NULL);
ReadHttpHeaders();
- SendReplyToGetHello();
- }
+ /* if received key is not match, exit */
+ if(IsRightKey(buff+strlen("GET /hello-"), sessionId)==FALSE){
+ connectMode=ENDCONNECT;
+ break;
+ }
+
+ /* set the hello wait mode OFF */
+ helloWait=FALSE;
+ }
+
/* read other string */
else{
}
/*abnormal read */
/* some alarm is ringed or connecion is closed */
/* connectionMode might be modified in onAlarm */
- if(connectMode==ENDCONNECT) break;
+
+ if(connectMode==ENDCONNECT){
+
+ /* wait short time to accept reconnection */
+ /* (to permit occasional disconnection at exchanging hello) */
+ if(helloWait==TRUE &&
+ (time(NULL)-sendHelloTime)<=atoi(GetConfValue("ReconnectTimeout"))){
+ AcceptHttpReConnect();
+ }
+
+ /* no reconnection, then terminate */
+ if(connectMode==ENDCONNECT){
+ break;
+ }
+ }
}
-
+
/* restart alarm */
EnableAlarm();
}
/* reset alarm */
- RemoveAlarm(NULL);
-
- /* send quit message to client */
- SendQuitClient();
+ RemoveAlarm(NULL);
Close(connfd);
return;
}
+/*************************/
+/* accept http reconnect */
+/*************************/
+void acceptHttpReConnect(void){
+
+ int startTime;
+
+ startTime=time(NULL);
+
+ /* wait a short time */
+ AddAlarm("ReadWaitAlarm",atoi(GetConfValue("ReconnectTimeout")),
+ TRUE, OnReadWaitAlarm);
+ EnableAlarm();
+
+ /* connection wait */
+ connfd = SelectAccept();
+
+ if(connfd<0){
+ /* abnormal return from selectAccept */
+ if(errno==EINTR){ /* timeout interupt */
+ err_msg("ERR at %s#%d: http reconnect timeout",
+ __FILE__,__LINE__);
+ connectMode=ENDCONNECT;
+ }else{ /* other errors */
+ err_msg("ERR: http reconnect error [%s]",strerror(errno));
+ connectMode=ENDCONNECT;
+ }
+
+ }else{
+ /* normal return from selectAccept */
+ if(debug>0)err_msg("INFO: http reconnect after %d seconds",
+ time(NULL)-startTime);
+ connectMode=HTTPCONNECT;
+ }
+
+ /* receive request */
+ RemoveAlarm("ReadWaitAlarm");
+}
+
+/*****************************************************************/
+/* Is the sent client key correct */
+/* request string is as follows */
+/* GET /hello-11111111111111111111-2222222222222222222 HTTP... */
+/* MD5digest(32chars) MD5digest(32chars) */
+/* nowKey nextKey */
+/* */
+/* client server */
+/* save sid <------------------- sid */
+/* md5(sid)+md5(md5(rand1)+sid) ---------> check nowkey */
+/* save nextKey */
+/* md5(rand1)+md5(md5(rand2)+sid)---------> check nowkey */
+/* save nextKey */
+/* md5(rand2)+md5(md5(rand3)+sid)---------> check nowkey */
+/* save nextKey */
+/*****************************************************************/
+int isRightKey(char *arg, char *sessionId)
+{
+ static char savedKey[33]=""; /* saved MD5 string */
+ char tempbuff[BUFFMAXLN]; /* work area */
+ char md5work[33] ; /* md5 work */
+ char *pNowKey;
+ char *pNextKey;
+
+ /* initial value of savedKey is md5(md5(sessionId)+sessionId) */
+ if(isNull(savedKey)){
+ md5hex(tempbuff, 33, sessionId);
+ strncat(tempbuff, sessionId, BUFFMAXLN);
+ md5hex(savedKey, 33, tempbuff);
+ }
+
+ /* split NowKey and NextKey in argument */
+ /* 32 is the length of MD5 result */
+ pNowKey=arg;
+ *(pNowKey+32)='\0';
+ pNextKey=pNowKey+33;
+ *(pNextKey+32)='\0';
+
+ /* make string [nowKey+sessionId] */
+ strncpy(tempbuff, pNowKey, BUFFMAXLN);
+ strncat(tempbuff, sessionId, BUFFMAXLN);
+
+ /* compare savedKey and md5(nowKey+sessionId) */
+ if(strcmp(savedKey, md5hex(md5work, 33, tempbuff))==0){
+
+ /* save nextKey for next check */
+ strncpy(savedKey, pNextKey, 33);
+ return TRUE;
+ }
+ else{
+ err_msg("ERR at %s#%d: incorrect client key",
+ __FILE__,__LINE__);
+ return FALSE;
+ }
+}
+
/***************************************/
/* called at periodic http alive check */
/***************************************/
void onCheckHttpAlarm(int signo)
{
- char macAddrNow[ADDRMAXLN]; /* MAC address at now */
+ /* at this timing, hello request might be received */
+ /* if in hello wait mode, it is abnormal */
+ if(helloWait==TRUE){
+ connectMode=ENDCONNECT;
+ return;
+ }
+
+ /* send delayed reply to hello request */
+ SendReplyToGetHello();
+
+ /* save time to send hello */
+ sendHelloTime = time(NULL);
+
+ /* set the hello wait mode ON */
+ helloWait=TRUE;
/* search new IPv6 addresses */
ScanNdpEntry(alarmArg.pClientAddr, alarmArg.userid,
alarmArg.macAddr6, alarmArg.userProperty);
- /* if long HTTP read waiting, then quit */
- if( (time(NULL)-readHelloTime) > alarmArg.checkInterval ){
- connectMode = ENDCONNECT;
- }else{
- connectMode = HTTPCONNECT;
- }
-
/* mac address check */
- if(alarmArg.ipStatus!=IPV6ONLY){
- GetMacAddrFromArp(alarmArg.clientAddr4, macAddrNow);
- if(strcmp(alarmArg.macAddr4, macAddrNow)!=0){
- err_msg("ERR at %s#%d: mac address is changed",__FILE__,__LINE__);
- connectMode=ENDCONNECT;
- return;
- }
- }else{
- GetMacAddrFromNdp(alarmArg.clientAddr6, macAddrNow);
- if(strcmp(alarmArg.macAddr6, macAddrNow)!=0){
- err_msg("ERR at %s#%d: mac address is changed",__FILE__,__LINE__);
- connectMode=ENDCONNECT;
- return;
- }
+ if(MacAddrCheck(alarmArg.ipStatus,
+ alarmArg.clientAddr4, alarmArg.clientAddr6,
+ alarmArg.macAddr4, alarmArg.macAddr6)==FALSE){
+ connectMode=ENDCONNECT;
+ return;
}
/* set the alarm for next periodic check */
AddAlarm("CheckHttpAlarm", alarmArg.checkInterval, FALSE, OnCheckHttpAlarm);
/* EnableAlarm is called automatically in alarm function */
+ /* normal return */
+ connectMode = HTTPCONNECT;
return;
}
char buff[BUFFMAXLN]; /* read in buffer */
FILE *fp;
char httpKeepDoc[BUFFMAXLN];
- char httpHelloInterval[WORDMAXLN];
char httpHelloUrl[BUFFMAXLN];
char terminateUrl[BUFFMAXLN];
char acceptDoc2Url[BUFFMAXLN];
char httpkeepJsUrl[BUFFMAXLN];
+ char md5JsUrl[BUFFMAXLN];
char *startPageUrl=GetConfValue("StartPage/Url");
int startPageType=atoi(GetConfValue("StartPage/Type"));
char opengateDir[BUFFMAXLN];
snprintf(httpHelloUrl, BUFFMAXLN, "http://%s:%d/hello",
GetConfValue("OpengateServerName"), port);
- /* create httphello interval [50] */
- snprintf(httpHelloInterval, WORDMAXLN, "%s", GetConfValue("HttpWatch/HelloInterval"));
-
/* create httpkeep.js url[http://<serveraddr>/opengate/httpkeep.js] */
snprintf(httpkeepJsUrl, BUFFMAXLN, "http://%s%s/%s",
GetConfValue("OpengateServerName"),
GetConfValue("OpengateDir"),GetConfValue("HttpKeepJS"));
+ /* create md5.js url[http://<serveraddr>/opengate/md5.js] */
+ snprintf(md5JsUrl, BUFFMAXLN, "http://%s%s/%s",
+ GetConfValue("OpengateServerName"),
+ GetConfValue("OpengateDir"),GetConfValue("Md5JS"));
+
/* create path to httpkeep doc */
snprintf(httpKeepDoc,BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
GetConfValue("OpengateDir"),language,GetConfValue("HttpKeepDoc"));
}
/* replace mark */
- htmlReplace(buff, "%%HTTPHELLOINTERVAL%%", httpHelloInterval);
htmlReplace(buff, "%%HTTPHELLOURL%%", httpHelloUrl);
htmlReplace(buff, "%%USERID%%", userid);
htmlReplace(buff, "%%SESSIONID%%", sessionId);
htmlReplace(buff, "%%TERMINATEURL%%", terminateUrl);
htmlReplace(buff, "%%HTTPKEEPJSURL%%", httpkeepJsUrl);
+ htmlReplace(buff, "%%MD5JSURL%%", md5JsUrl);
htmlReplace(buff, "%%OPENGATEDIR%%", opengateDir);
htmlReplace(buff, "%%OPENGATEPORT%%", portStr);
/* chunk end */
Writefmt(connfd,"0\r\n");
Writefmt(connfd,"\r\n");
+
fclose(fp);
}
+
+/*************************************************************/
+/* send reply to unknown http request eg:[GET /favico.ico..] */
+/*************************************************************/
+void sendHttpReply(char *reply)
+{
+ /* send HTTP headers */
+ Writefmt(connfd,"HTTP/1.1 200 OK\r\n");
+ Writefmt(connfd,"Transfer-Encoding: chunked\r\n");
+ Writefmt(connfd,"Keep-Alive: timeout=300\r\n");
+ Writefmt(connfd,"Connection: Keep-Alive\r\n");
+ Writefmt(connfd,"Content-Type: text/html\r\n");
+ Writefmt(connfd,"\r\n");
+
+ if(!isNull(reply)){
+ /* length of chunk in hex */
+ Writefmt(connfd, "%x\r\n", strlen(reply));
+ /* the chunk content */
+ Writefmt(connfd, "%s\r\n", reply);
+ }
+
+ /* chunk end */
+ Writefmt(connfd,"0\r\n");
+ Writefmt(connfd,"\r\n");
+}
+
/***************************************************/
/***************************************************/
void GetPeerAddr(int sockfd, char *peerAddr)
if(debug>1) err_msg("DEBUG:<=sendTerminateReply( )");
}
-void WaitHttpClose(struct clientAddr *pClientAddr, char *userid, char *userProperty, char *macAddr4, char *macAddr6, int ipStatus)
+void WaitHttpClose(struct clientAddr *pClientAddr, char *userid, char *userProperty, char *macAddr4, char *macAddr6, int ipStatus, char *sessionid, int port)
{
- if(debug>1) err_msg("DEBUG:=>waitHttpClose(%p,%s,userProperty,%s,%s,%d)",pClientAddr,userid,macAddr4,macAddr6,ipStatus);
- waitHttpClose(pClientAddr,userid,userProperty,macAddr4,macAddr6,ipStatus);
+ if(debug>1) err_msg("DEBUG:=>waitHttpClose(%p,%s,userProperty,%s,%s,%d,%s,%d)",pClientAddr,userid,macAddr4,macAddr6,ipStatus, sessionid, port);
+ waitHttpClose(pClientAddr,userid,userProperty,macAddr4,macAddr6,ipStatus, sessionid, port);
if(debug>1) err_msg("DEBUG:<=waitHttpClose( )");
}
if(debug>1) err_msg("DEBUG:=>sendReplyToGetHello( )");
sendReplyToGetHello();
if(debug>1) err_msg("DEBUG:<=sendReplyToGetHello( )");
-
}
void SendHttpKeepPage(char *userid, char *sessionId, char *language, int port)
return ret;
}
+
+void AcceptHttpReConnect(void){
+ if(debug>1) err_msg("DEBUG:=>acceptHttpReConnect()");
+ acceptHttpReConnect();
+ if(debug>1) err_msg("DEBUG:<=acceptHttpReConnect()");
+}
+
+int MacAddrCheck(int ipStatus, char *clientAddr4, char *clientAddr6, char *macAddr4, char *macAddr6) {
+ int ret;
+
+ if(debug>1) err_msg("DEBUG:=>macAddrCheck(%d,%s,%s,%s,%s)",
+ ipStatus, clientAddr4, clientAddr6, macAddr4, macAddr6);
+ ret=macAddrCheck(ipStatus, clientAddr4, clientAddr6, macAddr4, macAddr6);
+ if(debug>1) err_msg("DEBUG:(%d)<=macAddrCheck()",ret);
+
+ return ret;
+}
+
+int IsRightKey(char *pNowKey, char *sessionId){
+ int ret;
+
+ if(debug>1) err_msg("DEBUG:=>isRightKey(%s,%s)", pNowKey, sessionId);
+ ret=isRightKey(pNowKey, sessionId);
+ if(debug>1) err_msg("DEBUG:(%d)<=isRightKey()",ret);
+
+ return ret;
+}
+
+void SendHttpReply(char *reply){
+ if(debug>1) err_msg("DEBUG:=>sendHttpRepy(%s)", reply);
+ sendHttpReply(reply);
+ if(debug>1) err_msg("DEBUG:<=sendHttpReply()");
+}
+
+void CheckAjaxAbility(char *buff, char *sessionId){
+ if(debug>1) err_msg("DEBUG:=>checkAjaxAbility(%s,%s)",buff,sessionId);
+ checkAjaxAbility(buff,sessionId);
+ if(debug>1) err_msg("DEBUG:<=checkAjaxAbility()");
+}