* keepalived-0.4.9 released.
* Jan Holmberg, <jan@artech.net> added a memory managment framework.
In debug mode it is used as a memory leak buster. We can so use it
to debug quickly memory leaks (buffer overrun, allocation errors, ...).
* Jan Holmberg and I added support to SSL. Checker SSL_GET. Can be used
with autogenerated cert or with specific cafile, certfile, keyfile.
* Use the OpenSSL, <www.openssl.org> library for MD5 & SSL functions.
* Jan Holmberg and I Rewrote the HTTP_GET code to use full asynchronous
stream handling. The code use a common part for HTTP/SSL stream handling.
Review the MD5 digest buffer computation, update MD5 over received buffer.
* Patched some memory leaks in smtp handling.
* Jan Holmbarg added support to LVS FWMARK.
* Added command line option for keepalived. Used the libpopt library.
-h, -v, -n, -d, -l, -f.
* Jan Holmberg and I added debugging facility on keepalived console.
* Added a BOOTSTRAP_DELAY of 1sec when registering checkers during
daemon bootstrap.
* VRRP : Jan Holmberg added possibility to run an extra script when
VRRP Instance become or leave MASTER STATE (=> using a forked process).
* Review/fine the whole code to apply cosmetics patch.
* Rewrote the genhash utility.
* Started checkers API specs.
* doc doc doc...
* keepalived-0.4.8 released.
--- /dev/null
+Jan Holmberg <jan@artech.net>
+2001-12-10 Alexandre Cassen <acassen@linux-vs.org>
+ * keepalived-0.4.9 released.
+ * Jan Holmberg, <jan@artech.net> added a memory managment framework.
+ In debug mode it is used as a memory leak buster. We can so use it
+ to debug quickly memory leaks (buffer overrun, allocation errors, ...).
+ * Jan Holmberg and I added support to SSL. Checker SSL_GET. Can be used
+ with autogenerated cert or with specific cafile, certfile, keyfile.
+ * Use the OpenSSL, <www.openssl.org> library for MD5 & SSL functions.
+ * Jan Holmberg and I Rewrote the HTTP_GET code to use full asynchronous
+ stream handling. The code use a common part for HTTP/SSL stream handling.
+ Review the MD5 digest buffer computation, update MD5 over received buffer.
+ * Patched some memory leaks in smtp handling.
+ * Jan Holmbarg added support to LVS FWMARK.
+ * Added command line option for keepalived. Used the libpopt library.
+ -h, -v, -n, -d, -l, -f.
+ * Jan Holmberg and I added debugging facility on keepalived console.
+ * Added a BOOTSTRAP_DELAY of 1sec when registering checkers during
+ daemon bootstrap.
+ * VRRP : Jan Holmberg added possibility to run an extra script when
+ VRRP Instance become or leave MASTER STATE (=> using a forked process).
+ * Review/fine the whole code to apply cosmetics patch.
+ * Rewrote the genhash utility.
+ * Started checkers API specs.
+ * doc doc doc...
+
2001-11-20 Alexandre Cassen <acassen@linux-vs.org>
- * keepalived-0.4.8 released.
+ * keepalived-0.4.8 released.
* Rewrite the whole VRRP previous code.
* VRRP : Created a hierarchic scheduling framework.
Handle VRRP instances multiplexing on the same I/O fd.
2. cd into the directory
3. 'make' and 'make install'. This will install
keepalived into your system (binary and configuration file).
- 4. cd into genhash directory
+ 4. cd into genhash directory (read the INSTALL file).
5. 'make' and 'make install'. This will install
- the MD5 url digest generator. You need it to configure HTTP GET check.
+ the MD5 url digest generator. You need it to configure HTTP GET check
+ and SSL GET check in order to compute MD5SUM digest etalon.
6. link keepalived.init into your runlevel directory. On redhat systems :
ln -s /etc/rc.d/init.d/keepalived.init /etc/rc.d/rc3.d/S99keepalived
Have fun with it !
+Alexandre
# Makefile
# Alexandre Cassen <acassen@linux-vs.org>
-EXEC= keepalived
-CC= gcc
+EXEC = keepalived
+CC = gcc
-KERNEL := KERNEL_2_$(shell uname -r | cut -d'.' -f2)
+KERNEL := _KRNL_2_$(shell uname -r | cut -d'.' -f2)_
# To compile with debug messages uncomment the following line
-CFLAGS= -g -Wall -Wunused -DDEBUG -D$(KERNEL)
-#CFLAGS= -g -Wall -D$(KERNEL)
+CFLAGS= -g -O6 -Wall -Wunused -Wstrict-prototypes -D_DEBUG_ -D$(KERNEL)
+# CFLAGS= -g -Wall -O6 -D$(KERNEL) $(SSL)
DEFS=
-ifeq ($(KERNEL),KERNEL_2_2)
+SSL := -lssl -lcrypto
+LIB := $(LIB) $(SSL) -lpopt
+
+ifeq ($(KERNEL),_KRNL_2_2_)
LIB := $(LIB) libipfwc/libipfwc.a
endif
DEFS= main.h \
+ memory.h \
scheduler.h \
cfreader.h \
layer4.h \
check_tcp.h \
check_http.h \
+ check_ssl.h \
check_misc.h \
- md5.h \
vrrp.h \
vrrp_scheduler.h \
vrrp_netlink.h \
smtp.h
OBJECTS := main.o \
+ memory.o \
utils.o \
scheduler.o \
cfreader.o \
layer4.o \
check_tcp.o \
check_http.o \
+ check_ssl.o \
check_misc.o \
- md5.o \
ipwrapper.o \
ipvswrapper.o
-ifeq ($(KERNEL),KERNEL_2_2)
+ifeq ($(KERNEL),_KRNL_2_2_)
OBJECTS := $(OBJECTS) ipfwwrapper.o
endif
OBJECTS := $(OBJECTS) \
@echo ""
@echo "Make complete"
+debug: $(EXEC)
+ @echo""
+ @echo "Make complete"
+
$(EXEC): $(OBJECTS) $(DEFS) $(LIB)
$(CC) -o $(EXEC) $(CFLAGS) $(OBJECTS) $(LIB)
-ifeq ($(KERNEL),KERNEL_2_2)
+ifeq ($(KERNEL),_KRNL_2_2_)
libipfwc/libipfwc.a:
cd libipfwc/ && $(MAKE) libipfwc.a
endif
subclean:
-ifeq ($(KERNEL),KERNEL_2_2)
+ifeq ($(KERNEL),_KRNL_2_2_)
cd libipfwc/ && $(MAKE) clean
endif
install -m 755 etc/rc.d/init.d/keepalived.init /etc/rc.d/init.d/
mkdir /etc/keepalived
install -m 644 etc/keepalived/keepalived.conf /etc/keepalived/
+ mkdir /etc/keepalived/samples
+ install -m 644 samples/* /etc/keepalived/samples/
* Documentation.
* Synchronize IPVS topology with VRRP synchronization events.
* Insert LDAP, SSL, FTP, SSH, IMAP, POP, RADIUS checkers.
-* Security auditing.
+* Replave some unfixed len strcat & sprintf
* Add minimum configuration verification (realserver must have
a checker defined, ...)
* Add system verification (must have LVS support in kernel,
* data structure representation the conf file representing
* the loadbalanced server pool.
*
- * Version: $Id: cfreader.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: cfreader.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*/
#include "cfreader.h"
+#include "memory.h"
/* Global keyword structure defs */
char *string; /* Temp read buffer */
{KW_PTIMEOUT, "persistence_timeout"},
{KW_PROTOCOL, "protocol"},
{KW_SSVR, "sorry_server"},
+ {KW_FWMARK, "fwmark"},
{KW_SVR, "real_server"},
{KW_WEIGHT, "weight"},
{KW_VRRPIPADD, "virtual_ipaddress"},
{KW_VRRPSYNC, "sync_instance"},
{KW_VRRPPREEMPT, "preempt"},
+ {KW_VRRPDEBUG, "debug"},
+ {KW_VRRPNOTIFY, "notify"},
+
+ {KW_SSLPASSWORD, "password"},
+ {KW_SSLCAFILE, "ca"},
+ {KW_SSLCERTFILE, "certificate"},
+ {KW_SSLKEYFILE, "key"},
+ {KW_SSL, "SSL"},
{KW_UNKNOWN, NULL}
};
urls *t;
t = (urls *)lstptr->next;
- free(lstptr);
+ FREE(lstptr);
return t;
}
t = (realserver *)lstptr->next;
- if(lstptr->method->http_get != NULL) {
- while(lstptr->method->http_get->check_urls != NULL)
- lstptr->method->http_get->check_urls = remove_url(lstptr->method->http_get->check_urls);
- free(lstptr->method->http_get);
+ if(lstptr->method->u.http_get != NULL) {
+ while(lstptr->method->u.http_get->check_urls != NULL)
+ lstptr->method->u.http_get->check_urls = remove_url(lstptr->method->u.http_get->check_urls);
+ FREE(lstptr->method->u.http_get);
}
- free(lstptr->method);
- free(lstptr);
+ FREE(lstptr->method);
+ FREE(lstptr);
return t;
}
t = (virtualserver *)lstptr->next;
while(lstptr->svr != NULL) lstptr->svr = remove_svr(lstptr->svr);
- free(lstptr->s_svr);
- free(lstptr);
+
+ if (lstptr->s_svr)
+ FREE(lstptr->s_svr);
+ FREE(lstptr);
return t;
}
-vrrp_instance * remove_vrrp(vrrp_instance *lstptr)
+vrrp_instance *remove_vrrp(vrrp_instance *lstptr)
{
vrrp_instance *t;
t = (vrrp_instance *)lstptr->next;
- free(lstptr->vsrv->vaddr);
- free(lstptr->vsrv->ipsecah_counter);
- free(lstptr->vsrv->vif);
- free(lstptr->vsrv);
- free(lstptr);
+ FREE(lstptr->vsrv->vaddr);
+ FREE(lstptr->vsrv->ipsecah_counter);
+ FREE(lstptr->vsrv->vif);
+ FREE(lstptr->vsrv);
+ FREE(lstptr);
return t;
}
notification_email *t;
t = (notification_email *)lstptr->next;
- free(lstptr);
+ FREE(lstptr);
return t;
}
while(lstptr->lvstopology != NULL)
lstptr->lvstopology = remove_vs(lstptr->lvstopology);
+
+ /* All SSL GET use the same shared SSL context */
+ if (lstptr->ssldata)
+ FREE(lstptr->ssldata);
+
+ FREE(lstptr);
}
void clear_vrrp_instance(vrrp_instance *lstptr)
{
urls *pointerurls;
- syslog(LOG_DEBUG," -> Nb get retry = %d",
+ syslog(LOG_INFO," -> Nb get retry = %d",
pointerhttpget->nb_get_retry);
- syslog(LOG_DEBUG," -> Delay before retry = %d",
+ syslog(LOG_INFO," -> Delay before retry = %d",
pointerhttpget->delay_before_retry);
pointerurls = pointerhttpget->check_urls;
while(pointerhttpget->check_urls) {
- syslog(LOG_DEBUG," -> Url = %s, Digest = %s",
+ syslog(LOG_INFO," -> Url = %s, Digest = %s",
pointerhttpget->check_urls->url,
pointerhttpget->check_urls->digest);
void dump_svr(realserver *pointersvr)
{
while(pointersvr != NULL) {
- syslog(LOG_DEBUG," -> SVR IP = %s, PORT = %d, WEIGHT = %d",
+ syslog(LOG_INFO," -> SVR IP = %s, PORT = %d, WEIGHT = %d",
inet_ntoa(pointersvr->addr_ip),
ntohs(pointersvr->addr_port),
pointersvr->weight);
switch (pointersvr->method->type) {
- case ICMP_CHECK_ID:
- syslog(LOG_DEBUG," -> Keepalive method = ICMP_CHECK");
+ case ICMP_CHECK_ID: /* no more implemented... */
+ syslog(LOG_INFO," -> Keepalive method = ICMP_CHECK");
break;
case TCP_CHECK_ID:
- syslog(LOG_DEBUG," -> Keepalive method = TCP_CHECK");
- syslog(LOG_DEBUG," -> Connection timeout = %d",
+ syslog(LOG_INFO," -> Keepalive method = TCP_CHECK");
+ syslog(LOG_INFO," -> Connection timeout = %d",
pointersvr->method->connection_to);
break;
case HTTP_GET_ID:
- syslog(LOG_DEBUG," -> Keepalive method = HTTP_GET");
- syslog(LOG_DEBUG," -> Connection timeout = %d",
+ syslog(LOG_INFO," -> Keepalive method = HTTP_GET");
+ syslog(LOG_INFO," -> Connection timeout = %d",
pointersvr->method->connection_to);
- dump_httpget(pointersvr->method->http_get);
+ dump_httpget(pointersvr->method->u.http_get);
break;
case SSL_GET_ID:
+ syslog(LOG_INFO," -> Keepalive method = SSL_GET");
+ syslog(LOG_INFO," -> Connection timeout = %d",
+ pointersvr->method->connection_to);
+ dump_httpget(pointersvr->method->u.http_get);
break;
case LDAP_GET_ID:
break;
case MISC_CHECK_ID:
- syslog(LOG_DEBUG," -> Keepalive method = MISC_CHECK");
- syslog(LOG_DEBUG," -> Check path = %s",
- pointersvr->method->misc_check_path);
+ syslog(LOG_INFO," -> Keepalive method = MISC_CHECK");
+ syslog(LOG_INFO," -> Check path = %s",
+ pointersvr->method->u.misc_check_path);
break;
}
void dump_vs(virtualserver *pointervs)
{
while(pointervs != NULL) {
- syslog(LOG_DEBUG, " VS IP = %s, PORT = %d",
- inet_ntoa(pointervs->addr_ip),
- ntohs(pointervs->addr_port));
-
- syslog(LOG_DEBUG, " -> delay_loop = %d, lb_algo = %s, "
+ if (pointervs->vfwmark) {
+ syslog(LOG_INFO, " VS FWMARK = %d"
+ , pointervs->vfwmark);
+ } else {
+ syslog(LOG_INFO, " VS IP = %s, PORT = %d"
+ , inet_ntoa(pointervs->addr_ip)
+ , ntohs(pointervs->addr_port));
+ }
+ syslog(LOG_INFO, " -> delay_loop = %d, lb_algo = %s, "
"persistence = %s, protocol = %s",
pointervs->delay_loop, pointervs->sched,
pointervs->timeout_persistence,
(pointervs->service_type == IPPROTO_TCP)?"TCP":"UDP");
switch (pointervs->loadbalancing_kind) {
-#ifdef KERNEL_2_2
+#ifdef _KRNL_2_2_
case 0:
- syslog(LOG_DEBUG, " -> lb_kind = NAT");
- syslog(LOG_DEBUG, " -> nat mask = %s", inet_ntoa(pointervs->nat_mask));
+ syslog(LOG_INFO, " -> lb_kind = NAT");
+ syslog(LOG_INFO, " -> nat mask = %s", inet_ntoa(pointervs->nat_mask));
break;
case IP_MASQ_F_VS_DROUTE:
- syslog(LOG_DEBUG, " -> lb_kind = DR");
+ syslog(LOG_INFO, " -> lb_kind = DR");
break;
case IP_MASQ_F_VS_TUNNEL:
- syslog(LOG_DEBUG, " -> lb_kind = TUN");
+ syslog(LOG_INFO, " -> lb_kind = TUN");
break;
#else
case IP_VS_CONN_F_MASQ:
- syslog(LOG_DEBUG, " -> lb_kind = NAT");
+ syslog(LOG_INFO, " -> lb_kind = NAT");
break;
case IP_VS_CONN_F_DROUTE:
- syslog(LOG_DEBUG, " -> lb_kind = DR");
+ syslog(LOG_INFO, " -> lb_kind = DR");
break;
case IP_VS_CONN_F_TUNNEL:
- syslog(LOG_DEBUG, " -> lb_kind = TUN");
+ syslog(LOG_INFO, " -> lb_kind = TUN");
break;
#endif
}
if (pointervs->s_svr != NULL) {
- syslog(LOG_DEBUG, " -> sorry server = [%s:%d]",
- inet_ntoa(pointervs->s_svr->addr_ip),
- ntohs(pointervs->s_svr->addr_port));
+ syslog(LOG_INFO, " -> sorry server = [%s:%d]"
+ , inet_ntoa(pointervs->s_svr->addr_ip)
+ , ntohs(pointervs->s_svr->addr_port));
}
dump_svr(pointervs->svr);
void dump_email(notification_email *pointeremail)
{
while(pointeremail != NULL) {
- syslog(LOG_DEBUG," Email notification = %s", pointeremail->addr);
+ syslog(LOG_INFO," Email notification = %s", pointeremail->addr);
pointeremail = (notification_email *)pointeremail->next;
}
int i;
while (pointervrrp != NULL) {
- syslog(LOG_DEBUG, " VRRP Instance = %s", pointervrrp->iname);
+ syslog(LOG_INFO, " VRRP Instance = %s", pointervrrp->iname);
if (pointervrrp->vsrv->init_state == VRRP_STATE_BACK)
- syslog(LOG_DEBUG, " Want State = BACKUP");
+ syslog(LOG_INFO, " Want State = BACKUP");
else
- syslog(LOG_DEBUG, " Want State = MASTER");
- syslog(LOG_DEBUG, " Device = %s", pointervrrp->vsrv->vif->ifname);
+ syslog(LOG_INFO, " Want State = MASTER");
+ syslog(LOG_INFO, " Device = %s", pointervrrp->vsrv->vif->ifname);
if (strlen(pointervrrp->isync) > 0)
- syslog(LOG_DEBUG, " Sync with instance = %s", pointervrrp->isync);
- syslog(LOG_DEBUG, " Virtual Router ID = %d", pointervrrp->vsrv->vrid);
- syslog(LOG_DEBUG, " Priority = %d", pointervrrp->vsrv->priority);
- syslog(LOG_DEBUG, " Advert interval = %dsec",
+ syslog(LOG_INFO, " Sync with instance = %s", pointervrrp->isync);
+ syslog(LOG_INFO, " Virtual Router ID = %d", pointervrrp->vsrv->vrid);
+ syslog(LOG_INFO, " Priority = %d", pointervrrp->vsrv->priority);
+ syslog(LOG_INFO, " Advert interval = %dsec",
pointervrrp->vsrv->adver_int/VRRP_TIMER_HZ);
if (pointervrrp->vsrv->preempt)
- syslog(LOG_DEBUG, " Preempt active");
+ syslog(LOG_INFO, " Preempt active");
if (pointervrrp->vsrv->vif->auth_type) {
- syslog(LOG_DEBUG, " Authentication type = %s",
+ syslog(LOG_INFO, " Authentication type = %s",
(pointervrrp->vsrv->vif->auth_type == VRRP_AUTH_AH)?"IPSEC_AH":"SIMPLE_PASSWORD" );
- syslog(LOG_DEBUG, " Password = %s", pointervrrp->vsrv->vif->auth_data);
+ syslog(LOG_INFO, " Password = %s", pointervrrp->vsrv->vif->auth_data);
}
- syslog(LOG_DEBUG, " VIP count = %d", pointervrrp->vsrv->naddr);
+ syslog(LOG_INFO, " VIP count = %d", pointervrrp->vsrv->naddr);
for (i = 0; i<pointervrrp->vsrv->naddr; i++)
- syslog(LOG_DEBUG, " VIP%d = %s", i+1, ip_ntoa(ntohl(pointervrrp->vsrv->vaddr[i].addr)));
+ syslog(LOG_INFO, " VIP%d = %s", i+1, ip_ntoa(ntohl(pointervrrp->vsrv->vaddr[i].addr)));
pointervrrp = (vrrp_instance *)pointervrrp->next;
}
void dump_conf(configuration_data *lstconf)
{
- if(lstconf == NULL) {
- syslog(LOG_DEBUG, "Empty data configuration !!!");
+ if (lstconf == NULL) {
+ syslog(LOG_INFO, "Empty data configuration !!!");
} else {
- syslog(LOG_DEBUG,"------< Global definitions >------");
- syslog(LOG_DEBUG," LVS ID = %s",lstconf->lvs_id);
- syslog(LOG_DEBUG," Smtp server = %s", inet_ntoa(lstconf->smtp_server));
- syslog(LOG_DEBUG," Smtp server connection timeout = %d", lstconf->smtp_connection_to);
- syslog(LOG_DEBUG," Email notification from = %s",lstconf->email_from);
+ syslog(LOG_INFO, "------< Global definitions >------");
+ syslog(LOG_INFO, " LVS ID = %s",lstconf->lvs_id);
+ syslog(LOG_INFO, " Smtp server = %s", inet_ntoa(lstconf->smtp_server));
+ syslog(LOG_INFO, " Smtp server connection timeout = %d", lstconf->smtp_connection_to);
+ syslog(LOG_INFO, " Email notification from = %s", lstconf->email_from);
dump_email(lstconf->email);
+ if (lstconf->ssldata) {
+ syslog(LOG_INFO, "------< SSL definitions >------");
+ if (strlen(lstconf->ssldata->password) > 0)
+ syslog(LOG_INFO, " Password: %s", lstconf->ssldata->password);
+ if (strlen(lstconf->ssldata->cafile) > 0)
+ syslog(LOG_INFO, " CA-file: %s", lstconf->ssldata->cafile);
+ if (strlen(lstconf->ssldata->certfile) > 0)
+ syslog(LOG_INFO, " Certificate file: %s", lstconf->ssldata->certfile);
+ if (strlen(lstconf->ssldata->keyfile) > 0)
+ syslog(LOG_INFO, " Key file: %s", lstconf->ssldata->keyfile);
+ if (!strlen(lstconf->ssldata->keyfile) &&
+ !strlen(lstconf->ssldata->certfile) &&
+ !strlen(lstconf->ssldata->cafile) &&
+ !strlen(lstconf->ssldata->password))
+ syslog(LOG_INFO, " Using autogen SSL context");
+ }
+
if (lstconf->vrrp) {
- syslog(LOG_DEBUG,"------< VRRP Topology >------");
+ syslog(LOG_INFO, "------< VRRP Topology >------");
dump_vrrp(lstconf->vrrp);
}
if (lstconf->lvstopology) {
- syslog(LOG_DEBUG,"------< LVS Topology >------");
+ syslog(LOG_INFO, "------< LVS Topology >------");
dump_vs(lstconf->lvstopology);
}
}
keepalive_check *methodfill;
/* Allocate new method structure */
- methodfill = (keepalive_check *)malloc(sizeof(keepalive_check));
- memset(methodfill, 0, sizeof(keepalive_check));
+ methodfill = (keepalive_check *)MALLOC(sizeof(keepalive_check));
methodfill->type = ICMP_CHECK_ID;
- methodfill->http_get = NULL;
+ methodfill->u.http_get = NULL;
svrfill->method = methodfill;
}
keepalive_check *methodfill;
/* Allocate new method structure */
- methodfill = (keepalive_check *)malloc(sizeof(keepalive_check));
- memset(methodfill, 0, sizeof(keepalive_check));
+ methodfill = (keepalive_check *)MALLOC(sizeof(keepalive_check));
methodfill->type = TCP_CHECK_ID;
- methodfill->http_get = NULL;
+ methodfill->u.http_get = NULL;
do {
switch (key(string)) {
void process_stream_misccheck(FILE *stream, realserver *svrfill)
{
keepalive_check *methodfill;
- char* pathstring = (char*)malloc(512);
+ char* pathstring = (char*)MALLOC(512);
/* Allocate new method structure */
- methodfill = (keepalive_check *)malloc(sizeof(keepalive_check));
- memset(methodfill, 0, sizeof(keepalive_check));
+ methodfill = (keepalive_check *)MALLOC(sizeof(keepalive_check));
methodfill->type = MISC_CHECK_ID;
- methodfill->http_get = NULL;
- methodfill->misc_check_path = NULL;
+ methodfill->u.misc_check_path = NULL;
do {
switch (key(string)) {
break;
case KW_MISCPATH:
fgets(pathstring,512,stream);
- methodfill->misc_check_path=pathstring;
+ methodfill->u.misc_check_path=pathstring;
break;
case KW_UNKNOWN:
break;
urls *urlfill;
/* Allocate new url structure */
- urlfill = (urls *)malloc(sizeof(urls));
- memset(urlfill, 0, sizeof(urls));
+ urlfill = (urls *)MALLOC(sizeof(urls));
urlfill->next = NULL;
httpgetfill->check_urls = add_item_url(httpgetfill->check_urls, urlfill);
}
-void process_stream_httpget(FILE *stream, realserver *svrfill)
+void process_stream_httpget(FILE *stream, realserver *svrfill, int type)
{
keepalive_check *methodfill;
http_get_check *httpgetfill;
/* Allocate new method structure */
- methodfill = (keepalive_check *)malloc(sizeof(keepalive_check));
- memset(methodfill, 0, sizeof(keepalive_check));
+ methodfill = (keepalive_check *)MALLOC(sizeof(keepalive_check));
/* Allocate new http get structure */
- httpgetfill = (http_get_check *)malloc(sizeof(http_get_check));
- memset(httpgetfill, 0, sizeof(http_get_check));
+ httpgetfill = (http_get_check *)MALLOC(sizeof(http_get_check));
+
+ methodfill->type = type;
+ methodfill->u.http_get = httpgetfill;
- methodfill->type = HTTP_GET_ID;
- methodfill->http_get = httpgetfill;
httpgetfill->check_urls = NULL;
do {
realserver *svrfill;
/* Allocate new real server structure */
- svrfill = (realserver *)malloc(sizeof(realserver));
- memset(svrfill, 0, sizeof(realserver));
+ svrfill = (realserver *)MALLOC(sizeof(realserver));
/* Add the real server allocated to the virtual server
* data structure.
process_stream_tcpcheck(stream, svrfill);
break;
case KW_HTTPGET:
- process_stream_httpget(stream, svrfill);
+ process_stream_httpget(stream, svrfill, HTTP_GET_ID);
break;
- case KW_SSLGET: /* not yet implemented */
+ case KW_SSLGET:
+ process_stream_httpget(stream, svrfill, SSL_GET_ID);
break;
case KW_LDAPGET: /* not yet implemented */
break;
realserver *ssvrfill;
/* Allocate new sorry server structure */
- ssvrfill = (realserver *)malloc(sizeof(realserver));
- memset(ssvrfill, 0, sizeof(realserver));
+ ssvrfill = (realserver *)MALLOC(sizeof(realserver));
/* direct affectation, we can use add_item_svr, so
* can specify more than 1 sorry_server...
virtualserver *vsfill;
/* Allocate new virtual server structure */
- vsfill = (virtualserver *)malloc(sizeof(virtualserver));
- memset(vsfill, 0, sizeof(virtualserver));
+ vsfill = (virtualserver *)MALLOC(sizeof(virtualserver));
/* Add the virtual server allocated to the configuration
* data structure.
conf_data->lvstopology = add_item_vs(conf_data->lvstopology, vsfill);
fscanf(stream, "%s", string);
- vsfill->addr_ip.s_addr = inet_addr(string);
- fscanf(stream, "%s", string);
- vsfill->addr_port = htons(atoi(string));
+ if (!strcmp(string, "fwmark")) {
+ fscanf(stream, "%s", string);
+ vsfill->vfwmark = atoi(string);
+ } else {
+ vsfill->vfwmark = 0;
+ vsfill->addr_ip.s_addr = inet_addr(string);
+ fscanf(stream, "%s", string);
+ vsfill->addr_port = htons(atoi(string));
+ }
/* Setting default value */
vsfill->delay_loop = KEEPALIVED_DEFAULT_DELAY;
case KW_LBKIND:
fscanf(stream, "%s", string);
-#ifdef KERNEL_2_2
+#ifdef _KRNL_2_2_
if (strcmp(string, "NAT") == 0)
vsfill->loadbalancing_kind = 0;
else
do {
fscanf(stream, "%s", string);
if(key(string) != KW_BEGINFLAG && key(string) != KW_ENDFLAG) {
- emailfill = (notification_email *)malloc(sizeof(notification_email));
- memset(emailfill, 0, sizeof(notification_email));
+ emailfill = (notification_email *)MALLOC(sizeof(notification_email));
strncat(emailfill->addr, string, sizeof(emailfill->addr));
emailfill->next = NULL;
conf_data->email = add_item_email(conf_data->email, emailfill);
} while(key(string) != KW_ENDFLAG);
}
+int process_stream_ssl(FILE *stream, configuration_data *conf_data)
+{
+ /* Fill in the global defs structure */
+ do {
+ switch (key(string)) {
+ case KW_SSLPASSWORD:
+ fscanf(stream, "%s", conf_data->ssldata->password);
+ conf_data->ssldata->enable |= 1;
+ break;
+ case KW_SSLCAFILE:
+ fscanf(stream, "%s", conf_data->ssldata->cafile);
+ conf_data->ssldata->enable |= 2;
+ break;
+ case KW_SSLKEYFILE:
+ fscanf(stream, "%s", conf_data->ssldata->keyfile);
+ conf_data->ssldata->enable |= 4;
+ break;
+ case KW_SSLCERTFILE:
+ fscanf(stream, "%s", conf_data->ssldata->certfile);
+ conf_data->ssldata->enable |= 8;
+ break;
+ case KW_UNKNOWN:
+ break;
+ }
+ fscanf(stream, "%s", string);
+ } while(key(string) != KW_ENDFLAG);
+
+ return conf_data->ssldata->enable;
+}
+
static void add_item_vrrp_vip(vrrp_rt *vsrv, uint32_t ipaddr)
{
vsrv->naddr++;
/* alloc the room */
if( vsrv->vaddr ){
- vsrv->vaddr = realloc(vsrv->vaddr, vsrv->naddr*sizeof(*vsrv->vaddr));
+ vsrv->vaddr = REALLOC(vsrv->vaddr, vsrv->naddr*sizeof(*vsrv->vaddr));
} else {
- vsrv->vaddr = malloc(sizeof(*vsrv->vaddr));
+ vsrv->vaddr = (vip_addr *)MALLOC(sizeof(*vsrv->vaddr));
}
/* store the data */
vsrv->vaddr[vsrv->naddr-1].addr = ipaddr;
seq_counter *counterfill;
/* Allocate new VRRP structure */
- vrrpfill = (vrrp_instance *)malloc(sizeof(vrrp_instance));
- rtfill = (vrrp_rt *)malloc(sizeof(vrrp_rt));
- viffill = (vrrp_if *)malloc(sizeof(vrrp_if));
- counterfill = (seq_counter *)malloc(sizeof(seq_counter));
-
- memset(vrrpfill, 0, sizeof(vrrp_instance));
- memset(rtfill, 0, sizeof(vrrp_rt));
- memset(viffill, 0, sizeof(vrrp_if));
- memset(counterfill, 0, sizeof(seq_counter));
+ vrrpfill = (vrrp_instance *)MALLOC(sizeof(vrrp_instance));
+ rtfill = (vrrp_rt *) MALLOC(sizeof(vrrp_rt));
+ viffill = (vrrp_if *) MALLOC(sizeof(vrrp_if));
+ counterfill = (seq_counter *) MALLOC(sizeof(seq_counter));
/* Add the vrrp instance allocated to the configuration
* data structure.
*/
- vrrpfill->vsrv = rtfill;
- vrrpfill->vsrv->vif = viffill;
+ vrrpfill->vsrv = rtfill;
+ vrrpfill->vsrv->vif = viffill;
vrrpfill->vsrv->ipsecah_counter = counterfill;
- vrrpfill->vsrv->vaddr = NULL;
- vrrpfill->vsrv->vaddr = NULL;
- vrrpfill->next = NULL;
+ vrrpfill->vsrv->vaddr = NULL;
+ vrrpfill->vsrv->vaddr = NULL;
+ vrrpfill->next = NULL;
/* default value */
- rtfill->wantstate = VRRP_STATE_BACK;
- rtfill->init_state = VRRP_STATE_BACK;
+ rtfill->wantstate = VRRP_STATE_BACK;
+ rtfill->init_state = VRRP_STATE_BACK;
conf_data->vrrp = add_item_vrrp(conf_data->vrrp, vrrpfill);
case KW_VRRPPREEMPT:
rtfill->preempt = !rtfill->preempt;
break;
+ case KW_VRRPDEBUG:
+ fscanf(stream, "%d", &rtfill->debug);
+ if (VRRP_IS_BAD_DEBUG_INT(rtfill->debug)) {
+ syslog(LOG_DEBUG, "VRRP Error : Debug intervall not valid !");
+ syslog(LOG_DEBUG, "VRRP Error : must be between 0-4");
+ return 0;
+ }
+ break;
+ case KW_VRRPNOTIFY:
+ fscanf(stream, "%s", rtfill->notify_file);
+ rtfill->notify_exec = 1;
+ break;
case KW_UNKNOWN:
break;
}
return 1;
}
-configuration_data * conf_reader()
+configuration_data *conf_reader(char *conf_file)
{
configuration_data *conf_data;
FILE *stream;
- /* Allocate configuration data memory */
- conf_data = (configuration_data *)malloc(sizeof(configuration_data));
- memset(conf_data, 0, sizeof(configuration_data));
-
/* Parse the confuguration file */
- stream = fopen(CONFFILE, "r");
+ stream = fopen((conf_file)?conf_file:CONFFILE, "r");
if(!stream) {
syslog(LOG_INFO, "ConfReader : Can not read the configuration file...");
return(NULL);
}
+ /* Allocate configuration data memory */
+ conf_data = (configuration_data *)MALLOC(sizeof(configuration_data));
+
/* Allocate temp buffer string */
- string = (char *)malloc(TEMP_BUFFER_LENGTH);
- memset(string, 0, TEMP_BUFFER_LENGTH);
+ string = (char *)MALLOC(TEMP_BUFFER_LENGTH);
/* Initialise the dynamic data structure */
conf_data->email = NULL;
conf_data->lvstopology = NULL;
+ conf_data->ssldata = NULL;
while (!feof(stream)) {
switch (key(string)) {
if (!process_stream_vrrp(stream, conf_data))
return NULL;
break;
+ case KW_SSL:
+ conf_data->ssldata = (ssl_data *)MALLOC(sizeof(ssl_data));
+ conf_data->ssldata->enable = 0;
+ if ((process_stream_ssl(stream, conf_data) & 7) != 7)
+ return NULL;
+ break;
case KW_UNKNOWN:
break;
}
fscanf(stream, "%s", string);
}
- free(string);
+ FREE(string);
fclose(stream);
return(conf_data);
}
*
* Part: cfreader.c include file.
*
- * Version: $Id: cfreader.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: cfreader.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#include <stdint.h>
#include <syslog.h>
#include <arpa/inet.h>
-
-#ifdef KERNEL_2_2
+#include <openssl/ssl.h>
+#ifdef _KRNL_2_2_
#include <linux/ip_masq.h>
#include <net/ip_masq.h>
#else
#define MAX_TIMEOUT_LENGTH 5
#define MAX_INT_LENGTH 10
-#ifdef KERNEL_2_2
+#define MAX_SSL_PASSWORD 48
+#define MAX_SSL_PATH 240
+
+#ifdef _KRNL_2_2_
#define SCHED_MAX_LENGTH IP_MASQ_TNAME_MAX
#else
#define SCHED_MAX_LENGTH IP_VS_SCHEDNAME_MAXLEN
#define KW_VRRPSYNC 43
#define KW_VRRPPREEMPT 44
-#define KW_UNKNOWN 45
+#define KW_VRRPDEBUG 45
+#define KW_VRRPNOTIFY 46
+#define KW_FWMARK 47
+
+#define KW_SSLPASSWORD 48
+#define KW_SSLCAFILE 49
+#define KW_SSLKEYFILE 50
+#define KW_SSLCERTFILE 51
+#define KW_SSL 52
+
+#define KW_UNKNOWN 53
#define KEEPALIVED_DEFAULT_DELAY 60
/* Structure definition */
+
+/* SSL common data */
+typedef struct _ssl_data SSL_DATA;
+typedef struct _ssl_data {
+ int enable;
+ int strong_check;
+ SSL_CTX *ctx;
+ SSL_METHOD *meth;
+ char password[MAX_SSL_PASSWORD];
+ char cafile[MAX_SSL_PATH];
+ char certfile[MAX_SSL_PATH];
+ char keyfile[MAX_SSL_PATH];
+} ssl_data;
+
typedef struct _urls {
char url[MAX_URL_LENGTH];
char digest[DIGEST_LENGTH];
#define LDAP_GET_ID (1 << 4)
#define MISC_CHECK_ID (1 << 5)
int connection_to;
- http_get_check *http_get; /* FIXME : for new checker use union here */
- char *misc_check_path;
+ union {
+ http_get_check *http_get;
+ char *misc_check_path;
+ } u;
} keepalive_check;
typedef struct _real_server {
typedef struct _virtual_server {
struct in_addr addr_ip;
+ uint32_t vfwmark;
uint16_t addr_port;
uint16_t service_type;
int delay_loop;
int smtp_connection_to;
notification_email *email;
vrrp_instance *vrrp;
-
virtualserver *lvstopology;
+ ssl_data *ssldata;
} configuration_data;
/* prototypes */
-extern configuration_data * conf_reader();
+extern configuration_data *conf_reader(char *conf_file);
extern void clear_conf(configuration_data * lstptr);
extern void clear_vrrp_instance(vrrp_instance *lstptr);
extern void dump_conf(configuration_data * lstptr);
*
* Part: Checkers arguments structures definitions.
*
- * Version: $Id: check.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: check.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#ifndef _CHECK_H
#define _CHECK_H
+/* system includes */
+#include <openssl/md5.h>
+#include <openssl/ssl.h>
+
+/* ssl specific thread arguments defs */
+typedef struct {
+ char *buffer;
+ char *extracted;
+ int error;
+ int len;
+ SSL *ssl;
+ BIO *bio;
+ MD5_CTX context;
+} REQ;
+
/* http specific thread arguments defs */
-struct http_thread_arg {
+typedef struct _http_thread_arg {
int retry_it; /* current number of get retry */
int url_it; /* current url checked index */
-};
+ REQ *req; /* GET buffer and SSL args */
+} http_thread_arg;
/* global thread arguments defs */
-struct thread_arg {
+typedef struct _thread_arg {
configuration_data *root; /* pointer to the configuration root data */
virtualserver *vs; /* pointer to the checker thread virtualserver */
realserver *svr; /* pointer to the checker thread realserver */
void *checker_arg; /* pointer to the specific checker arg */
-};
+} thread_arg;
#endif
* <www.linuxvirtualserver.org>. It monitor & manipulate
* a loadbalanced server pool using multi-layer checks.
*
- * Part: HTTP GET CHECK. Perform an http get query to a specified
- * url, compute a MD5 over this result and match it to the
- * expected value.
+ * Part: WEB CHECK. Common HTTP/SSL checker primitives.
*
- * Version: $Id: check_http.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: check_http.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
- * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ * Authors: Alexandre Cassen, <acassen@linux-vs.org>
+ * Jan Holmberg, <jan@artech.net>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* 2 of the License, or (at your option) any later version.
*/
+#include <openssl/err.h>
#include "check_http.h"
+#include "check_ssl.h"
+#include "memory.h"
+
+/*
+ * The global design of this checker is the following :
+ *
+ * - All the actions are done asynchronously.
+ * - All the actions handle timeout connection.
+ * - All the actions handle error from low layer to upper
+ * layers.
+ *
+ * The global synopsis of the inter-thread-call is :
+ *
+ * http_connect_thread (handle layer4 connect)
+ * v
+ * http_check_thread (handle SSL connect)
+ * v
+ * http_request_thread (send SSL GET request)
+ * v
+ * http_response_thread (initialize read stream step)
+ * / \
+ * / \
+ * v v
+ * http_read_thread ssl_read_thread (perform HTTP|SSL stream)
+ * v v
+ * http_handle_response (next checker thread registration)
+ */
-/* simple function returning a pointer to the html buffer begin */
-char *extract_html(char *buffer, int size_buffer)
-{
- char *end=buffer+size_buffer;
-
- while ( buffer < end &&
- !(*buffer++ == '\n' &&
- (*buffer == '\n' || (*buffer ++ == '\r' && *buffer =='\n'))));
-
- if (*buffer == '\n') return buffer+1;
- return NULL;
-}
-
-/* return the url pointer of the current url iterator */
-urls *fetch_next_url(struct thread_arg *thread_arg)
+/*
+ * Simple epilog functions. Handling event timeout.
+ * Finish the checker with memory managment or url rety check.
+ *
+ * c == 0 => reset to 0 retry_it counter
+ * t == 0 => reset to 0 url_it counter
+ * method == 1 => register a new checker thread
+ * method == 2 => register a retry on url checker thread
+ */
+int epilog(thread *thread, int metod, int t, int c)
{
- struct http_thread_arg *checker_arg;
- int i = 0;
-
+ thread_arg *thread_arg = THREAD_ARG(thread);
+ http_thread_arg *checker_arg;
+ int delay = 0;
+ REQ *req;
+
checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+ req = checker_arg->req;
+
+ if (metod) {
+ checker_arg->url_it += t ? t : -checker_arg->url_it;
+ checker_arg->retry_it += c ? c : -checker_arg->retry_it;
+ }
- /* fetch the next url */
- for (i=0; i<checker_arg->url_it; i++)
- thread_arg->svr->method->http_get->check_urls=(urls *) thread_arg->svr->method->http_get->check_urls->next;
+ /* register next timer thread */
+ switch (metod) {
+ case 1:
+ if (req)
+ delay = thread_arg->vs->delay_loop;
+ else
+ delay = thread_arg->vs->delay_loop -
+ thread_arg->svr->method->u.http_get->delay_before_retry;
+ thread_add_timer(thread->master, http_connect_thread, thread_arg, delay);
+ break;
+ case 2:
+ delay = thread_arg->svr->method->u.http_get->delay_before_retry;
+ thread_add_timer(thread->master, http_connect_thread, thread_arg, delay);
+ break;
+ }
- if (thread_arg->svr->method->http_get->check_urls != NULL)
- return thread_arg->svr->method->http_get->check_urls;
+ /* If req == NULL, fd is not created */
+ if (req != NULL) {
+ if (req->ssl)
+ SSL_free(req->ssl);
+ if (req->buffer)
+ FREE(req->buffer);
+ FREE(req);
+ close(thread->u.fd);
+ }
- return NULL;
+ return 0;
}
-/* read http get result from the remote http server. Apply trigger check to this result */
-int http_response_thread(struct thread *thread)
+int timeout_epilog(thread *thread, char *smtp_msg, char *debug_msg)
{
- struct thread_arg *thread_arg;
- struct http_thread_arg *checker_arg;
- long total_length = 0;
- int rcv_buffer_size = 0;
- int di = 0;
- MD5_CTX context;
- unsigned char digest[16];
- char *buffer;
- char *digest_tmp;
- char *buffer_html;
- char *buffer_tmp;
- urls *fetched_url;
- urls *pointerurls;
+ thread_arg *thread_arg;
+ http_thread_arg *checker_arg;
- thread_arg = THREAD_ARG(thread);
+ thread_arg = THREAD_ARG(thread);
checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
- /* Handle read timeout */
- if(thread->type == THREAD_READ_TIMEOUT) {
-#ifdef DEBUG
+ /*
+ * The get retry implementation mean that we retry performing
+ * a GET on the same url until the remote web server return
+ * html buffer. This is sometime needed with some applications
+ * servers.
+ */
+ if (++checker_arg->retry_it <=
+ thread_arg->svr->method->u.http_get->nb_get_retry) {
+
+#ifdef _DEBUG_
+ syslog(LOG_DEBUG, "Retry %s server [%s:%d] after %d retry.", debug_msg,
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port),
+ checker_arg->retry_it - 1);
+#endif
+ return epilog(thread,2,0,1);
+ } else {
+#ifdef _DEBUG_
if (thread_arg->svr)
- syslog(LOG_DEBUG, "HTTP read timeout to [%s:%d].",
+ syslog(LOG_DEBUG, "Timeout %s server [%s:%d].", debug_msg,
inet_ntoa(thread_arg->svr->addr_ip),
ntohs(thread_arg->svr->addr_port));
#endif
/* check if server is currently alive */
if (thread_arg->svr->alive) {
- smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
- "DOWN", "=> HTTP CHECK failed on service : cannot receive data <=\n\n");
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr, "DOWN", smtp_msg);
perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
}
- /* reset iterator counters */
- memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
-
- /* register next timer thread */
- thread_add_timer(thread->master, http_connect_thread, thread_arg,
- thread_arg->vs->delay_loop);
-
- close(thread->u.fd);
- return 0;
+ return epilog(thread,1,0,0);
}
- /* Allocate the get buffers */
- buffer = (char *)malloc(MAX_BUFFER_LENGTH);
- buffer_tmp = (char *)malloc(GET_BUFFER_LENGTH);
-
- /* Cleanup the room */
- memset(buffer, 0, MAX_BUFFER_LENGTH);
- memset(buffer_tmp, 0, GET_BUFFER_LENGTH);
-
- /* Read the fd until remote sever stop sending data.
- -> FIXME : need to register a new read thread while receiving data */
- while ((rcv_buffer_size = read(thread->u.fd, buffer_tmp, GET_BUFFER_LENGTH)) != 0) {
- if (rcv_buffer_size == -1) {
- if (errno == EAGAIN) goto end;
- free(buffer);
- free(buffer_tmp);
- close(thread->u.fd);
-
- /* check if server is currently alive */
- if (thread_arg->svr->alive) {
- smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
- "DOWN", "=> HTTP CHECK failed on service : cannot receive data <=\n\n");
- perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
- }
-
- /* reset iterator counters */
- memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
-
- /* register next timer thread */
- thread_add_timer(thread->master, http_connect_thread, thread_arg,
- thread_arg->vs->delay_loop);
-
- return 0;
- }
-
- /* received data overflow buffer size ? */
- if (total_length >= MAX_BUFFER_LENGTH) {
- syslog(LOG_INFO, "Received buffer from [%s:%d] overflow our get buffer size.",
- inet_ntoa(thread_arg->svr->addr_ip),
- ntohs(thread_arg->svr->addr_port));
- free(buffer);
- free(buffer_tmp);
- close(thread->u.fd);
-
- /* check if server is currently alive */
- if (thread_arg->svr->alive) {
- smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
- "DOWN", "=> HTTP CHECK failed on service : received data overflow <=\n\n");
- perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
- }
-
- /* reset iterator counters */
- memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
-
- /* register next timer thread */
- thread_add_timer(thread->master, http_connect_thread, thread_arg,
- thread_arg->vs->delay_loop);
-
- return 0;
- } else {
- memcpy(buffer+total_length, buffer_tmp, rcv_buffer_size);
- memset(buffer_tmp, 0, GET_BUFFER_LENGTH);
- total_length += rcv_buffer_size;
- if (rcv_buffer_size < GET_BUFFER_LENGTH) goto end;
- }
- }
+ return 0;
+}
-end:
+/* HTML stream parser primitives */
+/* simple function returning a pointer to the html buffer begin */
+char *extract_html(char *buffer, int size_buffer)
+{
+ char *end = buffer+size_buffer;
- buffer_html = extract_html(buffer, total_length);
+ while ( buffer < end &&
+ !(*buffer++ == '\n' &&
+ (*buffer == '\n' || (*buffer ++ == '\r' && *buffer =='\n'))));
-//print_buffer(total_length - (buffer_html - buffer),buffer_html);
+ if (*buffer == '\n') return buffer+1;
+ return NULL;
+}
- if ((total_length == 0) || ((total_length-(buffer_html-buffer)) == 0)) {
-#ifdef DEBUG
- syslog(LOG_DEBUG, "No html data received from remote server [%s:%d].",
- inet_ntoa(thread_arg->svr->addr_ip),
- ntohs(thread_arg->svr->addr_port));
-#endif
+/* return the url pointer of the current url iterator */
+urls *fetch_next_url(thread_arg *thread_arg)
+{
+ http_thread_arg *checker_arg;
+ int i = 0;
- checker_arg->retry_it++;
+ checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
- /* The get retry implementation mean that we retry performing
- * a GET on the same url until the remote web server return
- * html buffer. This is sometime needed with some applications
- * servers.
- */
- if (checker_arg->retry_it >
- thread_arg->svr->method->http_get->nb_get_retry) {
+ /* fetch the next url */
+ for (i=0; i<checker_arg->url_it; i++)
+ thread_arg->svr->method->u.http_get->check_urls=(urls *)thread_arg->svr->method->u.http_get->check_urls->next;
-#ifdef DEBUG
- syslog(LOG_DEBUG, "Empty buffer returned from [%s:%d] after %d retry.",
- inet_ntoa(thread_arg->svr->addr_ip),
- ntohs(thread_arg->svr->addr_port),
- --checker_arg->retry_it);
-#endif
+ if (thread_arg->svr->method->u.http_get->check_urls != NULL)
+ return thread_arg->svr->method->u.http_get->check_urls;
- /* check if server is currently alive */
- if (thread_arg->svr->alive) {
- smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
- "DOWN", "=> HTTP CHECK failed on service : empty buffer received <=\n\n");
- perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
- }
+ return NULL;
+}
- /* reset iterator counters */
- memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
+/* Handle response */
+int http_handle_response(thread *thread, unsigned char digest[16], int empty_buffer)
+{
+ thread_arg *thread_arg;
+ http_thread_arg *checker_arg;
+ REQ *req;
+ int r, di = 0;
+ unsigned char *digest_tmp;
+ urls *fetched_url;
+ urls *pointerurls;
- /* register next timer thread */
- thread_add_timer(thread->master, http_connect_thread, thread_arg,
- thread_arg->vs->delay_loop);
+ thread_arg = THREAD_ARG(thread);
+ checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+ req = checker_arg->req;
- } else {
- thread_add_timer(thread->master, http_connect_thread, thread_arg,
- thread_arg->svr->method->http_get->delay_before_retry);
- }
+ if (empty_buffer) {
+ return timeout_epilog(thread,
+ "=> CHECK failed on service : empty buffer received <=\n\n",
+ "Read, no data received from ");
} else {
-
/* Compute MD5SUM */
- digest_tmp = (char *)malloc(2*sizeof(digest));
- memset(digest_tmp, 0, 2*sizeof(digest));
- memset(digest, 0, sizeof(digest));
- MD5Init(&context);
- MD5Update(&context, buffer_html, total_length-(buffer_html-buffer));
- MD5Final(digest, &context);
-
- for (di=0; di < 16; ++di)
+ digest_tmp = (char *)MALLOC(MD5_BUFFER_LENGTH+1);
+ for (di=0; di < 16; di++)
sprintf(digest_tmp+2*di, "%02x", digest[di]);
- pointerurls = thread_arg->svr->method->http_get->check_urls;
+ pointerurls = thread_arg->svr->method->u.http_get->check_urls;
fetched_url = fetch_next_url(thread_arg);
- thread_arg->svr->method->http_get->check_urls = pointerurls;
+ thread_arg->svr->method->u.http_get->check_urls = pointerurls;
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "MD5SUM to [%s:%d] url(%d) = [%s].",
inet_ntoa(thread_arg->svr->addr_ip),
ntohs(thread_arg->svr->addr_port),
checker_arg->url_it+1, digest_tmp);
#endif
- if (strcmp(fetched_url->digest, digest_tmp) != 0) {
+ r = strcmp(fetched_url->digest, digest_tmp);
+ FREE(digest_tmp);
-#ifdef DEBUG
+ if (r) {
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "MD5 digest error to [%s:%d] url(%d), expecting MD5SUM [%s].",
inet_ntoa(thread_arg->svr->addr_ip),
ntohs(thread_arg->svr->addr_port),
checker_arg->url_it+1, fetched_url->digest);
#endif
-
/* check if server is currently alive */
if (thread_arg->svr->alive) {
smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
- "DOWN", "=> HTTP CHECK failed on service : MD5 digest mismatch <=\n\n");
+ "DOWN", "=> CHECK failed on service : MD5 digest mismatch <=\n\n");
perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
}
-
- /* reset iterator counters */
- memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
-
- /* register next timer thread */
- thread_add_timer(thread->master, http_connect_thread, thread_arg,
- thread_arg->vs->delay_loop);
-
- /* free temporary buffer */
- free(digest_tmp);
-
+ return epilog(thread,1,0,0);
} else {
-
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "MD5 digest success to [%s:%d] url(%d), expected MD5SUM [%s] match.",
inet_ntoa(thread_arg->svr->addr_ip),
ntohs(thread_arg->svr->addr_port),
checker_arg->url_it+1, fetched_url->digest);
#endif
-
- /* reset retry iterator and increment url iterator */
- checker_arg->retry_it = 0;
- checker_arg->url_it++;
- free(digest_tmp);
-
- thread_add_timer(thread->master, http_connect_thread, thread_arg,
- thread_arg->svr->method->http_get->delay_before_retry);
+ return epilog(thread,2,1,0)+1;
}
}
-
- free(buffer);
- free(buffer_tmp);
- close(thread->u.fd);
-
- return 1;
+ return epilog(thread,0,0,0)+1;
}
-/* remote http server is connected, send it the get url query. */
-int http_request_thread(struct thread *thread)
+/* Asynchronous HTTP stream reader */
+int http_read_thread(thread *thread)
{
- struct thread_arg *thread_arg;
- struct http_thread_arg *checker_arg;
- char *str_request;
- urls *fetched_url;
- urls *pointerurls;
+ thread_arg *thread_arg;
+ http_thread_arg *checker_arg;
+ unsigned char digest[16];
+ REQ *req;
+ int r = 0;
- thread_arg = THREAD_ARG(thread);
+ thread_arg = THREAD_ARG(thread);
checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+ req = checker_arg->req;
/* Handle read timeout */
- if(thread->type == THREAD_WRITE_TIMEOUT) {
-#ifdef DEBUG
- if (thread_arg->svr)
- syslog(LOG_DEBUG, "HTTP write timeout to [%s:%d].",
- inet_ntoa(thread_arg->svr->addr_ip),
- ntohs(thread_arg->svr->addr_port));
-#endif
- /* check if server is currently alive */
- if (thread_arg->svr->alive) {
- smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
- "DOWN", "=> HTTP CHECK failed on service : cannot receive data <=\n\n");
- perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
- }
+ if (thread->type == THREAD_READ_TIMEOUT) {
+ return timeout_epilog(thread,
+ "=> HTTP CHECK failed on service : recevice data <=\n\n",
+ "HTTP read");
+ }
- /* reset iterator counters */
- memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
+ /* read the HTTP stream */
+ r = read(thread->u.fd, req->buffer+req->len, MAX_BUFFER_LENGTH-req->len);
- /* register next timer thread */
- thread_add_timer(thread->master, http_connect_thread, thread_arg,
- thread_arg->vs->delay_loop);
+ if (r == -1 || r == 0) { /* -1:error , 0:EOF */
- close(thread->u.fd);
- return 0;
- }
+ /* All the HTTP stream has been parsed */
+ MD5_Final(digest, &req->context);
- str_request = (char *)malloc(GET_REQUEST_BUFFER_LENGTH);
- memset(str_request, 0, GET_REQUEST_BUFFER_LENGTH);
+ if (r == -1) {
+ /* We have encourred a real read error */
+ if (thread_arg->svr->alive) {
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
+ "DOWN", "=> HTTP CHECK failed on service : cannot receive data <=\n\n");
+ perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
+ }
+ return epilog(thread,1,0,0);
+ }
- pointerurls = thread_arg->svr->method->http_get->check_urls;
- fetched_url = fetch_next_url(thread_arg);
- thread_arg->svr->method->http_get->check_urls = pointerurls;
+ /* Handle response stream */
+ http_handle_response(thread, digest, (!req->extracted)?1:0);
- if (fetched_url != NULL) {
- snprintf(str_request, GET_REQUEST_BUFFER_LENGTH, GETCMD, fetched_url->url);
} else {
- /* All the url have been successfully checked.
- * Check completed.
- */
- close(thread->u.fd);
- free(str_request);
- /* check if server is currently alive */
- if (!thread_arg->svr->alive) {
- smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
- "UP", "=> HTTP CHECK succeed on service <=\n\n");
- perform_svr_state(UP, thread_arg->vs, thread_arg->svr);
+ req->len += r;
+ if (!req->extracted) {
+ if ((req->extracted = extract_html(req->buffer, req->len))) {
+ r = req->len - (req->extracted-req->buffer);
+ if (r) {
+ memcpy(req->buffer, req->extracted, r);
+ MD5_Update(&req->context, req->buffer, r);
+ r=0;
+ }
+ req->len = r;
+ } else {
+ /* minimize buffer using no 2*CR/LF found yet */
+ if (req->len > 3) {
+ memcpy(req->buffer, req->buffer + req->len - 3, 3);
+ req->len = 3;
+ }
+ }
+ } else {
+ if (req->len) {
+ MD5_Update(&req->context, req->buffer, req->len);
+ req->len = 0;
+ }
}
- /* reset iterator counters */
- memset(checker_arg, 0, sizeof(struct http_thread_arg));
+ /*
+ * Register next http stream reader.
+ * Register itself to not perturbe global I/O multiplexer.
+ */
+ thread_add_read(thread->master, http_read_thread, thread_arg, thread->u.fd,
+ thread_arg->svr->method->connection_to);
+ }
+
+ return 0;
+}
+
+/*
+ * Read get result from the remote web server.
+ * Apply trigger check to this result.
+ */
+int http_response_thread(thread *thread)
+{
+ thread_arg *thread_arg;
+ http_thread_arg *checker_arg;
+ REQ *req;
- /* register next timer thread */
- thread_add_timer(thread->master, http_connect_thread, thread_arg,
- thread_arg->vs->delay_loop);
+ thread_arg = THREAD_ARG(thread);
+ checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+ req = checker_arg->req;
- return 1;
+ /* Handle read timeout */
+ if (thread->type == THREAD_READ_TIMEOUT) {
+ return timeout_epilog(thread,
+ "=> CHECK failed on service : recevice data <=\n\n",
+ "WEB read");
}
-#ifdef DEBUG
- syslog(LOG_DEBUG,"Processing url(%d) of [%s:%d].",
- checker_arg->url_it+1,
- inet_ntoa(thread_arg->svr->addr_ip),
- ntohs(thread_arg->svr->addr_port));
+ /* Allocate & clean the get buffer */
+ req->buffer = (char *)MALLOC(MAX_BUFFER_LENGTH);
+ req->extracted = NULL;
+ req->len = 0;
+ req->error = 0;
+ MD5_Init(&req->context);
+
+ /* Register asynchronous http/ssl read thread */
+ if (thread_arg->svr->method->type == SSL_GET_ID)
+ thread_add_read(thread->master, ssl_read_thread, thread_arg, thread->u.fd,
+ thread_arg->svr->method->connection_to);
+ else
+ thread_add_read(thread->master, http_read_thread, thread_arg, thread->u.fd,
+ thread_arg->svr->method->connection_to);
+ return 0;
+}
+
+/* remote Web server is connected, send it the get url query. */
+int http_request_thread(thread *thread)
+{
+ thread_arg *thread_arg;
+ http_thread_arg *checker_arg;
+ char *str_request;
+ urls *fetched_url;
+ urls *pointerurls;
+ REQ *req;
+ int ret = 0;
+
+ thread_arg = THREAD_ARG(thread);
+ checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+ req = checker_arg->req;
+
+ /* Handle read timeout */
+ if(thread->type == THREAD_WRITE_TIMEOUT) {
+ return timeout_epilog(thread,
+ "=> CHECK failed on service : read timeout <=\n\n",
+ "Web read, timeout");
+ }
+
+ /* Allocate & clean the GET string */
+ str_request = (char *)MALLOC(GET_REQUEST_BUFFER_LENGTH);
+
+ pointerurls = thread_arg->svr->method->u.http_get->check_urls;
+ fetched_url = fetch_next_url(thread_arg);
+ thread_arg->svr->method->u.http_get->check_urls = pointerurls;
+
+ snprintf(str_request, GET_REQUEST_BUFFER_LENGTH
+ , REQUEST_TEMPLATE, fetched_url->url
+ , inet_ntoa(thread_arg->svr->addr_ip)
+ , ntohs(thread_arg->svr->addr_port));
+
+#ifdef _DEBUG_
+ syslog(LOG_DEBUG, "Processing url(%d) of [%s:%d].",
+ checker_arg->url_it+1,
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
#endif
- if (send(thread->u.fd, str_request, strlen(str_request), 0) == -1) {
+ /* Send the GET request to remote Web server */
+ if (thread_arg->svr->method->type == SSL_GET_ID)
+ ret = ssl_send_request(req->ssl, str_request, strlen(str_request));
+ else
+ ret = (send(thread->u.fd, str_request, strlen(str_request), 0) != -1)?1:0;
+
+ FREE(str_request);
+
+ if (!ret) {
syslog(LOG_WARNING, "Cannot send get request to [%s:%d].",
inet_ntoa(thread_arg->svr->addr_ip),
ntohs(thread_arg->svr->addr_port));
/* check if server is currently alive */
if (thread_arg->svr->alive) {
smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
- "DOWN", "=> HTTP CHECK failed on service : cannot send data <=\n\n");
+ "DOWN", "=> CHECK failed on service : cannot send data <=\n\n");
perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
}
-
- /* reset iterator counters */
- memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
-
- /* register next timer thread */
- thread_add_timer(thread->master, http_connect_thread, thread_arg,
- thread_arg->vs->delay_loop);
-
- close(thread->u.fd);
- free(str_request);
- return 0;
+ return epilog(thread,1,0,0);
}
/* Register read timeouted thread */
thread_add_read(thread->master, http_response_thread, thread_arg, thread->u.fd,
thread_arg->svr->method->connection_to);
-
- free(str_request);
return 1;
}
-/* HTTP checkers threads */
-int
-http_check_thread(struct thread *thread)
+/* WEB checkers threads */
+int http_check_thread(thread *thread)
{
- struct thread_arg *thread_arg;
+ thread_arg *thread_arg;
+ http_thread_arg *checker_arg;
+ REQ *req;
+ int ret = 1;
+
int status;
- thread_arg = THREAD_ARG(thread);
+ thread_arg = THREAD_ARG(thread);
+ checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+ req = checker_arg->req;
status = tcp_socket_state(thread->u.fd, thread, http_check_thread);
switch (status) {
case connect_error:
-#ifdef DEBUG
- syslog(LOG_DEBUG,"Error connecting HTTP server [%s:%d].",
+#ifdef _DEBUG_
+ syslog(LOG_DEBUG,"Error connecting server [%s:%d].",
inet_ntoa(thread_arg->svr->addr_ip),
ntohs(thread_arg->svr->addr_port));
#endif
-
/* check if server is currently alive */
if (thread_arg->svr->alive) {
smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
- "DOWN", "=> HTTP CHECK failed on service : connection error <=\n\n");
+ "DOWN", "=> CHECK failed on service : connection error <=\n\n");
perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
}
-
- /* reset iterator counters */
- memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
-
- /* register next timer thread */
- thread_add_timer(thread->master, http_connect_thread, thread_arg,
- thread_arg->vs->delay_loop);
-
+ return epilog(thread,1,0,0);
break;
case connect_timeout:
-#ifdef DEBUG
- syslog(LOG_DEBUG, "Timeout connecting HTTP server [%s:%d].",
- inet_ntoa(thread_arg->svr->addr_ip),
- ntohs(thread_arg->svr->addr_port));
-#endif
-
- /* check if server is currently alive */
- if (thread_arg->svr->alive) {
- smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
- "DOWN", "=> HTTP CHECK failed on service : connection timeout <=\n\n");
- perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
- }
-
- /* reset iterator counters */
- memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
-
- /* register next timer thread */
- thread_add_timer(thread->master, http_connect_thread, thread_arg,
- thread_arg->vs->delay_loop);
-
+ return timeout_epilog(thread,
+ "==> CHECK failed on service : connection timeout <=\n\n",
+ "connect, timeout");
break;
- case connect_success:
- /* Remote HTTP server is connected.
- * Register the next step thread http_request_thread.
- */
-#ifdef DEBUG
- syslog(LOG_DEBUG, "Remote HTTP server [%s:%d] connected.",
- inet_ntoa(thread_arg->svr->addr_ip),
- ntohs(thread_arg->svr->addr_port));
+ case connect_success: {
+ if (thread_arg->svr->method->type == SSL_GET_ID)
+ ret = ssl_connect(thread);
+
+ if (ret) {
+ /* Remote WEB server is connected.
+ * Register the next step thread ssl_request_thread.
+ */
+#ifdef _DEBUG_
+ syslog(LOG_DEBUG, "Remote Web server [%s:%d] connected.",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
#endif
- thread_add_write(thread->master, http_request_thread, thread_arg, thread->u.fd,
- thread_arg->svr->method->connection_to);
- break;
+ thread_add_write(thread->master, http_request_thread, thread_arg, thread->u.fd,
+ thread_arg->svr->method->connection_to);
+ } else {
+#ifdef _DEBUG_
+ syslog(LOG_DEBUG, "Connection problem host: [%s:%d].",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+ if (thread_arg->svr->method->type == SSL_GET_ID)
+ ssl_printerr(SSL_get_error(req->ssl, ret));
+#endif
+ return epilog(thread,1,0,0);
+ }
+ }
+ break;
}
return 0;
}
-int
-http_connect_thread(struct thread *thread)
+int http_connect_thread(thread *thread)
{
- struct thread_arg *thread_arg;
- int fd;
+ thread_arg *thread_arg;
+ http_thread_arg *checker_arg;
+ urls *fetched_url;
+ urls *pointerurls;
enum connect_result status;
+ int fd;
+
+ thread_arg = THREAD_ARG(thread);
+ checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+
+ /* Find eventual url end */
+ pointerurls = thread_arg->svr->method->u.http_get->check_urls;
+ fetched_url = fetch_next_url(thread_arg);
+ thread_arg->svr->method->u.http_get->check_urls = pointerurls;
+ if (fetched_url == NULL) {
+ /* All the url have been successfully checked.
+ * Check completed.
+ * check if server is currently alive.
+ */
+ if (!thread_arg->svr->alive) {
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
+ "UP", "=> CHECK succeed on service <=\n\n");
+ perform_svr_state(UP, thread_arg->vs, thread_arg->svr);
+ }
+ checker_arg->req = NULL;
+ return epilog(thread,1,0,0)+1;
+ }
- thread_arg = THREAD_ARG(thread);
+ /* Allocate & clean request struct */
+ checker_arg->req = (REQ *)MALLOC(sizeof(REQ));
- if ( (fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) {
-#ifdef DEBUG
- syslog(LOG_DEBUG,"HTTP connect fail to create socket.");
+ if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+#ifdef _DEBUG_
+ syslog(LOG_DEBUG, "WEB connection fail to create socket.");
#endif
return 0;
}
*
* Part: check_http.c include file.
*
- * Version: $Id: check_http.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: check_http.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
- * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ * Authors: Alexandre Cassen, <acassen@linux-vs.org>
+ * Jan Holmberg, <jan@artech.net>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
#include "ipwrapper.h"
#include "scheduler.h"
#include "layer4.h"
-#include "md5.h"
/* global defs */
-#define SOCKET_ERROR 0
-#define SOCKET_SUCCESS 1
-
#define MD5_BUFFER_LENGTH 32
#define GET_REQUEST_BUFFER_LENGTH 128
#define GET_BUFFER_LENGTH 2048
#define MAX_BUFFER_LENGTH 4096
-#define LOGBUFFER_LENGTH 100
/* http get processing command */
-#define GETCMD "GET %s HTTP/1.0\r\n\r\n"
-
-/* Prototypes defs */
-extern int http_connect_thread(struct thread *thread);
-
-extern void smtp_alert(struct thread_master *master,
- configuration_data *root,
- realserver *rserver,
- const char *subject,
- const char *body);
+#define REQUEST_TEMPLATE "GET %s HTTP/1.0\r\n" \
+ "User-Agent:KeepAliveClient\r\n" \
+ "Host: %s:%d\r\n\r\n"
+
+/* Define prototypes */
+extern int epilog(thread *thread, int metod, int t, int c);
+extern int timeout_epilog(thread *thread, char *smtp_msg, char *debug_msg);
+extern char *extract_html(char *buffer, int size_buffer);
+extern urls *fetch_next_url(thread_arg *thread_arg);
+extern int http_handle_response(thread *thread
+ , unsigned char digest[16]
+ , int empty_buffer);
+
+extern void smtp_alert(thread_master *
+ , configuration_data *
+ , realserver *
+ , const char *
+ , const char *);
#endif
* Part: MISC CHECK. Perform a system call to run an extra
* system prog or script.
*
- * Version: $Id: check_misc.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: check_misc.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
- * Author: Eric Jarman, <ehj38230@cmsu2.cmsu.edu>
+ * Authors: Alexandre Cassen, <acassen@linux-vs.org>
+ * Eric Jarman, <ehj38230@cmsu2.cmsu.edu>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
#include "check_misc.h"
/* does this need to be threaded? */
-int
-misc_check_call(char* cmdline)
+int misc_check_call(char* cmdline)
{
int retval;
return retval;
}
-int
-misc_check_thread(struct thread *thread)
+int misc_check_thread(thread *thread)
{
- struct thread_arg *thread_arg;
+ thread_arg *thread_arg;
int status;
thread_arg = THREAD_ARG(thread);
- status = misc_check_call(thread_arg->svr->method->misc_check_path);
+ status = misc_check_call(thread_arg->svr->method->u.misc_check_path);
if (status == 0) {
/* everything is good */
*
* Part: check_misc.c include file.
*
- * Version: $Id: check_misc.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: check_misc.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
- * Author: Eric Jarman, <ehj38230@cmsu2.cmsu.edu>
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ * Eric Jarman, <ehj38230@cmsu2.cmsu.edu>
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
#include "smtp.h"
/* Prototypes defs */
-extern int misc_check_thread(struct thread *thread);
+extern int misc_check_thread(thread *thread);
#endif
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: SSL GET CHECK. Perform an ssl get query to a specified
+ * url, compute a MD5 over this result and match it to the
+ * expected value.
+ *
+ * Version: $Id: check_ssl.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
+ *
+ * Authors: Alexandre Cassen, <acassen@linux-vs.org>
+ * Jan Holmberg, <jan@artech.net>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <openssl/err.h>
+#include "check_ssl.h"
+#include "memory.h"
+
+/* SSL primitives */
+/* Free an SSL context */
+void clear_ssl(SSL_DATA *ssl)
+{
+ if (ssl)
+ if (ssl->ctx)
+ SSL_CTX_free(ssl->ctx);
+}
+
+/* PEM password callback function */
+static int password_cb(char *buf, int num, int rwflag, void *userdata)
+{
+ SSL_DATA *ssl = (SSL_DATA *)userdata;
+
+ if (num < strlen(ssl->password)+1)
+ return(0);
+
+ strcpy(buf, ssl->password);
+ return(strlen(ssl->password));
+}
+
+/* Inititalize global SSL context */
+static BIO *bio_err = 0;
+static SSL_DATA *build_ssl_ctx(SSL_DATA *ssl)
+{
+ /* Library initialization */
+ SSL_library_init();
+
+ SSL_load_error_strings();
+ bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
+
+ if (!ssl)
+ ssl = (SSL_DATA *)MALLOC(sizeof(ssl_data));
+
+ /* Initialize SSL context for SSL v2/3 */
+ ssl->meth = SSLv23_method();
+ ssl->ctx = SSL_CTX_new(ssl->meth);
+
+ /* Load our keys and certificates */
+ if (strlen(ssl->keyfile) > 0)
+ if (!(SSL_CTX_use_certificate_chain_file(ssl->ctx, ssl->keyfile))) {
+ syslog(LOG_INFO, "SSL error : Cant load certificate file...");
+ return NULL;
+ }
+
+ /* Handle password callback using userdata ssl */
+ if (strlen(ssl->password) > 0) {
+ SSL_CTX_set_default_passwd_cb_userdata(ssl->ctx, ssl);
+ SSL_CTX_set_default_passwd_cb(ssl->ctx, password_cb);
+ }
+
+ if (strlen(ssl->keyfile) > 0)
+ if (!(SSL_CTX_use_PrivateKey_file(ssl->ctx, ssl->keyfile, SSL_FILETYPE_PEM))) {
+ syslog(LOG_INFO, "SSL error : Cant load key file...");
+ return NULL;
+ }
+
+ /* Load the CAs we trust */
+ if (strlen(ssl->cafile) > 0)
+ if (!(SSL_CTX_load_verify_locations(ssl->ctx, ssl->cafile, 0))) {
+ syslog(LOG_INFO, "SSL error : Cant load CA file...");
+ return NULL;
+ }
+
+#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
+ SSL_CTX_set_verify_depth(ssl->ctx,1);
+#endif
+
+ return ssl;
+}
+
+/*
+ * Initialize the SSL context, with or without specific
+ * configuration files.
+ */
+SSL_DATA *init_ssl_ctx(SSL_DATA *ssl)
+{
+ if (!(ssl = build_ssl_ctx(ssl))) {
+ syslog(LOG_INFO, "Error Initialize SSL, ctx Instance");
+ syslog(LOG_INFO, " SSL keyfile:%s", ssl->keyfile);
+ syslog(LOG_INFO, " SSL password:%s", ssl->password);
+ syslog(LOG_INFO, " SSL cafile:%s", ssl->cafile);
+ syslog(LOG_INFO, "Terminate...\n");
+ clear_ssl(ssl);
+ return NULL;
+ }
+
+ return ssl;
+}
+
+/* Display SSL error to readable string */
+int ssl_printerr(int err)
+{
+ unsigned long extended_error = 0;
+ char *ssl_strerr;
+
+ switch (err) {
+ case SSL_ERROR_ZERO_RETURN:
+ syslog(LOG_DEBUG, " SSL error: (zero return)");
+ break;
+ case SSL_ERROR_WANT_READ:
+ syslog(LOG_DEBUG, " SSL error: (read error)");
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ syslog(LOG_DEBUG, " SSL error: (write error)");
+ break;
+ case SSL_ERROR_WANT_CONNECT:
+ syslog(LOG_DEBUG, " SSL error: (connect error)");
+ break;
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ syslog(LOG_DEBUG, " SSL error: (X509 lookup error)");
+ break;
+ case SSL_ERROR_SYSCALL:
+ syslog(LOG_DEBUG, " SSL error: (syscall error)");
+ break;
+ case SSL_ERROR_SSL: {
+ ssl_strerr = (char *)MALLOC(500);
+
+ extended_error = ERR_get_error();
+ ERR_error_string(extended_error, ssl_strerr);
+ syslog(LOG_DEBUG, " SSL error: (%s)", ssl_strerr);
+ FREE(ssl_strerr);
+ break;
+ }
+ }
+ return 0;
+}
+
+int ssl_connect(thread *thread)
+{
+ thread_arg *thread_arg;
+ http_thread_arg *checker_arg;
+ REQ *req;
+
+ thread_arg = THREAD_ARG(thread);
+ checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+ req = checker_arg->req;
+
+ req->ssl = SSL_new(thread_arg->root->ssldata->ctx);
+ req->bio = BIO_new_socket(thread->u.fd, BIO_NOCLOSE);
+ SSL_set_bio(req->ssl, req->bio, req->bio);
+
+ return (SSL_connect(req->ssl) > 0)?1:0;
+}
+
+int ssl_send_request(SSL *ssl, char *str_request, int request_len)
+{
+ int err, r = 0;
+
+ while (1) {
+ err = 1;
+ r = SSL_write(ssl, str_request, request_len);
+ if (SSL_ERROR_NONE != SSL_get_error(ssl, r))
+ break;
+ err++;
+ if (request_len != r)
+ break;
+ err++;
+ break;
+ }
+
+ return (err == 3)?1:0;
+}
+
+/* Asynchronous SSL stream reader */
+int ssl_read_thread(thread *thread)
+{
+ thread_arg *thread_arg;
+ http_thread_arg *checker_arg;
+ unsigned char digest[16];
+ REQ *req;
+ int r = 0;
+
+ thread_arg = THREAD_ARG(thread);
+ checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+ req = checker_arg->req;
+
+ /* Handle read timeout */
+ if (thread->type == THREAD_READ_TIMEOUT) {
+ return timeout_epilog(thread,
+ "=> SSL CHECK failed on service : recevice data <=\n\n",
+ "SSL read");
+ }
+
+ /* read the SSL stream */
+ r = SSL_read(req->ssl, req->buffer+req->len, MAX_BUFFER_LENGTH-req->len);
+ req->error = SSL_get_error(req->ssl, r);
+
+ if (req->error) {
+
+ /* All the SSL streal has been parsed */
+ MD5_Final(digest, &req->context);
+ SSL_set_quiet_shutdown(req->ssl, 1);
+
+ r = (req->error == SSL_ERROR_ZERO_RETURN) ? SSL_shutdown(req->ssl) : 0;
+
+ if (r != 1) {
+ /* check if server is currently alive */
+ if (thread_arg->svr->alive) {
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
+ "DOWN", "=> SSL CHECK failed on service : cannot receive data <=\n\n");
+ perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
+ }
+ return epilog(thread,1,0,0);
+ }
+
+ /* Handle response stream */
+ http_handle_response(thread, digest, (!req->extracted)?1:0);
+
+ } else if (r > 0 && req->error == 0) {
+
+ req->len += r;
+ if (!req->extracted) {
+ if ((req->extracted = extract_html(req->buffer, req->len))) {
+ r = req->len-(req->extracted-req->buffer);
+ if (r) {
+ memcpy(req->buffer, req->extracted, r);
+ MD5_Update(&req->context, req->buffer, r);
+ r=0;
+ }
+ req->len = r;
+ } else {
+ /* minimize buffer using no 2*CR/LF found yet */
+ if (req->len > 3) {
+ memcpy(req->buffer, req->buffer + req->len - 3, 3);
+ req->len = 3;
+ }
+ }
+ } else {
+ if (req->len) {
+ MD5_Update(&req->context, req->buffer, req->len);
+ req->len = 0;
+ }
+ }
+
+ /*
+ * Register next ssl stream reader.
+ * Register itself to not perturbe global I/O multiplexer.
+ */
+ thread_add_read(thread->master, ssl_read_thread, thread_arg, thread->u.fd,
+ thread_arg->svr->method->connection_to);
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: check_http.c include file.
+ *
+ * Version: $Id: check_http.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
+ *
+ * Authors: Alexandre Cassen, <acassen@linux-vs.org>
+ * Jan Holmberg, <jan@artech.net>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _SSL_H
+#define _SSL_H
+
+/* local includes */
+#include "check_http.h"
+
+/* Prototypes */
+extern SSL_DATA *init_ssl_ctx(SSL_DATA *ssl);
+extern void clear_ssl(SSL_DATA *ssl);
+extern int ssl_connect(thread *thread);
+extern int ssl_printerr(int err);
+extern int ssl_send_request(SSL *ssl, char *str_request, int request_len);
+extern int ssl_read_thread(thread *thread);
+
+#endif
*
* Part: TCP checker.
*
- * Version: $Id: check_tcp.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: check_tcp.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#include "check_tcp.h"
-int
-tcp_check_thread(struct thread *thread)
+int tcp_check_thread(thread *thread)
{
- struct thread_arg *thread_arg;
+ thread_arg *thread_arg;
int status;
thread_arg = THREAD_ARG(thread);
*/
if (status == connect_success) {
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "TCP connection to [%s:%d] success.",
inet_ntoa(thread_arg->svr->addr_ip),
ntohs(thread_arg->svr->addr_port));
}
} else {
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "TCP connection to [%s:%d] failed !!!",
inet_ntoa(thread_arg->svr->addr_ip),
ntohs(thread_arg->svr->addr_port));
return 0;
}
-int
-tcp_connect_thread(struct thread *thread)
+int tcp_connect_thread(thread *thread)
{
- struct thread_arg *thread_arg;
+ thread_arg *thread_arg;
int fd;
int status;
thread_arg = THREAD_ARG(thread);
if ( (fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) {
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "TCP connect fail to create socket.");
#endif
return 0;
*
* Part: check_tcp.c include file.
*
- * Version: $Id: check_tcp.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: check_tcp.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#include "smtp.h"
/* Prototypes defs */
-extern int tcp_connect_thread(struct thread *thread);
+extern int tcp_connect_thread(thread *thread);
#endif
lvs_id LVS_DEVEL
}
+;SSL {
+ password password
+ ca /etc/keepalived/root.pem
+ certificate /etc/keepalived/dh1024.pem
+ key /etc/keepalived/client.pem
+}
+
+vrrp_instance VI_1 {
+ state MASTER
+ interface eth0
+ virtual_router_id 51
+ priority 100
+ advert_int 1
+ authentication {
+ auth_type AH
+ auth_pass 1111
+ }
+ virtual_ipaddress {
+ 192.168.200.16
+ 192.168.200.17
+ 192.168.200.18
+ }
+}
+
+virtual_server 192.168.200.100 443 {
+ delay_loop 6
+ lb_algo rr
+ lb_kind NAT
+ nat_mask 255.255.255.0
+ persistence_timeout 50
+ protocol TCP
+
+ real_server 192.168.201.100 443 {
+ weight 1
+ SSL_GET {
+ url {
+ path /
+ digest ff20ad2481f97b1754ef3e12ecd3a9cc
+ }
+ url {
+ path /mrtg/
+ digest 9b3a0c85a887a256d6939da88aabd8cd
+ }
+ connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
+ }
+ }
+}
+
virtual_server 10.10.10.2 1358 {
delay_loop 6
lb_algo rr
--- /dev/null
+Alexandre Cassen <acassen@linux-vs.org>
+Jan Holmberg <jan@artech.se>
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
--- /dev/null
+2001-11-29 Alexandre Cassen <acassen@linux-vs.org>
+ * genhash 0.4.9 released.
+ * Rewrite the whole previous code
+ * Jan Holmberg, <jan@artech.se> and I added SSL support.
+ * Possibility to use specific SSL certificate.
+ * Added a command line parser using the popt library.
+ * Added error handling support.
+ * Review the MD5 computation.
+ * Added a dynamic buffer allocation for remote server
+ reply.
--- /dev/null
+Needs
+=====
+
+ Before trying to compile genhash tool you need to install
+ OpenSSL 0.9.6b (http://www.openssl.org).
+
+Installation
+============
+
+ Simply 'make' & 'make install'
+
+Utilisation
+===========
+
+ The genhash tool give you the ability to generate MD5 digest
+ from remote HTTP/HTTPS server connected.
+
+ The global synopsis for the tool is :
+
+ [user@lvs]$ genhash --help
+ genhash Version 0.4.9 (30/11, 2001)
+ Usage:
+ genhash -s server-address -p port -u url
+ genhash -S -K priv-key-file -P pem-password -s server-address -p port -u url
+ genhash -S -K priv-key-file -P pem-password -C cert-file -s server-address -p port -u url
+ genhash -h
+ genhash -v
+
+ Commands:
+ Either long or short options are allowed.
+ genhash --use-ssl -S Use SSL connection to remote server.
+ genhash --server -s Use the specified remote server address.
+ genhash --port -p Use the specified remote server port.
+ genhash --url -u Use the specified remote server url.
+ genhash --use-private-key -K Use the specified SSL private key.
+ genhash --use-password -P Use the specified SSL private key password.
+ genhash --use-certificate -C Use the specified SSL Certificate file.
+ genhash --help -h Display this short inlined help screen.
+ genhash --version -v Display the version number
+
+ Imagine we have a remote HTTP/HTTPS server owning the IP address 192.168.200.10.
+ We want to generate a MD5SUM over the server root url (/).
+ To proceed, simply use :
+
+ [user@lvs]$ genhash -s 192.168.200.10 -p 80 -u /
+ -----------------------[ HTTP Header Buffer ]-----------------------
+ 0000 48 54 54 50 2f 31 2e 31 - 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK.
+ 0010 0a 44 61 74 65 3a 20 57 - 65 64 2c 20 32 38 20 4e .Date: Wed, 28 N
+ ..........................................................................
+ -----------------------[ HTTP Header Ascii Buffer ]-----------------------
+ HTTP/1.1 200 OK
+ ..............
+ -----------------------[ HTML Buffer ]-----------------------
+ 0000 3c 21 44 4f 43 54 59 50 - 45 20 48 54 4d 4c 20 50 <!DOCTYPE HTML P
+ 0010 55 42 4c 49 43 20 22 2d - 2f 2f 57 33 43 2f 2f 44 UBLIC "-//W3C//D
+ ..........................................................................
+ -----------------------[ HTML MD5 resulting ]-----------------------
+ 0000 ff 20 ad 24 81 f9 7b 17 - 54 ef 3e 12 ec d3 a9 cc . .$..{.T.>.....
+ -----------------------[ HTML MD5 final resulting ]-----------------------
+ FF20AD2481F97B1754EF3E12ECD3A9CC
+
+ => So the Hash value generated for the remote HTTP root URL is :
+ http://192.168.200.10/ is FF20AD2481F97B1754EF3E12ECD3A9CC
+
+ Genhash can generate hash values over SSL content. Using the same sample
+ we will obtain :
+ [user@lvs]$ genhash -S -s 192.168.200.10 -p 443 -u /
+ -----------------------[ HTTP Header Buffer ]-----------------------
+ 0000 48 54 54 50 2f 31 2e 31 - 20 32 30 30 20 4f 4b 0d HTTP/1.1 200 OK.
+ 0010 0a 44 61 74 65 3a 20 57 - 65 64 2c 20 32 38 20 4e .Date: Wed, 28 N
+ ..........................................................................
+ -----------------------[ HTTP Header Ascii Buffer ]-----------------------
+ HTTP/1.1 200 OK
+ ..............
+ -----------------------[ HTML Buffer ]-----------------------
+ 0000 3c 21 44 4f 43 54 59 50 - 45 20 48 54 4d 4c 20 50 <!DOCTYPE HTML P
+ 0010 55 42 4c 49 43 20 22 2d - 2f 2f 57 33 43 2f 2f 44 UBLIC "-//W3C//D
+ ..........................................................................
+ -----------------------[ HTML MD5 resulting ]-----------------------
+ 0000 ff 20 ad 24 81 f9 7b 17 - 54 ef 3e 12 ec d3 a9 cc . .$..{.T.>.....
+ -----------------------[ HTML MD5 final resulting ]-----------------------
+ FF20AD2481F97B1754EF3E12ECD3A9CC
+
+ => So the Hash value generated for the remote HTTP root URL is :
+ https://192.168.200.10/ is FF20AD2481F97B1754EF3E12ECD3A9CC
+
+ => The same as http since the document root is a common location for
+ HTTP & HTTPS (in our sample).
+
+
+ In addition with this SSL support, we have added the capability to use
+ specific ssl private key and ssl certificate. Note that the private key
+ need to be generated into the PEM format. In our sample we have generated
+ the SSL file using the following openssl command lines :
+
+ [user@lvs]$ openssl genrsa -des3 -out ssl.key 1024
+ => we use the PEM password : password (really secure :) )
+ [user@lvs]$ openssl req -new -key ssl.key -out ssl.csr
+ [user@lvs]$ openssl req -x509 -key ssl.key -in ssl.csr -out ssl.crt
+ [user@lvs]$ cat ssl.key ssl.crt > ssl.pem
+
+ Then we perform a hash computation using this specific SSL file :
+
+ [user@lvs]$ genhash --use-ssl \
+ --server=192.168.201.100 --port=443 --url=/ \
+ --use-private-key=ssl.pem \
+ --use-password=password \
+ --use-certificate=ssl.crt
+ ..........................................................................
+ -----------------------[ HTML MD5 final resulting ]-----------------------
+ FF20AD2481F97B1754EF3E12ECD3A9CC
+
+
+Have fun with it !
+Alexandre
# Makefile
-# Alexandre Cassen <Alexandre.Cassen@wanadoo.fr>
+# Alexandre Cassen <acassen@linux-vs.org>
-EXEC= genhash
-CC= gcc
-CFLAGS= -Wall
-DEFS= genhash.h md5.h
-OBJECTS= md5.o genhash.o
-INCLUDE= -I/usr/src/linux/include
-.c.o:
- $(CC) -o $@ $(CFLAGS) $(INCLUDE) -c $*.c
+EXEC = genhash
-all: $(EXEC)
- strip $(EXEC)
- @echo ""
- @echo "Make complete"
+CC = gcc
+CFLAGS = -Wall -Wunused -Wstrict-prototypes -g -O2
+#LD = -lssl -lcrypto -dynamic -lpopt
+LD = -lssl -lcrypto -lpopt
-$(EXEC): $(OBJECTS) $(DEFS)
- $(CC) -o $(EXEC) $(CFLAGS) $(OBJECTS)
+OBJS = main.o client.o common.o
+all: genhash
+ strip genhash
+ @echo ""
+ @echo "Make complete"
+$(EXEC): $(OBJS)
+ $(CC) $(OBJS) -o $(EXEC) $(LD)
clean:
rm -f core *.o $(EXEC)
-
install:
install -m 755 genhash /usr/bin/
--- /dev/null
+The main goal of the keepalived project is to add a strong & robust
+keepalive facility to the Linux Virtual Server project.
+It implements a multilayer TCP/IP stack checks. Keepalived implements
+a framework based on three family checks : Layer3, Layer4 & Layer5.
+This framework gives the daemon the ability of checking a LVS server
+pool states. Keepalived can be sumarize as a LVS driving daemon.
+
+To generate MD5SUM digest the this tool (genhash) is used.
+
+Keepalived is free software. See the file COPYING for copying conditions.
--- /dev/null
+* Create a generic function to handle remote server reply.
+ That way we will remove duplicate code for read reply.
+* beautifull the code.
--- /dev/null
+/*
+ * Soft: Genhash compute MD5 digest from a HTTP get result. This
+ * program is use to compute hash value that you will add
+ * into the /etc/keepalived/keepalived.conf for HTTP_GET
+ * & SSL_GET keepalive method.
+ *
+ * Part: Layer4 global functions.
+ *
+ * Version: $Id: client.c,v 0.4.9 2001/11/28 11:50:23 acassen Exp $
+ *
+ * Authors: Alexandre Cassen, <acassen@linux-vs.org>
+ * Jan Holmberg, <jan@artech.se>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "client.h"
+
+int tcp_connect(int fd, char *host, int port)
+{
+ int long_inet = sizeof(struct sockaddr_in);
+ struct sockaddr_in adr_serv;
+ struct hostent *ip_serv;
+ int arglen;
+ struct timeval tv;
+ fd_set wfds;
+ int rc, val;
+
+ /* Proceed remote hostname */
+ memset(&ip_serv, 0, sizeof(struct hostent));
+ if ((ip_serv = gethostbyname(host)) == NULL)
+ return TCP_RESOLV_ERROR;
+
+ /* Fill in connection structure */
+ memset(&adr_serv, 0, long_inet);
+ adr_serv.sin_family = AF_INET;
+ adr_serv.sin_port = htons(port);
+ adr_serv.sin_addr = *(struct in_addr*)ip_serv->h_addr;
+
+ /* Set read/write socket nonblock */
+ val = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, val | O_NONBLOCK);
+
+ /* Connect the remote host */
+ rc = connect(fd, (struct sockaddr *)&adr_serv, long_inet);
+ if (rc == -1) {
+ if (errno != EINPROGRESS) {
+ rc = errno;
+ return TCP_CONNECT_ERROR;
+ }
+ }
+
+ /* Timeout settings */
+ tv.tv_sec = SOCKET_TIMEOUT_READ;
+ tv.tv_usec = 0;
+ FD_ZERO(&wfds);
+ FD_SET(fd, &wfds);
+
+ rc = select(fd+1, NULL, &wfds, NULL, &tv);
+ if (!FD_ISSET(fd, &wfds))
+ return TCP_WRITE_TIMEOUT;
+
+ if (rc <= 0) return TCP_SELECT_ERROR;
+
+ rc = 0;
+ arglen = sizeof(int);
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &rc, &arglen) < 0)
+ rc = errno;
+ if (rc) return TCP_CONNECT_FAILED;
+
+ /* Restore socket parameters */
+ fcntl(fd, F_SETFL, val);
+
+ return TCP_CONNECT_SUCCESS;
+}
+
+int tcp_send(int fd, char *request, int len)
+{
+ if (send(fd, request, len, 0) == -1)
+ return TCP_SEND_ERROR;
+ return 0;
+}
+
+int tcp_read_to(int fd)
+{
+ struct timeval tv;
+ fd_set rfds;
+
+ /* Timeout settings */
+ tv.tv_sec = SOCKET_TIMEOUT_READ;
+ tv.tv_usec = 0;
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+
+ /* attempt read data */
+ select(fd+1, &rfds, NULL, NULL, &tv);
+ if (!FD_ISSET(fd, &rfds))
+ return TCP_READ_TIMEOUT;
+ return 0;
+}
+
+int tcp_sock(void)
+{
+ int fd;
+ struct sockaddr_in adr_local;
+
+ if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) return (-1);
+ memset(&adr_local, 0, sizeof(struct sockaddr_in));
+ adr_local.sin_family = AF_INET;
+ adr_local.sin_port = htons(0);
+ adr_local.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ if (bind(fd, (struct sockaddr *)&adr_local, sizeof(struct sockaddr_in))) return (-1);
+
+ return(fd);
+}
--- /dev/null
+/*
+ * Soft: Genhash compute MD5 digest from a HTTP get result. This
+ * program is use to compute hash value that you will add
+ * into the /etc/keepalived/keepalived.conf for HTTP_GET
+ * & SSL_GET keepalive method.
+ *
+ * Part: client.c include file.
+ *
+ * Version: $Id: client.h,v 0.4.9 2001/11/28 11:50:23 acassen Exp $
+ *
+ * Authors: Alexandre Cassen, <acassen@linux-vs.org>
+ * Jan Holmberg, <jan@artech.se>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _CLIENT_H
+#define _CLIENT_H
+
+/* System includes */
+#include <stdio.h>
+#include <netdb.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+/* Socket timeout */
+#define SOCKET_TIMEOUT_READ 3
+#define SOCKET_TIMEOUT_WRITE 3
+
+/* Return codes */
+/* systems predefined ret codes */
+#define OUT_OF_MEMORY (1 << 0)
+
+/* TCP predefined ret codes */
+#define TCP_BIND_ERROR (1 << 1)
+#define TCP_RESOLV_ERROR (1 << 2)
+#define TCP_CONNECT_ERROR (1 << 3)
+#define TCP_CONNECT_SUCCESS (1 << 4)
+#define TCP_WRITE_TIMEOUT (1 << 5)
+#define TCP_SELECT_ERROR (1 << 6)
+#define TCP_CONNECT_FAILED (1 << 7)
+#define TCP_SEND_ERROR (1 << 8)
+#define TCP_READ_TIMEOUT (1 << 9)
+
+/* Upper Layer - HTTP predefined ret codes */
+#define HTTP_GET_SUCCESS (1 << 10)
+
+/* Upper Layer - SSL predefined ret codes */
+#define SSL_WRITE_ERROR (1 << 11)
+#define SSL_INCOMPLETE_WRITE (1 << 12)
+#define SSL_READ_ERROR (1 << 13)
+#define SSL_SHUTDOWN_FAILED (1 << 14)
+#define SSL_GET_SUCCESS (1 << 15)
+
+/* Prototypes */
+extern int tcp_connect(int fd, char *host, int port);
+extern int tcp_send(int fd, char *request, int len);
+extern int tcp_read_to(int fd);
+extern int tcp_sock(void);
+
+#endif
+
--- /dev/null
+/*
+ * Soft: Genhash compute MD5 digest from a HTTP get result. This
+ * program is use to compute hash value that you will add
+ * into the /etc/keepalived/keepalived.conf for HTTP_GET
+ * & SSL_GET keepalive method.
+ *
+ * Part: Common SSL functions.
+ *
+ * Version: $Id: common.c,v 0.4.9 2001/11/28 11:50:23 acassen Exp $
+ *
+ * Authors: Alexandre Cassen, <acassen@linux-vs.org>
+ * Jan Holmberg, <jan@artech.se>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <openssl/err.h>
+#include "common.h"
+
+static BIO *bio_err = 0;
+static char *pass;
+
+/* A simple error and exit routine*/
+int err_exit(char *string)
+{
+ fprintf(stderr, "%s\n", string);
+ exit(0);
+}
+
+/* Print SSL errors and exit*/
+int berr_exit(char *string)
+{
+ BIO_printf(bio_err, "%s\n", string);
+ ERR_print_errors(bio_err);
+ exit(0);
+}
+
+/*The password code is not thread safe*/
+static int password_cb(char *buf, int num, int rwflag, void *userdata)
+{
+ if (num < strlen(pass)+1)
+ return(0);
+
+ strcpy(buf, pass);
+ return(strlen(pass));
+}
+
+static void sigpipe_handle(int x) {
+}
+
+/* SSL context initializer */
+SSL_CTX *initialize_ctx(char *keyfile, char *password, char *cafile)
+{
+ SSL_METHOD *meth;
+ SSL_CTX *ctx;
+
+ if (!bio_err){
+ /* Global system initialization*/
+ SSL_library_init();
+ SSL_load_error_strings();
+
+ /* An error write context */
+ bio_err = BIO_new_fp(stderr, BIO_NOCLOSE);
+ }
+
+ /* Set up a SIGPIPE handler */
+ signal(SIGPIPE, sigpipe_handle);
+
+ /* Create our context*/
+ meth = SSLv23_method();
+ ctx = SSL_CTX_new(meth);
+
+ /* Load our keys and certificates*/
+ if (keyfile)
+ if(!(SSL_CTX_use_certificate_chain_file(ctx, keyfile)))
+ berr_exit("Can't read certificate file");
+
+ if (password) {
+ pass = password;
+ SSL_CTX_set_default_passwd_cb(ctx, password_cb);
+ }
+
+ if (keyfile)
+ if(!(SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM)))
+ berr_exit("Can't read key file");
+
+ /* Load the CAs we trust*/
+ if (cafile)
+ if(!(SSL_CTX_load_verify_locations(ctx, cafile, 0)))
+ berr_exit("Can't read CA list");
+#if (OPENSSL_VERSION_NUMBER < 0x00905100L)
+ SSL_CTX_set_verify_depth(ctx,1);
+#endif
+
+ return ctx;
+}
+
+void destroy_ctx(SSL_CTX *ctx)
+{
+ SSL_CTX_free(ctx);
+}
--- /dev/null
+/*
+ * Soft: Genhash compute MD5 digest from a HTTP get result. This
+ * program is use to compute hash value that you will add
+ * into the /etc/keepalived/keepalived.conf for HTTP_GET
+ * & SSL_GET keepalive method.
+ *
+ * Part: common.c include file.
+ *
+ * Version: $Id: common.h,v 0.4.9 2001/11/28 11:50:23 acassen Exp $
+ *
+ * Authors: Alexandre Cassen, <acassen@linux-vs.org>
+ * Jan Holmberg, <jan@artech.se>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _COMMON_H
+#define _COMMON_H
+
+/* System includes */
+#include <string.h>
+#include <signal.h>
+#include <openssl/ssl.h>
+
+/* prototypes */
+extern int berr_exit(char *string);
+extern int err_exit(char *string);
+extern SSL_CTX *initialize_ctx(char *keyfile, char *password, char *cafile);
+extern void destroy_ctx(SSL_CTX *ctx);
+
+#ifndef ALLOW_OLD_VERSIONS
+#if(OPENSSL_VERSION_NUMBER < 0x00905100L)
+#error "Must use OpenSSL 0.9.6 or later"
+#endif
+#endif
+
+#endif
+++ /dev/null
-/*
- * Soft: Genhash compute MD5 digest from a HTTP get result. This
- * program is use to compute hash value that you will add
- * into the /etc/keepalived/keepalived.conf for the
- * HTTP_GET_CHECK.
- *
- * Version: $Id: keepalived.c,v 0.3.0 2001/02/10 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : 2001/03/27 :
- * <+> Use non blocking socket.
- *
- * 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
- * 2 of the License, or (at your option) any later version.
- */
-
-#include "genhash.h"
-
-void print_buffer(int count, char *buff)
-{
- int i,j,c;
- int printnext=1;
-
- if(count) {
- if(count%16)
- c=count+(16-count%16);
- else c=count;
- } else
- c=count;
-
- for(i=0;i<c;i++) {
- if(printnext) {
- printnext--;
- printf("%.4x ",i&0xffff);
- }
- if(i<count)
- printf("%3.2x",buff[i]&0xff);
- else
- printf(" ");
- if(!((i+1)%8)) {
- if((i+1)%16)
- printf(" -");
- else {
- printf(" ");
- for(j=i-15;j<=i;j++)
- if(j<count) {
- if( (buff[j]&0xff) >= 0x20 && (buff[j]&0xff)<=0x7e)
- printf("%c",buff[j]&0xff);
- else printf(".");
- } else printf(" ");
- printf("\n"); printnext=1;
- }
- }
- }
-}
-
-char *extract_html(char *buffer, int size_buffer)
-{
- char *end=buffer+size_buffer;
-
- while ( buffer < end && !(*buffer++ == '\n' &&
- (*buffer == '\n' || (*buffer++ == '\r' && *buffer =='\n'))));
-
- if (*buffer == '\n') return buffer+1;
- return NULL;
-}
-
-int new_sock(int type)
-{
- int sd;
- struct sockaddr_in adr_local;
- if ( (sd = socket(AF_INET, type, 0)) == -1 ) return (-1);
-
- bzero(&adr_local, sizeof(struct sockaddr_in));
- adr_local.sin_family = AF_INET;
- adr_local.sin_port = htons(0);
- adr_local.sin_addr.s_addr = htonl(INADDR_ANY);
-
- if ( bind(sd, (struct sockaddr *)&adr_local, sizeof(struct sockaddr_in)) ) return (-1);
-
- return (sd);
-}
-
-int HTTP_GET(char *IP_DST, unsigned short int PORT_DST, char *URL, char *buffer)
-{
- register int sdesc;
- int long_inet;
- int rcv_buffer_size=0;
- long total_length=0;
- char *str_request;
- char *buffertmp;
- struct hostent *ip_serv;
- struct sockaddr_in adr_serv;
- struct timeval tv;
- fd_set rfds, wfds;
- int rc,val;
- int arglen;
-
- str_request=(char *)malloc(GET_BUFFER_LENGTH);
- buffertmp=(char *)malloc(RCV_BUFFER_LENGTH);
- memset(buffertmp,0,RCV_BUFFER_LENGTH);
-
- sprintf(str_request,GETCMD,URL);
-
- if ( (sdesc=new_sock(SOCK_STREAM)) == -1 ) {
- printf("-[ Can not bind remote address ]-\n");
- free(str_request);
- free(buffertmp);
- return(ERROR_SOCKET);
- }
-
- long_inet = sizeof(struct sockaddr_in);
-
- if ( (ip_serv=gethostbyname(IP_DST)) == NULL) {
- printf("-[ Can not resolve remote host ]-\n");
- free(str_request);
- free(buffertmp);
- close(sdesc);
- return(ERROR_SOCKET);
- }
-
- bzero(&adr_serv,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(PORT_DST);
-
- /* Set read/write socket timeout */
- val=fcntl(sdesc, F_GETFL);
- fcntl(sdesc, F_SETFL, val | O_NONBLOCK);
-
- /* Connect the remote host */
- if ( (rc=connect(sdesc, (struct sockaddr *)&adr_serv, long_inet)) == -1 ) {
- switch (errno) {
- case ETIMEDOUT:
- case EINTR:
- case EHOSTUNREACH:
- printf("-[ Connect error : Timeout ]-\n");
- break;
- case ECONNREFUSED:
- printf("-[ Connect error : Connectiono refused ]-\n");
- break;
- case ENETUNREACH:
- printf("-[ Connect error : Network unreachable ]-\n");
- break;
- case EINPROGRESS:
- printf("-[ NONBLOCK socket connection in progress ]-\n");
- goto next;
- default:
- printf("-[ Connect error : Error code %d (%s) ]-\n",errno,strerror(errno));
- }
-
- free(str_request);
- free(buffertmp);
- close(sdesc);
- return(ERROR_SOCKET);
- }
-
-next:
- /* Timeout settings */
- tv.tv_sec=SOCKET_TIMEOUT_READ;
- tv.tv_usec=0;
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_SET(sdesc,&rfds);
- FD_SET(sdesc,&wfds);
-
- rc = select(sdesc+1,NULL,&wfds,NULL,&tv);
- if (!FD_ISSET(sdesc,&wfds)) {
- printf("-[ Timeout writing data ]-\n");
- free(str_request);
- free(buffertmp);
- close(sdesc);
- return(ERROR_SOCKET);
- }
-
- if (rc <= 0) {
- printf("-[ select() bad returned descriptor ]-\n");
- free(str_request);
- free(buffertmp);
- close(sdesc);
- return(ERROR_SOCKET);
- }
-
- rc = 0;
- arglen=sizeof(int);
- if (getsockopt(sdesc,SOL_SOCKET,SO_ERROR,&rc,&arglen) < 0)
- rc = errno;
-
- if (rc) {
- printf("-[ Connection failed - error : %d (%s) ]-\n",rc,strerror(rc));
- free(str_request);
- free(buffertmp);
- close(sdesc);
- return(ERROR_SOCKET);
- }
-
- if (send(sdesc,str_request,strlen(str_request),0) == -1) {
- printf("-[ Can not send data to remote host ]-\n");
- free(str_request);
- free(buffertmp);
- close(sdesc);
- return(ERROR_SOCKET);
- }
-
- /* Proceed the HTTP server reply */
- select(sdesc+1,&rfds,NULL,NULL,&tv);
- if (!FD_ISSET(sdesc,&rfds)) {
- printf("-[ Timeout reading data ]-\n");
- free(str_request);
- free(buffertmp);
- close(sdesc);
- return(ERROR_SOCKET);
- }
-
- while((rcv_buffer_size = read(sdesc,buffertmp,RCV_BUFFER_LENGTH)) != 0) {
- if (rcv_buffer_size == -1) {
- if(errno == EAGAIN) goto end;
- free(str_request);
- free(buffertmp);
- close(sdesc);
- return(ERROR_SOCKET);
- }
- printf("-[ Reading data from remote host ]-\n");
- memcpy(buffer+total_length,buffertmp,rcv_buffer_size);
- memset(buffertmp,0,RCV_BUFFER_LENGTH);
- total_length += rcv_buffer_size;
- }
-
-end:
- close(sdesc);
- free(str_request);
- free(buffertmp);
- return(total_length);
-}
-
-
-int main(int argc, char **argv)
-{
- char *buffer_http;
- char *buffer_html;
- int buffer_http_size=0;
- char *MDResult;
- md5_state_t state;
- md5_byte_t digest[16];
- int di;
-
- printf(PROG" v"VERSION"\n");
- if (argc < 4) {
- printf("Usage: %s <IP address> <TCP port> <url path>\n", argv[0]);
- return(0);
- }
-
- buffer_http=(char *)malloc(RCV_BUFFER_LENGTH);
- MDResult=(char *)malloc(16*2*sizeof(char *));
- memset(buffer_http,0,RCV_BUFFER_LENGTH);
- memset(MDResult,0,16*2*sizeof(char *));
-
- buffer_http_size=HTTP_GET(argv[1],atoi(argv[2]),argv[3],buffer_http);
- buffer_html=extract_html(buffer_http,buffer_http_size);
-
- if(buffer_http_size > 0) {
- printf("---------------------------[ Received Buffer ]----------------------------\n");
- printf("%s\n",buffer_http);
-
- printf("--------------------------[ HTTP Header Buffer ]--------------------------\n");
- print_buffer(buffer_html-buffer_http,buffer_http);
-
- printf("------------------------------[ HTML Buffer ]-----------------------------\n");
- print_buffer(buffer_http_size-(buffer_html-buffer_http),buffer_html);
-
- printf("----------------------------[ HTML MD5 resulting ]------------------------\n");
- md5_init(&state);
- md5_append(&state, buffer_html,buffer_http_size-(buffer_html-buffer_http));
- md5_finish(&state,digest);
-
- for (di=0; di < 16; ++di)
- sprintf(MDResult+2*di,"%02x",digest[di]);
-
- printf("MD5 Digest : %s\n",MDResult);
- } else {
- printf("No buffer returned...\n");
- }
-
- free(MDResult);
- free(buffer_http);
- return(1);
-}
+++ /dev/null
-/*
- * Soft: Genhash compute MD5 digest from a HTTP get result. This
- * program is use to compute hash value that you will add
- * into the /etc/keepalived/keepalived.conf for the
- * HTTP_GET_CHECK.
- *
- * Part: genhash.c include file.
- *
- * Version: $Id: keepalived.c,v 0.2.0 2000/12/09 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : 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
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef GENHASH_H
-#define GENHASH_H
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <termios.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <netdb.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <linux/if_ether.h>
-#include <netinet/tcp.h>
-#include <netinet/ip_icmp.h>
-#include <fcntl.h>
-#include <string.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include "md5.h"
-
-#define GETCMD "GET %s HTTP/1.0\r\n\r\n"
-
-/* Socket Timeout */
-#define SOCKET_TIMEOUT_READ 3
-#define SOCKET_TIMEOUT_CONNECT 3
-
-/* Sockets connection errors codes */
-#define ERROR_SOCKET 0
-
-/* Data buffer length description */
-#define GET_BUFFER_LENGTH 180
-#define RCV_BUFFER_LENGTH 1024
-
-/* Build version */
-#define PROG "genhash"
-#define VERSION "0.2.3 (27/03, 2001), Alexandre Cassen"
-
-#endif
--- /dev/null
+/*
+ * Soft: Genhash compute MD5 digest from a HTTP get result. This
+ * program is use to compute hash value that you will add
+ * into the /etc/keepalived/keepalived.conf for HTTP_GET
+ * & SSL_GET keepalive method.
+ *
+ * Part: Main part performing get request and MD5SUM over content.
+ *
+ * Version: $Id: main.c,v 0.4.9 2001/11/28 11:50:23 acassen Exp $
+ *
+ * Authors: Alexandre Cassen, <acassen@linux-vs.org>
+ * Jan Holmberg, <jan@artech.se>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "main.h"
+#include "common.h"
+#include "client.h"
+
+/* Dump a buffer (ASCII or Binary) */
+static void print_buffer(int count, char *buff)
+{
+ int i,j,c;
+ int printnext=1;
+
+ if(count) {
+ if(count%16)
+ c=count+(16-count%16);
+ else c=count;
+ } else
+ c=count;
+
+ for(i=0;i<c;i++) {
+ if(printnext) {
+ printnext--;
+ printf("%.4x ",i&0xffff);
+ }
+ if(i<count)
+ printf("%3.2x",buff[i]&0xff);
+ else
+ printf(" ");
+ if(!((i+1)%8)) {
+ if((i+1)%16)
+ printf(" -");
+ else {
+ printf(" ");
+ for(j=i-15;j<=i;j++)
+ if(j<count) {
+ if( (buff[j]&0xff) >= 0x20 && (buff[j]&0xff)<=0x7e)
+ printf("%c",buff[j]&0xff);
+ else printf(".");
+ } else printf(" ");
+ printf("\n"); printnext=1;
+ }
+ }
+ }
+}
+
+/* Allocate & clean a buffer */
+static char *xmalloc(const int size)
+{
+ char *buffer;
+
+ buffer = (char *)malloc(size);
+ if (!buffer) return NULL;
+ memset(buffer, 0, size);
+
+ return buffer;
+}
+
+/* Return the html header from a global HTTP buffer */
+static char *extract_html(char *buffer, int size_buffer)
+{
+ char *end=buffer+size_buffer;
+
+ while ( buffer < end && !(*buffer++ == '\n' &&
+ (*buffer == '\n' || (*buffer++ == '\r' && *buffer =='\n'))));
+
+ if (*buffer == '\n') return buffer+1;
+ return NULL;
+}
+
+/* Build the GET request */
+static char *build_request(REQ* req)
+{
+ char *request;
+ int request_len = 0;
+
+ request_len = strlen(REQUEST_TEMPLATE) + strlen(req->host) + 12;
+ request = xmalloc(request_len);
+ if (!request) return NULL;
+
+ snprintf(request, request_len
+ , REQUEST_TEMPLATE
+ , req->url
+ , req->host
+ , req->port);
+ return request;
+}
+
+static int https_request(SSL *ssl, REQ *req)
+{
+ char *request = NULL;
+ int r, i, e = 0;
+ int request_len;
+ char *extracted;
+ unsigned char digest[16];
+ MD5_CTX context;
+
+ /* Build the SSL request */
+ request = build_request(req);
+ if (!request) return OUT_OF_MEMORY;
+ request_len = strlen(request);
+
+ /* Send the SSL request */
+ r = SSL_write(ssl, request, request_len);
+ if (SSL_ERROR_NONE != SSL_get_error(ssl, r)) {
+ free(request);
+ return SSL_WRITE_ERROR;
+ }
+
+ /* Test for eventual imcomplete SSL write */
+ if (request_len != r) {
+ free(request);
+ return SSL_INCOMPLETE_WRITE;
+ }
+
+ /* Init MD5 context */
+ MD5_Init(&context);
+ extracted = NULL;
+ req->len = 0;
+ e = 0;
+
+ /*
+ * Now read the server's response, assuming
+ * that it's terminated by a close.
+ *
+ * FIXME: Create a function to read data from remote
+ * server instead of code duplication.
+ */
+ printf(HTTP_HEADER_HEXA);
+
+ while (!e) {
+ r = SSL_read(ssl, req->buffer+req->len, req->max-req->len);
+ e = SSL_get_error(ssl, r);
+ if (e != SSL_ERROR_NONE) break;
+ if (r > 0 && e == 0) {
+ req->len +=r;
+ /* Only header yet ? */
+ if (!extracted) {
+ /* Found something more than header ? */
+ if ((extracted = extract_html(req->buffer, req->len))) {
+ r = req->len-(extracted-req->buffer);
+ if (r) {
+ print_buffer(r, req->buffer);
+ printf(HTTP_HEADER_ASCII);
+ for (i=0; i < extracted-req->buffer; i++)
+ printf("%c", req->buffer[i]);
+ printf("\n");
+ printf(HTML_HEADER_HEXA);
+ memcpy(req->buffer,extracted,r);
+ MD5_Update(&context, req->buffer, r);
+ r = 0;
+ }
+ req->len = r;
+ } else {
+ if ( req->len > 3 ) {
+ print_buffer(req->len - 3 , req->buffer);
+ printf(HTTP_HEADER_ASCII);
+ for (i=0; i < req->len -3 ; i++)
+ printf("%c", req->buffer[i]);
+ printf("\n");
+ printf(HTML_HEADER_HEXA);
+ memcpy( req->buffer, req->buffer+req->len-3, 3);
+ req->len = 3;
+ }
+ }
+ } else {
+ if ( req -> len ) {
+ print_buffer(req->len, req->buffer);
+ MD5_Update(&context, req->buffer, req->len);
+ req->len = 0;
+ }
+ }
+ }
+ }
+
+ /* Error handling */
+ if (e != SSL_ERROR_ZERO_RETURN && e != SSL_ERROR_SYSCALL) {
+ free(request);
+ return SSL_READ_ERROR;
+ }
+
+ if (e == SSL_ERROR_ZERO_RETURN)
+ if (SSL_shutdown(ssl) != 1) {
+ free(request);
+ return SSL_SHUTDOWN_FAILED;
+ }
+
+ if (e != SSL_ERROR_SYSCALL)
+ SSL_free(ssl);
+
+ MD5_Final(digest, &context);
+ printf(HTML_MD5);
+ print_buffer(16, digest);
+
+ printf(HTML_MD5_FINAL);
+ for (r=0; r<16; r++)
+ printf("%02x", digest[r]);
+ printf("\n\n");
+
+ free(request);
+ return SSL_GET_SUCCESS;
+}
+
+/*
+ * Connect a remote SSL server and generate a MD5SUM
+ * Upon the remote HTML content returned.
+ */
+static int genhash_ssl(REQ * req)
+{
+ SSL_CTX *ctx;
+ SSL *ssl;
+ BIO *sbio;
+ int retcode = 0;
+
+ /* SSL context initialization */
+ ctx = initialize_ctx(req->keyfile, req->password, req->cafile);
+
+ /* TCP socket creation */
+ req->fd = tcp_sock();
+ if (req->fd == -1) {
+ destroy_ctx(ctx);
+ return TCP_BIND_ERROR;
+ }
+
+ /* TCP connect remote host */
+ retcode = tcp_connect(req->fd, req->host, req->port);
+ if (retcode != TCP_CONNECT_SUCCESS) goto end;
+
+ /* Create the SSL context */
+ ssl = SSL_new(ctx);
+ sbio = BIO_new_socket(req->fd, BIO_NOCLOSE);
+ SSL_set_bio(ssl, sbio, sbio);
+
+ /* Connect remote SSL server */
+ if (SSL_connect(ssl) <= 0)
+ return -2;
+
+ /* Proceed the SSL server reply */
+ retcode = https_request(ssl, req);
+
+end:
+ /* Shutdown the socket */
+ destroy_ctx(ctx);
+ close(req->fd);
+ return(retcode);
+}
+
+/*
+ * Connect a remote HTTP server and generate a MD5SUM
+ * Upon the remote HTML content returned.
+ */
+static int genhash_http(REQ *req)
+{
+ int request_len = 0;
+ char *request = NULL;
+ char *buffertmp = NULL;
+ int retcode = 0;
+ int r;
+ char *extracted;
+ unsigned char digest[16];
+ MD5_CTX context;
+
+ /* Temporary get buffer allocation */
+ buffertmp = xmalloc(RCV_BUFFER_LENGTH);
+ if (!buffertmp) {
+ free(request);
+ return OUT_OF_MEMORY;
+ }
+
+ /* Build the HTTP request */
+ request = build_request(req);
+ if (!request) {
+ free(buffertmp);
+ return OUT_OF_MEMORY;
+ }
+ request_len = strlen(request);
+
+ /* TCP socket creation */
+ req->fd = tcp_sock();
+ if (req->fd == -1) {
+ free(request);
+ free(buffertmp);
+ return TCP_BIND_ERROR;
+ }
+
+ /* TCP connect remote host */
+ retcode = tcp_connect(req->fd, req->host, req->port);
+ if (retcode != TCP_CONNECT_SUCCESS) goto error;
+
+ /* Send the HTTP request */
+ retcode = tcp_send(req->fd, request, request_len);
+ if (retcode == TCP_SEND_ERROR) goto error;
+
+ /* Proceed the HTTP server reply */
+ retcode = tcp_read_to(req->fd);
+ if (retcode == TCP_READ_TIMEOUT) goto error;
+
+ MD5_Init(&context);
+ extracted = NULL;
+ req->len = 0;
+
+ /*
+ * Now read the server's response.
+ *
+ * FIXME: Create a function to read data from remote
+ * server instead of code duplication.
+ */
+ printf(HTTP_HEADER_HEXA);
+ while (1) {
+ r = read(req->fd, buffertmp, RCV_BUFFER_LENGTH);
+ if (r == -1 || r == 0) break;
+ memcpy(req->buffer+req->len, buffertmp, r);
+ req->len += r;
+ if (!extracted &&
+ (extracted = extract_html(req->buffer, req->len))) {
+ print_buffer(extracted-req->buffer, req->buffer);
+ printf(HTTP_HEADER_ASCII);
+ for ( r=0; r < extracted-req->buffer; r++)
+ printf("%c", req->buffer[r]);
+ printf("\n");
+
+ printf(HTML_HEADER_HEXA);
+ r = req->len - (extracted-req->buffer);
+ if (r)
+ memcpy(req->buffer,extracted,r);
+ req->len = r;
+ }
+
+ if (extracted && req->len) {
+ print_buffer(req->len, req->buffer);
+ MD5_Update(&context, req->buffer, req->len);
+ req->len = 0;
+ }
+ }
+
+ MD5_Final(digest, &context);
+ printf(HTML_MD5);
+ print_buffer(16, digest);
+
+ printf(HTML_MD5_FINAL);
+ for (r=0; r<16; r++)
+ printf("%02x", digest[r]);
+ printf("\n\n");
+
+ /* All is fine just return a success code */
+ retcode = HTTP_GET_SUCCESS;
+
+error:
+ close(req->fd);
+ free(request);
+ free(buffertmp);
+ return(retcode);
+}
+
+/* Error return function */
+static void print_error(int err)
+{
+ switch (err) {
+ /* System errors */
+ case OUT_OF_MEMORY: err_exit("Out Of Memery"); break;
+
+ /* TCP errors */
+ case TCP_BIND_ERROR: err_exit("TCP Bind error"); break;
+ case TCP_RESOLV_ERROR: err_exit("TCP Resolv error"); break;
+ case TCP_CONNECT_ERROR: err_exit("TCP Connect error"); break;
+ case TCP_WRITE_TIMEOUT: err_exit("TCP Write TimeOut"); break;
+ case TCP_READ_TIMEOUT: err_exit("TCP Read error"); break;
+ case TCP_SELECT_ERROR: err_exit("TCP Select error"); break;
+ case TCP_CONNECT_FAILED: err_exit("TCP Connectin failed"); break;
+ case TCP_SEND_ERROR: err_exit("TCP Send error"); break;
+
+ /* SSL errors */
+ case SSL_WRITE_ERROR: err_exit("SSL Write error"); break;
+ case SSL_INCOMPLETE_WRITE: err_exit("SSL Incomplete write");break;
+ case SSL_READ_ERROR: err_exit("SSL Read error"); break;
+ case SSL_SHUTDOWN_FAILED:err_exit("SSL Shutdown failed"); break;
+ }
+}
+
+/* Usage function */
+static void usage(const char *prog)
+{
+ fprintf(stderr, "%s Version %s\n", PROG, VERSION);
+ fprintf(stderr,
+ "Usage:\n"
+ " %s -s server-address -p port -u url\n"
+ " %s -S -K priv-key-file -P pem-password -s server-address -p port -u url\n"
+ " %s -S -K priv-key-file -P pem-password -C cert-file -s server-address -p port -u url\n"
+ " %s -h\n"
+ " %s -v\n\n",
+ prog, prog, prog, prog, prog);
+ fprintf(stderr,
+ "Commands:\n"
+ "Either long or short options are allowed.\n"
+ " %s --use-ssl -S Use SSL connection to remote server.\n"
+ " %s --server -s Use the specified remote server address.\n"
+ " %s --port -p Use the specified remote server port.\n"
+ " %s --url -u Use the specified remote server url.\n"
+ " %s --use-private-key -K Use the specified SSL private key.\n"
+ " %s --use-password -P Use the specified SSL private key password.\n"
+ " %s --use-certificate -C Use the specified SSL Certificate file.\n"
+ " %s --help -h Display this short inlined help screen.\n"
+ " %s --version -v Display the version number\n",
+ prog, prog, prog, prog, prog, prog, prog, prog, prog);
+}
+
+/* Command line parser */
+static int parse_cmdline(int argc, char **argv, REQ *req)
+{
+ poptContext context;
+ char *optarg = NULL;
+ int c;
+
+ struct poptOption options_table[] = {
+ {"version", 'v', POPT_ARG_NONE, NULL, 'v'},
+ {"help", 'h', POPT_ARG_NONE, NULL, 'h'},
+ {"use-ssl", 'S', POPT_ARG_NONE, NULL, 'S'},
+ {"server", 's', POPT_ARG_STRING, &optarg, 's'},
+ {"port", 'p', POPT_ARG_STRING, &optarg, 'p'},
+ {"url", 'u', POPT_ARG_STRING, &optarg, 'u'},
+ {"use-private-key", 'K', POPT_ARG_STRING, &optarg, 'K'},
+ {"use-password", 'P', POPT_ARG_STRING, &optarg, 'P'},
+ {"use-certificate", 'C', POPT_ARG_STRING, &optarg, 'C'},
+ {NULL, 0, 0, NULL, 0}
+ };
+
+ context = poptGetContext(PROG, argc, (const char **)argv
+ , options_table, 0);
+ if ((c = poptGetNextOpt(context)) < 0) {
+ usage(argv[0]);
+ return CMD_LINE_ERROR;
+ }
+
+ /* The first option car */
+ switch (c) {
+ case 'v':
+ fprintf(stderr, "%s Version %s\n", PROG, VERSION);
+ break;
+ case 'h':
+ usage(argv[0]);
+ break;
+ case 'S':
+ req->ssl = 1;
+ break;
+ case 's':
+ req->host = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ return CMD_LINE_ERROR;
+ }
+
+ /* the others */
+ while ((c = poptGetNextOpt(context)) >= 0) {
+ switch (c) {
+ case 's':
+ req->host = optarg;
+ break;
+ case 'p':
+ req->port = atoi(optarg);
+ break;
+ case 'u':
+ req->url = optarg;
+ break;
+ case 'K':
+ req->keyfile = optarg;
+ break;
+ case 'P':
+ req->password = optarg;
+ break;
+ case 'C':
+ req->cafile = optarg;
+ break;
+ default:
+ usage(argv[0]);
+ return CMD_LINE_ERROR;
+ }
+ }
+
+ /* check unexpected arguments */
+ if ((optarg = (char *)poptGetArg(context))) {
+ fprintf(stderr, "unexpected argument %s", optarg);
+ return CMD_LINE_ERROR;
+ }
+
+ /* free the allocated context */
+ poptFreeContext(context);
+
+ return CMD_LINE_SUCCESS;
+}
+
+int main(int argc, char **argv)
+{
+ REQ *req;
+ char *buffer;
+ int err=0;
+
+ /* Allocate the room */
+ req = (REQ *)xmalloc(sizeof(REQ));
+ buffer = (char *)xmalloc(RCV_BUFFER_LENGTH);
+
+ /* Command line parser */
+ if (!parse_cmdline(argc, argv, req))
+ exit(0);
+
+ /* Check minimum configuration need */
+ if (!req->host && !req->port && !req->url) {
+ exit(0);
+ }
+
+ /* finalize req initialisation */
+ req->buffer = buffer;
+ req->max = RCV_BUFFER_LENGTH;
+
+ /* Now make our HTTP/SSL request */
+ err = req->ssl ? genhash_ssl(req) : genhash_http(req);
+ print_error(err);
+
+ free(req);
+ return(1);
+}
--- /dev/null
+/*
+ * Soft: Genhash compute MD5 digest from a HTTP get result. This
+ * program is use to compute hash value that you will add
+ * into the /etc/keepalived/keepalived.conf for HTTP_GET
+ * & SSL_GET keepalive method.
+ *
+ * Part: main.c include file.
+ *
+ * Version: $Id: main.h,v 0.4.9 2001/11/28 11:50:23 acassen Exp $
+ *
+ * Authors: Alexandre Cassen, <acassen@linux-vs.org>
+ * Jan Holmberg, <jan@artech.se>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _MAIN_H
+#define _MAIN_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <openssl/md5.h>
+#include <popt.h>
+
+/* Build version */
+#define PROG "genhash"
+#define VERSION "0.4.9 (05/12, 2001)"
+
+/* HTTP/HTTPS GET command */
+#define REQUEST_TEMPLATE "GET %s HTTP/1.0\r\n" \
+ "User-Agent:KeepAliveClient\r\n" \
+ "Host: %s:%d\r\n\r\n"
+
+/* HTTP/HTTPS request structure */
+typedef struct {
+ char *host;
+ char *buffer;
+ int error;
+ int max;
+ int len;
+ char *url;
+ unsigned short int port;
+ int fd;
+ int ssl;
+ char *keyfile;
+ char *password;
+ char *cafile;
+} REQ;
+
+/* Output delimiters */
+#define DELIM_BEGIN "-----------------------["
+#define DELIM_END "]-----------------------\n"
+#define HTTP_HEADER_HEXA DELIM_BEGIN" HTTP Header Buffer "DELIM_END
+#define HTTP_HEADER_ASCII DELIM_BEGIN" HTTP Header Ascii Buffer "DELIM_END
+#define HTML_HEADER_HEXA DELIM_BEGIN" HTML Buffer "DELIM_END
+#define HTML_MD5 DELIM_BEGIN" HTML MD5 resulting "DELIM_END
+#define HTML_MD5_FINAL DELIM_BEGIN" HTML MD5 final resulting "DELIM_END
+
+/* Data buffer length description */
+#define RCV_BUFFER_LENGTH 512
+#define BUFSIZE 1024
+
+/* Command line error handling */
+#define CMD_LINE_ERROR 0
+#define CMD_LINE_SUCCESS 1
+
+#endif
+++ /dev/null
-/*\r
- Copyright (C) 1999 Aladdin Enterprises. All rights reserved.\r
-\r
- This software is provided 'as-is', without any express or implied\r
- warranty. In no event will the authors be held liable for any damages\r
- arising from the use of this software.\r
-\r
- Permission is granted to anyone to use this software for any purpose,\r
- including commercial applications, and to alter it and redistribute it\r
- freely, subject to the following restrictions:\r
-\r
- 1. The origin of this software must not be misrepresented; you must not\r
- claim that you wrote the original software. If you use this software\r
- in a product, an acknowledgment in the product documentation would be\r
- appreciated but is not required.\r
- 2. Altered source versions must be plainly marked as such, and must not be\r
- misrepresented as being the original software.\r
- 3. This notice may not be removed or altered from any source distribution.\r
-\r
- L. Peter Deutsch\r
- ghost@aladdin.com\r
-\r
- */\r
-/*$Id: md5.c $ */\r
-/*\r
- Independent implementation of MD5 (RFC 1321).\r
-\r
- This code implements the MD5 Algorithm defined in RFC 1321.\r
- It is derived directly from the text of the RFC and not from the\r
- reference implementation.\r
-\r
- The original and principal author of md5.c is L. Peter Deutsch\r
- <ghost@aladdin.com>. Other authors are noted in the change history\r
- that follows (in reverse chronological order):\r
-\r
- 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.\r
- 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).\r
- 1999-05-03 lpd Original version.\r
- */\r
-\r
-#include "md5.h"\r
-\r
-#define T1 0xd76aa478\r
-#define T2 0xe8c7b756\r
-#define T3 0x242070db\r
-#define T4 0xc1bdceee\r
-#define T5 0xf57c0faf\r
-#define T6 0x4787c62a\r
-#define T7 0xa8304613\r
-#define T8 0xfd469501\r
-#define T9 0x698098d8\r
-#define T10 0x8b44f7af\r
-#define T11 0xffff5bb1\r
-#define T12 0x895cd7be\r
-#define T13 0x6b901122\r
-#define T14 0xfd987193\r
-#define T15 0xa679438e\r
-#define T16 0x49b40821\r
-#define T17 0xf61e2562\r
-#define T18 0xc040b340\r
-#define T19 0x265e5a51\r
-#define T20 0xe9b6c7aa\r
-#define T21 0xd62f105d\r
-#define T22 0x02441453\r
-#define T23 0xd8a1e681\r
-#define T24 0xe7d3fbc8\r
-#define T25 0x21e1cde6\r
-#define T26 0xc33707d6\r
-#define T27 0xf4d50d87\r
-#define T28 0x455a14ed\r
-#define T29 0xa9e3e905\r
-#define T30 0xfcefa3f8\r
-#define T31 0x676f02d9\r
-#define T32 0x8d2a4c8a\r
-#define T33 0xfffa3942\r
-#define T34 0x8771f681\r
-#define T35 0x6d9d6122\r
-#define T36 0xfde5380c\r
-#define T37 0xa4beea44\r
-#define T38 0x4bdecfa9\r
-#define T39 0xf6bb4b60\r
-#define T40 0xbebfbc70\r
-#define T41 0x289b7ec6\r
-#define T42 0xeaa127fa\r
-#define T43 0xd4ef3085\r
-#define T44 0x04881d05\r
-#define T45 0xd9d4d039\r
-#define T46 0xe6db99e5\r
-#define T47 0x1fa27cf8\r
-#define T48 0xc4ac5665\r
-#define T49 0xf4292244\r
-#define T50 0x432aff97\r
-#define T51 0xab9423a7\r
-#define T52 0xfc93a039\r
-#define T53 0x655b59c3\r
-#define T54 0x8f0ccc92\r
-#define T55 0xffeff47d\r
-#define T56 0x85845dd1\r
-#define T57 0x6fa87e4f\r
-#define T58 0xfe2ce6e0\r
-#define T59 0xa3014314\r
-#define T60 0x4e0811a1\r
-#define T61 0xf7537e82\r
-#define T62 0xbd3af235\r
-#define T63 0x2ad7d2bb\r
-#define T64 0xeb86d391\r
-\r
-static void\r
-md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)\r
-{\r
- md5_word_t\r
- a = pms->abcd[0], b = pms->abcd[1],\r
- c = pms->abcd[2], d = pms->abcd[3];\r
- md5_word_t t;\r
-\r
-#ifndef ARCH_IS_BIG_ENDIAN\r
-# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */\r
-#endif\r
-#if ARCH_IS_BIG_ENDIAN\r
-\r
- /*\r
- * On big-endian machines, we must arrange the bytes in the right\r
- * order. (This also works on machines of unknown byte order.)\r
- */\r
- md5_word_t X[16];\r
- const md5_byte_t *xp = data;\r
- int i;\r
-\r
- for (i = 0; i < 16; ++i, xp += 4)\r
- X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);\r
-\r
-#else /* !ARCH_IS_BIG_ENDIAN */\r
-\r
- /*\r
- * On little-endian machines, we can process properly aligned data\r
- * without copying it.\r
- */\r
- md5_word_t xbuf[16];\r
- const md5_word_t *X;\r
-\r
- if (!((data - (const md5_byte_t *)0) & 3)) {\r
- /* data are properly aligned */\r
- X = (const md5_word_t *)data;\r
- } else {\r
- /* not aligned */\r
- memcpy(xbuf, data, 64);\r
- X = xbuf;\r
- }\r
-#endif\r
-\r
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))\r
-\r
- /* Round 1. */\r
- /* Let [abcd k s i] denote the operation\r
- a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */\r
-#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))\r
-#define SET(a, b, c, d, k, s, Ti) t = a + F(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b\r
- /* Do the following 16 operations. */\r
- SET(a, b, c, d, 0, 7, T1);\r
- SET(d, a, b, c, 1, 12, T2);\r
- SET(c, d, a, b, 2, 17, T3);\r
- SET(b, c, d, a, 3, 22, T4);\r
- SET(a, b, c, d, 4, 7, T5);\r
- SET(d, a, b, c, 5, 12, T6);\r
- SET(c, d, a, b, 6, 17, T7);\r
- SET(b, c, d, a, 7, 22, T8);\r
- SET(a, b, c, d, 8, 7, T9);\r
- SET(d, a, b, c, 9, 12, T10);\r
- SET(c, d, a, b, 10, 17, T11);\r
- SET(b, c, d, a, 11, 22, T12);\r
- SET(a, b, c, d, 12, 7, T13);\r
- SET(d, a, b, c, 13, 12, T14);\r
- SET(c, d, a, b, 14, 17, T15);\r
- SET(b, c, d, a, 15, 22, T16);\r
-#undef SET\r
-\r
- /* Round 2. */\r
- /* Let [abcd k s i] denote the operation\r
- a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */\r
-#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))\r
-#define SET(a, b, c, d, k, s, Ti) t = a + G(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b\r
- /* Do the following 16 operations. */\r
- SET(a, b, c, d, 1, 5, T17);\r
- SET(d, a, b, c, 6, 9, T18);\r
- SET(c, d, a, b, 11, 14, T19);\r
- SET(b, c, d, a, 0, 20, T20);\r
- SET(a, b, c, d, 5, 5, T21);\r
- SET(d, a, b, c, 10, 9, T22);\r
- SET(c, d, a, b, 15, 14, T23);\r
- SET(b, c, d, a, 4, 20, T24);\r
- SET(a, b, c, d, 9, 5, T25);\r
- SET(d, a, b, c, 14, 9, T26);\r
- SET(c, d, a, b, 3, 14, T27);\r
- SET(b, c, d, a, 8, 20, T28);\r
- SET(a, b, c, d, 13, 5, T29);\r
- SET(d, a, b, c, 2, 9, T30);\r
- SET(c, d, a, b, 7, 14, T31);\r
- SET(b, c, d, a, 12, 20, T32);\r
-#undef SET\r
-\r
- /* Round 3. */\r
- /* Let [abcd k s t] denote the operation\r
- a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */\r
-#define H(x, y, z) ((x) ^ (y) ^ (z))\r
-#define SET(a, b, c, d, k, s, Ti) t = a + H(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b\r
- /* Do the following 16 operations. */\r
- SET(a, b, c, d, 5, 4, T33);\r
- SET(d, a, b, c, 8, 11, T34);\r
- SET(c, d, a, b, 11, 16, T35);\r
- SET(b, c, d, a, 14, 23, T36);\r
- SET(a, b, c, d, 1, 4, T37);\r
- SET(d, a, b, c, 4, 11, T38);\r
- SET(c, d, a, b, 7, 16, T39);\r
- SET(b, c, d, a, 10, 23, T40);\r
- SET(a, b, c, d, 13, 4, T41);\r
- SET(d, a, b, c, 0, 11, T42);\r
- SET(c, d, a, b, 3, 16, T43);\r
- SET(b, c, d, a, 6, 23, T44);\r
- SET(a, b, c, d, 9, 4, T45);\r
- SET(d, a, b, c, 12, 11, T46);\r
- SET(c, d, a, b, 15, 16, T47);\r
- SET(b, c, d, a, 2, 23, T48);\r
-#undef SET\r
-\r
- /* Round 4. */\r
- /* Let [abcd k s t] denote the operation\r
- a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */\r
-#define I(x, y, z) ((y) ^ ((x) | ~(z)))\r
-#define SET(a, b, c, d, k, s, Ti) t = a + I(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b\r
- /* Do the following 16 operations. */\r
- SET(a, b, c, d, 0, 6, T49);\r
- SET(d, a, b, c, 7, 10, T50);\r
- SET(c, d, a, b, 14, 15, T51);\r
- SET(b, c, d, a, 5, 21, T52);\r
- SET(a, b, c, d, 12, 6, T53);\r
- SET(d, a, b, c, 3, 10, T54);\r
- SET(c, d, a, b, 10, 15, T55);\r
- SET(b, c, d, a, 1, 21, T56);\r
- SET(a, b, c, d, 8, 6, T57);\r
- SET(d, a, b, c, 15, 10, T58);\r
- SET(c, d, a, b, 6, 15, T59);\r
- SET(b, c, d, a, 13, 21, T60);\r
- SET(a, b, c, d, 4, 6, T61);\r
- SET(d, a, b, c, 11, 10, T62);\r
- SET(c, d, a, b, 2, 15, T63);\r
- SET(b, c, d, a, 9, 21, T64);\r
-#undef SET\r
-\r
- /* Then perform the following additions. (That is increment each\r
- of the four registers by the value it had before this block\r
- was started.) */\r
- pms->abcd[0] += a;\r
- pms->abcd[1] += b;\r
- pms->abcd[2] += c;\r
- pms->abcd[3] += d;\r
-}\r
-\r
-void\r
-md5_init(md5_state_t *pms)\r
-{\r
- pms->count[0] = pms->count[1] = 0;\r
- pms->abcd[0] = 0x67452301;\r
- pms->abcd[1] = 0xefcdab89;\r
- pms->abcd[2] = 0x98badcfe;\r
- pms->abcd[3] = 0x10325476;\r
-}\r
-\r
-void\r
-md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)\r
-{\r
- const md5_byte_t *p = data;\r
- int left = nbytes;\r
- int offset = (pms->count[0] >> 3) & 63;\r
- md5_word_t nbits = (md5_word_t)(nbytes << 3);\r
-\r
- if (nbytes <= 0)\r
- return;\r
-\r
- /* Update the message length. */\r
- pms->count[1] += nbytes >> 29;\r
- pms->count[0] += nbits;\r
- if (pms->count[0] < nbits)\r
- pms->count[1]++;\r
-\r
- /* Process an initial partial block. */\r
- if (offset) {\r
- int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);\r
-\r
- memcpy(pms->buf + offset, p, copy);\r
- if (offset + copy < 64)\r
- return;\r
- p += copy;\r
- left -= copy;\r
- md5_process(pms, pms->buf);\r
- }\r
-\r
- /* Process full blocks. */\r
- for (; left >= 64; p += 64, left -= 64)\r
- md5_process(pms, p);\r
-\r
- /* Process a final partial block. */\r
- if (left)\r
- memcpy(pms->buf, p, left);\r
-}\r
-\r
-void\r
-md5_finish(md5_state_t *pms, md5_byte_t digest[16])\r
-{\r
- static const md5_byte_t pad[64] = {\r
- 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\r
- };\r
- md5_byte_t data[8];\r
- int i;\r
-\r
- /* Save the length before padding. */\r
- for (i = 0; i < 8; ++i)\r
- data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));\r
- /* Pad to 56 bytes mod 64. */\r
- md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);\r
- /* Append the length. */\r
- md5_append(pms, data, 8);\r
- for (i = 0; i < 16; ++i)\r
- digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));\r
-}\r
+++ /dev/null
-/*\r
- Copyright (C) 1999 Aladdin Enterprises. All rights reserved.\r
-\r
- This software is provided 'as-is', without any express or implied\r
- warranty. In no event will the authors be held liable for any damages\r
- arising from the use of this software.\r
-\r
- Permission is granted to anyone to use this software for any purpose,\r
- including commercial applications, and to alter it and redistribute it\r
- freely, subject to the following restrictions:\r
-\r
- 1. The origin of this software must not be misrepresented; you must not\r
- claim that you wrote the original software. If you use this software\r
- in a product, an acknowledgment in the product documentation would be\r
- appreciated but is not required.\r
- 2. Altered source versions must be plainly marked as such, and must not be\r
- misrepresented as being the original software.\r
- 3. This notice may not be removed or altered from any source distribution.\r
-\r
- L. Peter Deutsch\r
- ghost@aladdin.com\r
-\r
- */\r
-/*$Id: md5.h $ */\r
-/*\r
- Independent implementation of MD5 (RFC 1321).\r
-\r
- This code implements the MD5 Algorithm defined in RFC 1321.\r
- It is derived directly from the text of the RFC and not from the\r
- reference implementation.\r
-\r
- The original and principal author of md5.h is L. Peter Deutsch\r
- <ghost@aladdin.com>. Other authors are noted in the change history\r
- that follows (in reverse chronological order):\r
-\r
- 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.\r
- 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);\r
- added conditionalization for C++ compilation from Martin\r
- Purschke <purschke@bnl.gov>.\r
- 1999-05-03 lpd Original version.\r
- */\r
-\r
-#ifndef md5_INCLUDED\r
-# define md5_INCLUDED\r
-\r
-/*\r
- * This code has some adaptations for the Ghostscript environment, but it\r
- * will compile and run correctly in any environment with 8-bit chars and\r
- * 32-bit ints. Specifically, it assumes that if the following are\r
- * defined, they have the same meaning as in Ghostscript: P1, P2, P3,\r
- * ARCH_IS_BIG_ENDIAN.\r
- */\r
-\r
-typedef unsigned char md5_byte_t; /* 8-bit byte */\r
-typedef unsigned int md5_word_t; /* 32-bit word */\r
-\r
-/* Define the state of the MD5 Algorithm. */\r
-typedef struct md5_state_s {\r
- md5_word_t count[2]; /* message length in bits, lsw first */\r
- md5_word_t abcd[4]; /* digest buffer */\r
- md5_byte_t buf[64]; /* accumulate block */\r
-} md5_state_t;\r
-\r
-#ifdef __cplusplus\r
-extern "C" \r
-{\r
-#endif\r
-\r
-/* Initialize the algorithm. */\r
-#ifdef P1\r
-void md5_init(P1(md5_state_t *pms));\r
-#else\r
-void md5_init(md5_state_t *pms);\r
-#endif\r
-\r
-/* Append a string to the message. */\r
-#ifdef P3\r
-void md5_append(P3(md5_state_t *pms, const md5_byte_t *data, int nbytes));\r
-#else\r
-void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);\r
-#endif\r
-\r
-/* Finish the message and return the digest. */\r
-#ifdef P2\r
-void md5_finish(P2(md5_state_t *pms, md5_byte_t digest[16]));\r
-#else\r
-void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);\r
-#endif\r
-\r
-#ifdef __cplusplus\r
-} /* end extern "C" */\r
-#endif\r
-\r
-#endif /* md5_INCLUDED */\r
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIICoDCCAgmgAwIBAgIBADANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJBVTET
+MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMB4XDTAxMTEyODE1MzcwMFoXDTAxMTIyODE1MzcwMFowRTELMAkGA1UE
+BhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp
+ZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqaHao73f
+HpyErd5yhBcY9MS0oN0uHFtSXsz63VXjfEwhl/7bgaw+9qR1a/iY8lW7NL7yON+9
+6o1wToTV/8gDs19rlUY+tpFiIsJzHUO2Xknnyp87dUPOU+bNu+r525DVnTvf4uxV
+6H56CPqqGDYKpG1dyjDtdiTgayIcehQNsiECAwEAAaOBnzCBnDAdBgNVHQ4EFgQU
+E3xmxdjFNxXJLa/NlzpeQtqwNZcwbQYDVR0jBGYwZIAUE3xmxdjFNxXJLa/Nlzpe
+QtqwNZehSaRHMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw
+HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGSCAQAwDAYDVR0TBAUwAwEB
+/zANBgkqhkiG9w0BAQQFAAOBgQCMAF/IJrmL7wSdY/YWjbj8+PKzIMzJmz6w6c8V
+LhbLHYreMurG5830Ljnd1udm7o7g+16qLNfq0rEwrWhnxDnC1Id8nHXxhUHO6IEg
+YDPBWMte7zOC7skgDzvJc585HiMNxXEuX1pwnBvHv+qqu36TtVZSXeOKZcOOmkwE
+eY40Bg==
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN CERTIFICATE REQUEST-----
+MIIBhDCB7gIBADBFMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEh
+MB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEB
+AQUAA4GNADCBiQKBgQCpodqjvd8enISt3nKEFxj0xLSg3S4cW1JezPrdVeN8TCGX
+/tuBrD72pHVr+JjyVbs0vvI4373qjXBOhNX/yAOzX2uVRj62kWIiwnMdQ7ZeSefK
+nzt1Q85T5s276vnbkNWdO9/i7FXofnoI+qoYNgqkbV3KMO12JOBrIhx6FA2yIQID
+AQABoAAwDQYJKoZIhvcNAQEEBQADgYEAJr5QWBjpWL1qsrHaNAP+qP17IAUWuZsz
+Zdy72zGnQcsrk3mn6b1z9OS7WOPKcKkSq2q1+DlQS7vfhPaYRM1g/sqOMbnPv+MJ
+CCvHvBcI+nKBjUS7WofEuZSvVzo8bdwoVyYLdQWKFi6w3Z+O8D3YxRlvXseWWOkI
+lj4W75ypRVU=
+-----END CERTIFICATE REQUEST-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,45FBDBEBCB52B1ED
+
+q6RONp0/s4kRRhz1n//irIU+QIed+F0Vu7ijixGARCJkkp+ZoXbGqOYwLJXjJXtH
+iC08SodwhFZLdLgCTttTn6IZvKR6Ye0K6or0JvSLQ+3+qdDy7GmgEnctPhE7j4Nk
+ptZejNPjjauh5tpu/rrIIq14ApE0zDuJpx97co4/i7VrGpB/HVVtJ61As3ry4aRL
+T8WvuQEIM5TLKC8tSxPb8rQKM5soY2IHd+GmMgYkiNg+Vcg6I7N34EQkse0CHNxA
+PUl2kPwP9kg981mR/xks22oNNM5AAkTuWXB8R3zDuyaVdYcpbSEiOeOBMPFo43CR
+yFsYRVOer9Dp97KSkYQ3VOwoYil2m6ddrpYBr9qDZ/PF9VBhdrJT37rA73+1V6AO
+YFkQvbWiL/SUsvByXFHes68Y09fCHkbCkbtY3tNvTK8Z37iI6ZuTPdBIYblTRYil
+51RDJkrCuUyLx3dzkPxQqq1nkBRx9QLz2DaY0xRc9PEgM01C/Q5T/7mwosSsE/zZ
+5oJB3upN8/1kmy+gTLLoE5kSyEZup8NsEHEqhU1z2z+t6DKOnFR8eg0YXdItIfHP
+y7QNKmFaSghtkNPQUrXz/s4Bh/9bEAicIOjj6Om2uVKG0vXEa+0b+Qz8sUcHvFB+
+IX2NJUCmFQgjFt6a3IYo6P0ajLy1g/ES+nPWwjYAMVXe0RHrB+Q0pwib9koWGvZN
+4N2xti19DEdKBNMgWRo7SBzTNtkv5Eo6btLw4M9oeqonC1YJfGThFUSssyC5ZCcY
+H+QeYs48mWoQwXwAufOr8CwALLmeAGhgBiIy6dcbvHpO7IQzTRRcIA==
+-----END RSA PRIVATE KEY-----
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,45FBDBEBCB52B1ED
+
+q6RONp0/s4kRRhz1n//irIU+QIed+F0Vu7ijixGARCJkkp+ZoXbGqOYwLJXjJXtH
+iC08SodwhFZLdLgCTttTn6IZvKR6Ye0K6or0JvSLQ+3+qdDy7GmgEnctPhE7j4Nk
+ptZejNPjjauh5tpu/rrIIq14ApE0zDuJpx97co4/i7VrGpB/HVVtJ61As3ry4aRL
+T8WvuQEIM5TLKC8tSxPb8rQKM5soY2IHd+GmMgYkiNg+Vcg6I7N34EQkse0CHNxA
+PUl2kPwP9kg981mR/xks22oNNM5AAkTuWXB8R3zDuyaVdYcpbSEiOeOBMPFo43CR
+yFsYRVOer9Dp97KSkYQ3VOwoYil2m6ddrpYBr9qDZ/PF9VBhdrJT37rA73+1V6AO
+YFkQvbWiL/SUsvByXFHes68Y09fCHkbCkbtY3tNvTK8Z37iI6ZuTPdBIYblTRYil
+51RDJkrCuUyLx3dzkPxQqq1nkBRx9QLz2DaY0xRc9PEgM01C/Q5T/7mwosSsE/zZ
+5oJB3upN8/1kmy+gTLLoE5kSyEZup8NsEHEqhU1z2z+t6DKOnFR8eg0YXdItIfHP
+y7QNKmFaSghtkNPQUrXz/s4Bh/9bEAicIOjj6Om2uVKG0vXEa+0b+Qz8sUcHvFB+
+IX2NJUCmFQgjFt6a3IYo6P0ajLy1g/ES+nPWwjYAMVXe0RHrB+Q0pwib9koWGvZN
+4N2xti19DEdKBNMgWRo7SBzTNtkv5Eo6btLw4M9oeqonC1YJfGThFUSssyC5ZCcY
+H+QeYs48mWoQwXwAufOr8CwALLmeAGhgBiIy6dcbvHpO7IQzTRRcIA==
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICoDCCAgmgAwIBAgIBADANBgkqhkiG9w0BAQQFADBFMQswCQYDVQQGEwJBVTET
+MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMB4XDTAxMTEyODE1MzcwMFoXDTAxMTIyODE1MzcwMFowRTELMAkGA1UE
+BhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNVBAoTGEludGVybmV0IFdp
+ZGdpdHMgUHR5IEx0ZDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqaHao73f
+HpyErd5yhBcY9MS0oN0uHFtSXsz63VXjfEwhl/7bgaw+9qR1a/iY8lW7NL7yON+9
+6o1wToTV/8gDs19rlUY+tpFiIsJzHUO2Xknnyp87dUPOU+bNu+r525DVnTvf4uxV
+6H56CPqqGDYKpG1dyjDtdiTgayIcehQNsiECAwEAAaOBnzCBnDAdBgNVHQ4EFgQU
+E3xmxdjFNxXJLa/NlzpeQtqwNZcwbQYDVR0jBGYwZIAUE3xmxdjFNxXJLa/Nlzpe
+QtqwNZehSaRHMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEw
+HwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGSCAQAwDAYDVR0TBAUwAwEB
+/zANBgkqhkiG9w0BAQQFAAOBgQCMAF/IJrmL7wSdY/YWjbj8+PKzIMzJmz6w6c8V
+LhbLHYreMurG5830Ljnd1udm7o7g+16qLNfq0rEwrWhnxDnC1Id8nHXxhUHO6IEg
+YDPBWMte7zOC7skgDzvJc585HiMNxXEuX1pwnBvHv+qqu36TtVZSXeOKZcOOmkwE
+eY40Bg==
+-----END CERTIFICATE-----
* library to add/remove server MASQ rules to the kernel
* firewall framework.
*
- * Version: $Id: ipfwwrapper.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: ipfwwrapper.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: ipfwwrapper.c include file.
*
- * Version: $Id: ipfwwrapper.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: ipfwwrapper.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
* Part: IPVS Kernel wrapper. Use setsockopt call to add/remove
* server to/from the loadbalanced server pool.
*
- * Version: $Id: ipvswrapper.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: ipvswrapper.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#include "ipvswrapper.h"
-#ifdef KERNEL_2_2 /* KERNEL 2.2 LVS handling */
+#ifdef _KRNL_2_2_ /* KERNEL 2.2 LVS handling */
int ipvs_cmd(int cmd, virtualserver *vserver, realserver *rserver)
{
ctl.u.vs_user.vs_flags = (ctl.u.vs_user.timeout!=0)?IP_VS_SVC_F_PERSISTENT:0;
/* VS specific */
- ctl.u.vs_user.vaddr = vserver->addr_ip.s_addr;
- ctl.u.vs_user.vport = vserver->addr_port;
+ if (vserver->vfwmark) {
+ ctl.u.vs_user.vfwmark = vserver->vfwmark;
+ } else {
+ ctl.u.vs_user.vaddr = vserver->addr_ip.s_addr;
+ ctl.u.vs_user.vport = vserver->addr_port;
+ }
/* SVR specific */
if (ctl.m_cmd == IP_MASQ_CMD_ADD_DEST || ctl.m_cmd == IP_MASQ_CMD_DEL_DEST) {
urule.vs_flags = (urule.timeout != 0)?IP_VS_SVC_F_PERSISTENT:0;
/* VS specific */
- urule.vaddr = vserver->addr_ip.s_addr;
- urule.vport = vserver->addr_port;
-
+ if (vserver->vfwmark) {
+ urule.vfwmark = vserver->vfwmark;
+ } else {
+ urule.vaddr = vserver->addr_ip.s_addr;
+ urule.vport = vserver->addr_port;
+ }
/* SVR specific */
if (cmd == IP_VS_SO_SET_ADDDEST || cmd == IP_VS_SO_SET_DELDEST) {
urule.weight = rserver->weight;
*
* Part: ipvswrapper.c include file.
*
- * Version: $Id: ipvswrapper.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: ipvswrapper.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#include <netinet/udp.h>
#include <netinet/tcp.h>
-#ifdef KERNEL_2_2
+#ifdef _KRNL_2_2_
#include <linux/ip_fw.h>
#include <net/ip_masq.h>
#endif
*
* Part: Manipulation functions for IPVS & IPFW wrappers.
*
- * Version: $id: ipwrapper.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $id: ipwrapper.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
return 0;
}
-#ifdef KERNEL_2_2
+#ifdef _KRNL_2_2_
/* IPFW cleaning server entry if granularity = /32 */
if (vserver->nat_mask.s_addr == HOST_NETMASK)
if (!ipfw_cmd(IP_FW_CMD_DEL, vserver, vserver->svr))
if (!clear_service_vs(vserver))
return 0;
-#ifdef KERNEL_2_2
+#ifdef _KRNL_2_2_
/* IPFW cleaner processing */
if (vserver->nat_mask.s_addr != HOST_NETMASK)
if (!ipfw_cmd(IP_FW_CMD_DEL, vserver, vserver->svr))
vserver->s_svr->alive = 0;
ipvs_cmd(LVS_CMD_DEL_DEST, vserver, vserver->s_svr);
-#ifdef KERNEL_2_2
+#ifdef _KRNL_2_2_
ipfw_cmd(IP_FW_CMD_DEL, vserver, vserver->s_svr);
#endif
}
inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
ipvs_cmd(LVS_CMD_ADD_DEST, vserver, rserver);
-#ifdef KERNEL_2_2
+#ifdef _KRNL_2_2_
if (vserver->nat_mask.s_addr == HOST_NETMASK)
ipfw_cmd(IP_FW_CMD_ADD, vserver, rserver);
#endif
/* server is down, it is removed from the LVS realserver pool */
ipvs_cmd(LVS_CMD_DEL_DEST, vserver, rserver);
-#ifdef KERNEL_2_2
+#ifdef _KRNL_2_2_
if (vserver->nat_mask.s_addr == HOST_NETMASK)
ipfw_cmd(IP_FW_CMD_DEL, vserver, rserver);
#endif
vserver->s_svr->alive = 1;
ipvs_cmd(LVS_CMD_ADD_DEST, vserver, vserver->s_svr);
-#ifdef KERNEL_2_2
+#ifdef _KRNL_2_2_
ipfw_cmd(IP_FW_CMD_ADD, vserver, vserver->s_svr);
#endif
}
return 0;
}
-#ifdef KERNEL_2_2
+#ifdef _KRNL_2_2_
/* if we have a /32 mask, we create one nat rules per
* realserver.
*/
if (!ipvs_cmd(LVS_CMD_ADD, vserver, vserver->svr))
return 0;
-#ifdef KERNEL_2_2
+#ifdef _KRNL_2_2_
/* work if all realserver ip address are in the
* same network (it is assumed).
*/
*
* Part: ipwrapper.c include file.
*
- * Version: $Id: ipwrapper.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: ipwrapper.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#define DOWN 0
/* LVS command set by kernel */
-#ifdef KERNEL_2_2
+#ifdef _KRNL_2_2_
#define LVS_CMD_ADD IP_MASQ_CMD_ADD
#define LVS_CMD_DEL IP_MASQ_CMD_DEL
#define LVS_CMD_ADD_DEST IP_MASQ_CMD_ADD_DEST
* Part: Layer4 checkers handling. Register worker threads &
* upper layer checkers.
*
- * Version: $Id: layer4.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: layer4.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
return connect_in_progress;
}
-enum connect_result
-tcp_socket_state(int fd, struct thread *thread,
- int (*func) (struct thread *))
+enum connect_result tcp_socket_state(int fd, thread *thread
+ , int (*func) (struct _thread *))
{
- struct thread_arg *thread_arg;
+ thread_arg *thread_arg;
int status;
int slen;
int ret = 0;
- struct timeval timer_now;
- struct timeval timer_min;
+ TIMEVAL timer_now;
+ TIMEVAL timer_min;
thread_arg = THREAD_ARG(thread);
/* Handle connection timeout */
if(thread->type == THREAD_WRITE_TIMEOUT) {
-#ifdef DEBUG
+#ifdef _DEBUG_
if (thread_arg->svr)
syslog(LOG_DEBUG, "TCP connection timeout to [%s:%d].",
inet_ntoa(thread_arg->svr->addr_ip),
/* Connection failed !!! */
if (ret) {
-#ifdef DEBUG
+#ifdef _DEBUG_
if (thread_arg->svr)
syslog(LOG_DEBUG, "TCP connection failed to [%s:%d].",
inet_ntoa(thread_arg->svr->addr_ip),
* Recompute the write timeout (or pending connection).
*/
if (status != 0) {
-#ifdef DEBUG
+#ifdef _DEBUG_
if (thread_arg->svr)
syslog(LOG_DEBUG, "TCP connection to [%s:%d] still IN_PROGRESS.",
inet_ntoa(thread_arg->svr->addr_ip),
return connect_success;
}
-void
-tcp_connection_state(int fd, enum connect_result status,
- struct thread *thread,
- int (*func) (struct thread *))
+void tcp_connection_state(int fd, enum connect_result status
+ , thread *thread
+ , int (*func) (struct _thread *))
{
- struct thread_arg *thread_arg;
+ thread_arg *thread_arg;
thread_arg = THREAD_ARG(thread);
switch (status) {
case connect_error:
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG,"TCP connection ERROR to [%s:%d].",
inet_ntoa(thread_arg->svr->addr_ip),
ntohs(thread_arg->svr->addr_port));
break;
case connect_success:
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG,"TCP connection SUCCESS to [%s:%d].",
inet_ntoa(thread_arg->svr->addr_ip),
ntohs(thread_arg->svr->addr_port));
/* Checking non-blocking connect, we wait until socket is writable */
case connect_in_progress:
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG,"TCP connection to [%s:%d] now IN_PROGRESS.",
inet_ntoa(thread_arg->svr->addr_ip),
ntohs(thread_arg->svr->addr_port));
*
* Part: layer4.c include file.
*
- * Version: $Id: layer4.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: layer4.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
tcp_connect(int fd, uint32_t IP_DST, uint16_t PORT_DST);
extern enum connect_result
-tcp_socket_state(int fd, struct thread *thread,
- int (*func) (struct thread *));
+tcp_socket_state(int fd, thread *thread,
+ int (*func) (struct _thread *));
extern void
tcp_connection_state(int fd, enum connect_result status,
- struct thread *thread,
- int (*func) (struct thread *));
+ thread *thread,
+ int (*func) (struct _thread *));
#endif
}
/* Get raw socket. */
-int ipfwc_get_raw_socket()
+int ipfwc_get_raw_socket(void)
{
return sockfd;
}
int ipfwc_set_policy(const ip_chainlabel chain, const ip_chainlabel policy);
/* Get raw socket. */
-int ipfwc_get_raw_socket();
+int ipfwc_get_raw_socket(void);
/* Translates errno numbers into more human-readable form than strerror. */
const char *ipfwc_strerror(int err);
*
* Part: Main program structure.
*
- * Version: $Id: main.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: main.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*/
#include "main.h"
+#include "memory.h"
/* SIGHUP handler */
void sighup(int sig)
thread_add_terminate_event(master);
}
+/* SIGCHLD handler */
+void sigchld(int sig)
+{
+ int child;
+
+ wait(&child);
+ child >>= 9;
+ if (child)
+ syslog(LOG_INFO, "Error from notify program, code:%d, %s"
+ , child, strerror(child));
+}
+
/* Signal wrapper */
-void * signal_set(int signo, void (*func)(int))
+void *signal_set(int signo, void (*func)(int))
{
int ret;
struct sigaction sig;
}
/* Initialize signal handler */
-void signal_init()
+void signal_init(void)
{
- signal_set (SIGHUP, sighup);
- signal_set (SIGINT, sighup);
- signal_set (SIGTERM, sighup);
- signal_set (SIGKILL, sighup);
+ signal_set(SIGHUP, sighup);
+ signal_set(SIGINT, sighup);
+ signal_set(SIGTERM, sighup);
+ signal_set(SIGKILL, sighup);
+ signal_set (SIGCHLD, sigchld);
}
/* Daemonization function coming from zebra source code */
-int daemon (int nochdir, int noclose)
+int daemon(int nochdir, int noclose)
{
pid_t pid;
- pid = fork ();
-
/* In case of fork is error. */
+ pid = fork ();
if (pid < 0) {
perror ("fork");
return -1;
/* Become session leader and get pid. */
pid = setsid();
-
if (pid < -1) {
perror ("setsid");
return -1;
}
/* Change directory to root. */
- if (! nochdir)
+ if (!nochdir)
chdir ("/");
/* File descriptor close. */
}
umask (0);
-
return 0;
}
+/* Usage function */
+static void usage(const char *prog)
+{
+ fprintf(stderr, "%s Version %s\n", PROG, VERSION);
+ fprintf(stderr,
+ "Usage:\n"
+ " %s\n"
+ " %s -n\n"
+ " %s -f keepalived.conf\n"
+ " %s -d\n"
+ " %s -h\n"
+ " %s -v\n\n",
+ prog, prog, prog, prog, prog, prog);
+ fprintf(stderr,
+ "Commands:\n"
+ "Either long or short options are allowed.\n"
+ " %s --dont-fork -n Dont fork the daemon process.\n"
+ " %s --use-file -f Use the specified configuration file.\n"
+ " Default is /etc/keepalived/keepalived.conf.\n"
+ " %s --dump-conf -d Dump the configuration data.\n"
+ " %s --log-console -l Log message to local console.\n"
+ " %s --help -h Display this short inlined help screen.\n"
+ " %s --version -v Display the version number\n",
+ prog, prog, prog, prog, prog, prog);
+}
+
+/* Command line parser */
+static char *parse_cmdline(int argc, char **argv)
+{
+ poptContext context;
+ char *optarg = NULL;
+ char *conf_file = NULL;
+ int c;
+
+ struct poptOption options_table[] = {
+ {"version", 'v', POPT_ARG_NONE, NULL, 'v'},
+ {"help", 'h', POPT_ARG_NONE, NULL, 'h'},
+ {"log-console", 'l', POPT_ARG_NONE, NULL, 'l'},
+ {"dont-fork", 'n', POPT_ARG_NONE, NULL, 'n'},
+ {"dump-conf", 'd', POPT_ARG_NONE, NULL, 'd'},
+ {"use-file", 'f', POPT_ARG_STRING, &optarg, 'f'},
+ {NULL, 0, 0, NULL, 0}
+ };
+
+ context = poptGetContext(PROG, argc, (const char **)argv
+ , options_table, 0);
+ if ((c = poptGetNextOpt(context)) < 0) {
+ return NULL;
+ }
+
+ /* The first option car */
+ switch (c) {
+ case 'v':
+ fprintf(stderr, "%s Version %s\n", PROG, VERSION);
+ exit(0);
+ break;
+ case 'h':
+ usage(argv[0]);
+ exit(0);
+ break;
+ case 'l':
+ debug |= 1;
+ break;
+ case 'n':
+ debug |= 2;
+ break;
+ case 'd':
+ debug |= 4;
+ break;
+ case 'f':
+ conf_file = optarg;
+ break;
+ }
+
+ /* the others */
+ while ((c = poptGetNextOpt(context)) >= 0) {
+ switch (c) {
+ case 'l':
+ debug |= 1;
+ break;
+ case 'n':
+ debug |= 2;
+ break;
+ case 'd':
+ debug |= 4;
+ break;
+ case 'f':
+ conf_file = optarg;
+ break;
+ }
+ }
+
+ /* check unexpected arguments */
+ if ((optarg = (char *)poptGetArg(context))) {
+ fprintf(stderr, "unexpected argument %s\n", optarg);
+ return NULL;
+ }
+
+ /* free the allocated context */
+ poptFreeContext(context);
+
+ return((conf_file)?conf_file:NULL);
+}
+
/* Entry point */
int main(int argc, char **argv)
{
configuration_data *conf_data;
- struct thread thread;
+ char *conf_file = NULL;
+ thread thread;
- openlog(PROG,LOG_PID, LOG_DAEMON);
+ /* Init debugging level */
+ debug = 0;
+
+ /*
+ * Parse command line and set debug level.
+ * bits 0..7 reserved by main.c
+ */
+ conf_file = parse_cmdline(argc, argv);
+
+ openlog(PROG, LOG_PID | (debug & 1)?LOG_CONS:0
+ , LOG_DAEMON);
syslog(LOG_INFO, "Starting "PROG" v"VERSION);
/* Check if keepalived is already running */
}
/* daemonize process */
- daemon(0, 0);
+ if (!(debug & 2)) {
+ daemon(0, 0);
+ }
/* write the pidfile */
if (!pidfile_write(getpid())) {
}
/* Parse the configuration file */
- if (!(conf_data = (configuration_data *)conf_reader())) {
+ if (!(conf_data = (configuration_data *)conf_reader(conf_file))) {
+ syslog(LOG_INFO, "Stopping "PROG" v"VERSION);
closelog();
exit(0);
}
-#ifdef DEBUG
- dump_conf(conf_data);
-#endif
+ /* SSL load static data & initialize common ctx context */
+ if (!(conf_data->ssldata = init_ssl_ctx(conf_data->ssldata))) {
+ closelog();
+ exit(0);
+ }
+
+ if (debug & 4)
+ dump_conf(conf_data);
if (!init_services(conf_data->lvstopology)) {
syslog(LOG_INFO, "Stopping "PROG" v"VERSION);
register_worker_thread(master, conf_data);
/* processing the master thread queues, return and execute one ready thread */
- while(thread_fetch(master, &thread))
+ while(thread_fetch(master, &thread)) {
+
+ /* Run until error, used for debuging only */
+#ifdef _DEBUG_
+ if ((debug & 520) == 520) {
+ debug &= ~520;
+ thread_add_terminate_event(master);
+ }
+#endif
thread_call(&thread);
+ }
/* Reached when terminate signal catched */
syslog(LOG_INFO, "Stopping "PROG" v"VERSION);
- /* We then cleanup the room & closelog */
+ /* Just cleanup memory & exit */
thread_destroy_master(master);
clear_services(conf_data->lvstopology);
-
- /* Stop VRRP instances */
clear_vrrp_instance(conf_data->vrrp);
+ clear_ssl(conf_data->ssldata);
clear_conf(conf_data);
- closelog();
+
pidfile_rm();
+#ifdef _DEBUG_
+ keepalived_free_final();
+#endif
+
+ closelog();
/* finally return from system */
exit(0);
}
*
* Part: Main program include file.
*
- * Version: $Id: main.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: main.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
/* global includes */
#include <sys/stat.h>
+#include <sys/wait.h>
+#include <popt.h>
/* local includes */
#include "utils.h"
#include "scheduler.h"
#include "ipwrapper.h"
#include "smtp.h"
+#include "vrrp.h"
+#include "check_ssl.h"
/* global var */
-struct thread_master *master;
+thread_master *master;
+unsigned int debug;
+
+/* SSL support */
+extern void clear_ssl(SSL_DATA *ssl);
+extern SSL_DATA *init_ssl_ctx(SSL_DATA *ssl);
/* Build version */
#define PROG "keepalived"
-#define VERSION "0.4.8 (20/11, 2001)"
+#define VERSION "0.4.9 (10/12, 2001)"
#endif
+++ /dev/null
-/*
- * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic
- * changes to accomodate it in the kernel by ji.
- * Minor changes to make 64 bit clean by Peter Onion (i.e. using u_int*_t).
- */
-
-/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
- */
-
-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-rights reserved.
-
-License to copy and use this software is granted provided that it
-is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-Algorithm" in all material mentioning or referencing this software
-or this function.
-
-License is also granted to make and use derivative works provided
-that such works are identified as "derived from the RSA Data
-Security, Inc. MD5 Message-Digest Algorithm" in all material
-mentioning or referencing the derived work.
-
-RSA Data Security, Inc. makes no representations concerning either
-the merchantability of this software or the suitability of this
-software for any particular purpose. It is provided "as is"
-without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this
-documentation and/or software.
- */
-
-/*
- * Additions by JI
- *
- * HAVEMEMCOPY is defined if mem* routines are available
- *
- * HAVEHTON is defined if htons() and htonl() can be used
- * for big/little endian conversions
- *
- */
-
-#include <stddef.h>
-#include <string.h>
-#include <sys/types.h> /* for u_int*_t */
-
-#include "md5.h"
-#include "endian.h" /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */
-
-#define HAVEMEMCOPY 1 /* use ISO C's memcpy and memset */
-
-/* Constants for MD5Transform routine.
- */
-
-#define S11 7
-#define S12 12
-#define S13 17
-#define S14 22
-#define S21 5
-#define S22 9
-#define S23 14
-#define S24 20
-#define S31 4
-#define S32 11
-#define S33 16
-#define S34 23
-#define S41 6
-#define S42 10
-#define S43 15
-#define S44 21
-
-#define MD5Transform _MD5Transform
-
-static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
-
-#if BYTE_ORDER == LITTLE_ENDIAN
-#define Encode MD5_memcpy
-#define Decode MD5_memcpy
-#else
-static void Encode PROTO_LIST
- ((unsigned char *, UINT4 *, unsigned int));
-static void Decode PROTO_LIST
- ((UINT4 *, unsigned char *, unsigned int));
-#endif
-
-#ifdef HAVEMEMCOPY
-#include <memory.h>
-#define MD5_memcpy memcpy
-#define MD5_memset memset
-#else
-#ifdef HAVEBCOPY
-#define MD5_memcpy(_a,_b,_c) memcpy((_a), (_b),(_c))
-#define MD5_memset(_a,_b,_c) memset((_a), '\0',(_c))
-#else
-static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
-static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
-#endif
-#endif
-static unsigned char PADDING[64] = {
- 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
-};
-
-/* F, G, H and I are basic MD5 functions.
- */
-#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
-#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
-#define H(x, y, z) ((x) ^ (y) ^ (z))
-#define I(x, y, z) ((y) ^ ((x) | (~z)))
-
-/* ROTATE_LEFT rotates x left n bits.
- */
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
-
-/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
-Rotation is separate from addition to prevent recomputation.
- */
-#define FF(a, b, c, d, x, s, ac) { \
- (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define GG(a, b, c, d, x, s, ac) { \
- (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define HH(a, b, c, d, x, s, ac) { \
- (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-#define II(a, b, c, d, x, s, ac) { \
- (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
- (a) = ROTATE_LEFT ((a), (s)); \
- (a) += (b); \
- }
-
-/* MD5 initialization. Begins an MD5 operation, writing a new context.
- */
-void MD5Init (context)
-MD5_CTX *context; /* context */
-{
- context->count[0] = context->count[1] = 0;
- /* Load magic initialization constants.
-*/
- context->state[0] = 0x67452301;
- context->state[1] = 0xefcdab89;
- context->state[2] = 0x98badcfe;
- context->state[3] = 0x10325476;
-}
-
-/* MD5 block update operation. Continues an MD5 message-digest
- operation, processing another message block, and updating the
- context.
- */
-void MD5Update (context, input, inputLen)
-MD5_CTX *context; /* context */
-unsigned char *input; /* input block */
-UINT4 inputLen; /* length of input block */
-{
- UINT4 i;
- unsigned int index, partLen;
-
- /* Compute number of bytes mod 64 */
- index = (unsigned int)((context->count[0] >> 3) & 0x3F);
-
- /* Update number of bits */
- if ((context->count[0] += (inputLen << 3)) < (inputLen << 3))
- context->count[1]++;
- context->count[1] += (inputLen >> 29);
-
- partLen = 64 - index;
-
- /* Transform as many times as possible. */
- if (inputLen >= partLen) {
- MD5_memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
- MD5Transform (context->state, context->buffer);
-
- for (i = partLen; i + 63 < inputLen; i += 64)
- MD5Transform (context->state, &input[i]);
-
- index = 0;
- }
- else
- i = 0;
-
- /* Buffer remaining input */
- MD5_memcpy((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
-}
-
-/* MD5 finalization. Ends an MD5 message-digest operation, writing the
- the message digest and zeroizing the context.
- */
-void MD5Final (digest, context)
-unsigned char digest[16]; /* message digest */
-MD5_CTX *context; /* context */
-{
- unsigned char bits[8];
- unsigned int index, padLen;
-
- /* Save number of bits */
- Encode (bits, context->count, 8);
-
- /* Pad out to 56 mod 64.
-*/
- index = (unsigned int)((context->count[0] >> 3) & 0x3f);
- padLen = (index < 56) ? (56 - index) : (120 - index);
- MD5Update (context, PADDING, padLen);
-
- /* Append length (before padding) */
- MD5Update (context, bits, 8);
-
- if (digest != NULL) /* Bill Simpson's padding */
- {
- /* store state in digest */
- Encode (digest, context->state, 16);
-
- /* Zeroize sensitive information.
- */
- MD5_memset ((POINTER)context, 0, sizeof (*context));
- }
-}
-
-/* MD5 basic transformation. Transforms state based on block.
- */
-static void MD5Transform (state, block)
-UINT4 state[4];
-unsigned char block[64];
-{
- UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
-
- Decode (x, block, 64);
-
- /* Round 1 */
- FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
- FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
- FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
- FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
- FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
- FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
- FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
- FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
- FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
- FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
- FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
- FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
- FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
- FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
- FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
- FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
-
- /* Round 2 */
- GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
- GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
- GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
- GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
- GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
- GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
- GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
- GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
- GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
- GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
- GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
- GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
- GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
- GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
- GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
- GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
-
- /* Round 3 */
- HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
- HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
- HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
- HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
- HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
- HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
- HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
- HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
- HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
- HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
- HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
- HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
- HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
- HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
- HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
- HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
-
- /* Round 4 */
- II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
- II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
- II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
- II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
- II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
- II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
- II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
- II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
- II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
- II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
- II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
- II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
- II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
- II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
- II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
- II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
-
- state[0] += a;
- state[1] += b;
- state[2] += c;
- state[3] += d;
-
- /* Zeroize sensitive information.
-*/
- MD5_memset ((POINTER)x, 0, sizeof (x));
-}
-
-#if BYTE_ORDER != LITTLE_ENDIAN
-
-/* Encodes input (UINT4) into output (unsigned char). Assumes len is
- a multiple of 4.
- */
-static void Encode (output, input, len)
-unsigned char *output;
-UINT4 *input;
-unsigned int len;
-{
- unsigned int i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4) {
- output[j] = (unsigned char)(input[i] & 0xff);
- output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
- output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
- output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
- }
-}
-
-/* Decodes input (unsigned char) into output (UINT4). Assumes len is
- a multiple of 4.
- */
-static void Decode (output, input, len)
-UINT4 *output;
-unsigned char *input;
-unsigned int len;
-{
- unsigned int i, j;
-
- for (i = 0, j = 0; j < len; i++, j += 4)
- output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
- (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
-}
-
-#endif
-
-#ifndef HAVEMEMCOPY
-#ifndef HAVEBCOPY
-/* Note: Replace "for loop" with standard memcpy if possible.
- */
-
-static void MD5_memcpy (output, input, len)
-POINTER output;
-POINTER input;
-unsigned int len;
-{
- unsigned int i;
-
- for (i = 0; i < len; i++)
-
- output[i] = input[i];
-}
-
-/* Note: Replace "for loop" with standard memset if possible.
- */
-static void MD5_memset (output, value, len)
-POINTER output;
-int value;
-unsigned int len;
-{
- unsigned int i;
-
- for (i = 0; i < len; i++)
- ((char *)output)[i] = (char)value;
-}
-#endif
-#endif
-
+++ /dev/null
-/* GLOBAL.H - RSAREF types and constants
- */
-
-/* PROTOTYPES should be set to one if and only if the compiler supports
- function argument prototyping.
- The following makes PROTOTYPES default to 0 if it has not already
- been defined with C compiler flags.
- */
-#ifndef PROTOTYPES
-#define PROTOTYPES 1
-#endif
-
-/* POINTER defines a generic pointer type */
-typedef unsigned char *POINTER;
-
-/* UINT2 defines a two byte word */
-typedef u_int16_t UINT2;
-
-/* UINT4 defines a four byte word */
-typedef u_int32_t UINT4;
-
-/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
- If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
- returns an empty list.
- */
-
-#if PROTOTYPES
-#define PROTO_LIST(list) list
-#else
-#define PROTO_LIST(list) ()
-#endif
-
-
-/* MD5.H - header file for MD5C.C
- */
-
-/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
-rights reserved.
-
-License to copy and use this software is granted provided that it
-is identified as the "RSA Data Security, Inc. MD5 Message-Digest
-Algorithm" in all material mentioning or referencing this software
-or this function.
-
-License is also granted to make and use derivative works provided
-that such works are identified as "derived from the RSA Data
-Security, Inc. MD5 Message-Digest Algorithm" in all material
-mentioning or referencing the derived work.
-
-RSA Data Security, Inc. makes no representations concerning either
-the merchantability of this software or the suitability of this
-software for any particular purpose. It is provided "as is"
-without express or implied warranty of any kind.
-
-These notices must be retained in any copies of any part of this
-documentation and/or software.
- */
-
-/* MD5 context. */
-typedef struct {
- UINT4 state[4]; /* state (ABCD) */
- UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
- unsigned char buffer[64]; /* input buffer */
-} MD5_CTX;
-
-void MD5Init PROTO_LIST ((MD5_CTX *));
-void MD5Update PROTO_LIST
- ((MD5_CTX *, unsigned char *, UINT4));
-void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
-
-#define _MD5_H_
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: Memory management framework. This framework is used to
+ * find any memory leak.
+ *
+ * Version: $Id: memory.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
+ *
+ * Authors: Alexandre Cassen, <acassen@linux-vs.org>
+ * Jan Holmberg, <jan@artech.net>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "memory.h"
+
+
+void *xalloc(unsigned long size)
+{
+ void *mem;
+
+ if ((mem = malloc(size)))
+ memset(mem, 0, size);
+ return mem;
+}
+
+/* KeepAlived memory management. in debug mode,
+ * help finding eventual memory leak.
+ * Allocation memory types manipulated are :
+ *
+ * +type+--------meaning--------+
+ * ! 0 ! Free slot !
+ * ! 1 ! Overrun !
+ * ! 2 ! free null !
+ * ! 3 ! realloc null !
+ * ! 4 ! Not previus allocated !
+ * ! 8 ! Last free list !
+ * ! 9 ! Allocated !
+ * +----+-----------------------+
+ *
+ * global variabel debug bit 9 ( 512 ) used to
+ * flag some memory error.
+ *
+ */
+
+#ifdef _DEBUG_
+extern void print_buffer(int,char *);
+
+typedef struct {
+ int type;
+ int line;
+ char *func;
+ char *file;
+ void *ptr;
+ unsigned long size;
+ long csum;
+} MEMCHECK;
+
+/* Last free pointers */
+static MEMCHECK free_list [256];
+
+static MEMCHECK alloc_list[512];
+static int number_alloc_list = 0;
+static int n = 0; /* Alloc list pointer */
+static int f = 0; /* Free list pointer */
+static int s = 0; /* Indent counter */
+
+static char * nspace(int n)
+{
+
+ return "";
+
+/*
+ static char buf[64];
+ int start = 0;
+ char *p;
+ p = buf;
+
+ while ( n-- > start ) {
+ *p++ = ' ';
+ }
+ *p=0;
+
+ return buf;
+*/
+
+}
+
+char *keepalived_malloc(unsigned long size, char *file, char *function, int line)
+{
+ void *buf;
+ int i = 0;
+ long check;
+
+ buf = xalloc(size+sizeof(long)) ;
+
+ check = 0xa5a5 + size;
+ *(long *)((char *)buf+size) = check;
+
+ while (i < number_alloc_list) {
+ if (alloc_list[i].type == 0)
+ break;
+ i++;
+ }
+
+ if (i == number_alloc_list)
+ number_alloc_list++;
+
+ alloc_list[i].ptr = buf;
+ alloc_list[i].size = size;
+ alloc_list[i].file = file;
+ alloc_list[i].func = function;
+ alloc_list[i].line = line;
+ alloc_list[i].csum = check;
+ alloc_list[i].type = 9;
+
+ if (debug & 1)
+ printf("%sxalloc[%3d:%3d], %p, %4ld at %s, %3d, %s\n"
+ ,nspace(s++), i, number_alloc_list, buf, size, file, line, function);
+
+ n++;
+ return buf;
+}
+
+int keepalived_free(void * buffer, char *file, char *function, int line)
+{
+ int i = 0;
+ void *buf;
+
+ /* If nullpointer remember */
+ if (buffer == NULL) {
+ i = number_alloc_list++;
+ alloc_list[i].ptr = buffer;
+ alloc_list[i].size = 0;
+ alloc_list[i].file = file;
+ alloc_list[i].func = function;
+ alloc_list[i].line = line;
+ alloc_list[i].type = 2;
+ if (debug & 1)
+ printf("%sfree NULL in %s, %3d, %s\n", nspace(s),file, line, function);
+
+ debug |= 512; /* Memory Error detect */
+
+ return n;
+ } else
+ buf = buffer;
+
+ while (i < number_alloc_list) {
+ if (alloc_list[i].type == 9 && alloc_list[i].ptr == buf) {
+ if (*((long *)((char *)alloc_list[i].ptr+alloc_list[i].size)) == alloc_list[i].csum)
+ alloc_list[i].type = 0; /* Release */
+ else {
+ alloc_list[i].type = 1; /* Overrun */
+ if (debug & 1) {
+ printf("%sfree corrupt, buffer overrun [%3d:%3d], %p, %4ld at %s, %3d, %s\n"
+ ,nspace(--s), i, number_alloc_list, buf, alloc_list[i].size, file, line, function);
+ print_buffer(alloc_list[i].size + sizeof(long), alloc_list[i].ptr);
+ printf("%sCheck_sum\n", nspace(i));
+ print_buffer(sizeof(long), (char *) & alloc_list[i].csum);
+
+ debug |= 512; /* Memory Error detect */
+ }
+ }
+ break;
+ }
+ i++;
+ }
+
+ /* Not found */
+ if (i == number_alloc_list) {
+ printf("Free ERROR %p\n", buffer);
+ number_alloc_list++;
+ alloc_list[i].ptr = buf;
+ alloc_list[i].size = 0;
+ alloc_list[i].file = file;
+ alloc_list[i].func = function;
+ alloc_list[i].line = line;
+ alloc_list[i].type = 4;
+ debug |= 512;
+
+ return n;
+ }
+
+ if (buffer != NULL)
+ free(buffer);
+
+ if (debug & 1)
+ printf("%sfree [%3d:%3d], %p, %4ld at %s, %3d, %s\n"
+ , nspace(--s), i, number_alloc_list, buf, alloc_list[i].size, file, line, function);
+
+ free_list[f].file = file;
+ free_list[f].line = line;
+ free_list[f].func = function;
+ free_list[f].ptr = buffer;
+ free_list[f].type = 8;
+ free_list[f].csum = i; /* Using this field for row id */
+
+ f++;
+ f&=255;
+ n--;
+
+ return n;
+}
+
+void keepalived_free_final(void)
+{
+ unsigned int sum=0, overrun=0, badptr=0;
+ int i, j;
+ i = 0;
+
+ printf("\n---[Keepalived memory dump]---\n\n");
+
+ while (i < number_alloc_list) {
+ switch (alloc_list[i].type ) {
+ case 3:
+ badptr++;
+ printf("null pointer to realloc(nil,%ld)! at %s, %3d, %s\n"
+ , alloc_list[i].size
+ , alloc_list[i].file
+ , alloc_list[i].line
+ , alloc_list[i].func);
+ break;
+ case 4:
+ badptr++;
+ printf("pointer not found in table to free(%p) [%3d:%3d], at %s, %3d, %s\n"
+ , alloc_list[i].ptr
+ , i, number_alloc_list
+ , alloc_list[i].file
+ , alloc_list[i].line
+ , alloc_list[i].func);
+ for (j=0; j< 256; j++)
+ if (free_list[j].ptr == alloc_list[i].ptr)
+ if (free_list[j].type == 8)
+ printf(" -> pointer allready released at [%3d:%3d], at %s, %3d, %s\n"
+ , (int) free_list[j].csum, number_alloc_list
+ , free_list[j].file
+ , free_list[j].line
+ , free_list[j].func);
+ break;
+ case 2:
+ badptr++;
+ printf("null pointer to free(nil)! at %s, %3d, %s\n"
+ , alloc_list[i].file
+ , alloc_list[i].line
+ , alloc_list[i].func);
+ break;
+ case 1:
+ overrun ++;
+ printf("%p [%3d:%3d], %4ld buffer overrun!:\n"
+ , alloc_list[i].ptr
+ , i, number_alloc_list
+ , alloc_list[i].size);
+ printf(" --> source of malloc: %s, %3d, %s\n"
+ , alloc_list[i].file
+ , alloc_list[i].line
+ , alloc_list[i].func);
+ break;
+ case 9:
+ sum += alloc_list[i].size;
+ printf("%p [%3d:%3d], %4ld not released!:\n"
+ , alloc_list[i].ptr
+ , i, number_alloc_list
+ , alloc_list[i].size);
+ printf(" --> source of malloc: %s, %3d, %s\n"
+ , alloc_list[i].file
+ , alloc_list[i].line
+ , alloc_list[i].func);
+ break;
+ }
+ i++;
+ }
+
+ printf("\n\n---[Keepalived memory dump summary]---\n");
+ printf("Total number of bytes not freed...: %d\n", sum);
+ printf("Number of entries not freed.......: %d\n", n);
+ printf("Maximum allocated entries.........: %d\n", number_alloc_list);
+ printf("Number of bad entries.............: %d\n", badptr);
+ printf("Number of buffer overrun..........: %d\n\n", overrun);
+
+ if (sum || n || badptr || overrun)
+ printf("=> Program seems to have some memory problem !!!\n\n");
+ else
+ printf("=> Program seems to be memory allocation safe...\n\n");
+}
+
+void *keepalived_realloc(void * buffer, unsigned long size, char *file, char* function, int line)
+{
+ int i = 0;
+ void *buf, *buf2;
+ long check;
+
+ if (buffer == NULL) {
+ printf("realloc %p %s, %3d %s\n", buffer, file, line, function);
+ i = number_alloc_list++;
+ alloc_list[i].ptr = buf;
+ alloc_list[i].size = 0;
+ alloc_list[i].file = file;
+ alloc_list[i].func = function;
+ alloc_list[i].line = line;
+ alloc_list[i].type = 3;
+ return keepalived_malloc(size, file, function, line);
+ }
+
+ buf = buffer;
+
+ while (i < number_alloc_list) {
+ if (alloc_list[i].ptr == buf) {
+ buf = alloc_list[i].ptr;
+ alloc_list[i].ptr = NULL;
+ break;
+ }
+ i++;
+ }
+
+ /* not found */
+ if (i == number_alloc_list) {
+ printf("realloc ERROR no matching xalloc %p \n", buffer);
+ number_alloc_list++;
+ alloc_list[i].ptr = buf;
+ alloc_list[i].size = 0;
+ alloc_list[i].file = file;
+ alloc_list[i].func = function;
+ alloc_list[i].line = line;
+ alloc_list[i].type = 9;
+ debug |= 512; /* Memory Error detect */
+ return NULL;
+ }
+
+ buf2 = ((char *)buf)+alloc_list[i].size;
+
+ if (*(long *)(buf2) != alloc_list[i].csum) {
+ alloc_list[i].type = 1;
+ debug |= 512; /* Memory Error detect */
+ }
+ buf = realloc(buffer, size+sizeof(long));
+
+ check = 0xa5a5 + size;
+ *(long *)((char *)buf+size) = check;
+ alloc_list[i].csum = check;
+
+ if (debug & 1)
+ printf("%srealloc [%3d:%3d] %p, %4ld %s %d %s -> %p %4ld %s %d %s\n"
+ , nspace(s),i, number_alloc_list
+ , alloc_list[i].ptr
+ , alloc_list[i].size, file, line, function, buf, size
+ , alloc_list[i].file
+ , alloc_list[i].line
+ , alloc_list[i].func);
+
+ alloc_list[i].ptr = buf;
+ alloc_list[i].size = size;
+ alloc_list[i].file = file;
+ alloc_list[i].line = line;
+ alloc_list[i].func = function;
+
+ return buf;
+}
+
+#endif
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: memory.c include file.
+ *
+ * Version: $Id: memory.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
+ *
+ * Authors: Alexandre Cassen, <acassen@linux-vs.org>
+ * Jan Holmberg, <jan@artech.net>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _MEMORY_H
+#define _MEMORY_H
+
+/* system includes */
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* extern types */
+extern unsigned int debug;
+
+/* Local defines */
+#ifdef _DEBUG_
+
+#define MALLOC(n) ( keepalived_malloc((n), \
+ (__FILE__), (__FUNCTION__), (__LINE__)) )
+#define FREE(b) ( keepalived_free((b), \
+ (__FILE__), (__FUNCTION__), (__LINE__)) )
+#define REALLOC(b,n) ( keepalived_realloc((b), (n), \
+ (__FILE__), (__FUNCTION__), (__LINE__)) )
+
+/* Memory debug prototypes defs */
+extern char *keepalived_malloc(unsigned long, char *, char *, int);
+extern int keepalived_free(void *, char *, char*, int);
+extern void *keepalived_realloc(void *, unsigned long, char *, char *, int);
+extern void keepalived_free_final(void);
+
+#else
+
+#define MALLOC(n) (xalloc(n))
+#define FREE(p) (free(p))
+#define REALLOC(p,n) (realloc((p),(n)))
+
+#endif
+
+#endif
*
* Part: pidfile utility.
*
- * Version: $Id: pidfile.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: pidfile.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
}
/* Remove the running daemon pidfile */
-void pidfile_rm()
+void pidfile_rm(void)
{
unlink(PIDFILENAME);
}
/* return the daemon running state */
-int keepalived_running()
+int keepalived_running(void)
{
FILE *pidfile = fopen(PIDFILENAME,"r");
pid_t pid;
*
* Part: pidfile.c include file.
*
- * Version: $Id: pidfile.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: pidfile.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
/* Prototypes */
extern int pidfile_write(int pid);
-extern void pidfile_rm();
-extern int keepalived_running();
+extern void pidfile_rm(void);
+extern int keepalived_running(void);
#endif
--- /dev/null
+-----BEGIN RSA PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,6D3B09E4CA5421FF
+
+SaDJA2MhJ12ZmDxfGkSLhQgjYPEQYqVfs5b4DZTz+9pJqzuNxHrZZU43oArbWBdB
+3DKc1THejbyHF2lY7xgPLk/5iax5r+CXesDKZroSliHyERBIOCUgDN6ecwvVGtYv
+C8IhlwGPEXyxr59lyV37RjkSUVXYBqiRbLlNIcQtp5T6GkFe+yftOnv6/UADCLTS
+Pu8xwkda1rf7dgPwYIKuk2SOTTe1VMDtWacRUGu8NteTJ4aiVaeeo9wdsKId5U2b
+Z7NTJjOjvdXOLRonfkGvDXmrmN4eICks0bV0ZBtkULAfGjKNGs6riY+XNGKNRmjI
+idRRB0za+EGorpiJ/vbe7n7uaFXIJlfqCwhTi4Up3mS8sR4tLHfmdjp85GV9P9B3
+xX3CHIeG5/EYDt0Qn1gRL5ODL/0O7nFGJslhcQUS6bMmcg9nSzhClTE2gREz0j9g
+pwzvRpEkIl3Tw4niZLIX8fW2cEIyKTBMCCG2MDwHHgXRL3SUXkOGeitFefkcXN/z
+/UWRS8XQcX7/lGWCiuEpgn+esoirjf8lFNVsx6OT0UXj3oBxGrz1iB/vpu/PMBVQ
+JsbEPSh/ElHSDUItw2ytjJmkolRtM01b7cFj16ZxbHjinXWTIGZFWUYIlaeA2zHK
+D/NRMFJwjrQYhjRgPqltvbw7M01Co7SNFBwSotARr36FBjsxbOH3F1jY6w+kXvJU
+X5m83C9UONM2K7kkKYXbE2yW+kzJF2LFX0Uu4yDluxNG767/WwqiQSI63aIzNAPp
+rSsaIMBSbVZia8q49gcvGyuvqBZpwm/PcZwr/PHJjvGs8hdU1ACmyQ==
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICFTCCAX4CAgECMA0GCSqGSIb3DQEBBAUAMFcxCzAJBgNVBAYTAlVTMRMwEQYD
+VQQKEwpSVEZNLCBJbmMuMRkwFwYDVQQLExBXaWRnZXRzIERpdmlzaW9uMRgwFgYD
+VQQDEw9UZXN0IENBMjAwMTA1MTcwHhcNMDEwNTE3MTYxMTM2WhcNMDQwMzA2MTYx
+MTM2WjBOMQswCQYDVQQGEwJVUzETMBEGA1UEChMKUlRGTSwgSW5jLjEZMBcGA1UE
+CxMQV2lkZ2V0cyBEaXZpc2lvbjEPMA0GA1UEAxMGY2xpZW50MIGfMA0GCSqGSIb3
+DQEBAQUAA4GNADCBiQKBgQCHNWSoNh6msUwYGGd7TYQDsdSG0ao6QXaYjk+78ZyM
+QeZUBu2dZFjG4wnzkKwrD4rp/J5PLR9AdxR72lb9AavEOKL2UDHJGsscZkGVw/bz
+ZbxrKF2rvdpZSvKP1OhV1MOds/WTpRm1gcmVSoV5vLOMqVjzjHoxQ/+1zpjzMxWL
+0wIDAQABMA0GCSqGSIb3DQEBBAUAA4GBACTJhRR5tv8A7dc5+zmKR1Q/i8qE3Mrn
+mp/MOXHfX+ifJ/w+twoc/yd4En+7pr+hGsiTofct1JOZDW9Akq/ZGu1+NpVRT7Cw
+53EdMwpi7ArwZAsLIUBsKA7QmLTbdwjU5S7WlZ24eygZHyqZrK4Few+JuzlFkkoI
+FIDCfinyz24m
+-----END CERTIFICATE-----
--- /dev/null
+-----BEGIN DH PARAMETERS-----
+MIGHAoGBANmAnfkETuKHOCWaE+W+F3kM/e7z5A8hZb7OqwGMQrUOaBEAr4BWeZBn
+G/87hhwZgNP69/KUchm714qd/PpOspCaUJ20x6PcmKujpAgca/f19HGMBjRawQMk
+R9oaBwazuQT0l0rTTKmvpMEcrQQIcVWii3CZI56I56oqF8biGPD7AgEC
+-----END DH PARAMETERS-----
--- /dev/null
+# Configuration File for keepalived
+
+global_defs {
+ notification_email {
+ acassen
+ }
+ notification_email_from Alexandre.Cassen@firewall.loc
+ smtp_server 192.168.200.1
+ smtp_connect_timeout 30
+ lvs_id LVS_DEVEL
+}
+
+;SSL {
+ password password
+ ca /etc/keepalived/root.pem
+ certificate /etc/keepalived/dh1024.pem
+ key /etc/keepalived/client.pem
+}
+
+vrrp_instance VI_1 {
+ state MASTER
+ interface eth0
+ virtual_router_id 51
+ priority 100
+ advert_int 1
+ authentication {
+ auth_type AH
+ auth_pass 1111
+ }
+ virtual_ipaddress {
+ 192.168.200.16
+ 192.168.200.17
+ 192.168.200.18
+ }
+}
+
+virtual_server 192.168.200.100 443 {
+ delay_loop 6
+ lb_algo rr
+ lb_kind NAT
+ nat_mask 255.255.255.0
+ persistence_timeout 50
+ protocol TCP
+
+ real_server 192.168.201.100 443 {
+ weight 1
+ SSL_GET {
+ url {
+ path /
+ digest ff20ad2481f97b1754ef3e12ecd3a9cc
+ }
+ url {
+ path /mrtg/
+ digest 9b3a0c85a887a256d6939da88aabd8cd
+ }
+ connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
+ }
+ }
+}
+
+virtual_server 192.168.200.100 80 {
+ delay_loop 6
+ lb_algo rr
+ lb_kind NAT
+ nat_mask 255.255.255.0
+ persistence_timeout 50
+ protocol TCP
+
+ real_server 192.168.201.100 80 {
+ weight 1
+ HTTP_GET {
+ url {
+ path /
+ digest ff20ad2481f97b1754ef3e12ecd3a9cc
+ }
+ url {
+ path /mrtg/
+ digest 9b3a0c85a887a256d6939da88aabd8cd
+ }
+ connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
+ }
+ }
+}
--- /dev/null
+# Configuration File for keepalived
+
+global_defs {
+ notification_email {
+ acassen
+ }
+ notification_email_from Alexandre.Cassen@firewall.loc
+ smtp_server 192.168.200.1
+ smtp_connect_timeout 30
+ lvs_id LVS_DEVEL
+}
+
+virtual_server 192.168.200.100 80 {
+ delay_loop 6
+ lb_algo rr
+ lb_kind NAT
+ nat_mask 255.255.255.0
+ persistence_timeout 50
+ protocol TCP
+
+ real_server 192.168.201.100 80 {
+ weight 1
+ SSL_GET {
+ url {
+ path /
+ digest FF20AD2481F97B1754EF3E12ECD3A9CC
+ }
+ connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
+ }
+ }
+}
--- /dev/null
+-----BEGIN CERTIFICATE-----
+MIICIjCCAYugAwIBAgIBADANBgkqhkiG9w0BAQQFADBXMQswCQYDVQQGEwJVUzET
+MBEGA1UEChMKUlRGTSwgSW5jLjEZMBcGA1UECxMQV2lkZ2V0cyBEaXZpc2lvbjEY
+MBYGA1UEAxMPVGVzdCBDQTIwMDEwNTE3MB4XDTAxMDUxNzE2MDExNFoXDTA2MTIy
+NTE2MDExNFowVzELMAkGA1UEBhMCVVMxEzARBgNVBAoTClJURk0sIEluYy4xGTAX
+BgNVBAsTEFdpZGdldHMgRGl2aXNpb24xGDAWBgNVBAMTD1Rlc3QgQ0EyMDAxMDUx
+NzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAmkX40warmH0+lnwD9YjsJhRz
+ZX6qXadFry0y2trZ6gMs8Mv33IKPwOu8TE7V+3PESEtjI2wr8juV9OkbIPOm+td5
+M8+6vXyIW+JBo3ch99i0QMTf5/jTgsW+3IjV8yEdiGcZFp2NWKLRvZPq2VRbuF7R
+1pvgcaRuBJ0wGOohwnsCAwEAATANBgkqhkiG9w0BAQQFAAOBgQCUB8zMKIlX5io8
+TalbzH9Qke7BcvFAL+wp/5w1ToVsWkNrINSWKv6bl/jcqOD3aPhK7qhaeOU8ZWKL
+PoPPCnRl9Wo+1JtsOO3qIgJP79Bl9ooLGahixF2v/gea5qNISjQvwYllLSa//APP
+6kXHngO0RIRbiTBYHSkAzm6hDdsvVA==
+-----END CERTIFICATE-----
* the thread management routine (thread.c) present in the
* very nice zebra project (http://www.zebra.org).
*
- * Version: $Id: scheduler.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: scheduler.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*/
#include "scheduler.h"
+#include "memory.h"
/* Make thread master. */
-struct thread_master *
-thread_make_master ()
+thread_master *thread_make_master(void)
{
- struct thread_master *new;
+ thread_master *new;
- new = (struct thread_master *)malloc(sizeof (struct thread_master));
- memset(new,0,sizeof(struct thread_master));
+ new = (thread_master *)MALLOC(sizeof(thread_master));
return new;
}
/* Make a new http thread arg */
-struct http_thread_arg *
-thread_http_checker_arg_new()
+http_thread_arg *thread_http_checker_arg_new(void)
{
- struct http_thread_arg *new;
+ http_thread_arg *new;
/* Allocate & prepare the thread argument structure */
- new = (struct http_thread_arg *)malloc(sizeof (struct http_thread_arg));
- memset(new, 0, sizeof(struct http_thread_arg));
+ new = (http_thread_arg *)MALLOC(sizeof(http_thread_arg));
return new;
}
/* Make a new global thread arg */
-struct thread_arg *
-thread_arg_new(configuration_data *root,
- virtualserver *vserver,
- realserver *rserver)
+thread_arg *thread_arg_new(configuration_data *root
+ , virtualserver *vserver
+ , realserver *rserver)
{
- struct thread_arg *new;
+ thread_arg *new;
/* Allocate & prepare the thread argument structure */
- new = (struct thread_arg *)malloc(sizeof (struct thread_arg));
- memset(new, 0, sizeof(struct thread_arg));
+ new = (thread_arg *)MALLOC(sizeof(thread_arg));
/* Assign structure elements */
new->root = root;
}
/* Add a new thread to the list. */
-static void
-thread_list_add (struct thread_list *list, struct thread *thread)
+static void thread_list_add(thread_list *list, thread *thread)
{
thread->next = NULL;
thread->prev = list->tail;
}
/* Add a new thread to the list. */
-void
-thread_list_add_before (struct thread_list *list,
- struct thread *point,
- struct thread *thread)
+void thread_list_add_before(thread_list *list
+ , thread *point
+ , thread *thread)
{
thread->next = point;
thread->prev = point->prev;
}
/* timer compare */
-int
-thread_timer_cmp (struct timeval a, struct timeval b)
+int thread_timer_cmp(TIMEVAL a, TIMEVAL b)
{
if (a.tv_sec > b.tv_sec)
return 1;
}
/* Add a thread in the list sorted by timeval */
-void
-thread_list_add_timeval(struct thread_list *list, struct thread *thread)
+void thread_list_add_timeval(thread_list *list, thread *thread)
{
- struct thread *tt;
+ struct _thread *tt;
for (tt = list->head; tt; tt = tt->next)
if (thread_timer_cmp (thread->sands, tt->sands) <= 0)
}
/* Delete a thread from the list. */
-struct thread *
-thread_list_delete (struct thread_list *list, struct thread *thread)
+thread *thread_list_delete(thread_list *list, thread *thread)
{
if (thread->next)
thread->next->prev = thread->prev;
}
/* Free all unused thread. */
-static void
-thread_clean_unuse (struct thread_master *m)
+static void thread_clean_unuse(thread_master *m)
{
- struct thread *thread;
+ thread *thread;
thread = m->unuse.head;
while (thread) {
- struct thread *t;
+ struct _thread *t;
+ thread_arg *ta;
t = thread;
thread = t->next;
- thread_list_delete (&m->unuse, t);
+ thread_list_delete(&m->unuse, t);
+ ta = t->arg;
- /* FIXME : Need to add thread_arg memory cleanup */
+ /* thread_arg memory cleanup */
+ if (ta) {
+ if (ta->checker_arg)
+ FREE(ta->checker_arg);
+ /* Free the arg if it is a thread_arg entry. */
+ if (ta->vs)
+ FREE(ta);
+ }
/* free the thread */
- free(t);
+ FREE(t);
m->alloc--;
}
}
/* Move thread to unuse list. */
-static void
-thread_add_unuse (struct thread_master *m, struct thread *thread)
+static void thread_add_unuse(thread_master *m, thread *thread)
{
- assert (m != NULL);
- assert (thread->next == NULL);
- assert (thread->prev == NULL);
- assert (thread->type == THREAD_UNUSED);
- thread_list_add (&m->unuse, thread);
+ assert(m != NULL);
+ assert(thread->next == NULL);
+ assert(thread->prev == NULL);
+ assert(thread->type == THREAD_UNUSED);
+ thread_list_add(&m->unuse, thread);
}
/* Move list element to unuse queue */
-void
-thread_destroy_list(struct thread_master *m, struct thread_list thread_list)
+void thread_destroy_list(thread_master *m, thread_list thread_list)
{
- struct thread *thread;
+ thread *thread;
thread = thread_list.head;
while (thread) {
- struct thread *t;
+ struct _thread *t;
t = thread;
thread = t->next;
- thread_list_delete (&thread_list, t);
+ thread_list_delete(&thread_list, t);
t->type = THREAD_UNUSED;
- thread_add_unuse (m, t);
+ thread_add_unuse(m, t);
}
}
/* Stop thread scheduler. */
-void
-thread_destroy_master (struct thread_master *m)
+void thread_destroy_master(thread_master *m)
{
- thread_destroy_list(m,m->read);
- thread_destroy_list(m,m->write);
- thread_destroy_list(m,m->timer);
- thread_destroy_list(m,m->event);
- thread_destroy_list(m,m->ready);
-
- thread_clean_unuse (m);
- free(m);
+ thread_destroy_list(m, m->read);
+ thread_destroy_list(m, m->write);
+ thread_destroy_list(m, m->timer);
+ thread_destroy_list(m, m->event);
+ thread_destroy_list(m, m->ready);
+
+ thread_clean_unuse(m);
+ FREE(m);
}
/* Delete top of the list and return it. */
-struct thread *
-thread_trim_head (struct thread_list *list)
+thread *thread_trim_head(thread_list *list)
{
if (list->head)
return thread_list_delete (list, list->head);
}
/* Make new thread. */
-struct thread *
-thread_new (struct thread_master *m)
+thread *thread_new(thread_master *m)
{
- struct thread *new;
+ thread *new;
/* If one thread is already allocated return it */
if (m->unuse.head) {
new = thread_trim_head(&m->unuse);
- memset(new,0,sizeof(struct thread));
+ memset(new, 0, sizeof(thread));
return new;
}
- new = (struct thread *)malloc(sizeof(struct thread));
- memset(new,0,sizeof(struct thread));
+ new = (thread *)MALLOC(sizeof(thread));
m->alloc++;
return new;
}
/* Add new read thread. */
-struct thread *
-thread_add_read (struct thread_master *m,
- int (*func)(struct thread *),
- void *arg,
- int fd,
- long timer)
+thread *thread_add_read(thread_master *m
+ , int (*func)(thread *)
+ , void *arg
+ , int fd
+ , long timer)
{
- struct thread *thread;
- struct timeval timer_now;
+ thread *thread;
+ TIMEVAL timer_now;
- assert (m != NULL);
+ assert(m != NULL);
if (FD_ISSET (fd, &m->readfd)) {
syslog(LOG_WARNING, "There is already read fd [%d]", fd);
return NULL;
}
- thread = thread_new (m);
+ thread = thread_new(m);
thread->type = THREAD_READ;
thread->id = 0;
thread->master = m;
}
/* Add new write thread. */
-struct thread *
-thread_add_write (struct thread_master *m,
- int (*func)(struct thread *),
- void *arg,
- int fd,
- long timer)
+thread *thread_add_write(thread_master *m
+ , int (*func)(thread *)
+ , void *arg
+ , int fd
+ , long timer)
{
- struct thread *thread;
- struct timeval timer_now;
+ thread *thread;
+ TIMEVAL timer_now;
- assert (m != NULL);
+ assert(m != NULL);
if (FD_ISSET (fd, &m->writefd)) {
syslog(LOG_WARNING, "There is already write fd [%d]", fd);
return NULL;
}
- thread = thread_new (m);
+ thread = thread_new(m);
thread->type = THREAD_WRITE;
thread->id = 0;
thread->master = m;
}
/* Add timer event thread. */
-struct thread *
-thread_add_timer (struct thread_master *m,
- int (*func)(struct thread *),
- void *arg,
- long timer)
+thread *thread_add_timer (thread_master *m
+ , int (*func)(thread *)
+ , void *arg
+ , long timer)
{
- struct timeval timer_now;
- struct thread *thread;
+ thread *thread;
+ TIMEVAL timer_now;
- assert (m != NULL);
+ assert(m != NULL);
- thread = thread_new (m);
+ thread = thread_new(m);
thread->type = THREAD_TIMER;
thread->id = 0;
thread->master = m;
}
/* Add simple event thread. */
-struct thread *
-thread_add_event (struct thread_master *m,
- int (*func)(struct thread *),
- void *arg,
- int val)
+thread *thread_add_event(thread_master *m
+ , int (*func)(thread *)
+ , void *arg
+ , int val)
{
- struct thread *thread;
+ thread *thread;
- assert (m != NULL);
+ assert(m != NULL);
- thread = thread_new (m);
+ thread = thread_new(m);
thread->type = THREAD_EVENT;
thread->id = 0;
thread->master = m;
}
/* Add simple event thread. */
-struct thread *
-thread_add_terminate_event (struct thread_master *m)
+thread *thread_add_terminate_event(thread_master *m)
{
- struct thread *thread;
+ thread *thread;
- assert (m != NULL);
+ assert(m != NULL);
- thread = thread_new (m);
+ thread = thread_new(m);
thread->type = THREAD_TERMINATE;
thread->id = 0;
thread->master = m;
thread->func = NULL;
thread->arg = NULL;
thread->u.val = 0;
- thread_list_add (&m->event, thread);
+ thread_list_add(&m->event, thread);
return thread;
}
/* Cancel thread from scheduler. */
-void
-thread_cancel (struct thread *thread)
+void thread_cancel(thread *thread)
{
switch (thread->type) {
case THREAD_READ:
}
thread->type = THREAD_UNUSED;
- thread_add_unuse (thread->master, thread);
+ thread_add_unuse(thread->master, thread);
}
/* Delete all events which has argument value arg. */
-void
-thread_cancel_event (struct thread_master *m, void *arg)
+void thread_cancel_event(thread_master *m, void *arg)
{
- struct thread *thread;
+ thread *thread;
thread = m->event.head;
while (thread) {
- struct thread *t;
+ struct _thread *t;
t = thread;
thread = t->next;
}
/* timer sub */
-struct timeval
-thread_timer_sub (struct timeval a, struct timeval b)
+TIMEVAL thread_timer_sub(TIMEVAL a, TIMEVAL b)
{
- struct timeval ret;
+ TIMEVAL ret;
ret.tv_usec = a.tv_usec - b.tv_usec;
ret.tv_sec = a.tv_sec - b.tv_sec;
return ret;
}
-static int thread_timer_null(struct timeval timer)
+static int thread_timer_null(TIMEVAL timer)
{
if (timer.tv_sec == 0 && timer.tv_usec == 0)
return 1;
}
/* Compute the wait timer. Take care of timeouted fd */
-struct timeval *
-thread_compute_timer(struct thread_master *m, struct timeval *timer_wait)
+TIMEVAL *thread_compute_timer(thread_master *m, TIMEVAL *timer_wait)
{
- struct timeval timer_now;
- struct timeval timer_min;
+ TIMEVAL timer_now;
+ TIMEVAL timer_min;
timer_min.tv_sec = 0;
timer_min.tv_usec = 0;
}
/* Fetch next ready thread. */
-struct thread *
-thread_fetch (struct thread_master *m, struct thread *fetch)
+thread *thread_fetch(thread_master *m, thread *fetch)
{
int ret;
- struct thread *thread;
+ thread *thread;
fd_set readfd;
fd_set writefd;
fd_set exceptfd;
- struct timeval timer_now;
- struct timeval *timer_wait;
+ TIMEVAL timer_now;
+ TIMEVAL *timer_wait;
- assert (m != NULL);
+ assert(m != NULL);
/* Timer allocation */
- timer_wait = (struct timeval *)malloc(sizeof(struct timeval));
- memset(timer_wait,0,sizeof(struct timeval));
+ timer_wait = (TIMEVAL *)MALLOC(sizeof(TIMEVAL));
retry: /* When thread can't fetch try to find next thread again. */
/* If there is event process it first. */
while ((thread = thread_trim_head(&m->event))) {
*fetch = *thread;
- free(timer_wait);
+ FREE(timer_wait);
/* If daemon hanging event is received return NULL pointer */
if (thread->type == THREAD_TERMINATE) {
*fetch = *thread;
thread->type = THREAD_UNUSED;
thread_add_unuse(m, thread);
- free(timer_wait);
+ FREE(timer_wait);
return fetch;
}
thread = m->read.head;
while (thread) {
- struct thread *t;
+ struct _thread *t;
t = thread;
thread = t->next;
thread = m->write.head;
while (thread) {
- struct thread *t;
+ struct _thread *t;
t = thread;
thread = t->next;
thread = m->timer.head;
while (thread) {
- struct thread *t;
+ struct _thread *t;
t = thread;
thread = t->next;
thread->type = THREAD_UNUSED;
thread_add_unuse (m, thread);
- free(timer_wait);
+ FREE(timer_wait);
return fetch;
}
/* Make unique thread id for non pthread version of thread manager. */
-unsigned long int
-thread_get_id ()
+unsigned long int thread_get_id(void)
{
static unsigned long int counter = 0;
return ++counter;
}
/* Call thread ! */
-void
-thread_call (struct thread *thread)
+void thread_call(thread *thread)
{
thread->id = thread_get_id ();
- (*thread->func) (thread);
+ (*thread->func)(thread);
}
/* Register worker thread. One per realserver of each virtualserver */
-void
-register_vs_worker_thread(struct thread_master *master,
- configuration_data *root,
- virtualserver *lstptr)
+void register_vs_worker_thread(thread_master *master
+ , configuration_data *root
+ , virtualserver *lstptr)
{
realserver *pointersvr;
- struct thread_arg *thread_arg;
+ thread_arg *thread_arg;
pointersvr = lstptr->svr;
while (lstptr->svr) {
switch (lstptr->svr->method->type) {
+ /* Implemented section */
case TCP_CHECK_ID:
- thread_arg = thread_arg_new(root, lstptr, lstptr->svr);
- thread_add_timer(master, tcp_connect_thread, thread_arg,
- thread_arg->vs->delay_loop);
- break;
case HTTP_GET_ID:
- thread_arg = thread_arg_new(root, lstptr, lstptr->svr);
- thread_arg->checker_arg = (struct http_thread_arg *)thread_http_checker_arg_new();
- thread_add_timer(master, http_connect_thread, thread_arg,
- thread_arg->vs->delay_loop);
- break;
case SSL_GET_ID:
+ case MISC_CHECK_ID:
+ thread_arg = thread_arg_new(root, lstptr, lstptr->svr);
+
+ switch (lstptr->svr->method->type ) {
+ case TCP_CHECK_ID:
+ thread_add_timer(master, tcp_connect_thread, thread_arg
+ , BOOTSTRAP_DELAY);
+ break;
+ case HTTP_GET_ID:
+ case SSL_GET_ID:
+ thread_arg->checker_arg = (http_thread_arg *)thread_http_checker_arg_new();
+ thread_add_timer(master, http_connect_thread, thread_arg
+ , BOOTSTRAP_DELAY);
+ break;
+ case MISC_CHECK_ID:
+ thread_add_timer(master, misc_check_thread, thread_arg
+ , BOOTSTRAP_DELAY);
+ break;
+ }
+
break;
+
+ /* Not yet implemented section */
case LDAP_GET_ID:
break;
- case MISC_CHECK_ID:
- thread_arg = thread_arg_new(root, lstptr, lstptr->svr);
- thread_add_timer(master, misc_check_thread, thread_arg,
- thread_arg->vs->delay_loop);
default:
break;
}
}
/* Register each virtualserver realservers worker thread */
-void
-register_worker_thread(struct thread_master *master, configuration_data *lstptr)
+void register_worker_thread(thread_master *master, configuration_data *lstptr)
{
virtualserver *pointervs;
*
* Part: scheduler.c include file.
*
- * Version: $Id: scheduler.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: scheduler.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#include "cfreader.h"
#include "check.h"
+/* Thread itself. */
+typedef struct timeval TIMEVAL;
+typedef struct _thread {
+ unsigned long id;
+ unsigned char type; /* thread type */
+ struct _thread *next; /* next pointer of the thread */
+ struct _thread *prev; /* previous pointer of the thread */
+ struct _thread_master *master; /* pointer to the struct thread_master. */
+ int (*func) (struct _thread *); /* event function */
+ void *arg; /* event argument */
+ TIMEVAL sands; /* rest of time sands value. */
+ union {
+ int val; /* second argument of the event. */
+ int fd; /* file descriptor in case of read/write. */
+ } u;
+} thread;
+
/* Linked list of thread. */
-struct thread_list
-{
- struct thread *head;
- struct thread *tail;
+typedef struct _thread_list {
+ thread *head;
+ thread *tail;
int count;
-};
+} thread_list;
/* Master of the theads. */
-struct thread_master
-{
- struct thread_list read;
- struct thread_list write;
- struct thread_list timer;
- struct thread_list event;
- struct thread_list ready;
- struct thread_list unuse;
+typedef struct _thread_master {
+ thread_list read;
+ thread_list write;
+ thread_list timer;
+ thread_list event;
+ thread_list ready;
+ thread_list unuse;
fd_set readfd;
fd_set writefd;
fd_set exceptfd;
unsigned long alloc;
-};
-
-/* Thread itself. */
-struct thread
-{
- unsigned long id;
- unsigned char type; /* thread type */
- struct thread *next; /* next pointer of the thread */
- struct thread *prev; /* previous pointer of the thread */
- struct thread_master *master; /* pointer to the struct thread_master. */
- int (*func) (struct thread *); /* event function */
- void *arg; /* event argument */
- struct timeval sands; /* rest of time sands value. */
- union {
- int val; /* second argument of the event. */
- int fd; /* file descriptor in case of read/write. */
- } u;
-};
+} thread_master;
/* Thread types. */
#define THREAD_READ 0
/* MICRO SEC def */
#define TIMER_SEC_MICRO 1000000
#define TIMER_MAX_SEC 1000
+#define BOOTSTRAP_DELAY 1
/* Macros. */
#define THREAD_ARG(X) ((X)->arg)
#define THREAD_VAL(X) ((X)->u.val)
/* Prototypes. */
-struct thread_master *thread_make_master ();
-
-struct thread *
-thread_add_terminate_event (struct thread_master *m);
+thread_master *thread_make_master(void);
-void
-thread_destroy_master (struct thread_master *m);
+thread *thread_add_terminate_event(thread_master *m);
-struct thread_arg *
-thread_arg_new (configuration_data *root,
- virtualserver *vserver,
- realserver *rserver);
+void thread_destroy_master(thread_master *m);
-struct thread *
-thread_add_read (struct thread_master *m,
- int (*func)(struct thread *),
- void *arg,
- int fd,
- long timeout);
+thread_arg *thread_arg_new(configuration_data *root
+ , virtualserver *vserver
+ , realserver *rserver);
-struct thread *
-thread_add_write (struct thread_master *m,
- int (*func)(struct thread *),
- void *arg,
- int fd,
- long timeout);
+thread *thread_add_read(thread_master *m
+ , int (*func)(thread *)
+ , void *arg
+ , int fd
+ , long timeout);
-struct thread *
-thread_add_timer (struct thread_master *m,
- int (*func)(struct thread *),
- void *arg,
- long timer);
+thread *thread_add_write(thread_master *m
+ , int (*func)(thread *)
+ , void *arg
+ , int fd
+ , long timeout);
-struct thread *
-thread_add_event (struct thread_master *m,
- int (*func)(struct thread *),
- void *arg,
- int val);
+thread *thread_add_timer(thread_master *m
+ , int (*func)(thread *)
+ , void *arg
+ , long timer);
+thread *thread_add_event(thread_master *m
+ , int (*func)(thread *)
+ , void *arg
+ , int val);
-void
-thread_cancel (struct thread *thread);
+void thread_cancel(thread *thread);
-void
-thread_cancel_event (struct thread_master *m, void *arg);
+void thread_cancel_event(thread_master *m, void *arg);
-struct thread *
-thread_fetch (struct thread_master *m,
- struct thread *fetch);
+thread *thread_fetch(thread_master *m, thread *fetch);
-void
-thread_call (struct thread *thread);
+void thread_call(thread *thread);
-int
-thread_timer_cmp (struct timeval a, struct timeval b);
+int thread_timer_cmp(TIMEVAL a, TIMEVAL b);
-struct timeval
-thread_timer_sub (struct timeval a, struct timeval b);
+TIMEVAL thread_timer_sub(TIMEVAL a, TIMEVAL b);
-void
-register_worker_thread(struct thread_master *master,
- configuration_data *lstptr);
+void register_worker_thread(thread_master *master
+ , configuration_data *lstptr);
/* extern prototypes */
-extern int
-tcp_connect_thread(struct thread *thread);
-
-extern int
-http_connect_thread(struct thread *thread);
-
-extern int
-misc_check_thread(struct thread *thread);
-
-extern int
-vrrp_dispatcher_init_thread(struct thread *thread);
+extern int tcp_connect_thread(thread *thread);
+extern int http_connect_thread(thread *thread);
+extern int ssl_connect_thread(thread *thread);
+extern int misc_check_thread(thread *thread);
+extern int vrrp_dispatcher_init_thread(thread *thread);
#endif
* using the smtp protocol according to the RFC 821. A non blocking
* timeouted connection is used to handle smtp protocol.
*
- * Version: $Id: smtp.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: smtp.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*/
#include "smtp.h"
+#include "memory.h"
/* static prototype */
-static int smtp_send_cmd_thread(struct thread *thread);
+static int smtp_send_cmd_thread(thread *thread);
-static void free_smtp_arg(struct smtp_thread_arg *smtp_arg)
+static void free_smtp_arg(smtp_thread_arg *smtp_arg)
{
- free(smtp_arg->subject);
- free(smtp_arg->body);
- free(smtp_arg);
+ FREE(smtp_arg->subject);
+ FREE(smtp_arg->body);
+ FREE(smtp_arg);
}
-static char *fetch_next_email(struct thread_arg *thread_arg)
+static void free_smtp_all(thread_arg *thread_arg)
{
- struct smtp_thread_arg *smtp_arg;
+ free_smtp_arg(THREAD_ARG_CHECKER_ARG(thread_arg));
+ FREE(thread_arg);
+}
+
+static char *fetch_next_email(thread_arg *thread_arg)
+{
+ smtp_thread_arg *smtp_arg;
int i = 0;
smtp_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
return NULL;
}
-static int smtp_read_cmd_thread(struct thread *thread)
+static int smtp_read_cmd_thread(thread *thread)
{
- struct thread_arg *thread_arg;
- struct smtp_thread_arg *smtp_arg;
+ thread_arg *thread_arg;
+ smtp_thread_arg *smtp_arg;
notification_email *pointeremail;
char *fetched_email;
long total_length = 0;
smtp_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
if (thread->type == THREAD_READ_TIMEOUT) {
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "Timeout reading data to remote SMTP server [%s:%d].",
inet_ntoa(thread_arg->root->smtp_server),
SMTP_PORT);
#endif
- free_smtp_arg(smtp_arg);
+ free_smtp_all(thread_arg);
thread_arg->checker_arg = NULL;
close(thread->u.fd);
return 0;
}
/* Allocate the get buffers */
- buffer = (char *)malloc(SMTP_BUFFER_MAX);
- buffer_tmp = (char *)malloc(SMTP_BUFFER_LENGTH);
+ buffer = (char *)MALLOC(SMTP_BUFFER_MAX);
+ buffer_tmp = (char *)MALLOC(SMTP_BUFFER_LENGTH);
/* Cleanup the room */
memset(buffer, 0, SMTP_BUFFER_MAX);
while ((rcv_buffer_size = read(thread->u.fd, buffer_tmp, SMTP_BUFFER_LENGTH)) != 0) {
if (rcv_buffer_size == -1) {
if (errno == EAGAIN) goto end;
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "Error reading data to remote SMTP server [%s:%d].",
inet_ntoa(thread_arg->root->smtp_server),
SMTP_PORT);
#endif
- free_smtp_arg(smtp_arg);
+ free_smtp_all(thread_arg);
thread_arg->checker_arg = NULL;
close(thread->u.fd);
- free(buffer);
- free(buffer_tmp);
+ FREE(buffer);
+ FREE(buffer_tmp);
return 0;
}
/* received data overflow buffer size ? */
if (total_length >= SMTP_BUFFER_MAX) {
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "Received buffer from remote SMTP server [%s:%d]"
" overflow our get read buffer length.",
inet_ntoa(thread_arg->root->smtp_server),
SMTP_PORT);
#endif
- free_smtp_arg(smtp_arg);
+ free_smtp_all(thread_arg);
thread_arg->checker_arg = NULL;
close(thread->u.fd);
- free(buffer);
- free(buffer_tmp);
+ FREE(buffer);
+ FREE(buffer_tmp);
return 0;
} else {
memcpy(buffer+total_length, buffer_tmp, rcv_buffer_size);
case quit:
/* final state, we are disconnected from the remote host */
- free_smtp_arg(smtp_arg);
+ free_smtp_all(thread_arg);
thread_arg->checker_arg = NULL;
close(thread->u.fd);
- free(buffer);
- free(buffer_tmp);
+ FREE(buffer);
+ FREE(buffer_tmp);
return 0;
break;
thread_add_write(thread->master, smtp_send_cmd_thread, thread_arg, thread->u.fd,
thread_arg->root->smtp_connection_to);
- free(buffer);
- free(buffer_tmp);
+ FREE(buffer);
+ FREE(buffer_tmp);
return 0;
}
/* Getting localhost official canonical name */
-static char *get_local_name()
+static char *get_local_name(void)
{
struct hostent *host;
struct utsname name;
return host->h_name;
}
-static int smtp_send_cmd_thread(struct thread *thread)
+static int smtp_send_cmd_thread(thread *thread)
{
- struct thread_arg *thread_arg;
- struct smtp_thread_arg *smtp_arg;
+ thread_arg *thread_arg;
+ smtp_thread_arg *smtp_arg;
notification_email *pointeremail;
char *fetched_email;
char *buffer;
smtp_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
if (thread->type == THREAD_WRITE_TIMEOUT) {
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "Timeout sending data to remote SMTP server [%s:%d].",
inet_ntoa(thread_arg->root->smtp_server),
SMTP_PORT);
#endif
- free_smtp_arg(smtp_arg);
+ free_smtp_all(thread_arg);
thread_arg->checker_arg = NULL;
close(thread->u.fd);
return 0;
}
/* allocate temporary command buffer */
- buffer = (char *)malloc(SMTP_BUFFER_MAX);
- memset(buffer, 0, SMTP_BUFFER_MAX);
+ buffer = (char *)MALLOC(SMTP_BUFFER_MAX);
switch (smtp_arg->stage) {
case connection:
break;
case error:
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "Can not send data to remote SMTP server [%s:%d].",
inet_ntoa(thread_arg->root->smtp_server),
SMTP_PORT);
#endif
/* we just cleanup the room */
- free_smtp_arg(smtp_arg);
+ free_smtp_all(thread_arg);
thread_arg->checker_arg = NULL;
close(thread->u.fd);
- free(buffer);
+ FREE(buffer);
return 0;
break;
}
thread_add_read(thread->master, smtp_read_cmd_thread, thread_arg, thread->u.fd,
thread_arg->root->smtp_connection_to);
- free(buffer);
+ FREE(buffer);
return 0;
}
/* SMTP checkers threads */
-static int smtp_check_thread(struct thread *thread)
+static int smtp_check_thread(thread *thread)
{
- struct thread_arg *thread_arg;
- struct smtp_thread_arg *smtp_arg;
+ thread_arg *thread_arg;
+ smtp_thread_arg *smtp_arg;
int status;
thread_arg = THREAD_ARG(thread);
switch (status) {
case connect_error:
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "Error connecting SMTP server [%s:%d].",
inet_ntoa(thread_arg->root->smtp_server),
SMTP_PORT);
#endif
- free_smtp_arg(smtp_arg);
+ free_smtp_all(thread_arg);
thread_arg->checker_arg = NULL;
break;
case connect_timeout:
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "Timeout writing data to SMTP server [%s:%d].",
inet_ntoa(thread_arg->root->smtp_server),
SMTP_PORT);
#endif
- free_smtp_arg(smtp_arg);
+ free_smtp_all(thread_arg);
thread_arg->checker_arg = NULL;
break;
/* Remote SMTP server is connected.
* Register the next step thread smtp_cmd_thread.
*/
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "Remote SMTP server [%s:%d] connected.",
inet_ntoa(thread_arg->root->smtp_server),
SMTP_PORT);
return 0;
}
-static int smtp_connect_thread(struct thread *thread)
+static int smtp_connect_thread(thread *thread)
{
- struct thread_arg *thread_arg;
- struct smtp_thread_arg *smtp_arg;
+ thread_arg *thread_arg;
+ smtp_thread_arg *smtp_arg;
enum connect_result status;
int fd;
smtp_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
if ( (fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) {
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "SMTP connect fail to create socket.");
#endif
return 0;
switch (status) {
case connect_error:
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "SMTP connection ERROR to [%s:%d].",
inet_ntoa(thread_arg->root->smtp_server),
SMTP_PORT);
#endif
- free_smtp_arg(smtp_arg);
+ free_smtp_all(thread_arg);
thread_arg->checker_arg = NULL;
close(fd);
return 0;
break;
case connect_timeout:
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "Timeout connecting SMTP server [%s:%d].",
inet_ntoa(thread_arg->root->smtp_server),
SMTP_PORT);
#endif
- free_smtp_arg(smtp_arg);
+ free_smtp_all(thread_arg);
thread_arg->checker_arg = NULL;
close(fd);
return 0;
break;
case connect_success:
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "SMTP connection SUCCESS to [%s:%d].",
inet_ntoa(thread_arg->root->smtp_server),
SMTP_PORT);
/* Checking non-blocking connect, we wait until socket is writable */
case connect_in_progress:
-#ifdef DEBUG
+#ifdef _DEBUG_
syslog(LOG_DEBUG, "SMTP connection to [%s:%d] now IN_PROGRESS.",
inet_ntoa(thread_arg->root->smtp_server),
SMTP_PORT);
return 1;
}
-void smtp_alert(struct thread_master *master,
- configuration_data *root,
- realserver *rserver,
- const char *subject,
- const char *body)
+void smtp_alert(thread_master *master
+ , configuration_data *root
+ , realserver *rserver
+ , const char *subject
+ , const char *body)
{
- struct thread_arg *thread_arg;
- struct smtp_thread_arg *smtp_arg;
+ thread_arg *thread_arg;
+ smtp_thread_arg *smtp_arg;
/* Only send mail if email specified */
if (root->email) {
thread_arg = thread_arg_new(root, NULL, NULL);
/* allocate & initialize smtp argument data structure */
- smtp_arg = (struct smtp_thread_arg *)malloc(sizeof(struct smtp_thread_arg));
- memset(smtp_arg, 0, sizeof(struct smtp_thread_arg));
-
- smtp_arg->subject = (char *)malloc(MAX_SUBJECT_LENGTH);
- smtp_arg->body = (char *)malloc(MAX_BODY_LENGTH);
- memset(smtp_arg->subject, 0, MAX_SUBJECT_LENGTH);
- memset(smtp_arg->body, 0, MAX_BODY_LENGTH);
+ smtp_arg = (smtp_thread_arg *)MALLOC(sizeof(smtp_thread_arg));
+ smtp_arg->subject = (char *)MALLOC(MAX_SUBJECT_LENGTH);
+ smtp_arg->body = (char *)MALLOC(MAX_BODY_LENGTH);
smtp_arg->stage = connection; /* first smtp command set to HELO */
*
* Part: smtp.c include file.
*
- * Version: $Id: smtp.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: smtp.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#define MAX_SUBJECT_LENGTH 256
#define MAX_BODY_LENGTH 512
-struct smtp_thread_arg {
+typedef struct _smtp_thread_arg {
enum smtp_cmd stage;
int email_it;
char *subject;
char *body;
-};
+} smtp_thread_arg;
/* Smtp error code */
#define SMTP_CONNECT "220"
#define SMTP_QUIT_CMD "QUIT\n"
/* Prototypes defs */
-extern void smtp_alert(struct thread_master *master,
- configuration_data *root,
- realserver *rserver,
- const char *subject,
- const char *body);
+extern void smtp_alert(thread_master *
+ , configuration_data *
+ , realserver *
+ , const char *
+ , const char *);
#endif
*
* Part: General program utils.
*
- * Version: $Id: utils.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: utils.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
-#ifndef _UTILES_H
-#define _UTILES_H
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: utils.h include file.
+ *
+ * Version: $Id: utils.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * 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
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _UTILS_H
+#define _UTILS_H
/* system includes */
#include <stdio.h>
/*
- * Soft: Vrrpd is an implementation of VRRPv2 as specified in rfc2338.
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: VRRP implementation of VRRPv2 as specified in rfc2338.
* VRRP is a protocol which elect a master server on a LAN. If the
* master fails, a backup server takes over.
* The original implementation has been made by jerome etienne.
*
- * Version: $Id: vrrp.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: vrrp.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
/* local include */
#include "vrrp_scheduler.h"
#include "vrrp.h"
+#include "memory.h"
+
+/* Close all FDs >= a specified value */
+void closeall(int fd)
+{
+ int fdlimit = sysconf(_SC_OPEN_MAX);
+
+ while (fd < fdlimit)
+ close(fd++);
+}
+
+static char *notify_get_name(vrrp_rt *vsrv)
+{
+ static char notifyfile[FILENAME_MAX+1];
+
+ if (vsrv->notify_exec) {
+ if (vsrv->notify_file != NULL)
+ strncpy(notifyfile,vsrv->notify_file, FILENAME_MAX);
+ else
+ snprintf( notifyfile, sizeof(notifyfile),"%s/" VRRP_NOTIFY_FORMAT
+ , VRRP_NOTIFY_DFL
+ , vsrv->vif->ifname
+ , vsrv->vrid );
+ }
+ return notifyfile;
+}
+
+/* Execute extern script/program */
+static int notify_exec( vrrp_rt *vsrv , char *cmd)
+{
+ char *name = notify_get_name(vsrv);
+ FILE *fOut = fopen(name, "r");
+ static char mycmd[FILENAME_MAX + 1 + 32];
+ char tmp[16];
+ int err;
+
+ pid_t pid;
+
+ if (!fOut) {
+ syslog(LOG_INFO, "Can't open %s (errno %d %s)\n", name
+ , errno
+ , strerror(errno));
+ return -1;
+ }
+ fclose(fOut);
+
+ pid = fork();
+
+ /* In case of fork is error. */
+ if (pid < 0) {
+ syslog (LOG_INFO, "Failed fork process");
+ return -1;
+ }
+
+ /* In case of this is parent process. */
+ if (pid) {
+ return (0);
+ }
+
+ closeall(0);
+
+ open("/dev/null", O_RDWR);
+ dup(0);
+ dup(0);
+
+ name = notify_get_name(vsrv);
+
+ if (strlen(name) + strlen(cmd) + 32 > FILENAME_MAX + 32) {
+ syslog(LOG_INFO,"To long exec stmt");
+ exit (1);
+ }
+
+ strcpy(mycmd,name);
+ strcat(mycmd," ");
+ strcat(mycmd,cmd);
+ strcat(mycmd," ");
+ snprintf(tmp,16,"%d",vsrv->vrid);
+ strcat(mycmd, tmp);
+
+ if (vsrv->debug > 0)
+ syslog(LOG_INFO, "Trying to exec %s", mycmd);
+
+ err = system(mycmd);
+
+ if (err != 0) {
+ if (err == 127)
+ syslog(LOG_ALERT, "Failed to exec %s", mycmd);
+ else
+ syslog(LOG_ALERT, "Error running %s, error: %d", mycmd, err);
+ }
+
+ exit(0);
+}
+
/* compute checksum */
static u_short in_csum( u_short *addr, int len, u_short csum)
}
/* IPSEC AH header length */
-int vrrp_ipsecah_len()
+int vrrp_ipsecah_len(void)
{
return sizeof(ipsec_ah);
}
*/
vsrv->ipsecah_counter->seq_number++;
if (ah->seq_number >= vsrv->ipsecah_counter->seq_number) {
-#ifdef DEBUG
+#ifdef _DEBUG_
// syslog(LOG_DEBUG, "IPSEC AH : SEQUENCE NUMBER : %d\n", ah->seq_number);
#endif
vsrv->ipsecah_counter->seq_number = ah->seq_number;
* then compute a ICV to compare with the one present in AH pkt.
* alloc a temp memory space to stock the ip mutable fields
*/
- digest=(unsigned char *)malloc(16*sizeof(unsigned char *));
- memset(digest, 0, 16*sizeof(unsigned char *));
+ digest = (unsigned char *)MALLOC(16*sizeof(unsigned char *));
/* zero the ip mutable fields */
ip->tos = 0;
return 1;
}
- free(digest);
+ FREE(digest);
return 0;
}
ipsec_ah *ah = (ipsec_ah *)(buffer + sizeof(struct iphdr));
/* alloc a temp memory space to stock the ip mutable fields */
- ip_mutable_fields=calloc(sizeof(ICV_mutable_fields), 1);
- memset(ip_mutable_fields, 0, sizeof(ICV_mutable_fields));
+ ip_mutable_fields = (ICV_mutable_fields *)MALLOC(sizeof(ICV_mutable_fields));
/* fill in next header filed --rfc2402.2.1 */
ah->next_header = IPPROTO_VRRP;
=> No padding needed.
-- rfc2402.3.3.3.1.1.1 & rfc2401.5
*/
- digest=(unsigned char *)malloc(16*sizeof(unsigned char *));
- memset(digest, 0, 16*sizeof(unsigned char *));
+ digest = (unsigned char *)MALLOC(16*sizeof(unsigned char *));
hmac_md5(buffer, buflen,vsrv->vif->auth_data, sizeof(vsrv->vif->auth_data), digest);
memcpy(ah->auth_data, digest, HMAC_MD5_TRUNC);
ip->frag_off = ip_mutable_fields->frag_off;
ip->check = ip_mutable_fields->check;
- free(ip_mutable_fields);
- free(digest);
+ FREE(ip_mutable_fields);
+ FREE(digest);
}
/* build VRRP header */
buflen = vrrp_dlt_len(vsrv) + vrrp_iphdr_len(vsrv) + vrrp_hd_len(vsrv);
if (vsrv->vif->auth_type == VRRP_AUTH_AH)
buflen += vrrp_ipsecah_len();
- buffer = calloc(buflen, 1);
- memset(buffer,0,buflen);
+
+ buffer = MALLOC(buflen);
/* build the packet */
vrrp_build_pkt(vsrv, prio, buffer, buflen);
ret = vrrp_send_pkt(vsrv, buffer, buflen);
/* free the memory */
- free(buffer);
+ FREE(buffer);
return ret;
}
syslog(LOG_INFO, "VRRP_Instance(%s) Entering MASTER STATE"
, vrrp_instance->iname);
+ if (vsrv->notify_exec) {
+ notify_exec(vsrv, "master");
+ if (vsrv->debug > 0)
+ syslog(LOG_INFO, "notify:%s, flg:%d"
+ , vsrv->notify_file
+ , vsrv->notify_exec);
+ }
+
vsrv->state = VRRP_STATE_MAST;
}
syslog(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE"
, instance->iname);
+ if (vsrv->notify_exec) {
+ notify_exec(vsrv, "backup");
+ if (vsrv->debug > 0)
+ syslog(LOG_INFO, "notify:%s, flg:%d"
+ , vsrv->notify_file
+ , vsrv->notify_exec);
+ }
+
/* register the vrrp backup handler */
vsrv->state = VRRP_STATE_BACK;
}
/* BACKUP state processing */
void vrrp_state_backup(vrrp_instance *instance, char *buf, int buflen)
{
- int ret = 0;
- vrrp_rt *vsrv = instance->vsrv;
- struct iphdr *iph = (struct iphdr *)buf;
- vrrp_pkt *hd;
+ int ret = 0;
+ vrrp_rt *vsrv = instance->vsrv;
+ struct iphdr *iph = (struct iphdr *)buf;
+ vrrp_pkt *hd = NULL;
/* Fill the VRRP header */
switch (iph->protocol) {
int vrrp_state_master_rx(vrrp_instance *instance, char *buf, int buflen)
{
- int ret = 0;
- vrrp_rt *vsrv = instance->vsrv;
- struct iphdr *iph = (struct iphdr *)buf;
- vrrp_pkt *hd;
+ int ret = 0;
+ vrrp_rt *vsrv = instance->vsrv;
+ struct iphdr *iph = (struct iphdr *)buf;
+ vrrp_pkt *hd = NULL;
/* Fill the VRRP header */
switch (iph->protocol) {
* master fails, a backup server takes over.
* The original implementation has been made by jerome etienne.
*
- * Version: $Id: vrrp.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Part: vrrp.c program include file.
+ *
+ * Version: $Id: vrrp.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
* Based on the Jerome Etienne, <jetienne@arobas.net> code.
#include "vrrp_ipsecah.h"
#include "utils.h"
+
+/* Default dir to notify file */
+#define VRRP_NOTIFY_DFL "/etc/init.d"
+
+/* notify name (vrrpd-eth0-101) */
+#define VRRP_NOTIFY_FORMAT "vrrpd-%s-%d"
+
typedef struct { /* rfc2338.5.1 */
uint8_t vers_type; /* 0-3=type, 4-7=version */
uint8_t vrid; /* virtual router id */
int wantstate; /* user explicitly wants a state (back/mast) */
int fd; /* the socket descriptor */
+ int debug; /* Debug level 0-4 */
+ int notify_exec;
+ char notify_file[FILENAME_MAX ];
+
+
/* rfc2336.6.2 */
uint32_t ms_down_timer;
struct timeval sands;
#define VRRP_PACKET_KO 1
#define VRRP_PACKET_DROP 2
#define VRRP_PACKET_NULL 3
+#define VRRP_PACKET_OTHER 4 /* Muliple VRRP on LAN, Identify "other" VRRP */
#define VRRP_PACKET_TEMP_LEN 256
#define VRRP_AUTH_LEN 8
#define VRRP_IS_BAD_VID(id) ((id)<1 || (id)>255) /* rfc2338.6.1.vrid */
#define VRRP_IS_BAD_PRIORITY(p) ((p)<1 || (p)>255) /* rfc2338.6.1.prio */
-#define VRRP_IS_BAD_ADVERT_INT(d) ((d)<1)
+#define VRRP_IS_BAD_ADVERT_INT(d) ((d)<1)
+
+#define VRRP_IS_BAD_DEBUG_INT(d) ((d)<0 || (d)>4)
+
#define VRRP_TIMER_HZ 1000000
#define VRRP_TIMER_SKEW(srv) ((256-(srv)->priority)*VRRP_TIMER_HZ/256)
#define VRRP_MAX(a, b) ((a) > (b)?(a):(b))
/* prototypes */
-extern int vrrp_ipsecah_len();
+extern int vrrp_ipsecah_len(void);
extern int complete_vrrp_init(vrrp_rt *vsrv);
extern void vrrp_state_stop_instance(vrrp_rt *vsrv);
* <www.linuxvirtualserver.org>. It monitor & manipulate
* a loadbalanced server pool using multi-layer checks.
*
- * Part: VRRP implementation of VRRPv2 as specified in rfc2338.
- * VRRP is a protocol which elect a master server on a LAN. If the
- * master fails, a backup server takes over.
- * The original implementation has been made by jerome etienne.
+ * Part: NETLINK IPv4 address manipulation.
*
- * Version: $Id: vrrp_ipaddress.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: vrrp_ipaddress.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: vrrp_ipaddress.c include file.
*
- * Version: $Id: vrrp_ipaddress.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: vrrp_ipaddress.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
* authentication data encryption using HMAC MD5 according to
* RFCs 2085 & 2104.
*
- * Version: $Id: vrrp_ipsecah.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: vrrp_ipsecah.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*/
#include "vrrp_ipsecah.h"
-#include "md5.h"
+#include <openssl/md5.h>
/* hmac_md5 computation according to the RFCs 2085 & 2104 */
void hmac_md5(unsigned char *buffer,int buffer_len,
MD5_CTX tctx;
/* Compute the MD5 digest */
- MD5Init(&tctx);
- MD5Update(&tctx,key,key_len);
- MD5Final(tk,&tctx);
+ MD5_Init(&tctx);
+ MD5_Update(&tctx,key,key_len);
+ MD5_Final(tk,&tctx);
key = tk;
key_len = 16;
}
/* Compute inner MD5 */
- MD5Init(&context); /* Init context for 1st pass */
- MD5Update(&context,k_ipad,64); /* start with inner pad */
- MD5Update(&context,buffer,buffer_len); /* next with buffer datagram */
- MD5Final(digest,&context); /* Finish 1st pass */
+ MD5_Init(&context); /* Init context for 1st pass */
+ MD5_Update(&context,k_ipad,64); /* start with inner pad */
+ MD5_Update(&context,buffer,buffer_len); /* next with buffer datagram */
+ MD5_Final(digest,&context); /* Finish 1st pass */
/* Compute outer MD5 */
- MD5Init(&context); /* Init context for 2nd pass */
- MD5Update(&context,k_opad,64); /* start with inner pad */
- MD5Update(&context,digest,16); /* next result of 1st pass */
- MD5Final(digest,&context); /* Finish 2nd pass */
+ MD5_Init(&context); /* Init context for 2nd pass */
+ MD5_Update(&context,k_opad,64); /* start with inner pad */
+ MD5_Update(&context,digest,16); /* next result of 1st pass */
+ MD5_Final(digest,&context); /* Finish 2nd pass */
}
*
* Part: vrrp_ipsecah.c include file.
*
- * Version: $Id: vrrp_ipsecah.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: vrrp_ipsecah.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: NETLINK kernel command channel.
*
- * Version: $Id: vrrp_netlink.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: vrrp_netlink.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: vrrp_netlink.c include file.
*
- * Version: $Id: vrrp_netlink.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: vrrp_netlink.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: Sheduling framework for vrrp code.
*
- * Version: $Id: vrrp_scheduler.c,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: vrrp_scheduler.c,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#include "vrrp_scheduler.h"
#include "vrrp_ipsecah.h"
#include "vrrp.h"
+#include "memory.h"
/*
* Initialize state handling
}
/* Timer functions */
-static struct timeval vrrp_compute_timer(const int fd, vrrp_instance *vrrp)
+static TIMEVAL vrrp_compute_timer(const int fd, vrrp_instance *vrrp)
{
vrrp_instance *ptr = vrrp;
- struct timeval timer;
+ TIMEVAL timer;
/* clean the memory */
memset(&timer, 0, sizeof(struct timeval));
return timer;
}
-static struct timeval vrrp_timer_delta(struct timeval timer)
+static TIMEVAL vrrp_timer_delta(TIMEVAL timer)
{
- struct timeval timer_now;
+ TIMEVAL timer_now;
/* init timer */
memset(&timer_now, 0, sizeof(struct timeval));
static long vrrp_timer_fd(const int fd, vrrp_instance *instance)
{
- struct timeval timer;
+ TIMEVAL timer;
long vrrp_timer = 0;
timer = vrrp_compute_timer(fd, instance);
static int vrrp_timer_vrid_timeout(const int fd, vrrp_instance *vrrp)
{
vrrp_instance *ptr = vrrp;
- struct timeval vrrp_timer;
+ TIMEVAL vrrp_timer;
int vrid = 0;
/* clean the memory */
static void vrrp_timer_dump(vrrp_instance *vrrp)
{
vrrp_instance *ptr = vrrp;
- struct timeval timer_now;
- struct timeval timer;
+ TIMEVAL timer_now;
+ TIMEVAL timer;
long vrrp_timer = 0;
memset(&timer, 0, sizeof(struct timeval));
*/
/* Thread functions */
-static void vrrp_register_workers(struct thread_master *master,
- vrrp_instance *instance,
- sockpool *pool)
+static void vrrp_register_workers(thread_master *master
+ , vrrp_instance *instance
+ , sockpool *pool)
{
sockpool *poolptr = pool;
- struct timeval timer;
+ TIMEVAL timer;
long vrrp_timer = 0;
/* init compute timer */
sockpool *t;
t = (sockpool *)pool->next;
- free(pool);
+ FREE(pool);
return t;
}
if (!already_exist_sock(pool, ifindex, proto)) {
/* allocate & clean the new struct */
- sock = (sockpool *)malloc(sizeof(sockpool));
- memset(sock, 0, sizeof(sockpool));
+ sock = (sockpool *)MALLOC(sizeof(sockpool));
/* fill in the new sock structure */
sock->ifindex = ifindex;
* are multiplexed through this fds. So our design can handle 2*n
* multiplexing points.
*/
-int vrrp_dispatcher_init_thread(struct thread *thread)
+int vrrp_dispatcher_init_thread(thread *thread)
{
vrrp_instance *instance = THREAD_ARG(thread);
sockpool *pool;
return NULL;
}
-static void vrrp_handle_backup(vrrp_instance *instance,
- char *vrrp_buffer,
- int len)
+static void vrrp_handle_backup(vrrp_instance *instance
+ , char *vrrp_buffer
+ , int len)
{
vrrp_state_backup(instance, vrrp_buffer, len);
}
-static void vrrp_handle_become_master(vrrp_instance *instance,
- char *vrrp_buffer,
- int len)
+static void vrrp_handle_become_master(vrrp_instance *instance
+ , char *vrrp_buffer
+ , int len)
{
vrrp_rt *vsrv = instance->vsrv;
struct iphdr *iph = (struct iphdr *)vrrp_buffer;
}
}
-static void vrrp_handle_leave_master(vrrp_instance *instance,
- char *vrrp_buffer,
- int len)
+static void vrrp_handle_leave_master(vrrp_instance *instance
+ , char *vrrp_buffer
+ , int len)
{
if (vrrp_state_master_rx(instance, vrrp_buffer, len)) {
syslog(LOG_INFO, "VRRP_Instance(%s) Received higher prio advert"
}
}
-static int vrrp_handle_state(vrrp_instance *instance,
- char *vrrp_buffer,
- int len)
+static int vrrp_handle_state(vrrp_instance *instance
+ , char *vrrp_buffer
+ , int len)
{
int previous_state;
}
/* Our read packet dispatcher */
-int vrrp_read_dispatcher_thread(struct thread *thread)
+int vrrp_read_dispatcher_thread(thread *thread)
{
vrrp_instance *instance = THREAD_ARG(thread);
vrrp_instance *ptr = instance;
} else {
/* allocate & clean the read buffer */
- vrrp_buffer = (char *)malloc(VRRP_PACKET_TEMP_LEN);
- memset(vrrp_buffer, 0, VRRP_PACKET_TEMP_LEN);
+ vrrp_buffer = (char *)MALLOC(VRRP_PACKET_TEMP_LEN);
/* read & affect received buffer */
len = read(thread->u.fd, vrrp_buffer, VRRP_PACKET_TEMP_LEN);
iph = (struct iphdr *)vrrp_buffer;
- switch (iph->protocol) {
- case IPPROTO_IPSEC_AH:
- hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2) + vrrp_ipsecah_len());
- break;
- case IPPROTO_VRRP:
- hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2));
- break;
- }
+ if (iph->protocol == IPPROTO_IPSEC_AH)
+ hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2) + vrrp_ipsecah_len());
+ else
+ hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2));
/* Searching for matching instance */
vrrp_instance = vrrp_search_instance(hd->vrid, instance);
}
/* cleanup the room */
- free(vrrp_buffer);
+ FREE(vrrp_buffer);
}
*
* Part: vrrp_scheduler.c include file.
*
- * Version: $Id: vrrp_scheduler.h,v 0.4.8 2001/11/20 15:26:11 acassen Exp $
+ * Version: $Id: vrrp_scheduler.h,v 0.4.9 2001/12/10 10:52:33 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
extern int open_vrrp_socket(const int proto, const int index);
extern int ifname_to_idx(const char *ifname);
extern void vrrp_send_gratuitous_arp(vrrp_instance *vrrp_instance);
-extern int vrrp_read_dispatcher_thread(struct thread *thread);
+extern int vrrp_read_dispatcher_thread(thread *thread);
extern int vrrp_state_master_rx(vrrp_instance *instance, char *buf, int buflen);
extern void vrrp_state_master_tx(vrrp_instance *instance, const int prio);
extern void vrrp_state_backup(vrrp_instance *instance, char *buf, int buflen);