📄 vrrpd.c
字号:
{ 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****************************************************************/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;}/**************************************************************** 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; }}/**************************************************************** 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; }}/**************************************************************** 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 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);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -