keepalived-0.4.0 v0.4.0
authorAlexandre Cassen <acassen@freebox.fr>
Thu, 23 Aug 2001 23:02:21 +0000 (01:02 +0200)
committerAlexandre Cassen <acassen@freebox.fr>
Mon, 28 Sep 2009 08:58:53 +0000 (10:58 +0200)
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.

49 files changed:
CONTRIBUTORS [deleted file]
ChangeLog
INSTALL
Makefile
TODO [new file with mode: 0644]
cfreader.c
cfreader.h
check.h
check_http.c
check_http.h
check_misc.c [deleted file]
check_tcp.c
check_tcp.h
etc/keepalived/keepalived.conf
etc/rc.d/init.d/keepalived.init
ipfwwrapper.c
ipfwwrapper.h
ipvswrapper.c
ipvswrapper.h
ipwrapper.c
ipwrapper.h
keepalived.conf.sample [moved from sample.keepalived.conf with 81% similarity]
keepalived.conf.vrrp [new file with mode: 0644]
layer4.c
layer4.h
libnetlink/Makefile [new file with mode: 0644]
libnetlink/libnetlink.c [new file with mode: 0644]
libnetlink/libnetlink.h [new file with mode: 0644]
libnetlink/ll_map.c [new file with mode: 0644]
libnetlink/ll_map.h [new file with mode: 0644]
main.c
main.h
pidfile.c
pidfile.h
sample.misccheck.smbcheck.sh [deleted file]
scheduler.c
scheduler.h
smtp.c
smtp.h
utils.c
utils.h
vrrp.c [new file with mode: 0644]
vrrp.h [new file with mode: 0644]
vrrp_ipaddress.c [new file with mode: 0644]
vrrp_ipaddress.h [moved from check_misc.h with 58% similarity]
vrrp_iproute.c [new file with mode: 0644]
vrrp_iproute.h [new file with mode: 0644]
vrrp_ipsecah.c [new file with mode: 0644]
vrrp_ipsecah.h [new file with mode: 0644]

diff --git a/CONTRIBUTORS b/CONTRIBUTORS
deleted file mode 100644 (file)
index 691faf8..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Eric Jarman <ehj38230@cmsu2.cmsu.edu>
index 0f74a28..90e6b06 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,17 +1,3 @@
-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>
 
@@ -36,6 +31,7 @@
         * 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 :
@@ -74,5 +75,7 @@
           . 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.
diff --git a/INSTALL b/INSTALL
index d96f166..51f28a0 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -5,7 +5,6 @@ Kernel needing
 
   IP aliasing
   Kernel/User netlink socket
-  Network firewalls
   Routing messages
   LinuxVirtualServer
 
@@ -32,6 +31,5 @@ Configuration
 
   http://keepalived.sourceforge.net
 
-Have fun with it !
 
-Alexandre Cassen, <acassen@linux-vs.org>
+Have fun with it !
index 73fe57b..82d6f65 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,29 +1,18 @@
 # 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 \
@@ -31,16 +20,16 @@ OBJECTS= main.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
 
@@ -55,15 +44,15 @@ all:        $(EXEC)
 $(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)
diff --git a/TODO b/TODO
new file mode 100644 (file)
index 0000000..0e5768d
--- /dev/null
+++ b/TODO
@@ -0,0 +1,10 @@
+* 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).
index 364dbae..e774f7c 100644 (file)
@@ -7,10 +7,12 @@
  *              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}
 };
@@ -110,9 +123,23 @@ int already_exist_svr(realserver *lstptr, uint32_t ip, uint16_t port)
   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;
@@ -126,7 +153,7 @@ notification_email * add_item_email(notification_email *lstemail,notification_em
 
 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;
 
@@ -142,7 +169,7 @@ virtualserver * add_item_vs(virtualserver *lstvs,virtualserver *vs)
 
 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;
 
@@ -158,7 +185,7 @@ realserver * add_item_svr(realserver *lstsvr,realserver *svr)
 
 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;
@@ -208,6 +235,19 @@ virtualserver * remove_vs(virtualserver * lstptr)
   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;
@@ -222,10 +262,21 @@ void clear_conf(configuration_data * lstptr)
   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)
 {
@@ -274,11 +325,6 @@ void dump_svr(realserver *pointersvr)
         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;
@@ -293,35 +339,13 @@ void dump_vs(virtualserver *pointervs)
                       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]", 
@@ -344,6 +368,34 @@ void dump_email(notification_email *pointeremail)
   }
 }
 
+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) {
@@ -354,11 +406,17 @@ void dump_conf(configuration_data *lstconf)
     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);
+    }
   }
 }
 
@@ -402,37 +460,6 @@ void process_stream_tcpcheck(FILE *stream, realserver *svrfill)
   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;
@@ -538,9 +565,6 @@ void process_stream_svr(FILE *stream, virtualserver *vsfill)
         break;
       case KW_LDAPGET: /* not yet implemented */
         break;
-      case KW_MISCCHECK:
-       process_stream_misccheck(stream, svrfill);
-       break;
       case KW_UNKNOWN:
         break;
     }
@@ -603,33 +627,11 @@ void process_stream_vs(FILE *stream, configuration_data *conf_data)
         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);
@@ -700,21 +702,155 @@ void process_stream_globaldefs(FILE *stream, configuration_data *conf_data)
   } 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);
@@ -731,6 +867,10 @@ configuration_data * conf_reader()
       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;
     }
index f4ef705..e707711 100644 (file)
@@ -5,7 +5,7 @@
  * 
  * 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 {
@@ -64,40 +54,52 @@ 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 {
@@ -120,10 +122,8 @@ typedef struct _keepalive_check {
 #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 {
@@ -141,7 +141,7 @@ typedef struct _virtual_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];
@@ -151,6 +151,14 @@ typedef struct _virtual_server {
   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];
 
@@ -163,6 +171,7 @@ typedef struct _configuration_data {
   struct in_addr smtp_server;
   int smtp_connection_to;
   notification_email *email;
+  vrrp_instance *vrrp;
 
   virtualserver *lvstopology;
 } configuration_data;
@@ -170,6 +179,7 @@ typedef struct _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
diff --git a/check.h b/check.h
index e30cabc..ce06375 100644 (file)
--- a/check.h
+++ b/check.h
@@ -5,7 +5,7 @@
  *
  * 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>
  *
index 165df34..2c97d2d 100644 (file)
@@ -7,10 +7,12 @@
  *              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.
index 6d5311f..2a95e7f 100644 (file)
@@ -5,7 +5,7 @@
  *
  * 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>
  *
diff --git a/check_misc.c b/check_misc.c
deleted file mode 100644 (file)
index 4b44ad7..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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;
-}
index 33a8bf1..aa95510 100644 (file)
@@ -5,10 +5,12 @@
  *
  * 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.
index 5c0a3c0..f7b7997 100644 (file)
@@ -5,7 +5,7 @@
  *
  * 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>
  *
index 31d9111..d781c0b 100644 (file)
@@ -2,7 +2,9 @@
 
 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
@@ -57,14 +59,6 @@ virtual_server 10.10.10.2 1358 {
             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 {
index 282d238..bcc4c4e 100755 (executable)
@@ -6,17 +6,20 @@
 # 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
        ;;
   *)
index 037b86e..a9874c2 100644 (file)
@@ -7,10 +7,12 @@
  *              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.
index eafb2a5..5e94164 100644 (file)
@@ -5,7 +5,7 @@
  *
  * 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>
  *
index 04d47ef..e1c85f4 100644 (file)
@@ -6,25 +6,33 @@
  * 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;
@@ -42,10 +50,13 @@ int ipvs_cmd(int cmd, virtualserver *vserver, realserver *rserver)
   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;
@@ -60,121 +71,41 @@ int ipvs_cmd(int cmd, virtualserver *vserver, realserver *rserver)
 
   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
  */
index 2aab5e5..a7bd166 100644 (file)
@@ -5,7 +5,7 @@
  *
  * 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);
index a4eac0f..28b406c 100644 (file)
@@ -5,10 +5,12 @@
  *
  * 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.
@@ -29,23 +31,21 @@ int clear_service_vs(virtualserver *vserver)
   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;
@@ -58,12 +58,11 @@ int clear_services(virtualserver *vserver)
     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;
   }
@@ -98,11 +97,8 @@ void perform_svr_state(int alive, virtualserver *vserver, realserver *rserver)
                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
       }
     }
 
@@ -110,12 +106,9 @@ void perform_svr_state(int alive, virtualserver *vserver, realserver *rserver)
     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 {
 
@@ -125,12 +118,9 @@ void perform_svr_state(int alive, virtualserver *vserver, realserver *rserver)
            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)) {
@@ -140,11 +130,8 @@ void perform_svr_state(int alive, virtualserver *vserver, realserver *rserver)
 
       /* 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
     }
 
   }
@@ -156,12 +143,11 @@ int init_service_vs(virtualserver *vserver)
 
   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.
      */
@@ -170,8 +156,6 @@ int init_service_vs(virtualserver *vserver)
         vserver->svr = pointersvr;
         return 0;
       }
-#endif
-
     vserver->svr = (realserver *)vserver->svr->next;
   }
   vserver->svr = pointersvr;
@@ -185,17 +169,15 @@ int init_services(virtualserver *vserver)
 
   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;
index 94254e4..a4e069f 100644 (file)
@@ -5,7 +5,7 @@
  *
  * 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);
similarity index 81%
rename from sample.keepalived.conf
rename to keepalived.conf.sample
index 31d9111..acace02 100644 (file)
@@ -10,6 +10,41 @@ global_defs {
    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 
@@ -57,14 +92,6 @@ virtual_server 10.10.10.2 1358 {
             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 {
diff --git a/keepalived.conf.vrrp b/keepalived.conf.vrrp
new file mode 100644 (file)
index 0000000..d3d4c3f
--- /dev/null
@@ -0,0 +1,47 @@
+# 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
+}
+
index 59c096b..babfe1d 100644 (file)
--- a/layer4.c
+++ b/layer4.c
@@ -6,10 +6,12 @@
  * 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.
index 8b47c9a..d63cc42 100644 (file)
--- a/layer4.h
+++ b/layer4.h
@@ -5,7 +5,7 @@
  *
  * 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>
  *
@@ -28,8 +28,6 @@
 #include <stdint.h>
 #include <netdb.h>
 #include <arpa/inet.h>
-#include <sys/socket.h>
-#include <sys/types.h>
 
 /* local includes */
 #include "cfreader.h"
diff --git a/libnetlink/Makefile b/libnetlink/Makefile
new file mode 100644 (file)
index 0000000..7d2a75d
--- /dev/null
@@ -0,0 +1,11 @@
+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 *~
diff --git a/libnetlink/libnetlink.c b/libnetlink/libnetlink.c
new file mode 100644 (file)
index 0000000..30fb520
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ * 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);
+}
+
diff --git a/libnetlink/libnetlink.h b/libnetlink/libnetlink.h
new file mode 100644 (file)
index 0000000..1444c7d
--- /dev/null
@@ -0,0 +1,46 @@
+#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__ */
+
diff --git a/libnetlink/ll_map.c b/libnetlink/ll_map.c
new file mode 100644 (file)
index 0000000..e5a95e6
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * 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;
+}
diff --git a/libnetlink/ll_map.h b/libnetlink/ll_map.h
new file mode 100644 (file)
index 0000000..739f157
--- /dev/null
@@ -0,0 +1,12 @@
+#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__ */
diff --git a/main.c b/main.c
index 6b2fc81..0017c98 100644 (file)
--- a/main.c
+++ b/main.c
@@ -5,10 +5,17 @@
  *
  * 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.
@@ -171,6 +178,8 @@ int main(int argc, char **argv)
   /* 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();
diff --git a/main.h b/main.h
index 9d4e745..52d04d8 100644 (file)
--- a/main.h
+++ b/main.h
@@ -5,7 +5,7 @@
  *
  * 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>
  *
@@ -39,6 +39,6 @@ struct thread_master *master;
 
 /* Build version */
 #define PROG    "keepalived"
-#define VERSION "0.3.8 (04/11, 2001)"
+#define VERSION "0.3.6 (10/08, 2001)"
 
 #endif
index a6fdee8..9fb55e2 100644 (file)
--- a/pidfile.c
+++ b/pidfile.c
@@ -5,10 +5,12 @@
  *
  * 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.
index 6775519..bb5a0ba 100644 (file)
--- a/pidfile.h
+++ b/pidfile.h
@@ -5,7 +5,7 @@
  *
  * 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>
  *
diff --git a/sample.misccheck.smbcheck.sh b/sample.misccheck.smbcheck.sh
deleted file mode 100644 (file)
index f555296..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/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
-
index 4142d60..d6e15d9 100644 (file)
@@ -7,10 +7,12 @@
  *              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.  
@@ -727,11 +729,6 @@ register_vs_worker_thread(struct thread_master *master,
         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;
     }
@@ -747,6 +744,16 @@ void
 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;
index 998ce8b..3df309e 100644 (file)
@@ -5,7 +5,7 @@
  *
  * 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>
  *
@@ -163,6 +163,6 @@ extern int
 http_connect_thread(struct thread *thread);
 
 extern int
-misc_check_thread(struct thread *thread);
+vrrp_state_init_thread(struct thread *thread);
 
 #endif
diff --git a/smtp.c b/smtp.c
index 8ebaef8..a59942f 100644 (file)
--- a/smtp.c
+++ b/smtp.c
@@ -7,10 +7,12 @@
  *              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.
diff --git a/smtp.h b/smtp.h
index b773499..27bfb60 100644 (file)
--- a/smtp.h
+++ b/smtp.h
@@ -5,7 +5,7 @@
  *
  * 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>
  *
diff --git a/utils.c b/utils.c
index 5271432..129a2af 100644 (file)
--- a/utils.c
+++ b/utils.c
@@ -5,7 +5,7 @@
  *
  * 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>
  *
@@ -60,4 +60,12 @@ void print_buffer(int count, char *buff)
   }
 }
 
+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;
+}
diff --git a/utils.h b/utils.h
index b3c2fbf..3c4430b 100644 (file)
--- a/utils.h
+++ b/utils.h
@@ -1,32 +1,12 @@
-/*
- * 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
diff --git a/vrrp.c b/vrrp.c
new file mode 100644 (file)
index 0000000..c66aaab
--- /dev/null
+++ b/vrrp.c
@@ -0,0 +1,1157 @@
+/*
+ * 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);
+}
diff --git a/vrrp.h b/vrrp.h
new file mode 100644 (file)
index 0000000..71d6e11
--- /dev/null
+++ b/vrrp.h
@@ -0,0 +1,146 @@
+/*
+ * 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
diff --git a/vrrp_ipaddress.c b/vrrp_ipaddress.c
new file mode 100644 (file)
index 0000000..6617e3f
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * 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);
+}
+
similarity index 58%
rename from check_misc.h
rename to vrrp_ipaddress.h
index 5ae7109..e84017e 100644 (file)
@@ -3,36 +3,42 @@
  *              <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
+
diff --git a/vrrp_iproute.c b/vrrp_iproute.c
new file mode 100644 (file)
index 0000000..b4a74dc
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ * 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;
+}
diff --git a/vrrp_iproute.h b/vrrp_iproute.h
new file mode 100644 (file)
index 0000000..a07d8ce
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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
diff --git a/vrrp_ipsecah.c b/vrrp_ipsecah.c
new file mode 100644 (file)
index 0000000..be57c70
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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 */
+}
diff --git a/vrrp_ipsecah.h b/vrrp_ipsecah.h
new file mode 100644 (file)
index 0000000..d0876f3
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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