# Makefile
-# Alexandre Cassen <Alexandre.Cassen@canal-plus.com>
+# Alexandre Cassen <Alexandre.Cassen@wanadoo.fr>
EXEC= genhash
CC= gcc
rm -f core *.o $(EXEC)
install:
- cp -av genhash /usr/bin/
+ cp -av genhash /usr/bin
# Makefile
-# Alexandre Cassen <Alexandre.Cassen@canal-plus.com>
+# Alexandre Cassen <Alexandre.Cassen@wanadoo.fr>
EXEC= keepalived
CC= gcc
* data structure representation the conf file representing
* the loadbalanced server pool.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: cfreader.c,v 0.2.1 2000/12/09 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
printf("Queue empty !!!\n");
else
while(lstptr != NULL) {
- bzero(tempbuff,TEMPBUFFERLENGTH);
+ memset(tempbuff,0,TEMPBUFFERLENGTH);
sprintf(tempbuff,"VS IP = %s, Port = %s, SCHED = %s, PERSISTENCE TIMEOUT = %s\n",
lstptr->addr_ip, lstptr->addr_port,
lstptr->sched, lstptr->timeout_persistence);
logmessage(tempbuff,getpid());
pointersvr=lstptr->svr;
while(lstptr->svr != NULL) {
- bzero(tempbuff,TEMPBUFFERLENGTH);
+ memset(tempbuff,0,TEMPBUFFERLENGTH);
sprintf(tempbuff," -> SVR IP = %s, Port = %s\n",lstptr->svr->addr_ip,lstptr->svr->addr_port);
logmessage(tempbuff,getpid());
- bzero(tempbuff,TEMPBUFFERLENGTH);
+ memset(tempbuff,0,TEMPBUFFERLENGTH);
sprintf(tempbuff," -> KM = %s, KA = %s, KU = %s, KR = %s\n",
lstptr->svr->keepalive_method, lstptr->svr->keepalive_url,
lstptr->svr->keepalive_algo, lstptr->svr->keepalive_result);
logmessage(tempbuff,getpid());
- bzero(tempbuff,TEMPBUFFERLENGTH);
+ memset(tempbuff,0,TEMPBUFFERLENGTH);
sprintf(tempbuff," -> LB = %s, Weight = %s, ST = %s, Alive = %d\n",
lstptr->svr->loadbalancing_kind, lstptr->svr->weight,
lstptr->svr->service_type, lstptr->svr->alive);
*
* Part: cfreader.c include file.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: cfreader.h,v 0.2.1 2000/12/09 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
* url, compute a MD5 over this result and match it to the
* expected value.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: httpget.c,v 0.2.1 2000/12/09 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
return(SOCKET_ERROR);
}
- bzero(&adr_serv,long_inet);
+ memset(&adr_serv,0,long_inet);
adr_serv.sin_family=ip_serv->h_addrtype;
bcopy(ip_serv->h_addr, &adr_serv.sin_addr.s_addr,ip_serv->h_length);
adr_serv.sin_port=htons(atoi(PORT_DST));
int retcode=0;
bufferget=(char *)malloc(GET_BUFFER_LENGTH);
- bzero(bufferget,GET_BUFFER_LENGTH);
+ memset(bufferget,0,GET_BUFFER_LENGTH);
if ((retcode=GET(IP_SRC,IP_DST,PORT_DST,URL,bufferget))!=0) {
MD5Data(bufferget,retcode,MDResult);
*
* Part: httpget.c include file.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: httpget.h,v 0.2.1 2000/12/09 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
* Part: ICMP CHECK. Build an ICMP packet and send it to a remote
* server.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: icmpcheck.c,v 0.2.3 2001/01/01 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
* Changes:
- * Alexandre Cassen : Initial release
+ * Alexandre Cassen : 2001/01/01 :
+ * <+> Added recvfrom_to() function to handle recvfrom timeouted connection.
+ * Call this function in ICMP_RCV_ECHOREPLY with 1s timeout.
+ * <+> Added a timer (2s timeouted) in ICMP_RCV_ECHOREPLY to check
+ * ECHO_REPLY. Check perform on icmp type flag, remote ip address.
+ * <+> Added a 3 time ECHO_REQUEST send retry.
+ *
+ * Alexandre Cassen : 2000/12/09 : Initial release
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
struct timeval to;
fd_set readset,writeset;
- to.tv_sec = timo/100000;
- to.tv_usec = (timo - (to.tv_sec*100000))*10;
+ to.tv_sec = timo/1000;
+ to.tv_usec = 0;
FD_ZERO(&readset);
FD_ZERO(&writeset);
FD_SET(s,&readset);
nfound = select(s+1,&readset,&writeset,NULL,&to);
if (nfound<0) {
- //printf("select failed !!!\n");
return(-1);
}
- if (nfound==0) return -1; /* timeout */
+ if (nfound==0) return -1;
slen=sizeof(struct sockaddr);
n=recvfrom(s,buf,len,0,saddr,&slen);
- if (n<0) return -1; // printf("Error recvfrom");
+ if (n<0) return -1;
return n;
}
-int ICMP_CHECK(char dst_ip[16])
+int ICMP_SEND_ECHOREQUEST(char *IP_DST)
{
struct iphdr *ipHdr;
struct icmphdr *icmpHdr;
- struct sockaddr_in addr ;
- struct sockaddr_in response_addr ;
- struct ip *ip;
- struct icmp *icp;
+ struct sockaddr_in addr;
unsigned char *sendbuff;
- unsigned char *recvbuff;
char *debugmsg;
char on = 1;
int hlen;
debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
sendbuff = (unsigned char *)malloc(BUFFSIZE);
- bzero(sendbuff,BUFFSIZE);
+ memset(debugmsg,0,BUFFSIZE);
+ memset(sendbuff,0,BUFFSIZE);
- if( (sockfd = socket( AF_INET , SOCK_RAW , IPPROTO_ICMP )) < 0 ) {
+ if((sockfd = socket( AF_INET , SOCK_RAW , IPPROTO_ICMP )) < 0) {
free(debugmsg);
free(sendbuff);
- return(0);
+ return(SOCKET_ERROR);
}
- if( setsockopt(sockfd , IPPROTO_IP , IP_HDRINCL , &on , sizeof(on)) < 0 ) {
+ if(setsockopt(sockfd , IPPROTO_IP , IP_HDRINCL , &on , sizeof(on)) < 0) {
free(debugmsg);
free(sendbuff);
close(sockfd);
- return(0);
+ return(SOCKET_ERROR);
}
ipHdr = (struct iphdr *)sendbuff;
ipHdr->protocol = IPPROTO_ICMP;
ipHdr->check = 0 ;
- if( hostToaddr(dst_ip, &tmp) < 0 ) {
- // perror("Host to addr conversion failed!");
+ if( hostToaddr(IP_DST, &tmp) < 0 ) {
close(sockfd);
free(sendbuff);
free(debugmsg);
- return(0);
+ return(SOCKET_ERROR);
}
ipHdr->daddr = tmp;
icmpHdr->un.echo.sequence = getpid();
icmpHdr->checksum = in_cksum( (unsigned short *)icmpHdr , sizeof(struct icmphdr) );
- bzero( (char *)&addr, sizeof(addr) );
+ memset((char *)&addr,0,sizeof(addr));
addr.sin_addr.s_addr = ipHdr->daddr;
addr.sin_family = AF_INET;
- /* Add the icmp data part */
- bcopy(ICMP_DATA,sendbuff+HDRBUFFSIZE,sizeof(ICMP_DATA));
+ /* Add the icmp data part
+ memcpy(sendbuff+HDRBUFFSIZE,ICMP_DATA,sizeof(ICMP_DATA)); */
if( sendto(sockfd, sendbuff , sizeof(struct iphdr)+sizeof(struct icmphdr) , 0 , (struct sockaddr *)&addr , sizeof(addr)) < 0 ) {
- //perror("SendTo Error:");
close(sockfd);
free(sendbuff);
free(debugmsg);
- return(0);
+ return(SOCKET_ERROR);
}
- /* Handle arp request */
- sleep(DELAY_TIME);
+ close(sockfd);
+ free(sendbuff);
+ free(debugmsg);
+ return(SOCKET_SUCCESS);
+}
+
+int ICMP_RCV_ECHOREPLY(char *IP_DST)
+{
+ struct sockaddr_in response_addr ;
+ struct iphdr *ip;
+ struct icmphdr *icp;
+ unsigned char *recvbuff;
+ char *debugmsg;
+ time_t hint;
+ struct tm *date;
+ int timer_before, timer_after;
+ char on = 1;
+ int hlen;
+ int result;
+ int sockfd;
+ int loop=1;
- /* Echo reply test */
+ /* Packet pointer affectation */
+ debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
recvbuff=(char *)malloc(BUFFSIZE);
- bzero((char *)recvbuff,BUFFSIZE);
+ memset((char *)recvbuff,0,BUFFSIZE);
- result=recvfrom_wto(sockfd,recvbuff,BUFFSIZE,(struct sockaddr *)&response_addr,select_time);
+ if((sockfd = socket( AF_INET , SOCK_RAW , IPPROTO_ICMP )) < 0) {
+ free(debugmsg);
+ free(recvbuff);
+ return(SOCKET_ERROR);
+ }
+
+ if(setsockopt(sockfd , IPPROTO_IP , IP_HDRINCL , &on , sizeof(on)) < 0) {
+ free(debugmsg);
+ free(recvbuff);
+ close(sockfd);
+ return(SOCKET_ERROR);
+ }
+
+ /* Timer initialization */
+ /* We can also use a signal SIGALRM and catch this signal with handler to break the loop */
+ hint = time((long*)0);
+ date = localtime(&hint);
+ timer_before = date->tm_sec;
+
+ while(loop) {
+ result=recvfrom_wto(sockfd,recvbuff,BUFFSIZE,(struct sockaddr *)&response_addr,select_time);
#ifdef DEBUG
- if (result<0) {
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ICMP_CHECK : icmp timeout to %s...\n",dst_ip);
- logmessage(debugmsg,getpid());
- }
+ if (result<0) {
+ memset(debugmsg,0,LOGBUFFER_LENGTH);
+ sprintf(debugmsg,"ICMP_CHECK : icmp timeout to [%s]...\n",IP_DST);
+ logmessage(debugmsg,getpid());
+ }
#endif
- ip = (struct ip *)recvbuff;
+ ip = (struct iphdr *)recvbuff;
+ hlen = ip->ihl << 2;
+
+ if (result < hlen+ICMP_MINLEN) {
+#ifdef DEBUG
+ memset(debugmsg,0,LOGBUFFER_LENGTH);
+ sprintf(debugmsg,"ICMP_CHECK : Received packet too short according to ICMP protocol from [%s]...\n",IP_DST);
+ logmessage(debugmsg,getpid());
+#endif
+ }
- hlen = ip->ip_hl << 2;
+ icp = (struct icmphdr *)(recvbuff + hlen);
+ if ( (icp->type == ICMP_ECHOREPLY) &&
+ (ip->saddr == inet_addr(IP_DST)) &&
+ (result >= hlen+ICMP_MINLEN) ) {
+ close(sockfd);
+ free(recvbuff);
+ free(debugmsg);
+ return(SOCKET_SUCCESS);
+ }
- if (result < hlen+ICMP_MINLEN) {
#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ICMP_CHECK : Received packet too short according to ICMP protocol to %s...\n",dst_ip);
- logmessage(debugmsg,getpid());
+ memset(debugmsg,0,LOGBUFFER_LENGTH);
+ sprintf(debugmsg,"ICMP_CHECK : ECHO_REPLY not received from [%s] retry\n",IP_DST);
+ logmessage(debugmsg,getpid());
#endif
- close(sockfd);
- free(sendbuff);
- free(debugmsg);
- return(0);
+
+ /* timer to evaluate packet loosed */
+ hint = time((long*)0);
+ date = localtime(&hint);
+ timer_after = date->tm_sec;
+
+ if(abs(timer_after-timer_before)>1) loop=0;
}
- icp = (struct icmp *)(recvbuff + hlen);
- if (icp->icmp_type != ICMP_ECHOREPLY) {
#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ICMP_CHECK : ICMP ECHO REPLY not received from %s !!!\n",dst_ip);
- logmessage(debugmsg,getpid());
+ memset(debugmsg,0,LOGBUFFER_LENGTH);
+ sprintf(debugmsg,"ICMP_CHECK : ECHO_REPLY not received from [%s] packet losed\n",IP_DST);
+ logmessage(debugmsg,getpid());
#endif
- close(sockfd);
- free(sendbuff);
- free(debugmsg);
- return(0);
- } else {
+
+ close(sockfd);
+ free(recvbuff);
+ free(debugmsg);
+ return(SOCKET_ERROR);
+}
+
+int ICMP_CHECK(char *IP_DST)
+{
+ char *debugmsg;
+ int loop=1;
+ int retry=0;
+
+ /* Memory allocation for the data structures */
+ debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
+
+ while(loop) {
+
+ if(!ICMP_SEND_ECHOREQUEST(IP_DST)) {
+#ifdef DEBUG
+ memset(debugmsg,0,LOGBUFFER_LENGTH);
+ sprintf(debugmsg,"ICMP_CHECK : Can't send ECHO_REQUEST to [%s]\n",IP_DST);
+ logmessage(debugmsg,getpid());
+#endif
+ free(debugmsg);
+ return(SOCKET_ERROR);
+ }
+ if(ICMP_RCV_ECHOREPLY(IP_DST)) {
+ loop=0;
+ } else {
+ retry++;
+#ifdef DEBUG
+ memset(debugmsg,0,LOGBUFFER_LENGTH);
+ sprintf(debugmsg,"ICMP_CHECK : Reexpedite ECHO_REQUEST to [%s]\n",IP_DST);
+ logmessage(debugmsg,getpid());
+#endif
+ loop=(retry==NB_RETRY)?0:1;
+ }
+ }
+
+ if(retry==NB_RETRY) {
#ifdef DEBUG
memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ICMP_CHECK : ICMP ECHO REPLY recived from %s...\n",dst_ip);
+ sprintf(debugmsg,"ICMP_CHECK : ECHO_REPLY not received from [%s] after 3 try\n",IP_DST);
logmessage(debugmsg,getpid());
#endif
+ free(debugmsg);
+ return(SOCKET_ERROR);
}
- free(sendbuff);
- free(recvbuff);
free(debugmsg);
-
- close(sockfd);
- return(1);
+ return(SOCKET_SUCCESS);
}
*
* Part: icmpcheck.c include file.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: icmpcheck.h,v 0.2.1 2000/12/09 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
-#define ICMP_DATA "KeepAlive for LVS v1.0"
+#define ICMP_DATA "keepalived for LVS"
+
+#define SOCKET_ERROR 0
+#define SOCKET_SUCCESS 1
#define HDRBUFFSIZE (sizeof(struct icmphdr) + sizeof(struct iphdr))
#define BUFFSIZE (HDRBUFFSIZE + sizeof(ICMP_DATA))
#define SIZE_ICMP_HDR ICMP_MINLEN
#define DELAY_TIME 1
+#define NB_RETRY 3
#define LOGBUFFER_LENGTH 100
#define select_time (DEFAULT_SELECT_TIME * 100)
/* prototypes */
-int ICMP_CHECK(char dst_ip[16]);
+int ICMP_CHECK(char *IP_DST);
#endif
*
* Part: IP packets Utilities.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: iputils.c,v 0.2.1 2000/12/09 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
*
* Part: iputils.c include file.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: iputils.h,v 0.2.1 2000/12/09 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
* Part: IPVS Kernel wrapper. Use setsockopt call to add/remove
* server to/from the loadbalanced server pool.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: ipvswrapper.c,v 0.2.1 2000/12/09 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
if (strcmp(vserver->svr->loadbalancing_kind,"TUN")==0)
ctl.u.vs_user.masq_flags = IP_MASQ_F_VS_TUNNEL;
else {
- bzero(debugmsg,LOGBUFFER_LENGTH);
+ memset(debugmsg,0,LOGBUFFER_LENGTH);
sprintf(debugmsg,"ipvs_pool_cmd : service [%s:%s] [%s] unknown routing method...\n",
vserver->svr->addr_ip, vserver->svr->addr_port,
vserver->svr->loadbalancing_kind);
*
* Part: ipvswrapper.c include file.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: ipvswrapper.h,v 0.2.1 2000/12/09 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
*
* Part: Main program structure.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: keepalived.c,v 0.2.3 2001/01/01 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
* Changes:
- * Alexandre Cassen : Initial release
+ * Alexandre Cassen : 2001/01/01 :
+ * <+> Change the signalhandling.
+ *
+ * Alexandre Cassen : 2000/12/09 : Initial release
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
if (signal(SIGTERM,sig_handler) == SIG_IGN)
signal(SIGTERM,SIG_IGN);
-
- signal(SIGINT,sig_handler);
- signal(SIGHUP,sig_handler);
+ signal(SIGINT,SIG_IGN);
+ signal(SIGHUP,SIG_IGN);
if ((lstVS=(virtualserver *)ConfReader(lstVS,delay_loop))==NULL) {
logmessage("Config file contain no data\n",getpid());
while (keep_going) {
perform_checks(lstVS);
-/* sleep(delay_loop); */
- sleep(60);
+ sleep(delay_loop);
}
return 0;
char *logbuffer;
logbuffer=(char *)malloc(LOGBUFFER_LENGTH);
-
if (!lstptr->svr->alive && alive) {
lstptr->svr->alive=alive;
memset(logbuffer,0,LOGBUFFER_LENGTH);
if (strcmp(lstptr->svr->keepalive_method,"ICMP_CHECK") == 0) {
if (ICMP_CHECK(lstptr->svr->addr_ip)) {
+#ifdef DEBUG
+ logmessage("ICMP check succeed\n",getpid());
+#endif
if (!lstptr->svr->alive) {
memset(logbuffer,0,LOGBUFFER_LENGTH);
sprintf(logbuffer,"ICMP check succeed to %s.\n",lstptr->svr->addr_ip);
perform_ipvs(1,lstptr);
}
} else {
+#ifdef DEBUG
+ logmessage("ICMP check failed\n",getpid());
+#endif
if (lstptr->svr->alive) {
memset(logbuffer,0,LOGBUFFER_LENGTH);
sprintf(logbuffer,"ICMP check failed to %s.\n",lstptr->svr->addr_ip);
if (strcmp(lstptr->svr->keepalive_method,"TCP_CHECK") == 0) {
if (TCP_CHECK(lstptr->addr_ip,lstptr->svr->addr_ip,lstptr->svr->addr_port)) {
+#ifdef DEBUG
logmessage("TCP check succeed\n",getpid());
+#endif
if (!lstptr->svr->alive) {
memset(logbuffer,0,LOGBUFFER_LENGTH);
sprintf(logbuffer,"TCP check succeed to %s:%s.\n",lstptr->svr->addr_ip,
perform_ipvs(1,lstptr);
}
} else {
+#ifdef DEBUG
logmessage("TCP check failed\n",getpid());
+#endif
if (lstptr->svr->alive) {
- bzero(logbuffer,LOGBUFFER_LENGTH);
+ memset(logbuffer,0,LOGBUFFER_LENGTH);
sprintf(logbuffer,"TCP check failed to %s:%s.\n",lstptr->svr->addr_ip,
lstptr->svr->addr_port);
logmessage(logbuffer,getpid());
lstptr->svr->keepalive_url,MD5Result)) {
if (strcmp(lstptr->svr->keepalive_result,MD5Result) == 0) {
+#ifdef DEBUG
logmessage("HTTP GET check succeed\n",getpid());
+#endif
if (!lstptr->svr->alive) {
memset(logbuffer,0,LOGBUFFER_LENGTH);
sprintf(logbuffer,"HTTP GET check succeed to %s:%s.\n",lstptr->svr->addr_ip,
perform_ipvs(1,lstptr);
}
} else {
+#ifdef DEBUG
logmessage("HTTP GET check failed\n",getpid());
+#endif
if (lstptr->svr->alive) {
memset(logbuffer,0,LOGBUFFER_LENGTH);
sprintf(logbuffer,"HTTP GET check failed to %s:%s.\n",lstptr->svr->addr_ip,
/* Global variables */
volatile sig_atomic_t keep_going = 1;
virtualserver *lstVS;
-int delay_loop = 5;
+int delay_loop = 60;
/* Build version */
#define PROG "keepalived"
-#define VERSION "0.2.1 (12/23, 2000), Alexandre Cassen"
+#define VERSION "0.2.3 (01/01, 2001), Alexandre Cassen"
/* prototypes */
void sig_handler(int signum);
* server. This check implement the tcp half open connection
* check.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: tcpcheck.c,v 0.2.3 2000/12/29 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
* Changes:
- * Alexandre Cassen : Initial release
- *
+ * Alexandre Cassen : 2000/12/29 :
+ * <+> Added recvfrom_to() function to handle recvfrom timeouted connection.
+ * Call this function in TCP_RCV_SYNACK_PACKET with 1s timeout.
+ * <+> Added a timer (2s timeouted) in TCP_RCV_SYNACK_PACKET to check
+ * SYN|ACK packet. Check perform on tcp sequence, remote tcp port number,
+ * tcp SYN|ACK flag, remote ip address.
+ * <+> Added a 3 time SYN packet send retry.
+ *
+ * Alexandre Cassen : 2000/12/09 : Initial release
+ *
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
#include "tcpcheck.h"
-#define SEQUENCE 0x28376839
+int recvfrom_to(int s, char *buf, int len, struct sockaddr *saddr, int timo)
+{
+ int nfound,slen,n;
+ struct timeval to;
+ fd_set readset,writeset;
+
+ to.tv_sec = timo/1000;
+ to.tv_usec = 0;
+
+ FD_ZERO(&readset);
+ FD_ZERO(&writeset);
+ FD_SET(s,&readset);
+ nfound = select(s+1,&readset,&writeset,NULL,&to);
+ if (nfound<0) {
+#ifdef DEBUG
+ logmessage("TCP_CHECK : Select socket descriptor error...\n",getpid());
+#endif
+ return(-1);
+ }
+ if (nfound==0) {
+#ifdef DEBUG
+ logmessage("TCP_CHECK : Timeout receiving SYN response...\n",getpid());
+#endif
+ return -1;
+ }
+ slen=sizeof(struct sockaddr_in);
+ n=recvfrom(s,buf,len,0,saddr,&slen);
+ if (n<0) {
+#ifdef DEBUG
+ logmessage("TCP_CHECK : recvfrom error...\n",getpid());
+#endif
+ return -1;
+ }
+ return n;
+}
-int TCP_SEND_PACKET(char *IP_SRC,char *IP_DST,char *PORT_DST,char *FLAG)
+int TCP_SEND_PACKET(char *IP_SRC,char *IP_DST,char *PORT_DST,char *FLAG,unsigned long int SEQ)
{
register int rawsock;
struct linger li = { 0 };
struct iphdr *packet_ip;
struct tcphdr *packet_tcp;
struct tcphdr_pseudo packet_tcppseudo;
- struct sockaddr dest;
+ struct sockaddr_in dest;
char *packet;
/* Packet pointer affectation */
packet=(char *)malloc(SYNPACKET_LENGTH);
- bzero(packet,SYNPACKET_LENGTH);
+ memset(packet,0,SYNPACKET_LENGTH);
+ memset(&dest,0,sizeof(struct sockaddr_in));
packet_ip=(struct iphdr *)packet;
packet_tcp=(struct tcphdr *)(packet_ip+1);
/* Fill in the TCP header structure */
packet_tcp->source = htons(STCP);
packet_tcp->dest = htons(atoi(PORT_DST));
- packet_tcp->seq = htonl(SEQUENCE);
+ packet_tcp->seq = SEQ;
packet_tcp->doff = sizeof(struct tcphdr)/4;
packet_tcp->ack_seq = 0;
packet_tcp->res1 = 0;
sizeof(struct tcphdr_pseudo));
/* Fill in the Sockaddr structure */
- dest.sa_family = AF_INET;
- bcopy(&packet_ip->daddr,&dest.sa_data[2],4);
- bcopy(&packet_tcp->source,&dest.sa_data[0],2);
+ /* A little fake, IP & PORT are in IP & TCP headers */
+ dest.sin_family = AF_INET;
+ dest.sin_port = packet_tcp->dest;
+ dest.sin_addr.s_addr = packet_ip->daddr;
if (sendto(rawsock,packet,sizeof(struct iphdr) + sizeof(struct tcphdr),
0,&dest,sizeof(dest)) < 0) {
free(packet);
return(SOCKET_ERROR);
}
+
+ close(rawsock);
free(packet);
return(SOCKET_SUCCESS);
}
-int TCP_RCV_SYNACK_PACKET()
+int TCP_RCV_SYNACK_PACKET(char *IP_DST, char *PORT_DST, unsigned long int SEQ)
{
register int rawsock;
struct linger li = { 0 };
+ time_t hint;
+ struct tm *date;
+ int timer_before, timer_after;
+ int loop = 1;
+ char *debugmsg;
/* Packet Data representation */
struct iphdr *packet_ip;
struct tcphdr *packet_tcp;
struct tcphdr_pseudo packet_tcppseudo;
- struct sockaddr dest;
+ struct sockaddr_in dest;
char *packet;
- int fromlen=0;
-
- fromlen=sizeof(struct sockaddr);
/* Packet pointer affectation */
+ debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
packet=(char *)malloc(SYNPACKET_LENGTH);
- bzero(packet,SYNPACKET_LENGTH);
+ memset(packet,0,SYNPACKET_LENGTH);
+ memset(debugmsg,0,LOGBUFFER_LENGTH);
+ memset(&dest,0,sizeof(struct sockaddr_in));
packet_ip=(struct iphdr *)packet;
packet_tcp=(struct tcphdr *)(packet_ip+1);
if ( (rawsock = socket(AF_INET, SOCK_RAW, IPPROTO_TCP)) == -1 ) {
+ free(debugmsg);
free(packet);
return (SOCKET_ERROR);
}
li.l_linger=0;
setsockopt(rawsock,SOL_SOCKET,SO_LINGER,(char *)&li,sizeof(struct linger));
- if (recvfrom(rawsock,packet,SYNPACKET_LENGTH,
- 0,(struct sockaddr *)&dest,&fromlen) < 0) {
- free(packet);
- close(rawsock);
- return(SOCKET_ERROR);
- }
+ /* Fill in the Sockaddr structure */
+ memset(&dest,0,sizeof(struct sockaddr_in));
+ dest.sin_family = AF_INET;
+ dest.sin_port = htons(atoi(PORT_DST));
+ dest.sin_addr.s_addr = inet_addr(IP_DST);
- close(rawsock);
+ /* Timer initialization */
+ /* We can also use a signal SIGALRM and catch this signal with handler to break the loop */
+ hint = time((long*)0);
+ date = localtime(&hint);
+ timer_before = date->tm_sec;
- if ( packet_tcp->syn && packet_tcp->ack) {
- free(packet);
- return(SOCKET_SUCCESS);
- } else {
- free(packet);
- return(SOCKET_ERROR);
+ while(loop) {
+ if (recvfrom_to(rawsock,packet,SYNPACKET_LENGTH,(struct sockaddr *)&dest,1000) < 0) {
+ close(rawsock);
+ free(debugmsg);
+ free(packet);
+ return(SOCKET_ERROR);
+ }
+
+ if ( packet_tcp->syn && packet_tcp->ack &&
+ (packet_tcp->ack_seq == SEQ) &&
+ (packet_ip->saddr == dest.sin_addr.s_addr) &&
+ (packet_tcp->source == htons(atoi(PORT_DST))) ) {
+ close(rawsock);
+ free(debugmsg);
+ free(packet);
+ return(SOCKET_SUCCESS);
+ }
+
+#ifdef DEBUG
+ memset(debugmsg,0,LOGBUFFER_LENGTH);
+ sprintf(debugmsg,"TCP_CHECK : SYN|ACK packet not recieved from [%s:%s]. Retry\n",IP_DST,PORT_DST);
+ logmessage(debugmsg,getpid());
+#endif
+
+ /* timer to evaluate packet loosed */
+ hint = time((long*)0);
+ date = localtime(&hint);
+ timer_after = date->tm_sec;
+
+ if(abs(timer_after-timer_before)>1) loop=0;
}
+
+#ifdef DEBUG
+ memset(debugmsg,0,LOGBUFFER_LENGTH);
+ sprintf(debugmsg,"TCP_CHECK : SYN|ACK packet loosed from [%s:%s]\n",IP_DST,PORT_DST);
+ logmessage(debugmsg,getpid());
+#endif
+
+ close(rawsock);
+ free(debugmsg);
+ free(packet);
+ return(SOCKET_ERROR);
}
int TCP_CHECK(char *IP_SRC, char *IP_DST, char *PORT_DST)
{
register int tcpsock;
char *debugmsg;
+ int loop=1;
+ int retry=0;
+ unsigned long int SEQTCP=0;
/* Memory allocation for the data structures */
debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
- bzero(debugmsg,LOGBUFFER_LENGTH);
- if(!TCP_SEND_PACKET(IP_SRC,IP_DST,PORT_DST,"SYN")) {
+ while(loop) {
+ SEQTCP = random() & 0xffff;
+
+ if(!TCP_SEND_PACKET(IP_SRC,IP_DST,PORT_DST,"SYN",htonl(SEQTCP-1))) {
#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"TCP_CHECK : Can't send SYN request to [%s:%s]\n",IP_DST,PORT_DST);
- logmessage(debugmsg,getpid());
+ memset(debugmsg,0,LOGBUFFER_LENGTH);
+ sprintf(debugmsg,"TCP_CHECK : Can't send SYN request to [%s:%s]\n",IP_DST,PORT_DST);
+ logmessage(debugmsg,getpid());
#endif
- free(debugmsg);
- return(SOCKET_ERROR);
+ free(debugmsg);
+ return(SOCKET_ERROR);
+ }
+ if(TCP_RCV_SYNACK_PACKET(IP_DST,PORT_DST,htonl(SEQTCP))) {
+ loop=0;
+ } else {
+ retry++;
+#ifdef DEBUG
+ memset(debugmsg,0,LOGBUFFER_LENGTH);
+ sprintf(debugmsg,"TCP_CHECK : Reexpedite SYN request to [%s:%s]\n",IP_DST,PORT_DST);
+ logmessage(debugmsg,getpid());
+#endif
+ loop=(retry==NB_RETRY)?0:1;
+ }
}
- if(!TCP_RCV_SYNACK_PACKET()) {
+ if (retry==NB_RETRY) {
#ifdef DEBUG
memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"TCP_CHECK : Didn't recieve SYN response from [%s:%s]\n",IP_DST,PORT_DST);
+ sprintf(debugmsg,"TCP_CHECK : SYN|ACK response not recieved from [%s:%s] after 3 try\n",IP_DST,PORT_DST);
logmessage(debugmsg,getpid());
#endif
free(debugmsg);
return(SOCKET_ERROR);
}
- if(!TCP_SEND_PACKET(IP_SRC,IP_DST,PORT_DST,"RST ACK")) {
+ /* The we send a RST TCP packet to be sure that the remote host */
+ /* close the communication channel. */
+ /* Needed some time by MS Windows .... damned... */
+
+ if(!TCP_SEND_PACKET(IP_SRC,IP_DST,PORT_DST,"RST ACK",SEQTCP)) {
#ifdef DEBUG
memset(debugmsg,0,LOGBUFFER_LENGTH);
sprintf(debugmsg,"TCP_CHECK : Can't send RST to [%s:%s]\n",IP_DST,PORT_DST);
*
* Part: tcpcheck.c include file.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: tcpcheck.h,v 0.2.1 2000/12/09 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
#define CFREADER_H
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <netdb.h>
#define SOCKET_ERROR 0
#define SOCKET_SUCCESS 1
-#define STCP 1111
+#define STCP 1111
#define LOGBUFFER_LENGTH 100
#define SYNPACKET_LENGTH 1024
#define HOSTNAME_LENGTH 30
+#define NB_RETRY 3
+
/* Structures used */
struct tcphdr_pseudo {
unsigned int saddr;
*
* Part: General program utils.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: utils.c,v 0.2.1 2000/12/09 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*
*
* Part: utils.c include file.
*
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: utils.h,v 0.2.1 2000/12/09 $
*
* Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
*