#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> #include <netdb.h> #include <sys/stat.h> #include <fcntl.h> #include <termios.h> #include <errno.h> #include <pthread.h> #include <sys/param.h> #include "grpAddr.h" //#include "ipaddr.h" #define _POSIX_SOURCE 1 /* POSIX compliant source */ #define BAUDRATE B38400//B115200 #define MODEMDEVICE "/dev/ttyS0" #define BROADCAST 0xffff #define BROADCASTON 0xfffd #define BROADCASTCR 0xfffc #define GETSRC_MAC 0x00 #define GETPANID 0x01 #define GETSERVER 0x02 #define UNICAST 0x10 #define GROUPCAST 0x11 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; static char PidDir[FILENAME_MAX+1]; int failure = 0; int failCount; /*============================================================== return IP address by ifname ==============================================================*/ 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; } /*============================================================== copy hardware address to addr by ifname ==============================================================*/ 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; } /*************************************************************** authentication ***************************************************************/ 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 */ }else if( !strncmp(str, "pw/0x", 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<len ;i++,j++ ){ /* sanity check */ if( !isxdigit(str[i]) ) return -1; str[i] = toupper(str[i]); if( str[i] >= 'A' ) str[i] -= 'A' - 10; else str[i] -= '0'; vif->auth_data[j/2] |= str[i] << (j&1 ? 0 : 4 ); //WORK: printf(" j=%d c=%d 0x%x\n",j,str[i],vif->auth_data[j/2]); } if( i != len ) return -1; }else{ return -1; } return(0); } /*============================================================== display the usage ==============================================================*/ 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, "Usage: vrrpd -i ifname -v vrid [-f piddir] [-s] [-a auth] [-p prio] [-nh]\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" ); } /*============================================================== parse the command line ================================================================================================*/ 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" ); c = getopt( argc, argv, "f:si:v:a:p:d:h" ); /* 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 by ifname*/ vif->ipaddr = ifname_to_ip( optarg ); if( !vif->ipaddr ){ fprintf( stderr, "no interface found!\n" ); goto err; } /* get the hwaddr by vif->ifname and fill it in vif->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; } /*============================================================== ==============================================================*/ 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) );*/ vsrv->vaddr = realloc( vsrv->vaddr , sizeof(*vsrv->vaddr) ); } else { vsrv->vaddr = malloc( sizeof(*vsrv->vaddr) ); } assert( vsrv->vaddr ); /* store the data vsrv->vaddr[vsrv->naddr-1].addr = ipaddr; vsrv->vaddr[vsrv->naddr-1].deletable = 0;*/ vsrv->vaddr[0].addr = ipaddr; vsrv->vaddr[0].deletable = 0; } /*============================================================== TRUE if the minimal configuration isnt done ==============================================================*/ 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); } /*============================================================== open the socket and join the multicast group. ==============================================================*/ 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; } /************************************************************************** ***************************************************************/ static char *pidfile_get_name( vrrp_rt *vsrv ) { static char pidfile[FILENAME_MAX+1]; snprintf( pidfile, sizeof(pidfile), "%s/" VRRP_PID_FORMAT , PidDir , vsrv->vif.ifname , vsrv->vrid ); return pidfile; } /*************************************************************** ***************************************************************/ static void pidfile_rm( vrrp_rt *vsrv ) { unlink( pidfile_get_name(vsrv) ); } /*************************************************************** return 0 if there is no valid pid in the pidfile or no pidfile *********************************************************************************************/ 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; } /*************************************************************** ***************************************************************/ 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); } /*================================================================= ============================================================== 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; }*/ /*============================================================== let virtual IP address be associative with the interface ===================================================================== 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; }*/ /*================================================================= ==============================================================*/ static int vrrp_dlt_len( vrrp_rt *rt ) { return ETHER_HDR_LEN; /* hardcoded for ethernet */ } /*============================================================== ==============================================================*/ static int vrrp_iphdr_len( vrrp_rt *vsrv ) { return sizeof( struct iphdr ); } /*============================================================== ==============================================================*/ static int vrrp_hd_len( vrrp_rt *vsrv ) { return sizeof( vrrp_pkt ) + sizeof(uint32_t) + VRRP_AUTH_LEN; /*return sizeof( vrrp_pkt ) + vsrv->naddr*sizeof(uint32_t) + VRRP_AUTH_LEN;*/ } /*============================================================== ==============================================================*/ 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 ); } /*============================================================== ==============================================================*/ 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); } /*============================================================== ==============================================================*/ 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 ); } /*============================================================== ==============================================================*/ 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[0] = htonl( vsrv->vaddr[0].addr ); //} hd->chksum = in_csum( (u_short*)hd, vrrp_hd_len(vsrv), 0); /* copy the passwd if the authentication is VRRP_AH_PASS */ if( vif->auth_type == VRRP_AUTH_PASS ){ //char *pw = (char *)hd+sizeof(*hd)+vsrv->naddr*4; char *pw = (char *)hd+sizeof(*hd)+4; memcpy( pw, vif->auth_data, sizeof(vif->auth_data)); } return(0); } /*============================================================== ==============================================================*/ 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 ); } /*============================================================== ==============================================================*/ 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) ); /* sendto prototype: ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr, socklen_t dest_len); */ //printf("len=%d\n",len); close( fd ); return len; } /*============================================================== ======================================================================*/ 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 */ if (!failure) ret = vrrp_send_pkt( vsrv, buffer, buflen ); /* build the memory */ free( buffer ); return ret; } /*************************************************************** ************************************************************** 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 ); }*/ /*============================================================== =====================================================================*/ 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; } /*============================================================== =====================================================================================*/ static void state_init( vrrp_rt *vsrv ) { if( vsrv->priority == VRRP_PRIO_OWNER || vsrv->wantstate == VRRP_STATE_MAST ){ state_goto_master( vsrv ); } else { // RFC 5798 here: Set Master_Adver_Interval to Advertisement_Interval ? int delay = 3*vsrv->adver_int;// + VRRP_TIMER_SKEW(vsrv); //Master_Down_Interval VRRP_TIMER_SET( vsrv->ms_down_timer, delay ); vsrv->state = VRRP_STATE_BACK; } } /*============================================================== check incoming packets ==============================================================*/ 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; } return 0; } /*************************************************************** ***************************************************************/ 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; } /*============================================================== ==============================================================*/ 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, 0);//VRRP_TIMER_SKEW(vsrv) ); state_goto_master( vsrv ); } else if( !vsrv->preempt || hd->priority >= vsrv->priority ) { int delay = 3*vsrv->adver_int;// + VRRP_TIMER_SKEW(vsrv); //Master_Down_Interval VRRP_TIMER_SET( vsrv->ms_down_timer, delay ); } } /*============================================================== ==============================================================*/ 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 ); }*/ } /*============================================================== ==============================================================*/ 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); //Master_Down_Interval 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; } } /*************************************************************** ***************************************************************/ 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 ); } /*************************************************************** ***************************************************************/ 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 ); } int ufd; int sock; struct sockaddr_in s_sa; struct sockaddr_in r_sa; //void signal_handler_IO (int status); /* definition of signal handler */ int wait_flag=1; struct ip_mreq r_ma; int mSock; void *recv_thread(void); void *send_thread(void); /*============================================================== signal handler. set wait_flag to 0 to indicate data have been received. ==============================================================*/ void signal_handler_IO (int status) { //printf("received SIGIO signal: %d.\n", status); wait_flag = 0; } int rate1; int rate2; int fCount; /*================================================================================================== main function ==================================================================================================*/ int main( int argc, char *argv[] ) { //rate = atoi(argv[argc]); //printf("rate:%d argc:%s\n", rate, argv[argc]); fCount = atoi(argv[argc-3]); rate1 = atoi(argv[argc-2]); rate2 = atoi(argv[argc-1]); // printf("rate1=%d , argc-2: %d\n", rate1, argv[argc-2]); // printf("rate2=%d , argc-1: %d\n", rate2, argv[argc-1]); printf("rate=%d/%d \n", rate2, rate1); 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 memset( vsrv, 0, sizeof(*vsrv) ); vsrv->state = VRRP_STATE_INIT; vsrv->priority = VRRP_PRIO_DFL; vsrv->adver_int = VRRP_ADVER_DFL*VRRP_TIMER_HZ; vsrv->preempt = VRRP_PREEMPT_DFL; vsrv->no_vmac = 1; //GroupAddress uses no virtual MAC //vif->ipaddr /* 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) ); }*/ vsrv->naddr=0; uint32_t ipaddr=0; 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 ); ////////////////////////////read data from UART///////////////////////////// struct termios oldtio, newtio; struct sigaction saio; /* definition of signal action */ sigset_t sigset; //printf("Start...\n"); /* �}��PC��COM2�q�T�� O_RDWR: �iŪ�g���äD���}���� O_NOCTTY:�i�Dlinux�A�o�ӵ{�����Q����tty�ɭ��A�p�G���]�o�ӺX�� ���ǿ��J(�p���Labort�H��)�|�v�T���{���C */ ufd=open(MODEMDEVICE, O_RDWR | O_NOCTTY | O_NONBLOCK); if(ufd<0) { perror(MODEMDEVICE); exit(1); } //printf("Open...\n"); /* install the signal handler before making the device asynchronous */ saio.sa_handler = signal_handler_IO; sigemptyset(&sigset); saio.sa_mask = sigset; saio.sa_flags = 0; saio.sa_restorer = NULL; sigaction(SIGIO,&saio,NULL); /* allow the process to receive SIGIO */ fcntl(ufd, F_SETOWN, getpid()); /* Make the file descriptor asynchronous (the manual page says only O_APPEND and O_NONBLOCK, will work with F_SETFL...) */ fcntl(ufd, F_SETFL, FASYNC); tcgetattr(ufd,&oldtio); //�N�ثe�ݾ��ѼƦs��oldtio���c bzero(&newtio,sizeof(newtio));//�M��newtio���c�A���s�]�w�q�T���w /* �q�T���w�]��8N1 */ newtio.c_cflag = BAUDRATE|CS8|CLOCAL|CREAD; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; newtio.c_lflag = 0;//ICANON; //�]�����W�Ҧ� newtio.c_cc[VMIN]=5; newtio.c_cc[VTIME]=1; tcflush(ufd,TCIFLUSH); /* �s��termios���c�@���q�T�𪺰Ѽ� */ tcsetattr(ufd,TCSANOW,&newtio); //printf("Reading....\n"); /////////////////////////////////socket///////////////////////////////// sock = socket(PF_INET, SOCK_DGRAM, 0); if (-1 == sock) /* if socket failed to initialize, exit */ { printf("Error Creating Socket"); exit(EXIT_FAILURE); } bzero(&s_sa, sizeof(s_sa)); s_sa.sin_family = AF_INET; s_sa.sin_port = htons(17654); inet_pton(AF_INET, argv[9], &s_sa.sin_addr); //MULTICAST int mRet; mSock = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ); if( mSock < 0 ){ printf("cant open raw socket. errno=%d. (try to run it as root)\n", errno); return -1; } int reuse = 1; if (setsockopt(mSock, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) { fprintf(stderr, "setsockopt: %d\n", errno); return 1; } bzero(&r_sa, sizeof(r_sa)); r_sa.sin_family = AF_INET; r_sa.sin_port = htons(17654); r_sa.sin_addr.s_addr = htonl(INADDR_ANY); //inet_pton(AF_INET, "239.255.255.1", &r_sa.sin_addr); if (-1 == bind(mSock,(struct sockaddr *)&r_sa, sizeof(r_sa))) { perror("error bind failed"); close(mSock); exit(EXIT_FAILURE); } memset( &r_ma, 0, sizeof (r_ma)); // r_ma.imr_multiaddr.s_addr = htonl(0xe0000101); r_ma.imr_multiaddr.s_addr = inet_addr("224.0.0.200"); r_ma.imr_interface.s_addr = htonl(vsrv->vif.ipaddr); // join a multicast group mRet = setsockopt (mSock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &r_ma, sizeof (struct ip_mreq)); if( mRet < 0 ){ printf("cant do IP_ADD_MEMBERSHIP errno=%d\n",errno); return -1; } int tRes; pthread_t rThread; pthread_t sThread; tRes = pthread_create(&rThread, NULL, recv_thread, NULL); if (tRes != 0){ perror("Thread creation failed"); exit(EXIT_FAILURE); } tRes = pthread_create(&sThread, NULL, send_thread, NULL); if (tRes != 0){ perror("Thread creation failed"); exit(EXIT_FAILURE); } /* main loop */ while( 1 ){ switch( vsrv->state ){ case VRRP_STATE_INIT: state_init( vsrv ); break;//printf("init\n"); break; case VRRP_STATE_BACK: state_back( vsrv ); break;//printf("backup\n"); break; case VRRP_STATE_MAST: state_mast( vsrv ); break;//printf("master\n"); break; } //if(uBuf[0]=='/')break; } close(sock); /* close the socket */ close(mSock); close(ufd); /* �^�s�ª��q�T���Ѽ� */ tcsetattr(ufd,TCSANOW,&oldtio); return(0); } /*============================================================== socket thread ==============================================================*/ void *recv_thread() { vrrp_rt *vsrv; unsigned char sbuffer[256]; int uart_write, sock_recv; socklen_t fromlen; int i; while(1){ sock_recv = recvfrom(mSock, (void *)sbuffer, 256, 0, (struct sockaddr *)&r_sa, &fromlen); //sock_recv = read(mSock, sbuffer, 256 ); if (sock_recv < 0) fprintf(stderr, "%s\n", strerror(errno)); else{ printf("Receive from Server: \nlength=%d data= ", sock_recv); for (i=0;i<sock_recv;i++) printf("%c", sbuffer[i]); printf("\n"); vsrv = &glob_vsrv; if(vsrv->state==VRRP_STATE_MAST){ uart_write = write(ufd, sbuffer , sock_recv); printf("***The active translator has sent data to ZigBee device.\n"); } } } if (sock_recv < 0) fprintf(stderr, "%s\n", strerror(errno)); } /*============================================================== socket thread ==============================================================*/ void *send_thread() { vrrp_rt *vsrv; unsigned char uBuf[256]; int uart_read; int i; int recv=0; srand(time(NULL)); while(1){ if(wait_flag==0) { recv++; if(recv%100==1) failure=0; uart_read=read(ufd,uBuf,255); uBuf[uart_read]=0; //printf("Receive from ZigBee device: \nlength=%d data= ", uart_read); //for (i=0;i<uart_read;i++) printf("%x ",uBuf[i]); //printf("\n"); //printf("sequence:%d\n", uBuf[uart_read-1]*16+uBuf[uart_read-2]); printf("sequence:%d\n", uBuf[uart_read-1]); if(!failure) { if( rand()%rate1 < rate2 ) { failure = 1; failCount = fCount; printf("fail\n"); } else{ vsrv = &glob_vsrv; if(vsrv->state==VRRP_STATE_MAST) { if(sendto(sock, uBuf, uart_read, 0,(struct sockaddr*)&s_sa, sizeof(s_sa)) <0) printf("Error sending packet: %s\n", strerror(errno)); else printf("***The active translator has sent data to server.\n"); } } } else if (failCount == 0){ failure=0; printf("come back\n"); } else failCount--; if(recv==1000) exit(1); wait_flag = 1; } } }