--- vrrpd-1.0.orig/ll_map.h +++ vrrpd-1.0/ll_map.h @@ -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__ */ --- vrrpd-1.0.orig/Changes +++ vrrpd-1.0/Changes @@ -1,3 +1,33 @@ +- Pascal Lengard : Make syslog log with LOG_DAEMON and be used for all errors + after startup. + Can give a name to a VRID to be displayed in the logs, handy + when you get several vrrp daemons running on same hosts. + modified files : vrrpd.c vrrpd.h + doc: + daemon uses stderr to report errors when starting, but will + now use syslog to LOG_DAEMON when in normal use. + have a look in your logs !! + +0.7 - February 4th 2002 +- David Hunter : Added monitored interface routines and definitions. These will + only work for drivers that implement the MII calls. Two new + command-line flags are added for this, -m and -c. Tested with + up to four monitored interfaces simultaneously on eepro100 + drivers. + +0.6 - August 14th 2001 +- Alexandre Cassen : 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. + +0.5 - May 23th 2001 +- Alexandre Cassen : Added IPSEC-AH support using HMAC-96bits digest wih anti-replay. + rfc2402 & rfc2104 +- Alexandre Cassen : Added manipulated buffer memory allocation in state_mast/state_back. +- Alexandre Cassen : Added incoming packet check integrity for VRID. + The ipaddr associated with a VRID must be the same as the ones present in + the MASTER VRRP advert. + 0.4 - Sep 26th 2000 - written a man(8) page - implemented the password authentication rfc2338.10.2 --- vrrpd-1.0.orig/daemon.h +++ vrrpd-1.0/daemon.h @@ -0,0 +1,7 @@ +#ifndef DAEMON_H +#define DAEMON_H 1 + +#define _PATH_DEVNULL "/dev/null" +int daemon(int,int); + +#endif --- vrrpd-1.0.orig/vrrpd.h +++ vrrpd-1.0/vrrpd.h @@ -1,27 +1,46 @@ -/*==========================[ (c) GURU SOFT ]=================================== -FILE : [vrrp.h] -CREATED : 00/02/02 12:12:06 LAST SAVE : 00/10/04 21:59:46 -WHO : jerome@mycpu Linux 2.2.14 -REMARK : -================================================================================ -- 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. -==============================================================================*/ +/* + * 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: vrrpd.h,v 0.7 2002/02/04 12:00:00 dhunter Exp $ + * + * Author: Jerome Etienne, + * + * Contributor: Alexandre Cassen, + * + * Changes: + * David Hunter : 2002/02/04 : + * <+> Added orig_prio & delt_prio in vrrp_rt. + * Alexandre Cassen : 2001/05/23 : + * <+> Added IPSEC AH sequence number counter in vrrp_rt. + * + * 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 - -#define VRRPD_VERSION "0.4" -/* Scott added 9-4-02 */ #include #define vrrpd_log syslog +#define VRRPD_VERSION "1.0" + /* local include */ +#include "iproute.h" +#include "ipaddr.h" +#include "ipsecah.h" typedef struct { /* rfc2338.5.1 */ uint8_t vers_type; /* 0-3=type, 4-7=version */ @@ -53,6 +72,7 @@ /* implementation specific */ #define VRRP_PIDDIR_DFL "/var/run" /* dir to store the pid file */ #define VRRP_PID_FORMAT "vrrpd_%s_%d.pid" /* pid file format */ +#define VRIDNAME_MAX 20 /* name for logging */ typedef struct { /* parameters per interface -- rfc2338.6.1.1 */ int auth_type; /* authentification type. VRRP_AUTH_* */ @@ -61,6 +81,7 @@ uint32_t ipaddr; /* the address of the interface */ char hwaddr[6]; /* WORK: lame hardcoded for ethernet !!!! */ char *ifname; /* the device name for this ipaddr */ + struct rt_entry *rt; /* device routing table */ } vrrp_if; typedef struct { @@ -94,9 +115,19 @@ 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; + + /* Monitored Interface values */ + int orig_prio; + int delt_prio; } vrrp_rt; +#define VRRP_DELTA_DFL 50 /* Default priority delta */ + /* VRRP state machine -- rfc2338.6.4 */ #define VRRP_STATE_INIT 1 /* rfc2338.6.4.1 */ #define VRRP_STATE_BACK 2 /* rfc2338.6.4.2 */ @@ -110,8 +141,6 @@ #define VRRP_IS_BAD_PRIORITY(p) ((p)<1 || (p)>255) /* rfc2338.6.1.prio */ #define VRRP_IS_BAD_ADVERT_INT(d) ((d)<1) - - /* use the 'tcp sequence number arithmetic' to handle the wraparound. ** VRRP_TIMER_SUB: <0 if t1 precedes t2, =0 if t1 equals t2, >0 if t1 follows t2 */ @@ -129,7 +158,6 @@ return tv.tv_sec*VRRP_TIMER_HZ+tv.tv_usec; } - #define VRRP_TIMER_SKEW( srv ) ((256-(srv)->priority)*VRRP_TIMER_HZ/256) #define VRRP_MIN( a , b ) ( (a) < (b) ? (a) : (b) ) --- vrrpd-1.0.orig/ll_map.c +++ vrrpd-1.0/ll_map.c @@ -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, + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} --- vrrpd-1.0.orig/vrrpd.c +++ vrrpd-1.0/vrrpd.c @@ -1,14 +1,51 @@ -/*==========================[ (c) JME SOFT ]=================================== -FILE : [vrrp.c] -CREATED : 00/02/02 12:54:37 LAST SAVE : 00/10/04 22:11:39 -WHO : jerome@mycpu Linux 2.2.14 -REMARK : -================================================================================ -- 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. -==============================================================================*/ +/* + * 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: vrrpd.c,v 0.7.1 2003/11/16 02:00:00 ccwu Exp $ + * + * Author: Jerome Etienne, + * + * Contributor: Alexandre Cassen, + * Contributor: David Hunter, + * Contributor: Chao-Cheng Wu, + * + * Changes: + * Alfredo Pironti (alfredio@ciaoweb.it) + * <+> Added -D option to go into background (daemon) mode + * Chao-Cheng Wu : 2003/11/16 : + * Fix Change the position of the Backup Routing Table's codes + * to fix VRRPD always restore Routing Table to the + * state of the VRRPD start. + * Scott ????? : 2002/04/09: + * <+> Added master_ipaddr to report to syslog the IP changes. + * David Hunter : 2002/02/04 : + * <+> Added Monitored Interface functionality using code + * from Donald Becker's mii-diag.c + * to check MII registers and IFF_UP state. + * Alexandre Cassen : 2001/05/23 : + * <+> Added IPSEC-AH support using HMAC-96bits digest with + * anti-replay. + * -- rfc2401 / rfc2402 / rfc2102 + * draft-paridaens-xcast-sec-framework-01.txt + * <+> Added manipulated buffer memory allocation in state_mast + * & state_back. + * <+> Added incoming packet check integrity for VRID. + * The ipaddr asssociated with a VRID must be the same as + * the ones present in the MASTER VRRP advert. + * + * 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. + */ /* system include */ #include @@ -33,804 +70,1218 @@ #include #include +#include +#include +#ifdef use_linux_libc5 +#include +#include +#endif + /* local include */ #include "vrrpd.h" -#include "ipaddr.h" - -int ip_id = 0; /* 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) */ - /* WORK: this packet isnt routed, i can check the outgoing MTU - ** to warn the user only if the outoing mtu is too small */ -static char vrrp_hwaddr[6]; // WORK: lame hardcoded for ethernet -static vrrp_rt glob_vsrv; /* a global because used in the signal handler*/ -/* Scott added 9-4-02 */ -int master_ipaddr = 0; -static char PidDir[FILENAME_MAX+1]; +int ip_id = 0; /* 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) */ + /* WORK: this packet isnt routed, i can check the outgoing MTU + ** to warn the user only if the outoing mtu is too small */ +static char vrrp_hwaddr[6]; // WORK: lame hardcoded for ethernet +static vrrp_rt glob_vsrv; /* a global because used in the signal handler*/ +int master_ipaddr=0; + +static char VridName[VRIDNAME_MAX+1]="vrrpd"; /* handy to have a name in the logs */ +static char PidDir[FILENAME_MAX+1]; + +/* VRRP monitored interface definitions */ +static int monitorit(); +static int mdio_read( int phy_id, int location, int i ); +static void init_int( int i ); +static int chk_iff( int i ); + +typedef unsigned short u16; +typedef unsigned int u32; + +#ifndef SIOCGMIIPHY +#define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Get the PHY in use. */ +#define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read a PHY register. */ +#define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write a PHY register. */ +#define SIOCGPARAMS (SIOCDEVPRIVATE+3) /* Read operational parameters. */ +#define SIOCSPARAMS (SIOCDEVPRIVATE+4) /* Set operational parameters. */ +#endif +#define MAXINTS 64 /* Maximum interfaces supported */ +int skfd[MAXINTS]; /* AF_INET socket for ioctl() calls. */ +struct ifreq ifr[MAXINTS]; +char *ifname[MAXINTS]; + +/**************************************************************** + NAME : print_buffer 01/05/23 12:26:27 + AIM : simple debugging proc + CONTRIB : Alexandre Cassen : 2001/05/23 +****************************************************************/ +void print_buffer(int count, char *buff) +{ + int i,j,c; + int printnext=1; + + if(count) { + if(count%16) + c=count+(16-count%16); + else c=count; + } else + c=count; + + for(i=0;i= 0x20 && (buff[j]&0xff)<=0x7e) + printf("%c",buff[j]&0xff); + else printf("."); + } else printf(" "); + printf("\n"); printnext=1; + } + } + } +} /**************************************************************** - NAME : get_pid_name 00/10/04 21:06:44 - AIM : - REMARK : + NAME : get_pid_name 00/10/04 21:06:44 + AIM : + REMARK : ****************************************************************/ static char *pidfile_get_name( vrrp_rt *vsrv ) { - static char pidfile[FILENAME_MAX+1]; - snprintf( pidfile, sizeof(pidfile), "%s/" VRRP_PID_FORMAT - , PidDir - , vsrv->vif.ifname - , vsrv->vrid ); - return pidfile; + static char pidfile[FILENAME_MAX+1]; + snprintf( pidfile, sizeof(pidfile), "%s/" VRRP_PID_FORMAT + , PidDir + , vsrv->vif.ifname + , vsrv->vrid ); + return pidfile; } /**************************************************************** - NAME : pidfile_write 00/10/04 21:12:26 - AIM : - REMARK : write the pid file + NAME : pidfile_write 00/10/04 21:12:26 + AIM : + REMARK : write the pid file ****************************************************************/ static int pidfile_write( vrrp_rt *vsrv ) { - char *name = pidfile_get_name(vsrv); - FILE *fOut = fopen( name, "w" ); - if( !fOut ){ - fprintf( stderr, "Can't open %s (errno %d %s)\n", name - , errno - , strerror(errno) - ); - return -1; - } - fprintf( fOut, "%d\n", getpid() ); - fclose( fOut ); - return(0); + char *name = pidfile_get_name(vsrv); + FILE *fOut = fopen( name, "w" ); + if( !fOut ){ + fprintf( stderr, "Can't open %s (errno %d %s)\n", name + , errno + , strerror(errno) + ); + return -1; + } + fprintf( fOut, "%d\n", getpid() ); + fclose( fOut ); + return(0); } /**************************************************************** - NAME : pidfile_rm 00/10/04 21:12:26 - AIM : - REMARK : + NAME : pidfile_rm 00/10/04 21:12:26 + AIM : + REMARK : ****************************************************************/ static void pidfile_rm( vrrp_rt *vsrv ) { - unlink( pidfile_get_name(vsrv) ); + unlink( pidfile_get_name(vsrv) ); } /**************************************************************** - NAME : pidfile_exist 00/10/04 21:12:26 - AIM : return 0 if there is no valid pid in the pidfile or no pidfile - REMARK : + NAME : pidfile_exist 00/10/04 21:12:26 + AIM : return 0 if there is no valid pid in the pidfile or no pidfile + REMARK : ****************************************************************/ static int pidfile_exist( vrrp_rt *vsrv ) { - char *name = pidfile_get_name(vsrv); - FILE *fIn = fopen( name, "r" ); - pid_t pid; - /* if there is no file */ - if( !fIn ) return 0; - fscanf( fIn, "%d", &pid ); - fclose( fIn ); - /* if there is no process, remove the stale file */ - if( kill( pid, 0 ) ){ - fprintf(stderr, "Remove a stale pid file %s\n", name ); - pidfile_rm( vsrv ); - return 0; - } - /* if the kill suceed, return an error */ - return -1; + char *name = pidfile_get_name(vsrv); + FILE *fIn = fopen( name, "r" ); + pid_t pid; + /* if there is no file */ + if( !fIn ) return 0; + fscanf( fIn, "%d", &pid ); + fclose( fIn ); + /* if there is no process, remove the stale file */ + if( kill( pid, 0 ) ){ + fprintf(stderr, "Remove a stale pid file %s\n", name ); + pidfile_rm( vsrv ); + return 0; + } + /* if the kill suceed, return an error */ + return -1; } - - /**************************************************************** - NAME : in_csum 00/05/10 20:12:20 - AIM : compute a IP checksum - REMARK : from kuznet's iputils + NAME : in_csum 00/05/10 20:12:20 + AIM : compute a IP checksum + REMARK : from kuznet's iputils ****************************************************************/ 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); + 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); } - /**************************************************************** - NAME : get_dev_from_ip 00/02/08 06:51:32 - AIM : - REMARK : + NAME : get_dev_from_ip 00/02/08 06:51:32 + AIM : + REMARK : ****************************************************************/ 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; + 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; } /**************************************************************** - NAME : get_dev_from_ip 00/02/08 06:51:32 - AIM : - REMARK : + NAME : get_dev_from_ip 00/02/08 06:51:32 + AIM : + REMARK : ****************************************************************/ 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; + 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; } /**************************************************************** - NAME : rcvhwaddr_op 00/02/08 06:51:32 - AIM : - REMARK : + NAME : rcvhwaddr_op 00/02/08 06:51:32 + AIM : + REMARK : ****************************************************************/ 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 ){ - printf("Can't %s on %s. errno=%d\n" - , addF ? "SIOCADDMULTI" : "SIOCDELMULTI" - , ifname, errno ); - } - close(fd); - return ret; + 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 ){ + printf("Can't %s on %s. errno=%d\n" + , addF ? "SIOCADDMULTI" : "SIOCDELMULTI" + , ifname, errno ); + } + close(fd); + return ret; } /**************************************************************** - NAME : hwaddr_set 00/02/08 06:51:32 - AIM : - REMARK : linux refuse to change the hwaddress if the interface is up + NAME : hwaddr_set 00/02/08 06:51:32 + AIM : + REMARK : linux refuse to change the hwaddress if the interface is up ****************************************************************/ 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; + 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 ) printf("error errno=%d\n",errno); +if( ret ) printf("error errno=%d\n",errno); - close(fd); - return ret; + close(fd); + return ret; } /**************************************************************** - NAME : hwaddr_get 00/02/08 06:51:32 - AIM : - REMARK : + NAME : hwaddr_get 00/02/08 06:51:32 + AIM : + REMARK : ****************************************************************/ 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 ); + 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 ); //printf("%x:%x:%x:%x:%x:%x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] ); - close(fd); - return ret; + close(fd); + return ret; } /**************************************************************** - NAME : ipaddr_ops 00/02/08 06:51:32 - AIM : - REMARK : + NAME : ipaddr_ops 00/02/08 06:51:32 + AIM : + REMARK : ****************************************************************/ 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); - VRRP_LOG(("cant %s the address %s to %s\n" - , addF ? "set" : "remove" - , inet_ntoa(in) - , vsrv->vif.ifname)); - }else{ - vadd->deletable = 1; - } - } - return err; + 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); + VRRP_LOG(("cant %s the address %s to %s\n" + , addF ? "set" : "remove" + , inet_ntoa(in) + , vsrv->vif.ifname)); + }else{ + vadd->deletable = 1; + } + } + return err; } /**************************************************************** - NAME : vrrp_dlthd_len 00/02/02 15:16:23 - AIM : return the vrrp header size in byte - REMARK : + NAME : vrrp_dlthd_len 00/02/02 15:16:23 + AIM : return the vrrp header size in byte + REMARK : ****************************************************************/ static int vrrp_dlt_len( vrrp_rt *rt ) { - return ETHER_HDR_LEN; /* hardcoded for ethernet */ + return ETHER_HDR_LEN; /* hardcoded for ethernet */ } /**************************************************************** - NAME : vrrp_iphdr_len 00/02/02 15:16:23 - AIM : return the ip header size in byte - REMARK : + NAME : vrrp_iphdr_len 00/02/02 15:16:23 + AIM : return the ip header size in byte + REMARK : ****************************************************************/ static int vrrp_iphdr_len( vrrp_rt *vsrv ) { - return sizeof( struct iphdr ); + return sizeof( struct iphdr ); +} + +/**************************************************************** + NAME : vrrp_ipsecah_len 01/05/23 12:26:27 + AIM : return the ipsec AH header size in byte + CONTRIB : Alexandre Cassen : 2001/05/23 +****************************************************************/ +static int vrrp_ipsecah_len( vrrp_rt *vsrv ) +{ + return sizeof( ipsec_ah ); } /**************************************************************** - NAME : vrrp_hd_len 00/02/02 15:16:23 - AIM : return the vrrp header size in byte - REMARK : + NAME : vrrp_hd_len 00/02/02 15:16:23 + AIM : return the vrrp header size in byte + REMARK : ****************************************************************/ static int vrrp_hd_len( vrrp_rt *vsrv ) { - return sizeof( vrrp_pkt ) + vsrv->naddr*sizeof(uint32_t) - + VRRP_AUTH_LEN; + return sizeof( vrrp_pkt ) + vsrv->naddr*sizeof(uint32_t) + + VRRP_AUTH_LEN; } /**************************************************************** - NAME : vrrp_in_chk 00/02/02 12:54:54 - AIM : check a incoming packet. return 0 if the pkt is valid, != 0 else - REMARK : rfc2338.7.1 -****************************************************************/ -static int vrrp_in_chk( vrrp_rt *vsrv, struct iphdr *ip ) -{ - int ihl = ip->ihl << 2; - vrrp_pkt * hd = (vrrp_pkt *)((char *)ip + ihl); - vrrp_if *vif = &vsrv->vif; - /* MUST verify that the IP TTL is 255 */ - if( ip->ttl != VRRP_IP_TTL ) { - VRRP_LOG(("invalid ttl. %d and expect %d", ip->ttl,VRRP_IP_TTL)); - return 1; - } - /* MUST verify the VRRP version */ - if( (hd->vers_type >> 4) != VRRP_VERSION ){ - VRRP_LOG(("invalid version. %d and expect %d" - , (hd->vers_type >> 4), VRRP_VERSION)); - return 1; - } - /* 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) ){ - VRRP_LOG(("ip payload too short. %d and expect at least %d" - , ntohs(ip->tot_len)-ihl, sizeof(vrrp_pkt) )); - return 1; - } - /* WORK: MUST verify the VRRP checksum */ - if( in_csum( (u_short*)hd, vrrp_hd_len(vsrv), 0) ){ - VRRP_LOG(("Invalid vrrp checksum" )); - return 1; - } -/* MUST perform authentication specified by Auth Type */ - /* check the authentication type */ - if( vif->auth_type != hd->auth_type ){ - VRRP_LOG(("receive a %d auth, expecting %d!", vif->auth_type - , hd->auth_type)); - return 1; - } - /* 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)) ){ - VRRP_LOG(("receive an invalid passwd!")); - return 1; - } - } - - /* MUST verify that the VRID is valid on the receiving interface */ - if( vsrv->vrid != hd->vrid ){ - return 1; - } - - /* MAY verify that the IP address(es) associated with the VRID are - ** valid */ - /* WORK: currently we don't */ - - /* 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 ){ - VRRP_LOG(("advertissement interval mismatch mine=%d rcved=%d" - , vsrv->adver_int, hd->adver_int )); - return 1; - } - - /* Scott added 9-4-02 */ - master_ipaddr = ip->saddr; - return 0; -} - -/**************************************************************** - NAME : vrrp_build_dlt 00/02/02 14:39:18 - AIM : - REMARK : rfc2338.7.3 + NAME : vrrp_in_chk_ipsecah 01/05/23 15:55:23 + AIM : check ipsec ah. return 0 for a valid pkt, != 0 else. + CONTRIB : Alexandre Cassen : 2001/05/23 + SA lookup, sequence number verif, ICV verif +****************************************************************/ +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 ) { + vrrpd_log(LOG_ERR,"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 + printf("Processing SEQUENCE NUMBER : %d\n",ah->seq_number); +#endif + vsrv->ipsecah_counter.seq_number = ah->seq_number; + } else { + vrrpd_log(LOG_ERR,"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 *)); + assert( digest ); + 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) { + vrrpd_log(LOG_ERR,"invalid IPSEC HMAC-MD5 value. Due to fields mutation or bad password !"); + return 1; + } + + free(digest); + return 0; +} + +/**************************************************************** + NAME : vrrp_in_chk_vips 01/05/23 15:55:23 + AIM : check if ipaddr is present in VIP buffer + CONTRIB : Alexandre Cassen : 2001/05/23 +****************************************************************/ +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; +} + +/**************************************************************** + NAME : vrrp_alloc_pkt + AIM : return a correctly aligned buffer that holds buflen + REMARK: the buffer must be aligned such that the IP or ARP + header is 32-bit aligned. + The alignment fixup is stored one byte before the + returned address, for use by vrrp_free_pkt() +****************************************************************/ +static char * vrrp_alloc_pkt( vrrp_rt *rt, int buf_len ) +{ + int alignment; + char * unaligned_buffer, * buffer; + + unaligned_buffer = calloc( buf_len + 4, 1 ); + assert( unaligned_buffer ); + alignment = ((unaligned_buffer - (char*)0) + vrrp_dlt_len(rt)) & 3; + buffer = unaligned_buffer + (4 - alignment); + *(buffer-1) = alignment; + return buffer; +} + +/**************************************************************** + NAME : vrrp_free_pkt + AIM : free a buffer allocated with vrrp_alloc_pkt() + REMARK: +****************************************************************/ +static void vrrp_free_pkt( vrrp_rt *rt, char *buffer) +{ + int alignment; + + alignment = *(buffer-1); + free( buffer - alignment ); +} + +/**************************************************************** + NAME : vrrp_in_chk 01/05/23 12:54:54 + AIM : check a incoming packet. return 0 if the pkt is valid, != 0 else + REMARK : rfc2338.7.1 + CHANGES : Alexandre Cassen : 2001/05/23 : + <+> Added IPSEC AH checks + <+> Added check for IPs addr associated with he VRID +****************************************************************/ +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 ) { + vrrpd_log(LOG_ERR,"invalid ttl. %d and expected %d", ip->ttl,VRRP_IP_TTL); + return 1; + } + /* MUST verify the VRRP version */ + if( (hd->vers_type >> 4) != VRRP_VERSION ){ + vrrpd_log(LOG_ERR,"invalid version. %d and expected %d", (hd->vers_type >> 4), VRRP_VERSION); + return 1; + } + /* 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) ){ + vrrpd_log(LOG_ERR,"ip payload too short. %d and expected at least %d" + , ntohs(ip->tot_len)-ihl, sizeof(vrrp_pkt) ); + return 1; + } + /* WORK: MUST verify the VRRP checksum */ + if( in_csum( (u_short*)hd, vrrp_hd_len(vsrv), 0) ){ + vrrpd_log(LOG_ERR,"Invalid vrrp checksum" ); + return 1; + } + /* MUST perform authentication specified by Auth Type */ + /* check the authentication type */ + if( vif->auth_type != hd->auth_type ){ + vrrpd_log(LOG_ERR,"received a %d auth, expecting %d!", vif->auth_type, hd->auth_type); + return 1; + } + /* 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)) ){ + vrrpd_log(LOG_ERR,"receive an invalid passwd!"); + return 1; + } + } + + /* MUST verify that the VRID is valid on the receiving interface */ + if( vsrv->vrid != hd->vrid ){ + return 1; + } + + /* MAY verify that the IP address(es) associated with the VRID are + ** valid */ + if (vsrv->naddr != hd->naddr) { + vrrpd_log(LOG_ERR,"receive an invalid ip number count associated with VRID!"); + return 1; + } + + for ( i=0; i < vsrv->naddr; i++ ) + if (!vrrp_in_chk_vips(vsrv,vsrv->vaddr[i].addr,vips)) { + vrrpd_log(LOG_ERR,"ip address associated with VRID not present in received packet : %d",vsrv->vaddr[i].addr); + vrrpd_log(LOG_ERR,"one or more VIP associated with VRID mismatch actual MASTER advert"); + vrrpd_log(LOG_ERR,"EXITING"); + exit(1); /* Ugly */ + } + + /* 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 ){ + vrrpd_log(LOG_ERR,"advertisement interval mismatch mine=%d rcved=%d" + , vsrv->adver_int, hd->adver_int ); + vrrpd_log(LOG_ERR,"EXITING"); + exit(1); /* Ugly too : to prevent concurent VRID running => multiple master in 1 VRID */ + } + + /* Set the address of the Master */ + master_ipaddr = ip->saddr; + + /* check the authenicaion if it is ipsec ah */ + if( hd->auth_type == VRRP_AUTH_AH ) + return(vrrp_in_chk_ipsecah(vsrv,buffer)); + + return 0; +} + +/**************************************************************** + NAME : vrrp_build_dlt 00/02/02 14:39:18 + AIM : + REMARK : rfc2338.7.3 ****************************************************************/ 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, vrrp_hwaddr, sizeof(vrrp_hwaddr)); - /* type */ - eth->ether_type = htons( ETHERTYPE_IP ); + /* 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, vrrp_hwaddr, sizeof(vrrp_hwaddr)); + /* type */ + eth->ether_type = htons( ETHERTYPE_IP ); } /**************************************************************** - NAME : vrrp_build_ip 00/02/02 14:39:18 - AIM : build a ip packet - REMARK : + NAME : vrrp_build_ip 00/02/02 14:39:18 + AIM : build a ip packet + REMARK : + CHANGES : Alexandre Cassen : 2001/05/23 : + <+> IPSEC AH protocol handling ****************************************************************/ 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 = ++ip_id; - ip->frag_off = 0; - ip->ttl = VRRP_IP_TTL; - ip->protocol = 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 ); + 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 = ++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 ); +} + +/**************************************************************** + NAME : vrrp_build_ipsecah 01/05/23 15:55:23 + AIM : build a ipsec ah packet + CONTRIB : Alexandre Cassen : 2001/05/23 +****************************************************************/ +static void vrrp_build_ipsecah( vrrp_rt *vsrv, char *buffer, int buflen ) +{ +#ifdef DEBUG + int di; +#endif + 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); + assert( ip_mutable_fields ); + 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 ); + +//printf("----[ Header IP ]----\nChecksump = %02x\n",ip->check); +//print_buffer((int)ip->ihl*4,(char *)ip); + + /* 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 : + */ + 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 *)); + assert( digest ); + 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); + +#ifdef DEBUG + printf("\n----------[ Buffer IPSEC AH : Begin ]----------\n"); + print_buffer(buflen,buffer); + printf("IPSEC AH key value : 0x"); + for (di=0;di<8;++di) printf("%02x",vsrv->vif.auth_data[di]); + printf("\n"); + printf("IPSEC AH digest value : 0x"); + for (di=0;di<16;++di) printf("%02x",digest[di]); + printf("\n"); + printf("----------[ Buffer IPSEC AH : End ]----------\n"); +#endif + + /* 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); } /**************************************************************** - NAME : vrrp_build_vrrp 00/02/02 14:39:18 - AIM : - REMARK : + NAME : vrrp_build_vrrp 00/02/02 14:39:18 + AIM : + REMARK : ****************************************************************/ 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 ); - } - /* 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)); - } - /* Must perform the checksum AFTER we copy the password */ - hd->chksum = in_csum( (u_short*)hd, vrrp_hd_len(vsrv), 0); - return(0); + 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 ); + } + /* 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)); + } + /* Must perform the checksum AFTER we copy the password */ + hd->chksum = in_csum( (u_short*)hd, vrrp_hd_len(vsrv), 0); + return(0); } /**************************************************************** - NAME : vrrp_set_ptk 00/02/02 13:33:32 - AIM : build a advertissement packet - REMARK : + NAME : vrrp_set_ptk 00/02/02 13:33:32 + AIM : build a advertissement packet + REMARK : + CHANGES : Alexandre Cassen : 2001/05/23 : + <+> IPSEC AH header processing ****************************************************************/ static void vrrp_build_pkt( vrrp_rt *vsrv, int prio, char *buffer, int buflen ) { -// printf("dltlen=%d iplen=%d", vrrp_dlt_len(vsrv), vrrp_iphdr_len(vsrv) ); - /* build the ethernet header */ - vrrp_build_dlt( vsrv, buffer, buflen ); - buffer += vrrp_dlt_len(vsrv); - buflen -= vrrp_dlt_len(vsrv); - /* build the ip header */ - vrrp_build_ip( vsrv, buffer, buflen ); - buffer += vrrp_iphdr_len(vsrv); - buflen -= vrrp_iphdr_len(vsrv); - /* build the vrrp header */ - vrrp_build_vrrp( vsrv, prio, buffer, buflen ); + char *bufptr; + + bufptr=buffer; +// printf("dltlen=%d iplen=%d ahlen=%d", vrrp_dlt_len(vsrv), vrrp_iphdr_len(vsrv),vrrp_ipsecah_len(vsrv) ); + /* 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 ); + } } /**************************************************************** - NAME : vrrp_send_pkt 00/02/06 16:37:10 - AIM : - REMARK : + NAME : vrrp_send_pkt 00/02/06 16:37:10 + AIM : + REMARK : ****************************************************************/ 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 */ + struct sockaddr from; + int len; + int fd = socket(PF_PACKET, SOCK_PACKET, 0x300); /* 0x300 is magic */ // WORK: - if( fd < 0 ){ - perror( "socket" ); - 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) ); -//printf("len=%d\n",len); - close( fd ); - return len; + if( fd < 0 ){ + perror( "socket" ); + 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; } /**************************************************************** - NAME : vrrp_send_adv 00/02/06 16:31:24 - AIM : - REMARK : + NAME : vrrp_send_adv 00/02/06 16:31:24 + AIM : + REMARK : + CHANGES : Alexandre Cassen : 2001/05/23 : + <+> IPSEC AH header memory allocation ****************************************************************/ static int vrrp_send_adv( vrrp_rt *vsrv, int prio ) { - int buflen, ret; - char * buffer; -#if 0 /* just for debug */ - struct in_addr in; - in.s_addr = htonl(vsrv->vif.ipaddr); - printf("send an advertissement on %s\n",inet_ntoa(in) ); + int buflen, ret; + char *buffer; +#if 0 /* just for debug */ + struct in_addr in; + in.s_addr = htonl(vsrv->vif.ipaddr); + printf("send an advertissement on %s\n",inet_ntoa(in) ); +#endif + /* 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 = vrrp_alloc_pkt( vsrv, buflen ); + 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 + printf("\nSended Advertisment\n"); + print_buffer(buflen,buffer); #endif - /* alloc the memory */ - buflen = vrrp_dlt_len(vsrv) + vrrp_iphdr_len(vsrv) + vrrp_hd_len(vsrv); - buffer = calloc( buflen, 1 ); - assert( buffer ); - /* build the packet */ - vrrp_build_pkt( vsrv, prio, buffer, buflen ); - /* send it */ - ret = vrrp_send_pkt( vsrv, buffer, buflen ); - /* build the memory */ - free( buffer ); - return ret; + /* build the memory */ + vrrp_free_pkt( vsrv, buffer ); + /* This free() generates an error ? - jfs */ + /* free( buffer ); */ + return ret; } - /**************************************************************** - NAME : usage 00/02/06 08:50:28 - AIM : display the usage - REMARK : + NAME : usage 00/02/06 08:50:28 + AIM : display the usage + REMARK : ****************************************************************/ static void usage( void ) { - fprintf( stderr, "vrrpd version %s\n", VRRPD_VERSION ); - fprintf( stderr, "Usage: vrrpd -i ifname -v vrid [-f piddir] [-s] [-a auth] [-p prio] [-nh] ipaddr\n" ); - fprintf( stderr, " -h : display this short inlined help\n" ); - fprintf( stderr, " -n : Dont handle the virtual mac address\n" ); - fprintf( stderr, " -i ifname: the interface name to run on\n" ); - fprintf( stderr, " -v vrid : the id of the virtual server [1-255]\n" ); - fprintf( stderr, " -s : Switch the preemption mode (%s by default)\n" - , VRRP_PREEMPT_DFL? "Enabled" : "Disabled" ); - fprintf( stderr, " -a auth : (not yet implemented) set the authentification type\n" ); - fprintf( stderr, " auth=(none|pass/hexkey|ah/hexkey) hexkey=0x[0-9a-fA-F]+\n"); - fprintf( stderr, " -p prio : Set the priority of this host in the virtual server (dfl: %d)\n" - , VRRP_PRIO_DFL ); - fprintf( stderr, " -f piddir: specify the directory where the pid file is stored (dfl: %s)\n" - , VRRP_PIDDIR_DFL ); - fprintf( stderr, " -d delay : Set the advertisement interval (in sec) (dfl: %d)\n" - , VRRP_ADVER_DFL ); - fprintf( stderr, " ipaddr : the ip address(es) of the virtual server\n" ); + fprintf( stderr, "vrrpd version %s\n", VRRPD_VERSION ); + fprintf( stderr, "Usage: vrrpd -i ifname -v vrid [-f piddir] [-s] [-a auth] [-p prio] [-m ifname] [-c delta] [-nhD] ipaddr\n" ); + fprintf( stderr, " -h : display this short inlined help\n" ); + fprintf( stderr, " -n : Dont handle the virtual mac address\n" ); + fprintf( stderr, " -D : Go to background, daemonize\n" ); + fprintf( stderr, " -i ifname: the interface name to run on\n" ); + fprintf( stderr, " -v vrid : the id of the virtual server [1-255]\n" ); + fprintf( stderr, " -s : Switch the preemption mode (%s by default)\n" + , VRRP_PREEMPT_DFL? "Enabled" : "Disabled" ); + fprintf( stderr, " -a auth : set the authentification type\n" ); + fprintf( stderr, " auth=(none|pass/hexkey|ah/hexkey) hexkey=0x[0-9a-fA-F]+\n"); + fprintf( stderr, " -p prio : Set the priority of this host in the virtual server (dfl: %d)\n" + , VRRP_PRIO_DFL ); + fprintf( stderr, " -f piddir: specify the directory where the pid file is stored (dfl: %s)\n" + , VRRP_PIDDIR_DFL ); + fprintf( stderr, " -d delay : Set the advertisement interval (in sec) (dfl: %d)\n" + , VRRP_ADVER_DFL ); + fprintf( stderr, " -m ifname: Interface(s) to monitor for failure\n"); + fprintf( stderr, " Use \x22 \x22 for multiple interfaces\n"); + fprintf( stderr, " -c delta : Set the delta to decrease priority by (dfl: %d)\n" + , VRRP_DELTA_DFL ); + fprintf( stderr, " -l name : use this name is syslog messages (helps in case several vrid run)\n"); + fprintf( stderr, " ipaddr : the ip address(es) of the virtual server\n" ); } /**************************************************************** - NAME : parse_authopt 00/09/26 22:01:17 - AIM : - REMARK : parse the authentication option from the user + NAME : parse_authopt 00/09/26 22:01:17 + AIM : + REMARK : parse the authentication option from the user ****************************************************************/ static int parse_authopt(vrrp_rt *vsrv, char *str) { - int len = strlen(str); - vrrp_if *vif = &vsrv->vif; - - vif->auth_type = VRRP_AUTH_NONE; - /* epxlicitly no authentication */ - if( !strcmp(str,"none") ) return 0; - /* below the min len */ - if( len < 5 ) return -1; - /* check the type of authentication */ - if( !strncmp(str, "ah/0x", 5 ) ){ - vif->auth_type = VRRP_AUTH_AH; - return -1; /* WORK: not yet implemented */ -#if 0 // I don't know what he was trying to do here! -- Scott 9-6-02 - }else if( !strncmp(str, "pw/", 5 ) ){ - int i,j; - vif->auth_type = VRRP_AUTH_PASS; - memset( vif->auth_data, 0, sizeof(vif->auth_data) ); - /* parse the key */ - for( i=5,j=0; j < sizeof(vif->auth_data)*2 && i= 'A' ) str[i] -= 'A' - 10; - else str[i] -= '0'; - vif->auth_data[j/2] |= str[i] << (j&1 ? 0 : 4 ); -//WORK: printf(" j=%d c=%d 0x%x\n",j,str[i],vif->auth_data[j/2]); - } - if( i != len ) return -1; -#endif - }else if( !strncmp(str, "pw/", 3 ) ){ - vif->auth_type = VRRP_AUTH_PASS; - // Must set unused bytes to 0 - memset (vif->auth_data, 0, sizeof(vif->auth_data) ); - // Simply copy up to 8 characters - if (len > 11) - len = 11; - memcpy (vif->auth_data, &str[3], len - 3); - }else{ - return -1; - } - return(0); -} - - -/**************************************************************** - NAME : parse_cmdline 00/02/06 09:09:11 - AIM : - REMARK : -****************************************************************/ -static int parse_cmdline( vrrp_rt *vsrv, int argc, char *argv[] ) -{ - vrrp_if *vif = &vsrv->vif; - int c; - while( 1 ){ - c = getopt( argc, argv, "f:si:v:a:p:d:hn" ); - /* if the parsing is completed, exit */ - if( c == EOF ) break; - switch( c ){ - case 'n': - vsrv->no_vmac = 1; - break; - case 's': - vsrv->preempt = !vsrv->preempt; - break; - case 'f': - snprintf( PidDir, sizeof(PidDir), "%s", optarg ); - break; - case 'i': - vif->ifname = strdup( optarg ); - /* get the ip address */ - vif->ipaddr = ifname_to_ip( optarg ); - if( !vif->ipaddr ){ - fprintf( stderr, "no interface found!\n" ); - goto err; - } - /* get the hwaddr */ - if( hwaddr_get( vif->ifname, vif->hwaddr - , sizeof(vif->hwaddr)) ){ - fprintf( stderr, "Can't read the hwaddr on this interface!\n" ); - goto err; - } -// printf("ifname=%s 0x%x\n",vsrv->vif.ifname,vsrv->vif.ipaddr); - break; - case 'v': - vsrv->vrid = atoi( optarg ); - if( VRRP_IS_BAD_VID(vsrv->vrid) ){ - fprintf( stderr, "bad vrid!\n" ); - goto err; - } - vrrp_hwaddr[0] = 0x00; - vrrp_hwaddr[1] = 0x00; - vrrp_hwaddr[2] = 0x5E; - vrrp_hwaddr[3] = 0x00; - vrrp_hwaddr[4] = 0x01; - vrrp_hwaddr[5] = vsrv->vrid; - break; - case 'a': - if( parse_authopt( vsrv, optarg ) ){ - fprintf( stderr, "Invalid authentication key!\n" ); - goto err; - } - break; - case 'p': - vsrv->priority = atoi( optarg ); - if( VRRP_IS_BAD_PRIORITY(vsrv->priority) ){ - fprintf( stderr, "bad priority!\n" ); - goto err; - } - break; - case 'd': - vsrv->adver_int = atoi( optarg ); - if( VRRP_IS_BAD_ADVERT_INT(vsrv->adver_int) ){ - fprintf( stderr, "bad advert_int!\n" ); - goto err; - } - vsrv->adver_int *= VRRP_TIMER_HZ; - break; - case 'h': - usage(); - exit( 1 ); break; - case ':': /* missing parameter */ - case '?': /* unknown option */ - default: - goto err; - } - } - return optind; + int len = strlen(str); + int i,j; + vrrp_if *vif = &vsrv->vif; + + vif->auth_type = VRRP_AUTH_NONE; + /* epxlicitly no authentication */ + if( !strcmp(str,"none") ) return 0; + /* below the min len */ + if( len < 5 ) return -1; + + /* check the type of authentication */ + /* IPSEC AH authentication type */ + if( !strncmp(str, "ah/0x", 5 ) ){ + vif->auth_type = VRRP_AUTH_AH; + memset( vif->auth_data, 0, sizeof(vif->auth_data) ); + /* parse the key */ + for( i=5,j=0; j < sizeof(vif->auth_data)*2 && i= 'A' ) str[i] -= 'A' - 10; + else str[i] -= '0'; + vif->auth_data[j/2] |= str[i] << (j&1 ? 0 : 4 ); + } + if( i != len ) return -1; + + /* Password based authentication type */ + } else if( !strncmp(str, "pw/0x", 5 ) ){ + vif->auth_type = VRRP_AUTH_PASS; + memset( vif->auth_data, 0, sizeof(vif->auth_data) ); + /* parse the key */ + for( i=5,j=0; j < sizeof(vif->auth_data)*2 && i= 'A' ) str[i] -= 'A' - 10; + else str[i] -= '0'; + vif->auth_data[j/2] |= str[i] << (j&1 ? 0 : 4 ); +//WORK: printf(" j=%d c=%d 0x%x\n",j,str[i],vif->auth_data[j/2]); + } + if( i != len ) return -1; + }else{ + return -1; + } + return(0); +} + +/**************************************************************** + NAME : parse_cmdline 00/02/06 09:09:11 + AIM : + REMARK : + CHANGES : Chao-Cheng Wu : 2003/11/16 : + <-> Backup routing table +****************************************************************/ +static int parse_cmdline( vrrp_rt *vsrv, int argc, char *argv[], int *daemon ) +{ + vrrp_if *vif = &vsrv->vif; +// struct rt_entry rt_table; + int c, i = 0; + char *int_list; + + while( 1 ){ + c = getopt( argc, argv, "f:si:v:a:p:d:m:c:hnDl:" ); + /* if the parsing is completed, exit */ + if( c == EOF ) break; + switch( c ){ + case 'n': + vsrv->no_vmac = 1; + break; + case 's': + vsrv->preempt = !vsrv->preempt; + break; + case 'f': + snprintf( PidDir, sizeof(PidDir), "%s", optarg ); + break; + case 'l': + snprintf( VridName, sizeof(VridName), "vrrpd->%s", optarg ); + break; + case 'i': + vif->ifname = strdup( optarg ); + /* get the ip address */ + vif->ipaddr = ifname_to_ip( optarg ); + if( !vif->ipaddr ){ + fprintf( stderr, "no interface found!\n" ); + goto err; + } + /* get the hwaddr */ + if( hwaddr_get( vif->ifname, vif->hwaddr + , sizeof(vif->hwaddr)) ){ + fprintf( stderr, "Can't read the hwaddr on this interface!\n" ); + goto err; + } + /* backup the routing table */ +// memset(&rt_table, 0, sizeof(struct rt_entry)); +// if (!rt_fetch(&rt_table)) { +// fprintf(stderr, "Can't parse routing table !\n"); +// goto err; +// } +// vif->rt = rt_table.next; +// rt_dump(vif->rt); +// rt_clear(vif->rt); + break; + case 'v': + vsrv->vrid = atoi( optarg ); + if( VRRP_IS_BAD_VID(vsrv->vrid) ){ + fprintf( stderr, "bad vrid!\n" ); + goto err; + } + vrrp_hwaddr[0] = 0x00; + vrrp_hwaddr[1] = 0x00; + vrrp_hwaddr[2] = 0x5E; + vrrp_hwaddr[3] = 0x00; + vrrp_hwaddr[4] = 0x01; + vrrp_hwaddr[5] = vsrv->vrid; + break; + case 'a': + if( parse_authopt( vsrv, optarg ) ){ + fprintf( stderr, "Invalid authentication key!\n" ); + goto err; + } + break; + case 'p': + vsrv->orig_prio = vsrv->priority = atoi( optarg ); + if( VRRP_IS_BAD_PRIORITY(vsrv->priority) ){ + fprintf( stderr, "bad priority!\n" ); + goto err; + } + break; + case 'd': + vsrv->adver_int = atoi( optarg ); + if( VRRP_IS_BAD_ADVERT_INT(vsrv->adver_int) ){ + fprintf( stderr, "bad adver_int!\n" ); + goto err; + } + vsrv->adver_int *= VRRP_TIMER_HZ; + break; + case 'm': + int_list = strdup( optarg ); + ifname[i++] = strtok( int_list, " " ); + while (( ifname[i++] = strtok( NULL, " " )) != NULL ); + for ( i = 0; ifname[i] != NULL; init_int( i++ )); + break; + case 'c': + vsrv->delt_prio = atoi( optarg ); + if( VRRP_IS_BAD_PRIORITY(vsrv->delt_prio) ){ + fprintf( stderr, "bad priority delta!\n" ); + goto err; + } + break; + case 'D': + *daemon = 1; + break; + case 'h': + usage(); + exit( 1 ); break; + case ':': /* missing parameter */ + case '?': /* unknown option */ + default: + goto err; + } + } + return optind; err:; - usage(); - return -1; + usage(); + return -1; } /**************************************************************** - NAME : cfg_add_ipaddr 00/02/06 09:24:08 - AIM : - REMARK : + NAME : cfg_add_ipaddr 00/02/06 09:24:08 + AIM : + REMARK : ****************************************************************/ static void cfg_add_ipaddr( 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) ); - } - assert( vsrv->vaddr ); - /* store the data */ - vsrv->vaddr[vsrv->naddr-1].addr = ipaddr; - vsrv->vaddr[vsrv->naddr-1].deletable = 0; + 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) ); + } + assert( vsrv->vaddr ); + /* store the data */ + vsrv->vaddr[vsrv->naddr-1].addr = ipaddr; + vsrv->vaddr[vsrv->naddr-1].deletable = 0; } /**************************************************************** - NAME : init_virtual_srv 00/02/06 09:18:02 - AIM : - REMARK : + NAME : init_virtual_srv 00/02/06 09:18:02 + AIM : + REMARK : ****************************************************************/ static void init_virtual_srv( vrrp_rt *vsrv ) { - memset( vsrv, 0, sizeof(*vsrv) ); - vsrv->state = VRRP_STATE_INIT; - vsrv->priority = VRRP_PRIO_DFL; - vsrv->adver_int = VRRP_ADVER_DFL*VRRP_TIMER_HZ; - vsrv->preempt = VRRP_PREEMPT_DFL; + memset( vsrv, 0, sizeof(*vsrv) ); + vsrv->state = VRRP_STATE_INIT; + vsrv->priority = VRRP_PRIO_DFL; + vsrv->adver_int = VRRP_ADVER_DFL*VRRP_TIMER_HZ; + vsrv->preempt = VRRP_PREEMPT_DFL; + vsrv->delt_prio = VRRP_DELTA_DFL; } /**************************************************************** - NAME : chk_min_cfg 00/02/06 17:07:45 - AIM : TRUE if the minimal configuration isnt done - REMARK : + NAME : chk_min_cfg 00/02/06 17:07:45 + AIM : TRUE if the minimal configuration isnt done + REMARK : ****************************************************************/ static int chk_min_cfg( vrrp_rt *vsrv ) { - if( vsrv->naddr == 0 ){ - fprintf(stderr, "provide at least one ip for the virtual server\n"); - return -1; - } - if( vsrv->vrid == 0 ){ - fprintf(stderr, "the virtual id must be set!\n"); - return -1; - } - if( vsrv->vif.ipaddr == 0 ){ - fprintf(stderr, "the interface ipaddr must be set!\n"); - return -1; - } - /* make vrrp use the native hwaddr and not the virtual one */ - if( vsrv->no_vmac ){ - memcpy( vrrp_hwaddr, vsrv->vif.hwaddr,sizeof(vsrv->vif.hwaddr)); - } - return(0); + if( vsrv->naddr == 0 ){ + fprintf(stderr, "provide at least one ip for the virtual server\n"); + return -1; + } + if( vsrv->vrid == 0 ){ + fprintf(stderr, "the virtual id must be set!\n"); + return -1; + } + if( vsrv->vif.ipaddr == 0 ){ + fprintf(stderr, "the interface ipaddr must be set!\n"); + return -1; + } + /* make vrrp use the native hwaddr and not the virtual one */ + if( vsrv->no_vmac ){ + memcpy( vrrp_hwaddr, vsrv->vif.hwaddr,sizeof(vsrv->vif.hwaddr)); + } + if(( ifname[0] == NULL ) && (vsrv->delt_prio != VRRP_DELTA_DFL )){ + fprintf(stderr, "provide at least one monitored interface!\n"); + return -1; + } + return(0); } /**************************************************************** - NAME : vrrp_read 00/02/07 00:04:53 - AIM : - REMARK : + NAME : vrrp_read 00/02/07 00:04:53 + AIM : + REMARK : ****************************************************************/ static int vrrp_read( vrrp_rt *vsrv, char *buf, int buflen ) { - fd_set readfds; - struct timeval timeout; - uint32_t next = 0xFFFFFFFF; - int len = 0; - /* cpu the next timer */ - if( VRRP_TIMER_IS_RUNNING( vsrv->adver_timer ) ){ - int32_t delta = VRRP_TIMER_DELTA(vsrv->adver_timer); - if( delta < 0 ) delta = 0; - next = VRRP_MIN( next, delta ); - }else{ /* here vsrv->ms_down_timer is assumed running */ - int32_t delta = VRRP_TIMER_DELTA(vsrv->ms_down_timer); - assert( VRRP_TIMER_IS_RUNNING( vsrv->ms_down_timer ) ); - if( delta < 0 ) delta = 0; - next = VRRP_MIN( next, delta ); - } - /* setup the select() */ - FD_ZERO( &readfds ); - FD_SET( vsrv->sockfd, &readfds ); - timeout.tv_sec = next / VRRP_TIMER_HZ; - timeout.tv_usec = next % VRRP_TIMER_HZ; -//printf( "val %u,%u %u\n", timeout.tv_sec, timeout.tv_usec, next ); - if( select( vsrv->sockfd + 1, &readfds, NULL, NULL, &timeout ) > 0 ){ - len = read( vsrv->sockfd, buf, buflen ); -// printf("packet received (%d bytes)\n",len); - if( vrrp_in_chk( vsrv, (struct iphdr *)buf ) ){ -// printf("bogus packet!\n"); - len = 0; - } - } - return len; + fd_set readfds; + struct timeval timeout; + uint32_t next = 0xFFFFFFFF; + int len = 0; + + /* cpu the next timer */ + if( VRRP_TIMER_IS_RUNNING( vsrv->adver_timer ) ){ + int32_t delta = VRRP_TIMER_DELTA(vsrv->adver_timer); + if( delta < 0 ) delta = 0; + next = VRRP_MIN( next, delta ); + }else{ /* here vsrv->ms_down_timer is assumed running */ + int32_t delta = VRRP_TIMER_DELTA(vsrv->ms_down_timer); + assert( VRRP_TIMER_IS_RUNNING( vsrv->ms_down_timer ) ); + if( delta < 0 ) delta = 0; + next = VRRP_MIN( next, delta ); + } + /* setup the select() */ + FD_ZERO( &readfds ); + FD_SET( vsrv->sockfd, &readfds ); + timeout.tv_sec = next / VRRP_TIMER_HZ; + timeout.tv_usec = next % VRRP_TIMER_HZ; + +/* printf("val %lu,%lu %u\n",timeout.tv_sec,timeout.tv_usec,next); */ + + if( select( vsrv->sockfd + 1, &readfds, NULL, NULL, &timeout ) > 0 ){ + len = read( vsrv->sockfd, buf, buflen ); + +#ifdef DEBUG + printf("VRRP packet received (%d bytes)\n",len); + print_buffer(buflen,buf); +#endif + + if( vrrp_in_chk( vsrv, buf ) ){ +/* printf("bogus packet!\n"); */ + len = 0; + } + } /* else { +printf("\nTimeout receiving vrrp packet...\n"); + } */ + return len; } /**************************************************************** - NAME : send_gratuitous_arp 00/05/11 11:56:30 - AIM : - REMARK : rfc0826 - : WORK: ugly because heavily hardcoded for ethernet + NAME : send_gratuitous_arp 00/05/11 11:56:30 + AIM : + REMARK : rfc0826 + : WORK: ugly because heavily hardcoded for ethernet ****************************************************************/ static int send_gratuitous_arp( vrrp_rt *vsrv, int addr, int vAddrF ) { @@ -847,323 +1298,537 @@ 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 ? vrrp_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 ); + char buflen = sizeof(struct m_arphdr)+ETHER_HDR_LEN; + char * buf = vrrp_alloc_pkt( vsrv, buflen ); + struct ether_header *eth = (struct ether_header *)buf; + struct m_arphdr *arph = (struct m_arphdr *)(buf+vrrp_dlt_len(vsrv)); + char *hwaddr = vAddrF ? vrrp_hwaddr : vsrv->vif.hwaddr; + int hwlen = ETH_ALEN; + int rc; + + /* 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 */ + 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 ); + rc = vrrp_send_pkt( vsrv, buf, buflen ); + vrrp_free_pkt( vsrv, buf ); + return rc; } - /**************************************************************** - NAME : state_gotomaster 00/02/07 00:15:26 - AIM : - REMARK : called when the state is now MASTER + NAME : ipaddr_to_str + AIM : Convert an IP address to a string + REMARK : + CHANGES : ****************************************************************/ char *ipaddr_to_str(uint32_t ipaddr) { - static char temp_ipaddr[32]; - snprintf(temp_ipaddr, 32, "%d.%d.%d.%d", - (unsigned char)(ipaddr & 0xff), - (unsigned char)((ipaddr >> 8) & 0xff), - (unsigned char)((ipaddr >> 16) & 0xff), - (unsigned char)((ipaddr >> 24) & 0xff)); - return temp_ipaddr; + static char temp_ipaddr[32]; + snprintf(temp_ipaddr, 32, "%d.%d.%d.%d", + (unsigned char)(ipaddr & 0xff), + (unsigned char)((ipaddr >> 8) & 0xff), + (unsigned char)((ipaddr >> 16) & 0xff), + (unsigned char)((ipaddr >> 24) & 0xff)); + return temp_ipaddr; } +/**************************************************************** + NAME : state_gotomaster 00/02/07 00:15:26 + AIM : + REMARK : called when the state is now MASTER + CHANGES : Chao-Cheng Wu : 2003/11/16 : + <+> Backup routing table +****************************************************************/ static void state_goto_master( vrrp_rt *vsrv ) { - int i; - vrrp_if *vif = &vsrv->vif; + int i; + 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 */ + memset(&rt_table, 0, sizeof(struct rt_entry)); + if (!rt_fetch(&rt_table)) + fprintf(stderr, "Can't parse routing table !\n"); + vif->rt = rt_table.next; + /* set the VRRP MAC address */ + hwaddr_set( vif->ifname, vrrp_hwaddr, sizeof(vrrp_hwaddr) ); + rcvhwaddr_op( vif->ifname, vif->hwaddr, sizeof(vif->hwaddr), 1); + /* restore routing table */ + rt_restore(vif->rt, vif->ifname); + } + /* 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 ); + /* init the struct */ + VRRP_TIMER_SET( vsrv->adver_timer, vsrv->adver_int ); + vsrv->state = VRRP_STATE_MAST; + vrrpd_log(LOG_WARNING, "VRRP ID %d on %s (prio: %d): %s%swe are now the master router.", vsrv->vrid, vif->ifname, vsrv->priority, master_ipaddr ? ipaddr_to_str(master_ipaddr) : "", master_ipaddr ? " is down, " : ""); - /* set the VRRP MAC address -- rfc2338.7.3 */ - if( !vsrv->no_vmac ){ - hwaddr_set( vif->ifname, vrrp_hwaddr, sizeof(vrrp_hwaddr) ); - rcvhwaddr_op( vif->ifname, vif->hwaddr, sizeof(vif->hwaddr), 1); - } - /* 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 ); - /* init the struct */ - VRRP_TIMER_SET( vsrv->adver_timer, vsrv->adver_int ); - vsrv->state = VRRP_STATE_MAST; - vrrpd_log(LOG_WARNING, "VRRP ID %d on %s: %s%swe are now the master router.", vsrv->vrid, vif->ifname, - master_ipaddr ? ipaddr_to_str(master_ipaddr) : "", master_ipaddr ? " is down, " : ""); } /**************************************************************** - NAME : state_leavemaster 00/02/07 00:15:26 - AIM : - REMARK : called when the state is no more MASTER + NAME : state_leavemaster 00/02/07 00:15:26 + AIM : + REMARK : called when the state is no more MASTER + CHANGES : Chao-Cheng Wu : 2003/11/16 : + <+> Backup routing table ****************************************************************/ static void state_leave_master( vrrp_rt *vsrv, int advF ) { - uint32_t addr[1024]; - vrrp_if *vif = &vsrv->vif; + 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 */ + memset(&rt_table, 0, sizeof(struct rt_entry)); + if (!rt_fetch(&rt_table)) + fprintf(stderr, "Can't parse routing table !\n"); + vif->rt = rt_table.next; + /* restore the original MAC addresses */ + hwaddr_set( vif->ifname, vif->hwaddr, sizeof(vif->hwaddr) ); + rcvhwaddr_op( vif->ifname, vif->hwaddr, sizeof(vif->hwaddr), 0); + /* restore routing table */ + rt_restore(vif->rt, vif->ifname); + } + /* 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 ); + } - /* restore the original MAC addresses */ - if( !vsrv->no_vmac ){ - hwaddr_set( vif->ifname, vif->hwaddr, sizeof(vif->hwaddr) ); - rcvhwaddr_op( vif->ifname, vif->hwaddr, sizeof(vif->hwaddr), 0); - } - /* 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 ); - } } /**************************************************************** - NAME : state_init 00/02/07 00:15:26 - AIM : - REMARK : rfc2338.6.4.1 + NAME : state_init 00/02/07 00:15:26 + AIM : + REMARK : rfc2338.6.4.1 ****************************************************************/ static void state_init( vrrp_rt *vsrv ) { - if( vsrv->priority == VRRP_PRIO_OWNER - || vsrv->wantstate == VRRP_STATE_MAST ){ - state_goto_master( vsrv ); - } else { - int delay = 3*vsrv->adver_int + VRRP_TIMER_SKEW(vsrv); - VRRP_TIMER_SET( vsrv->ms_down_timer, delay ); - vsrv->state = VRRP_STATE_BACK; - vrrpd_log(LOG_WARNING, "VRRP ID %d on %s: %s%swe are now a backup router.", vsrv->vrid, vsrv->vif.ifname, - master_ipaddr ? ipaddr_to_str(master_ipaddr) : "", master_ipaddr ? " is up, " : ""); - } + if( vsrv->priority == VRRP_PRIO_OWNER + || vsrv->wantstate == VRRP_STATE_MAST ){ + state_goto_master( vsrv ); + } else { + int delay = 3*vsrv->adver_int + VRRP_TIMER_SKEW(vsrv); + VRRP_TIMER_SET( vsrv->ms_down_timer, delay ); + vsrv->state = VRRP_STATE_BACK; + vrrpd_log(LOG_WARNING, "VRRP ID %d on %s (prio: %d) : %s%swe are now a backup router.", vsrv->vrid, vsrv->vif.ifname, vsrv->priority, master_ipaddr ? ipaddr_to_str(master_ipaddr) : "", master_ipaddr ? " is up, " : ""); + } } /**************************************************************** - NAME : state_back 00/02/07 00:15:26 - AIM : - REMARK : rfc2338.6.4.2 + NAME : state_back 00/02/07 00:15:26 + AIM : + REMARK : rfc2338.6.4.2 + CHANGES : Alexandre Cassen : 2001/05/23 : + <+> Modify buffer memory allocation + <+> IPSEC AH support ****************************************************************/ static void state_back( vrrp_rt *vsrv ) { - char buf[300]; /* WORK: lame ! */ - int len = vrrp_read( vsrv, buf, sizeof(buf) ); - struct iphdr *iph = (struct iphdr *)buf; - vrrp_pkt *hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2)); - if( (!len && VRRP_TIMER_EXPIRED(vsrv->ms_down_timer)) - || vsrv->wantstate == VRRP_STATE_MAST ){ - state_goto_master( vsrv ); - return; - } - if( !len ) return; - if ( hd->priority == 0 ) { - VRRP_TIMER_SET( vsrv->ms_down_timer, VRRP_TIMER_SKEW(vsrv) ); - } else if( !vsrv->preempt || hd->priority >= vsrv->priority ) { - int delay = 3*vsrv->adver_int + VRRP_TIMER_SKEW(vsrv); - VRRP_TIMER_SET( vsrv->ms_down_timer, delay ); - } + char *buf; + int len = 0; + int buflen = 0; + struct iphdr *iph; + vrrp_pkt *hd; + +#ifdef DEBUG + printf("\nBACKUP STATE...\n"); +#endif + + /* 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; + } + + /* 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); + assert( buf ); + memset(buf,0,buflen); + /* fill the header structure */ + len = 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); + assert( buf ); + memset(buf,0,buflen); + /* fill the header structure */ + len = vrrp_read( vsrv, buf, buflen ); + iph = (struct iphdr *)buf; + hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2)); + } + + if( (!len && VRRP_TIMER_EXPIRED(vsrv->ms_down_timer)) + || vsrv->wantstate == VRRP_STATE_MAST ){ + free(buf); + state_goto_master( vsrv ); + return; + } + if( !len ) { + free(buf); + return; + } + if ( hd->priority == 0 ) { + VRRP_TIMER_SET( vsrv->ms_down_timer, VRRP_TIMER_SKEW(vsrv) ); + } else if( !vsrv->preempt || hd->priority >= vsrv->priority ) { + int delay = 3*vsrv->adver_int + VRRP_TIMER_SKEW(vsrv); + VRRP_TIMER_SET( vsrv->ms_down_timer, delay ); + } + free(buf); } /**************************************************************** - NAME : state_mast 00/02/07 00:15:26 - AIM : - REMARK : rfc2338.6.4.3 + NAME : state_mast 00/02/07 00:15:26 + AIM : + REMARK : rfc2338.6.4.3 + CHANGES : Alexandre Cassen : 2001/05/23 : + <+> Modify buffer memory allocation + <+> IPSEC AH support ****************************************************************/ static void state_mast( vrrp_rt *vsrv ) { - char buf[300]; /* WORK: lame ! */ - int len = vrrp_read( vsrv, buf, sizeof(buf) ); - struct iphdr *iph = (struct iphdr *)buf; - vrrp_pkt *hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2)); - if( vsrv->wantstate == VRRP_STATE_BACK ){ - goto be_backup; - } - if( !len && VRRP_TIMER_EXPIRED(vsrv->adver_timer) ){ - vrrp_send_adv( vsrv, vsrv->priority ); - VRRP_TIMER_SET(vsrv->adver_timer,vsrv->adver_int); - return; - } - if( !len ) return; - if( hd->priority == 0 ){ - vrrp_send_adv( vsrv, vsrv->priority ); - VRRP_TIMER_SET(vsrv->adver_timer,vsrv->adver_int); - }else if( hd->priority > vsrv->priority || - (hd->priority == vsrv->priority && - ntohl(iph->saddr) > vsrv->vif.ipaddr) ){ - int delay = 3*vsrv->adver_int + VRRP_TIMER_SKEW(vsrv); + char *buf; + int len = 0; + int buflen = 0; + int delay = 3*vsrv->adver_int + VRRP_TIMER_SKEW(vsrv); + struct iphdr *iph; + vrrp_pkt *hd; + +#ifdef DEBUG + printf("\nMASTER STATE...\n"); +#endif + + /* 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); + assert( buf ); + memset(buf,0,buflen); + /* fill the header structure */ + len = 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); + assert( buf ); + memset(buf,0,buflen); + /* fill the header structure */ + len = vrrp_read( vsrv, buf, buflen ); + iph = (struct iphdr *)buf; + hd = (vrrp_pkt *)((char *)iph + (iph->ihl<<2)); + } + + if(vsrv->wantstate == VRRP_STATE_BACK) + goto be_backup; + + /* ipsecah counter have cycled */ + if (vsrv->ipsecah_counter.cycle) + goto ipsecah_seq_number; + + if( !len && VRRP_TIMER_EXPIRED(vsrv->adver_timer) ){ + vrrp_send_adv( vsrv, vsrv->priority ); + VRRP_TIMER_SET(vsrv->adver_timer,vsrv->adver_int); + free(buf); + return; + } + if( !len ) { + free(buf); + return; + } + if( hd->priority == 0){ + vrrp_send_adv( vsrv, vsrv->priority ); + VRRP_TIMER_SET(vsrv->adver_timer,vsrv->adver_int); + }else if( hd->priority > vsrv->priority || + (hd->priority == vsrv->priority && + ntohl(iph->saddr) > vsrv->vif.ipaddr) ){ +ipsecah_seq_number: + delay = 3*vsrv->adver_int + VRRP_TIMER_SKEW(vsrv); be_backup: - VRRP_TIMER_SET( vsrv->ms_down_timer, delay ); - VRRP_TIMER_CLR( vsrv->adver_timer ); - state_leave_master( vsrv, 0 ); - vsrv->state = VRRP_STATE_BACK; - vrrpd_log(LOG_WARNING, "VRRP ID %d on %s: %s%swe are now a backup router.", vsrv->vrid, vsrv->vif.ifname, - master_ipaddr ? ipaddr_to_str(master_ipaddr) : "", master_ipaddr ? " is up, " : ""); - } + VRRP_TIMER_SET( vsrv->ms_down_timer, delay ); + VRRP_TIMER_CLR( vsrv->adver_timer ); + state_leave_master( vsrv, 0 ); + vsrv->state = VRRP_STATE_BACK; + vrrpd_log(LOG_NOTICE, "VRRP ID %d on %s (prio: %d) : %s%swe are now a backup router.", vsrv->vrid, vsrv->vif.ifname, vsrv->priority, master_ipaddr ? ipaddr_to_str(master_ipaddr) : "", master_ipaddr ? " is up, " : ""); + } + free(buf); } /**************************************************************** - NAME : open_sock 00/02/07 12:40:00 - AIM : open the socket and join the multicast group. - REMARK : + NAME : open_sock 00/02/07 12:40:00 + AIM : open the socket and join the multicast group. + REMARK : + CHANGES : Alexandre Cassen : 2001/05/23 : + <+> Added IPSEC AH socket support ****************************************************************/ static int open_sock( vrrp_rt *vsrv ) { - struct ip_mreq req; - int ret; - /* open the socket */ - vsrv->sockfd = socket( AF_INET, SOCK_RAW, IPPROTO_VRRP ); - if( vsrv->sockfd < 0 ){ - int err = errno; - VRRP_LOG(("cant open raw socket. errno=%d. (try to run it as root)\n" - , 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 (vsrv->sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, - (char *) &req, sizeof (struct ip_mreq)); - if( ret < 0 ){ - int err = errno; - VRRP_LOG(("cant do IP_ADD_MEMBERSHIP errno=%d\n",err)); - return -1; - } - return 0; + struct ip_mreq req; + int ret; + /* open the socket */ + if (vsrv->vif.auth_type == VRRP_AUTH_AH) + vsrv->sockfd = socket( AF_INET, SOCK_RAW, IPPROTO_IPSEC_AH ); + else + vsrv->sockfd = socket( AF_INET, SOCK_RAW, IPPROTO_VRRP ); + + if( vsrv->sockfd < 0 ){ + int err = errno; + VRRP_LOG(("cant open raw socket. errno=%d. (try to run it as root)\n" + , 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 (vsrv->sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + (char *) &req, sizeof (struct ip_mreq)); + if( ret < 0 ){ + int err = errno; + VRRP_LOG(("cant do IP_ADD_MEMBERSHIP errno=%d\n",err)); + return -1; + } + return 0; } /**************************************************************** - NAME : signal_end 00/05/10 23:20:36 - AIM : - REMARK : + NAME : signal_end 00/05/10 23:20:36 + AIM : + REMARK : ****************************************************************/ static void signal_end( int nosig ) { - vrrp_rt *vsrv = &glob_vsrv; + vrrp_rt *vsrv = &glob_vsrv; - /* remove the pid file */ - pidfile_rm( vsrv ); - /* if the deamon is master, leave this state */ - if( vsrv->state == VRRP_STATE_MAST ){ - state_leave_master( vsrv, 1 ); - } - exit( 0 ); + /* remove the pid file */ + pidfile_rm( vsrv ); + /* if the deamon is master, leave this state */ + if( vsrv->state == VRRP_STATE_MAST ){ + state_leave_master( vsrv, 1 ); + } + exit( 0 ); } /**************************************************************** - NAME : signal_user 00/05/10 23:20:36 - AIM : - REMARK : + NAME : signal_user 00/05/10 23:20:36 + AIM : + REMARK : ****************************************************************/ static void signal_user( int nosig ) { - vrrp_rt *vsrv = &glob_vsrv; + vrrp_rt *vsrv = &glob_vsrv; - if( nosig == SIGUSR1 ){ - vsrv->wantstate = VRRP_STATE_MAST; - } - if( nosig == SIGUSR2 ){ - vsrv->wantstate = VRRP_STATE_BACK; - } - - /* rearm the signal */ - signal( nosig, signal_user ); + if( nosig == SIGUSR1 ){ + vsrv->wantstate = VRRP_STATE_MAST; + } + if( nosig == SIGUSR2 ){ + vsrv->wantstate = VRRP_STATE_BACK; + } + + /* rearm the signal */ + signal( nosig, signal_user ); } /**************************************************************** - NAME : main 00/02/06 08:48:02 - AIM : - REMARK : + NAME : main 00/02/06 08:48:02 + AIM : + REMARK : ****************************************************************/ int main( int argc, char *argv[] ) { - vrrp_rt *vsrv = &glob_vsrv; - -#if 1 /* for debug only */ - setbuf(stdout,NULL); - setbuf(stderr,NULL); + vrrp_rt *vsrv = &glob_vsrv; + int fail_prio; + int daemonize = 0; + +#if 1 /* for debug only */ + setbuf(stdout,NULL); + setbuf(stderr,NULL); #endif - - // First we fork and kill our parent - if (fork()) - exit(0); - - vrrpd_log(LOG_WARNING, "vrrpd version %s starting...\n", VRRPD_VERSION); - - snprintf( PidDir, sizeof(PidDir), "%s", VRRP_PIDDIR_DFL ); - - init_virtual_srv(vsrv); - /* parse the command line */ - argc = parse_cmdline(vsrv,argc, argv ); - if( argc < 0 ) { - return -1; - } - /* add the virtual server ip */ - for( ; argv[argc]; argc++ ){ - uint32_t ipaddr = inet_addr( argv[argc] ); - cfg_add_ipaddr( vsrv, ntohl(ipaddr) ); - } - /* check if the minimal configuration has been done */ - if( chk_min_cfg( vsrv ) ){ - fprintf(stderr, "try '%s -h' to read the help\n", argv[0]); - return -1; - } - if( open_sock( vsrv ) ){ - return -1; - } - - /* the init is completed */ - vsrv->initF = 1; - - /* init signal handler */ - signal( SIGINT, signal_end ); - signal( SIGTERM, signal_end ); - signal( SIGUSR1, signal_user ); - signal( SIGUSR2, signal_user ); - - /* try to write a pid file */ - if( pidfile_exist( vsrv ) ) return -1; - pidfile_write( vsrv ); - - /* main loop */ - while( 1 ){ - switch( vsrv->state ){ - case VRRP_STATE_INIT: state_init( vsrv ); break; - case VRRP_STATE_BACK: state_back( vsrv ); break; - case VRRP_STATE_MAST: state_mast( vsrv ); break; - } - } + + snprintf( PidDir, sizeof(PidDir), "%s", VRRP_PIDDIR_DFL ); - return(0); + init_virtual_srv(vsrv); + /* parse the command line */ + argc = parse_cmdline(vsrv,argc, argv, &daemonize ); + if( argc < 0 ) { + return -1; + } + /* add the virtual server ip */ + for( ; argv[argc]; argc++ ){ + uint32_t ipaddr = inet_addr( argv[argc] ); + cfg_add_ipaddr( vsrv, ntohl(ipaddr) ); + } + /* check if the minimal configuration has been done */ + if( chk_min_cfg( vsrv ) ){ + fprintf(stderr, "try '%s -h' to read the help\n", argv[0]); + return -1; + } + + /* set some default syslog behaviour */ + openlog (VridName,LOG_PID,LOG_DAEMON); + + if( open_sock( vsrv ) ){ + return -1; + } + + /* the init is completed */ + vsrv->initF = 1; + + /* go into daemon mode if asked to */ + if (daemonize) { + if (daemon(0,0) == -1) { + vrrpd_log(LOG_WARNING, "vrrpd could not demonize.\n"); + exit(1); + } + } + + /* init signal handler */ + signal( SIGINT, signal_end ); + signal( SIGTERM, signal_end ); + signal( SIGUSR1, signal_user ); + signal( SIGUSR2, signal_user ); + + /* try to write a pid file */ + if( pidfile_exist( vsrv ) ) return -1; + pidfile_write( vsrv ); + + /* Set monitored interface failure priority */ + fail_prio = (( vsrv->orig_prio - vsrv->delt_prio ) > 1) ? vsrv->orig_prio - vsrv->delt_prio : 1; + + // Tell the syslog we're starting + vrrpd_log(LOG_NOTICE, "Starting (adver_int: %d, vrid: %d, use virtual mac: %s)", vsrv->adver_int,vsrv->vrid, vsrv->no_vmac ? "no" : "yes" ); + + + /* main loop */ + while( 1 ){ + if ( monitorit() ) vsrv->priority = vsrv->orig_prio; + else vsrv->priority = fail_prio; + switch( vsrv->state ){ + case VRRP_STATE_INIT: state_init( vsrv ); break; + case VRRP_STATE_BACK: state_back( vsrv ); break; + case VRRP_STATE_MAST: state_mast( vsrv ); break; + } + } + + return(0); +} + +/**************************************************************** + NAME : monitorit 2002/02/04 + AIM : Return TRUE if all interfaces are OK + REMARK : +****************************************************************/ +static int monitorit() +{ + u16 status, *data; + int i; + + for ( i = 0; ifname[i] != NULL; i++ ) { + data = (u16 *)(&ifr[i].ifr_data); + if (( status = mdio_read( data[0], 1, i )) == 0xffff ) { + fprintf(stderr, "No MII transceiver present!\n"); + return 0; + } + if ((( status & 0x0016 ) != 0x0004 ) || ( !chk_iff( i ))) return 0; + } + return 1; +} + +/**************************************************************** + NAME : mdio_read 2002/02/04 + AIM : Read MII registers from NIC driver + REMARK : +****************************************************************/ +static int mdio_read( int phy_id, int location, int i ) +{ + u16 *data; + + data = (u16 *)(&ifr[i].ifr_data); + data[0] = phy_id; + data[1] = location; + + if ( ioctl( skfd[i], SIOCGMIIREG, &ifr[i] ) < 0 ) { + fprintf( stderr, "SIOCGMIIREG on %s failed: %s\n", ifr[i].ifr_name, + strerror( errno )); + return -1; + } + return data[3]; +} + +/**************************************************************** + NAME : init_int 2002/03/04 + AIM : Set up the interface structures + REMARK : +****************************************************************/ +static void init_int( int i ) +{ + /* Open a basic socket. */ + if (( skfd[i] = socket( AF_INET, SOCK_DGRAM,0 )) < 0 ) { + perror( "socket" ); + exit( -1 ); + } + /* Get the vitals from the interface. */ + strncpy( ifr[i].ifr_name, ifname[i], IFNAMSIZ ); + if ( ioctl( skfd[i], SIOCGMIIPHY, &ifr[i]) < 0 ) { + fprintf( stderr, "SIOCGMIIPHY on %s failed: %s\n", ifname[i], + strerror( errno )); + (void) close( skfd[i] ); + exit( -1 ); + } +} + +/**************************************************************** + NAME : chk_iff 2002/02/04 + AIM : Check ifconfig up/down state + REMARK : +****************************************************************/ +static int chk_iff( int i ) +{ + struct ifreq ifr_up; + + strncpy( ifr_up.ifr_name, ifname[i], IFNAMSIZ ); + if ( ioctl( skfd[i], SIOCGIFFLAGS, &ifr_up) < 0 ) { + fprintf( stderr, "SIOCGIFFLAGS on %s failed!\n", ifname[i]); + return 0; + } + else if ( ifr_up.ifr_flags & IFF_UP ) return 1; + return 0; } --- vrrpd-1.0.orig/Makefile +++ vrrpd-1.0/Makefile @@ -2,11 +2,11 @@ ALL_EXE=vrrpd -VRRPD_OBJS = vrrpd.o libnetlink.o ipaddr.o +VRRPD_OBJS = vrrpd.o libnetlink.o ll_map.o iproute.o ipaddr.o md5.o ipsecah.o daemon.o -MAIN_OPT= +MAIN_OPT=-O PROF_OPT= -DBG_OPT=-g +#DBG_OPT=-g -DDEBUG #MACHINEOPT=-DMY_BIG_ENDIAN -DSUNOS #MACHINEOPT=-DMY_LITTLE_ENDIAN #INCLUDEOPT= @@ -27,12 +27,9 @@ dist: (make clean; rm -fr .protect/; cd ..; tar cvzf vrrpd-lastest.tgz vrrpd) -############################################## -# beyond this points only mangement target. # -############################################## clean : @echo Begin to clean - $(RM) *.[ao] *~ core + $(RM) *.[ao] *~ core $(ALL_EXE) @echo Clean is completed mrproper : clean @@ -50,17 +47,3 @@ (cd .. && tar cf - $(PROJECT) | gzip -9 >$(PROJECT).tgz) sync @echo Backup is completed - -# only GCC. -#depend dep: -# @echo Start to build depedances in .depend -# for i in *.c; do $(CPP) -M $(CFLAGS) $$i; done > .tmpdepend -# mv -f .tmpdepend .depend -# @echo Dependances completed - -# only gmake and good make -#ifeq (.depend,$(wildcard .depend)) -#include .depend -#endif - - --- vrrpd-1.0.orig/vrrpd.8 +++ vrrpd-1.0/vrrpd.8 @@ -1,10 +1,10 @@ .\" -*- nroff -*- -.TH VRRPD 8 "September 2000" "vrrpd(8)" "Vrrpd's Manual" +.TH VRRPD 8 "December 2002" "vrrpd(8)" "Vrrpd's Manual" .SH NAME vrrpd \- Virtual Router Redundancy Protocol Deamon .SH SYNOPSIS .B vrrpd --i ifname -v vrid [-s] [-a auth] [-p prio] [-nh] ipaddr +-i ifname -v vrid [-f piddir] [-s] [-a auth] [-p prio] [-m ifname] [-c delta] [-nhD] ipaddr .SH DESCRIPTION vrrpd is an implementation of VRRPv2 as specified in rfc2338. It run in userspace for linux. @@ -12,7 +12,7 @@ the master answers to a 'virtual ip address'. If it fails, a backup server takes over the ip address. -A longuer answer in the rfc2338 abstract : +A longer answer in the rfc2338 abstract : "This memo defines the Virtual Router Redundancy Protocol (VRRP). VRRP specifies an election protocol that dynamically assigns responsibility for a virtual router to one of the VRRP routers on a @@ -27,6 +27,14 @@ discovery protocols on every end-host." Copyright (C) The Internet Society (1998). All Rights Reserved. +Monitored interface functionality is useful on high availability +router or firewall platforms, where single interface failure +can cause asymmetrical routing issues. + +Ideally, what is required is a method for a vrrpd process to +detect a failure of the 'other' network interface, and lower +it's own VRRP priority below that of the 'backup' vrrpd process. +This allows failover to occur normally. .SS OPTIONS .TP @@ -34,22 +42,32 @@ display this short inlined help .TP .I "-n" -Dont handle the virtual mac address +Don't handle the virtual mac address +.TP +.I "-D" +Go into background mode, daemonize .TP .I "-i ifname" -the interface name to run on +the interface name to run on. More than one interface can be monitored +by the one vrrpd process, a list like "eth1 eth2 eth3 eth4 eth5" +is acceptable. Losing link-beat on any of these will cause +the priority of that vrrpd process to be decreased by the specified +value, or a default of 100. +Note that as MII calls are used, this implementation is limited to +Fast and Gigabit Ethernet chipsets only - 10Mbps Ethernet cards +will not work. .TP .I "-v vrid" the id of the virtual server [1-255] .TP .I "-s" -Switch the preemption mode (Enabled by default) +iqxSwitch the preemption mode (Enabled by default) .TP .I "-a auth" -(not yet implemented) set the authentification type +set the authentification type auth=(none|pw/hexkey|ah/hexkey) hexkey=0x[0-9a-fA-F]+ Password is a symbolic security, anybody with a sniffer can break it. -AH is a bit stronger but not yet implemented. +AH is a bit stronger. .TP .I "-p prio" Set the priority of this host in the virtual server (dfl: 100) @@ -59,6 +77,11 @@ .TP .I "-d delay" Set the advertisement interval (in sec) (dfl: 1) +.I "-m ifname" +Interface(s) to monitor for failure. Use " " for multiple interfaces +.TP +.I "-c delta" +Set the delta to decrease priority by (dfl: 50) .TP .I "ipaddr" the ip address(es) of the virtual server @@ -71,7 +94,18 @@ .SH AUTHOR .B vrrpd -was written by Jerome Etienne +was written by Jerome Etienne , it was later improved +by Alexandre Cassert and David Hunter .SH BUGS -If you find bugs, tell me. - +Suggestions, bugs or questions should be directed to the Sourceforge project at +.IR http://sourceforge.net/projects/vrrpd/ +.P +Bug reports +regarding this package should be submitted to Debian using the +.I reportbug +or +.I bug +tool. +.SH MORE INFO +For more information please read the documents under /usr/share/doc/vrrpd/ : README, README.Debian +FAQ and TODO. --- vrrpd-1.0.orig/README +++ vrrpd-1.0/README @@ -0,0 +1,70 @@ +vrrpd version 1.0 2002/02/05 +============================ + +The Monitored Interface extensions to vrrpd were originally +implemented to provide support for failover between a pair +of state-synchronised Checkpoint Firewall-1 modules. These +servers were HP LT6000r machines with two quad ethernet +NICs each and Red Hat Linux 7.0 (2.2 kernel required by +Firewall-1 v4.1 SP5). + +Full credit to David Moore of Hewlett-Packard (NZ) Ltd +for initiating the project that made this necessary. + +Anyway, an example command line for a primary server is; + + vrrpd -i eth0 -v 10 -p 200 -m "eth1 eth2 eth3" -c 100 + +This specifies eth0 as the interface to run the VRRP process +on, a VRID of 10, a priority of 200, that interfaces eth1, eth2 +and eth3 are to be monitored for failure, and that if one of +these interfaces does fail, the priority is to be reduced by 100. + +This allows the vrrpd process below (on the standby) to win; + + vrrpd -i eth0 -v 10 -p 150 + +as the master will advertise a priority of 100 while any of eth1-3 +are disconnected or administratively down. Note that there is +little point in monitoring interfaces on the secondary UNLESS +you are load balancing PAIRS of interfaces across different +servers. + +This configuration has been tested as providing transparent +failover for HP-UX systems as well as routers, with up to five +vrrpd daemons running concurrently on separate interfaces. +Each vrrpd process was monitoring the other four interfaces, +and was using the multicast VRRP MAC address so that arp +caching was not an issue. Intel 82559-based cards (eepro100 +driver) were used. + +During a failure (ie: ifconfig ethX down, pull cable out, turn +switch off, etc.) there is a 3x advertisement delay while the +VRRP election takes place. At the default advertisment interval +(1 sec), this was not long enough to cause TCP streams to break. + +Interfaces are monitored in two different ways. The IFF_UP flag +is checked to detect an administrative shutdown, and the link +status bits of the MII transceiver status word are checked to +detect a failed cable, switch or port. This should work with +most Fast Ethernet drivers, but not with 10Mbps-only cards. +Gigabit NICs have not been tested. + +There is no way to have different priority deltas for the +different monitored interfaces at present. However, it would +not be difficult to implement. + +As a last point, if you are using this on a firewall (eg: FW-1), +do not forget to allow VRRP and IGMP traffic from the 'original' +IP addresses of all interfaces running vrrpd to destination +address 224.0.0.18, otherwise elections will not work. + +Comments are welcome, I guess... + + +David Hunter +Technical Consultant +gen-i limited +Auckland, NZ + + --- vrrpd-1.0.orig/daemon.c +++ vrrpd-1.0/daemon.c @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * From: @(#)daemon.c 8.1 (Berkeley) 6/4/93 + * NetBSD: daemon.c,v 1.4 1995/02/25 13:41:16 cgd Exp + */ +char daemon_rcsid[] = + "$Id: daemon.c,v 1.3 1996/08/14 23:54:14 dholland Exp $"; + +#include +#include + +#include "daemon.h" + +int daemon(int nochdir, int noclose) +{ + int fd; + + switch (fork()) { + case -1: + return -1; + case 0: + break; + default: + _exit(0); + } + + if (setsid() == -1) return -1; + if (!nochdir) chdir("/"); + if (noclose) return 0; + + fd = open(_PATH_DEVNULL, O_RDWR, 0); + if (fd != -1) { + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > 2) close(fd); + } + return 0; +} --- vrrpd-1.0.orig/TODO +++ vrrpd-1.0/TODO @@ -1,8 +1,20 @@ +Possible bugs: +- Change VRRP_LOG into a function that can either call to syslog or + print to STDERR based on command line options. + That would allow for debugging on console as well as syslog + (even though vrrpd does not yet provide an options to run as a daemon). + Notice that some of the messages sent to syslog currently were not + though to be sent to syslog and, in some cases, might cause problems + if malicious users start sending crafted VRRPD packets (and fill up the + logs) +- Similarly to above, add different debugging options + Feature: - launch a script according to the state change. - add a test to set automatically the priority to 255 when the host own the ip addresses - as vrrpd needs root access, audit the code security. + Note: The output of 'rats' is provided in rats.output for peer review - test interoperability. - code the plain text authentication and hardcode AH. - make the master down interval tunable. --- vrrpd-1.0.orig/ipsecah.h +++ vrrpd-1.0/ipsecah.h @@ -0,0 +1,69 @@ +/* + * Soft: IPSEC AH implementation according to RFC 2402. Processing + * authentication data encryption using HMAC MD5 according to + * RFCs 2085 & 2104. + * + * Version: $Id: ipsecah.h,v 0.2.8 2001/05/23 16:25:32 acassen Exp $ + * + * Author: Alexandre Cassen, + * + * Changes: + * Alexandre Cassen : 2001/04/27 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. + */ + +#ifndef IPSEC_AH_H +#define IPSEC_AH_H + +#include +#include +#include +#include +#include +#include "md5.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 --- vrrpd-1.0.orig/md5.c +++ vrrpd-1.0/md5.c @@ -0,0 +1,385 @@ +/* + * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic + * changes to accomodate it in the kernel by ji. + * Minor changes to make 64 bit clean by Peter Onion (i.e. using u_int*_t). + */ + +/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +/* + * Additions by JI + * + * HAVEMEMCOPY is defined if mem* routines are available + * + * HAVEHTON is defined if htons() and htonl() can be used + * for big/little endian conversions + * + */ + +#include +#include +#include /* for u_int*_t */ + +#include "md5.h" +#include "endian.h" /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */ + +#define HAVEMEMCOPY 1 /* use ISO C's memcpy and memset */ + +/* Constants for MD5Transform routine. + */ + +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +#define MD5Transform _MD5Transform + +static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64])); + +#if BYTE_ORDER == LITTLE_ENDIAN +#define Encode MD5_memcpy +#define Decode MD5_memcpy +#else +static void Encode PROTO_LIST + ((unsigned char *, UINT4 *, unsigned int)); +static void Decode PROTO_LIST + ((UINT4 *, unsigned char *, unsigned int)); +#endif + +#ifdef HAVEMEMCOPY +#include +#define MD5_memcpy memcpy +#define MD5_memset memset +#else +#ifdef HAVEBCOPY +#define MD5_memcpy(_a,_b,_c) memcpy((_a), (_b),(_c)) +#define MD5_memset(_a,_b,_c) memset((_a), '\0',(_c)) +#else +static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int)); +static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int)); +#endif +#endif +static unsigned char PADDING[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 +}; + +/* F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. +Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +/* MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void MD5Init (context) +MD5_CTX *context; /* context */ +{ + context->count[0] = context->count[1] = 0; + /* Load magic initialization constants. +*/ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* MD5 block update operation. Continues an MD5 message-digest + operation, processing another message block, and updating the + context. + */ +void MD5Update (context, input, inputLen) +MD5_CTX *context; /* context */ +unsigned char *input; /* input block */ +UINT4 inputLen; /* length of input block */ +{ + UINT4 i; + unsigned int index, partLen; + + /* Compute number of bytes mod 64 */ + index = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += (inputLen << 3)) < (inputLen << 3)) + context->count[1]++; + context->count[1] += (inputLen >> 29); + + partLen = 64 - index; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) { + MD5_memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen); + MD5Transform (context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + MD5Transform (context->state, &input[i]); + + index = 0; + } + else + i = 0; + + /* Buffer remaining input */ + MD5_memcpy((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i); +} + +/* MD5 finalization. Ends an MD5 message-digest operation, writing the + the message digest and zeroizing the context. + */ +void MD5Final (digest, context) +unsigned char digest[16]; /* message digest */ +MD5_CTX *context; /* context */ +{ + unsigned char bits[8]; + unsigned int index, padLen; + + /* Save number of bits */ + Encode (bits, context->count, 8); + + /* Pad out to 56 mod 64. +*/ + index = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (index < 56) ? (56 - index) : (120 - index); + MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + MD5Update (context, bits, 8); + + if (digest != NULL) /* Bill Simpson's padding */ + { + /* store state in digest */ + Encode (digest, context->state, 16); + + /* Zeroize sensitive information. + */ + MD5_memset ((POINTER)context, 0, sizeof (*context)); + } +} + +/* MD5 basic transformation. Transforms state based on block. + */ +static void MD5Transform (state, block) +UINT4 state[4]; +unsigned char block[64]; +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode (x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. +*/ + MD5_memset ((POINTER)x, 0, sizeof (x)); +} + +#if BYTE_ORDER != LITTLE_ENDIAN + +/* Encodes input (UINT4) into output (unsigned char). Assumes len is + a multiple of 4. + */ +static void Encode (output, input, len) +unsigned char *output; +UINT4 *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* Decodes input (unsigned char) into output (UINT4). Assumes len is + a multiple of 4. + */ +static void Decode (output, input, len) +UINT4 *output; +unsigned char *input; +unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +#endif + +#ifndef HAVEMEMCOPY +#ifndef HAVEBCOPY +/* Note: Replace "for loop" with standard memcpy if possible. + */ + +static void MD5_memcpy (output, input, len) +POINTER output; +POINTER input; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + + output[i] = input[i]; +} + +/* Note: Replace "for loop" with standard memset if possible. + */ +static void MD5_memset (output, value, len) +POINTER output; +int value; +unsigned int len; +{ + unsigned int i; + + for (i = 0; i < len; i++) + ((char *)output)[i] = (char)value; +} +#endif +#endif + --- vrrpd-1.0.orig/iproute.c +++ vrrpd-1.0/iproute.c @@ -0,0 +1,308 @@ +/* + * 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: iproute.c,v 0.6.1 2003/11/16 04:00:00 ccwu Exp $ + * + * Author: Alexandre Cassen, + * Contributor: Chao-Cheng Wu, + * + * Changes: + * <+> rt_sort - Restore No Gateway's Routing Entry First. + * Prevent the fail of the routing table's + * restoration when the gateway of the early routing + * entry base on the late routing entry. + * + * 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 "iproute.h" + +/* Allocation function */ +struct rt_entry * rt_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 rt_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; + rt_del(entry); + return t; +} + +void rt_clear(struct rt_entry *lstentry) +{ + while (lstentry) + lstentry = clear_entry(lstentry); +} + +/* Append rt entry function */ +struct rt_entry * rt_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 rt_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) { + printf("BUG: wrong nlmsg len %d\n", 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 = rt_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 = rt_append(rtarg, entry); + } + + + return 0; +} + +struct rt_entry * rt_fetch(struct rt_entry *r) +{ + struct rtnl_handle rth; + + if (rtnl_open(&rth, 0) < 0) { + printf("Can not initialize netlink interface...\n"); + return NULL; + } + + ll_init_map(&rth); + + if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETROUTE) < 0) { + printf("Cannot send dump request\n"); + close(rth.fd); + return NULL; + } + + if (rtnl_dump_filter(&rth, rt_filter, r, NULL, NULL) < 0) { + printf("Dump terminated.\n"); + close(rth.fd); + return NULL; + } + + close(rth.fd); + return r; +} + +int rt_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) { + printf("Can not initialize netlink interface...\n"); + return -1; + } + + if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) { + printf("Can not talk with netlink interface...\n"); + return -1; + } + + return 0; +} + +int rt_restore(struct rt_entry *lstentry, char *dev) +{ + int idx = ll_name_to_index(dev); + int ret = 0; + + lstentry = rt_sort(lstentry); + + while (lstentry) { + if (lstentry->oif == idx) { + ret = rt_restore_entry(lstentry); + if (ret < 0) return ret; + } + + lstentry = (struct rt_entry *)lstentry->next; + } + + return 0; +} + +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; +} + +/* rt netlink dump function */ +void rt_dump(struct rt_entry *r) +{ + while (r) { + if (r->src) printf("src %s ", ip_ntoa(r->src)); + if (r->psrc) printf("prefsrc %s ", ip_ntoa(r->psrc)); + if (r->iif) printf("idev %s", ll_index_to_name(r->iif)); + + if (r->dest) printf("dest %s ", ip_ntoa(r->dest)); + if (r->gate) printf("gateway %s ", ip_ntoa(r->gate)); + + if (r->prio) printf("priority %d ", r->prio); + if (r->metrics) printf("metrics %d ", r->metrics); + + if (r->oif) printf("odev %s ", ll_index_to_name(r->oif)); + + /* rtmsg specifics */ + if (r->rtm->rtm_dst_len) printf("mask %d ", r->rtm->rtm_dst_len); + if (r->rtm->rtm_scope == RT_SCOPE_LINK) printf("scope link"); + + printf("\n"); + + r = (struct rt_entry *)r->next; + } +} + +struct rt_entry *rt_sort(struct rt_entry *entry) +{ + struct rt_entry *previous, *start; + + previous = start = (struct rt_entry *)entry; + if (!entry || !entry->next) { + /* return inmediately, there is only one entry */ + return start; + } + while (entry) { + /* select no gateway routing entry go to start */ + if (!entry->gate) { + previous->next = (struct rt_entry *)entry->next; + entry->next = (struct rt_entry *)start; + start = (struct rt_entry *)entry; + entry = (struct rt_entry *)previous; + } + previous = (struct rt_entry *)entry; + entry = (struct rt_entry *)entry->next; + } + + return start; +} --- vrrpd-1.0.orig/ipsecah.c +++ vrrpd-1.0/ipsecah.c @@ -0,0 +1,84 @@ +/* + * Soft: IPSEC AH implementation according to RFC 2402. Processing + * authentication data encryption using HMAC MD5 according to + * RFCs 2085 & 2104. + * + * Version: $Id: ipsecah.h,v 0.2.8 2001/05/23 16:25:32 acassen Exp $ + * + * Author: Alexandre Cassen, + * + * Changes: + * Alexandre Cassen : 2001/04/27 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 "ipsecah.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 */ +} --- vrrpd-1.0.orig/rats.output +++ vrrpd-1.0/rats.output @@ -0,0 +1,274 @@ +Entries in perl database: 33 +Entries in python database: 62 +Entries in c database: 334 +Entries in php database: 55 +Analyzing ipaddr.c +Analyzing iproute.c +Analyzing ipsecah.c +Analyzing libnetlink.c +Analyzing ll_map.c +Analyzing md5.c +Analyzing vrrpd.c +Analyzing ipaddr.h +Analyzing iproute.h +Analyzing ipsecah.h +Analyzing libnetlink.h +Analyzing ll_map.h +Analyzing md5.h +Analyzing proto.h +Analyzing vrrpd.h +ipaddr.c:132: High: fixed size local buffer + char buf[256]; +iproute.c:187: High: fixed size local buffer + char buf[1024]; +iproute.c:252: High: fixed size local buffer + static char buf[20]; +ipsecah.c:32: High: fixed size local buffer + unsigned char k_ipad[65]; /* inner padding - key XORd with ipad */ +ipsecah.c:33: High: fixed size local buffer + unsigned char k_opad[65]; /* outer padding - key XORd with opad */ +ipsecah.c:34: High: fixed size local buffer + unsigned char tk[16]; +libnetlink.c:137: High: fixed size local buffer + char buf[8192]; +libnetlink.c:222: High: fixed size local buffer + char buf[8192]; +libnetlink.c:335: High: fixed size local buffer + char buf[8192]; +libnetlink.c:407: High: fixed size local buffer + char buf[8192]; +ll_map.c:32: High: fixed size local buffer + unsigned char addr[8]; +ll_map.c:33: High: fixed size local buffer + char name[16]; +ll_map.c:104: High: fixed size local buffer + static char nbuf[16]; +ll_map.c:136: High: fixed size local buffer + static char ncache[16]; +md5.c:199: High: fixed size local buffer + unsigned char bits[8]; +vrrpd.c:163: High: fixed size local buffer + static char pidfile[FILENAME_MAX+1]; +vrrpd.c:1283: High: fixed size local buffer + unsigned char __ar_sha[ETH_ALEN]; /* Sender hardware address. */ +vrrpd.c:1284: High: fixed size local buffer + unsigned char __ar_sip[4]; /* Sender IP address. */ +vrrpd.c:1285: High: fixed size local buffer + unsigned char __ar_tha[ETH_ALEN]; /* Target hardware address. */ +vrrpd.c:1286: High: fixed size local buffer + unsigned char __ar_tip[4]; /* Target IP address. */ +md5.h:63: High: fixed size local buffer + unsigned char buffer[64]; /* input buffer */ +vrrpd.h:80: High: fixed size local buffer + char hwaddr[6]; /* WORK: lame hardcoded for ethernet !!!! */ +Extra care should be taken to ensure that character arrays that are allocated +on the stack are used safely. They are prime targets for buffer overflow +attacks. + +ll_map.c:84: High: strcpy + strcpy(im->name, RTA_DATA(tb[IFLA_IFNAME])); +ll_map.c:149: High: strcpy + strcpy(ncache, name); +vrrpd.c:907: High: strcpy + strcpy( from.sa_data, vsrv->vif.ifname ); +Check to be sure that argument 2 passed to this function call will not copy +more data than can be handled, resulting in a buffer overflow. + +vrrpd.c:467: High: syslog + syslog(LOG_ERR,"invalid IPSEC SPI value. %d and expect %d",ip->saddr,ah->spi); +vrrpd.c:481: High: syslog + syslog(LOG_ERR,"IPSEC AH sequence number %d already proceeded. Packet droped",ah->seq_number); +vrrpd.c:504: High: syslog + syslog(LOG_ERR,"invalid IPSEC HMAC-MD5 value. Due to fields mutation or bad password !"); +vrrpd.c:594: High: syslog + syslog(LOG_ERR,"invalid ttl. %d and expected %d", ip->ttl,VRRP_IP_TTL); +vrrpd.c:599: High: syslog + syslog(LOG_ERR,"invalid version. %d and expected %d", (hd->vers_type >> 4), VRRP_VERSION); +vrrpd.c:605: High: syslog + syslog(LOG_ERR,"ip payload too short. %d and expected at least %d" +vrrpd.c:611: High: syslog + syslog(LOG_ERR,"Invalid vrrp checksum" ); +vrrpd.c:617: High: syslog + syslog(LOG_ERR,"received a %d auth, expecting %d!", vif->auth_type, hd->auth_type); +vrrpd.c:625: High: syslog + syslog(LOG_ERR,"receive an invalid passwd!"); +vrrpd.c:638: High: syslog + syslog(LOG_ERR,"receive an invalid ip number count associated with VRID!"); +vrrpd.c:644: High: syslog + syslog(LOG_ERR,"ip address associated with VRID not present in received packet : %d",vsrv->vaddr[i].addr); +vrrpd.c:645: High: syslog + syslog(LOG_ERR,"one or more VIP associated with VRID mismatch actual MASTER advert"); +vrrpd.c:646: High: syslog + syslog(LOG_ERR,"EXITING"); +vrrpd.c:653: High: syslog + syslog(LOG_ERR,"advertisement interval mismatch mine=%d rcved=%d" +vrrpd.c:655: High: syslog + syslog(LOG_ERR,"EXITING"); +vrrpd.c:1355: High: syslog + syslog(LOG_NOTICE, "Gone to master...(prio: %d / vrid: %d)", vsrv->priority,vsrv->vrid); +vrrpd.c:1400: High: syslog + syslog(LOG_NOTICE, "Left master...(prio: %d / vrid: %d)", vsrv->priority, vsrv->vrid); +vrrpd.c:1696: High: syslog + syslog(LOG_NOTICE, "Starting (adver_int: %d, vrid: %d, use virtual mac: %s)", vsrv->adver_int,vsrv->vrid, vsrv->no_vmac ? "no" : "yes" ); +Truncate all input strings to a reasonable length before passing them to this function + +vrrpd.c:1050: High: getopt + c = getopt( argc, argv, "f:si:v:a:p:d:m:c:hnl:" ); +Truncate all input strings to a reasonable length before passing them to this function + +vrrpd.c:1162: Medium: realloc + vsrv->vaddr = realloc( vsrv->vaddr +Don't use on memory intended to be secure, because the old structure will not be zeroed out. + +vrrpd.c:1250: Medium: read + len = read( vsrv->sockfd, buf, buflen ); +Check buffer boundaries if calling this function in a loop and make sure you are not in danger of writing past the allocated space. + +vrrpd.c:1635: Medium: signal + signal( nosig, signal_user ); +vrrpd.c:1683: Medium: signal + signal( SIGINT, signal_end ); +vrrpd.c:1684: Medium: signal + signal( SIGTERM, signal_end ); +vrrpd.c:1685: Medium: signal + signal( SIGUSR1, signal_user ); +vrrpd.c:1686: Medium: signal + signal( SIGUSR2, signal_user ); +When setting signal handlers, do not use the same function to handle multiple signals. There exists the possibility a race condition will result if 2 or more different signals are sent to the process at nearly the same time. Also, when writing signal handlers, it is best to do as little as possible in them. The best strategy is to use the signal handler to set a flag, that another part of the program tests and performs the appropriate action(s) when it is set. +See also: http://razor.bindview.com/publish/papers/signals.txt + +iproute.c:129: Low: memcpy + memcpy(entry->rtm, r, sizeof(struct rtmsg)); +iproute.c:136: Low: memcpy + if (tb[RTA_SRC]) memcpy(&entry->src, RTA_DATA(tb[RTA_SRC]), 4); +iproute.c:137: Low: memcpy + if (tb[RTA_PREFSRC]) memcpy(&entry->psrc, RTA_DATA(tb[RTA_PREFSRC]), 4); +iproute.c:138: Low: memcpy + if (tb[RTA_DST]) memcpy(&entry->dest, RTA_DATA(tb[RTA_DST]), 4); +iproute.c:139: Low: memcpy + if (tb[RTA_GATEWAY]) memcpy(&entry->gate, RTA_DATA(tb[RTA_GATEWAY]), 4); +iproute.c:140: Low: memcpy + if (tb[RTA_FLOW]) memcpy(&entry->flow, RTA_DATA(tb[RTA_FLOW]), 4); +iproute.c:196: Low: memcpy + memcpy(&req.r, r->rtm, sizeof(struct rtmsg)); +ipsecah.c:64: Low: memcpy + memcpy(k_ipad,key,key_len); +ipsecah.c:65: Low: memcpy + memcpy(k_opad,key,key_len); +libnetlink.c:299: Low: memcpy + memcpy(answer, h, h->nlmsg_len); +libnetlink.c:307: Low: memcpy + memcpy(answer, h, h->nlmsg_len); +libnetlink.c:470: Low: memcpy + memcpy(RTA_DATA(rta), &data, 4); +libnetlink.c:485: Low: memcpy + memcpy(RTA_DATA(rta), data, alen); +libnetlink.c:500: Low: memcpy + memcpy(RTA_DATA(subrta), &data, 4); +libnetlink.c:515: Low: memcpy + memcpy(RTA_DATA(subrta), data, alen); +ll_map.c:79: Low: memcpy + memcpy(im->addr, RTA_DATA(tb[IFLA_ADDRESS]), alen); +vrrpd.c:312: Low: memcpy + memcpy( ifr.ifr_hwaddr.sa_data, addr, addrlen ); +vrrpd.c:346: Low: memcpy + memcpy( ifr.ifr_hwaddr.sa_data, addr, addrlen ); +vrrpd.c:374: Low: memcpy + memcpy( addr, ifr.ifr_hwaddr.sa_data, addrlen ); +vrrpd.c:496: Low: memcpy + memcpy(backup_auth_data,ah->auth_data,sizeof(ah->auth_data)); +vrrpd.c:683: Low: memcpy + memcpy( eth->ether_shost, vrrp_hwaddr, sizeof(vrrp_hwaddr)); +vrrpd.c:800: Low: memcpy + memcpy(ah->auth_data,digest,HMAC_MD5_TRUNC); +vrrpd.c:850: Low: memcpy + memcpy( pw, vif->auth_data, sizeof(vif->auth_data)); +vrrpd.c:1209: Low: memcpy + memcpy( vrrp_hwaddr, vsrv->vif.hwaddr,sizeof(vsrv->vif.hwaddr)); +vrrpd.c:1298: Low: memcpy + memcpy( eth->ether_shost, hwaddr, hwlen ); +vrrpd.c:1307: Low: memcpy + memcpy( arph->__ar_sha, hwaddr, hwlen ); +vrrpd.c:1309: Low: memcpy + memcpy( arph->__ar_sip, &addr, sizeof(addr) ); +vrrpd.c:1310: Low: memcpy + memcpy( arph->__ar_tip, &addr, sizeof(addr) ); +Double check that your buffer is as big as you specify. +When using functions that accept a number n of bytes to copy, such as strncpy, be aware that if the dest buffer size = n it may not NULL-terminate the string. + +ll_map.c:97: Low: snprintf + snprintf(buf, 16, "if%d", idx); +vrrpd.c:164: Low: snprintf + snprintf( pidfile, sizeof(pidfile), "%s/" VRRP_PID_FORMAT +vrrpd.c:1061: Low: snprintf + snprintf( PidDir, sizeof(PidDir), "%s", optarg ); +vrrpd.c:1064: Low: snprintf + snprintf( VridName, sizeof(VridName), "vrrpd->%s", optarg ); +vrrpd.c:1653: Low: snprintf + snprintf( PidDir, sizeof(PidDir), "%s", VRRP_PIDDIR_DFL ); +Double check that your buffer is as big as you specify. +When using functions that accept a number n of bytes to copy, such as strncpy, be aware that if the dest buffer size = n it may not NULL-terminate the string. + +md5.c:98: Low: fixed size global buffer +static unsigned char PADDING[64] = { +md5.c:196: Low: fixed size global buffer +unsigned char digest[16]; /* message digest */ +md5.c:229: Low: fixed size global buffer +unsigned char block[64]; +vrrpd.c:85: Low: fixed size global buffer +static char vrrp_hwaddr[6]; // WORK: lame hardcoded for ethernet +vrrpd.c:88: Low: fixed size global buffer +static char VridName[VRIDNAME_MAX+1]="vrrpd"; /* handy to have a name in the logs */ +vrrpd.c:89: Low: fixed size global buffer +static char PidDir[FILENAME_MAX+1]; +vrrpd.c:111: Low: fixed size global buffer +char *ifname[MAXINTS]; +Extra care should be taken to ensure that character arrays that are allocated +with a static size are used safely. This appears to be a global allocation +and is less dangerous than a similar one on the stack. Extra caution is still +advised, however. + +vrrpd.c:273: Low: strncpy + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); +vrrpd.c:293: Low: strncpy + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); +vrrpd.c:311: Low: strncpy + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); +vrrpd.c:336: Low: strncpy + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); +vrrpd.c:372: Low: strncpy + strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); +vrrpd.c:1768: Low: strncpy + strncpy( ifr[i].ifr_name, ifname[i], IFNAMSIZ ); +vrrpd.c:1786: Low: strncpy + strncpy( ifr_up.ifr_name, ifname[i], IFNAMSIZ ); +Double check that your buffer is as big as you specify. +When using functions that accept a number n of bytes to copy, such as strncpy, be aware that if the dest buffer size = n it may not NULL-terminate the string. Also, consider using strlcpy() instead, if it is avaialable to you. + +vrrpd.c:523: Low: bcopy + bcopy(buffer+i*sizeof(uint32_t),&ipbuf,sizeof(uint32_t)); +Double check that your buffer is as big as you specify. +When using functions that accept a number n of bytes to copy, such as strncpy, be aware that if the dest buffer size = n it may not NULL-terminate the string. + +vrrpd.c:988: Low: strlen + int len = strlen(str); +This function does not properly handle non-NULL terminated +strings. This does not result in exploitable code, but can lead to access violations. + +vrrpd.c:179: Low: fopen + FILE *fOut = fopen( name, "w" ); +vrrpd.c:210: Low: fopen + FILE *fIn = fopen( name, "r" ); +A potential race condition vulnerability exists here. Normally a call to this +function is vulnerable only when a match check precedes it. No check was +detected, however one could still exist that could not be detected. + +vrrpd.c:199: Low: unlink + unlink( pidfile_get_name(vsrv) ); +A potential race condition vulnerability exists here. Normally a call to this +function is vulnerable only when a match check precedes it. No check was +detected, however one could still exist that could not be detected. + +Total lines analyzed: 3930 +Total time 0.045509 seconds +86356 lines per second --- vrrpd-1.0.orig/libnetlink.c +++ vrrpd-1.0/libnetlink.c @@ -28,7 +28,7 @@ /* jme- workaround because glibc-2.1.1 or below doesnt have MSG_TRUNC */ #ifndef MSG_TRUNC # define MSG_TRUNC 0x20 -#endif MSG_TRUNC +#endif #if 1 # define nl_perror(str) perror(str) @@ -188,7 +188,6 @@ fprintf(stderr, "ERROR truncated\n"); } else { errno = -err->error; - /* Scott checked for EEXIST and return 0! 9-4-02*/ if (errno != EEXIST) nl_perror("RTNETLINK answers"); else return 0; @@ -302,7 +301,6 @@ memcpy(answer, h, h->nlmsg_len); return 0; } - /* Scott checked for EEXIST and return 0! 9-4-02*/ if (errno != EEXIST) nl_perror("RTNETLINK answers"); else return 0; --- vrrpd-1.0.orig/md5.h +++ vrrpd-1.0/md5.h @@ -0,0 +1,71 @@ +/* GLOBAL.H - RSAREF types and constants + */ + +/* PROTOTYPES should be set to one if and only if the compiler supports + function argument prototyping. + The following makes PROTOTYPES default to 0 if it has not already + been defined with C compiler flags. + */ +#ifndef PROTOTYPES +#define PROTOTYPES 1 +#endif + +/* POINTER defines a generic pointer type */ +typedef unsigned char *POINTER; + +/* UINT2 defines a two byte word */ +typedef u_int16_t UINT2; + +/* UINT4 defines a four byte word */ +typedef u_int32_t UINT4; + +/* PROTO_LIST is defined depending on how PROTOTYPES is defined above. + If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it + returns an empty list. + */ + +#if PROTOTYPES +#define PROTO_LIST(list) list +#else +#define PROTO_LIST(list) () +#endif + + +/* MD5.H - header file for MD5C.C + */ + +/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All +rights reserved. + +License to copy and use this software is granted provided that it +is identified as the "RSA Data Security, Inc. MD5 Message-Digest +Algorithm" in all material mentioning or referencing this software +or this function. + +License is also granted to make and use derivative works provided +that such works are identified as "derived from the RSA Data +Security, Inc. MD5 Message-Digest Algorithm" in all material +mentioning or referencing the derived work. + +RSA Data Security, Inc. makes no representations concerning either +the merchantability of this software or the suitability of this +software for any particular purpose. It is provided "as is" +without express or implied warranty of any kind. + +These notices must be retained in any copies of any part of this +documentation and/or software. + */ + +/* MD5 context. */ +typedef struct { + UINT4 state[4]; /* state (ABCD) */ + UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} MD5_CTX; + +void MD5Init PROTO_LIST ((MD5_CTX *)); +void MD5Update PROTO_LIST + ((MD5_CTX *, unsigned char *, UINT4)); +void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); + +#define _MD5_H_ --- vrrpd-1.0.orig/iproute.h +++ vrrpd-1.0/iproute.h @@ -0,0 +1,66 @@ +/* + * 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: iproute.h,v 0.6 2001/05/23 16:25:32 acassen Exp $ + * + * Author: Alexandre Cassen, + * + * 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 _IPROUTE_H +#define _IPROUTE_H + +/* global includes */ +#include +#include +#include +#include +#include +#include +#include + +/* local includes */ +#include "libnetlink.h" +#include "ll_map.h" + +/* macro definitions */ +#define VRRP_RT(X) ((X)) + +/* 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 *rt_fetch(struct rt_entry *r); +extern void rt_dump(struct rt_entry *r); +extern void rt_clear(struct rt_entry *lstentry); +extern int rt_restore(struct rt_entry *lstentry, char *dev); +extern struct rt_entry *rt_sort(struct rt_entry *entry); + +#endif --- vrrpd-1.0.orig/debian/dirs +++ vrrpd-1.0/debian/dirs @@ -0,0 +1 @@ +usr/sbin/ --- vrrpd-1.0.orig/debian/docs +++ vrrpd-1.0/debian/docs @@ -0,0 +1,3 @@ +README +FAQ +TODO --- vrrpd-1.0.orig/debian/rules +++ vrrpd-1.0/debian/rules @@ -0,0 +1,52 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 to 1999 by Joey Hess. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +build: build-stamp +build-stamp: + dh_testdir + $(MAKE) + touch build-stamp + +clean: + dh_testdir + dh_testroot + rm -f build-stamp configure-stamp + -$(MAKE) mrproper + dh_clean + +install: build + dh_testdir + dh_testroot + dh_prep + dh_installdirs + install -m 755 vrrpd $(CURDIR)/debian/vrrpd/usr/sbin/ + + +# Build architecture-independent files here. +binary-indep: build install +# We have nothing to do by default. + +# Build architecture-dependent files here. +binary-arch: build install + dh_testdir + dh_testroot + dh_installdocs + dh_installexamples + dh_installman vrrpd.8 + dh_installchangelogs Changes + dh_link + dh_strip + dh_compress + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary: binary-indep binary-arch +.PHONY: build clean binary-indep binary-arch binary install configure --- vrrpd-1.0.orig/debian/copyright +++ vrrpd-1.0/debian/copyright @@ -0,0 +1,35 @@ +This package was debianized by Javier Fernandez-Sanguino Peņa +Tue, 20 Nov 2001 16:52:58 +0100. + +Version 1.0 is available and +http://www.imagestream.com/VRRP.html +and https://sourceforge.net/projects/vrrpd/ +Which is actually based in version 0.4 (Jerome Etienne's version) but does +not include the patches developed by Alexandre Cassert and +David Hunter. + +The original upstream (0.4) version is still available at +http://www.off.net/~jme/vrrpd/index.html +[ If that URL gives you a 404 you might want to check Freshmeat's project +page at http://freshmeat.net/releases/35929/ ] +Version 0.6 is still available at +http://www.linuxvirtualserver.org/~acassen/software/ (URL available) + +Version 0.7 is based on code originally downloaded from +http://gen-i.co.nz/cms.asp?category=content%2F20what+we+do%2Fdevelop+products%2Fvrrpd +(URL no longer available) + + +Upstream Authors: + Jerome Etienne + Alexandre Cassert + David Hunter + +Copyright: + + 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. + + You can find a copy of the GNU GPL at /usr/share/common-licenses/ --- vrrpd-1.0.orig/debian/README.Debian +++ vrrpd-1.0/debian/README.Debian @@ -0,0 +1,28 @@ +vrrpd for Debian +---------------- + +Vrrpd is really easy to setup, as demonstrated by +http://lartc.org/howto/lartc.other.html +Unfortunately, it is undermaintained and has not seen changes for +quite a while. + +If you are interested in VRRP implementations and vrrpd does not work +ok for you you might want to check out some other projects including: + +- freebrpd (http://www.b0l.org/?idcategory=3&idsection=1) +- keepalived (http://keepalived.sourceforge.net/ and available as a +Debian package) +and +- OpenBSD's ucarp (http://www.ucarp.org, also available as a Debian +package) which is a patent-free VRRPd-like implementation. + +For more information on VRRP please check out +http://www.ietf.org/ids.by.wg/vrrp.html + +TODO: + +- Provide an init script for vrrpd with some sane defaults and an + /etc/default/vrrpd configuration + + -- Javier Fernandez-Sanguino Pen~a + Thu, 26 Aug 2004 19:22:50 +0200 --- vrrpd-1.0.orig/debian/control +++ vrrpd-1.0/debian/control @@ -0,0 +1,18 @@ +Source: vrrpd +Section: net +Priority: optional +Maintainer: Javier Fernandez-Sanguino Pen~a +Build-Depends: debhelper (>> 3.0.0) +Standards-Version: 3.5.2 +Homepage: http://sourceforge.net/projects/vrrpd/ + +Package: vrrpd +Architecture: any +Depends: ${shlibs:Depends} +Description: Virtual Router Redundancy Protocol user-space implementation + This package provides an implementation of VRRPv2 as specified in rfc2338. + It runs in the Linux kernel's userspace (as root). + . + VRRP can be used to setup high-availability services in Debian since two + machines can use the same (virtual) IP address which is transfered upon + failover. Some kernel features need to be enabled (please read the FAQ) --- vrrpd-1.0.orig/debian/init.d.TODO +++ vrrpd-1.0/debian/init.d.TODO @@ -0,0 +1,70 @@ +#! /bin/sh +# +# skeleton example file to build /etc/init.d/ scripts. +# This file should be used to construct scripts for /etc/init.d. +# +# Written by Miquel van Smoorenburg . +# Modified for Debian GNU/Linux +# by Ian Murdock . +# +# Version: @(#)skeleton 1.8 03-Mar-1998 miquels@cistron.nl +# +# This file was automatically customized by dh-make on Tue, 20 Nov 2001 16:52:58 +0100 + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/vrrpd +NAME=vrrpd +DESC=vrrpd + +test -f $DAEMON || exit 0 + +set -e + +case "$1" in + start) + echo -n "Starting $DESC: " + start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ + --exec $DAEMON + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --stop --quiet --pidfile /var/run/$NAME.pid \ + --exec $DAEMON + echo "$NAME." + ;; + #reload) + # + # If the daemon can reload its config files on the fly + # for example by sending it SIGHUP, do it here. + # + # If the daemon responds to changes in its config file + # directly anyway, make this a do-nothing entry. + # + # echo "Reloading $DESC configuration files." + # start-stop-daemon --stop --signal 1 --quiet --pidfile \ + # /var/run/$NAME.pid --exec $DAEMON + #;; + restart|force-reload) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart". + # + echo -n "Restarting $DESC: " + start-stop-daemon --stop --quiet --pidfile \ + /var/run/$NAME.pid --exec $DAEMON + sleep 1 + start-stop-daemon --start --quiet --pidfile \ + /var/run/$NAME.pid --exec $DAEMON + echo "$NAME." + ;; + *) + N=/etc/init.d/$NAME + # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 --- vrrpd-1.0.orig/debian/doc-base.vrrp +++ vrrpd-1.0/debian/doc-base.vrrp @@ -0,0 +1,11 @@ +Document: faq-vrrpd +Title: vrrpd FAQ +Author: Jerome Etienne +Abstract: This manual describes what vrrpd is + and how it can be used to provide high-availabity + services on Debian GNU/Linux systems. +Section: admin + +Format: text +Files: /usr/share/doc/vrrpd/FAQ.gz + --- vrrpd-1.0.orig/debian/changelog +++ vrrpd-1.0/debian/changelog @@ -0,0 +1,95 @@ +vrrpd (1.0-2) unstable; urgency=low + + * Prevent infinite loop in systems with only one route defined and no + gateway. (Closes: 601327) + * Use debhelper compatibility version 5 + * debian/control: Move Homepage to header + + -- Javier Fernandez-Sanguino Pen~a Wed, 27 Oct 2010 22:59:01 +0200 + +vrrpd (1.0-1) unstable; urgency=low + + * New "upstream" version. Actually upstream is more or less dead and + inactive since the version at Sourceforge does not provide patches + developed by other maintainers (incoporated in this package). + In any case the Debian package is now going to be based on this one + (to facilitate patch development) + * Removed the RFCs from the upstream package, to avoid reproducing + #199816 + * Debian/copyright and control now point to sourceforge as upstream + (Closes: #267821) + * Ported all patches to the new code. + * Syslog calls are now vrrpd_log calls for consistency with 1.0's code. + * Included Sourceforge's Track Item [ 990755 ] daemon.c and -b option, only + that I've changed it's behaviour and called it -D, by default, vrrpd + will _not_ daemonize. It might actually be useful when an init script + is added to the package (start-stop-daemon could be used too, of course). + * Added more info on VRRP implementations and some other information tidbits + in README.Debian + * Fixed some typos in the manpage and modify BUG info to tell users to + report bugs upstream. + * debian/rules cleanup + + -- Javier Fernandez-Sanguino Pen~a Thu, 26 Aug 2004 19:52:08 +0200 + +vrrpd (0.7.0-2) unstable; urgency=low + + * Fixed typo in control file (Closes: #227669) + * Send most error messages to the syslog with patch from Pascal Lengard, + since this is potentially dangerous, added a note in the TODO + since this needs further review and potentially a command line switch + to determine wether to log to syslog or not and the debug level to use. + (Closes: #226911) + * Added the output of running RATS ('rats.output') in the source in + order to do a security audit review in the near future. + + -- Javier Fernandez-Sanguino Pen~a Sun, 23 May 2004 21:04:18 +0200 + +vrrpd (0.7.0-1) unstable; urgency=low + + * Minor upstream bump to force inclusion of .orig.tar.gz which was + not properly included previously + * Removed RFCs from package : rfc2338.txt.vrrp, + draft-ietf-vrrp-spec-v2-05.txt and + draft-jou-duplicate-ip-address-02.txt (Closes: #199816) + * Applied patch contributed by Johann Klasek, upstream has not + approved it but the comment is clear enough (Closes: #199911) + * Included alignment patch provided by Nicolas S. Dade which fixes + bus fault on sparc (Closes: #199795) + * Included patch from Chao-Cheng Wu which: + - will not remove the routing table entries added after VRRP + was started in the event of a failover. + - will not fail if the gateway of the early routing entry is + base on the late routing entry (?) + (Closes: #223859) + + -- Javier Fernandez-Sanguino Pen~a Sat, 20 Dec 2003 15:44:58 +0100 + +vrrpd (0.7-2) unstable; urgency=low + + * Applied patch so that vrrpd logs to syslog with patch provided by + Dariush Pietrzak (Closes: #187240) + * Fixed lintian warning + + -- Javier Fernandez-Sanguino Pen~a Thu, 3 Apr 2003 23:41:38 +0200 + +vrrpd (0.7-1) unstable; urgency=low + + * Fixed typo in description (Closes: #125466) + * Updated to latest release (Closes: #144149) + * Updated information in debian/copyright + + -- Javier Fernandez-Sanguino Pen~a Tue, 17 Dec 2002 01:55:43 +0100 + +vrrpd (0.4-2) unstable; urgency=low + + * Fixed typo in description (Closes: #121361) + + -- Javier Fernandez-Sanguino Pen~a Tue, 27 Nov 2001 10:57:10 +0100 + +vrrpd (0.4-1) unstable; urgency=low + + * Initial Release (Closes: #89453). + + -- Javier Fernandez-Sanguino Pen~a Tue, 20 Nov 2001 16:52:58 +0100 + --- vrrpd-1.0.orig/debian/compat +++ vrrpd-1.0/debian/compat @@ -0,0 +1 @@ +5