📄 vrrpd.c
字号:
/*==========================[ (c) JME SOFT ]===================================FILE : [vrrp.c]CREATED : 00/02/02 12:54:37 LAST SAVE : 00/10/04 22:11:39WHO : jerome@mycpu Linux 2.2.14REMARK :================================================================================- 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 <stdio.h>#include <assert.h>#include <net/ethernet.h>#include <netinet/ip.h>#include <stdlib.h>#include <unistd.h>#include <signal.h>#include <string.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/time.h>#include <netinet/in.h>#include <arpa/inet.h>#include <time.h>#include <sys/errno.h>#include <net/if.h>#include <net/if_arp.h>#include <net/ethernet.h>#include <sys/ioctl.h>#include <ctype.h>#include <string.h>/* 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 ethernetstatic vrrp_rt glob_vsrv; /* a global because used in the signal handler*/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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -