buffer overflow over script path must be handled.
* Added VRRP support using our scheduling I/O multiplexer.
VRRP implementation support to IPSEC-AH using HMAC-96bits digest
with anti-replay. rfc2402 & rfc2104.
* Added routing table fetcher. We ignore route when it is a
cloned route from other router, learn by an ICMP redirect
or set by kernel. Only UNICAST route are stored.
* Added dropping packet support.
+++ /dev/null
-Eric Jarman <ehj38230@cmsu2.cmsu.edu>
-2001-11-04 Alexandre Cassen <acassen@linux-vs.org>
-
- * keepalived-0.3.8 released.
- * Added support to native IPTABLE LVS CODE
- => using NAT on 2.4 kernel ipchains kernel support
- has been removed.
- * Added support to Direct Routing & Tunneling.
- * Review the keepalived.init script to be much more generic.
-
-2001-09-14 Alexandre Cassen <acassen@linux-vs.org>
-
- * keepalived-0.3.7 released.
- * Added support to LVS kernel 2.4 code
-
2001-08-23 Alexandre Cassen <acassen@linux-vs.org>
* keepalived-0.3.6 released.
* Eric Jarman, <ehj38230@cmsu2.cmsu.edu> added MISC CHECKER.
It Perform a system call to run an extra system or script.
=> security auditing needed for system call,
- buffer overflow over script path must be handled.
+ buffer overflow over script path must be handled.
+
+ * Added VRRP support using our scheduling I/O multiplexer.
+ VRRP implementation support to IPSEC-AH using HMAC-96bits digest
+ with anti-replay. rfc2402 & rfc2104.
+ * Added routing table fetcher. We ignore route when it is a
+ cloned route from other router, learn by an ICMP redirect
+ or set by kernel. Only UNICAST route are stored.
+ * Added dropping packet support.
+
2001-07-15 Alexandre Cassen <acassen@linux-vs.org>
* Added a daemonization function imported from zebra.
* Rewrite the pidfile handling, check if daemon is running, if not
remove eventual stalled pidfile and create new pidfile.
+
* Added a strong scheduling framework based on an I/O multiplexer
to handle asynchronous process. This code is imported from zebra
and have been enhanced for keepalived purposes.
=> With this framework keepalived use a Boss/Worker thread model design,
fetching ready thread from a master threading queues.
+
* Rewrite the configuration file reader to add flexibility on extending.
The dynamic data structure has been rewritten to use apropriate types.
Right now parsing framework is ready for easy new checker structures
integration.
+
* Rewrite the smtp connector. The implementation take advantage of the
I/O multiplexer. All read/write operations from/to the remote smtp server
are done asynchronously. The implementation is rfc 821 compliant (multiple
receiver are handled by a multiple RCPT TO command as specified in rfc821.3.1).
+
* Rewrite the IPFW & IPVS wrappers.
+
* Added support for NAT mask on IP MASQ rules (keyword nat_mask in configuration
file). Added support for sorry server facility, so when all the server from a
VS server pool are removed, a sorry server is automaticaly added to the VS pool
(typically this is used when you have a spare server online).
+
* Rewrite the previous checkers. Checkers are now based on a hierarchic layer
stack framework. The protocol implemented for the moment is TCP. All layer 5
checkers are using layer4.c primitives with the same design :
. a connection checker thread testing connection states (error, in_progress,
timeout, success). When connection success upper level thread are registered
to handle checks.
+
* Delay loop is now checkers specifics since we can use a multithreaded framework.
+
* Update the PDF documentation file.
IP aliasing
Kernel/User netlink socket
- Network firewalls
Routing messages
LinuxVirtualServer
http://keepalived.sourceforge.net
-Have fun with it !
-Alexandre Cassen, <acassen@linux-vs.org>
+Have fun with it !
# Makefile
-# Alexandre Cassen <Alexandre.Cassen@wanadoo.fr>
+# Alexandre Cassen <acassen@linux-vs.org>
EXEC= keepalived
CC= gcc
-KERNEL := KERNEL_2_$(shell uname -r | cut -d'.' -f2)
-
# To compile with debug messages uncomment the following line
-CFLAGS= -g -Wall -DDEBUG -D$(KERNEL)
-#CFLAGS= -g -Wall -D$(KERNEL)
-
-ifeq ($(KERNEL),KERNEL_2_2)
- LIB := $(LIB) libipfwc/libipfwc.a
-endif
+CFLAGS= -g -Wall -D DEBUG
+#CFLAGS= -g -Wall
+DEFS=
-DEFS= main.h \
- scheduler.h \
- cfreader.h \
- layer4.h \
- check_tcp.h \
- check_http.h \
- check_misc.h \
- md5.h \
- smtp.h
+LIB= libipfwc/libipfwc.a \
+ libnetlink/libnetlink.a
+#DEFS= main.h scheduler.h cfreader.h layer4.h check_tcp.h check_http.h md5.h smtp.h
OBJECTS= main.o \
utils.o \
scheduler.o \
layer4.o \
check_tcp.o \
check_http.o \
- check_misc.o \
md5.o \
ipwrapper.o \
- ipvswrapper.o
-ifeq ($(KERNEL),KERNEL_2_2)
- OBJECTS := $(OBJECTS) ipfwwrapper.o
-endif
-OBJECTS := $(OBJECTS) \
+ ipvswrapper.o \
+ ipfwwrapper.o \
pidfile.o \
- smtp.o
+ smtp.o \
+ vrrp.o \
+ vrrp_iproute.o \
+ vrrp_ipaddress.o \
+ vrrp_ipsecah.o
INCLUDE= -I/usr/src/linux/include
$(EXEC): $(OBJECTS) $(DEFS) $(LIB)
$(CC) -o $(EXEC) $(CFLAGS) $(OBJECTS) $(LIB)
-ifeq ($(KERNEL),KERNEL_2_2)
libipfwc/libipfwc.a:
cd libipfwc/ && $(MAKE) libipfwc.a
-endif
+
+libnetlink/libnetlink.a:
+ cd libnetlink/ && $(MAKE) libnetlink.a
subclean:
-ifeq ($(KERNEL),KERNEL_2_2)
cd libipfwc/ && $(MAKE) clean
-endif
+ cd libnetlink/ && $(MAKE) clean
clean: subclean
rm -f core *.o $(EXEC)
--- /dev/null
+* VRRP : handle specific interface multicast binding.
+* Documentation.
+* Insert LDAP, SSL, FTP, SSH, IMAP, POP, RADIUS checkers.
+* Security auditing.
+* Add minimum configuration verification (realserver must have
+ a checker defined, ...)
+* Add system verification (must have LVS support in kernel,
+ must have netlink support in kernel,
+ must have ip alias support in kernel,
+ must have routing messages in kernel).
* data structure representation the conf file representing
* the loadbalanced server pool.
*
- * Version: $Id: cfreader.c,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: cfreader.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
+ * Changes: Alexandre Cassen : 2001/06/25 : Initial release
+ *
* 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.
char *string; /* Temp read buffer */
struct keyword keywords[] = {
- {KW_BEGINFLAG, "{"},
- {KW_ENDFLAG, "}"},
-
- {KW_GLOBALDEFS, "global_defs"},
- {KW_EMAIL, "notification_email"},
- {KW_EMAILFROM, "notification_email_from"},
- {KW_LVSID, "lvs_id"},
- {KW_SMTP, "smtp_server"},
- {KW_STIMEOUT, "smtp_connect_timeout"},
-
- {KW_VS, "virtual_server"},
- {KW_DELAY, "delay_loop"},
- {KW_LBSCHED, "lb_algo"},
- {KW_LBKIND, "lb_kind"},
- {KW_NATMASK, "nat_mask"},
- {KW_PTIMEOUT, "persistence_timeout"},
- {KW_PROTOCOL, "protocol"},
- {KW_SSVR, "sorry_server"},
-
- {KW_SVR, "real_server"},
- {KW_WEIGHT, "weight"},
- {KW_CTIMEOUT, "connect_timeout"},
- {KW_URL, "url"},
- {KW_URLPATH, "path"},
- {KW_DIGEST, "digest"},
- {KW_NBGETRETRY, "nb_get_retry"},
- {KW_DELAYRETRY, "delay_before_retry"},
-
- {KW_ICMPCHECK, "ICMP_CHECK"},
- {KW_TCPCHECK, "TCP_CHECK"},
- {KW_HTTPGET, "HTTP_GET"},
- {KW_SSLGET, "SSL_GET"},
- {KW_LDAPGET, "LDAP_GET"},
-
- {KW_MISCCHECK, "MISC_CHECK"},
- {KW_MISCPATH, "misc_path"},
+ {KW_BEGINFLAG, "{"},
+ {KW_ENDFLAG, "}"},
+
+ {KW_GLOBALDEFS, "global_defs"},
+ {KW_EMAIL, "notification_email"},
+ {KW_EMAILFROM, "notification_email_from"},
+ {KW_LVSID, "lvs_id"},
+ {KW_SMTP, "smtp_server"},
+ {KW_STIMEOUT, "smtp_connect_timeout"},
+
+ {KW_VS, "virtual_server"},
+ {KW_DELAY, "delay_loop"},
+ {KW_LBSCHED, "lb_algo"},
+ {KW_LBKIND, "lb_kind"},
+ {KW_NATMASK, "nat_mask"},
+ {KW_PTIMEOUT, "persistence_timeout"},
+ {KW_PROTOCOL, "protocol"},
+ {KW_SSVR, "sorry_server"},
+
+ {KW_SVR, "real_server"},
+ {KW_WEIGHT, "weight"},
+ {KW_CTIMEOUT, "connect_timeout"},
+ {KW_URL, "url"},
+ {KW_URLPATH, "path"},
+ {KW_DIGEST, "digest"},
+ {KW_NBGETRETRY, "nb_get_retry"},
+ {KW_DELAYRETRY, "delay_before_retry"},
+
+ {KW_ICMPCHECK, "ICMP_CHECK"},
+ {KW_TCPCHECK, "TCP_CHECK"},
+ {KW_HTTPGET, "HTTP_GET"},
+ {KW_SSLGET, "SSL_GET"},
+ {KW_LDAPGET, "LDAP_GET"},
+
+ {KW_VRRP, "vrrp_instance"},
+ {KW_VRRPINT, "interface"},
+ {KW_VRRPVRID, "virtual_router_id"},
+ {KW_VRRPAUTH, "authentication"},
+ {KW_VRRPAUTHTYPE, "auth_type"},
+ {KW_VRRPAUTHAH, "AH"},
+ {KW_VRRPAUTHPWD, "PASS"},
+ {KW_VRRPAUTHPASS, "auth_pass"},
+ {KW_VRRPPRIO, "priority"},
+ {KW_VRRPADVERT, "advert_int"},
+ {KW_VRRPIPADD, "virtual_ipaddress"},
+ {KW_VRRPSYNC, "sync_instance"},
+ {KW_VRRPPREEMPT, "preempt"},
{KW_UNKNOWN, NULL}
};
return 0;
}
+vrrp_instance * add_item_vrrp(vrrp_instance *lstvrrp, vrrp_instance *vrrp)
+{
+ vrrp_instance *pointerlst = lstvrrp;
+
+ if (lstvrrp != NULL) {
+ while(lstvrrp->next != NULL) lstvrrp = (vrrp_instance *)lstvrrp->next;
+ lstvrrp->next = (struct vrrp_instance *)vrrp;
+ return pointerlst;
+ } else {
+ lstvrrp = vrrp;
+ return lstvrrp;
+ }
+}
+
notification_email * add_item_email(notification_email *lstemail,notification_email *email)
{
- notification_email *pointerlst=lstemail;
+ notification_email *pointerlst = lstemail;
if (lstemail != NULL) {
while(lstemail->next != NULL) lstemail = (notification_email *)lstemail->next;
virtualserver * add_item_vs(virtualserver *lstvs,virtualserver *vs)
{
- virtualserver *pointerlst=lstvs;
+ virtualserver *pointerlst = lstvs;
if(already_exist_vs(lstvs, vs->addr_ip.s_addr, vs->addr_port)) return lstvs;
realserver * add_item_svr(realserver *lstsvr,realserver *svr)
{
- realserver *pointerlst=lstsvr;
+ realserver *pointerlst = lstsvr;
if(already_exist_svr(lstsvr, svr->addr_ip.s_addr, svr->addr_port)) return lstsvr;
urls * add_item_url(urls *lsturls,urls *url)
{
- urls *pointerlst=lsturls;
+ urls *pointerlst = lsturls;
if (lsturls != NULL) {
while(lsturls->next != NULL) lsturls = (urls *)lsturls->next;
return t;
}
+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);
+ return t;
+}
+
notification_email * remove_email(notification_email *lstptr)
{
notification_email *t;
while(lstptr->email != NULL)
lstptr->email = remove_email(lstptr->email);
+ while(lstptr->vrrp != NULL)
+ lstptr->vrrp = remove_vrrp(lstptr->vrrp);
+
while(lstptr->lvstopology != NULL)
lstptr->lvstopology = remove_vs(lstptr->lvstopology);
}
+void clear_vrrp_instance(vrrp_instance *lstptr)
+{
+ while (lstptr) {
+ vrrp_state_stop_instance(lstptr->vsrv);
+ lstptr = (vrrp_instance *)lstptr->next;
+ }
+}
+
/* Dynamic data structure dump functions start here */
void dump_httpget(http_get_check *pointerhttpget)
{
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);
- break;
}
pointersvr = (realserver *)pointersvr->next;
ntohs(pointervs->addr_port));
syslog(LOG_DEBUG, " -> delay_loop = %d, lb_algo = %s, "
- "persistence = %s, protocol = %s",
+ "lb_kind = %s, persistence = %s, protocol = %s",
pointervs->delay_loop, pointervs->sched,
+ (pointervs->loadbalancing_kind == 0)?"NAT":"UNKNOWN",
pointervs->timeout_persistence,
(pointervs->service_type == IPPROTO_TCP)?"TCP":"UDP");
- switch (pointervs->loadbalancing_kind) {
-#ifdef KERNEL_2_2
- case 0:
- syslog(LOG_DEBUG, " -> lb_kind = NAT");
- syslog(LOG_DEBUG, " -> nat mask = %s", inet_ntoa(pointervs->nat_mask));
- break;
- case IP_MASQ_F_VS_DROUTE:
- syslog(LOG_DEBUG, " -> lb_kind = DR");
- break;
- case IP_MASQ_F_VS_TUNNEL:
- syslog(LOG_DEBUG, " -> lb_kind = TUN");
- break;
-#else
- case IP_VS_CONN_F_MASQ:
- syslog(LOG_DEBUG, " -> lb_kind = NAT");
- break;
- case IP_VS_CONN_F_DROUTE:
- syslog(LOG_DEBUG, " -> lb_kind = DR");
- break;
- case IP_VS_CONN_F_TUNNEL:
- syslog(LOG_DEBUG, " -> lb_kind = TUN");
- break;
-#endif
- }
+ syslog(LOG_DEBUG, " -> nat mask = %s", inet_ntoa(pointervs->nat_mask));
if (pointervs->s_svr != NULL) {
syslog(LOG_DEBUG, " -> sorry server = [%s:%d]",
}
}
+void dump_vrrp(vrrp_instance *pointervrrp)
+{
+ int i;
+
+ while (pointervrrp != NULL) {
+ syslog(LOG_DEBUG, " VRRP Instance = %s", pointervrrp->iname);
+ syslog(LOG_DEBUG, " 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",
+ pointervrrp->vsrv->adver_int/VRRP_TIMER_HZ);
+ if (pointervrrp->vsrv->preempt)
+ syslog(LOG_DEBUG, " Preempt active");
+ if (pointervrrp->vsrv->vif->auth_type) {
+ syslog(LOG_DEBUG, " 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_DEBUG, " 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)));
+
+ pointervrrp = (vrrp_instance *)pointervrrp->next;
+ }
+}
+
void dump_conf(configuration_data *lstconf)
{
if(lstconf == NULL) {
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);
-
dump_email(lstconf->email);
- syslog(LOG_DEBUG,"------< LVS Topology >------");
- dump_vs(lstconf->lvstopology);
+ if (lstconf->vrrp) {
+ syslog(LOG_DEBUG,"------< VRRP Topology >------");
+ dump_vrrp(lstconf->vrrp);
+ }
+
+ if (lstconf->lvstopology) {
+ syslog(LOG_DEBUG,"------< LVS Topology >------");
+ dump_vs(lstconf->lvstopology);
+ }
}
}
svrfill->method = methodfill;
}
-void process_stream_misccheck(FILE *stream, realserver *svrfill)
-{
- keepalive_check *methodfill;
- char* pathstring = (char*)malloc(512);
-
- /* Allocate new method structure */
- methodfill = (keepalive_check *)malloc(sizeof(keepalive_check));
- memset(methodfill, 0, sizeof(keepalive_check));
-
- methodfill->type = MISC_CHECK_ID;
- methodfill->http_get = NULL;
- methodfill->misc_check_path = NULL;
-
- do {
- switch (key(string)) {
- case KW_CTIMEOUT:
- fscanf(stream, "%d", &methodfill->connection_to);
- break;
- case KW_MISCPATH:
- fgets(pathstring,512,stream);
- methodfill->misc_check_path=pathstring;
- break;
- case KW_UNKNOWN:
- break;
- }
- fscanf(stream, "%s", string);
- } while(key(string) != KW_ENDFLAG);
-
- svrfill->method = methodfill;
-}
-
void process_stream_url(FILE *stream, http_get_check *httpgetfill)
{
urls *urlfill;
break;
case KW_LDAPGET: /* not yet implemented */
break;
- case KW_MISCCHECK:
- process_stream_misccheck(stream, svrfill);
- break;
case KW_UNKNOWN:
break;
}
break;
case KW_LBKIND:
fscanf(stream, "%s", string);
-
-#ifdef KERNEL_2_2
- if (strcmp(string, "NAT") == 0)
- vsfill->loadbalancing_kind = 0;
- else
- if (strcmp(string, "DR") == 0)
- vsfill->loadbalancing_kind = IP_MASQ_F_VS_DROUTE;
- else
- if (strcmp(string, "TUN") == 0)
- vsfill->loadbalancing_kind = IP_MASQ_F_VS_TUNNEL;
- else
- syslog(LOG_DEBUG,"CFREADER : unknown [%s] routing method."
- , string);
-#else
- if (strcmp(string, "NAT") == 0)
- vsfill->loadbalancing_kind = IP_VS_CONN_F_MASQ;
- else
- if (strcmp(string, "DR") == 0)
- vsfill->loadbalancing_kind = IP_VS_CONN_F_DROUTE;
- else
- if (strcmp(string, "TUN") == 0)
- vsfill->loadbalancing_kind = IP_VS_CONN_F_TUNNEL;
- else
- syslog(LOG_DEBUG,"CFREADER : unknown [%s] routing method."
- , string);
-#endif
-
+ /* For the moment only NAT is supported.
+ * masq_flags : IP_MASQ_F_VS_DROUTE & IP_MASQ_F_VS_TUNNEL not supported.
+ * So we just set masq_flags to 0.
+ */
+ vsfill->loadbalancing_kind = 0;
break;
case KW_NATMASK:
fscanf(stream, "%s", string);
} while(key(string) != KW_ENDFLAG);
}
+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));
+ } else {
+ vsrv->vaddr = malloc(sizeof(*vsrv->vaddr));
+ }
+ /* store the data */
+ vsrv->vaddr[vsrv->naddr-1].addr = ipaddr;
+ vsrv->vaddr[vsrv->naddr-1].deletable = 0;
+}
+
+void process_stream_vrrp_ipaddress(FILE *stream, vrrp_rt *vrrp)
+{
+ uint32_t ipaddr;
+
+ do {
+ fscanf(stream, "%s", string);
+ if(key(string) != KW_BEGINFLAG && key(string) != KW_ENDFLAG) {
+ ipaddr = inet_addr(string);
+ add_item_vrrp_vip(vrrp, ntohl(ipaddr));
+ }
+ } while(key(string) != KW_ENDFLAG);
+}
+
+void process_stream_vrrp_auth(FILE *stream, vrrp_if *vif)
+{
+ do {
+ switch (key(string)) {
+ case KW_VRRPAUTHTYPE:
+ fscanf(stream, "%s", string);
+ vif->auth_type = (key(string) == KW_VRRPAUTHAH)?VRRP_AUTH_AH:VRRP_AUTH_PASS;
+ break;
+ case KW_VRRPAUTHPASS:
+ fscanf(stream, "%s", vif->auth_data);
+ break;
+ case KW_UNKNOWN:
+ break;
+ }
+ fscanf(stream, "%s", string);
+ } while(key(string) != KW_ENDFLAG);
+}
+
+int process_stream_vrrp(FILE *stream, configuration_data *conf_data)
+{
+ vrrp_instance *vrrpfill;
+ vrrp_rt *rtfill;
+ vrrp_if *viffill;
+ 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));
+
+ /* Add the vrrp instance allocated to the configuration
+ * data structure.
+ */
+ vrrpfill->vsrv = rtfill;
+ vrrpfill->vsrv->vif = viffill;
+ vrrpfill->vsrv->ipsecah_counter = counterfill;
+ vrrpfill->vsrv->vaddr = NULL;
+ vrrpfill->vsrv->vaddr = NULL;
+ vrrpfill->next = NULL;
+
+ conf_data->vrrp = add_item_vrrp(conf_data->vrrp, vrrpfill);
+
+ fscanf(stream, "%s", vrrpfill->iname);
+
+ /* Fill in the VRRP structure */
+ do {
+ switch (key(string)) {
+ case KW_VRRPSYNC:
+ fscanf(stream, "%s", vrrpfill->isync);
+ break;
+ case KW_VRRPINT:
+ fscanf(stream, "%s", viffill->ifname);
+ break;
+ case KW_VRRPVRID:
+ fscanf(stream, "%d", &rtfill->vrid);
+ if (VRRP_IS_BAD_VID(rtfill->vrid)) {
+ syslog(LOG_DEBUG, "VRRP Error : VRID not valid !");
+ syslog(LOG_DEBUG, "VRRP Error : must be between 1 & 255. reconfigure !");
+ return 0;
+ }
+ break;
+ case KW_VRRPPRIO:
+ fscanf(stream, "%d", &rtfill->priority);
+ if (VRRP_IS_BAD_PRIORITY(rtfill->priority)) {
+ syslog(LOG_DEBUG, "VRRP Error : priority not valid !");
+ syslog(LOG_DEBUG, "VRRP Error : must be between 1 & 255. reconfigure !");
+ return 0;
+ }
+ break;
+ case KW_VRRPADVERT:
+ fscanf(stream, "%d", &rtfill->adver_int);
+ if (VRRP_IS_BAD_ADVERT_INT(rtfill->adver_int)) {
+ syslog(LOG_DEBUG, "VRRP Error : Advert intervall not valid !");
+ syslog(LOG_DEBUG, "VRRP Error : must be between less than 1sec. reconfigure !");
+ return 0;
+ }
+ rtfill->adver_int *= VRRP_TIMER_HZ;
+ break;
+ case KW_VRRPAUTH:
+ process_stream_vrrp_auth(stream, viffill);
+ break;
+ case KW_VRRPIPADD:
+ process_stream_vrrp_ipaddress(stream, rtfill);
+ break;
+ case KW_VRRPPREEMPT:
+ rtfill->preempt = !rtfill->preempt;
+ break;
+ case KW_UNKNOWN:
+ break;
+ }
+ fscanf(stream, "%s", string);
+ } while(key(string) != KW_ENDFLAG);
+
+ /* Compute the static values to finish initialization */
+ if (!complete_vrrp_init(rtfill))
+ return 0;
+
+ return 1;
+}
+
configuration_data * conf_reader()
{
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");
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));
- memset(conf_data, 0, sizeof(configuration_data));
-
/* Allocate temp buffer string */
string = (char *)malloc(TEMP_BUFFER_LENGTH);
memset(string, 0, TEMP_BUFFER_LENGTH);
case KW_VS:
process_stream_vs(stream, conf_data);
break;
+ case KW_VRRP:
+ if (!process_stream_vrrp(stream, conf_data))
+ return NULL;
+ break;
case KW_UNKNOWN:
break;
}
*
* Part: cfreader.c include file.
*
- * Version: $Id: cfreader.h,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: cfreader.h,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#include <syslog.h>
#include <arpa/inet.h>
-#ifdef KERNEL_2_2
- #include <linux/ip_masq.h>
- #include <net/ip_masq.h>
-#else
- #include <net/ip_vs.h>
-#endif
+#include <linux/ip_masq.h>
/* local includes */
#include "utils.h"
+#include "vrrp.h"
#define CONFFILE "/etc/keepalived/keepalived.conf"
-/* locals defines */
#define TEMP_BUFFER_LENGTH 100
#define MAX_EMAIL_LENGTH 45
#define MAX_LVSID_LENGTH 20
#define MAX_URL_LENGTH 110
#define DIGEST_LENGTH 32+1
#define MAX_TIMEOUT_LENGTH 5
-
-#ifdef KERNEL_2_2
- #define SCHED_MAX_LENGTH IP_MASQ_TNAME_MAX
-#else
- #define SCHED_MAX_LENGTH IP_VS_SCHEDNAME_MAXLEN
-#endif
+#define MAX_INT_LENGTH 10
/* Keywords definition */
struct keyword {
};
/* configuration file keyword definition */
-#define KW_GLOBALDEFS (1 << 0)
-#define KW_VS (1 << 1)
-#define KW_SVR (1 << 2)
-#define KW_SSVR (1 << 3)
-#define KW_BEGINFLAG (1 << 4)
-#define KW_ENDFLAG (1 << 5)
-#define KW_DELAY (1 << 6)
-#define KW_EMAIL (1 << 7)
-#define KW_EMAILFROM (1 << 8)
-#define KW_LVSID (1 << 9)
-#define KW_SMTP (1 << 10)
-#define KW_STIMEOUT (1 << 11)
-#define KW_LBSCHED (1 << 12)
-#define KW_LBKIND (1 << 13)
-#define KW_NATMASK (1 << 14)
-#define KW_PTIMEOUT (1 << 15)
-#define KW_PROTOCOL (1 << 16)
-#define KW_WEIGHT (1 << 17)
-#define KW_URL (1 << 18)
-#define KW_URLPATH (1 << 19)
-#define KW_DIGEST (1 << 20)
-#define KW_CTIMEOUT (1 << 21)
-#define KW_NBGETRETRY (1 << 22)
-#define KW_DELAYRETRY (1 << 23)
-
-#define KW_ICMPCHECK (1 << 24)
-#define KW_TCPCHECK (1 << 25)
-#define KW_HTTPGET (1 << 26)
-#define KW_SSLGET (1 << 27)
-#define KW_LDAPGET (1 << 28)
-#define KW_MISCCHECK (1 << 29)
-#define KW_MISCPATH (1 << 30)
-
-#define KW_UNKNOWN (1 << 31)
+#define KW_GLOBALDEFS 0
+#define KW_VS 1
+#define KW_SVR 2
+#define KW_SSVR 3
+#define KW_BEGINFLAG 4
+#define KW_ENDFLAG 5
+#define KW_DELAY 6
+#define KW_EMAIL 7
+#define KW_EMAILFROM 8
+#define KW_LVSID 9
+#define KW_SMTP 10
+#define KW_STIMEOUT 11
+#define KW_LBSCHED 12
+#define KW_LBKIND 13
+#define KW_NATMASK 14
+#define KW_PTIMEOUT 15
+#define KW_PROTOCOL 16
+#define KW_WEIGHT 17
+#define KW_URL 18
+#define KW_URLPATH 19
+#define KW_DIGEST 20
+#define KW_CTIMEOUT 21
+#define KW_NBGETRETRY 22
+#define KW_DELAYRETRY 23
+
+#define KW_ICMPCHECK 24
+#define KW_TCPCHECK 25
+#define KW_HTTPGET 26
+#define KW_SSLGET 27
+#define KW_LDAPGET 28
+
+#define KW_VRRP 29
+#define KW_VRRPINT 30
+#define KW_VRRPVRID 31
+#define KW_VRRPAUTH 32
+#define KW_VRRPAUTHTYPE 33
+#define KW_VRRPAUTHAH 34
+#define KW_VRRPAUTHPWD 35
+#define KW_VRRPAUTHPASS 36
+#define KW_VRRPPRIO 37
+#define KW_VRRPADVERT 38
+#define KW_VRRPIPADD 39
+#define KW_VRRPSYNC 40
+#define KW_VRRPPREEMPT 41
+
+#define KW_UNKNOWN 42
/* Structure definition */
typedef struct _urls {
#define HTTP_GET_ID (1 << 2)
#define SSL_GET_ID (1 << 3)
#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;
} keepalive_check;
typedef struct _real_server {
uint16_t addr_port;
uint16_t service_type;
int delay_loop;
- char sched[SCHED_MAX_LENGTH];
+ char sched[IP_MASQ_TNAME_MAX];
unsigned loadbalancing_kind;
struct in_addr nat_mask;
char timeout_persistence[MAX_TIMEOUT_LENGTH];
struct virtualserver *next;
} virtualserver;
+typedef struct _vrrp_instance {
+ char iname[MAX_INT_LENGTH]; /* Instance Name */
+ char isync[MAX_INT_LENGTH]; /* Instance Name to synchronize with */
+ vrrp_rt *vsrv; /* VRRP data */
+
+ struct vrrp_instance *next;
+} vrrp_instance;
+
typedef struct _notification_email {
char addr[MAX_EMAIL_LENGTH];
struct in_addr smtp_server;
int smtp_connection_to;
notification_email *email;
+ vrrp_instance *vrrp;
virtualserver *lvstopology;
} configuration_data;
/* prototypes */
extern configuration_data * conf_reader();
extern void clear_conf(configuration_data * lstptr);
+extern void clear_vrrp_instance(vrrp_instance *lstptr);
extern void dump_conf(configuration_data * lstptr);
#endif
*
* Part: Checkers arguments structures definitions.
*
- * Version: $Id: check.h,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: check.h,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
* url, compute a MD5 over this result and match it to the
* expected value.
*
- * Version: $Id: check_http.c,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: check_http.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
+ * Changes: Alexandre Cassen : 2001/06/25 : Initial release
+ *
* 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.
*
* Part: check_http.c include file.
*
- * Version: $Id: check_http.h,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: check_http.h,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
+++ /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: MISC CHECK. Perform a system call to run an extra
- * system prog or script.
- *
- * Version: $Id: check_misc.c,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
- *
- * Author: 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
- * 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 "check_misc.h"
-
-/* does this need to be threaded? */
-int
-misc_check_call(char* cmdline)
-{
- int retval;
-
- retval = system(cmdline);
-
- if (retval == 127) {
- /* couldn't exec command */
- syslog(LOG_DEBUG,"Couldn't exec command: %s", cmdline);
- } else if (retval == -1) {
- /* other error */
- syslog(LOG_DEBUG,"Error exec-ing command: %s", cmdline);
- } else {
- /* everything is good */
- syslog(LOG_DEBUG, "Successfully exec command: %s retval is %d"
- , cmdline, retval);
- }
-
- return retval;
-}
-
-int
-misc_check_thread(struct thread *thread)
-{
- struct thread_arg *thread_arg;
- int status;
-
- thread_arg = THREAD_ARG(thread);
-
- status = misc_check_call(thread_arg->svr->method->misc_check_path);
-
- if (status == 0) {
- /* everything is good */
- if (!thread_arg->svr->alive) {
- perform_svr_state(UP, thread_arg->vs, thread_arg->svr);
- }
- } else {
- if (thread_arg->svr->alive) {
- perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
- }
- }
-
- /* Register next timer checker */
- thread_add_timer(thread->master, misc_check_thread, thread_arg,
- thread_arg->vs->delay_loop);
-
- return 0;
-}
*
* Part: TCP checker.
*
- * Version: $Id: check_tcp.c,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: check_tcp.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
+ * Changes: Alexandre Cassen : 2001/06/25 : Initial release
+ *
* 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.
*
* Part: check_tcp.c include file.
*
- * Version: $Id: check_tcp.h,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: check_tcp.h,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
global_defs {
notification_email {
- acassen
+ acassen@firewall.loc
+ failover@firewall.loc
+ sysadmin@firewall.loc
}
notification_email_from Alexandre.Cassen@firewall.loc
smtp_server 192.168.200.1
delay_before_retry 3
}
}
-
- real_server 192.168.200.6 1358 {
- weight 1
- MISC_CHECK {
- misc_path /usr/local/bin/script.sh
- }
- }
-
}
virtual_server 10.10.10.3 1358 {
# pidfile: /var/run/keepalived.pid
# config: /etc/keepalived/keepalived.conf
+
+# Source function library.
+. /etc/rc.d/init.d/functions
+
# See how we were called.
case "$1" in
start)
echo -n "Starting Keepalived for LVS: "
- keepalived
+ daemon keepalived
echo
;;
stop)
echo -n "Shutting down Keepalived for LVS: "
- PID=`ps ax | grep keepalived | awk '{print $1}'`
- kill $PID
+ killproc keepalived
echo
;;
*)
* library to add/remove server MASQ rules to the kernel
* firewall framework.
*
- * Version: $Id: ipfwwrapper.c,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: ipfwwrapper.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
+ * Changes: Alexandre Cassen : 2001/06/25 : Initial release
+ *
* 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.
*
* Part: ipfwwrapper.c include file.
*
- * Version: $Id: ipfwwrapper.h,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: ipfwwrapper.h,v 0.4.0 2001/08/24 00:35:19 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.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: ipvswrapper.c,v 0.4.0 2001/08/24 00:35:19 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.
+ * Changes:
+ * Alexandre Cassen : 2001/03/27 :
+ * <+> Added setsockopt return value.
+ * <+> Added support to the IP_MASQ_CMD ruleset.
+ * IP_MASQ_CMD_ADD : Adding a virtual service.
+ * IP_MASQ_CMD_DEL : Deleting a virtual service.
+ * IP_MASQ_CMD_ADD_DEST : Adding a real service.
+ * IP_MASQ_CMD_DEL_DEST : Deleting a real service.
+ * Alexandre Cassen : Initial release
+ *
+ * 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.
+ * 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 "ipvswrapper.h"
-#ifdef KERNEL_2_2 /* KERNEL 2.2 LVS handling */
-
int ipvs_cmd(int cmd, virtualserver *vserver, realserver *rserver)
{
struct ip_masq_ctl ctl;
ctl.u.vs_user.protocol = vserver->service_type;
if(!parse_timeout(vserver->timeout_persistence, &ctl.u.vs_user.timeout)) {
- syslog(LOG_INFO, "IPVS WRAPPER : Virtual service [%s:%d] illegal timeout.",
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "IPVS WRAPPER : Virtual service [%s:%d] illegal timeout.",
inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
+#endif
}
ctl.u.vs_user.vs_flags = (ctl.u.vs_user.timeout!=0)?IP_VS_SVC_F_PERSISTENT:0;
+ ctl.u.vs_user.vfwmark = 0;
/* VS specific */
ctl.u.vs_user.vaddr = vserver->addr_ip.s_addr;
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (sockfd == -1) {
- syslog(LOG_INFO, "IPVS WRAPPER : Can not initialize SOCK_RAW descriptor.");
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "IPVS WRAPPER : Can not initialize SOCK_RAW descriptor.");
+#endif
return IPVS_ERROR;
}
result = setsockopt(sockfd, IPPROTO_IP, IP_FW_MASQ_CTL, (char *)&ctl, sizeof(ctl));
if (errno == ESRCH) {
- syslog(LOG_INFO, "IPVS WRAPPER : Virtual service [%s:%d] not defined.",
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "IPVS WRAPPER : Virtual service [%s:%d] not defined.",
inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
+#endif
close(sockfd);
- return IPVS_ERROR;
+ return IPVSNOTDEFINED;
} else if (errno == EEXIST) {
- syslog(LOG_INFO, "IPVS WRAPPER : Destination already exists [%s:%d].",
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "IPVS WRAPPER : Destination already exists [%s:%d].",
inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port));
+#endif
+ close(sockfd);
+ return IPVSSVREXIST;
} else if (errno == ENOENT) {
- syslog(LOG_INFO, "IPVS WRAPPER : No such destination [%s:%d].",
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "IPVS WRAPPER : No such destination [%s:%d].",
inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port));
+#endif
+ close(sockfd);
+ return IPVSNODEST;
}
close(sockfd);
return IPVS_SUCCESS;
}
-#else /* KERNEL 2.4 LVS handling */
-
-int ipvs_cmd(int cmd, virtualserver *vserver, realserver *rserver)
-{
- struct ip_vs_rule_user urule;
- int result=0;
- int sockfd;
-
- memset(&urule, 0, sizeof(struct ip_vs_rule_user));
-
- strncpy(urule.sched_name, vserver->sched, IP_VS_SCHEDNAME_MAXLEN);
- urule.weight = 1;
- urule.conn_flags = vserver->loadbalancing_kind;
- urule.netmask = ((u_int32_t) 0xffffffff);
- urule.protocol = vserver->service_type;
-
- if (!parse_timeout(vserver->timeout_persistence, &urule.timeout)) {
- syslog(LOG_INFO, "IPVS WRAPPER : Virtual service [%s:%d] illegal timeout.",
- inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
- }
- 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;
-
- /* SVR specific */
- if (cmd == IP_VS_SO_SET_ADDDEST || cmd == IP_VS_SO_SET_DELDEST) {
- urule.weight = rserver->weight;
- urule.daddr = rserver->addr_ip.s_addr;
- urule.dport = rserver->addr_port;
- }
-
- sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
- if (sockfd == -1) {
- syslog(LOG_INFO, "IPVS WRAPPER : Can not initialize SOCK_RAW descriptor.");
- return IPVS_ERROR;
- }
-
- result = setsockopt(sockfd, IPPROTO_IP, cmd, (char *)&urule, sizeof(urule));
-
- /* kernel return error handling */
- if (result) {
- syslog(LOG_INFO, "IPVS WRAPPER : setsockopt failed !!!");
-
- switch (cmd) {
- case IP_VS_SO_SET_ADD:
- if (errno == EEXIST)
- syslog(LOG_INFO, "IPVS WRAPPER : Destination already exists [%s:%d].",
- inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
- else if (errno == ENOENT) {
- syslog(LOG_INFO, "IPVS WRAPPER : Scheduler not found: ip_vs_%s.o !!!",
- urule.sched_name);
- close(sockfd);
- return IPVS_ERROR;
- }
- break;
-
- case IP_VS_SO_SET_DEL:
- if (errno == ESRCH)
- syslog(LOG_INFO, "IPVS WRAPPER : No such service [%s:%d].",
- inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
- close(sockfd);
- return IPVS_ERROR;
- break;
-
- case IP_VS_SO_SET_ADDDEST:
- if (errno == ESRCH)
- syslog(LOG_INFO, "IPVS WRAPPER : Service not defined [%s:%d].",
- inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port));
- else if (errno == EEXIST)
- syslog(LOG_INFO, "IPVS WRAPPER : Destination already exists [%s:%d].",
- inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port));
- break;
-
- case IP_VS_SO_SET_DELDEST:
- if (errno == ESRCH)
- syslog(LOG_INFO, "IPVS WRAPPER : Service not defined [%s:%d].",
- inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port));
- else if (errno == ENOENT)
- syslog(LOG_INFO, "IPVS WRAPPER : No such destination [%s:%d].",
- inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port));
- break;
- }
- }
-
- close(sockfd);
- return IPVS_SUCCESS;
-}
-
-#endif
-
/*
* Source code from the ipvsadm.c Wensong code
*/
*
* Part: ipvswrapper.c include file.
*
- * Version: $Id: ipvswrapper.h,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: ipvswrapper.h,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
#include <netinet/tcp.h>
-
-#ifdef KERNEL_2_2
- #include <linux/ip_fw.h>
- #include <net/ip_masq.h>
-#endif
-
+#include <linux/ip_fw.h>
+#include <linux/ip_masq.h>
+#include <net/ip_masq.h>
#include <net/ip_vs.h>
/* locale includes */
#define IPVS_ERROR 0
#define IPVS_SUCCESS 1
+/* Return codes */
+#define IPVSNOTDEFINED 0x0003
+#define IPVSSVREXIST 0x0004
+#define IPVSNODEST 0x0005
+
/* prototypes */
extern int parse_timeout(char *buf, unsigned *timeout);
extern int string_to_number(const char *s, int min, int max);
*
* Part: Manipulation functions for IPVS & IPFW wrappers.
*
- * Version: $Id: ipwrapper.c,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $id: ipwrapper.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
+ * Changes: Alexandre Cassen : 2001/06/25 : Initial release
+ *
* 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.
pointersvr = vserver->svr;
while (vserver->svr) {
/* IPVS cleaning server entry */
- if (!ipvs_cmd(LVS_CMD_DEL_DEST, vserver, vserver->svr)) {
+ if (!ipvs_cmd(IP_MASQ_CMD_DEL_DEST, vserver, vserver->svr)) {
vserver->svr = pointersvr;
return 0;
}
-#ifdef KERNEL_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))
return 0;
-#endif
vserver->svr = (realserver *)vserver->svr->next;
}
vserver->svr = pointersvr;
- if (!ipvs_cmd(LVS_CMD_DEL, vserver, vserver->svr))
+ if (!ipvs_cmd(IP_MASQ_CMD_DEL, vserver, vserver->svr))
return 0;
return 1;
if (!clear_service_vs(vserver))
return 0;
-#ifdef KERNEL_2_2
/* IPFW cleaner processing */
- if (vserver->nat_mask.s_addr != HOST_NETMASK)
+ if (vserver->nat_mask.s_addr != HOST_NETMASK) {
if (!ipfw_cmd(IP_FW_CMD_DEL, vserver, vserver->svr))
return 0;
-#endif
+ }
vserver = (virtualserver *)vserver->next;
}
inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
vserver->s_svr->alive = 0;
- ipvs_cmd(LVS_CMD_DEL_DEST, vserver, vserver->s_svr);
-
-#ifdef KERNEL_2_2
+ ipvs_cmd(IP_MASQ_CMD_DEL_DEST, vserver, vserver->s_svr);
ipfw_cmd(IP_FW_CMD_DEL, vserver, vserver->s_svr);
-#endif
}
}
syslog(LOG_INFO, "Adding service [%s:%d] to VS [%s:%d]",
inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port),
inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
- ipvs_cmd(LVS_CMD_ADD_DEST, vserver, rserver);
-
-#ifdef KERNEL_2_2
+ ipvs_cmd(IP_MASQ_CMD_ADD_DEST, vserver, rserver);
if (vserver->nat_mask.s_addr == HOST_NETMASK)
ipfw_cmd(IP_FW_CMD_ADD, vserver, rserver);
-#endif
} else {
inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
/* server is down, it is removed from the LVS realserver pool */
- ipvs_cmd(LVS_CMD_DEL_DEST, vserver, rserver);
-
-#ifdef KERNEL_2_2
+ ipvs_cmd(IP_MASQ_CMD_DEL_DEST, vserver, rserver);
if (vserver->nat_mask.s_addr == HOST_NETMASK)
ipfw_cmd(IP_FW_CMD_DEL, vserver, rserver);
-#endif
/* if all the realserver pool is down, we add sorry server */
if (vserver->s_svr && all_realservers_down(vserver)) {
/* the sorry server is now up in the pool, we flag it alive */
vserver->s_svr->alive = 1;
- ipvs_cmd(LVS_CMD_ADD_DEST, vserver, vserver->s_svr);
-
-#ifdef KERNEL_2_2
+ ipvs_cmd(IP_MASQ_CMD_ADD_DEST, vserver, vserver->s_svr);
ipfw_cmd(IP_FW_CMD_ADD, vserver, vserver->s_svr);
-#endif
}
}
pointersvr = vserver->svr;
while (vserver->svr) {
- if (!ipvs_cmd(LVS_CMD_ADD_DEST, vserver, vserver->svr)) {
+ if (!ipvs_cmd(IP_MASQ_CMD_ADD_DEST, vserver, vserver->svr)) {
vserver->svr = pointersvr;
return 0;
}
-#ifdef KERNEL_2_2
/* if we have a /32 mask, we create one nat rules per
* realserver.
*/
vserver->svr = pointersvr;
return 0;
}
-#endif
-
vserver->svr = (realserver *)vserver->svr->next;
}
vserver->svr = pointersvr;
pointervs = vserver;
while (vserver) {
- if (!ipvs_cmd(LVS_CMD_ADD, vserver, vserver->svr))
+ if (!ipvs_cmd(IP_MASQ_CMD_ADD, vserver, vserver->svr))
return 0;
-#ifdef KERNEL_2_2
/* work if all realserver ip address are in the
* same network (it is assumed).
*/
if (vserver->nat_mask.s_addr != HOST_NETMASK)
if (!ipfw_cmd(IP_FW_CMD_ADD, vserver, vserver->svr))
return 0;
-#endif
if (!init_service_vs(vserver))
return 0;
*
* Part: ipwrapper.c include file.
*
- * Version: $Id: ipwrapper.h,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: ipwrapper.h,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#define UP 1
#define DOWN 0
-/* LVS command set by kernel */
-#ifdef KERNEL_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
- #define LVS_CMD_DEL_DEST IP_MASQ_CMD_DEL_DEST
-#else
- #define LVS_CMD_ADD IP_VS_SO_SET_ADD
- #define LVS_CMD_DEL IP_VS_SO_SET_DEL
- #define LVS_CMD_ADD_DEST IP_VS_SO_SET_ADDDEST
- #define LVS_CMD_DEL_DEST IP_VS_SO_SET_DELDEST
-#endif
-
/* prototypes */
extern void perform_svr_state(int alive, virtualserver *vserver, realserver *rserver);
extern int init_services(virtualserver *vserver);
lvs_id LVS_DEVEL
}
+vrrp_instance VI_1 {
+ interface eth0
+ virtual_router_id 50
+ preempt
+ authentication {
+ auth_type AH
+ auth_pass k@!v361
+ }
+ priority 100
+ advert_int 1
+ virtual_ipaddress {
+ 192.168.200.11
+ 192.168.200.12
+ 192.168.200.13
+ }
+ sync_instance VI_2
+}
+
+vrrp_instance VI_2 {
+ interface eth1
+ virtual_router_id 51
+ authentication {
+ auth_type AH
+ auth_pass k@!v362
+ }
+ priority 100
+ advert_int 1
+ virtual_ipaddress {
+ 192.168.201.11
+ 192.168.201.12
+ 192.168.201.13
+ }
+ sync_instance VI_1
+}
+
virtual_server 10.10.10.2 1358 {
delay_loop 6
lb_algo rr
delay_before_retry 3
}
}
-
- real_server 192.168.200.6 1358 {
- weight 1
- MISC_CHECK {
- misc_path /usr/local/bin/script.sh
- }
- }
-
}
virtual_server 10.10.10.3 1358 {
--- /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
+}
+
+vrrp_instance VI_1 {
+ interface eth0
+ virtual_router_id 50
+ authentication {
+ auth_type AH
+ auth_pass k!4@lve1
+ }
+ priority 100
+ advert_int 1
+ virtual_ipaddress {
+ 192.168.200.11
+ 192.168.200.12
+ 192.168.200.13
+ }
+ sync_instance VI_2
+ preempt
+}
+
+vrrp_instance VI_2 {
+ interface eth1
+ virtual_router_id 51
+ authentication {
+ auth_type AH
+ auth_pass k!4@lve2
+ }
+ priority 100
+ advert_int 1
+ virtual_ipaddress {
+ 192.168.201.11
+ 192.168.201.12
+ 192.168.201.13
+ }
+ sync_instance VI_1
+}
+
* Part: Layer4 checkers handling. Register worker threads &
* upper layer checkers.
*
- * Version: $Id: layer4.c,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: layer4.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
+ * Changes: Alexandre Cassen : 2001/06/25 : Initial release
+ *
* 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.
*
* Part: layer4.c include file.
*
- * Version: $Id: layer4.h,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: layer4.h,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
#include <stdint.h>
#include <netdb.h>
#include <arpa/inet.h>
-#include <sys/socket.h>
-#include <sys/types.h>
/* local includes */
#include "cfreader.h"
--- /dev/null
+CC = gcc
+COPTS = -g -O
+CFLAGS = -Wall -Wunused $(COPTS)
+
+libnetlink.a: libnetlink.a(libnetlink.o ll_map.o)
+
+libnetlink.o: libnetlink.h
+ll_map.o: ll_map.h
+
+clean:
+ rm -f *.a *.o *~
--- /dev/null
+/*
+ * libnetlink.c RTnetlink service routines.
+ *
+ * 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.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <net/if_arp.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/uio.h>
+
+#include "libnetlink.h"
+
+#ifndef MSG_TRUNC
+# define MSG_TRUNC 0x20
+#endif MSG_TRUNC
+
+#if 1
+# define nl_perror(str) perror(str)
+#else
+# define nl_perror(str)
+#endif
+
+int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions)
+{
+ int addr_len;
+
+ memset(rth, 0, sizeof(rth));
+
+ rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (rth->fd < 0) {
+ nl_perror("Cannot open netlink socket");
+ return -1;
+ }
+
+ memset(&rth->local, 0, sizeof(rth->local));
+ rth->local.nl_family = AF_NETLINK;
+ rth->local.nl_groups = subscriptions;
+
+ if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) {
+ nl_perror("Cannot bind netlink socket");
+ return -1;
+ }
+ addr_len = sizeof(rth->local);
+ if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) {
+ nl_perror("Cannot getsockname");
+ return -1;
+ }
+ if (addr_len != sizeof(rth->local)) {
+ fprintf(stderr, "Wrong address length %d\n", addr_len);
+ return -1;
+ }
+ if (rth->local.nl_family != AF_NETLINK) {
+ fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family);
+ return -1;
+ }
+ rth->seq = time(NULL);
+ return 0;
+}
+
+int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type)
+{
+ struct {
+ struct nlmsghdr nlh;
+ struct rtgenmsg g;
+ } req;
+ struct sockaddr_nl nladdr;
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ req.nlh.nlmsg_len = sizeof(req);
+ req.nlh.nlmsg_type = type;
+ req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+ req.nlh.nlmsg_pid = 0;
+ req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
+ req.g.rtgen_family = family;
+
+ return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
+}
+
+int rtnl_send(struct rtnl_handle *rth, char *buf, int len)
+{
+ struct sockaddr_nl nladdr;
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr));
+}
+
+int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
+{
+ struct nlmsghdr nlh;
+ struct sockaddr_nl nladdr;
+ struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } };
+ struct msghdr msg = {
+ (void*)&nladdr, sizeof(nladdr),
+ iov, 2,
+ NULL, 0,
+ 0
+ };
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+
+ nlh.nlmsg_len = NLMSG_LENGTH(len);
+ nlh.nlmsg_type = type;
+ nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST;
+ nlh.nlmsg_pid = 0;
+ nlh.nlmsg_seq = rth->dump = ++rth->seq;
+
+ return sendmsg(rth->fd, &msg, 0);
+}
+
+int rtnl_dump_filter(struct rtnl_handle *rth,
+ int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
+ void *arg1,
+ int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
+ void *arg2)
+{
+ char buf[8192];
+ struct sockaddr_nl nladdr;
+ struct iovec iov = { buf, sizeof(buf) };
+
+ while (1) {
+ int status;
+ struct nlmsghdr *h;
+
+ struct msghdr msg = {
+ (void*)&nladdr, sizeof(nladdr),
+ &iov, 1,
+ NULL, 0,
+ 0
+ };
+
+ status = recvmsg(rth->fd, &msg, 0);
+
+ if (status < 0) {
+ if (errno == EINTR)
+ continue;
+ nl_perror("OVERRUN");
+ continue;
+ }
+ if (status == 0) {
+ fprintf(stderr, "EOF on netlink\n");
+ return -1;
+ }
+ if (msg.msg_namelen != sizeof(nladdr)) {
+ fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
+ exit(1);
+ }
+
+ h = (struct nlmsghdr*)buf;
+ while (NLMSG_OK(h, status)) {
+ int err;
+
+ if (h->nlmsg_pid != rth->local.nl_pid ||
+ h->nlmsg_seq != rth->dump) {
+ if (junk) {
+ err = junk(&nladdr, h, arg2);
+ if (err < 0)
+ return err;
+ }
+ goto skip_it;
+ }
+
+ if (h->nlmsg_type == NLMSG_DONE)
+ return 0;
+ if (h->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+ if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) {
+ fprintf(stderr, "ERROR truncated\n");
+ } else {
+ errno = -err->error;
+ nl_perror("RTNETLINK answers");
+ }
+ return -1;
+ }
+ err = filter(&nladdr, h, arg1);
+ if (err < 0)
+ return err;
+
+skip_it:
+ h = NLMSG_NEXT(h, status);
+ }
+ if (msg.msg_flags & MSG_TRUNC) {
+ fprintf(stderr, "Message truncated\n");
+ continue;
+ }
+ if (status) {
+ fprintf(stderr, "!!!Remnant of size %d\n", status);
+ exit(1);
+ }
+ }
+}
+
+int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
+ unsigned groups, struct nlmsghdr *answer,
+ int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
+ void *jarg)
+{
+ int status;
+ struct nlmsghdr *h;
+ struct sockaddr_nl nladdr;
+ struct iovec iov = { (void*)n, n->nlmsg_len };
+ char buf[8192];
+ struct msghdr msg = {
+ (void*)&nladdr, sizeof(nladdr),
+ &iov, 1,
+ NULL, 0,
+ 0
+ };
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ nladdr.nl_pid = peer;
+ nladdr.nl_groups = groups;
+
+ n->nlmsg_seq = ++rtnl->seq;
+ if (answer == NULL)
+ n->nlmsg_flags |= NLM_F_ACK;
+
+ status = sendmsg(rtnl->fd, &msg, 0);
+
+ if (status < 0) {
+ nl_perror("Cannot talk to rtnetlink");
+ return -1;
+ }
+
+ iov.iov_base = buf;
+ iov.iov_len = sizeof(buf);
+
+ while (1) {
+ status = recvmsg(rtnl->fd, &msg, 0);
+
+ if (status < 0) {
+ if (errno == EINTR)
+ continue;
+ nl_perror("OVERRUN");
+ continue;
+ }
+ if (status == 0) {
+ fprintf(stderr, "EOF on netlink\n");
+ return -1;
+ }
+ if (msg.msg_namelen != sizeof(nladdr)) {
+ fprintf(stderr, "sender address length == %d\n", msg.msg_namelen);
+ exit(1);
+ }
+ for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
+ int err;
+ int len = h->nlmsg_len;
+ pid_t pid=h->nlmsg_pid;
+ int l = len - sizeof(*h);
+ unsigned seq=h->nlmsg_seq;
+
+ if (l<0 || len>status) {
+ if (msg.msg_flags & MSG_TRUNC) {
+ fprintf(stderr, "Truncated message\n");
+ return -1;
+ }
+ fprintf(stderr, "!!!malformed message: len=%d\n", len);
+ exit(1);
+ }
+
+ if (h->nlmsg_pid != pid || h->nlmsg_seq != seq) {
+ if (junk) {
+ err = junk(&nladdr, h, jarg);
+ if (err < 0)
+ return err;
+ }
+ continue;
+ }
+
+ if (h->nlmsg_type == NLMSG_ERROR) {
+ struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h);
+ if (l < sizeof(struct nlmsgerr)) {
+ fprintf(stderr, "ERROR truncated\n");
+ } else {
+ errno = -err->error;
+ if (errno == 0) {
+ if (answer)
+ memcpy(answer, h, h->nlmsg_len);
+ return 0;
+ }
+ nl_perror("RTNETLINK answers");
+ }
+ return -1;
+ }
+ if (answer) {
+ memcpy(answer, h, h->nlmsg_len);
+ return 0;
+ }
+
+ fprintf(stderr, "Unexpected reply!!!\n");
+
+ status -= NLMSG_ALIGN(len);
+ h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
+ }
+ if (msg.msg_flags & MSG_TRUNC) {
+ fprintf(stderr, "Message truncated\n");
+ continue;
+ }
+ if (status) {
+ fprintf(stderr, "!!!Remnant of size %d\n", status);
+ exit(1);
+ }
+ }
+}
+
+int rtnl_listen(struct rtnl_handle *rtnl,
+ int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
+ void *jarg)
+{
+ int status;
+ struct nlmsghdr *h;
+ struct sockaddr_nl nladdr;
+ struct iovec iov;
+ char buf[8192];
+ struct msghdr msg = {
+ (void*)&nladdr, sizeof(nladdr),
+ &iov, 1,
+ NULL, 0,
+ 0
+ };
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ nladdr.nl_pid = 0;
+ nladdr.nl_groups = 0;
+
+
+ iov.iov_base = buf;
+ iov.iov_len = sizeof(buf);
+
+ while (1) {
+ status = recvmsg(rtnl->fd, &msg, 0);
+
+ if (status < 0) {
+ if (errno == EINTR)
+ continue;
+ nl_perror("OVERRUN");
+ continue;
+ }
+ if (status == 0) {
+ fprintf(stderr, "EOF on netlink\n");
+ return -1;
+ }
+ if (msg.msg_namelen != sizeof(nladdr)) {
+ fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen);
+ exit(1);
+ }
+ for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) {
+ int err;
+ int len = h->nlmsg_len;
+ int l = len - sizeof(*h);
+
+ if (l<0 || len>status) {
+ if (msg.msg_flags & MSG_TRUNC) {
+ fprintf(stderr, "Truncated message\n");
+ return -1;
+ }
+ fprintf(stderr, "!!!malformed message: len=%d\n", len);
+ exit(1);
+ }
+
+ err = handler(&nladdr, h, jarg);
+ if (err < 0)
+ return err;
+
+ status -= NLMSG_ALIGN(len);
+ h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len));
+ }
+ if (msg.msg_flags & MSG_TRUNC) {
+ fprintf(stderr, "Message truncated\n");
+ continue;
+ }
+ if (status) {
+ fprintf(stderr, "!!!Remnant of size %d\n", status);
+ exit(1);
+ }
+ }
+}
+
+int rtnl_from_file(FILE *rtnl,
+ int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
+ void *jarg)
+{
+ int status;
+ struct sockaddr_nl nladdr;
+ char buf[8192];
+ struct nlmsghdr *h = (void*)buf;
+
+ memset(&nladdr, 0, sizeof(nladdr));
+ nladdr.nl_family = AF_NETLINK;
+ nladdr.nl_pid = 0;
+ nladdr.nl_groups = 0;
+
+ while (1) {
+ int err, len, type;
+ pid_t pid;
+ int l;
+ unsigned seq;
+
+ status = fread(&buf, 1, sizeof(*h), rtnl);
+
+ if (status < 0) {
+ if (errno == EINTR)
+ continue;
+ nl_perror("rtnl_from_file: fread");
+ return -1;
+ }
+ if (status == 0)
+ return 0;
+
+ len = h->nlmsg_len;
+ type= h->nlmsg_type;
+ pid=h->nlmsg_pid;
+ l = len - sizeof(*h);
+ seq=h->nlmsg_seq;
+
+ if (l<0 || len>sizeof(buf)) {
+ fprintf(stderr, "!!!malformed message: len=%d @%lu\n",
+ len, ftell(rtnl));
+ return -1;
+ }
+
+ status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl);
+
+ if (status < 0) {
+ nl_perror("rtnl_from_file: fread");
+ return -1;
+ }
+ if (status < l) {
+ fprintf(stderr, "rtnl-from_file: truncated message\n");
+ return -1;
+ }
+
+ err = handler(&nladdr, h, jarg);
+ if (err < 0)
+ return err;
+ }
+}
+
+int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data)
+{
+ int len = RTA_LENGTH(4);
+ struct rtattr *rta;
+ if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
+ return -1;
+ rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
+ rta->rta_type = type;
+ rta->rta_len = len;
+ memcpy(RTA_DATA(rta), &data, 4);
+ n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
+ return 0;
+}
+
+int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen)
+{
+ int len = RTA_LENGTH(alen);
+ struct rtattr *rta;
+
+ if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen)
+ return -1;
+ rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len));
+ rta->rta_type = type;
+ rta->rta_len = len;
+ memcpy(RTA_DATA(rta), data, alen);
+ n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len;
+ return 0;
+}
+
+int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data)
+{
+ int len = RTA_LENGTH(4);
+ struct rtattr *subrta;
+
+ if (RTA_ALIGN(rta->rta_len) + len > maxlen)
+ return -1;
+ subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
+ subrta->rta_type = type;
+ subrta->rta_len = len;
+ memcpy(RTA_DATA(subrta), &data, 4);
+ rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
+ return 0;
+}
+
+int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen)
+{
+ struct rtattr *subrta;
+ int len = RTA_LENGTH(alen);
+
+ if (RTA_ALIGN(rta->rta_len) + len > maxlen)
+ return -1;
+ subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len));
+ subrta->rta_type = type;
+ subrta->rta_len = len;
+ memcpy(RTA_DATA(subrta), data, alen);
+ rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len;
+ return 0;
+}
+
+
+int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len)
+{
+ while (RTA_OK(rta, len)) {
+ if (rta->rta_type <= max)
+ tb[rta->rta_type] = rta;
+ rta = RTA_NEXT(rta,len);
+ }
+ if (len)
+ fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len);
+ return 0;
+}
+
+/****************************************************************
+ NAME : rtnl_close 00/06/02 23:43:45
+ AIM :
+ REMARK :
+****************************************************************/
+int rtnl_close(struct rtnl_handle *rth)
+{
+ /* close the fd */
+ close( rth->fd );
+ return(0);
+}
+
--- /dev/null
+#ifndef __LIBNETLINK_H__
+#define __LIBNETLINK_H__ 1
+
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+
+struct rtnl_handle
+{
+ int fd;
+ struct sockaddr_nl local;
+ struct sockaddr_nl peer;
+ __u32 seq;
+ __u32 dump;
+};
+
+extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions);
+extern int rtnl_close(struct rtnl_handle *rth);
+extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type);
+extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len);
+extern int rtnl_dump_filter(struct rtnl_handle *rth,
+ int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
+ void *arg1,
+ int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
+ void *arg2);
+extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
+ unsigned groups, struct nlmsghdr *answer,
+ int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
+ void *jarg);
+extern int rtnl_send(struct rtnl_handle *rth, char *buf, int);
+
+
+extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data);
+extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen);
+extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data);
+extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen);
+
+extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len);
+
+extern int rtnl_listen(struct rtnl_handle *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
+ void *jarg);
+extern int rtnl_from_file(FILE *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
+ void *jarg);
+
+#endif /* __LIBNETLINK_H__ */
+
--- /dev/null
+/*
+ * ll_map.c
+ *
+ * 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.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <string.h>
+
+#include "libnetlink.h"
+#include "ll_map.h"
+
+struct idxmap
+{
+ struct idxmap * next;
+ int index;
+ int type;
+ int alen;
+ unsigned flags;
+ unsigned char addr[8];
+ char name[16];
+};
+
+static struct idxmap *idxmap[16];
+
+int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ int h;
+ struct ifinfomsg *ifi = NLMSG_DATA(n);
+ struct idxmap *im, **imp;
+ struct rtattr *tb[IFLA_MAX+1];
+
+ if (n->nlmsg_type != RTM_NEWLINK)
+ return 0;
+
+ if (n->nlmsg_len < NLMSG_LENGTH(sizeof(ifi)))
+ return -1;
+
+
+ memset(tb, 0, sizeof(tb));
+ parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
+ if (tb[IFLA_IFNAME] == NULL)
+ return 0;
+
+ h = ifi->ifi_index&0xF;
+
+ for (imp=&idxmap[h]; (im=*imp)!=NULL; imp = &im->next)
+ if (im->index == ifi->ifi_index)
+ break;
+
+ if (im == NULL) {
+ im = malloc(sizeof(*im));
+ if (im == NULL)
+ return 0;
+ im->next = *imp;
+ im->index = ifi->ifi_index;
+ *imp = im;
+ }
+
+ im->type = ifi->ifi_type;
+ im->flags = ifi->ifi_flags;
+ if (tb[IFLA_ADDRESS]) {
+ int alen;
+ im->alen = alen = RTA_PAYLOAD(tb[IFLA_ADDRESS]);
+ if (alen > sizeof(im->addr))
+ alen = sizeof(im->addr);
+ memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen);
+ } else {
+ im->alen = 0;
+ memset(im->addr, 0, sizeof(im->addr));
+ }
+ strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME]));
+ return 0;
+}
+
+const char *ll_idx_n2a(int idx, char *buf)
+{
+ struct idxmap *im;
+
+ if (idx == 0)
+ return "*";
+ for (im = idxmap[idx&0xF]; im; im = im->next)
+ if (im->index == idx)
+ return im->name;
+ snprintf(buf, 16, "if%d", idx);
+ return buf;
+}
+
+
+const char *ll_index_to_name(int idx)
+{
+ static char nbuf[16];
+
+ return ll_idx_n2a(idx, nbuf);
+}
+
+int ll_index_to_type(int idx)
+{
+ struct idxmap *im;
+
+ if (idx == 0)
+ return -1;
+ for (im = idxmap[idx&0xF]; im; im = im->next)
+ if (im->index == idx)
+ return im->type;
+ return -1;
+}
+
+unsigned ll_index_to_flags(int idx)
+{
+ struct idxmap *im;
+
+ if (idx == 0)
+ return 0;
+
+ for (im = idxmap[idx&0xF]; im; im = im->next)
+ if (im->index == idx)
+ return im->flags;
+ return 0;
+}
+
+int ll_name_to_index(char *name)
+{
+ static char ncache[16];
+ static int icache;
+ struct idxmap *im;
+ int i;
+
+ if (name == NULL)
+ return 0;
+ if (icache && strcmp(name, ncache) == 0)
+ return icache;
+ for (i=0; i<16; i++) {
+ for (im = idxmap[i]; im; im = im->next) {
+ if (strcmp(im->name, name) == 0) {
+ icache = im->index;
+ strcpy(ncache, name);
+ return im->index;
+ }
+ }
+ }
+ return 0;
+}
+
+int ll_init_map(struct rtnl_handle *rth)
+{
+ if (rtnl_wilddump_request(rth, AF_UNSPEC, RTM_GETLINK) < 0) {
+ perror("Cannot send dump request");
+ exit(1);
+ }
+
+ if (rtnl_dump_filter(rth, ll_remember_index, &idxmap, NULL, NULL) < 0) {
+ fprintf(stderr, "Dump terminated\n");
+ exit(1);
+ }
+ return 0;
+}
--- /dev/null
+#ifndef __LL_MAP_H__
+#define __LL_MAP_H__ 1
+
+extern int ll_remember_index(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
+extern int ll_init_map(struct rtnl_handle *rth);
+extern int ll_name_to_index(char *name);
+extern const char *ll_index_to_name(int idx);
+extern const char *ll_idx_n2a(int idx, char *buf);
+extern int ll_index_to_type(int idx);
+extern unsigned ll_index_to_flags(int idx);
+
+#endif /* __LL_MAP_H__ */
*
* Part: Main program structure.
*
- * Version: $Id: main.c,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: main.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
+ * Changes:
+ * Alexandre Cassen : 2001/06/25 : Rewritte the whole framework
+ * <+> Added scheduling framework using I/O multiplexer thread
+ * <+> Added syslog support
+ * <+> Change the signal handling
+ * Alexandre Cassen : 2000/12/09 : Initial release
+ *
* 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.
/* We then cleanup the room & closelog */
thread_destroy_master(master);
clear_services(conf_data->lvstopology);
+ /* Stop VRRP instances */
+ clear_vrrp_instance(conf_data->vrrp);
clear_conf(conf_data);
closelog();
pidfile_rm();
*
* Part: Main program include file.
*
- * Version: $Id: main.h,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: main.h,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
/* Build version */
#define PROG "keepalived"
-#define VERSION "0.3.8 (04/11, 2001)"
+#define VERSION "0.3.6 (10/08, 2001)"
#endif
*
* Part: pidfile utility.
*
- * Version: $Id: pidfile.c,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: pidfile.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
+ * Changes: Alexandre Cassen : 2001/06/25 : Initial release
+ *
* 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.
*
* Part: pidfile.c include file.
*
- * Version: $Id: pidfile.h,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: pidfile.h,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
+++ /dev/null
-#!/bin/sh
-# remove it as smbcheck.sh and put it the location you want
-
-SAMBA_BIN=`which smbclient 2> /dev/null`
-
-if [ -z "$SAMBA_BIN" ] ; then
- exit 2
-fi
-
-if [ -z "$1" ] ; then
- echo "Usage: $0 <ip address>"
- exit 2
-fi
-
-($SAMBA_BIN -N -L $1 -W CENTRALB -U nobody) \
- | egrep '^Domain=\[[A-Za-z0-9_-]+\]' > /dev/null 2>&1
-
* the thread management routine (thread.c) present in the
* very nice zebra project (http://www.zebra.org).
*
- * Version: $Id: scheduler.c,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: scheduler.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
+ * Changes: Alexandre Cassen : 2001/06/08 : Initial release
+ *
* 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.
break;
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);
- break;
default:
break;
}
register_worker_thread(struct thread_master *master, configuration_data *lstptr)
{
virtualserver *pointervs;
+ vrrp_instance *pointervrrp;
+
+ /* register VRRP specifics threads */
+ pointervrrp = lstptr->vrrp;
+ while (lstptr->vrrp) {
+ thread_add_event(master, vrrp_state_init_thread, lstptr->vrrp, VRRP_STATE_INIT);
+
+ lstptr->vrrp = (vrrp_instance *)lstptr->vrrp->next;
+ }
+ lstptr->vrrp = pointervrrp;
/* register VS specifics threads */
pointervs = lstptr->lvstopology;
*
* Part: scheduler.c include file.
*
- * Version: $Id: scheduler.h,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: scheduler.h,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
http_connect_thread(struct thread *thread);
extern int
-misc_check_thread(struct thread *thread);
+vrrp_state_init_thread(struct 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.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: smtp.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
+ * Changes: Alexandre Cassen : 2001/07/15 : Initial release
+ *
* 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.
*
* Part: smtp.c include file.
*
- * Version: $Id: smtp.h,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: smtp.h,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
*
* Part: General program utils.
*
- * Version: $Id: utils.c,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: utils.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
* Author: Alexandre Cassen, <acassen@linux-vs.org>
*
}
}
+char *ip_ntoa(uint32_t ip)
+{
+ static char buf[20];
+ unsigned char *bytep;
+ bytep = (unsigned char *) &(ip);
+ sprintf(buf, "%d.%d.%d.%d", bytep[0], bytep[1], bytep[2], bytep[3]);
+ return buf;
+}
-/*
- * 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.c include file.
- *
- * Version: $Id: utils.h,v 0.3.8 2001/11/04 21:41:32 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 _UTILES_H
#define _UTILES_H
/* system includes */
#include <stdio.h>
+#include <stdint.h>
/* Prototypes defs */
-void print_buffer(int count, char *buff);
+extern void print_buffer(int count, char *buff);
+extern char *ip_ntoa(uint32_t ip);
#endif
--- /dev/null
+/*
+ * Soft: Vrrpd is an 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.0 2001/08/24 00:35:19 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ * Based on the Jerome Etienne, <jetienne@arobas.net> code.
+ *
+ * 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.
+ */
+
+/* local include */
+#include "scheduler.h"
+#include "cfreader.h"
+#include "utils.h"
+#include "vrrp.h"
+
+/* local prototypes */
+static int vrrp_state_goto_master_thread(struct thread *thread);
+static int vrrp_state_master_thread(struct thread *thread);
+int vrrp_state_backup_thread(struct thread *thread);
+
+/* compute checksum */
+static u_short in_csum( u_short *addr, int len, u_short csum)
+{
+ register int nleft = len;
+ const u_short *w = addr;
+ register u_short answer;
+ register int sum = csum;
+
+ /*
+ * Our algorithm is simple, using a 32 bit accumulator (sum),
+ * we add sequential 16 bit words to it, and at the end, fold
+ * back all the carry bits from the top 16 bits into the lower
+ * 16 bits.
+ */
+ while (nleft > 1) {
+ sum += *w++;
+ nleft -= 2;
+ }
+
+ /* mop up an odd byte, if necessary */
+ if (nleft == 1)
+ sum += htons(*(u_char *)w << 8);
+
+ /*
+ * add back carry outs from top 16 bits to low 16 bits
+ */
+ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
+ sum += (sum >> 16); /* add carry */
+ answer = ~sum; /* truncate to 16 bits */
+ return (answer);
+}
+
+/* resolve ipaddress from interface name */
+static uint32_t ifname_to_ip(char *ifname)
+{
+ struct ifreq ifr;
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ uint32_t addr = 0;
+
+ if (fd < 0) return (-1);
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFADDR, (char *)&ifr) == 0) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)&ifr.ifr_addr;
+ addr = ntohl(sin->sin_addr.s_addr);
+ }
+
+ close(fd);
+ return addr;
+}
+
+/* resolve interface index from interface name */
+static int ifname_to_idx(char *ifname)
+{
+ struct ifreq ifr;
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ int ifindex = -1;
+
+ if (fd < 0) return (-1);
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ if (ioctl(fd, SIOCGIFINDEX, (char *)&ifr) == 0)
+ ifindex = ifr.ifr_ifindex;
+
+ close(fd);
+ return ifindex;
+}
+
+/* retrieve MAC options */
+static int rcvhwaddr_op(char *ifname, char *addr, int addrlen, int addF)
+{
+ struct ifreq ifr;
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ int ret;
+
+ if (fd < 0) return (-1);
+
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ memcpy( ifr.ifr_hwaddr.sa_data, addr, addrlen );
+ ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
+
+ ret = ioctl(fd, addF ? SIOCADDMULTI : SIOCDELMULTI, (char *)&ifr);
+ if (ret) {
+ syslog(LOG_INFO, "Can't %s on %s. errno=%d"
+ , addF ? "SIOCADDMULTI" : "SIOCDELMULTI"
+ , ifname, errno );
+ }
+ close(fd);
+ return ret;
+}
+
+/* Set MAC address - need to shutdown the interface before */
+static int hwaddr_set(char *ifname, char *addr, int addrlen)
+{
+ struct ifreq ifr;
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ int ret;
+ unsigned long flags;
+
+ if (fd < 0) return (-1);
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+
+ /* get the flags */
+ ret = ioctl(fd, SIOCGIFFLAGS, (char *)&ifr);
+ if (ret) goto end;
+ flags = ifr.ifr_flags;
+
+ /* set the interface down */
+ ifr.ifr_flags &= ~IFF_UP;
+ ret = ioctl(fd, SIOCSIFFLAGS, (char *)&ifr);
+ if(ret) goto end;
+
+ /* change the hwaddr */
+ memcpy(ifr.ifr_hwaddr.sa_data, addr, addrlen);
+ ifr.ifr_hwaddr.sa_family = AF_UNIX;
+ ret = ioctl(fd, SIOCSIFHWADDR, (char *)&ifr);
+ if(ret) goto end;
+
+ /* set the interface up */
+ ifr.ifr_flags = flags;
+ ret = ioctl(fd, SIOCSIFFLAGS, (char *)&ifr);
+ if(ret) goto end;
+
+end:;
+ if (ret) syslog(LOG_INFO, "MAC set : error errno=%d", errno);
+
+ close(fd);
+ return ret;
+}
+
+/* retrieve MAC address from interface name */
+static int hwaddr_get(char *ifname, char *addr, int addrlen)
+{
+ struct ifreq ifr;
+ int fd = socket(AF_INET, SOCK_DGRAM, 0);
+ int ret;
+
+ if (fd < 0) return (-1);
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
+ ret = ioctl(fd, SIOCGIFHWADDR, (char *)&ifr);
+ memcpy(addr, ifr.ifr_hwaddr.sa_data, addrlen);
+ close(fd);
+ return ret;
+}
+
+/* add/remove VIP */
+static int ipaddr_ops(vrrp_rt *vsrv, int addF)
+{
+ int i, err = 0;
+ int ifidx = ifname_to_idx(vsrv->vif->ifname);
+ struct in_addr in;
+
+ for(i = 0; i < vsrv->naddr; i++ ) {
+ vip_addr *vadd = &vsrv->vaddr[i];
+ if(!addF && !vadd->deletable) continue;
+
+ if (ipaddr_op(ifidx , vadd->addr, addF)) {
+ err = 1;
+ vadd->deletable = 0;
+ in.s_addr = htonl(vadd->addr);
+ syslog(LOG_INFO, "cant %s the address %s to %s\n"
+ , addF ? "set" : "remove"
+ , inet_ntoa(in)
+ , vsrv->vif->ifname);
+ } else {
+ vadd->deletable = 1;
+ }
+ }
+ return err;
+}
+
+/* ARP header length */
+static int vrrp_dlt_len( vrrp_rt *rt )
+{
+ return ETHER_HDR_LEN; /* hardcoded for ethernet */
+}
+
+/* IP header length */
+static int vrrp_iphdr_len(vrrp_rt *vsrv)
+{
+ return sizeof(struct iphdr);
+}
+
+/* IPSEC AH header length */
+static int vrrp_ipsecah_len(vrrp_rt *vsrv)
+{
+ return sizeof(ipsec_ah);
+}
+
+/* VRRP header length */
+static int vrrp_hd_len(vrrp_rt *vsrv)
+{
+ return sizeof(vrrp_pkt)
+ + vsrv->naddr*sizeof(uint32_t)
+ + VRRP_AUTH_LEN;
+}
+
+/*
+ * IPSEC AH incoming packet check.
+ * return 0 for a valid pkt, != 0 otherwise.
+ */
+static int vrrp_in_chk_ipsecah( vrrp_rt *vsrv, char *buffer)
+{
+ struct iphdr *ip = (struct iphdr*)(buffer);
+ ipsec_ah *ah = (ipsec_ah *)((char *)ip + (ip->ihl<<2));
+ unsigned char *digest;
+ uint32_t backup_auth_data[3];
+
+ /* first verify that the SPI value is equal to src IP */
+ if(ah->spi != ip->saddr) {
+ syslog(LOG_INFO, "IPSEC AH : invalid IPSEC SPI value. %d and expect %d"
+ , ip->saddr, ah->spi);
+ return 1;
+ }
+
+ /*
+ * then proceed with the sequence number to prevent against replay attack.
+ * in inbound processing, we increment seq_number counter to audit
+ * sender counter.
+ */
+ vsrv->ipsecah_counter->seq_number++;
+ if (ah->seq_number >= vsrv->ipsecah_counter->seq_number) {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "IPSEC AH : SEQUENCE NUMBER : %d\n", ah->seq_number);
+#endif
+ vsrv->ipsecah_counter->seq_number = ah->seq_number;
+ } else {
+ syslog(LOG_INFO, "IPSEC AH : sequence number %d already proceeded."
+ " Packet droped", ah->seq_number);
+ return 1;
+ }
+
+ /*
+ * 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 *));
+
+ /* zero the ip mutable fields */
+ ip->tos = 0;
+ ip->id = 0;
+ ip->frag_off = 0;
+ ip->check = 0;
+ memcpy(backup_auth_data, ah->auth_data, sizeof(ah->auth_data));
+ memset(ah->auth_data, 0, sizeof(ah->auth_data));
+
+ /* Compute the ICV */
+ hmac_md5(buffer, vrrp_iphdr_len(vsrv)+vrrp_ipsecah_len(vsrv)+vrrp_hd_len(vsrv),
+ vsrv->vif->auth_data, sizeof(vsrv->vif->auth_data), digest);
+
+ if (memcmp(backup_auth_data,digest,HMAC_MD5_TRUNC) != 0) {
+ syslog(LOG_INFO, "IPSEC AH : invalid IPSEC HMAC-MD5 value."
+ " Due to fields mutation or bad password !");
+ return 1;
+ }
+
+ free(digest);
+ return 0;
+}
+
+/* check if ipaddr is present in VIP buffer */
+static int vrrp_in_chk_vips(vrrp_rt *vsrv, uint32_t ipaddr, unsigned char *buffer)
+{
+ int i;
+ uint32_t ipbuf;
+
+ for (i=0; i < vsrv->naddr; i++) {
+ bcopy(buffer+i*sizeof(uint32_t),&ipbuf,sizeof(uint32_t));
+ if (ipaddr == ntohl(ipbuf)) return 1;
+ }
+
+ return 0;
+}
+
+/*
+ * VRRP incoming packet check.
+ * return 0 if the pkt is valid, != 0 otherwise.
+ */
+static int vrrp_in_chk(vrrp_rt *vsrv, char *buffer)
+{
+ struct iphdr *ip = (struct iphdr*)(buffer);
+ int ihl = ip->ihl << 2;
+ vrrp_if *vif = vsrv->vif;
+ ipsec_ah *ah;
+ vrrp_pkt *hd;
+ unsigned char *vips;
+ int i;
+
+ if (vif->auth_type == VRRP_AUTH_AH) {
+ ah = (ipsec_ah *)(buffer + sizeof(struct iphdr));
+ hd = (vrrp_pkt *)(buffer + ihl + vrrp_ipsecah_len(vsrv));
+ } else {
+ hd = (vrrp_pkt *)(buffer + ihl);
+ }
+
+ /* pointer to vrrp vips pkt zone */
+ vips = (unsigned char *)((char *)hd + sizeof(vrrp_pkt));
+
+ /* MUST verify that the IP TTL is 255 */
+ if( ip->ttl != VRRP_IP_TTL ) {
+ syslog(LOG_INFO, "invalid ttl. %d and expect %d"
+ , ip->ttl, VRRP_IP_TTL);
+ return VRRP_PACKET_KO;
+ }
+
+ /* MUST verify the VRRP version */
+ if ((hd->vers_type >> 4) != VRRP_VERSION) {
+ syslog(LOG_INFO, "invalid version. %d and expect %d"
+ , (hd->vers_type >> 4), VRRP_VERSION);
+ return VRRP_PACKET_KO;
+ }
+
+ /*
+ * MUST verify that the received packet length is greater than or
+ * equal to the VRRP header
+ */
+ if ((ntohs(ip->tot_len)-ihl) <= sizeof(vrrp_pkt)) {
+ syslog(LOG_INFO, "ip payload too short. %d and expect at least %d"
+ , ntohs(ip->tot_len)-ihl, sizeof(vrrp_pkt));
+ return VRRP_PACKET_KO;
+ }
+
+ /* MUST verify the VRRP checksum */
+ if (in_csum( (u_short*)hd, vrrp_hd_len(vsrv), 0)) {
+ syslog(LOG_INFO, "Invalid vrrp checksum");
+ return VRRP_PACKET_KO;
+ }
+
+ /*
+ * MUST perform authentication specified by Auth Type
+ * check the authentication type
+ */
+ if (vif->auth_type != hd->auth_type) {
+ syslog(LOG_INFO, "receive a %d auth, expecting %d!", vif->auth_type
+ , hd->auth_type);
+ return VRRP_PACKET_KO;
+ }
+
+ /* check the authentication if it is a passwd */
+ if (hd->auth_type == VRRP_AUTH_PASS) {
+ char *pw = (char *)ip + ntohs(ip->tot_len)
+ - sizeof(vif->auth_data);
+ if (memcmp( pw, vif->auth_data, sizeof(vif->auth_data))){
+ syslog(LOG_INFO, "receive an invalid passwd!");
+ return VRRP_PACKET_KO;
+ }
+ }
+
+ /* MUST verify that the VRID is valid on the receiving interface */
+ if (vsrv->vrid != hd->vrid)
+ return VRRP_PACKET_KO;
+
+ /*
+ * MAY verify that the IP address(es) associated with the
+ * VRID are valid
+ */
+ if (vsrv->naddr != hd->naddr) {
+ syslog(LOG_INFO, "receive an invalid ip number count associated with VRID!");
+ return VRRP_PACKET_KO;
+ }
+
+ for (i=0; i < vsrv->naddr; i++)
+ if (!vrrp_in_chk_vips(vsrv,vsrv->vaddr[i].addr,vips)) {
+ syslog(LOG_INFO, "ip address associated with VRID"
+ " not present in received packet : %d"
+ , vsrv->vaddr[i].addr);
+ syslog(LOG_INFO, "one or more VIP associated with"
+ " VRID mismatch actual MASTER advert");
+ return VRRP_PACKET_DROP;
+ }
+
+ /*
+ * MUST verify that the Adver Interval in the packet is the same as
+ * the locally configured for this virtual router
+ */
+ if (vsrv->adver_int/VRRP_TIMER_HZ != hd->adver_int) {
+ syslog(LOG_INFO, "advertissement interval mismatch mine=%d rcved=%d"
+ , vsrv->adver_int, hd->adver_int);
+ /* to prevent concurent VRID running => multiple master in 1 VRID */
+ return VRRP_PACKET_DROP;
+ }
+
+ /* check the authenicaion if it is ipsec ah */
+ if(hd->auth_type == VRRP_AUTH_AH)
+ return(vrrp_in_chk_ipsecah(vsrv,buffer));
+
+ return VRRP_PACKET_OK;
+}
+
+/* build ARP header */
+static void vrrp_build_dlt(vrrp_rt *vsrv, char *buffer, int buflen)
+{
+ /* hardcoded for ethernet */
+ struct ether_header * eth = (struct ether_header *)buffer;
+
+ /* destination address --rfc1122.6.4*/
+ eth->ether_dhost[0] = 0x01;
+ eth->ether_dhost[1] = 0x00;
+ eth->ether_dhost[2] = 0x5E;
+ eth->ether_dhost[3] = (INADDR_VRRP_GROUP >> 16) & 0x7F;
+ eth->ether_dhost[4] = (INADDR_VRRP_GROUP >> 8) & 0xFF;
+ eth->ether_dhost[5] = INADDR_VRRP_GROUP & 0xFF;
+
+ /* source address -- rfc2338.7.3 */
+ memcpy(eth->ether_shost, vsrv->hwaddr, sizeof(vsrv->hwaddr));
+
+ /* type */
+ eth->ether_type = htons(ETHERTYPE_IP);
+}
+
+/* build IP header */
+static void vrrp_build_ip(vrrp_rt *vsrv, char *buffer, int buflen)
+{
+ struct iphdr *ip = (struct iphdr *)(buffer);
+
+ ip->ihl = 5;
+ ip->version = 4;
+ ip->tos = 0;
+ ip->tot_len = ip->ihl*4 + vrrp_hd_len( vsrv );
+ ip->tot_len = htons(ip->tot_len);
+ ip->id = ++vsrv->vif->ip_id;
+ ip->frag_off = 0;
+ ip->ttl = VRRP_IP_TTL;
+
+ /* fill protocol type --rfc2402.2 */
+ ip->protocol = (vsrv->vif->auth_type == VRRP_AUTH_AH)?IPPROTO_IPSEC_AH:IPPROTO_VRRP;
+ ip->saddr = htonl(vsrv->vif->ipaddr);
+ ip->daddr = htonl(INADDR_VRRP_GROUP);
+
+ /* checksum must be done last */
+ ip->check = in_csum( (u_short*)ip, ip->ihl*4, 0 );
+}
+
+/* build IPSEC AH header */
+static void vrrp_build_ipsecah(vrrp_rt *vsrv, char *buffer, int buflen)
+{
+ ICV_mutable_fields *ip_mutable_fields;
+ unsigned char *digest;
+ struct iphdr *ip = (struct iphdr *)(buffer);
+ 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));
+
+ /* fill in next header filed --rfc2402.2.1 */
+ ah->next_header = IPPROTO_VRRP;
+
+ /* update IP header total length value */
+ ip->tot_len = ip->ihl*4 + vrrp_ipsecah_len( vsrv ) + vrrp_hd_len( vsrv );
+ ip->tot_len = htons(ip->tot_len);
+
+ /* update ip checksum */
+ ip->check = 0;
+ ip->check = in_csum((u_short*)ip, ip->ihl*4, 0);
+
+ /* backup the ip mutable fields */
+ ip_mutable_fields->tos = ip->tos;
+ ip_mutable_fields->id = ip->id;
+ ip_mutable_fields->frag_off = ip->frag_off;
+ ip_mutable_fields->check = ip->check;
+
+ /* zero the ip mutable fields */
+ ip->tos = 0;
+ ip->id = 0;
+ ip->frag_off = 0;
+ ip->check = 0;
+
+ /* fill in the Payload len field */
+ ah->payload_len = IPSEC_AH_PLEN;
+
+ /* The SPI value is filled with the ip header source address.
+ SPI uniquely identify the Security Association (SA). This value
+ is chosen by the recipient itself when setting up the SA. In a
+ multicast environment, this becomes unfeasible.
+
+ If left to the sender, the choice of the SPI value should be done
+ so by the sender that it cannot possibly conflict with SPI values
+ chosen by other entities sending IPSEC traffic to any of the receivers.
+ To overpass this problem, the rule I have chosen to implement here is
+ that the SPI value chosen by the sender is based on unique information
+ such as its IP address.
+ -- INTERNET draft : <draft-paridaens-xcast-sec-framework-01.txt>
+ */
+ ah->spi = ip->saddr;
+
+ /* Processing sequence number.
+ Cycled assumed if 0xFFFFFFFD reached. So the MASTER state is free for another srv.
+ Here can result a flapping MASTER state owner when max seq_number value reached.
+ => Much work needed here.
+ In the current implementation if counter has cycled, we stop sending adverts and
+ become BACKUP. If all the master are down we reset the counter for becoming MASTER.
+ */
+// if (vsrv->ipsecah_counter->seq_number > 5) {
+ if (vsrv->ipsecah_counter->seq_number > 0xFFFFFFFD) {
+ vsrv->ipsecah_counter->cycle = 1;
+ } else {
+ vsrv->ipsecah_counter->seq_number++;
+ }
+
+ ah->seq_number = vsrv->ipsecah_counter->seq_number;
+
+ /* Compute the ICV & trunc the digest to 96bits
+ => 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 *));
+ hmac_md5(buffer, buflen,vsrv->vif->auth_data, sizeof(vsrv->vif->auth_data), digest);
+ memcpy(ah->auth_data, digest, HMAC_MD5_TRUNC);
+
+ /* Restore the ip mutable fields */
+ ip->tos = ip_mutable_fields->tos;
+ ip->id = ip_mutable_fields->id;
+ ip->frag_off = ip_mutable_fields->frag_off;
+ ip->check = ip_mutable_fields->check;
+
+ free(ip_mutable_fields);
+ free(digest);
+}
+
+/* build VRRP header */
+static int vrrp_build_vrrp(vrrp_rt *vsrv, int prio, char *buffer, int buflen)
+{
+ int i;
+ vrrp_if *vif = vsrv->vif;
+ vrrp_pkt *hd = (vrrp_pkt *)buffer;
+ uint32_t *iparr = (uint32_t *)((char *)hd+sizeof(*hd));
+
+ hd->vers_type = (VRRP_VERSION<<4) | VRRP_PKT_ADVERT;
+ hd->vrid = vsrv->vrid;
+ hd->priority = prio;
+ hd->naddr = vsrv->naddr;
+ hd->auth_type = vsrv->vif->auth_type;
+ hd->adver_int = vsrv->adver_int/VRRP_TIMER_HZ;
+
+ /* copy the ip addresses */
+ for( i = 0; i < vsrv->naddr; i++ ){
+ iparr[i] = htonl( vsrv->vaddr[i].addr );
+ }
+ hd->chksum = in_csum( (u_short*)hd, vrrp_hd_len(vsrv), 0);
+
+ /* copy the passwd if the authentication is VRRP_AH_PASS */
+ if( vif->auth_type == VRRP_AUTH_PASS ){
+ char *pw = (char *)hd+sizeof(*hd)+vsrv->naddr*4;
+ memcpy( pw, vif->auth_data, sizeof(vif->auth_data));
+ }
+
+ return(0);
+}
+
+/* build VRRP packet */
+static void vrrp_build_pkt( vrrp_rt *vsrv, int prio, char *buffer, int buflen )
+{
+ char *bufptr;
+
+ bufptr = buffer;
+
+ /* build the ethernet header */
+ vrrp_build_dlt(vsrv, buffer, buflen);
+
+ /* build the ip header */
+ buffer += vrrp_dlt_len(vsrv);
+ buflen -= vrrp_dlt_len(vsrv);
+ vrrp_build_ip( vsrv, buffer, buflen );
+
+ /* build the vrrp header */
+ buffer += vrrp_iphdr_len(vsrv);
+
+ if (vsrv->vif->auth_type == VRRP_AUTH_AH)
+ buffer += vrrp_ipsecah_len(vsrv);
+ buflen -= vrrp_iphdr_len(vsrv);
+
+ if (vsrv->vif->auth_type == VRRP_AUTH_AH)
+ buflen -= vrrp_ipsecah_len(vsrv);
+ vrrp_build_vrrp(vsrv, prio, buffer, buflen);
+
+ /* build the IPSEC AH header */
+ if (vsrv->vif->auth_type == VRRP_AUTH_AH) {
+ bufptr += vrrp_dlt_len(vsrv);
+ buflen += vrrp_ipsecah_len(vsrv) + vrrp_iphdr_len(vsrv);;
+ vrrp_build_ipsecah(vsrv, bufptr, buflen);
+ }
+}
+
+/* send VRRP packet */
+static int vrrp_send_pkt(vrrp_rt *vsrv, char *buffer, int buflen)
+{
+ struct sockaddr from;
+ int len;
+ int fd = socket(PF_PACKET, SOCK_PACKET, 0x300); /* 0x300 is magic */
+
+ if( fd < 0 ){
+ syslog(LOG_DEBUG, "VRRP Error : socket creation");
+ return -1;
+ }
+
+ /* build the address */
+ memset(&from, 0 , sizeof(from));
+ strcpy( from.sa_data, vsrv->vif->ifname );
+
+ /* send the data */
+ len = sendto(fd, buffer, buflen, 0, &from, sizeof(from));
+
+ close( fd );
+ return len;
+}
+
+/* send VRRP advertissement */
+static int vrrp_send_adv(vrrp_rt *vsrv, int prio)
+{
+ int buflen, ret;
+ char *buffer;
+
+ /* alloc the memory */
+ 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(vsrv);
+ buffer = calloc(buflen, 1);
+ memset(buffer,0,buflen);
+
+ /* build the packet */
+ vrrp_build_pkt(vsrv, prio, buffer, buflen);
+
+ /* send it */
+ ret = vrrp_send_pkt(vsrv, buffer, buflen);
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Sending VRRP Advert on %s", vsrv->vif->ifname);
+// printf("Sending on : %s : fd :%d\n", vsrv->vif->ifname,vsrv->sockfd);
+// print_buffer(buflen,buffer);
+#endif
+
+ /* free the memory */
+ free(buffer);
+ return ret;
+}
+
+
+/* Received packet processing */
+static int vrrp_read(vrrp_rt *vsrv, char *buf, int buflen)
+{
+ int len = 0;
+ int ret;
+
+ len = read(vsrv->sockfd, buf, buflen);
+
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "VRRP packet received (%d bytes)", len);
+// print_buffer(buflen,buf);
+#endif
+
+ if (len > 0) {
+ ret = vrrp_in_chk(vsrv, buf);
+
+ if (ret == VRRP_PACKET_KO || ret == VRRP_PACKET_DROP)
+ syslog(LOG_INFO, "bogus VRRP packet received !!!");
+
+ return ret;
+ }
+
+ return VRRP_PACKET_NULL;
+}
+
+/* send a gratuitous ARP packet */
+static int send_gratuitous_arp(vrrp_rt *vsrv, int addr, int vAddrF)
+{
+ struct m_arphdr {
+ unsigned short int ar_hrd; /* Format of hardware address. */
+ unsigned short int ar_pro; /* Format of protocol address. */
+ unsigned char ar_hln; /* Length of hardware address. */
+ unsigned char ar_pln; /* Length of protocol address. */
+ unsigned short int ar_op; /* ARP opcode (command). */
+ /* Ethernet looks like this : This bit is variable sized however... */
+ unsigned char __ar_sha[ETH_ALEN]; /* Sender hardware address. */
+ unsigned char __ar_sip[4]; /* Sender IP address. */
+ unsigned char __ar_tha[ETH_ALEN]; /* Target hardware address. */
+ unsigned char __ar_tip[4]; /* Target IP address. */
+ };
+
+ char buf[sizeof(struct m_arphdr)+ETHER_HDR_LEN];
+ char buflen = sizeof(struct m_arphdr)+ETHER_HDR_LEN;
+ struct ether_header *eth = (struct ether_header *)buf;
+ struct m_arphdr *arph = (struct m_arphdr *)(buf+vrrp_dlt_len(vsrv));
+ char *hwaddr = vAddrF ? vsrv->hwaddr : vsrv->vif->hwaddr;
+ int hwlen = ETH_ALEN;
+
+ /* hardcoded for ethernet */
+ memset(eth->ether_dhost, 0xFF, ETH_ALEN);
+ memcpy(eth->ether_shost, hwaddr, hwlen);
+ eth->ether_type = htons(ETHERTYPE_ARP);
+
+ /* build the arp payload */
+ memset(arph, 0, sizeof( *arph ));
+ arph->ar_hrd = htons(ARPHRD_ETHER);
+ arph->ar_pro = htons(ETHERTYPE_IP);
+ arph->ar_hln = 6;
+ arph->ar_pln = 4;
+ arph->ar_op = htons(ARPOP_REQUEST);
+ memcpy(arph->__ar_sha, hwaddr, hwlen);
+ addr = htonl(addr);
+ memcpy(arph->__ar_sip, &addr, sizeof(addr));
+ memcpy(arph->__ar_tip, &addr, sizeof(addr));
+ return vrrp_send_pkt(vsrv, buf, buflen);
+}
+
+/* becoming master */
+static int vrrp_state_goto_master_thread(struct thread *thread)
+{
+ int i;
+ vrrp_instance *vrrp_instance = THREAD_ARG(thread);
+ vrrp_rt *vsrv = vrrp_instance->vsrv;
+ vrrp_if *vif = vsrv->vif;
+ struct rt_entry *rt_table;
+
+ /* set the VRRP MAC address -- rfc2338.7.3 */
+ if(!vsrv->no_vmac) {
+ /* backup the routing table */
+ rt_table = iproute_list(vif->ifname);
+
+ hwaddr_set(vif->ifname, vsrv->hwaddr, sizeof(vsrv->hwaddr));
+ rcvhwaddr_op(vif->ifname, vif->hwaddr, sizeof(vif->hwaddr), 1);
+
+ /* restore routing table */
+ iproute_restore(rt_table, vif->ifname);
+ iproute_clear(rt_table);
+ }
+
+ /* add the ip addresses */
+ ipaddr_ops(vsrv, 1);
+
+ /* send an advertisement */
+ vrrp_send_adv(vsrv, vsrv->priority);
+
+ /* send gratuitous arp for each virtual ip */
+ for (i = 0; i < vsrv->naddr; i++)
+ send_gratuitous_arp(vsrv, vsrv->vaddr[i].addr, 1);
+
+ syslog(LOG_INFO, "VRRP_Instance(%s) entering MASTER STATE"
+ , vrrp_instance->iname);
+
+ /* register master state thread */
+ vsrv->state = VRRP_STATE_MAST;
+ thread_add_read(thread->master, vrrp_state_master_thread, vrrp_instance,
+ vsrv->sockfd, vsrv->adver_int);
+
+ return 0;
+}
+
+/* leaving master state */
+static void vrrp_restore_interface(vrrp_rt *vsrv, int advF)
+{
+ uint32_t addr[1024];
+ vrrp_if *vif = vsrv->vif;
+ struct rt_entry *rt_table;
+
+ /* restore the original MAC addresses */
+ if (!vsrv->no_vmac) {
+ /* backup the routing table */
+ rt_table = iproute_list(vif->ifname);
+
+ hwaddr_set(vif->ifname, vif->hwaddr, sizeof(vif->hwaddr));
+ rcvhwaddr_op(vif->ifname, vif->hwaddr, sizeof(vif->hwaddr), 0);
+
+ /* restore routing table */
+ iproute_restore(rt_table, vif->ifname);
+ iproute_clear(rt_table);
+ }
+
+ /* remove the ip addresses */
+ ipaddr_ops(vsrv, 0);
+
+ /* if we stop vrrpd, warn the other routers to speed up the recovery */
+ if (advF) {
+ vrrp_send_adv(vsrv, VRRP_PRIO_STOP);
+ }
+
+ /*
+ * Send gratuitous ARP for all the non-vrrp ip addresses to update
+ * the cache of remote hosts using these addresses
+ */
+ if (!vsrv->no_vmac) {
+ int i, naddr;
+ naddr = ipaddr_list(ifname_to_idx(vif->ifname), addr
+ , sizeof(addr)/sizeof(addr[0]));
+ for (i = 0; i < naddr; i++)
+ send_gratuitous_arp(vsrv, addr[i], 0);
+ }
+}
+
+static int vrrp_state_leave_master_thread(struct thread *thread)
+{
+ vrrp_instance *vrrp_instance = THREAD_ARG(thread);
+ vrrp_rt *vsrv = vrrp_instance->vsrv;
+
+ /* restore the routing table & remove VIPs */
+ vrrp_restore_interface(vsrv, 0);
+
+ syslog(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE"
+ , vrrp_instance->iname);
+
+ /* register the vrrp backup handler */
+ vsrv->state = VRRP_STATE_BACK;
+ thread_add_read(thread->master, vrrp_state_backup_thread, vrrp_instance,
+ vsrv->sockfd, vsrv->ms_down_timer);
+ return 0;
+}
+
+/* BACKUP state processing */
+int vrrp_state_backup_thread(struct thread *thread)
+{
+ char *buf;
+ int ret = 0;
+ int buflen = 0;
+ struct iphdr *iph;
+ vrrp_pkt *hd;
+ vrrp_instance *vrrp_instance = THREAD_ARG(thread);
+ vrrp_rt *vsrv = vrrp_instance->vsrv;
+
+//printf("-----[ %s ]------\nBACKUP STATE fd : %d\n", vrrp_instance->iname, thread->u.fd);
+
+ if (thread->type == THREAD_READ_TIMEOUT) {
+
+ /* If becoming MASTER in IPSEC AH AUTH, we reset the anti-replay */
+ if (vsrv->ipsecah_counter->cycle) {
+ vsrv->ipsecah_counter->cycle = 0;
+ vsrv->ipsecah_counter->seq_number = 0;
+ }
+
+ /* register the vrrp transit backup state */
+ vsrv->state = VRRP_STATE_BACK;
+ thread_add_event(thread->master, vrrp_state_goto_master_thread,
+ vrrp_instance, VRRP_STATE_MAST);
+
+ syslog(LOG_INFO, "VRRP_Instance(%s) becoming MASTER"
+ , vrrp_instance->iname);
+ } else {
+ /* buffer allocation */
+ if(vsrv->vif->auth_type == VRRP_AUTH_AH) {
+ buflen = vrrp_iphdr_len(vsrv) + vrrp_ipsecah_len(vsrv) + vrrp_hd_len(vsrv);
+ buf = calloc(buflen,1);
+ memset(buf,0,buflen);
+
+ /* fill the header structure */
+ ret = vrrp_read(vsrv, buf, buflen);
+ iph = (struct iphdr *)buf;
+ hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2) + vrrp_ipsecah_len(vsrv));
+ } else {
+ buflen = vrrp_iphdr_len(vsrv) + vrrp_hd_len(vsrv);
+ buf = calloc(buflen, 1);
+ memset(buf,0,buflen);
+
+ /* fill the header structure */
+ ret = vrrp_read( vsrv, buf, buflen );
+ iph = (struct iphdr *)buf;
+ hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2));
+ }
+
+ if (ret == VRRP_PACKET_KO ||
+ ret == VRRP_PACKET_NULL ||
+ ret == VRRP_PACKET_DROP) {
+ syslog(LOG_INFO, "Dropping received advertisment...\n");
+ vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
+ } else if (hd->priority == 0) {
+ vsrv->ms_down_timer = VRRP_TIMER_SKEW(vsrv);
+ } else if( !vsrv->preempt || hd->priority >= vsrv->priority ) {
+ vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
+ }
+
+ /* register next vrrp master thread */
+ thread_add_read(thread->master, vrrp_state_backup_thread, vrrp_instance,
+ thread->u.fd, vsrv->ms_down_timer);
+
+ free(buf);
+ }
+
+ return 0;
+}
+
+/* MASTER state processing */
+static int vrrp_state_master_thread(struct thread *thread)
+{
+ char *buf;
+ int ret = 0;
+ int buflen = 0;
+ struct iphdr *iph;
+ vrrp_pkt *hd;
+ vrrp_instance *vrrp_instance = THREAD_ARG(thread);
+ vrrp_rt *vsrv = vrrp_instance->vsrv;
+
+//printf("-----[ %s ]------\nMASTER STATE fd : %d\n", vrrp_instance->iname, thread->u.fd);
+
+ if (thread->type == THREAD_READ_TIMEOUT) {
+
+ if (vsrv->wantstate == VRRP_STATE_BACK ||
+ vsrv->ipsecah_counter->cycle) {
+ vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
+
+ /* register the vrrp transit backup state */
+ vsrv->state = VRRP_STATE_BACK;
+ thread_add_event(thread->master, vrrp_state_leave_master_thread,
+ vrrp_instance, VRRP_STATE_BACK);
+
+ syslog(LOG_INFO, "VRRP_Instance(%s) becoming BACKUP"
+ , vrrp_instance->iname);
+ }
+
+ vrrp_send_adv(vsrv, vsrv->priority);
+
+ /* register next vrrp master thread */
+ thread_add_read(thread->master, vrrp_state_master_thread, vrrp_instance,
+ thread->u.fd, vsrv->adver_int);
+ } else {
+ /* buffer allocation */
+ if (vsrv->vif->auth_type == VRRP_AUTH_AH) {
+ buflen = vrrp_iphdr_len(vsrv) + vrrp_ipsecah_len(vsrv) + vrrp_hd_len(vsrv);
+ buf = calloc(buflen,1);
+ memset(buf,0,buflen);
+
+ /* fill the header structure */
+ ret = vrrp_read(vsrv, buf, buflen);
+ iph = (struct iphdr *)buf;
+ hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2) + vrrp_ipsecah_len(vsrv));
+ } else {
+ buflen = vrrp_iphdr_len(vsrv) + vrrp_hd_len(vsrv);
+ buf = calloc(buflen, 1);
+ memset(buf,0,buflen);
+
+ /* fill the header structure */
+ ret = vrrp_read(vsrv, buf, buflen);
+ iph = (struct iphdr *)buf;
+ hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2));
+ }
+
+ if (ret == VRRP_PACKET_KO ||
+ ret == VRRP_PACKET_NULL ||
+ ret == VRRP_PACKET_DROP) {
+ syslog(LOG_INFO, "Dropping received VRRP packet...\n");
+ vrrp_send_adv(vsrv, vsrv->priority);
+
+ /* register next vrrp master thread */
+ thread_add_read(thread->master, vrrp_state_master_thread, vrrp_instance,
+ thread->u.fd, vsrv->adver_int);
+
+ } else if (hd->priority == 0) {
+ vrrp_send_adv(vsrv, vsrv->priority);
+
+ /* register next vrrp master thread */
+ thread_add_read(thread->master, vrrp_state_master_thread, vrrp_instance,
+ thread->u.fd, vsrv->adver_int);
+
+ } else if( hd->priority > vsrv->priority ||
+ (hd->priority == vsrv->priority &&
+ ntohl(iph->saddr) > vsrv->vif->ipaddr)) {
+
+ vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
+
+ /* register the vrrp transit backup state */
+ vsrv->state = VRRP_STATE_BACK;
+ thread_add_event(thread->master, vrrp_state_leave_master_thread,
+ vrrp_instance, VRRP_STATE_BACK);
+ }
+ free(buf);
+ }
+
+ return 0;
+}
+
+/* check for minimum configuration requirements */
+static int chk_min_cfg(vrrp_rt *vsrv)
+{
+ if( vsrv->naddr == 0 ){
+ syslog(LOG_INFO, "provide at least one ip for the virtual server");
+ return 0;
+ }
+ if( vsrv->vrid == 0 ){
+ syslog(LOG_INFO, "the virtual id must be set!");
+ return 0;
+ }
+ if( vsrv->vif->ipaddr == 0 ){
+ syslog(LOG_INFO, "the interface ipaddr must be set!");
+ return 0;
+ }
+
+ /* vrrp structure is completed */
+ vsrv->initF = 1;
+
+ return 1;
+}
+
+/* compute vrrp structure */
+int complete_vrrp_init(vrrp_rt *vsrv)
+{
+ vrrp_if *vif = vsrv->vif;
+
+ /* complete the VMAC address */
+ vsrv->hwaddr[0] = 0x00;
+ vsrv->hwaddr[1] = 0x00;
+ vsrv->hwaddr[2] = 0x5E;
+ vsrv->hwaddr[3] = 0x00;
+ vsrv->hwaddr[4] = 0x01;
+ vsrv->hwaddr[5] = vsrv->vrid;
+
+ /* get the ip address */
+ vif->ipaddr = ifname_to_ip(vif->ifname);
+ if (!vif->ipaddr) {
+ syslog(LOG_INFO, "VRRP Error : no interface found : %s !\n", vif->ifname);
+ return 0;
+ }
+ /* get the hwaddr */
+ if (hwaddr_get(vif->ifname, vif->hwaddr, sizeof(vif->hwaddr))) {
+ syslog(LOG_INFO, "VRRP Error : Unreadable MAC"
+ "address for interface : %s !\n", vif->ifname);
+ return 0;
+ }
+
+ vsrv->state = VRRP_STATE_INIT;
+ if (!vsrv->adver_int) vsrv->adver_int = VRRP_ADVER_DFL * VRRP_TIMER_HZ;
+ if (!vsrv->priority) vsrv->priority = VRRP_PRIO_DFL;
+ if (!vsrv->preempt) vsrv->preempt = VRRP_PREEMPT_DFL;
+
+ return(chk_min_cfg(vsrv));
+}
+
+/* open the socket and join the multicast group. */
+static int open_vrrp_socket(vrrp_rt *vsrv)
+{
+ struct ip_mreq req;
+ struct ip_mreqn interface;
+ u_char loop;
+ int fd;
+ int ret;
+
+ /* open the socket */
+ if (vsrv->vif->auth_type == VRRP_AUTH_AH)
+ fd = socket(AF_INET, SOCK_RAW, IPPROTO_IPSEC_AH);
+ else
+ fd = socket(AF_INET, SOCK_RAW, IPPROTO_VRRP);
+
+ if(fd < 0){
+ int err = errno;
+ syslog(LOG_INFO, "cant open raw socket. errno=%d. (try to run it as root)"
+ , err);
+ return -1;
+ }
+
+ /* join the multicast group */
+ memset(&req, 0, sizeof (req));
+ req.imr_multiaddr.s_addr = htonl(INADDR_VRRP_GROUP);
+ req.imr_interface.s_addr = htonl(vsrv->vif->ipaddr);
+ ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP,
+ (char *)&req, sizeof(struct ip_mreq));
+
+ /* disable loop back to local socket */
+ loop = 0;
+// setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop));
+
+ if (ret < 0) {
+ int err = errno;
+ syslog(LOG_INFO, "cant do IP_ADD_MEMBERSHIP errno=%d", err);
+ return -1;
+ }
+#ifdef DEBUG
+ else {
+ syslog(LOG_DEBUG, "VRRP socket successfully created...");
+ }
+#endif
+
+ /* binding the socket to the local interface */
+ memset(&interface, 0, sizeof(interface));
+ interface.imr_multiaddr.s_addr = htonl(INADDR_VRRP_GROUP);
+ interface.imr_address.s_addr = htonl(vsrv->vif->ipaddr);
+ interface.imr_ifindex = ifname_to_idx(vsrv->vif->ifname);
+ ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_IF,
+ &interface, sizeof(struct ip_mreqn));
+
+ if (ret < 0) {
+ int err = errno;
+ syslog(LOG_INFO, "cant bind socket to interface errno=%d", err);
+ return -1;
+ }
+
+ return fd;
+}
+
+/*
+ * Initialize state handling
+ * --rfc2338.6.4.1
+ */
+int vrrp_state_init_thread(struct thread *thread)
+{
+ vrrp_instance *vrrp_instance = THREAD_ARG(thread);
+ vrrp_rt *vsrv = vrrp_instance->vsrv;
+ int fd;
+
+ /* create the socket */
+ fd = open_vrrp_socket(vsrv);
+ if (fd < 0) return -1;
+
+ vsrv->sockfd = fd;
+
+ if (vsrv->priority == VRRP_PRIO_OWNER ||
+ vsrv->wantstate == VRRP_STATE_MAST){
+ thread_add_event(thread->master, vrrp_state_goto_master_thread,
+ vrrp_instance, VRRP_STATE_MAST);
+ } else {
+ vsrv->ms_down_timer = 3 * vsrv->adver_int + VRRP_TIMER_SKEW(vsrv);
+
+ syslog(LOG_INFO, "VRRP_Instance(%s) Entering BACKUP STATE"
+ , vrrp_instance->iname);
+
+ /* register the vrrp backup handler */
+ vsrv->state = VRRP_STATE_BACK;
+ thread_add_read(thread->master, vrrp_state_backup_thread,
+ vrrp_instance, fd, vsrv->ms_down_timer);
+ }
+
+ return 0;
+}
+
+/* handle terminate state */
+void vrrp_state_stop_instance(vrrp_rt *vsrv)
+{
+ /* restore MAC, routing table & remove VIPs */
+ vrrp_restore_interface(vsrv, 1);
+}
--- /dev/null
+/*
+ * Soft: Vrrpd is an 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.h,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ * Based on the Jerome Etienne, <jetienne@arobas.net> code.
+ *
+ * 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 _VRRP_H
+#define _VRRP_H
+
+/* system include */
+#include <net/ethernet.h>
+#include <netinet/ip.h>
+#include <net/if.h>
+#include <net/if_arp.h>
+#include <sys/ioctl.h>
+
+/* local include */
+#include "vrrp_iproute.h"
+#include "vrrp_ipaddress.h"
+#include "vrrp_ipsecah.h"
+
+typedef struct { /* rfc2338.5.1 */
+ uint8_t vers_type; /* 0-3=type, 4-7=version */
+ uint8_t vrid; /* virtual router id */
+ uint8_t priority; /* router priority */
+ uint8_t naddr; /* address counter */
+ uint8_t auth_type; /* authentification type */
+ uint8_t adver_int; /* advertissement interval(in sec) */
+ uint16_t chksum; /* checksum (ip-like one) */
+/* here <naddr> ip addresses */
+/* here authentification infos */
+} vrrp_pkt;
+
+/* protocol constants */
+#define INADDR_VRRP_GROUP 0xe0000012 /* multicast addr - rfc2338.5.2.2 */
+#define VRRP_IP_TTL 255 /* in and out pkt ttl -- rfc2338.5.2.3 */
+#define IPPROTO_VRRP 112 /* IP protocol number -- rfc2338.5.2.4*/
+#define VRRP_VERSION 2 /* current version -- rfc2338.5.3.1 */
+#define VRRP_PKT_ADVERT 1 /* packet type -- rfc2338.5.3.2 */
+#define VRRP_PRIO_OWNER 255 /* priority of the ip owner -- rfc2338.5.3.4 */
+#define VRRP_PRIO_DFL 100 /* default priority -- rfc2338.5.3.4 */
+#define VRRP_PRIO_STOP 0 /* priority to stop -- rfc2338.5.3.4 */
+#define VRRP_AUTH_NONE 0 /* no authentification -- rfc2338.5.3.6 */
+#define VRRP_AUTH_PASS 1 /* password authentification -- rfc2338.5.3.6 */
+#define VRRP_AUTH_AH 2 /* AH(IPSec) authentification - rfc2338.5.3.6 */
+#define VRRP_ADVER_DFL 1 /* advert. interval (in sec) -- rfc2338.5.3.7 */
+#define VRRP_PREEMPT_DFL 1 /* rfc2338.6.1.2.Preempt_Mode */
+
+typedef struct { /* parameters per interface -- rfc2338.6.1.1 */
+ int auth_type; /* authentification type. VRRP_AUTH_* */
+ uint8_t auth_data[8]; /* authentification data */
+
+ uint32_t ipaddr; /* the address of the interface */
+ char hwaddr[6]; /* hardcoded for ethernet */
+ char ifname[10]; /* the device name for this ipaddr */
+ /*
+ * To have my own ip_id creates collision with kernel ip->id
+ * but it should be ok because the packets are unlikely to be
+ * fragmented (they are non routable and small)
+ * This packet isnt routed, i can check the outgoing MTU
+ * to warn the user only if the outoing mtu is too small
+ */
+ int ip_id;
+
+} vrrp_if;
+
+typedef struct {
+ uint32_t addr; /* the ip address */
+ int deletable; /* TRUE if one of my primary addr */
+} vip_addr;
+
+typedef struct { /* parameters per virtual router -- rfc2338.6.1.2 */
+ int vrid; /* virtual id. from 1(!) to 255 */
+ int priority; /* priority value */
+ int naddr; /* number of ip addresses */
+ vip_addr *vaddr; /* point on the ip address array */
+ int adver_int; /* delay between advertisements(in sec) */
+ char hwaddr[6]; /* VMAC -- rfc2338.7.3 */
+
+#if 0 /* dynamically calculated */
+ double skew_time; /* skew Master_Down_Interval. (256-Prio)/256 */
+ int mast_down_int; /* interval for backup to declare master down*/
+#endif
+ int preempt; /* true if a higher prio preempt a lower one */
+ int state; /* internal state (init/backup/master) */
+ int wantstate; /* user explicitly wants a state (back/mast) */
+ int sockfd; /* the socket descriptor */
+ int initF; /* true if the struct is init */
+ int no_vmac; /* dont handle the virtual MAC --rfc2338.7.3 */
+
+ /* rfc2336.6.2 */
+ uint32_t ms_down_timer;
+ uint32_t adver_timer;
+
+ /* IPSEC AH counter def --rfc2402.3.3.2 */
+ seq_counter *ipsecah_counter;
+
+ /* interface parameters */
+ vrrp_if *vif;
+} vrrp_rt;
+
+/* VRRP state machine -- rfc2338.6.4 */
+#define VRRP_STATE_INIT 1 /* rfc2338.6.4.1 */
+#define VRRP_STATE_BACK 2 /* rfc2338.6.4.2 */
+#define VRRP_STATE_MAST 3 /* rfc2338.6.4.3 */
+#define VRRP_STATE_NONE 99 /* internal */
+
+/* VRRP packet handling */
+#define VRRP_PACKET_OK 0
+#define VRRP_PACKET_KO 1
+#define VRRP_PACKET_DROP 2
+#define VRRP_PACKET_NULL 3
+
+#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_TIMER_HZ 1000000
+#define VRRP_TIMER_SKEW( srv ) ((256-(srv)->priority)*VRRP_TIMER_HZ/256)
+
+#define VRRP_MIN( a , b ) ( (a) < (b) ? (a) : (b) )
+#define VRRP_MAX( a , b ) ( (a) > (b) ? (a) : (b) )
+
+/* prototypes */
+extern int complete_vrrp_init(vrrp_rt *vsrv);
+extern void vrrp_state_stop_instance(vrrp_rt *vsrv);
+
+#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: 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_ipaddress.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * Changes: Alexandre Cassen : 2001/08/20 Initial release
+ *
+ * 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.
+ */
+
+/* local include */
+#include "vrrp_ipaddress.h"
+#include "libnetlink/libnetlink.h"
+
+static int get_addrinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ struct ifaddrmsg *ifa = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ iplist_ctx *ctx = (iplist_ctx *)arg;
+ struct rtattr *rta_tb[IFA_MAX+1];
+
+ /* sanity check */
+ len -= NLMSG_LENGTH(sizeof(*ifa));
+ if (len < 0) {
+ syslog(LOG_INFO, "IPADDRESS : BUG: wrong nlmsg len %d", len);
+ return -1;
+ }
+
+ /* check the message type */
+ if (n->nlmsg_type != RTM_NEWADDR)
+ return 0;
+ /* check it is ipv4 */
+ if( ifa->ifa_family != AF_INET)
+ return 0;
+
+ /* check it is the good interface */
+ if(ifa->ifa_index != ctx->ifindex)
+ return 0;
+
+ /* parse the attribute */
+ memset(rta_tb, 0, sizeof(rta_tb));
+ parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), len);
+
+ if (!rta_tb[IFA_LOCAL])
+ rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS];
+
+ if (rta_tb[IFA_LOCAL]) {
+ u_char *src = RTA_DATA(rta_tb[IFA_LOCAL]);
+ if( ctx->nb_elem >= ctx->max_elem )
+ return 0;
+ ctx->addr[ctx->nb_elem++] = (src[0]<<24) + (src[1]<<16) +
+ (src[2]<<8) + src[3];
+ }
+ return 0;
+}
+
+int ipaddr_list( int ifindex, uint32_t *array, int max_elem )
+{
+ struct rtnl_handle rth;
+ iplist_ctx ctx;
+
+ /* init the struct */
+ ctx.ifindex = ifindex;
+ ctx.addr = array;
+ ctx.max_elem = max_elem;
+ ctx.nb_elem = 0;
+
+ /* open the rtnetlink socket */
+ if( rtnl_open( &rth, 0) )
+ return -1;
+
+ /* send the request */
+ if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETADDR) < 0) {
+ syslog(LOG_INFO, "IPADDRESS : Cannot send dump request");
+ return -1;
+ }
+
+ /* parse the answer */
+ if (rtnl_dump_filter(&rth, get_addrinfo, &ctx, NULL, NULL) < 0) {
+ syslog(LOG_INFO, "IPADDRESS : Flush terminated");
+ exit(1);
+ }
+
+ /* to close the clocket */
+ rtnl_close(&rth);
+
+ return ctx.nb_elem;
+}
+
+int ipaddr_op(int ifindex, uint32_t addr, int addF)
+{
+ struct rtnl_handle rth;
+ struct {
+ struct nlmsghdr n;
+ struct ifaddrmsg ifa;
+ char buf[256];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = addF ? RTM_NEWADDR : RTM_DELADDR;
+ req.ifa.ifa_family = AF_INET;
+ req.ifa.ifa_index = ifindex;
+ req.ifa.ifa_prefixlen = 32;
+
+ addr = htonl(addr);
+ addattr_l(&req.n, sizeof(req), IFA_LOCAL, &addr, sizeof(addr));
+
+ if (rtnl_open(&rth, 0) < 0)
+ return -1;
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
+ return -1;
+
+ /* to close the clocket */
+ rtnl_close( &rth );
+
+ return(0);
+}
+
* <www.linuxvirtualserver.org>. It monitor & manipulate
* a loadbalanced server pool using multi-layer checks.
*
- * Part: check_misc.c include file.
+ * Part: vrrp_ipaddress.c include file.
*
- * Version: $Id: check_misc.h,v 0.3.8 2001/11/04 21:41:32 acassen Exp $
+ * Version: $Id: vrrp_ipaddress.h,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
*
- * Author: Eric Jarman, <ehj38230@cmsu2.cmsu.edu>
+ * 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 _MISC_H
-#define _MISC_H
-
-/* system includes */
-#include <stdlib.h>
+#ifndef _VRRP_IPADDR_H
+#define _VRRP_IPADDR_H
-/* local includes */
-#include "cfreader.h"
-#include "ipwrapper.h"
-#include "scheduler.h"
-#include "smtp.h"
+/* global includes */
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <syslog.h>
-/* Prototypes defs */
-extern int misc_check_thread(struct thread *thread);
+/* types definitions */
+typedef struct {
+ int ifindex;
+ uint32_t *addr;
+ int max_elem;
+ int nb_elem;
+} iplist_ctx;
+/* prototypes */
+int ipaddr_list(int ifindex, uint32_t *array, int max_elem);
+int ipaddr_op(int ifindex, uint32_t addr, int addF);
+
#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: Routing utilities using the NETLINK kernel interface.
+ *
+ * Version: $Id: vrrp_iproute.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * Changes: Alexandre Cassen : 2001/08/20 Initial release
+ *
+ * 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.
+ */
+
+/* local includes */
+#include "vrrp_iproute.h"
+#include "libnetlink/libnetlink.h"
+#include "libnetlink/ll_map.h"
+#include "utils.h"
+
+/* Allocation function */
+struct rt_entry * iproute_new()
+{
+ struct rt_entry *entry;
+
+ entry = (struct rt_entry *)malloc(sizeof(struct rt_entry));
+ memset(entry, 0, sizeof(struct rt_entry));
+
+ entry->rtm = (struct rtmsg *)malloc(sizeof(struct rtmsg));
+ memset(entry->rtm, 0, sizeof(struct rtmsg));
+
+ return entry;
+}
+
+/* free memory */
+void iproute_del(struct rt_entry *entry)
+{
+ free(entry->rtm);
+ free(entry);
+}
+
+/* destroy functions */
+struct rt_entry * clear_entry(struct rt_entry *entry)
+{
+ struct rt_entry *t;
+
+ t = (struct rt_entry *)entry->next;
+ iproute_del(entry);
+ return t;
+}
+
+void iproute_clear(struct rt_entry *lstentry)
+{
+ while (lstentry)
+ lstentry = clear_entry(lstentry);
+}
+
+/* Append rt entry function */
+struct rt_entry * iproute_append(struct rt_entry *lstentry, struct rt_entry *entry)
+{
+ struct rt_entry *ptr = lstentry;
+
+ if (lstentry) {
+ while (lstentry->next) lstentry = (struct rt_entry *)lstentry->next;
+ lstentry->next = (struct rt_entry *)entry;
+ return ptr;
+ } else {
+ lstentry = entry;
+ return lstentry;
+ }
+}
+
+/* Our rt netlink filter */
+int iproute_filter(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
+{
+ struct rt_entry *rtarg;
+ struct rtmsg *r = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr *tb[RTA_MAX+1];
+ struct rt_entry *entry;
+
+ rtarg = (struct rt_entry *)arg;
+
+ /* Just lookup the Main routing table */
+ if (r->rtm_table != RT_TABLE_MAIN)
+ return 0;
+
+ /* init len value */
+ len -= NLMSG_LENGTH(sizeof(*r));
+ if (len <0) {
+ syslog(LOG_INFO, "IPROUTE : BUG: wrong nlmsg len %d", len);
+ return -1;
+ }
+
+ /* init the parse attribute space */
+ memset(tb, 0, sizeof(tb));
+ parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
+
+ /*
+ * we return from filter when route is
+ * cloned from another route, learn by an
+ * ICMP redirect or set by kernel.
+ * Return too when rt type != gateway or direct route.
+ */
+ if (r->rtm_flags & RTM_F_CLONED)
+ return 0;
+ if (r->rtm_protocol == RTPROT_REDIRECT)
+ return 0;
+ if (r->rtm_protocol == RTPROT_KERNEL)
+ return 0;
+ if (r->rtm_type != RTN_UNICAST)
+ return 0;
+
+ if (tb[RTA_OIF]) {
+ /* alloc new memory entry */
+ entry = iproute_new();
+
+ /* copy the rtmsg infos */
+ memcpy(entry->rtm, r, sizeof(struct rtmsg));
+
+ /*
+ * can use RTA_PAYLOAD(tb[RTA_SRC])
+ * but ipv4 addr are 4 bytes coded
+ */
+ entry->oif = *(int *) RTA_DATA(tb[RTA_OIF]);
+ if (tb[RTA_SRC]) memcpy(&entry->src, RTA_DATA(tb[RTA_SRC]), 4);
+ if (tb[RTA_PREFSRC]) memcpy(&entry->psrc, RTA_DATA(tb[RTA_PREFSRC]), 4);
+ if (tb[RTA_DST]) memcpy(&entry->dest, RTA_DATA(tb[RTA_DST]), 4);
+ if (tb[RTA_GATEWAY]) memcpy(&entry->gate, RTA_DATA(tb[RTA_GATEWAY]), 4);
+ if (tb[RTA_FLOW]) memcpy(&entry->flow, RTA_DATA(tb[RTA_FLOW]), 4);
+ if (tb[RTA_IIF]) entry->iif = *(int *) RTA_DATA(tb[RTA_IIF]);
+ if (tb[RTA_PRIORITY]) entry->prio = *(int *) RTA_DATA(tb[RTA_PRIORITY]);
+ if (tb[RTA_METRICS]) entry->metrics = *(int *) RTA_DATA(tb[RTA_METRICS]);
+
+ /* save this entry */
+ rtarg = iproute_append(rtarg, entry);
+ }
+
+ return 0;
+}
+
+struct rt_entry * iproute_fetch(struct rt_entry *r)
+{
+ struct rtnl_handle rth;
+
+ if (rtnl_open(&rth, 0) < 0) {
+ syslog(LOG_INFO, "IPROUTE : Can not initialize netlink interface...");
+ return NULL;
+ }
+
+ ll_init_map(&rth);
+
+ if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETROUTE) < 0) {
+ syslog(LOG_INFO, "IPROUTE : Cannot send dump request.");
+ close(rth.fd);
+ return NULL;
+ }
+
+ if (rtnl_dump_filter(&rth, iproute_filter, r, NULL, NULL) < 0) {
+ syslog(LOG_INFO, "IPROUTE : Dump terminated.");
+ close(rth.fd);
+ return NULL;
+ }
+
+ close(rth.fd);
+ return r;
+}
+
+int iproute_restore_entry(struct rt_entry *r)
+{
+ struct rtnl_handle rth;
+
+ struct {
+ struct nlmsghdr n;
+ struct rtmsg r;
+ char buf[1024];
+ } req;
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE;
+ req.n.nlmsg_type = RTM_NEWROUTE;
+
+ memcpy(&req.r, r->rtm, sizeof(struct rtmsg));
+
+ if (r->src)
+ addattr_l(&req.n, sizeof(req), RTA_SRC, &r->src, 4);
+ if (r->psrc)
+ addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &r->psrc, 4);
+ if (r->dest)
+ addattr_l(&req.n, sizeof(req), RTA_DST, &r->dest, 4);
+ if (r->gate)
+ addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &r->gate, 4);
+ if (r->flow)
+ addattr_l(&req.n, sizeof(req), RTA_FLOW, &r->flow, 4);
+
+ if (r->oif)
+ addattr32(&req.n, sizeof(req), RTA_OIF, r->oif);
+ if (r->iif)
+ addattr32(&req.n, sizeof(req), RTA_IIF, r->iif);
+ if (r->prio)
+ addattr32(&req.n, sizeof(req), RTA_PRIORITY, r->prio);
+ if (r->metrics)
+ addattr32(&req.n, sizeof(req), RTA_METRICS, r->metrics);
+
+ if (rtnl_open(&rth, 0) < 0) {
+ syslog(LOG_INFO, "IPROUTE : Can not initialize netlink interface...");
+ return -1;
+ }
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
+ syslog(LOG_INFO, "IPROUTE : Can not talk with netlink interface...");
+ return -1;
+ }
+
+ return 0;
+}
+
+/* rt netlink dump function */
+void iproute_dump(struct rt_entry *r)
+{
+ while (r) {
+ if (r->src) syslog(LOG_DEBUG, "src %s ", ip_ntoa(r->src));
+ if (r->psrc) syslog(LOG_DEBUG, "prefsrc %s ", ip_ntoa(r->psrc));
+ if (r->iif) syslog(LOG_DEBUG, "idev %s", ll_index_to_name(r->iif));
+
+ if (r->dest) syslog(LOG_DEBUG, "dest %s ", ip_ntoa(r->dest));
+ if (r->gate) syslog(LOG_DEBUG, "gateway %s ", ip_ntoa(r->gate));
+
+ if (r->prio) syslog(LOG_DEBUG, "priority %d ", r->prio);
+ if (r->metrics) syslog(LOG_DEBUG, "metrics %d ", r->metrics);
+
+ if (r->oif) syslog(LOG_DEBUG, "odev %s ", ll_index_to_name(r->oif));
+
+ /* rtmsg specifics */
+ if (r->rtm->rtm_dst_len) syslog(LOG_DEBUG, "mask %d ", r->rtm->rtm_dst_len);
+ if (r->rtm->rtm_scope == RT_SCOPE_LINK) syslog(LOG_DEBUG, "scope link");
+
+ printf("\n");
+
+ r = (struct rt_entry *)r->next;
+ }
+}
+
+struct rt_entry *iproute_list(char *dev)
+{
+ struct rt_entry rt_table;
+
+ /* Fetch the main routing table */
+ memset(&rt_table, 0, sizeof(struct rt_entry));
+ if (!iproute_fetch(&rt_table)) return NULL;
+
+ return rt_table.next;
+}
+
+int iproute_restore(struct rt_entry *lstentry, char *dev)
+{
+ int idx = ll_name_to_index(dev);
+ int ret = 0;
+
+ while (lstentry) {
+ if (lstentry->oif == idx) {
+ ret = iproute_restore_entry(lstentry);
+ if (ret < 0) return ret;
+ }
+
+ lstentry = (struct rt_entry *)lstentry->next;
+ }
+
+ 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: vrrp_iproute.c include file.
+ *
+ * Version: $Id: vrrp_iproute.h,v 0.4.0 2001/08/24 00:35:19 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 _VRRP_IPROUTE_H
+#define _VRRP_IPROUTE_H
+
+/* global includes */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <syslog.h>
+
+/* specify a routing entry */
+struct rt_entry {
+ struct rtmsg *rtm;
+
+ uint32_t psrc;
+ uint32_t src;
+ uint32_t dest;
+ uint32_t gate;
+ uint32_t flow;
+ int iif;
+ int oif;
+ int prio;
+ int metrics;
+
+ struct rt_entry *next;
+};
+
+/* prototypes */
+
+extern struct rt_entry *iproute_fetch(struct rt_entry *r);
+extern void iproute_dump(struct rt_entry *r);
+extern void iproute_clear(struct rt_entry *lstentry);
+extern int iproute_restore(struct rt_entry *lstentry, char *dev);
+extern struct rt_entry *iproute_list(char *dev);
+
+#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: IPSEC AH implementation according to RFC 2402. Processing
+ * authentication data encryption using HMAC MD5 according to
+ * RFCs 2085 & 2104.
+ *
+ * Version: $Id: vrrp_ipsecah.c,v 0.4.0 2001/08/24 00:35:19 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * Changes: Alexandre Cassen : 2001/08/20 Initial release
+ *
+ * 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 "vrrp_ipsecah.h"
+#include "md5.h"
+
+/* hmac_md5 computation according to the RFCs 2085 & 2104 */
+void hmac_md5(unsigned char *buffer,int buffer_len,
+ unsigned char *key,int key_len,unsigned char *digest)
+{
+ MD5_CTX context;
+ unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */
+ unsigned char k_opad[65]; /* outer padding - key XORd with opad */
+ unsigned char tk[16];
+ int i;
+
+ /* Initialize data */
+ memset(k_ipad,0,sizeof(k_ipad));
+ memset(k_opad,0,sizeof(k_opad));
+ memset(tk,0,sizeof(tk));
+
+ /* If the key is longer than 64 bytes => set it to key=MD5(key) */
+ if (key_len > 64) {
+ MD5_CTX tctx;
+
+ /* Compute the MD5 digest */
+ MD5Init(&tctx);
+ MD5Update(&tctx,key,key_len);
+ MD5Final(tk,&tctx);
+
+ key = tk;
+ key_len = 16;
+ }
+
+ /* The global HMAC_MD5 algo looks like (rfc2085.2.2) :
+ MD5(K XOR opad, MD5(K XOR ipad, buffer))
+ K : an n byte key
+ ipad : byte 0x36 repeated 64 times
+ opad : byte 0x5c repeated 64 times
+ buffer : buffer being protected
+ */
+ memset(k_ipad,0,sizeof(k_ipad));
+ memset(k_opad,0,sizeof(k_opad));
+ memcpy(k_ipad,key,key_len);
+ memcpy(k_opad,key,key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i=0;i<64;i++) {
+ k_ipad[i] ^=0x36;
+ k_opad[i] ^=0x5c;
+ }
+
+ /* 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 */
+
+ /* 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 */
+}
--- /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: vrrp_ipsecah.c include file.
+ *
+ * Version: $Id: vrrp_ipsecah.h,v 0.4.0 2001/08/24 00:35:19 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 _VRRP_IPSEC_AH_H
+#define _VRRP_IPSEC_AH_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdint.h>
+
+/* Predefined values */
+#define HMAC_MD5_TRUNC 0x0C /* MD5 digest truncate value : 96-bit
+ -- rfc2403.2 & rfc2104.5 */
+#define IPSEC_AH_PLEN 0x04 /* Const for a 96-bit auth value :
+ Computed in 32-bit words minus 2
+ => (HMAC_MD5_TRUNC*8+3*32)/32 - 2
+ -- rfc2402.2.2 */
+#define IPPROTO_IPSEC_AH 51 /* IP protocol number -- rfc2402.2 */
+
+typedef struct { /* rfc2402.2 */
+ uint8_t next_header; /* Next header field */
+ uint8_t payload_len; /* Payload Lenght */
+ uint16_t reserved; /* Reserved field */
+ uint32_t spi; /* Security Parameter Index */
+ uint32_t seq_number; /* Sequence number */
+ uint32_t auth_data[3]; /* Authentication data 128-bit MD5 digest trucated
+ => HMAC_MD5_TRUNC*8/32 */
+} ipsec_ah;
+
+typedef struct { /* rfc2402.3.3.3.1.1.1 */
+ u_int8_t tos;
+ u_int16_t id;
+ u_int16_t frag_off;
+ u_int16_t check;
+} ICV_mutable_fields; /* We need to zero this fields to compute the ICV */
+
+typedef struct {
+ int cycle;
+ uint32_t seq_number;
+} seq_counter;
+
+
+extern void hmac_md5(unsigned char *buffer, int buffer_len,
+ unsigned char *key, int key_len, unsigned char *digest);
+
+#endif