vrrpd-1.0/0000755000175000017500000000000007537132605012105 5ustar jfsjfs00000000000000vrrpd-1.0/CVS/0000755000175000017500000000000007537132661012542 5ustar jfsjfs00000000000000vrrpd-1.0/CVS/Root0000644000175000017500000000007207537132605013405 0ustar jfsjfs00000000000000:ext:imagestream@cvs.vrrpd.sourceforge.net:/cvsroot/vrrpd vrrpd-1.0/CVS/Repository0000644000175000017500000000002507537132605014637 0ustar jfsjfs00000000000000/cvsroot/vrrpd/vrrpd vrrpd-1.0/CVS/Entries0000644000175000017500000000126007537132661014075 0ustar jfsjfs00000000000000/Changes/1.1.1.1/Mon Sep 9 14:51:13 2002// /FAQ/1.1.1.1/Mon Sep 9 14:51:13 2002// /INSTALL/1.1.1.1/Mon Sep 9 14:51:13 2002// /Makefile/1.1.1.1/Mon Sep 9 14:51:13 2002// /TODO/1.1.1.1/Mon Sep 9 14:51:13 2002// /ipaddr.c/1.1.1.1/Mon Sep 9 14:51:13 2002// /ipaddr.h/1.1.1.1/Mon Sep 9 14:51:13 2002// /libnetlink.c/1.1.1.1/Mon Sep 9 14:51:13 2002// /libnetlink.h/1.1.1.1/Mon Sep 9 14:51:13 2002// /proto.h/1.1.1.1/Mon Sep 9 14:51:13 2002// /route.generic/1.1.1.1/Mon Sep 9 14:51:13 2002// /scott_example/1.1.1.1/Mon Sep 9 14:51:13 2002// /vrrpd.8/1.1.1.1/Mon Sep 9 14:51:13 2002// /vrrpd.c/1.1.1.1/Mon Sep 9 14:51:13 2002// /vrrpd.h/1.1.1.1/Mon Sep 9 14:51:13 2002// D/doc//// vrrpd-1.0/Makefile0000644000175000017500000000261707537132541013552 0ustar jfsjfs00000000000000PROJECT=vrrpd ALL_EXE=vrrpd VRRPD_OBJS = vrrpd.o libnetlink.o ipaddr.o MAIN_OPT= PROF_OPT= DBG_OPT=-g #MACHINEOPT=-DMY_BIG_ENDIAN -DSUNOS #MACHINEOPT=-DMY_LITTLE_ENDIAN #INCLUDEOPT= #INCLUDEOPT= -I./libpcap #LINKLIB = -lpcap COMMON_CFLAGS= $(MAIN_OPT) $(INCLUDEOPT) $(PROF_OPT) $(DBG_OPT) $(MACHINEOPT) # set to compile with GCC CC=gcc CFLAGS= $(COMMON_CFLAGS) -Wall vrrpd : $(VRRPD_OBJS) $(CC) $(PROF_OPT) -o $@ $(VRRPD_OBJS) $(LINKLIB) vrrpd.o: vrrpd.h libnetlink.o: libnetlink.h 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 @echo Clean is completed mrproper : clean @echo Begin to mrproper $(RM) -fr .depend .protect/ $(ALL_EXE) @echo Mrproper is completed strip : @echo Begin to strip $(ALL_EXE) $(STRIP) $(ALL_EXE) @echo $(ALL_EXE) have been striped backup: mrproper cleanlog @echo Backup to backup (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/Changes0000644000175000017500000000221407537132541013376 0ustar jfsjfs000000000000000.4 - Sep 26th 2000 - written a man(8) page - implemented the password authentication rfc2338.10.2 (not tested because i have a single computer :) - change the state according to unix signal. USR1=be master, USR2=be backup pid stored in a file vrrpd_[IF]_[VRID].pid (e.g. vrrp_eth0_50.pid) WARNING: for guru only 0.3 - june 8th 2000 - add -n option. if it is set, vrrpd doesnt handle the virtual mac address. It isnt compliant to the rfc. but in practice it work and allow to have several virtual groups per interface (workaround the kernel assumption 1 MAC per physical interface) - fix a compilation problem with glibc-2.1.1 or below, MSG_TRUNC is undefined. reported by Hannes R. Boehm 0.2 - may 18th 2000 - knowledgable comment and bug fix from Hannes R. Boehm (VRRP_IS_BAD_PRIORITY, authentication field) - gratuitous arp for non-vrrp addresses when the master becomes backup - bug fix not to remove the primary address when the master is the address owner and become backup. - no more depends on 'ip' from iproute tools. now netlink is used directly to set/remove the ip addresses. 0.1 - may 14th 2000 - release of the first version vrrpd-1.0/FAQ0000644000175000017500000001170507537132541012442 0ustar jfsjfs00000000000000vrrpd is a deamon which support the VRRP v2 protocol as specified in rfc2338. ------------------------------------------------------------------- Introduction: Q. what is VRRPd ? vrrpd is an implementation of VRRPv2 as specified in rfc2338. It run in userspace for linux. Q. what is VRRP ? A. In short, VRRP is a protocol which elects a master server on a LAN and 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 : "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 LAN. The VRRP router controlling the IP address(es) associated with a virtual router is called the Master, and forwards packets sent to these IP addresses. The election process provides dynamic fail over in the forwarding responsibility should the Master become unavailable. This allows any of the virtual router IP addresses on the LAN to be used as the default first hop router by end-hosts. The advantage gained from using VRRP is a higher availability default path without requiring configuration of dynamic routing or router discovery protocols on every end-host." Copyright (C) The Internet Society (1998). All Rights Reserved. NOTE: the RFC keep talking about routers for historical reasons but the protocol isn't dedicated to routers and it can used it for any kind of server. ------------------------------------------------------------------- Configuration: Q. how can i set up the 'ip authentication header' ? A. Ip authentication header is the long name for AH (rfc2402) and is outside the scope of vrrpd. To have this protection, you should configure IPSec. Q. What are the required options to compiled in the kernel ? A. Set the following options: IP aliasing: to have several IP addresses per interface Kernel/User netlink socket: to communicate between the process and the kernel Routing messages: to add/del ip addresses for an interface ------------------------------------------------------------------- Trouble shot: Q. When i launch vrrpd, it display 'cant open raw socket', why ? A. try running it as root. vrrpd does several operations (set ip address, MAC address, send/rcv packet directly from the link) which require root access. Q. Why i can't have more than one virtual router per physical interface ? A. you can with the -n option which prevents vrrpd to handle the virtual MAC. It isnt compliant to the rfc but work in practice. VRRP requires to use a special MAC address for the ip packets with the address of the virtual router. Currently, as far as i know, linux doesnt support several MAC on transmition. so a host can't be MASTER of several group at the same time. It is possible to workaround this limitation by connecting several physical interfaces to the same link. Q. vrrpd doesn't set the virtual router addresses when it become master, why ? A. It is likely a problem when it try to set several addresses to the interface. the kernel must support ip aliasing. (linux configuration: Networking Option: IP aliasing support). Q. why it doesn't work with the implementation made by XXXX ? A. currently i have tested any inter-operability because i dont have any other implementations available. i did some intra-operabilty tests and it seems to work. ------------------------------------------------------------------- Technical: Q. What are the supported OS ? A. currently only linux. it is my development platform and don't have others available. Q. How hard would it be to port it on another OS ? A. i don't know. i use several 'low level' features which may be different or unavailable on other OS. a list follow: SIOCGIFADDR/SIOCSIFADDR to set/get the 'primary' hardware address SIOCADDMULTI/SIOCDELMULTI to add/remove a 'receiving' hardware address Use netlink to change the ip address, a clean but non standard way. Q. why vrrp packets are build by hand from vrrp payload to ethernet header ? A. the vrrp packets are send directly over the link without using a SOCK_RAW/IP_HDRINCL because of a requirement in the rfc2338.7.2 "Set the source MAC address to the Virtual Router MAC Address" Q. how the MAC address change is handled ? A. I set the interface MAC address to the vrrp one. I set the original MAC address as a receiving MAC (multicast). thus i can send/receive packet with vrrp MAC and still receive packet with the old MAC. This avoid a system disruption at each change. nevertheless it prevent the user from running several virtual routers on a single physical interface. Q. how the IP address change is handled ? A. The virtual router addresses are set/removed as ip aliases. the primary ip address of the interface is never modified. Thus the connections using the primary ip (tcp or other) go on without trouble. vrrpd-1.0/INSTALL0000644000175000017500000000040607537132541013135 0ustar jfsjfs000000000000001. uncompress the source 2. cd in the directory 3. type 'make' 4. if everything is ok, there is now a file 'vrrpd' in the directory 5. copy vrrpd in your path (e.g /usr/sbin) and vrrpd.8 in your man path (e.g. /usr/man/man8) it requires to be run as root. vrrpd-1.0/ipaddr.c0000644000175000017500000000763707537132541013530 0ustar jfsjfs00000000000000/*===========================[ (c) JME SOFT ]=================================== FILE : [ipaddr.c] CREATED : 00/06/02 20:01:59 LAST SAVE : 00/06/02 23:49:56 WHO : jerome@mycpu Linux 2.2.14 REMARK : ================================================================================ - highly inspired from ip/ipaddress.c in iproute2 from alexey ==============================================================================*/ /* system include */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* local include */ #include "libnetlink.h" typedef struct { int ifindex; uint32_t *addr; int max_elem; int nb_elem; } iplist_ctx; /**************************************************************** NAME : print_addr 00/06/02 18:24:09 AIM : REMARK : ****************************************************************/ static int get_addrinfo(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) { struct ifaddrmsg *ifa = NLMSG_DATA(n); int len = n->nlmsg_len; iplist_ctx *ctx = (iplist_ctx *)arg; struct rtattr *rta_tb[IFA_MAX+1]; /* sanity check */ len -= NLMSG_LENGTH(sizeof(*ifa)); if (len < 0) { fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); return -1; } /* check the message type */ if (n->nlmsg_type != RTM_NEWADDR ) return 0; /* check it is ipv4 */ if( ifa->ifa_family != AF_INET) return 0; /* check it is the good interface */ if( ifa->ifa_index != ctx->ifindex ) return 0; /* parse the attribute */ memset(rta_tb, 0, sizeof(rta_tb)); parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), len); if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; if (rta_tb[IFA_LOCAL]) { u_char *src = RTA_DATA(rta_tb[IFA_LOCAL]); if( ctx->nb_elem >= ctx->max_elem ) return 0; ctx->addr[ctx->nb_elem++] = (src[0]<<24) + (src[1]<<16) + (src[2]<<8) + src[3]; } return 0; } /**************************************************************** NAME : ipaddr_list 00/06/02 20:02:23 AIM : REMARK : ****************************************************************/ int ipaddr_list( int ifindex, uint32_t *array, int max_elem ) { struct rtnl_handle rth; iplist_ctx ctx; /* init the struct */ ctx.ifindex = ifindex; ctx.addr = array; ctx.max_elem = max_elem; ctx.nb_elem = 0; /* open the rtnetlink socket */ if( rtnl_open( &rth, 0) ) return -1; /* send the request */ if (rtnl_wilddump_request(&rth, AF_INET, RTM_GETADDR) < 0) { perror("Cannot send dump request"); return -1; } /* parse the answer */ if (rtnl_dump_filter(&rth, get_addrinfo, &ctx, NULL, NULL) < 0) { fprintf(stderr, "Flush terminated\n"); exit(1); } /* to close the clocket */ rtnl_close( &rth ); return ctx.nb_elem; } /**************************************************************** NAME : ipaddr_add 00/06/02 23:00:58 AIM : add or remove REMARK : ****************************************************************/ int ipaddr_op( int ifindex, uint32_t addr, int addF ) { struct rtnl_handle rth; struct { struct nlmsghdr n; struct ifaddrmsg ifa; char buf[256]; } req; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = addF ? RTM_NEWADDR : RTM_DELADDR; req.ifa.ifa_family = AF_INET; req.ifa.ifa_index = ifindex; req.ifa.ifa_prefixlen = 32; addr = htonl( addr ); addattr_l(&req.n, sizeof(req), IFA_LOCAL, &addr, sizeof(addr) ); if (rtnl_open(&rth, 0) < 0) return -1; if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) return -1; /* to close the clocket */ rtnl_close( &rth ); return(0); } vrrpd-1.0/TODO0000644000175000017500000000161507537132541012577 0ustar jfsjfs00000000000000Feature: - 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. - test interoperability. - code the plain text authentication and hardcode AH. - make the master down interval tunable. - work only with ethernet, all is hardcoded. it is ugly. see what you can do for fddi/tokenring -> problem i dont have the hardware so i can't test. - beautifull the code. - change the state according to unix signal USR1=be master, USR2=be backup pid stored in a file vrrpd_[IF]_[VRID].pid (e.g. vrrp_eth0_50.pid) DONE - provide a mode in which you don't change the MAC address and thus support multiple virtual router per physical interface. DONE (-n) Things to test: - vrrpd vs commercial version - vrrpd vs vrrpd - multiple authentications (NONE,passwd, AH) - checksum vrrpd-1.0/doc/0000755000175000017500000000000010113431033012627 5ustar jfsjfs00000000000000vrrpd-1.0/doc/CVS/0000755000175000017500000000000007537132606013306 5ustar jfsjfs00000000000000vrrpd-1.0/doc/CVS/Root0000644000175000017500000000007207537132605014152 0ustar jfsjfs00000000000000:ext:imagestream@cvs.vrrpd.sourceforge.net:/cvsroot/vrrpd vrrpd-1.0/doc/CVS/Repository0000644000175000017500000000003107537132605015401 0ustar jfsjfs00000000000000/cvsroot/vrrpd/vrrpd/doc vrrpd-1.0/doc/CVS/Entries0000644000175000017500000000030407537132606014637 0ustar jfsjfs00000000000000/draft-ietf-vrrp-spec-v2-05.txt/1.1.1.1/Mon Sep 9 14:51:13 2002// /draft-jou-duplicate-ip-address-02.txt/1.1.1.1/Mon Sep 9 14:51:13 2002// /rfc2338.txt.vrrp/1.1.1.1/Mon Sep 9 14:51:14 2002// D vrrpd-1.0/ipaddr.h0000644000175000017500000000142307537132541013520 0ustar jfsjfs00000000000000/*===========================[ (c) JME SOFT ]=================================== FILE : [ipaddr.h] CREATED : 00/06/02 20:12:33 LAST SAVE : 00/06/02 23:47:42 WHO : jerome@mycpu Linux 2.2.14 REMARK : ================================================================================ ==============================================================================*/ #ifndef __IPADDR_H__ #define __IPADDR_H__ /* system include */ /* local include */ /*@$#[ipaddr.c] global proto. AutoProtoSigV1.1. date: 00/06/02 23:47:40 */ #include "proto.h" int ipaddr_list PROTO((int ifindex, uint32_t *array, int max_elem)); int ipaddr_op PROTO((int ifindex, uint32_t addr, int addF)); /*@$% end of AutoProtoSigV1.1 (Dont remove this line) []*/ #endif /* __IPADDR_H__ */ vrrpd-1.0/libnetlink.c0000644000175000017500000003026607537132541014412 0ustar jfsjfs00000000000000/* * libnetlink.c RTnetlink service routines. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Authors: Alexey Kuznetsov, * */ #include #include #include #include #include #include #include #include #include #include #include #include #include "libnetlink.h" /* jme- workaround because glibc-2.1.1 or below doesnt have MSG_TRUNC */ #ifndef MSG_TRUNC # define MSG_TRUNC 0x20 #endif MSG_TRUNC #if 1 # define nl_perror(str) perror(str) #else # define nl_perror(str) #endif int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions) { int addr_len; memset(rth, 0, sizeof(rth)); rth->fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); if (rth->fd < 0) { nl_perror("Cannot open netlink socket"); return -1; } memset(&rth->local, 0, sizeof(rth->local)); rth->local.nl_family = AF_NETLINK; rth->local.nl_groups = subscriptions; if (bind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local)) < 0) { nl_perror("Cannot bind netlink socket"); return -1; } addr_len = sizeof(rth->local); if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0) { nl_perror("Cannot getsockname"); return -1; } if (addr_len != sizeof(rth->local)) { fprintf(stderr, "Wrong address length %d\n", addr_len); return -1; } if (rth->local.nl_family != AF_NETLINK) { fprintf(stderr, "Wrong address family %d\n", rth->local.nl_family); return -1; } rth->seq = time(NULL); return 0; } int rtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) { struct { struct nlmsghdr nlh; struct rtgenmsg g; } req; struct sockaddr_nl nladdr; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; req.nlh.nlmsg_len = sizeof(req); req.nlh.nlmsg_type = type; req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; req.nlh.nlmsg_pid = 0; req.nlh.nlmsg_seq = rth->dump = ++rth->seq; req.g.rtgen_family = family; return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); } int rtnl_send(struct rtnl_handle *rth, char *buf, int len) { struct sockaddr_nl nladdr; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; return sendto(rth->fd, buf, len, 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); } int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) { struct nlmsghdr nlh; struct sockaddr_nl nladdr; struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } }; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), iov, 2, NULL, 0, 0 }; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nlh.nlmsg_len = NLMSG_LENGTH(len); nlh.nlmsg_type = type; nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST; nlh.nlmsg_pid = 0; nlh.nlmsg_seq = rth->dump = ++rth->seq; return sendmsg(rth->fd, &msg, 0); } int rtnl_dump_filter(struct rtnl_handle *rth, int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), void *arg1, int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *arg2) { char buf[8192]; struct sockaddr_nl nladdr; struct iovec iov = { buf, sizeof(buf) }; while (1) { int status; struct nlmsghdr *h; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; status = recvmsg(rth->fd, &msg, 0); if (status < 0) { if (errno == EINTR) continue; nl_perror("OVERRUN"); continue; } if (status == 0) { fprintf(stderr, "EOF on netlink\n"); return -1; } if (msg.msg_namelen != sizeof(nladdr)) { fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); exit(1); } h = (struct nlmsghdr*)buf; while (NLMSG_OK(h, status)) { int err; if (h->nlmsg_pid != rth->local.nl_pid || h->nlmsg_seq != rth->dump) { if (junk) { err = junk(&nladdr, h, arg2); if (err < 0) return err; } goto skip_it; } if (h->nlmsg_type == NLMSG_DONE) return 0; if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); if (h->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) { fprintf(stderr, "ERROR truncated\n"); } else { errno = -err->error; /* Scott checked for EEXIST and return 0! 9-4-02*/ if (errno != EEXIST) nl_perror("RTNETLINK answers"); else return 0; } return -1; } err = filter(&nladdr, h, arg1); if (err < 0) return err; skip_it: h = NLMSG_NEXT(h, status); } if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Message truncated\n"); continue; } if (status) { fprintf(stderr, "!!!Remnant of size %d\n", status); exit(1); } } } int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, unsigned groups, struct nlmsghdr *answer, int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg) { int status; struct nlmsghdr *h; struct sockaddr_nl nladdr; struct iovec iov = { (void*)n, n->nlmsg_len }; char buf[8192]; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = peer; nladdr.nl_groups = groups; n->nlmsg_seq = ++rtnl->seq; if (answer == NULL) n->nlmsg_flags |= NLM_F_ACK; status = sendmsg(rtnl->fd, &msg, 0); if (status < 0) { nl_perror("Cannot talk to rtnetlink"); return -1; } iov.iov_base = buf; iov.iov_len = sizeof(buf); while (1) { status = recvmsg(rtnl->fd, &msg, 0); if (status < 0) { if (errno == EINTR) continue; nl_perror("OVERRUN"); continue; } if (status == 0) { fprintf(stderr, "EOF on netlink\n"); return -1; } if (msg.msg_namelen != sizeof(nladdr)) { fprintf(stderr, "sender address length == %d\n", msg.msg_namelen); exit(1); } for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { int err; int len = h->nlmsg_len; pid_t pid=h->nlmsg_pid; int l = len - sizeof(*h); unsigned seq=h->nlmsg_seq; if (l<0 || len>status) { if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Truncated message\n"); return -1; } fprintf(stderr, "!!!malformed message: len=%d\n", len); exit(1); } if (h->nlmsg_pid != pid || h->nlmsg_seq != seq) { if (junk) { err = junk(&nladdr, h, jarg); if (err < 0) return err; } continue; } if (h->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr*)NLMSG_DATA(h); if (l < sizeof(struct nlmsgerr)) { fprintf(stderr, "ERROR truncated\n"); } else { errno = -err->error; if (errno == 0) { if (answer) memcpy(answer, h, h->nlmsg_len); return 0; } /* Scott checked for EEXIST and return 0! 9-4-02*/ if (errno != EEXIST) nl_perror("RTNETLINK answers"); else return 0; } return -1; } if (answer) { memcpy(answer, h, h->nlmsg_len); return 0; } fprintf(stderr, "Unexpected reply!!!\n"); status -= NLMSG_ALIGN(len); h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); } if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Message truncated\n"); continue; } if (status) { fprintf(stderr, "!!!Remnant of size %d\n", status); exit(1); } } } int rtnl_listen(struct rtnl_handle *rtnl, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg) { int status; struct nlmsghdr *h; struct sockaddr_nl nladdr; struct iovec iov; char buf[8192]; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = 0; nladdr.nl_groups = 0; iov.iov_base = buf; iov.iov_len = sizeof(buf); while (1) { status = recvmsg(rtnl->fd, &msg, 0); if (status < 0) { if (errno == EINTR) continue; nl_perror("OVERRUN"); continue; } if (status == 0) { fprintf(stderr, "EOF on netlink\n"); return -1; } if (msg.msg_namelen != sizeof(nladdr)) { fprintf(stderr, "Sender address length == %d\n", msg.msg_namelen); exit(1); } for (h = (struct nlmsghdr*)buf; status >= sizeof(*h); ) { int err; int len = h->nlmsg_len; int l = len - sizeof(*h); if (l<0 || len>status) { if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Truncated message\n"); return -1; } fprintf(stderr, "!!!malformed message: len=%d\n", len); exit(1); } err = handler(&nladdr, h, jarg); if (err < 0) return err; status -= NLMSG_ALIGN(len); h = (struct nlmsghdr*)((char*)h + NLMSG_ALIGN(len)); } if (msg.msg_flags & MSG_TRUNC) { fprintf(stderr, "Message truncated\n"); continue; } if (status) { fprintf(stderr, "!!!Remnant of size %d\n", status); exit(1); } } } int rtnl_from_file(FILE *rtnl, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg) { int status; struct sockaddr_nl nladdr; char buf[8192]; struct nlmsghdr *h = (void*)buf; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; nladdr.nl_pid = 0; nladdr.nl_groups = 0; while (1) { int err, len, type; pid_t pid; int l; unsigned seq; status = fread(&buf, 1, sizeof(*h), rtnl); if (status < 0) { if (errno == EINTR) continue; nl_perror("rtnl_from_file: fread"); return -1; } if (status == 0) return 0; len = h->nlmsg_len; type= h->nlmsg_type; pid=h->nlmsg_pid; l = len - sizeof(*h); seq=h->nlmsg_seq; if (l<0 || len>sizeof(buf)) { fprintf(stderr, "!!!malformed message: len=%d @%lu\n", len, ftell(rtnl)); return -1; } status = fread(NLMSG_DATA(h), 1, NLMSG_ALIGN(l), rtnl); if (status < 0) { nl_perror("rtnl_from_file: fread"); return -1; } if (status < l) { fprintf(stderr, "rtnl-from_file: truncated message\n"); return -1; } err = handler(&nladdr, h, jarg); if (err < 0) return err; } } int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data) { int len = RTA_LENGTH(4); struct rtattr *rta; if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) return -1; rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; memcpy(RTA_DATA(rta), &data, 4); n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; return 0; } int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen) { int len = RTA_LENGTH(alen); struct rtattr *rta; if (NLMSG_ALIGN(n->nlmsg_len) + len > maxlen) return -1; rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; memcpy(RTA_DATA(rta), data, alen); n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; return 0; } int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data) { int len = RTA_LENGTH(4); struct rtattr *subrta; if (RTA_ALIGN(rta->rta_len) + len > maxlen) return -1; subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); subrta->rta_type = type; subrta->rta_len = len; memcpy(RTA_DATA(subrta), &data, 4); rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; return 0; } int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen) { struct rtattr *subrta; int len = RTA_LENGTH(alen); if (RTA_ALIGN(rta->rta_len) + len > maxlen) return -1; subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); subrta->rta_type = type; subrta->rta_len = len; memcpy(RTA_DATA(subrta), data, alen); rta->rta_len = NLMSG_ALIGN(rta->rta_len) + len; return 0; } int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) { while (RTA_OK(rta, len)) { if (rta->rta_type <= max) tb[rta->rta_type] = rta; rta = RTA_NEXT(rta,len); } if (len) fprintf(stderr, "!!!Deficit %d, rta_len=%d\n", len, rta->rta_len); return 0; } /**************************************************************** NAME : rtnl_close 00/06/02 23:43:45 AIM : REMARK : ****************************************************************/ int rtnl_close(struct rtnl_handle *rth) { /* close the fd */ close( rth->fd ); return(0); } vrrpd-1.0/libnetlink.h0000644000175000017500000000332707537132541014415 0ustar jfsjfs00000000000000#ifndef __LIBNETLINK_H__ #define __LIBNETLINK_H__ 1 #include #include #include struct rtnl_handle { int fd; struct sockaddr_nl local; struct sockaddr_nl peer; __u32 seq; __u32 dump; }; extern int rtnl_open(struct rtnl_handle *rth, unsigned subscriptions); extern int rtnl_close(struct rtnl_handle *rth); extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type); extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len); extern int rtnl_dump_filter(struct rtnl_handle *rth, int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), void *arg1, int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *arg2); extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, unsigned groups, struct nlmsghdr *answer, int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg); extern int rtnl_send(struct rtnl_handle *rth, char *buf, int); extern int addattr32(struct nlmsghdr *n, int maxlen, int type, __u32 data); extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int alen); extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, __u32 data); extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen); extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len); extern int rtnl_listen(struct rtnl_handle *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg); extern int rtnl_from_file(FILE *, int (*handler)(struct sockaddr_nl *,struct nlmsghdr *n, void *), void *jarg); #endif /* __LIBNETLINK_H__ */ vrrpd-1.0/proto.h0000644000175000017500000000104107537132541013414 0ustar jfsjfs00000000000000/*=========================[ (c) POIPOI SOFT ]================================== FILE : [protodef.h] DATE : 95/11/10 22:44:23 WHO : poipoi@hwi.resi.insa-lyon.fr Linux 1.2.13 REMARK : ================================================================================ ==============================================================================*/ #ifndef __PROTODEF_H__ #define __PROTODEF_H__ #ifndef PROTO #if __STDC__ # define PROTO(x) x #else # define PROTO(x) () #endif #endif #endif /* __PROTODEF_H__ */ vrrpd-1.0/route.generic0000644000175000017500000010354707537132541014612 0ustar jfsjfs00000000000000diff -ru -x*~ linux-lt-2.3.99-pre3.prev/Documentation/networking/ip-sysctl.txt linux-lt-2.3.99-pre3/Documentation/networking/ip-sysctl.txt --- linux-lt-2.3.99-pre3.prev/Documentation/networking/ip-sysctl.txt Sun Jan 23 03:54:56 2000 +++ linux-lt-2.3.99-pre3/Documentation/networking/ip-sysctl.txt Tue Mar 28 19:40:59 2000 @@ -262,13 +262,21 @@ Do proxy arp. shared_media - BOOLEAN - Send(router) or accept(host) RFC1620 shared media redirects. + Do not check the new gateway specified in incoming ICMP redirect + messages for belonging to a directly attached network (i.e. the + routing table has for this address an entry pointing to the given + device, doesn't have a gateway, and with scope not wider SCOPE_LINK). + If this variable is TRUE then new gateways are only checked for being a + unicast addresses. If it is FALSE then the full check described + above is performed. See RFC1620 for background information about + shared media. Overrides ip_secure_redirects. default TRUE secure_redirects - BOOLEAN - Accept ICMP redirect messages only for gateways, - listed in default gateway list. + Accept ICMP redirect messages only for gateways already listed as + gateways in the routing tables. This check is performed only when + `shared_media' is FALSE. default TRUE send_redirects - BOOLEAN @@ -287,6 +295,19 @@ default TRUE (router) FALSE (host) +source_check - BOOLEAN + Check source address for outgoing packets. + If source_check is turned on all outgoing packets (including going + through a loopback interface) are checked for the source address + being local. An address is considered as local for this purposes if + a route lookup in the opposite direction (i.e. with source and + destination addresses being reversed) gives a unicast local route + entry. + Note: source addresses are always checked for being not a multicast, + limited broadcast, zero net, or loopback (for non-loopback + interfaces) independetly of the setting of the option. + default TRUE + rp_filter - BOOLEAN 1 - do source validation by reversed path, as specified in RFC1812 Recommended option for single homed hosts and stub network @@ -305,4 +326,8 @@ Updated by: Andi Kleen ak@muc.de + +Andrey Savochkin +saw@msu.ru + $Id: route.generic,v 1.1.1.1 2002/09/09 14:51:13 imagestream Exp $ diff -ru -x*~ linux-lt-2.3.99-pre3.prev/include/linux/in_route.h linux-lt-2.3.99-pre3/include/linux/in_route.h --- linux-lt-2.3.99-pre3.prev/include/linux/in_route.h Fri Jun 12 13:52:33 1998 +++ linux-lt-2.3.99-pre3/include/linux/in_route.h Tue Mar 28 19:39:49 2000 @@ -4,6 +4,7 @@ /* IPv4 routing cache flags */ #define RTCF_DEAD RTNH_F_DEAD +#define RTCF_PERVASIVE RTNH_F_PERVASIVE #define RTCF_ONLINK RTNH_F_ONLINK /* Obsolete flag. About to be deleted */ diff -ru -x*~ linux-lt-2.3.99-pre3.prev/include/linux/inetdevice.h linux-lt-2.3.99-pre3/include/linux/inetdevice.h --- linux-lt-2.3.99-pre3.prev/include/linux/inetdevice.h Tue Aug 24 01:01:02 1999 +++ linux-lt-2.3.99-pre3/include/linux/inetdevice.h Tue Mar 28 19:39:49 2000 @@ -9,6 +9,7 @@ int send_redirects; int secure_redirects; int shared_media; + int source_check; int accept_source_route; int rp_filter; int proxy_arp; @@ -46,6 +47,7 @@ #define IN_DEV_SHARED_MEDIA(in_dev) (ipv4_devconf.shared_media || (in_dev)->cnf.shared_media) #define IN_DEV_TX_REDIRECTS(in_dev) (ipv4_devconf.send_redirects || (in_dev)->cnf.send_redirects) #define IN_DEV_SEC_REDIRECTS(in_dev) (ipv4_devconf.secure_redirects || (in_dev)->cnf.secure_redirects) +#define IN_DEV_SRC_CHECK(in_dev) (ipv4_devconf.source_check || (in_dev)->cnf.source_check) #define IN_DEV_IDTAG(in_dev) ((in_dev)->cnf.tag) #define IN_DEV_RX_REDIRECTS(in_dev) \ @@ -73,7 +75,6 @@ extern int unregister_inetaddr_notifier(struct notifier_block *nb); extern struct net_device *ip_dev_find(u32 addr); -extern int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b); extern int devinet_ioctl(unsigned int cmd, void *); extern void devinet_init(void); extern struct in_device *inetdev_init(struct net_device *dev); diff -ru -x*~ linux-lt-2.3.99-pre3.prev/include/linux/rtnetlink.h linux-lt-2.3.99-pre3/include/linux/rtnetlink.h --- linux-lt-2.3.99-pre3.prev/include/linux/rtnetlink.h Thu Feb 10 12:08:09 2000 +++ linux-lt-2.3.99-pre3/include/linux/rtnetlink.h Tue Mar 28 19:39:49 2000 @@ -224,9 +224,11 @@ /* rtnh_flags */ -#define RTNH_F_DEAD 1 /* Nexthop is dead (used by multipath) */ -#define RTNH_F_PERVASIVE 2 /* Do recursive gateway lookup */ -#define RTNH_F_ONLINK 4 /* Gateway is forced on link */ +#define RTNH_F_DEAD 0x01 /* Nexthop is dead (used by multipath) */ +#define RTNH_F_PERVASIVE 0x02 /* Omit gateway & pref_src test */ +#define RTNH_F_ONLINK 0x04 /* Gateway is forced on link */ +#define RTNH_F_GLUE 0x08 /* Nexthop is glued */ +#define RTNH_F_USEFIRST 0x10 /* Use only it (for multipath) */ /* Macros to handle hexthops */ diff -ru -x*~ linux-lt-2.3.99-pre3.prev/include/linux/sysctl.h linux-lt-2.3.99-pre3/include/linux/sysctl.h --- linux-lt-2.3.99-pre3.prev/include/linux/sysctl.h Thu Mar 9 01:16:24 2000 +++ linux-lt-2.3.99-pre3/include/linux/sysctl.h Tue Mar 28 19:39:49 2000 @@ -302,7 +302,8 @@ NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE=9, NET_IPV4_CONF_BOOTP_RELAY=10, NET_IPV4_CONF_LOG_MARTIANS=11, - NET_IPV4_CONF_TAG=12 + NET_IPV4_CONF_TAG=12, + NET_IPV4_CONF_SRC_CHECK=13, }; /* /proc/sys/net/ipv6 */ diff -ru -x*~ linux-lt-2.3.99-pre3.prev/include/net/ip_fib.h linux-lt-2.3.99-pre3/include/net/ip_fib.h --- linux-lt-2.3.99-pre3.prev/include/net/ip_fib.h Tue Aug 24 01:01:02 1999 +++ linux-lt-2.3.99-pre3/include/net/ip_fib.h Tue Mar 28 19:39:49 2000 @@ -217,7 +217,8 @@ extern int fib_dump_info(struct sk_buff *skb, u32 pid, u32 seq, int event, u8 tb_id, u8 type, u8 scope, void *dst, int dst_len, u8 tos, struct fib_info *fi); -extern int fib_sync_down(u32 local, struct net_device *dev, int force); +extern int fib_sync_addr_down(u32 local); +extern int fib_sync_dev_down(struct net_device *dev, int force); extern int fib_sync_up(struct net_device *dev); extern int fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm, struct kern_rta *rta, struct rtentry *r); diff -ru -x*~ linux-lt-2.3.99-pre3.prev/include/net/route.h linux-lt-2.3.99-pre3/include/net/route.h --- linux-lt-2.3.99-pre3.prev/include/net/route.h Sun Mar 19 04:11:22 2000 +++ linux-lt-2.3.99-pre3/include/net/route.h Tue Mar 28 19:39:49 2000 @@ -106,6 +106,9 @@ extern void ip_rt_send_redirect(struct sk_buff *skb); extern unsigned inet_addr_type(u32 addr); +extern int inet_addr_onlink(struct net_device *, u32 dst, u32 src, u8 tos); +extern int fib_local_source(u32 saddr, u32 daddr, u8 tos, struct net_device *); +extern u32 fib_select_addr(struct net_device *, u32 dst, int scope); extern void ip_rt_multicast_event(struct in_device *); extern int ip_rt_ioctl(unsigned int cmd, void *arg); extern void ip_rt_get_source(u8 *src, struct rtable *rt); diff -ru -x*~ linux-lt-2.3.99-pre3.prev/net/ipv4/af_inet.c linux-lt-2.3.99-pre3/net/ipv4/af_inet.c --- linux-lt-2.3.99-pre3.prev/net/ipv4/af_inet.c Tue Feb 22 09:35:06 2000 +++ linux-lt-2.3.99-pre3/net/ipv4/af_inet.c Tue Mar 28 19:43:30 2000 @@ -463,6 +463,15 @@ return -EINVAL; chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); + /* The source address check is omitted here. + * We may allow to bind sockets to any address for listening purposes. + * Such sockets will get only those packets which were considered as + * "local" by routing (i.e. configured to go locally by the + * administrator). + * Outgoing packets are checked by output routing (see + * ip_route_output_slow and outrt_check_src in net/ipv4/route.c). + * 1999/11/13 SAW + */ snum = ntohs(addr->sin_port); if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)) diff -ru -x*~ linux-lt-2.3.99-pre3.prev/net/ipv4/arp.c linux-lt-2.3.99-pre3/net/ipv4/arp.c --- linux-lt-2.3.99-pre3.prev/net/ipv4/arp.c Sun Jan 23 03:54:57 2000 +++ linux-lt-2.3.99-pre3/net/ipv4/arp.c Tue Mar 28 19:39:50 2000 @@ -333,10 +333,11 @@ u32 target = *(u32*)neigh->primary_key; int probes = atomic_read(&neigh->probes); - if (skb && inet_addr_type(skb->nh.iph->saddr) == RTN_LOCAL) + if (skb && fib_local_source(skb->nh.iph->saddr, target, + skb->nh.iph->tos, dev) == 0) saddr = skb->nh.iph->saddr; else - saddr = inet_select_addr(dev, target, RT_SCOPE_LINK); + saddr = fib_select_addr(dev, target, RT_SCOPE_LINK); if ((probes -= neigh->parms->ucast_probes) < 0) { if (!(neigh->nud_state&NUD_VALID)) diff -ru -x*~ linux-lt-2.3.99-pre3.prev/net/ipv4/devinet.c linux-lt-2.3.99-pre3/net/ipv4/devinet.c --- linux-lt-2.3.99-pre3.prev/net/ipv4/devinet.c Sun Jan 9 13:36:20 2000 +++ linux-lt-2.3.99-pre3/net/ipv4/devinet.c Tue Mar 28 19:39:50 2000 @@ -58,8 +58,8 @@ #include #include -struct ipv4_devconf ipv4_devconf = { 1, 1, 1, 1, 0, }; -static struct ipv4_devconf ipv4_devconf_dflt = { 1, 1, 1, 1, 1, }; +struct ipv4_devconf ipv4_devconf = { 1, 1, 1, 1, 1, 0, }; +static struct ipv4_devconf ipv4_devconf_dflt = { 1, 1, 1, 1, 1, 1, }; #ifdef CONFIG_RTNETLINK static void rtmsg_ifa(int event, struct in_ifaddr *); @@ -186,21 +186,6 @@ in_dev_put(in_dev); } -int inet_addr_onlink(struct in_device *in_dev, u32 a, u32 b) -{ - read_lock(&in_dev->lock); - for_primary_ifa(in_dev) { - if (inet_ifa_match(a, ifa)) { - if (!b || inet_ifa_match(b, ifa)) { - read_unlock(&in_dev->lock); - return 1; - } - } - } endfor_ifa(in_dev); - read_unlock(&in_dev->lock); - return 0; -} - static void inet_del_ifa(struct in_device *in_dev, struct in_ifaddr **ifap, int destroy) { @@ -1027,7 +1012,7 @@ static struct devinet_sysctl_table { struct ctl_table_header *sysctl_header; - ctl_table devinet_vars[13]; + ctl_table devinet_vars[14]; ctl_table devinet_dev[2]; ctl_table devinet_conf_dir[2]; ctl_table devinet_proto_dir[2]; @@ -1066,6 +1051,9 @@ &proc_dointvec}, {NET_IPV4_CONF_LOG_MARTIANS, "log_martians", &ipv4_devconf.log_martians, sizeof(int), 0644, NULL, + &proc_dointvec}, + {NET_IPV4_CONF_SRC_CHECK, "source_check", + &ipv4_devconf.source_check, sizeof(int), 0644, NULL, &proc_dointvec}, {NET_IPV4_CONF_TAG, "tag", &ipv4_devconf.tag, sizeof(int), 0644, NULL, diff -ru -x*~ linux-lt-2.3.99-pre3.prev/net/ipv4/fib_frontend.c linux-lt-2.3.99-pre3/net/ipv4/fib_frontend.c --- linux-lt-2.3.99-pre3.prev/net/ipv4/fib_frontend.c Thu Dec 23 11:55:38 1999 +++ linux-lt-2.3.99-pre3/net/ipv4/fib_frontend.c Tue Mar 28 19:39:50 2000 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -168,11 +169,31 @@ return dev; } +int fib_local_source(u32 saddr, u32 daddr, u8 tos, struct net_device *dev) +{ + struct rt_key key; + struct fib_result res; + + memset(&key, 0, sizeof(key)); + key.src = daddr; + key.dst = saddr; + key.tos = tos; + key.iif = dev->ifindex; + if (fib_lookup(&key, &res) == 0) { + unsigned ret; + ret = res.type; + fib_res_put(&res); + if (ret != RTN_LOCAL) + return -EINVAL; + } + return 0; +} + unsigned inet_addr_type(u32 addr) { struct rt_key key; struct fib_result res; - unsigned ret = RTN_BROADCAST; + unsigned ret; if (ZERONET(addr) || BADCLASS(addr)) return RTN_BROADCAST; @@ -180,21 +201,57 @@ return RTN_MULTICAST; memset(&key, 0, sizeof(key)); + key.src = addr; key.dst = addr; -#ifdef CONFIG_IP_MULTIPLE_TABLES - res.r = NULL; -#endif - if (local_table) { - ret = RTN_UNICAST; - if (local_table->tb_lookup(local_table, &key, &res) == 0) { - ret = res.type; - fib_res_put(&res); - } + ret = RTN_UNICAST; + if (fib_lookup(&key, &res) == 0) { + ret = res.type; + fib_res_put(&res); } return ret; } +u32 fib_select_addr(struct net_device *dev, u32 dst, int scope) +{ + struct rt_key key; + struct fib_result res; + u32 ret; + + memset(&key, 0, sizeof(key)); + key.src = dst; + key.dst = dst; + key.oif = dev->ifindex; + key.scope = scope; + + if (fib_lookup(&key, &res) == 0) { + ret = FIB_RES_PREFSRC(res); + fib_res_put(&res); + } else + ret = inet_select_addr(dev, dst, scope); + return ret; +} + +/* Check if dst is a UNICAST address and reachable via device dev */ +int inet_addr_onlink(struct net_device *dev, u32 dst, u32 src, u8 tos) +{ + struct rt_key key; + struct fib_result res; + int ret; + + key.src = src; + key.dst = dst; + key.tos = tos; + key.iif = 0; + key.oif = 0; + key.scope = RT_SCOPE_LINK; + if (fib_lookup(&key, &res) != 0) + return 0; + ret = (res.type == RTN_UNICAST && FIB_RES_DEV(res) == dev); + fib_res_put(&res); + return ret; +} + /* Given (packet source, input interface) and optional (dst, oif, tos): - (main) check, that source is valid i.e. not broadcast or our local address. @@ -559,7 +616,7 @@ First of all, we scan fib_info list searching for stray nexthop entries, then ignite fib_flush. */ - if (fib_sync_down(ifa->ifa_local, NULL, 0)) + if (fib_sync_addr_down(ifa->ifa_local)) fib_flush(); } } @@ -571,7 +628,7 @@ static void fib_disable_ip(struct net_device *dev, int force) { - if (fib_sync_down(0, dev, force)) + if (fib_sync_dev_down(dev, force)) fib_flush(); rt_cache_flush(0); arp_ifdown(dev); @@ -591,8 +648,10 @@ /* Last address was deleted from this interface. Disable IP. */ + printk("fib_inetaddr_event: dev down, fib_disable_ip(1)\n"); fib_disable_ip(ifa->ifa_dev->dev, 1); } else { + printk("fib_inetaddr_event: dev down, fib_del_ifaddr\n"); fib_del_ifaddr(ifa); rt_cache_flush(-1); } @@ -606,11 +665,10 @@ struct net_device *dev = ptr; struct in_device *in_dev = __in_dev_get(dev); - if (!in_dev) - return NOTIFY_DONE; - switch (event) { case NETDEV_UP: + if (!in_dev) + break; for_ifa(in_dev) { fib_add_ifaddr(ifa); } endfor_ifa(in_dev); @@ -620,9 +678,18 @@ rt_cache_flush(-1); break; case NETDEV_DOWN: + printk("fib_netdev_event: dev down, fib_disable_ip(0)\n"); fib_disable_ip(dev, 0); break; case NETDEV_UNREGISTER: + /* Routes pointing to dev may still exists even when IP has + * been shut down. It may happen because routes of local type + * has special nexthop (see fib_create_info() and + * fib_sync_dev_down()). I don't know if this state is valid. + * Now I call fib_disable_ip() independently from if the device + * has IP because otherwise stale device references are left. + * 1999/11/28 SAW */ + printk("fib_netdev_event: dev unregister, fib_disable_ip(1)\n"); fib_disable_ip(dev, 1); break; case NETDEV_CHANGEMTU: diff -ru -x*~ linux-lt-2.3.99-pre3.prev/net/ipv4/fib_semantics.c linux-lt-2.3.99-pre3/net/ipv4/fib_semantics.c --- linux-lt-2.3.99-pre3.prev/net/ipv4/fib_semantics.c Tue Aug 24 01:01:02 1999 +++ linux-lt-2.3.99-pre3/net/ipv4/fib_semantics.c Tue Mar 28 19:39:50 2000 @@ -345,14 +345,15 @@ { int err; + if (nh->nh_flags&RTNH_F_PERVASIVE) { + fi->fib_flags |= RTCF_PERVASIVE; + return 0; + } + if (nh->nh_gw) { struct rt_key key; struct fib_result res; -#ifdef CONFIG_IP_ROUTE_PERVASIVE - if (nh->nh_flags&RTNH_F_PERVASIVE) - return 0; -#endif if (nh->nh_flags&RTNH_F_ONLINK) { struct net_device *dev; @@ -389,7 +390,7 @@ } else { struct in_device *in_dev; - if (nh->nh_flags&(RTNH_F_PERVASIVE|RTNH_F_ONLINK)) + if (nh->nh_flags&RTNH_F_ONLINK) return -EINVAL; in_dev = inetdev_by_index(nh->nh_oif); @@ -528,7 +529,7 @@ } endfor_nexthops(fi) } - if (fi->fib_prefsrc) { + if (fi->fib_prefsrc && !(fi->fib_flags&RTCF_PERVASIVE)) { if (r->rtm_type != RTN_LOCAL || rta->rta_dst == NULL || memcmp(&fi->fib_prefsrc, rta->rta_dst, 4)) if (inet_addr_type(fi->fib_prefsrc) != RTN_LOCAL) @@ -857,19 +858,34 @@ - device went down -> we must shutdown all nexthops going via it. */ -int fib_sync_down(u32 local, struct net_device *dev, int force) +int fib_sync_addr_down(u32 local) +{ + int ret = 0; + + if (!local) + goto out; + + for_fib_info() { + if (fi->fib_prefsrc == local && + !(fi->fib_flags&RTCF_PERVASIVE)) { + fi->fib_flags |= RTCF_DEAD; + ret++; + } + } endfor_fib_info(); +out: + return ret; +} + +int fib_sync_dev_down(struct net_device *dev, int force) { int ret = 0; int scope = RT_SCOPE_NOWHERE; - + if (force) scope = -1; for_fib_info() { - if (local && fi->fib_prefsrc == local) { - fi->fib_flags |= RTNH_F_DEAD; - ret++; - } else if (dev && fi->fib_nhs) { + if (fi->fib_nhs) { int dead = 0; change_nexthops(fi) { @@ -886,7 +902,7 @@ } } endfor_nexthops(fi) if (dead == fi->fib_nhs) { - fi->fib_flags |= RTNH_F_DEAD; + fi->fib_flags |= RTCF_DEAD; ret++; } } @@ -947,6 +963,10 @@ int power = 0; change_nexthops(fi) { if (!(nh->nh_flags&RTNH_F_DEAD)) { + if (nh->nh_flags&RTNH_F_USEFIRST) { + res->nh_sel = nhsel; + return; + } power += nh->nh_weight; nh->nh_power = nh->nh_weight; } diff -ru -x*~ linux-lt-2.3.99-pre3.prev/net/ipv4/route.c linux-lt-2.3.99-pre3/net/ipv4/route.c --- linux-lt-2.3.99-pre3.prev/net/ipv4/route.c Mon Mar 27 18:25:56 2000 +++ linux-lt-2.3.99-pre3/net/ipv4/route.c Tue Mar 28 19:57:19 2000 @@ -711,22 +711,28 @@ struct rtable *rth, **rthp; u32 skeys[2] = { saddr, 0 }; int ikeys[2] = { dev->ifindex, 0 }; + char *reason; tos &= IPTOS_TOS_MASK; if (!in_dev) return; + reason = "bad gateway"; if (new_gw == old_gw || !IN_DEV_RX_REDIRECTS(in_dev) || MULTICAST(new_gw) || BADCLASS(new_gw) || ZERONET(new_gw)) goto reject_redirect; if (!IN_DEV_SHARED_MEDIA(in_dev)) { - if (!inet_addr_onlink(in_dev, new_gw, old_gw)) + reason = "gateway not onlink"; + if (!inet_addr_onlink(dev, new_gw, saddr, tos)) goto reject_redirect; - if (IN_DEV_SEC_REDIRECTS(in_dev) && ip_fib_check_default(new_gw, dev)) + reason = "insecure gateway"; + if (IN_DEV_SEC_REDIRECTS(in_dev) && + ip_fib_check_default(new_gw, dev)) goto reject_redirect; } else { + reason = "unacceptable gateway"; if (inet_addr_type(new_gw) != RTN_UNICAST) goto reject_redirect; } @@ -816,9 +822,9 @@ reject_redirect: #ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) - printk(KERN_INFO "Redirect from %X/%s to %X ignored." + printk(KERN_INFO "Redirect from %X/%s to %X ignored (%s). " "Path = %X -> %X, tos %02x\n", - ntohl(old_gw), dev->name, ntohl(new_gw), + ntohl(old_gw), dev->name, ntohl(new_gw), reason, ntohl(saddr), ntohl(daddr), tos); #endif in_dev_put(in_dev); @@ -836,7 +842,7 @@ if ((rt->rt_flags&RTCF_REDIRECTED) || rt->u.dst.expires) { unsigned hash = rt_hash_code(rt->key.dst, rt->key.src^(rt->key.oif<<5), rt->key.tos); #if RT_CACHE_DEBUG >= 1 - printk(KERN_DEBUG "ip_rt_advice: redirect to %d.%d.%d.%d/%02x dropped\n", NIPQUAD(rt->rt_dst), rt->key.tos); + printk(KERN_DEBUG "ip_rt_advice: cache entry to %d.%d.%d.%d/%02x dropped\n", NIPQUAD(rt->rt_dst), rt->key.tos); #endif rt_del(hash, rt); return NULL; @@ -1106,6 +1112,10 @@ } #endif +/********************************************************************* + Input/output routing + *********************************************************************/ + static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag) { struct fib_info *fi = res->fi; @@ -1145,6 +1155,10 @@ rt->rt_type = res->type; } +/********************************************************************* + Input + *********************************************************************/ + static int ip_route_input_mc(struct sk_buff *skb, u32 daddr, u32 saddr, u8 tos, struct net_device *dev, int our) @@ -1362,9 +1376,7 @@ if (err) flags |= RTCF_DIRECTSRC; - if (out_dev == in_dev && err && !(flags&(RTCF_NAT|RTCF_MASQ)) && - (IN_DEV_SHARED_MEDIA(out_dev) - || inet_addr_onlink(out_dev, saddr, FIB_RES_GW(res)))) + if (out_dev == in_dev && err && !(flags&(RTCF_NAT|RTCF_MASQ))) flags |= RTCF_DOREDIRECT; if (skb->protocol != __constant_htons(ETH_P_IP)) { @@ -1592,22 +1604,183 @@ return ip_route_input_slow(skb, daddr, saddr, tos, dev); } +/********************************************************************* + Output + *********************************************************************/ + +/* TODO: + - Check if CONFIG_IP_MROUTE ifdef makes any sense. + */ + +/* User supplied source address verification for output packets. + Such a verification can't be considered as a security measure. + It's rather an additional Internet protection against bugs in applications + (like using an uninitialized garbage as a source for UDP packets). + */ +static int outrt_check_src(u32 saddr, u32 daddr, u32 tos, struct net_device *dev_out) +{ + struct in_device *in_dev; + int src_check; + + if (MULTICAST(saddr) || BADCLASS(saddr) || ZERONET(saddr)) + return -EINVAL; + if (saddr == htonl(INADDR_BROADCAST)) + return -EINVAL; + + in_dev = in_dev_get(dev_out); + src_check = IN_DEV_SRC_CHECK(in_dev); + in_dev_put(in_dev); + if (!src_check) + return 0; + + if (LOOPBACK(saddr) && !(dev_out->flags&IFF_LOOPBACK)) + return -EINVAL; + + return fib_local_source(saddr, daddr, tos, dev_out); +} + +static int outrt_make_route(struct rtable **rp, + /* route lookup key */ + struct rt_key *key, + /* path */ + u32 daddr, u32 saddr, struct net_device *dev_out, + /* FIB lookup results (type, fi, nh.gw, nh.scope) */ + struct fib_result *res + ) +{ + struct rtable *rth; + unsigned hash; + unsigned flags; + + rth = dst_alloc(&ipv4_dst_ops); + if (!rth) + return -ENOBUFS; + + atomic_set(&rth->u.dst.__refcnt, 1); + rth->u.dst.flags= DST_HOST; + rth->key = *key; + rth->key.iif = 0; /* output route */ + rth->rt_dst = daddr; + rth->rt_src = saddr; +#ifdef CONFIG_IP_ROUTE_NAT + rth->rt_dst_map = daddr; + rth->rt_src_map = saddr; +#endif + + /* Set input, output ROUTINES and rt_spec_dst */ + switch (res->type) { + case RTN_LOCAL: + /* Use loopback interface for unicast local traffic */ + fib_res_put(res); + res->fi = NULL; +#ifdef CONFIG_IP_MULTIPLE_TABLES + res->r = NULL; +#endif + dev_out = &loopback_dev; + flags = RTCF_LOCAL; + rth->u.dst.input = ip_local_deliver; + rth->u.dst.output = ip_output; + rth->rt_spec_dst = daddr; /* local side of the path */ + break; + case RTN_UNICAST: + flags = 0; + rth->u.dst.output = ip_output; + rth->rt_spec_dst = saddr; +#ifdef CONFIG_IP_ROUTE_MULTIPATH + if (res->fi->fib_nhs > 1 && key->oif == 0) + /* Set the proper res->nh_sel. */ + fib_select_multipath(key, res); + else +#endif + if (res->prefixlen == 0 && res->type == RTN_UNICAST && + key->oif == 0) + fib_select_default(key, res); + break; + case RTN_BROADCAST: + flags = RTCF_BROADCAST|RTCF_LOCAL; + rth->u.dst.input = ip_local_deliver; + if (!(dev_out->flags&IFF_LOOPBACK)) + rth->u.dst.output = ip_mc_output; + else + rth->u.dst.output = ip_output; + rth->rt_spec_dst = saddr; + break; + case RTN_MULTICAST: + { + /* Please note that all ancient band-aids were removed. + I don't try to catch route table deficient for + multicast or 255.255.255.255 routes and "smartly" + replace a gatewayed default by the corresponding + route. 1999/11/06 SAW + */ + struct in_device *in_dev = in_dev_get(dev_out); + rth->u.dst.input = ip_local_deliver; + rth->u.dst.output = ip_output; + flags = RTCF_MULTICAST; + if (in_dev && ip_check_mc(in_dev, daddr)) { + /* Note: I preserve the original behaviour + here. It means that users after joining and + leaving a multicast group have to flush + the route cache. I hope they know about it + :-) 1999/11/06 SAW + */ + flags = RTCF_MULTICAST|RTCF_LOCAL; + if (!(dev_out->flags&IFF_LOOPBACK)) + rth->u.dst.output = ip_mc_output; + } +#ifdef CONFIG_IP_MROUTE + if (in_dev && !(dev_out->flags&IFF_LOOPBACK)) { + if (IN_DEV_MFORWARD(in_dev) && + !LOCAL_MCAST(daddr)) + { + rth->u.dst.input = ip_mr_input; + rth->u.dst.output = ip_mc_output; + } + } +#endif + if (in_dev) + in_dev_put(in_dev); + rth->rt_spec_dst = saddr; + } + break; + case RTN_NAT: + dst_free(&rth->u.dst); + return -EINVAL; + default: + printk(KERN_CRIT "bad lookup result type in route output\n"); + return -EINVAL; + } + + /* INTERFACE */ + /* Store the interface information to allow users to get it via + * [SOL_IP, IP_PKTINFO] conrol message for locally seen packets + * (including broadcast and multicast ones). --SAW */ + rth->rt_iif = key->oif ? : dev_out->ifindex; + /* Set output device */ + rth->u.dst.dev = dev_out; + dev_hold(dev_out); + + /* Set GATEWAY */ + rth->rt_gateway = daddr; + /* if res->fi != NULL set the real gateway */ + rt_set_nexthop(rth, res, 0); + + rth->rt_flags = flags; + + hash = rt_hash_code(key->dst, key->src^(key->oif<<5), key->tos); + return rt_intern_hash(hash, rth, rp); +} + /* * Major route resolver routine. */ - int ip_route_output_slow(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif) { struct rt_key key; struct fib_result res; - unsigned flags = 0; - struct rtable *rth; struct net_device *dev_out = NULL; - unsigned hash; - int free_res = 0; int err; - tos &= IPTOS_TOS_MASK|RTO_ONLINK; key.dst = daddr; key.src = saddr; key.tos = tos&IPTOS_TOS_MASK; @@ -1619,252 +1792,100 @@ res.r = NULL; #endif - if (saddr) { - if (MULTICAST(saddr) || BADCLASS(saddr) || ZERONET(saddr)) - return -EINVAL; - - /* It is equivalent to inet_addr_type(saddr) == RTN_LOCAL */ - dev_out = ip_dev_find(saddr); - if (dev_out == NULL) - return -EINVAL; - - /* I removed check for oif == dev_out->oif here. - It was wrong by three reasons: - 1. ip_dev_find(saddr) can return wrong iface, if saddr is - assigned to multiple interfaces. - 2. Moreover, we are allowed to send packets with saddr - of another iface. --ANK - */ - - if (oif == 0 && - (MULTICAST(daddr) || daddr == 0xFFFFFFFF)) { - /* Special hack: user can direct multicasts - and limited broadcast via necessary interface - without fiddling with IP_MULTICAST_IF or IP_PKTINFO. - This hack is not just for fun, it allows - vic,vat and friends to work. - They bind socket to loopback, set ttl to zero - and expect that it will work. - From the viewpoint of routing cache they are broken, - because we are not allowed to build multicast path - with loopback source addr (look, routing cache - cannot know, that ttl is zero, so that packet - will not leave this host and route is valid). - Luckily, this hack is good workaround. - */ - - key.oif = dev_out->ifindex; - goto make_route; - } - if (dev_out) - dev_put(dev_out); - dev_out = NULL; - } - if (oif) { - dev_out = dev_get_by_index(oif); - if (dev_out == NULL) - return -ENODEV; - if (__in_dev_get(dev_out) == NULL) { - dev_put(dev_out); - return -ENODEV; /* Wrong error code */ - } - - if (LOCAL_MCAST(daddr) || daddr == 0xFFFFFFFF) { - if (!key.src) - key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK); - goto make_route; - } - if (!key.src) { - if (MULTICAST(daddr)) - key.src = inet_select_addr(dev_out, 0, key.scope); - else if (!daddr) - key.src = inet_select_addr(dev_out, 0, RT_SCOPE_HOST); - } - } + if (!daddr) + goto dest_insanity; - if (!key.dst) { - key.dst = key.src; - if (!key.dst) - key.dst = key.src = htonl(INADDR_LOOPBACK); - if (dev_out) - dev_put(dev_out); - dev_out = &loopback_dev; + err = fib_lookup(&key, &res); + if (!err) { + dev_out = FIB_RES_DEV(res); dev_hold(dev_out); - key.oif = loopback_dev.ifindex; - res.type = RTN_LOCAL; - flags |= RTCF_LOCAL; - goto make_route; - } - - if (fib_lookup(&key, &res)) { - res.fi = NULL; - if (oif) { - /* Apparently, routing tables are wrong. Assume, - that the destination is on link. - - WHY? DW. - Because we are allowed to send to iface - even if it has NO routes and NO assigned - addresses. When oif is specified, routing - tables are looked up with only one purpose: - to catch if destination is gatewayed, rather than - direct. Moreover, if MSG_DONTROUTE is set, - we send packet, ignoring both routing tables - and ifaddr state. --ANK - - - We could make it even if oif is unknown, - likely IPv6, but we do not. + if (saddr) { + /* Verify user supplied source address */ + err = outrt_check_src(saddr, daddr, tos, dev_out); + } else { + /* Obtain path source from routing table */ + saddr = FIB_RES_PREFSRC(res); + /* We don't verify source address obtained from routing + * table. It's a task of administrators to keep it + * sane. */ - - if (key.src == 0) - key.src = inet_select_addr(dev_out, 0, RT_SCOPE_LINK); - res.type = RTN_UNICAST; - goto make_route; } - if (dev_out) - dev_put(dev_out); - return -ENETUNREACH; - } - free_res = 1; - - if (res.type == RTN_NAT) - goto e_inval; - - if (res.type == RTN_LOCAL) { - if (!key.src) - key.src = key.dst; - if (dev_out) - dev_put(dev_out); - dev_out = &loopback_dev; - dev_hold(dev_out); - key.oif = dev_out->ifindex; - if (res.fi) - fib_info_put(res.fi); - res.fi = NULL; - flags |= RTCF_LOCAL; - goto make_route; - } - -#ifdef CONFIG_IP_ROUTE_MULTIPATH - if (res.fi->fib_nhs > 1 && key.oif == 0) - fib_select_multipath(&key, &res); - else -#endif - if (res.prefixlen==0 && res.type == RTN_UNICAST && key.oif == 0) - fib_select_default(&key, &res); - - if (!key.src) - key.src = FIB_RES_PREFSRC(res); - - if (dev_out) - dev_put(dev_out); - dev_out = FIB_RES_DEV(res); - dev_hold(dev_out); - key.oif = dev_out->ifindex; - -make_route: - if (LOOPBACK(key.src) && !(dev_out->flags&IFF_LOOPBACK)) - goto e_inval; - - if (key.dst == 0xFFFFFFFF) - res.type = RTN_BROADCAST; - else if (MULTICAST(key.dst)) - res.type = RTN_MULTICAST; - else if (BADCLASS(key.dst) || ZERONET(key.dst)) - goto e_inval; + if (!err) + err = outrt_make_route(rp, &key, daddr, saddr, + dev_out, &res); + fib_res_put(&res); + /* The usual code path ends here */ - if (dev_out->flags&IFF_LOOPBACK) - flags |= RTCF_LOCAL; + } else if (err == -ENETUNREACH) { - if (res.type == RTN_BROADCAST) { - flags |= RTCF_BROADCAST|RTCF_LOCAL; - if (res.fi) { - fib_info_put(res.fi); - res.fi = NULL; - } - } else if (res.type == RTN_MULTICAST) { - flags |= RTCF_MULTICAST|RTCF_LOCAL; - read_lock(&inetdev_lock); - if (!__in_dev_get(dev_out) || !ip_check_mc(__in_dev_get(dev_out), daddr)) - flags &= ~RTCF_LOCAL; - read_unlock(&inetdev_lock); - /* If multicast route do not exist use - default one, but do not gateway in this case. - Yes, it is hack. + /* Just return if the access is prohibited etc. + If the routing table doesn't have both an appropriate route + and a default assume that the destination is on link. --SAW + + WHY? DW. + Because we are allowed to send to iface + even if it has NO routes and NO assigned + addresses. When oif is specified, routing + tables are looked up with only one purpose: + to catch if destination is gatewayed, rather than + direct. Moreover, if MSG_DONTROUTE is set, + we send packet, ignoring both routing tables + and ifaddr state. --ANK + + We could make it even if oif is unknown, + likely IPv6, but we do not. + + The above statements aren't exactly correct. + Routing tables contain a lot of useful information (like + preferred source, for instance). But the general idea is + right. --SAW */ - if (res.fi && res.prefixlen < 4) { - fib_info_put(res.fi); - res.fi = NULL; - } - } - - rth = dst_alloc(&ipv4_dst_ops); - if (!rth) - goto e_nobufs; - - atomic_set(&rth->u.dst.__refcnt, 1); - rth->u.dst.flags= DST_HOST; - rth->key.dst = daddr; - rth->key.tos = tos; - rth->key.src = saddr; - rth->key.iif = 0; - rth->key.oif = oif; - rth->rt_dst = key.dst; - rth->rt_src = key.src; -#ifdef CONFIG_IP_ROUTE_NAT - rth->rt_dst_map = key.dst; - rth->rt_src_map = key.src; -#endif - rth->rt_iif = oif ? : dev_out->ifindex; - rth->u.dst.dev = dev_out; - dev_hold(dev_out); - rth->rt_gateway = key.dst; - rth->rt_spec_dst= key.src; - - rth->u.dst.output=ip_output; - - if (flags&RTCF_LOCAL) { - rth->u.dst.input = ip_local_deliver; - rth->rt_spec_dst = key.dst; - } - if (flags&(RTCF_BROADCAST|RTCF_MULTICAST)) { - rth->rt_spec_dst = key.src; - if (flags&RTCF_LOCAL && !(dev_out->flags&IFF_LOOPBACK)) - rth->u.dst.output = ip_mc_output; -#ifdef CONFIG_IP_MROUTE - if (res.type == RTN_MULTICAST) { - struct in_device *in_dev = in_dev_get(dev_out); - if (in_dev) { - if (IN_DEV_MFORWARD(in_dev) && !LOCAL_MCAST(daddr)) { - rth->u.dst.input = ip_mr_input; - rth->u.dst.output = ip_mc_output; - } - in_dev_put(in_dev); + if (oif) { + err = -ENODEV; + dev_out = dev_get_by_index(oif); + if (dev_out == NULL) + goto out; + if (__in_dev_get(dev_out) == NULL) + goto out; /* Wrong error code */ + if (saddr) { + /* Verify user supplied source address */ + err = outrt_check_src(saddr, daddr, tos, dev_out); + if (err) + goto out; + } else { + int scope; + if (LOCAL_MCAST(daddr) || daddr == 0xFFFFFFFF) + scope = RT_SCOPE_LINK; + else if (MULTICAST(daddr)) + scope = key.scope; + else + scope = RT_SCOPE_HOST; + saddr = inet_select_addr(dev_out, 0, scope); } - } -#endif + res.type = RTN_UNICAST; + res.fi = NULL; + err = outrt_make_route(rp, &key, daddr, saddr, dev_out, + &res); + } else + err = -ENETUNREACH; } - - rt_set_nexthop(rth, &res, 0); - - rth->rt_flags = flags; - - hash = rt_hash_code(daddr, saddr^(oif<<5), tos); - err = rt_intern_hash(hash, rth, rp); -done: - if (free_res) - fib_res_put(&res); +out: if (dev_out) dev_put(dev_out); return err; -e_inval: - err = -EINVAL; - goto done; -e_nobufs: - err = -ENOBUFS; - goto done; + /* I don't know what reason this hack was for */ +dest_insanity: + daddr = saddr; + if (!daddr) + daddr = saddr = htonl(INADDR_LOOPBACK); + dev_out = &loopback_dev; + dev_hold(dev_out); + key.oif = loopback_dev.ifindex; + res.type = RTN_LOCAL; + res.fi = NULL; + err = outrt_make_route(rp, &key, daddr, saddr, dev_out, &res); + goto out; } int ip_route_output(struct rtable **rp, u32 daddr, u32 saddr, u32 tos, int oif) vrrpd-1.0/scott_example0000644000175000017500000000006107537132541014673 0ustar jfsjfs00000000000000vrrpd -i eth0 -v 1 -n 12.12.199.1 172.16.117.150 vrrpd-1.0/vrrpd.80000644000175000017500000000456707537132541013346 0ustar jfsjfs00000000000000.\" -*- nroff -*- .TH VRRPD 8 "September 2000" "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 .SH DESCRIPTION vrrpd is an implementation of VRRPv2 as specified in rfc2338. It run in userspace for linux. In short, VRRP is a protocol which elects a master server on a LAN and 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 : "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 LAN. The VRRP router controlling the IP address(es) associated with a virtual router is called the Master, and forwards packets sent to these IP addresses. The election process provides dynamic fail over in the forwarding responsibility should the Master become unavailable. This allows any of the virtual router IP addresses on the LAN to be used as the default first hop router by end-hosts. The advantage gained from using VRRP is a higher availability default path without requiring configuration of dynamic routing or router discovery protocols on every end-host." Copyright (C) The Internet Society (1998). All Rights Reserved. .SS OPTIONS .TP .I "-h" display this short inlined help .TP .I "-n" Dont handle the virtual mac address .TP .I "-i ifname" the interface name to run on .TP .I "-v vrid" the id of the virtual server [1-255] .TP .I "-s" Switch the preemption mode (Enabled by default) .TP .I "-a auth" (not yet implemented) 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. .TP .I "-p prio" Set the priority of this host in the virtual server (dfl: 100) .TP .I "-f piddir" specify the directory where the pid file is stored (dfl: /var/run) .TP .I "-d delay" Set the advertisement interval (in sec) (dfl: 1) .TP .I "ipaddr" the ip address(es) of the virtual server .SH EXAMPLES vrrpd -i eth0 -v 50 10.0.0.1 run vrrp on the interface eth0 with the virtual id 50 and 10.0.0.1 as virtual ip address .SH AUTHOR .B vrrpd was written by Jerome Etienne .SH BUGS If you find bugs, tell me. vrrpd-1.0/vrrpd.c0000644000175000017500000010614607537132541013415 0ustar jfsjfs00000000000000/*==========================[ (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. ==============================================================================*/ /* system include */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* 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]; /**************************************************************** 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; } /**************************************************************** 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); } /**************************************************************** NAME : pidfile_rm 00/10/04 21:12:26 AIM : REMARK : ****************************************************************/ static void pidfile_rm( vrrp_rt *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 : ****************************************************************/ 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; } /**************************************************************** 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); } /**************************************************************** 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; } /**************************************************************** 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; } /**************************************************************** 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; } /**************************************************************** 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; end:; if( ret ) printf("error errno=%d\n",errno); close(fd); return ret; } /**************************************************************** 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 ); //printf("%x:%x:%x:%x:%x:%x\n", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5] ); close(fd); return ret; } /**************************************************************** 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; } /**************************************************************** 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 */ } /**************************************************************** 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 ); } /**************************************************************** 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; } /**************************************************************** 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 ****************************************************************/ 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 ); } /**************************************************************** NAME : vrrp_build_ip 00/02/02 14:39:18 AIM : build a ip packet REMARK : ****************************************************************/ 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 ); } /**************************************************************** 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); } /**************************************************************** NAME : vrrp_set_ptk 00/02/02 13:33:32 AIM : build a advertissement packet REMARK : ****************************************************************/ 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 ); } /**************************************************************** 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 */ // 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; } /**************************************************************** NAME : vrrp_send_adv 00/02/06 16:31:24 AIM : REMARK : ****************************************************************/ 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) ); #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; } /**************************************************************** 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" ); } /**************************************************************** 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; err:; usage(); return -1; } /**************************************************************** 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; } /**************************************************************** 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; } /**************************************************************** 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); } /**************************************************************** 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; } /**************************************************************** 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 ) { struct m_arphdr { unsigned short int ar_hrd; /* Format of hardware address. */ unsigned short int ar_pro; /* Format of protocol address. */ unsigned char ar_hln; /* Length of hardware address. */ unsigned char ar_pln; /* Length of protocol address. */ unsigned short int ar_op; /* ARP opcode (command). */ /* Ethernet looks like this : This bit is variable sized however... */ unsigned char __ar_sha[ETH_ALEN]; /* Sender hardware address. */ unsigned char __ar_sip[4]; /* Sender IP address. */ unsigned char __ar_tha[ETH_ALEN]; /* Target hardware address. */ unsigned char __ar_tip[4]; /* Target IP address. */ }; char buf[sizeof(struct m_arphdr)+ETHER_HDR_LEN]; char buflen = sizeof(struct m_arphdr)+ETHER_HDR_LEN; struct ether_header *eth = (struct ether_header *)buf; struct m_arphdr *arph = (struct m_arphdr *)(buf+vrrp_dlt_len(vsrv)); char *hwaddr = vAddrF ? 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 ); } /**************************************************************** NAME : state_gotomaster 00/02/07 00:15:26 AIM : REMARK : called when the state is now MASTER ****************************************************************/ 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 void state_goto_master( vrrp_rt *vsrv ) { int i; vrrp_if *vif = &vsrv->vif; /* 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 ****************************************************************/ static void state_leave_master( vrrp_rt *vsrv, int advF ) { uint32_t addr[1024]; vrrp_if *vif = &vsrv->vif; /* 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 ****************************************************************/ 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, " : ""); } } /**************************************************************** NAME : state_back 00/02/07 00:15:26 AIM : REMARK : rfc2338.6.4.2 ****************************************************************/ 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 ); } } /**************************************************************** NAME : state_mast 00/02/07 00:15:26 AIM : REMARK : rfc2338.6.4.3 ****************************************************************/ 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); 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, " : ""); } } /**************************************************************** NAME : open_sock 00/02/07 12:40:00 AIM : open the socket and join the multicast group. REMARK : ****************************************************************/ 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; } /**************************************************************** NAME : signal_end 00/05/10 23:20:36 AIM : REMARK : ****************************************************************/ static void signal_end( int nosig ) { 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 ); } /**************************************************************** NAME : signal_user 00/05/10 23:20:36 AIM : REMARK : ****************************************************************/ static void signal_user( int nosig ) { 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 ); } /**************************************************************** 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); #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; } } return(0); } vrrpd-1.0/vrrpd.h0000644000175000017500000001203507537132541013413 0ustar jfsjfs00000000000000/*==========================[ (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. ==============================================================================*/ #ifndef __VRRP_H__ #define __VRRP_H__ /* system include */ #include #define VRRPD_VERSION "0.4" /* Scott added 9-4-02 */ #include #define vrrpd_log syslog /* local include */ typedef struct { /* rfc2338.5.1 */ uint8_t vers_type; /* 0-3=type, 4-7=version */ uint8_t vrid; /* virtual router id */ uint8_t priority; /* router priority */ uint8_t naddr; /* address counter */ uint8_t auth_type; /* authentification type */ uint8_t adver_int; /* advertissement interval(in sec) */ uint16_t chksum; /* checksum (ip-like one) */ /* here ip addresses */ /* here authentification infos */ } vrrp_pkt; /* protocol constants */ #define INADDR_VRRP_GROUP 0xe0000012 /* multicast addr - rfc2338.5.2.2 */ #define VRRP_IP_TTL 255 /* in and out pkt ttl -- rfc2338.5.2.3 */ #define IPPROTO_VRRP 112 /* IP protocol number -- rfc2338.5.2.4*/ #define VRRP_VERSION 2 /* current version -- rfc2338.5.3.1 */ #define VRRP_PKT_ADVERT 1 /* packet type -- rfc2338.5.3.2 */ #define VRRP_PRIO_OWNER 255 /* priority of the ip owner -- rfc2338.5.3.4 */ #define VRRP_PRIO_DFL 100 /* default priority -- rfc2338.5.3.4 */ #define VRRP_PRIO_STOP 0 /* priority to stop -- rfc2338.5.3.4 */ #define VRRP_AUTH_NONE 0 /* no authentification -- rfc2338.5.3.6 */ #define VRRP_AUTH_PASS 1 /* password authentification -- rfc2338.5.3.6 */ #define VRRP_AUTH_AH 2 /* AH(IPSec) authentification - rfc2338.5.3.6 */ #define VRRP_ADVER_DFL 1 /* advert. interval (in sec) -- rfc2338.5.3.7 */ #define VRRP_PREEMPT_DFL 1 /* rfc2338.6.1.2.Preempt_Mode */ /* 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 */ typedef struct { /* parameters per interface -- rfc2338.6.1.1 */ int auth_type; /* authentification type. VRRP_AUTH_* */ uint8_t auth_data[8]; /* authentification data */ uint32_t ipaddr; /* the address of the interface */ char hwaddr[6]; /* WORK: lame hardcoded for ethernet !!!! */ char *ifname; /* the device name for this ipaddr */ } vrrp_if; typedef struct { uint32_t addr; /* the ip address */ int deletable; /* TRUE if one of my primary addr */ } vip_addr; typedef struct { /* parameters per virtual router -- rfc2338.6.1.2 */ int vrid; /* virtual id. from 1(!) to 255 */ int priority; /* priority value */ int naddr; /* number of ip addresses */ vip_addr *vaddr; /* point on the ip address array */ int adver_int; /* delay between advertisements(in sec) */ #if 0 /* dynamically calculated */ double skew_time; /* skew Master_Down_Interval. (256-Prio)/256 */ int mast_down_int; /* interval for backup to declare master down*/ #endif int preempt; /* true if a higher prio preempt a lower one */ int state; /* internal state (init/backup/master) */ int wantstate; /* user explicitly wants a state (back/mast) */ int sockfd; /* the socket descriptor */ int initF; /* true if the struct is init */ int no_vmac; /* dont handle the virtual MAC --rfc2338.7.3 */ /* rfc2336.6.2 */ uint32_t ms_down_timer; uint32_t adver_timer; vrrp_if vif; } vrrp_rt; /* VRRP state machine -- rfc2338.6.4 */ #define VRRP_STATE_INIT 1 /* rfc2338.6.4.1 */ #define VRRP_STATE_BACK 2 /* rfc2338.6.4.2 */ #define VRRP_STATE_MAST 3 /* rfc2338.6.4.3 */ #define VRRP_STATE_NONE 99 /* internal */ #define VRRP_LOG( str ) printf str #define VRRP_AUTH_LEN 8 #define VRRP_IS_BAD_VID(id) ((id)<1 || (id)>255) /* rfc2338.6.1.vrid */ #define VRRP_IS_BAD_PRIORITY(p) ((p)<1 || (p)>255) /* rfc2338.6.1.prio */ #define VRRP_IS_BAD_ADVERT_INT(d) ((d)<1) /* 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 */ #define VRRP_TIMER_SET( val, delta ) (val) = VRRP_TIMER_CLK() + (delta) #define VRRP_TIMER_SUB( t1, t2 ) ((int32_t)(((uint32_t)t1)-((uint32_t)t2))) #define VRRP_TIMER_DELTA( val ) VRRP_TIMER_SUB( val, VRRP_TIMER_CLK() ) #define VRRP_TIMER_EXPIRED( val ) ((val) && VRRP_TIMER_DELTA(val)<=0) #define VRRP_TIMER_CLR( val ) (val) = 0 #define VRRP_TIMER_IS_RUNNING( val ) (val) #define VRRP_TIMER_HZ 1000000 uint32_t VRRP_TIMER_CLK( void ) { struct timeval tv; gettimeofday(&tv, NULL ); 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) ) #define VRRP_MAX( a , b ) ( (a) > (b) ? (a) : (b) ) #endif /* __VRRP_H__ */