1 /*************************************************
3 module for communication with client program (javascript)
5 Copyright (C) 1999 Opengate Project Team
6 Written by Yoshiaki Watanabe 1999-2006
7 Modified Katsuhiko Eguchi, 2005
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 Email: watanaby@is.saga-u.ac.jp
24 **************************************************/
26 #include "opengatesrv.h"
28 void GetPeerAddr(int sockfd, char *peerAddr);
29 void SendTerminateReply(void);
30 void ReadHttpHeaders(void);
31 void SendReplyToGetHello(void);
32 void SendHttpKeepPage(char *userid, char *sessionId, char *language, int port, int cookieAuth, char *redirectedUrl);
33 int SelectAccept(void);
34 void AcceptHttpReConnect(int timeout);
35 int MacAddrCheck(int ipStatus,char *clientAddr4, char *clientAddr6, char *macAddr4, char *macAddr6);
36 int IsRightKey(char *pNowKey, char *sessionId);
37 void SendHttpReply(char *reply);
38 void SendHttpNotFound(void);
40 void OnUsageTimeLimitAlarm(int signo);
41 void OnCheckBasicAlarm(int signo);
42 void OnCheckHttpAlarm(int signo);
43 void OnReadWaitAlarm(int signo);
44 void OnAjaxWaitAlarm(int signo);
45 void CheckBasic(void);
49 extern char ruleNumber4[WORDMAXLN]; /* ipfw rule number in string form */
50 extern char ruleNumber6[WORDMAXLN]; /* ip6fw rule number in string form */
51 extern char language[WORDMAXLN]; /* message language */
53 int ipType=IPV4; /* using IP type */
54 int listenfd[2]; /* file descriptor for listen port */
55 int hasSock6=TRUE; /* can get the socket for IPv6 */
56 int connfd; /* file descriptor for connection port */
57 int connectMode = NOCONNECT; /* the TCP connection mode */
58 char previousHello[BUFFMAXLN]; /* save previous hello request string */
60 struct AlarmArg{ /* arguments used in on-alarm functions */
61 struct clientAddr *pClientAddr;
68 int ipStatus; /* ipv4 ipv6 or dual */
73 int helloWait=FALSE; /* hello reply waiting mode */
74 int readHelloTime=0; /* the time of reading hello */
75 int sendHelloTime=0; /* the time of sending hello */
76 int noReplyCount=0; /* count up the no reply to hello message */
78 int checkBasicAlarmRinged=FALSE;
79 int checkHttpAlarmRinged=FALSE;
82 /*******************************************************/
83 /* get temporary listen port of this server */
84 /* opengate uses specific server port for each client */
85 /*******************************************************/
86 int getListenPort(void)
88 struct sockaddr_in servaddr4;
89 struct sockaddr_in6 servaddr6;
90 extern const struct in6_addr in6addr_any;
96 bzero(&servaddr4, sizeof(servaddr4));
97 bzero(&servaddr6, sizeof(servaddr6));
99 servaddr4.sin_family=AF_INET;
100 servaddr4.sin_addr.s_addr=htonl(INADDR_ANY);
102 servaddr6.sin6_family=AF_INET6;
103 servaddr6.sin6_addr=in6addr_any;
105 /* get port search range from config file */
106 portmin=atoi(GetConfValue("ListenPort/Min"));
107 portmax=atoi(GetConfValue("ListenPort/Max"));
109 /* search unused port between PORTMIN and PORTMAX */
110 for(portNo=portmin; portNo<=portmax; portNo++){
111 servaddr4.sin_port=htons(portNo);
112 servaddr6.sin6_port=htons(portNo);
114 listenfd[0]=Socket(AF_INET, SOCK_STREAM, 0);
115 listenfd[1]=Socket(AF_INET6, SOCK_STREAM, 0);
117 if(listenfd[0]<0) return -1; /* if error, return */
118 if(listenfd[1]<0) hasSock6=FALSE; /* IPv6 disabled */
121 /* case of socket IPv6 is enabled */
122 if(listenfd[0]>=FD_SETSIZE && listenfd[1]>=FD_SETSIZE) return -1;
124 if((bind(listenfd[0], (SA *)&servaddr4, sizeof(servaddr4))==0) &&
125 (bind(listenfd[1], (SA *)&servaddr6, sizeof(servaddr6))==0) ){
133 /* case of socket IPv6 is disabled */
134 if(listenfd[0]>=FD_SETSIZE) return -1;
135 if(bind(listenfd[0], (SA *)&servaddr4, sizeof(servaddr4))==0)break;
141 if(portNo>portmax) return -1; /* cannot get unused port */
143 if(Listen(listenfd[0], LISTENQ)<0) return -1; /* if error, return */
145 if(Listen(listenfd[1], LISTENQ)<0) return -1;
150 /******************************************************/
151 /* wait connection from client side Ajax type program */
152 /* if no connection, return after some delay. */
153 /* this function makes direct tcp connection to client*/
154 /* (not via web server) to keep long term connection */
155 /******************************************************/
156 int waitClientConnect(char *userid, char *userProperty, char *sessionId, char *clientAddr4, char *clientAddr6, int duration, char *macAddr4, char *macAddr6, int ipStatus, struct clientAddr *pClientAddr, char *language, int port, int pid, int cookieAuth, char *redirectedUrl)
158 char buff[BUFFMAXLN]; /* read in buffer */
159 char connectAddr[ADDRMAXLN]; /* connected client address */
160 char httpStr[BUFFMAXLN]; /* HTTP GET string at terminate */
161 int timeSendHttpkeep=0;
164 timeStart=time(NULL);
166 /* set arguments sending to alarm function */
167 alarmArg.pClientAddr=pClientAddr;
168 alarmArg.clientAddr4=clientAddr4;
169 alarmArg.clientAddr6=clientAddr6;
170 alarmArg.macAddr4=macAddr4;
171 alarmArg.macAddr6=macAddr6;
172 alarmArg.userid=userid;
173 alarmArg.userProperty=userProperty;
174 alarmArg.ipStatus=ipStatus;
175 alarmArg.checkInterval=atoi(GetConfValue("ActiveCheckInterval"));
176 alarmArg.noPacketInterval=atoi(GetConfValue("NoPacketInterval"));
178 /* set no conection initially */
179 connectMode=NOCONNECT;
181 /* set the alarm for usage time limit */
182 /* (at no ajax connection, the gate is closed after the duration) */
183 AddAlarm("UsageTimeLimitAlarm",duration,FALSE,OnUsageTimeLimitAlarm);
185 /* set the alarm for periodic keep alive check */
186 AddAlarm("CheckBasicAlarm", alarmArg.checkInterval, FALSE, OnCheckBasicAlarm);
188 /* loop until accepting correct user */
189 /* the connectMode is changed to ENDCONNECT when UsageTimeLimitAlarm rings */
190 while(connectMode == NOCONNECT){
195 /* wait connection in this function */
196 connfd = SelectAccept();
198 /* wait is eterminated when connection-arrived or alarm-ringed */
202 /* negative return means fail-connection (an error/interupt occurs) */
206 if(checkBasicAlarmRinged) CheckBasic();
212 /* reaching this point means real-connection (not an error/interupt) */
213 /* is it from the correct client addr (the check is skipped for IPv6) */
214 if(ipType==IPV4 && ipStatus!=IPV6ONLY){
215 GetPeerAddr(connfd, connectAddr);
216 if(isNull(connectAddr)||strcmp(connectAddr, clientAddr4)!=0){
222 /* reaching this point means real-connection from correct client */
223 /* set read wait alarm */
224 AddAlarm("ReadWaitAlarm",atoi(GetConfValue("CommWaitTimeout")),
225 TRUE, OnReadWaitAlarm);
228 /* get string from connection */
229 if(readln(connfd, buff, BUFFMAXLN) <0){
230 /* if abnormal, wait next request */
234 RemoveAlarm("ReadWaitAlarm");
236 /* is it the httpkeep page download request */
237 /* the request is [GET /httpkeep.html ....] */
238 snprintf(httpStr, BUFFMAXLN, "GET /httpkeep-%s-%s", userid,sessionId);
239 if(strstr(buff, httpStr)==buff){
241 /* if so, read out the remained headers and send the httpkeep page */
243 SendHttpKeepPage(userid, sessionId, language, port, cookieAuth,
245 timeSendHttpkeep=time(NULL);
247 /* return to wait next request (that night be GET /hello..) */
252 /* is it hello request from javascript in httpkeep.html */
253 if(strstr(buff, "GET /hello-")==buff){
255 /* if so, read out the remained headers */
258 /* if the hello request is premature or too late, ignore the request */
259 if((timeSendHttpkeep == 0)||
260 (time(NULL)-timeSendHttpkeep)> atoi(GetConfValue("CommWaitTimeout"))){
265 /* if received key is incorrect, ignore the request */
266 /* [GET /hello-key1-key2 ..] */
267 if( IsRightKey(buff+strlen("GET /hello-"), sessionId)==FALSE){
272 /* exit loop and enter to the Http watch mode. the connection is keeped (not closed) */
273 /* reply to the hello request are executed in WaitHttpClose routine */
274 connectMode=HTTPCONNECT;
278 /* is it the termination request */
279 /* the request is [GET /terminate-<pid> ..] */
280 snprintf(httpStr, BUFFMAXLN, "GET /terminate-%d", pid);
282 /* if terminate request found, send reply and exit loop */
283 if(strstr(buff, httpStr)==buff){
284 SendTerminateReply();
285 connectMode=ENDCONNECT;
290 /* other request is ignored */
291 if(strstr(buff, "GET /")==buff){
299 /* at exiting loop, stop all alarms */
305 /****************************/
306 /* wait for TCP connection */
307 /****************************/
308 int selectAccept(void)
312 int smax; /* select max descliptor */
313 fd_set rfd0; /* fd_set for select */
315 struct sockaddr_storage cliaddr; /* client IP adddress */
316 socklen_t len = sizeof(cliaddr);
320 FD_SET(listenfd[0], &rfd0);
321 if(hasSock6) FD_SET(listenfd[1], &rfd0);
324 if(listenfd[0]>listenfd[1]) smax=listenfd[0]+1;
325 else smax=listenfd[1]+1;
330 /* wait connection */
331 if((n = select(smax, &rfd0, NULL, NULL, NULL)) > 0){
333 /* connect by ipv4 */
334 if(FD_ISSET(listenfd[0], &rfd0)){
335 if((connfd1=accept(listenfd[0],(struct sockaddr *)&cliaddr, &len))>=0){
340 /* connect by ipv6 */
342 if(FD_ISSET(listenfd[1], &rfd0)){
343 if((connfd2=accept(listenfd[1],(struct sockaddr *)&cliaddr, &len))>=0){
350 if(connfd1>=0 && connfd2>=0){
354 else if(connfd1>=0 && connfd2<0) return connfd1;
355 else if(connfd1<0 && connfd2>=0) return connfd2;
360 /******************************/
361 /* called at usage time limit */
362 /******************************/
363 void onUsageTimeLimitAlarm(int signo)
365 connectMode=ENDCONNECT;
366 err_msg("ERR at %s#%d: duration timeout",__FILE__,__LINE__);
369 /**********************************/
370 /* called at read wait time limit */
371 /**********************************/
372 void onReadWaitAlarm(int signo)
374 connectMode=ENDCONNECT;
377 /***************************************/
378 /* called at ajax request wait timeout */
379 /***************************************/
380 void onAjaxWaitAlarm(int signo)
382 connectMode=NOCONNECT;
385 /***************************************/
386 /* called at periodic alive basic check */
387 /***************************************/
388 void onCheckBasicAlarm(int signo)
390 checkBasicAlarmRinged=TRUE;
393 /******************************/
394 /* periodic alive basic check */
395 /******************************/
396 void checkBasic(void)
398 static int packetCountPrev=0; /* packet count at previous check */
399 int packetCountNow=0; /* packet count at now */
400 static int noPacketIntervalCount=0; /* no packet count in check loop */
401 static int firstCheck=TRUE;
402 int duplicateRule4,duplicateRule6;
405 /* search new IPv6 addresses */
406 ScanNdpEntry(alarmArg.pClientAddr, alarmArg.userid,
407 alarmArg.macAddr6, alarmArg.userProperty);
409 /* mac address check */
410 if(MacAddrCheck(alarmArg.ipStatus,
411 alarmArg.clientAddr4, alarmArg.clientAddr6,
412 alarmArg.macAddr4, alarmArg.macAddr6)==FALSE){
413 connectMode=ENDCONNECT;
417 /* packet flow check */
418 packetCountNow=GetPacketCount(alarmArg.pClientAddr);
419 if(packetCountNow==packetCountPrev){ /* no packet between checks */
420 noPacketIntervalCount++;
422 noPacketIntervalCount=0;
423 packetCountPrev=packetCountNow;
426 if(noPacketIntervalCount*alarmArg.checkInterval
427 >= alarmArg.noPacketInterval){
428 err_msg("ERR at %s#%d: no packet passed for the client",
430 connectMode=ENDCONNECT;
434 /* duplicated session check */
435 /* this is added for ios behavior */
436 /* (duplication of ios web-auth and user web-auth) */
437 /* if dup, the process in basic mode is ended */
440 if( FindDuplicateInDbAndClose(alarmArg.clientAddr4,
441 &duplicateRule4, &duplicateRule6, &otherPid) ){
443 /* the process exists (ret==0 means the existence) */
444 if(kill(otherPid, 0)==0){
446 /* remove my rules and return as duplicated */
447 RemoveDuplicateRule(duplicateRule4, duplicateRule6);
448 err_msg("ERR at %s#%d: duplicated ipfw rules for %s are removed",
449 __FILE__,__LINE__, alarmArg.clientAddr4);
450 connectMode=DUPLICATED;
453 /* the process does not exist */
455 FixProcessEndInDb(otherPid, "NONE");
460 /* set the alarm for next periodic keep alive check */
461 checkBasicAlarmRinged=FALSE;
462 AddAlarm("CheckBasicAlarm", alarmArg.checkInterval, FALSE, OnCheckBasicAlarm); /* EnableAlarm is called automatically in alarm function */
465 /***************************************/
466 /* check mac address change */
467 /***************************************/
468 int macAddrCheck(int ipStatus, char *clientAddr4, char *clientAddr6, char *macAddr4, char *macAddr6)
470 char macAddrNow[ADDRMAXLN]; /* MAC address at now */
472 if(ipStatus!=IPV6ONLY){
473 /* check mac address from arp */
474 GetMacAddrFromArp(clientAddr4, macAddrNow);
475 if(*macAddrNow!='?' && strcmp(macAddr4, macAddrNow)!=0){
476 err_msg("ERR at %s#%d: mac address is changed",__FILE__,__LINE__);
477 connectMode=ENDCONNECT;
481 /* check mac address from ndp */
482 GetMacAddrFromNdp(clientAddr6, macAddrNow);
483 if(*macAddrNow!='?' && strcmp(macAddr6, macAddrNow)!=0){
484 err_msg("ERR at %s#%d: mac address is changed",__FILE__,__LINE__);
485 connectMode=ENDCONNECT;
492 /******************************************/
493 /* get address of connected remote site */
494 /******************************************/
495 void getPeerAddr(int sockfd, char *peerAddr)
497 struct sockaddr *cliaddr;
501 *peerAddr='\0'; /* set null string */
503 if((cliaddr=Malloc(ADDRMAXLN))==NULL) return; /* if error, return */
506 if(Getpeername(sockfd, cliaddr, &len)<0) return; /* if error, return */
508 pAddr=Sock_ntop_host(cliaddr, len);
509 if(pAddr!=NULL) strlcpy(peerAddr, pAddr, ADDRMAXLN);
517 /**********************************************************/
518 /* send reply to terminate access via connfd (not stdout) */
519 /* simulate web server response */
520 /**********************************************************/
521 void sendTerminateReply(void)
523 /* send HTTP headers */
524 Writefmt(connfd,"HTTP/1.1 200 OK\r\n");
525 Writefmt(connfd,"Connection: Close\r\n");
526 Writefmt(connfd,"Content-Type: text/html\r\n");
527 Writefmt(connfd,"Content-Length: 92\r\n");
528 Writefmt(connfd,"\r\n");
530 Writefmt(connfd,"<META HTTP-EQUIV=Pragma CONTENT=no-cache>");
531 Writefmt(connfd,"<HTML><BODY> Network is closed. </BODY></HTML> \r\n\r\n");
535 /***************************************************/
536 /* send quit to client and close connection */
537 /***************************************************/
538 void sendQuitClient(void)
540 Writefmt(connfd,"quit\r\n");
544 /************************************************************/
545 /* wait for close connection */
546 /* this function keeps direct tcp connection to client Ajax */
547 /* (not via web server) */
548 /* execute periodic hello exchange in HTTP format */
549 /************************************************************/
550 void waitHttpClose(struct clientAddr *pClientAddr, char *userid, char *userProperty, char *macAddr4, char *macAddr6, int ipStatus, char *sessionId, int port)
552 char buff[BUFFMAXLN];
555 /* set alarm function arguments */
556 alarmArg.pClientAddr=pClientAddr;
557 alarmArg.macAddr4=macAddr4;
558 alarmArg.macAddr6=macAddr6;
559 alarmArg.userid=userid;
560 alarmArg.userProperty=userProperty;
561 alarmArg.ipStatus=ipStatus;
562 alarmArg.checkInterval=atoi(GetConfValue("ActiveCheckInterval"));
564 /* save the time of read hello */
565 readHelloTime = time(NULL);
567 /* send first reply to hello (corresponding request is in WaitClientConnect)*/
568 SendReplyToGetHello();
569 sendHelloTime = time(NULL);
571 /* set the hello wait mode ON */
574 /* TCP read/write loop */
575 /* this loop implement following logic */
576 /* repeat until receiving 'GET /terminate' or EOF from client */
577 /* wait request from client. */
578 /* if wait timeout, then quit */
579 /* if 'GET /hello' request, then send reply */
580 /* if 'GET /terminate' request, then quit */
581 /* if connection closed, then quit */
583 /* set the alarm for periodic client check */
584 AddAlarm("checkHttpAlarm", alarmArg.checkInterval, FALSE, OnCheckHttpAlarm);
587 /* loop until end connection */
588 while(connectMode!=ENDCONNECT){
590 /* set default to unknown */
591 connectMode=NOCONNECT;
593 /* read wait for client request */
594 ret=readln(connfd, buff, BUFFMAXLN);
596 /* at recieve, stop alarm between readin check*/
602 /* is it [GET /hello] */
603 if(strstr(buff,"GET /hello") == buff){
605 /* if so, read out the remained headers */
608 /* if retry request (having same key as previous) */
609 if(strncmp(buff, previousHello, BUFFMAXLN)==0) {
611 /*SendReplyToGetHello();*/
612 /* some mulfunction on communication. reset connection */
613 connectMode=NOCONNECT;
615 AcceptHttpReConnect(atoi(GetConfValue("CommWaitTimeout")));
619 /* save hello request string including keys */
620 strlcpy(previousHello, buff, BUFFMAXLN);
622 /* if received key is correct */
623 if(IsRightKey(buff+strlen("GET /hello-"), sessionId)){
625 /* recognize HTTP hello request */
626 connectMode=HTTPCONNECT;
628 /* save time to read hello */
629 readHelloTime = time(NULL);
631 /* set the hello wait mode OFF */
635 /* if key is incorrect, terminate */
637 connectMode=ENDCONNECT;
641 /* read other string */
644 /* read request and reply not found */
645 if(strstr(buff,"GET /") == buff){
649 err_msg("ERR at %s#%d: Unknown request",__FILE__,__LINE__);
650 connectMode=NOCONNECT;
652 AcceptHttpReConnect(atoi(GetConfValue("CommWaitTimeout")));
658 /* some alarm is ringed or connecion is closed */
661 if(checkHttpAlarmRinged) CheckHttp();
663 /* if no connection, retry connect */
664 if(connectMode==NOCONNECT){
666 /* wait short time to accept reconnection */
667 /* (to permit occasional disconnection at exchanging hello) */
670 AcceptHttpReConnect(atoi(GetConfValue("ReconnectTimeout")));
672 AcceptHttpReConnect(atoi(GetConfValue("CommWaitTimeout")));
689 /******************************************/
690 /* accept http reconnect */
691 /* to cope with accidental disconnection */
692 /* permit reconnection with short delay */
693 /******************************************/
694 void acceptHttpReConnect(int timeout){
698 startTime=time(NULL);
700 /* timeout value should be positive */
702 connectMode=ENDCONNECT;
706 /* wait a short time */
707 AddAlarm("ReadWaitAlarm", timeout, TRUE, OnReadWaitAlarm);
710 /* connection wait */
711 connfd = SelectAccept();
713 /* receive request */
714 RemoveAlarm("ReadWaitAlarm");
715 if(connfd<0){ /* timeout or abnormal */
716 connectMode=ENDCONNECT;
717 }else{ /* reconnected */
718 connectMode=HTTPCONNECT;
719 RemoveAlarm("CheckHttpAlarm");
720 AddAlarm("CheckHttpAlarm", alarmArg.checkInterval, FALSE, OnCheckHttpAlarm);
724 /*****************************************************************/
725 /* simple override check by exchanging keys */
726 /* Is the sent client key correct */
727 /* request string is as follows */
728 /* GET /hello-11111111111111111111-2222222222222222222 HTTP... */
729 /* MD5digest(32chars) MD5digest(32chars) */
733 /* save sid <------------------- sid */
734 /* md5(sid)+md5(md5(rand1)+sid) ---------> check nowkey */
736 /* md5(rand1)+md5(md5(rand2)+sid)---------> check nowkey */
738 /* md5(rand2)+md5(md5(rand3)+sid)---------> check nowkey */
740 /*****************************************************************/
741 int isRightKey(char *arg, char *sessionId)
743 static char savedKey[33]=""; /* saved MD5 string */
744 char tempbuff[BUFFMAXLN]; /* work area */
745 char md5work[33] ; /* md5 work */
749 /* initial value of savedKey is md5(md5(sessionId)+sessionId) */
750 if(isNull(savedKey)){
751 md5hex(tempbuff, 33, sessionId);
752 strlcat(tempbuff, sessionId, BUFFMAXLN);
753 md5hex(savedKey, 33, tempbuff);
756 /* split NowKey and NextKey in argument */
757 /* 32 is the length of MD5 result */
763 /* make string [nowKey+sessionId] */
764 strlcpy(tempbuff, pNowKey, BUFFMAXLN);
765 strlcat(tempbuff, sessionId, BUFFMAXLN);
767 /* compare savedKey and md5(nowKey+sessionId) */
768 if(strcmp(savedKey, md5hex(md5work, 33, tempbuff))==0){
770 /* save nextKey for next check */
771 strlcpy(savedKey, pNextKey, 33);
779 /***************************************/
780 /* called at periodic http alive check */
781 /***************************************/
782 void onCheckHttpAlarm(int signo)
784 checkHttpAlarmRinged=TRUE;
787 /***************************************/
788 /* called at periodic http alive check */
789 /***************************************/
792 /* at this timing, hello request might be received */
793 /* if in hello wait mode, it is abnormal */
795 connectMode=NOCONNECT;
799 /* send delayed reply to hello request */
800 SendReplyToGetHello();
802 /* save time to send hello */
803 sendHelloTime = time(NULL);
805 /* set the hello wait mode ON */
808 /* search new IPv6 addresses */
809 ScanNdpEntry(alarmArg.pClientAddr, alarmArg.userid,
810 alarmArg.macAddr6, alarmArg.userProperty);
812 /* mac address check */
813 if(MacAddrCheck(alarmArg.ipStatus,
814 alarmArg.clientAddr4, alarmArg.clientAddr6,
815 alarmArg.macAddr4, alarmArg.macAddr6)==FALSE){
816 connectMode=ENDCONNECT;
820 /* set the alarm for next periodic check */
821 checkHttpAlarmRinged=FALSE;
822 AddAlarm("CheckHttpAlarm", alarmArg.checkInterval, FALSE, OnCheckHttpAlarm);
823 /* EnableAlarm is called automatically in alarm function */
826 connectMode = HTTPCONNECT;
830 /***************************************************/
831 /* read and skip Http headers (ended by null line) */
832 /***************************************************/
833 void readHttpHeaders(void)
835 char buff[BUFFMAXLN]; /* read in buffer */
838 /* read until null line (only CRLF code) */
839 while((n=readln(connfd, buff, BUFFMAXLN))>0){
844 /********************************************************/
845 /* send hello to client for replying GET /hello request */
846 /* simulate web server response in chunked mode */
847 /********************************************************/
848 void sendReplyToGetHello(void)
850 /* send HTTP headers */
851 Writefmt(connfd,"HTTP/1.1 200 OK\r\n");
852 Writefmt(connfd,"Transfer-Encoding: chunked\r\n");
853 Writefmt(connfd,"Keep-Alive: timeout=300\r\n");
854 Writefmt(connfd,"Connection: Keep-Alive\r\n");
855 Writefmt(connfd,"Content-Type: text/html\r\n");
856 Writefmt(connfd,"\r\n");
858 /* send reply to hello */
859 Writefmt(connfd,"5\r\n");
860 Writefmt(connfd,"hello\r\n");
862 /* send end of chunk */
863 Writefmt(connfd,"0\r\n");
864 Writefmt(connfd,"\r\n");
867 /***************************************************/
868 /* send httpkeep page to client via connfd */
869 /* after variables in template file are replaced */
870 /* simulate web server response */
871 /***************************************************/
872 void sendHttpKeepPage(char *userid, char *sessionId, char *language, int port, int cookieAuth, char *redirectedUrl)
874 char buff[BUFFMAXLN]; /* read in buffer */
877 char httpKeepDoc[BUFFMAXLN];
878 char httpHelloUrl[BUFFMAXLN];
879 char terminateUrl[BUFFMAXLN];
880 char acceptDoc2Url[BUFFMAXLN];
881 char httpkeepJsUrl[BUFFMAXLN];
882 char md5JsUrl[BUFFMAXLN];
883 char portStr[WORDMAXLN];
884 char *startPageUrl="";
885 int startPageType=atoi(GetConfValue("StartPage/Type"));
887 char *opengateServerName=GetConfValue("OpengateServerName");
888 char *opengateDir=GetConfValue("OpengateDir");
889 char useridshort[USERMAXLN];
890 char extraId[USERMAXLN];
892 /* split id to display short format of userid */
893 SplitId(userid, useridshort, extraId);
895 /* create path to accept2 doc */
896 snprintf(acceptDoc2Url, BUFFMAXLN,
897 "http://%s%s/%s/%s",opengateServerName,
898 opengateDir,language,GetConfValue("AcceptDoc2"));
900 /* create terminate url [http://<servaddr>:<port>/terminate-<pid>] */
901 snprintf(terminateUrl, BUFFMAXLN, "http://%s:%d/terminate-%d",
902 opengateServerName, port, getpid());
904 /* create httphello url [http://<servaddr>:<port>/hello] */
905 snprintf(httpHelloUrl, BUFFMAXLN, "http://%s:%d/hello",
906 opengateServerName, port);
908 /* create httpkeep.js url[http://<serveraddr>/opengate/httpkeep.js] */
909 snprintf(httpkeepJsUrl, BUFFMAXLN, "http://%s%s/%s",
911 opengateDir,GetConfValue("HttpKeepJS"));
913 /* create md5.js url[http://<serveraddr>/opengate/md5.js] */
914 snprintf(md5JsUrl, BUFFMAXLN, "http://%s%s/%s",
916 opengateDir,GetConfValue("Md5JS"));
918 /* create path to httpkeep doc */
919 snprintf(httpKeepDoc,BUFFMAXLN, "%s%s/%s/%s",GetConfValue("DocumentRoot"),
920 opengateDir,language,GetConfValue("HttpKeepDoc"));
922 /* create port string */
923 snprintf(portStr, WORDMAXLN, "%d", port);
925 /* open httpkeepdoc */
926 if((fp=fopen(httpKeepDoc, "r"))==NULL){
927 err_msg("ERR at %s#%d: cannot open %s",__FILE__,__LINE__,httpKeepDoc);
928 PutClientMsg("Cannot find html document");
932 /* if redirect page is not set, use other setting */
933 if(isNull(redirectedUrl)){
934 if(isNull(GetConfValue("StartPage/Url"))) redirectedUrl=acceptDoc2Url;
935 else redirectedUrl=GetConfValue("StartPage/Url");
938 /* create start page url to put information */
939 if(cookieAuth==1) startPageUrl=redirectedUrl;
940 else if(startPageType==0) startPageUrl=acceptDoc2Url;
941 else if(startPageType==1) startPageUrl=GetConfValue("StartPage/Url");
942 else if(startPageType==2) startPageUrl=redirectedUrl;
943 else startPageUrl=acceptDoc2Url;
945 /* send HTTP headers */
946 Writefmt(connfd,"HTTP/1.1 200 OK\r\n");
947 Writefmt(connfd,"Transfer-Encoding: chunked\r\n");
948 Writefmt(connfd,"Keep-Alive: timeout=300\r\n");
949 Writefmt(connfd,"Connection: Keep-Alive\r\n");
950 Writefmt(connfd,"Content-Type: text/html\r\n");
951 Writefmt(connfd,"\r\n");
953 while(fgets(buff, BUFFMAXLN, fp)!=NULL){
956 if(strlen(buff)>=BUFFMAXLN-1){
957 err_msg("ERR at %s#%d: too long line in %s",__FILE__,__LINE__,
962 htmlReplace(buff, "%%OPENGATESERVERNAME%%", opengateServerName);
963 htmlReplace(buff, "%%HTTPHELLOURL%%", httpHelloUrl);
964 htmlReplace(buff, "%%USERID%%", useridshort);
965 htmlReplace(buff, "%%SESSIONID%%", sessionId);
966 htmlReplace(buff, "%%TERMINATEURL%%", terminateUrl);
967 htmlReplace(buff, "%%HTTPKEEPJSURL%%", httpkeepJsUrl);
968 htmlReplace(buff, "%%MD5JSURL%%", md5JsUrl);
970 htmlReplace(buff, "%%OPENGATEDIR%%", opengateDir);
971 htmlReplace(buff, "%%OPENGATEPORT%%", portStr);
972 htmlReplace(buff, "%%LANGUAGE%%", language);
973 htmlReplace(buff, "%%STARTURL%%", startPageUrl);
974 htmlReplace(buff, "%%COOKIENAME%%", COOKIENAME);
975 htmlReplace(buff, "%%REDIRECTEDURL%%", redirectedUrl);
977 /* length of chunk in hex */
978 Writefmt(connfd, "%x\r\n", strlen(buff));
979 /* the chunk content */
980 Writefmt(connfd, "%s\r\n", buff);
984 Writefmt(connfd,"0\r\n");
985 Writefmt(connfd,"\r\n");
991 /*************************************************************/
992 /* send reply to unknown http request eg:[GET /favico.ico..] */
993 /* simulate web server response in chunked mode */
994 /*************************************************************/
995 void sendHttpReply(char *reply)
997 /* send HTTP headers */
998 Writefmt(connfd,"HTTP/1.1 200 OK\r\n");
999 Writefmt(connfd,"Transfer-Encoding: chunked\r\n");
1000 Writefmt(connfd,"Keep-Alive: timeout=300\r\n");
1001 Writefmt(connfd,"Connection: Keep-Alive\r\n");
1002 Writefmt(connfd,"Content-Type: text/html\r\n");
1003 Writefmt(connfd,"\r\n");
1006 /* length of chunk in hex */
1007 Writefmt(connfd, "%x\r\n", strlen(reply));
1008 /* the chunk content */
1009 Writefmt(connfd, "%s\r\n", reply);
1013 Writefmt(connfd,"0\r\n");
1014 Writefmt(connfd,"\r\n");
1017 /*************************************************************/
1018 /* send NOT FOUND reply to unknown http request */
1019 /* simulate web server response */
1020 /*************************************************************/
1021 void sendHttpNotFound(void)
1023 /* send HTTP headers */
1024 Writefmt(connfd,"HTTP/1.1 404\r\n");
1025 Writefmt(connfd,"\r\n");
1030 /***************************************************/
1031 /***************************************************/
1032 void GetPeerAddr(int sockfd, char *peerAddr)
1034 if(debug>1) err_msg("DEBUG:=>getPeerAddr( )");
1035 getPeerAddr(sockfd,peerAddr);
1036 if(debug>1) err_msg("DEBUG:<=getPeerAddr(,%s)",peerAddr);
1040 int GetListenPort(void)
1044 if(debug>1) err_msg("DEBUG:=>getListenPort( )");
1045 ret=getListenPort();
1046 if(debug>1) err_msg("DEBUG:(%d)<=getListenPort( )",ret);
1051 int WaitClientConnect(char *userid, char *userProperty, char *sessionId, char *clientAddr4, char *clientAddr6, int duration, char *macAddr4, char *macAddr6, int ipStatus, struct clientAddr *pClientAddr, char *language, int port, int pid, int cookieAuth, char *redirectedUrl)
1055 if(debug>1) err_msg("DEBUG:=>waitClientConnect(%s,%s,%s,%s,%s,%d,%s,%s,%d,%s,%d,%d,%d,%s)",userid,userProperty,sessionId,clientAddr4,clientAddr6,duration,macAddr4,macAddr6,ipStatus,language,port,pid,cookieAuth,redirectedUrl);
1056 ret=waitClientConnect(userid,userProperty,sessionId,clientAddr4,clientAddr6,duration,macAddr4,macAddr6,ipStatus,pClientAddr,language,port,pid,cookieAuth,redirectedUrl);
1057 if(debug>1) err_msg("DEBUG:(%d)<=waitClientConnect( )",ret);
1062 void SendQuitClient(void)
1064 if(debug>1) err_msg("DEBUG:=>sendQuitClient( )");
1066 if(debug>1) err_msg("DEBUG:<=sendQuitClient( )");
1069 void SendTerminateReply(void)
1071 if(debug>1) err_msg("DEBUG:=>sendTerminateReply( )");
1072 sendTerminateReply();
1073 if(debug>1) err_msg("DEBUG:<=sendTerminateReply( )");
1076 void WaitHttpClose(struct clientAddr *pClientAddr, char *userid, char *userProperty, char *macAddr4, char *macAddr6, int ipStatus, char *sessionid, int port)
1078 if(debug>1) err_msg("DEBUG:=>waitHttpClose(%p,%s,userProperty,%s,%s,%d,%s,%d)",pClientAddr,userid,macAddr4,macAddr6,ipStatus, sessionid, port);
1079 waitHttpClose(pClientAddr,userid,userProperty,macAddr4,macAddr6,ipStatus, sessionid, port);
1080 if(debug>1) err_msg("DEBUG:<=waitHttpClose( )");
1084 void ReadHttpHeaders(void)
1086 if(debug>1) err_msg("DEBUG:=>readHttpHeaders( )");
1088 if(debug>1) err_msg("DEBUG:<=readHttpHeaders( )");
1091 void SendReplyToGetHello(void)
1093 if(debug>1) err_msg("DEBUG:=>sendReplyToGetHello( )");
1094 sendReplyToGetHello();
1095 if(debug>1) err_msg("DEBUG:<=sendReplyToGetHello( )");
1098 void SendHttpKeepPage(char *userid, char *sessionId, char *language, int port, int cookieAuth, char *redirectedUrl)
1100 if(debug>1) err_msg("DEBUG:=>sendHttpKeepPage(%s,%s,%s,%d,%d,%s)", userid, sessionId, language, port, cookieAuth, redirectedUrl);
1101 sendHttpKeepPage(userid, sessionId, language, port, cookieAuth, redirectedUrl);
1102 if(debug>1) err_msg("DEBUG:<=sendHttpKeepPage( )");
1106 void OnUsageTimeLimitAlarm(int signo){
1108 if(debug>1) err_msg("DEBUG:=>onUsageTimeLimitAlarm()");
1109 onUsageTimeLimitAlarm(signo);
1110 if(debug>1) err_msg("DEBUG:<=onUsageTimeLimitAlarm()");
1113 void OnCheckBasicAlarm(int signo){
1115 if(debug>1) err_msg("DEBUG:=>onCheckBasicAlarm()");
1116 onCheckBasicAlarm(signo);
1117 if(debug>1) err_msg("DEBUG:<=onCheckBasicAlarm()");
1120 void CheckBasic(void){
1122 if(debug>1) err_msg("DEBUG:=>checkBasic()");
1124 if(debug>1) err_msg("DEBUG:<=checkBasic()");
1127 void OnCheckHttpAlarm(int signo){
1129 if(debug>1) err_msg("DEBUG:=>onCheckHttpAlarm()");
1130 onCheckHttpAlarm(signo);
1131 if(debug>1) err_msg("DEBUG:<=onCheckHttpAlarm()");
1134 void CheckHttp(void){
1136 if(debug>1) err_msg("DEBUG:=>checkHttp()");
1138 if(debug>1) err_msg("DEBUG:<=checkHttp()");
1141 void OnReadWaitAlarm(int signo){
1143 if(debug>1) err_msg("DEBUG:=>onReadWaitAlarm()");
1144 onReadWaitAlarm(signo);
1145 if(debug>1) err_msg("DEBUG:<=onReadWaitAlarm()");
1148 void OnAjaxWaitAlarm(int signo){
1150 if(debug>1) err_msg("DEBUG:=>onAjaxWaitAlarm()");
1151 onAjaxWaitAlarm(signo);
1152 if(debug>1) err_msg("DEBUG:<=onAjaxWaitAlarm()");
1155 int SelectAccept(void){
1158 if(debug>1) err_msg("DEBUG:=>selectAccept()");
1160 if(debug>1) err_msg("DEBUG:(%d)<=selectAccept()",ret);
1165 void AcceptHttpReConnect(int timeout){
1166 if(debug>1) err_msg("DEBUG:=>acceptHttpReConnect(%d)",timeout);
1167 acceptHttpReConnect(timeout);
1168 if(debug>1) err_msg("DEBUG:<=acceptHttpReConnect()");
1171 int MacAddrCheck(int ipStatus, char *clientAddr4, char *clientAddr6, char *macAddr4, char *macAddr6) {
1174 if(debug>1) err_msg("DEBUG:=>macAddrCheck(%d,%s,%s,%s,%s)",
1175 ipStatus, clientAddr4, clientAddr6, macAddr4, macAddr6);
1176 ret=macAddrCheck(ipStatus, clientAddr4, clientAddr6, macAddr4, macAddr6);
1177 if(debug>1) err_msg("DEBUG:(%d)<=macAddrCheck()",ret);
1182 int IsRightKey(char *pNowKey, char *sessionId){
1185 if(debug>1) err_msg("DEBUG:=>isRightKey(%s,%s)", pNowKey, sessionId);
1186 ret=isRightKey(pNowKey, sessionId);
1187 if(debug>1) err_msg("DEBUG:(%d)<=isRightKey()",ret);
1192 void SendHttpReply(char *reply){
1193 if(debug>1) err_msg("DEBUG:=>sendHttpRepy(%s)", reply);
1194 sendHttpReply(reply);
1195 if(debug>1) err_msg("DEBUG:<=sendHttpReply()");
1199 void SendHttpNotFound(void){
1200 if(debug>1) err_msg("DEBUG:=>sendHttpNotFound()");
1202 if(debug>1) err_msg("DEBUG:<=sendHttpNotFound()");