diff -rNu keepalived-1.1.13/doc/man/man5/keepalived.conf.5 keepalived-1.1.13-extcheck/doc/man/man5/keepalived.conf.5 --- keepalived-1.1.13/doc/man/man5/keepalived.conf.5 2005-02-07 10:24:59.000000000 +0900 +++ keepalived-1.1.13-extcheck/doc/man/man5/keepalived.conf.5 2007-07-06 17:19:38.000000000 +0900 @@ -346,7 +346,7 @@ notify_down | # pick one healthchecker - # HTTP_GET|SSL_GET|TCP_CHECK|SMTP_CHECK|MISC_CHECK + # HTTP_GET|SSL_GET|TCP_CHECK|SMTP_CHECK|FTP_CHECK|DNS_CHECK|SSL_HELLO|MISC_CHECK # HTTP and SSL healthcheckers HTTP_GET|SSL_GET @@ -431,6 +431,40 @@ # weight to 253) misc_dynamic } + + #FTP healthchecker + FTP_CHECK + { + connect_port + connect_timeout + bindto + retry + delay_before_retry + } + + #DNS healthchecker + DNS_CHECK + { + port + timeout + retry + # DNS request record type + # A|NS|SOA... (see RFC1035 + # the default of A + type | + name | + } + + #SSL HELLO healthchecker + SSL_HELLO + { + connect_port + connect_timeout + retry + delay_before_retry + common_name | + } + } # realserver defn } # virtual service diff -rNu keepalived-1.1.13/keepalived/check/Makefile.in keepalived-1.1.13-extcheck/keepalived/check/Makefile.in --- keepalived-1.1.13/keepalived/check/Makefile.in 2006-03-09 22:19:59.000000000 +0900 +++ keepalived-1.1.13-extcheck/keepalived/check/Makefile.in 2007-07-06 17:19:38.000000000 +0900 @@ -14,7 +14,8 @@ OBJS = check_daemon.o check_data.o check_parser.o \ check_api.o check_tcp.o check_http.o check_ssl.o \ - check_smtp.o check_misc.o ipwrapper.o ipvswrapper.o + check_smtp.o check_misc.o ipwrapper.o ipvswrapper.o \ + check_ssl_hello.o check_ftp.o check_dns.o ifeq ($(KERNEL),_KRNL_2_2_) OBJS += ipfwwrapper.o @@ -68,3 +69,13 @@ ../../lib/utils.h ../../lib/notify.h ipvswrapper.o: ipvswrapper.c ../include/ipvswrapper.h ../../lib/utils.h \ ../../lib/memory.h +check_ssl_hello.o: check_ssl_hello.c ../include/check_ssl_hello.h ../include/check_api.h \ + ../../lib/memory.h ../include/ipwrapper.h ../include/layer4.h \ + ../../lib/utils.h ../../lib/parser.h ../include/smtp.h +check_ftp.o: check_ftp.c ../include/check_ftp.h ../include/check_api.h \ + ../../lib/memory.h ../include/ipwrapper.h ../include/smtp.h \ + ../../lib/utils.h ../../lib/notify.h ../../lib/parser.h ../include/daemon.h +check_dns.o: check_dns.c ../include/check_dns.h ../include/check_api.h \ + ../../lib/memory.h ../include/ipwrapper.h ../include/smtp.h \ + ../../lib/utils.h ../../lib/parser.h + diff -rNu keepalived-1.1.13/keepalived/check/check_api.c keepalived-1.1.13-extcheck/keepalived/check/check_api.c --- keepalived-1.1.13/keepalived/check/check_api.c 2006-10-11 18:40:17.000000000 +0900 +++ keepalived-1.1.13-extcheck/keepalived/check/check_api.c 2007-07-06 17:19:38.000000000 +0900 @@ -35,6 +35,9 @@ #include "check_tcp.h" #include "check_http.h" #include "check_ssl.h" +#include "check_ssl_hello.h" +#include "check_ftp.h" +#include "check_dns.h" /* Global vars */ static checker_id_t ncheckers = 0; @@ -171,4 +174,7 @@ install_tcp_check_keyword(); install_http_check_keyword(); install_ssl_check_keyword(); + install_ssl_hello_keyword(); + install_ftp_check_keyword(); + install_dns_check_keyword(); } diff -rNu keepalived-1.1.13/keepalived/check/check_dns.c keepalived-1.1.13-extcheck/keepalived/check/check_dns.c --- keepalived-1.1.13/keepalived/check/check_dns.c 1970-01-01 09:00:00.000000000 +0900 +++ keepalived-1.1.13-extcheck/keepalived/check/check_dns.c 2007-07-06 17:19:38.000000000 +0900 @@ -0,0 +1,388 @@ +#include +#include +#include "check_dns.h" +#include "scheduler.h" +#include "check_api.h" +#include "memory.h" +#include "ipwrapper.h" +#include "utils.h" +#include "parser.h" +#include "smtp.h" + +int dns_send_thread(thread *thread_obj); +int dns_recv_thread(thread *thread_obj); + +char *RRTYPE[]={"A","NS","MD","MF","CNAME","SOA","MB","MG","MR", + "NULL","WKS","PTR","HINFO","MINFO","MX","TXT",NULL}; + +void +dns_log(thread *thread_obj, int level, const char *format, ...) +{ + checker *chk = THREAD_ARG(thread_obj); + dns_checker *dns = CHECKER_ARG(chk); + char buff[1024]; + va_list varg_list; + if(dns->log_level >= level){ + va_start(varg_list, format); + vsnprintf(buff, 1024, format, varg_list); + va_end(varg_list); + syslog(LOG_INFO,"DNS_CHECK[%s:%d] %s",inet_ntop2(CHECKER_RIP(chk)), ntohs(dns->port),buff); + } +} + +int +dns_final(thread *thread_obj, int error) +{ + checker *chk = THREAD_ARG(thread_obj); + dns_checker *dns = CHECKER_ARG(chk); + + close(thread_obj->u.fd); + dns_log(thread_obj, 7, "final error=%d attempts=%d retry=%d", error, dns->attempts, dns->retry); + if(error){ + if(svr_checker_up(chk->id, chk->rs)){ + if(dns->attempts < dns->retry) { + dns->attempts++; + thread_add_timer(thread_obj->master, dns_send_thread, chk, chk->vs->delay_loop); + return 0; + } + update_svr_checker_state(DOWN, chk->id, chk->vs, chk->rs); + smtp_alert(chk->rs, NULL, NULL, "DOWN", "=> DNS CHECK failed on service <="); + } + }else{ + if(!svr_checker_up(chk->id, chk->rs)){ + smtp_alert(chk->rs, NULL, NULL, "UP", "=> DNS CHECK succeed on service <="); + update_svr_checker_state(UP, chk->id, chk->vs, chk->rs); + } + } + dns->attempts = 0; + thread_add_timer(thread_obj->master, dns_send_thread, chk, chk->vs->delay_loop); + return(0); +} + +void +dns_dump(void *data) +{ + dns_checker *dns = CHECKER_DATA(data); + syslog(LOG_INFO, " Port = %d", ntohs(dns->port)); + syslog(LOG_INFO, " Timeout = %d", dns->timeout/TIMER_HZ); + syslog(LOG_INFO, " Retry = %d", dns->retry); + syslog(LOG_INFO, " Type = %s", dns->type); + syslog(LOG_INFO, " Name = %s", dns->name); +} + +int +dns_recv_thread(thread *thread_obj) +{ + size_t r; + socklen_t len; + struct sockaddr_in addr; + checker *chk = THREAD_ARG(thread_obj); + dns_checker *dns = CHECKER_ARG(chk); + dns_header s_header; + dns_header r_header; + + dns_log(thread_obj, 7, "recv_thread"); + if(thread_obj->type == THREAD_READ_TIMEOUT){ + dns_log(thread_obj, 1, "read timeout"); + dns_final(thread_obj,1); + return(0); + } + + len = sizeof(addr); + r = recvfrom(thread_obj->u.fd, dns->read, dns->size, MSG_DONTWAIT, (struct sockaddr *)&addr, &len); + if(r == -1 && (errno == EAGAIN || errno == EINTR)) { + thread_add_read(thread_obj->master, dns_recv_thread, chk, thread_obj->u.fd, dns->timeout); + return(0); + } + + if(r <= 0){ + /*----- error -----*/ + dns_log(thread_obj, 0,"socket read error!"); + dns_final(thread_obj,1); + return(0); + } + + dns_log(thread_obj,7,"read size=%d",r); + if(addr.sin_addr.s_addr != CHECKER_RIP(chk) || addr.sin_port != dns->port){ + dns_log(thread_obj, 1, "ignore message [%s:%d]", inet_ntop2(addr.sin_addr.s_addr), ntohs(addr.sin_port)); + thread_add_read(thread_obj->master, dns_recv_thread, chk, thread_obj->u.fd, dns->timeout); + return(0); + } + + if(r < sizeof(r_header)){ + dns->read += r; + dns->size -= r; + thread_add_read(thread_obj->master, dns_recv_thread, chk, thread_obj->u.fd, dns->timeout); + return(0); + } + + memcpy(&s_header, dns->send, sizeof(s_header)); + s_header.id = ntohs(s_header.id); + s_header.flags = ntohs(s_header.flags); + s_header.qdcount = ntohs(s_header.qdcount); + s_header.ancount = ntohs(s_header.ancount); + s_header.nscount = ntohs(s_header.nscount); + s_header.arcount = ntohs(s_header.arcount); + + memcpy(&r_header, dns->recv, sizeof(r_header)); + r_header.id = ntohs(r_header.id); + r_header.flags = ntohs(r_header.flags); + r_header.qdcount = ntohs(r_header.qdcount); + r_header.ancount = ntohs(r_header.ancount); + r_header.nscount = ntohs(r_header.nscount); + r_header.arcount = ntohs(r_header.arcount); + + /* ID CHECK */ + if(s_header.id != r_header.id){ + dns_log(thread_obj, 1, "ID is different! (%04x != %04x)", s_header.id, r_header.id); + thread_add_read(thread_obj->master, dns_recv_thread, chk, thread_obj->u.fd, dns->timeout); + return(0); + } + + /* QR CHECK */ + if(!DNS_QR(r_header.flags)){ + dns_log(thread_obj, 1, "dns query receive?"); + thread_add_read(thread_obj->master, dns_recv_thread, chk, thread_obj->u.fd, dns->timeout); + return(0); + } + + /* success */ + dns_final(thread_obj,0); + return 0; +} + +int +dns_send_query(thread *thread_obj) +{ + size_t w; + struct sockaddr_in addr; + checker *chk = THREAD_ARG(thread_obj); + dns_checker *dns = CHECKER_ARG(chk); + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = CHECKER_RIP(chk); + addr.sin_port = dns->port; + + dns_log(thread_obj, 7, "send_request"); + if(thread_obj->type == THREAD_WRITE_TIMEOUT){ + dns_log(thread_obj, 0, "write timeout"); + dns_final(thread_obj,1); + return(0); + } + + w = sendto(thread_obj->u.fd, dns->read, dns->size, MSG_DONTWAIT, (struct sockaddr *)&addr, sizeof(addr)); + if(w == -1 && (errno == EAGAIN || errno == EINTR)) { + thread_add_write(thread_obj->master, dns_send_query, chk, thread_obj->u.fd, dns->timeout); + return(0); + } + + if(w <= 0){ + /*----- error -----*/ + dns_log(thread_obj, 0,"socket write error!"); + dns_final(thread_obj,1); + return(0); + } + + if(w == dns->size){ + dns->read = dns->recv; + dns->size = sizeof(dns->recv); + thread_add_read(thread_obj->master, dns_recv_thread, chk, thread_obj->u.fd, dns->timeout); + }else{ + dns->read += w; + dns->size -= w; + thread_add_write(thread_obj->master, dns_send_query, chk, thread_obj->u.fd, dns->timeout); + } + + return(0); +} + +int dns_make_query(thread *thread_obj) +{ + int i,s; + char buff[256]; + char *n = buff; + checker *chk = THREAD_ARG(thread_obj); + dns_checker *dns = CHECKER_ARG(chk); + uint8_t *p = dns->send; + + uint16_t id = random(); + uint16_t flags = 0; + uint16_t flag_qr = 0; + uint16_t flag_op = 0; + uint16_t flag_aa = 0; + uint16_t flag_tc = 0; + uint16_t flag_rd = 1; + uint16_t flag_ra = 0; + uint16_t flag_z = 0; + uint16_t flag_rc = 0; + uint16_t qdcount = 1; + uint16_t ancount = 0; + uint16_t nscount = 0; + uint16_t arcount = 0; + uint16_t rr_type = 1; /* A */ + uint16_t rr_class = 1; /* IN */ + + if(dns->type){ + for(i=0;RRTYPE[i];i++){ + if(!strcasecmp(dns->type,RRTYPE[i])){ + rr_type=i+1; + break; + } + } + } + + /*----- ID -----*/ + *(p++) = ((id >> 8) & 0xff); + *(p++) = ((id >> 0) & 0xff); + + /*----- FLAG -----*/ + flags |= ((flag_qr & 0x0001) << 15); + flags |= ((flag_op & 0x000F) << 11); + flags |= ((flag_aa & 0x0001) << 10); + flags |= ((flag_tc & 0x0001) << 9); + flags |= ((flag_rd & 0x0001) << 8); + flags |= ((flag_ra & 0x0001) << 7); + flags |= ((flag_z & 0x0007) << 4); + flags |= ((flag_rc & 0x000f) << 0); + *(p++) = ((flags >> 8) & 0xff); + *(p++) = ((flags >> 0) & 0xff); + + /*----- COUNT -----*/ + *(p++) = ((qdcount >> 8) & 0xff); + *(p++) = ((qdcount >> 0) & 0xff); + *(p++) = ((ancount >> 8) & 0xff); + *(p++) = ((ancount >> 0) & 0xff); + *(p++) = ((nscount >> 8) & 0xff); + *(p++) = ((nscount >> 0) & 0xff); + *(p++) = ((arcount >> 8) & 0xff); + *(p++) = ((arcount >> 0) & 0xff); + + /*----- RR(Name) -----*/ + strcpy(n, dns->name); + for(n=strtok(n,".");n;n=strtok(NULL,".")){ + s = strlen(n); + *(p++) = s; + memcpy(p,n,s); + p += s; + } + *(p++)=0; + + /*----- RR(Type) -----*/ + *(p++) = ((rr_type >> 8) & 0xff); + *(p++) = ((rr_type >> 0) & 0xff); + + /*----- RR(Class) -----*/ + *(p++) = ((rr_class >> 8) & 0xff); + *(p++) = ((rr_class >> 0) & 0xff); + + dns->size = p - dns->send; + dns->read = dns -> send; + return(0); +} + +int +dns_send_thread(thread *thread_obj) +{ + int fd; + checker *chk = THREAD_ARG(thread_obj); + dns_checker *dns = CHECKER_ARG(chk); + + if(!dns->port){ + dns->port = CHECKER_RPORT(chk); + } + if(!CHECKER_ENABLED(chk)){ + thread_add_timer(thread_obj->master, dns_send_thread, chk, chk->vs->delay_loop); + return 0; + } + dns_log(thread_obj, 7, "send_thread"); + if((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + dns_log(thread_obj, 0, "can't create socket"); + return 0; + } + dns_make_query(thread_obj); + thread_add_write(thread_obj->master, dns_send_query, chk, fd, dns->timeout); + return 0; +} + +void +dns_free(void *data) +{ + dns_checker *dns = CHECKER_DATA(data); + FREE(dns); + FREE(data); +} + +void +dns_check_handler(vector strvec) +{ + dns_checker *dns = (dns_checker *)MALLOC(sizeof(dns_checker)); + if(!dns){ + syslog(LOG_INFO, "DNS_CHECK: out of memory!"); + fprintf(stderr, "DNS_CHECK: out of memory!\n"); + }else{ + dns->port = htons(53); + dns->retry = 3; + dns->timeout = 5 * TIMER_HZ; + dns->attempts = 0; + dns->type = DNS_DEFAULT_TYPE; + dns->name = DNS_DEFAULT_NAME; + queue_checker(dns_free, dns_dump, dns_send_thread, dns); + } +} + +void +dns_port_handler(vector strvec) +{ + dns_checker *dns = CHECKER_GET(); + dns->port = htons(CHECKER_VALUE_INT(strvec)); +} + +void +dns_timeout_handler(vector strvec) +{ + dns_checker *dns = CHECKER_GET(); + dns->timeout = CHECKER_VALUE_INT(strvec) * TIMER_HZ; +} + +void +dns_retry_handler(vector strvec) +{ + dns_checker *dns = CHECKER_GET(); + dns->retry = CHECKER_VALUE_INT(strvec); +} + +void +dns_type_handler(vector strvec) +{ + dns_checker *dns = CHECKER_GET(); + dns->type = CHECKER_VALUE_STRING(strvec); +} + +void +dns_name_handler(vector strvec) +{ + dns_checker *dns = CHECKER_GET(); + dns->name = CHECKER_VALUE_STRING(strvec); +} + +void +dns_log_level_handler(vector strvec) +{ + dns_checker *dns = CHECKER_GET(); + dns->log_level = CHECKER_VALUE_INT(strvec); +} + +void +install_dns_check_keyword(void) +{ + install_keyword("DNS_CHECK", &dns_check_handler); + install_sublevel(); + install_keyword("port", &dns_port_handler); + install_keyword("timeout", &dns_timeout_handler); + install_keyword("retry", &dns_retry_handler); + install_keyword("type", &dns_type_handler); + install_keyword("name", &dns_name_handler); + install_keyword("log_level", &dns_log_level_handler); + install_sublevel_end(); +} + diff -rNu keepalived-1.1.13/keepalived/check/check_ftp.c keepalived-1.1.13-extcheck/keepalived/check/check_ftp.c --- keepalived-1.1.13/keepalived/check/check_ftp.c 1970-01-01 09:00:00.000000000 +0900 +++ keepalived-1.1.13-extcheck/keepalived/check/check_ftp.c 2007-07-06 17:19:38.000000000 +0900 @@ -0,0 +1,386 @@ +#include "check_ftp.h" +#include "check_api.h" +#include "memory.h" +#include "ipwrapper.h" +#include "utils.h" +#include "parser.h" +#include "daemon.h" +#include "smtp.h" + +int ftp_connect_thread(thread *); + +void +ftp_log(thread *t_obj, int level, const char *format, ...) +{ + checker *chk = THREAD_ARG(t_obj); + ftp_checker *ftp = CHECKER_ARG(chk); + char info[FTP_INFO_MAX]; + va_list varg_list; + if(ftp->log_level >= level){ + va_start(varg_list, format); + vsnprintf(info, FTP_INFO_MAX, format, varg_list); + va_end(varg_list); + syslog(LOG_INFO, "FTP_CHECK[%s:%d] %s", inet_ntop2(CHECKER_RIP(chk)), ntohs(ftp->port), info); + } +} + +void +ftp_clear_buff(thread *t_obj) +{ + checker *chk = THREAD_ARG(t_obj); + ftp_checker *ftp = CHECKER_ARG(chk); + memset(ftp->buff, 0, FTP_BUFF_MAX); + ftp->buff_ctr = 0; +} + +int +ftp_final(thread *t_obj, int error) +{ + checker *chk = THREAD_ARG(t_obj); + ftp_checker *ftp = CHECKER_ARG(chk); + + int timeout = chk->vs->delay_loop; + close(t_obj->u.fd); + if(error){ + if(ftp->attempts < ftp->retry){ + ftp->attempts++; + timeout=ftp->db_retry; + }else{ + if(svr_checker_up(chk->id, chk->rs)){ + smtp_alert(chk->rs, NULL, NULL, "DOWN", "=> FTP CHECK failed on service <="); + update_svr_checker_state(DOWN, chk->id, chk->vs, chk->rs); + } + } + }else{ + ftp->attempts = 0; + if(!svr_checker_up(chk->id, chk->rs)){ + smtp_alert(chk->rs, NULL, NULL, "UP", "=> FTP CHECK succeed on service <="); + update_svr_checker_state(UP, chk->id, chk->vs, chk->rs); + } + } + thread_add_timer(t_obj->master, ftp_connect_thread, chk, timeout); + return 0; +} + +int +ftp_get_line_cb(thread *t_obj) +{ + checker *chk = THREAD_ARG(t_obj); + ftp_checker *ftp = CHECKER_ARG(chk); + int i, f, r; + + if(t_obj->type == THREAD_READ_TIMEOUT){ + ftp_log(t_obj, 3, "Read timeout from server"); + ftp_final(t_obj, 1); + return 0; + } + + f = fcntl(t_obj->u.fd, F_GETFL, 0); + fcntl(t_obj->u.fd, F_SETFL, f | O_NONBLOCK); + r = read(t_obj->u.fd, ftp->buff + ftp->buff_ctr, FTP_BUFF_MAX - ftp->buff_ctr); + fcntl(t_obj->u.fd, F_SETFL, f); + + if(r == -1 && (errno == EAGAIN || errno == EINTR)){ + thread_add_read(t_obj->master, ftp_get_line_cb, chk, t_obj->u.fd, ftp->timeout); + return 0; + } + + if(r <= 0){ + ftp_log(t_obj, 3, "Read failure"); + ftp_final(t_obj, 1); + return 0; + } + + for(i=0;ibuff_ctr){ + ftp_log(t_obj, 0, "ftp buffer over fllow"); + ftp_final(t_obj, 1); + return(0); + } + if(ftp->buff[ftp->buff_ctr] == '\n'){ + ftp->buff[ftp->buff_ctr] = '\0'; + (ftp->buff_cb)(t_obj); + return 0; + } + (ftp->buff_ctr)++; + } + thread_add_read(t_obj->master, ftp_get_line_cb, chk, t_obj->u.fd, ftp->timeout); + return 0; +} + +void +ftp_get_line(thread *t_obj, int (*callback) (struct _thread *)) +{ + checker *chk = THREAD_ARG(t_obj); + ftp_checker *ftp = CHECKER_ARG(chk); + + ftp_clear_buff(t_obj); + ftp->buff_cb = callback; + thread_add_read(t_obj->master, ftp_get_line_cb, chk, t_obj->u.fd, ftp->timeout); + return; +} + +int +ftp_put_line_cb(thread *t_obj) +{ + checker *chk = THREAD_ARG(t_obj); + ftp_checker *ftp = CHECKER_ARG(chk); + int f, w; + + if(t_obj->type == THREAD_WRITE_TIMEOUT) { + ftp_log(t_obj, 3, "Write timeout"); + ftp_final(t_obj, 1); + return 0; + } + + f = fcntl(t_obj->u.fd, F_GETFL, 0); + fcntl(t_obj->u.fd, F_SETFL, f | O_NONBLOCK); + w = write(t_obj->u.fd, ftp->buff, ftp->buff_ctr); + fcntl(t_obj->u.fd, F_SETFL, f); + + if(w == -1 && (errno == EAGAIN || errno == EINTR)) { + thread_add_write(t_obj->master, ftp_put_line_cb, chk, t_obj->u.fd, ftp->timeout); + return 0; + } + + if(w <= 0) { + ftp_log(t_obj, 3, "Write failure"); + ftp_final(t_obj, 1); + return 0; + } + + if(ftp->buff_ctr -= w){ + thread_add_write(t_obj->master, ftp_put_line_cb, chk, t_obj->u.fd, ftp->timeout); + }else{ + (ftp->buff_cb)(t_obj); + } + return 0; +} + +void +ftp_put_line(thread *t_obj, int (*callback)(struct _thread *)) +{ + checker *chk = THREAD_ARG(t_obj); + ftp_checker *ftp = CHECKER_ARG(chk); + + ftp->buff[FTP_BUFF_MAX - 1] = '\0'; + ftp->buff_ctr = strlen(ftp->buff); + ftp->buff_cb = callback; + thread_add_write(t_obj->master, ftp_put_line_cb, chk, t_obj->u.fd, ftp->timeout); + return; +} + +int +ftp_get_status(thread *t_obj) +{ + checker *chk = THREAD_ARG(t_obj); + ftp_checker *ftp = CHECKER_ARG(chk); + char *buff = ftp->buff; + if(isdigit(buff[0]) && isdigit(buff[1]) && isdigit(buff[2])){ + buff[3] = '\0'; + return atoi(buff); + } + return(-1); +} + +int +ftp_engine_thread(thread *t_obj) +{ + checker *chk = THREAD_ARG(t_obj); + ftp_checker *ftp = CHECKER_ARG(chk); + + switch (ftp->state) { + case FTP_START: + ftp->state = FTP_HAVE_BANNER; + ftp_get_line(t_obj, ftp_engine_thread); + return 0; + break; + + case FTP_HAVE_BANNER: + if(ftp_get_status(t_obj) != 220) { + ftp_log(t_obj, 0, "Bad greeting banner"); + ftp_final(t_obj, 1); + return 0; + } + ftp->state = FTP_SENT_NOOP; + snprintf(ftp->buff, FTP_BUFF_MAX, "NOOP\r\n"); + ftp_put_line(t_obj, ftp_engine_thread); + return 0; + break; + + case FTP_SENT_NOOP: + ftp->state = FTP_RECV_NOOP; + ftp_get_line(t_obj, ftp_engine_thread); + return 0; + break; + + case FTP_RECV_NOOP: + if (ftp_get_status(t_obj) != 200) { + ftp_log(t_obj, 0, "Bad NOOP response"); + ftp_final(t_obj, 1); + return 0; + } + ftp->state = FTP_SENT_QUIT; + snprintf(ftp->buff, FTP_BUFF_MAX, "QUIT\r\n"); + ftp_put_line(t_obj, ftp_engine_thread); + return 0; + break; + + case FTP_SENT_QUIT: + ftp->state = FTP_RECV_QUIT; + ftp_get_line(t_obj, ftp_engine_thread); + return 0; + break; + + case FTP_RECV_QUIT: + ftp_final(t_obj, 0); + return 0; + break; + } + ftp_log(t_obj, 0, "unknown state=%d", ftp->state); + ftp_final(t_obj, 1); + return 0; +} + +int +ftp_check_thread(thread *t_obj) +{ + checker *chk = THREAD_ARG(t_obj); + ftp_checker *ftp = CHECKER_ARG(chk); + int status; + + status = tcp_socket_state(t_obj->u.fd, t_obj, CHECKER_RIP(chk), ftp->port, ftp_check_thread); + switch (status) { + case connect_error: + ftp_log(t_obj, 3, "Error connecting"); + ftp_final(t_obj, 1); + return 0; + break; + + case connect_timeout: + ftp_log(t_obj, 3, "Connection timeout"); + ftp_final(t_obj, 1); + return 0; + break; + + case connect_success: + ftp->state = FTP_START; + ftp_engine_thread(t_obj); + return 0; + break; + } + ftp_log(t_obj, 0, "Unknown connection error"); + ftp_final(t_obj, 1); + return 0; +} + +int +ftp_connect_thread(thread *t_obj) +{ + int fd; + checker *chk = THREAD_ARG(t_obj); + ftp_checker *ftp = CHECKER_ARG(chk); + enum connect_result status; + + if(!CHECKER_ENABLED(chk)) { + thread_add_timer(t_obj->master, ftp_connect_thread, chk, chk->vs->delay_loop); + return 0; + } + if((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { + ftp_log(t_obj, 0, "can't create socket"); + thread_add_timer(t_obj->master, ftp_connect_thread, chk, chk->vs->delay_loop); + return 0; + } + status = tcp_bind_connect(fd, CHECKER_RIP(chk), ftp->port, ftp->bindto); + tcp_connection_state(fd, status, t_obj, ftp_check_thread, ftp->timeout); + return 0; +} + +void +ftp_port_handler(vector strvec) +{ + ftp_checker *ftp = CHECKER_GET(); + ftp->port = htons(CHECKER_VALUE_INT(strvec)); +} + +void +ftp_timeout_handler(vector strvec) +{ + ftp_checker *ftp = CHECKER_GET(); + ftp->timeout = CHECKER_VALUE_INT(strvec) * TIMER_HZ; +} + +void +ftp_retry_handler(vector strvec) +{ + ftp_checker *ftp = CHECKER_GET(); + ftp->retry = CHECKER_VALUE_INT(strvec); +} + +void +ftp_db_retry_handler(vector strvec) +{ + ftp_checker *ftp = CHECKER_GET(); + ftp->db_retry = CHECKER_VALUE_INT(strvec) * TIMER_HZ; +} + +void +ftp_bindto_handler(vector strvec) +{ + ftp_checker *ftp = CHECKER_GET(); + inet_ston(VECTOR_SLOT(strvec, 1), &ftp->bindto); +} + +void +ftp_log_level_handler(vector strvec) +{ + ftp_checker *ftp = CHECKER_GET(); + ftp->log_level = CHECKER_VALUE_INT(strvec); +} + +void +free_ftp_check(void *data) +{ + ftp_checker *ftp = CHECKER_DATA(data); + FREE(ftp); + FREE(data); +} + +void +dump_ftp_check(void *data) +{ + ftp_checker *ftp = CHECKER_DATA(data); + syslog(LOG_INFO, " Keepalive method = FTP_CHECK"); + syslog(LOG_INFO, " timeout = %ld", ftp->timeout/TIMER_HZ); + syslog(LOG_INFO, " retry = %d", ftp->retry); + syslog(LOG_INFO, " delay before retry = %ld", ftp->db_retry/TIMER_HZ); +} + +void +ftp_check_handler(vector strvec) +{ + ftp_checker *ftp = (ftp_checker *)MALLOC(sizeof(ftp_checker)); + ftp->port = htons(21); + ftp->bindto = 0; + ftp->timeout = 5 * TIMER_HZ; + ftp->db_retry = 3 * TIMER_HZ; + ftp->retry = 3; + ftp->attempts = 0; + ftp->log_level = 0; + queue_checker(free_ftp_check, dump_ftp_check, ftp_connect_thread ,ftp); +} + +void +install_ftp_check_keyword(void) +{ + install_keyword("FTP_CHECK", &ftp_check_handler); + install_sublevel(); + install_keyword("connect_port", &ftp_port_handler); + install_keyword("bindto", &ftp_bindto_handler); + install_keyword("connect_timeout", &ftp_timeout_handler); + install_keyword("delay_before_retry", &ftp_db_retry_handler); + install_keyword("retry", &ftp_retry_handler); + install_keyword("log_level", &ftp_log_level_handler); + install_sublevel_end(); +} + diff -rNu keepalived-1.1.13/keepalived/check/check_ssl_hello.c keepalived-1.1.13-extcheck/keepalived/check/check_ssl_hello.c --- keepalived-1.1.13/keepalived/check/check_ssl_hello.c 1970-01-01 09:00:00.000000000 +0900 +++ keepalived-1.1.13-extcheck/keepalived/check/check_ssl_hello.c 2007-07-11 21:34:14.000000000 +0900 @@ -0,0 +1,730 @@ +#include +#include +#include "check_ssl_hello.h" +#include "scheduler.h" +#include "check_api.h" +#include "memory.h" +#include "ipwrapper.h" +#include "layer4.h" +#include "utils.h" +#include "parser.h" +#include "smtp.h" + +int ssl_hello_engine_thread(thread *); +int ssl_hello_check_thread(thread *); +int ssl_hello_connect_thread(thread *); + +void +ssl_hello_log(thread *thread_obj, int level, const char *format, ...) +{ + checker *chk = THREAD_ARG(thread_obj); + ssl_hello_checker *ssl = CHECKER_ARG(chk); + char buff[1024]; + va_list varg_list; + if(ssl->log_level >= level){ + va_start(varg_list, format); + vsnprintf(buff, 1024, format, varg_list); + va_end(varg_list); + syslog(LOG_INFO,"SSL_HELLO[%s:%d] %s",inet_ntop2(CHECKER_RIP(chk)), ntohs(ssl->port),buff); + } +} + +int +ssl_hello_asn1_get_length(uint8_t *b, int *o) +{ + int len, i; + if(!(b[*o] & 0x80)){ + len = b[(*o)++]; + } + else{ + int length_bytes = b[(*o)++]&0x7f; + len = 0; + for(i=0;iType = 0; + record->Size = 0; + record->Read = NULL; + record->Data = NULL; + } + return(record); +} + +void +ssl_hello_clear_record(ssl_hello_record *record) +{ + if(record){ + if(record->Data){ + FREE(record->Data); + } + memset(record, 0, sizeof(ssl_hello_record)); + } +} + +void +ssl_hello_free_record(ssl_hello_record *record) +{ + ssl_hello_clear_record(record); + FREE(record); +} + +int +ssl_hello_final(thread *thread_obj, int error) +{ + checker *chk = THREAD_ARG(thread_obj); + ssl_hello_checker *ssl = CHECKER_ARG(chk); + + close(thread_obj->u.fd); + ssl_hello_clear_record(ssl->send_record); + ssl_hello_clear_record(ssl->recv_record); + ssl_hello_log(thread_obj, 7, "final error=%d check=%d attempts=%d", error, ssl->check_flag, ssl->attempts); + if(error || !ssl->check_flag){ + if(svr_checker_up(chk->id, chk->rs)){ + if(ssl->attempts < ssl->retry) { + ssl->attempts++; + thread_add_timer(thread_obj->master, ssl_hello_connect_thread, chk, ssl->db_retry); + return 0; + } + smtp_alert(chk->rs, NULL, NULL, "UP", "=> SSL HELLO succeed on service <="); + update_svr_checker_state(DOWN, chk->id, chk->vs, chk->rs); + } + }else{ + if(!svr_checker_up(chk->id, chk->rs)){ + smtp_alert(chk->rs, NULL, NULL, "DOWN", "=> SSL HELLO failed on service <="); + update_svr_checker_state(UP, chk->id, chk->vs, chk->rs); + } + } + ssl->attempts = 0; + ssl->check_flag = 0; + thread_add_timer(thread_obj->master, ssl_hello_connect_thread, chk, chk->vs->delay_loop); + return(0); +} + +int +ssl_hello_get_handshake(ssl_hello_record *r, ssl_hello_handshake *h){ + if(r->Read >= r->Data + r->Size) return(0); + h->Type = *(r->Read); + r->Read++; + if(r->Read >= r->Data + r->Size) return(-1); + h->Size = *(r->Read) * 65536; + r->Read++; + if(r->Read >= r->Data + r->Size) return(-2); + h->Size += *(r->Read) * 256; + r->Read++; + if(r->Read >= r->Data + r->Size) return(-3); + h->Size += *(r->Read); + r->Read++; + if(!h->Size){ + h->Data = NULL; + }else{ + h->Data = r->Read; + r->Read += h->Size; + if(r->Read > r->Data + r->Size) return(-4); + } + return(1); +} + +void +ssl_hello_dump(void *data) +{ + ssl_hello_checker *ssl = CHECKER_DATA(data); + syslog(LOG_INFO, " Connection port = %d", ntohs(ssl->port)); + syslog(LOG_INFO, " Connection timeout = %d", ssl->timeout/TIMER_HZ); + syslog(LOG_INFO, " Retry = %d", ssl->retry); + syslog(LOG_INFO, " delay_before_retry = %d", ssl->db_retry); + if(ssl->common_name){ + syslog(LOG_INFO, " common_name = %s", ssl->common_name); + } +} + +int +ssl_hello_send_thread(thread *thread_obj) +{ + int f; + int w; + int l; + checker *chk = THREAD_ARG(thread_obj); + ssl_hello_checker *ssl = CHECKER_ARG(chk); + ssl_hello_record *send_record = ssl->send_record; + + if(thread_obj->type == THREAD_WRITE_TIMEOUT){ + ssl_hello_log(thread_obj, 0, "write timeout"); + ssl_hello_final(thread_obj,1); + return(0); + } + + f = fcntl(thread_obj->u.fd, F_GETFL, 0); + fcntl(thread_obj->u.fd, F_SETFL, f | O_NONBLOCK); + + l = send_record->Size - (send_record->Read - send_record->Data); + w = write(thread_obj->u.fd, send_record->Read, l); + + if(w == -1 && (errno == EAGAIN || errno == EINTR)) { + thread_add_write(thread_obj->master, ssl_hello_send_thread, chk, thread_obj->u.fd, ssl->timeout); + fcntl(thread_obj->u.fd, F_SETFL, f); + return(0); + } + + if(w <= 0){ + /*----- error -----*/ + ssl_hello_log(thread_obj, 0,"socket write error!"); + fcntl(thread_obj->u.fd, F_SETFL, f); + ssl_hello_final(thread_obj,1); + return(0); + } + + ssl->send_record->Read += w; + if(w != l){ + thread_add_write(thread_obj->master, ssl_hello_send_thread, chk, thread_obj->u.fd, ssl->timeout); + fcntl(thread_obj->u.fd, F_SETFL, f); + return(0); + } + + /*----- send complate -----*/ + if(send_record->Type == 0x15){ + fcntl(thread_obj->u.fd, F_SETFL, f); + ssl_hello_final(thread_obj,0); + }else{ + ssl_hello_engine_thread(thread_obj); + fcntl(thread_obj->u.fd, F_SETFL, f); + ssl_hello_clear_record(send_record); + } + + return(0); +} + +int +send_client_hello(thread *thread_obj) +{ + int i; + int len; + checker *chk = THREAD_ARG(thread_obj); + ssl_hello_checker *ssl = CHECKER_ARG(chk); + ssl_hello_record *send_record = ssl->send_record; + + unsigned char *p; + unsigned char *record_len; + unsigned char *handshake_len; + unsigned char *ciphers_len; + unsigned long Time=(unsigned long)time(NULL); + + ssl_hello_log(thread_obj, 7, "send client hello"); + send_record->Type = 0x16; /* SSL_HANDSHAKE */ + send_record->Vers = 0x0300; /* SSLv3 */ + + send_record->Data = MALLOC(512); + send_record->Read = send_record->Data; + p = send_record->Data; + + *(p++) = send_record->Type; + *(p++) = ((send_record->Vers >> 8)&0xff); + *(p++) = ((send_record->Vers )&0xff); + record_len = p; + p += 2; + + *(p++) = 0x01; /* CLIENT_HELLO */ + handshake_len = p; + p += 3; + + /* client version */ + *(p++) = ((send_record->Vers) >> 8 & 0xff); + *(p++) = ((send_record->Vers) & 0xff); + + /* Random */ + *(p++) = (unsigned char)((Time>>24)&0xff); + *(p++) = (unsigned char)((Time>>16)&0xff); + *(p++) = (unsigned char)((Time>> 8)&0xff); + *(p++) = (unsigned char)((Time )&0xff); + p+=28; + + /* Session ID */ + *(p++)=0; + + /* Ciphers */ + ciphers_len = p; + p+=2; + for(i=1;i<28;i++){ + *(p++) = (unsigned char)((i >> 8)&0xff); + *(p++) = (unsigned char)((i )&0xff); + } + len = (p - ciphers_len) - 2; + *(ciphers_len + 0) = (unsigned char)((len >> 8)&0xff); + *(ciphers_len + 1) = (unsigned char)((len )&0xff); + + /* COMPRESSION */ + *(p++)=1; + *(p++)=0; /* Add NULL method */ + + /*----- handshake length -----*/ + len = (p - handshake_len) - 3; + *(handshake_len + 0) = (unsigned char)((len >>16)&0xff); + *(handshake_len + 1) = (unsigned char)((len >> 8)&0xff); + *(handshake_len + 2) = (unsigned char)((len )&0xff); + + /*----- record length -----*/ + len = (p - record_len) - 2; + *(record_len + 0) = (unsigned char)((len >> 8)&0xff); + *(record_len + 1) = (unsigned char)((len )&0xff); + + /*----- DataSize -----*/ + send_record->Size=(p - send_record->Data); + + /*----- Send -----*/ + thread_add_write(thread_obj->master, ssl_hello_send_thread, chk, thread_obj->u.fd, ssl->timeout); + return(0); +} + +int +send_alart(thread *thread_obj) +{ + checker *chk = THREAD_ARG(thread_obj); + ssl_hello_checker *ssl = CHECKER_ARG(chk); + ssl_hello_record *send_record = ssl->send_record; + + ssl_hello_log(thread_obj, 7, "send alart"); + send_record->Type = 0x15; /* SSL_ALART */ + send_record->Vers = 0x0300; /* SSLv3 */ + send_record->Size = 7; + send_record->Data = MALLOC(send_record->Size); + send_record->Read = send_record->Data; + unsigned char *p = send_record->Data; + + *(p++) = send_record->Type; + *(p++) = ((send_record->Vers >> 8)&0xff); + *(p++) = ((send_record->Vers )&0xff); + *(p++) = 0; + *(p++) = 2; + *(p++) = 0x02; /* ALART_TYPE_FATAL */ + *(p++) = 0x28; /* HANDSHAKE_FAILURE */ + + thread_add_write(thread_obj->master, ssl_hello_send_thread, chk, thread_obj->u.fd, ssl->timeout); + return(0); +} + +int +ssl_hello_recv_check(thread *thread_obj) +{ + checker *chk = THREAD_ARG(thread_obj); + ssl_hello_checker *ssl = CHECKER_ARG(chk); + ssl_hello_record *recv_record = ssl->recv_record; + if(!recv_record){ + return(0); + } + if(!recv_record->Size){ + return(0); + } + if(!recv_record->Data || !recv_record->Read){ + return(0); + } + return(recv_record->Read - recv_record->Data == recv_record->Size); +} + +int +ssl_hello_recv_thread(thread *thread_obj) +{ + char d; + int f,r; + int count; + int error; + checker *chk = THREAD_ARG(thread_obj); + ssl_hello_checker *ssl = CHECKER_ARG(chk); + ssl_hello_record *recv_record = ssl->recv_record; + + if(thread_obj->type == THREAD_READ_TIMEOUT){ + ssl_hello_log(thread_obj, 1, "Read Timeout!"); + ssl_hello_final(thread_obj,1); + return(0); + } + + count = (recv_record->Read - recv_record->Data); + f = fcntl(thread_obj->u.fd, F_GETFL, 0); + fcntl(thread_obj->u.fd, F_SETFL, f | O_NONBLOCK); + + if(!recv_record->Data){ + r=read(thread_obj->u.fd,&d,1); + }else{ + r=read(thread_obj->u.fd, recv_record->Read, recv_record->Size - count); + } + error = errno; + fcntl(thread_obj->u.fd, F_SETFL, f); + + if(r == -1 && (error == EAGAIN || error == EINTR)) { + thread_add_read(thread_obj->master, ssl_hello_recv_thread, chk, thread_obj->u.fd, ssl->timeout); + return 0; + } + + if(r <= 0){ + ssl_hello_log(thread_obj, 1, "Read Error!"); + ssl_hello_final(thread_obj,1); + return(0); + } + + ssl_hello_log(thread_obj, 7, "ssl_hello_recv_thread: recv size=%d",r); + recv_record->Read += r; + if(recv_record->Data){ + if(ssl_hello_recv_check(thread_obj)){ + ssl_hello_engine_thread(thread_obj); + return(0); + } + }else{ + switch(count){ + case 0: + recv_record->Type = d; + break; + case 1: + recv_record->Vers = d * 256; + break; + case 2: + recv_record->Vers += d; + break; + case 3: + recv_record->Size = d * 256; + break; + case 4: + recv_record->Size += d; + ssl_hello_log(thread_obj, 7, "ssl_hello_recv_thread: RecordSize=%d", recv_record->Size); + recv_record->Data = MALLOC(recv_record->Size); + recv_record->Read = recv_record->Data; + break; + } + } + thread_add_read(thread_obj->master, ssl_hello_recv_thread, chk, thread_obj->u.fd, ssl->timeout); + return(0); +} + +int +ssl_hello_cn_check(thread *thread_obj, ssl_hello_handshake *handshake, char *common_name) +{ + int r=0; + char *cn; + + if(!common_name){ + r = 1; + }else{ + cn = ssl_hello_get_cn(handshake->Data, handshake->Size); + if(cn){ + r=(strcmp(cn, common_name)==0); + if(r){ + ssl_hello_log(thread_obj, 7, "cn_check OK ('%s'=='%s')", cn, common_name); + }else{ + ssl_hello_log(thread_obj, 7, "cn_check NG ('%s'!='%s')", cn, common_name); + } + FREE(cn); + } + } + return(r); +} + +int +ssl_hello_engine_thread(thread *thread_obj) +{ + int r; + unsigned short oldsize; + checker *chk = THREAD_ARG(thread_obj); + ssl_hello_checker *ssl = CHECKER_ARG(chk); + ssl_hello_handshake handshake; + + if(ssl_hello_recv_check(thread_obj)){ + ssl->recv_record->Read = ssl->recv_record->Data; + while(r=ssl_hello_get_handshake(ssl->recv_record,&handshake)){ + if(r < 0){ + ssl_hello_log(thread_obj, 7, "engine_thread: err=%d htype=%d hsize=%d", r,handshake.Type, handshake.Size); + if(r > -4){ + ssl_hello_final(thread_obj,1); + }else{ + oldsize = ssl->recv_record->Size; + ssl->recv_record->Size = ssl->recv_record->Read - ssl->recv_record->Data; + ssl->recv_record->Read = ssl->recv_record->Data; + ssl->recv_record->Data = MALLOC(ssl->recv_record->Size); + if(ssl->recv_record->Data == NULL){ + ssl_hello_log(thread_obj, 0, "engine_thread: out of memory"); + ssl_hello_final(thread_obj,1); + }else{ + memcpy(ssl->recv_record->Data, ssl->recv_record->Read, oldsize); + FREE(ssl->recv_record->Read); + ssl->recv_record->Read = ssl->recv_record->Data + oldsize; + ssl_hello_log(thread_obj, 7, "engine_thread: recv(%d)", ssl->recv_record->Size - (ssl->recv_record->Read - ssl->recv_record->Data)); + thread_add_read(thread_obj->master, ssl_hello_recv_thread, chk, thread_obj->u.fd, ssl->timeout); + } + } + return(0); + }else{ + switch(handshake.Type){ + case 0x02: /* SERVER_HELLO */ + ssl_hello_log(thread_obj, 7, "engine_thread HandshakeType = SERVER_HELLO"); + break; + case 0x0b: /* SERVER_CERTIFICATE */ + ssl_hello_log(thread_obj, 7, "engine_thread HandshakeType = SERVER_CERTIFICATE"); + ssl->check_flag = ssl_hello_cn_check(thread_obj, &handshake, ssl->common_name); + break; + case 0x0d: /* CERTIFICATE_REQUEST */ + ssl_hello_log(thread_obj, 7, "engine_thread HandshakeType = CERTIFICATE_REQUEST"); + break; + case 0x0e: /* SERVER_HELLO_DONE */ + ssl_hello_log(thread_obj, 7, "engine_thread HandshakeType = SERVER_HELLO_DONE"); + send_alart(thread_obj); + return(0); + default: + ssl_hello_log(thread_obj, 7, "engine_thread HandshakeType = 0x%02x",handshake.Type); + break; + } + } + } + } + ssl_hello_clear_record(ssl->recv_record); + thread_add_read(thread_obj->master, ssl_hello_recv_thread, chk, thread_obj->u.fd, ssl->timeout); + return(0); +} + +int +ssl_hello_check_thread(thread *thread_obj) +{ + int status; + checker *chk = THREAD_ARG(thread_obj); + ssl_hello_checker *ssl = CHECKER_ARG(chk); + + ssl_hello_log(thread_obj, 7, "check_thread"); + status = tcp_socket_state(thread_obj->u.fd, thread_obj, CHECKER_RIP(chk), ssl->port, ssl_hello_check_thread); + if(status==connect_success){ + send_client_hello(thread_obj); + }else{ + ssl_hello_log(thread_obj, 1, "Connect Error!!"); + ssl_hello_final(thread_obj,1); + } + return 0; +} + +int +ssl_hello_connect_thread(thread *thread_obj) +{ + int fd; + int status; + checker *chk = THREAD_ARG(thread_obj); + ssl_hello_checker *ssl = CHECKER_ARG(chk); + + if(!ssl->port){ + ssl->port = CHECKER_RPORT(chk); + } + + if(!CHECKER_ENABLED(chk)){ + thread_add_timer(thread_obj->master, ssl_hello_connect_thread, chk, chk->vs->delay_loop); + return 0; + } + + ssl_hello_log(thread_obj, 7, "connect_thread"); + if((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { + ssl_hello_log(thread_obj, 0, "can't create socket"); + return 0; + } + status = tcp_connect(fd, CHECKER_RIP(chk), ssl->port); + tcp_connection_state(fd, status, thread_obj, ssl_hello_check_thread, ssl->timeout); + return 0; +} + +void +ssl_hello_free(void *data) +{ + ssl_hello_checker *ssl = CHECKER_DATA(data); + ssl_hello_free_record(ssl->send_record); + ssl_hello_free_record(ssl->recv_record); + FREE(ssl); + FREE(data); +} + +void +ssl_hello_check_handler(vector strvec) +{ + ssl_hello_checker *ssl = (ssl_hello_checker *)MALLOC(sizeof(ssl_hello_checker)); + if(!ssl){ + syslog(LOG_INFO, "SSL_HELLO: out of memory!"); + fprintf(stderr, "SSL_HELLO: out of memory!\n"); + }else{ + ssl->port = htons(443); + ssl->retry = 3; + ssl->timeout = 5 * TIMER_HZ; + ssl->db_retry = 3 * TIMER_HZ; + ssl->attempts = 0; + ssl->log_level = 0; + ssl->common_name = NULL; + ssl->send_record = ssl_hello_create_record(); + ssl->recv_record = ssl_hello_create_record(); + queue_checker(ssl_hello_free, ssl_hello_dump, ssl_hello_connect_thread, ssl); + } +} + +void +ssl_hello_port_handler(vector strvec) +{ + ssl_hello_checker *ssl = CHECKER_GET(); + ssl->port = htons(CHECKER_VALUE_INT(strvec)); +} + +void +ssl_hello_timeout_handler(vector strvec) +{ + ssl_hello_checker *ssl = CHECKER_GET(); + ssl->timeout = CHECKER_VALUE_INT(strvec) * TIMER_HZ; +} + +void +ssl_hello_retry_handler(vector strvec) +{ + ssl_hello_checker *ssl = CHECKER_GET(); + ssl->retry = CHECKER_VALUE_INT(strvec); +} + +void +ssl_hello_db_retry_handler(vector strvec) +{ + ssl_hello_checker *ssl = CHECKER_GET(); + ssl->db_retry = CHECKER_VALUE_INT(strvec) * TIMER_HZ; +} + +void +ssl_hello_common_name_handler(vector strvec) +{ + ssl_hello_checker *ssl = CHECKER_GET(); + ssl->common_name = CHECKER_VALUE_STRING(strvec); +} + +void +ssl_hello_log_level_handler(vector strvec) +{ + ssl_hello_checker *ssl = CHECKER_GET(); + ssl->log_level = CHECKER_VALUE_INT(strvec); +} + +void +install_ssl_hello_keyword(void) +{ + install_keyword("SSL_HELLO", &ssl_hello_check_handler); + install_sublevel(); + install_keyword("connect_port", &ssl_hello_port_handler); + install_keyword("connect_timeout", &ssl_hello_timeout_handler); + install_keyword("common_name", &ssl_hello_common_name_handler); + install_keyword("retry", &ssl_hello_retry_handler); + install_keyword("delay_before_retry", &ssl_hello_db_retry_handler); + install_keyword("log_level", &ssl_hello_log_level_handler); + install_sublevel_end(); +} + diff -rNu keepalived-1.1.13/keepalived/include/check_dns.h keepalived-1.1.13-extcheck/keepalived/include/check_dns.h --- keepalived-1.1.13/keepalived/include/check_dns.h 1970-01-01 09:00:00.000000000 +0900 +++ keepalived-1.1.13-extcheck/keepalived/include/check_dns.h 2007-07-06 17:19:38.000000000 +0900 @@ -0,0 +1,40 @@ +#ifndef _CHECK_DNS_CHECK_H +#define _CHECK_DNS_CHECK_H + +#define DNS_DEFAULT_TYPE "" +#define DNS_DEFAULT_NAME "" +#define DNS_BUFFER_SIZE 768 +#define DNS_QR(flags) ((flags >> 15) & 0x0001) +#define DNS_OP(flags) ((flags >> 11) & 0x000F) +#define DNS_AA(flags) ((flags >> 10) & 0x0001) +#define DNS_TC(flags) ((flags >> 9) & 0x0001) +#define DNS_RD(flags) ((flags >> 8) & 0x0001) +#define DNS_RA(flags) ((flags >> 7) & 0x0001) +#define DNS_Z(flags) ((flags >> 4) & 0x0007) +#define DNS_RC(flags) ((flags >> 0) & 0x000F) + +typedef struct _dns_header { + uint16_t id; + uint16_t flags; + uint16_t qdcount; + uint16_t ancount; + uint16_t nscount; + uint16_t arcount; +} dns_header; + +typedef struct _dns_checker { + uint16_t port; + int timeout; + int retry; + int log_level; + int attempts; + char *type; + char *name; + size_t size; + uint8_t *read; + uint8_t send[DNS_BUFFER_SIZE]; + uint8_t recv[DNS_BUFFER_SIZE]; +} dns_checker; + +extern void install_dns_check_keyword(void); +#endif diff -rNu keepalived-1.1.13/keepalived/include/check_ftp.h keepalived-1.1.13-extcheck/keepalived/include/check_ftp.h --- keepalived-1.1.13/keepalived/include/check_ftp.h 1970-01-01 09:00:00.000000000 +0900 +++ keepalived-1.1.13-extcheck/keepalived/include/check_ftp.h 2007-07-06 17:19:38.000000000 +0900 @@ -0,0 +1,32 @@ +#ifndef _CHECK_FTP_H +#define _CHECK_FTP_H +#include "check_data.h" +#include "scheduler.h" + +#define FTP_START 1 +#define FTP_HAVE_BANNER 2 +#define FTP_SENT_NOOP 3 +#define FTP_RECV_NOOP 4 +#define FTP_SENT_QUIT 5 +#define FTP_RECV_QUIT 6 +#define FTP_DEFAULT_PORT 21 +#define FTP_BUFF_MAX 512 +#define FTP_INFO_MAX 512 + +typedef struct _ftp_checker { + uint16_t port; + uint32_t bindto; + long timeout; + long db_retry; + int retry; + int attempts; + char buff[FTP_BUFF_MAX]; + int buff_ctr; + int (*buff_cb)(struct _thread *); + int state; + int log_level; +} ftp_checker; + +extern void install_ftp_check_keyword(void); + +#endif diff -rNu keepalived-1.1.13/keepalived/include/check_ssl_hello.h keepalived-1.1.13-extcheck/keepalived/include/check_ssl_hello.h --- keepalived-1.1.13/keepalived/include/check_ssl_hello.h 1970-01-01 09:00:00.000000000 +0900 +++ keepalived-1.1.13-extcheck/keepalived/include/check_ssl_hello.h 2007-07-06 17:19:38.000000000 +0900 @@ -0,0 +1,33 @@ +#ifndef _CHECK_SSL_HELLO_H +#define _CHECK_SSL_HELLO_H + +typedef struct _ssl_hello_record { + unsigned char Type; + unsigned short Vers; + unsigned short Size; + unsigned char *Read; + unsigned char *Data; +} ssl_hello_record; + +typedef struct _ssl_hello_handshake { + unsigned char Type; + unsigned short Size; + unsigned char *Data; +} ssl_hello_handshake; + +typedef struct _ssl_hello_checker { + uint16_t port; + int timeout; + int retry; + int db_retry; + int log_level; + int attempts; + int check_flag; + char *common_name; + ssl_hello_record *send_record; + ssl_hello_record *recv_record; +} ssl_hello_checker; + +extern void install_ssl_hello_keyword(void); + +#endif