Annotation of embedaddon/freevrrpd/vrrp_network.c, revision 1.1

1.1     ! misho       1: /*
        !             2:  * Copyright (c) 2001,2002 Sebastien Petit <spe@bsdfr.org>
        !             3:  *
        !             4:  * Redistribution and use in source forms, with and without modification,
        !             5:  * are permitted provided that the following conditions are met:
        !             6:  * 1. Redistributions of source code must retain the above copyright notice,
        !             7:  *    this list of conditions and the following disclaimer.
        !             8:  * 2. Redistributions in binary form must reproduce the above copyright notice,
        !             9:  *    this list of conditions and the following disclaimer in the documentation
        !            10:  *    and/or other materials provided with the distribution. Obviously, it
        !            11:  *    would be nice if you gave credit where credit is due but requiring it
        !            12:  *    would be too onerous.
        !            13:  * 3. All advertising materials mentioning features or use of this software
        !            14:  *    must display the following acknowledgement:
        !            15:  *      This product includes software developed by Sebastien Petit.
        !            16:  * 4. Neither the name of its contributors may be used to endorse or promote
        !            17:  *    products derived from this software without specific prior written
        !            18:  *    permission.
        !            19:  *
        !            20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            30:  * SUCH DAMAGE.
        !            31:  *
        !            32:  * $Id: vrrp_network.c,v 1.27 2004/04/04 19:45:46 rival Exp $
        !            33:  */
        !            34: 
        !            35: #include <errno.h>
        !            36: #include <sys/param.h>
        !            37: #include "vrrp_network.h"
        !            38: #include "vrrp_ah.h"
        !            39: 
        !            40: u_short         ip_id;
        !            41: 
        !            42: /* Initialisation pour l'identification IP */
        !            43: void 
        !            44: vrrp_network_initialize(void)
        !            45: {
        !            46:        srand(time(NULL));
        !            47:        ip_id = random() % 65535;
        !            48: 
        !            49:        return;
        !            50: }
        !            51: 
        !            52: /* Open VRRP socket for reading */
        !            53: char 
        !            54: vrrp_network_open_socket(struct vrrp_vr * vr)
        !            55: {
        !            56:        struct timeval timeout;
        !            57:        int hincl = 1;
        !            58: 
        !            59:        vr->sd = socket(AF_INET, SOCK_RAW, IPPROTO_VRRP);
        !            60:        if (vr->sd == -1) {
        !            61:                syslog(LOG_ERR, "cannot open raw socket for VRRP protocol [ AF_INET, SOCK_RAW, IPPROTO_VRRP ]: %s", strerror(errno));
        !            62:                return -1;
        !            63:        }
        !            64:        if (setsockopt(vr->sd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl))) {
        !            65:                syslog(LOG_ERR, "cannot set IP_HDRINCL option on the IPPROTO_IP raw socket: %s", strerror(errno));
        !            66:                return -1;
        !            67:        }
        !            68:        timeout.tv_sec  = 0;
        !            69:        timeout.tv_usec = 100000;
        !            70:        if (setsockopt(vr->sd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) == -1) {
        !            71:                syslog(LOG_ERR, "cannot set SO_RCVTIMEO option on the IPPROTO_VRRP raw socket: %s", strerror(errno));
        !            72:                return -1;
        !            73:        }
        !            74: 
        !            75:        return 0;
        !            76: }
        !            77: 
        !            78: ssize_t
        !            79: vrrp_network_send_packet(char *buffer, int sizebuf, int sd, int log)
        !            80: {
        !            81:        struct sockaddr_in addr;
        !            82:        ssize_t          octets;
        !            83: 
        !            84:        addr.sin_family = AF_INET;
        !            85:        addr.sin_port = 0;
        !            86:        addr.sin_len = sizeof(struct sockaddr_in);
        !            87:        addr.sin_addr.s_addr = inet_addr(VRRP_MULTICAST_IP);
        !            88:        octets = sendto(sd, buffer, sizebuf, 0, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));
        !            89:        if (octets < 0) {
        !            90:                if (log)
        !            91:                        syslog(LOG_ERR, "can't write to socket: %s", strerror(errno));
        !            92:                return -1;
        !            93:        }
        !            94: 
        !            95:        return octets;
        !            96: }
        !            97: 
        !            98: u_int 
        !            99: vrrp_network_vrrphdr_len(struct vrrp_vr * vr)
        !           100: {
        !           101:        u_int           len = sizeof(struct vrrp_hdr);
        !           102: 
        !           103:        len += (vr->cnt_ip << 2) + VRRP_AUTH_DATA_LEN;
        !           104: 
        !           105:        return len;
        !           106: }
        !           107: 
        !           108: void    
        !           109: vrrp_network_init_iphdr(char *buffer, struct vrrp_vr * vr)      
        !           110: {       
        !           111:         struct ip      *iph = (struct ip *)buffer;      
        !           112:         
        !           113:         iph->ip_hl = 5;
        !           114:         iph->ip_v = 4;
        !           115:         iph->ip_tos = 0;
        !           116: #if (defined(__FreeBSD__) && (__FreeBSD_version < 1100030)) || defined(__NetBSD__)
        !           117:         iph->ip_len = sizeof(struct ip) + vrrp_network_vrrphdr_len(vr) + vrrp_ah_ahhdr_len(vr);
        !           118: #else
        !           119:         iph->ip_len = htons(sizeof(struct ip) + vrrp_network_vrrphdr_len(vr) + vrrp_ah_ahhdr_len(vr));
        !           120: #endif
        !           121:         /* iph->ip_id = ++ip_id; */
        !           122:         iph->ip_off = 0;
        !           123:         iph->ip_ttl = VRRP_MULTICAST_TTL;
        !           124: #ifdef ENABLE_VRRP_AH
        !           125:         if (vr->AHencryption == 1)
        !           126:             iph->ip_p = IPPROTO_AH;
        !           127:         else
        !           128:             iph->ip_p = IPPROTO_VRRP;
        !           129: #else
        !           130:         iph->ip_p = IPPROTO_VRRP;
        !           131: #endif
        !           132:         iph->ip_src.s_addr = vr->vr_if->ip_addrs[0].s_addr;
        !           133:         iph->ip_dst.s_addr = inet_addr(VRRP_MULTICAST_IP);
        !           134:         iph->ip_sum = vrrp_misc_compute_checksum((u_short *) iph, iph->ip_hl << 2);
        !           135:         
        !           136:        return;
        !           137: }
        !           138: 
        !           139: void 
        !           140: vrrp_network_init_vrrphdr(char *buffer, struct vrrp_vr * vr)
        !           141: {
        !           142:        struct vrrp_hdr *vp;
        !           143:        struct in_addr *addr;
        !           144:        char           *password;
        !           145:        int             cpt;
        !           146: 
        !           147:        vp = (struct vrrp_hdr *)buffer;
        !           148:        vp->vrrp_v = VRRP_PROTOCOL_VERSION;
        !           149:        vp->vrrp_t = VRRP_PROTOCOL_ADVERTISEMENT;
        !           150:        vp->vr_id = vr->vr_id;
        !           151:        vp->priority = vr->priority;
        !           152:        vp->cnt_ip = vr->cnt_ip;
        !           153:        vp->auth_type = vr->auth_type;
        !           154:        vp->adv_int = vr->adv_int;
        !           155:        addr = (struct in_addr *) & buffer[sizeof(struct vrrp_hdr)];
        !           156:        for (cpt = 0; cpt < vr->cnt_ip; cpt++) {
        !           157:                addr[cpt].s_addr = vr->vr_ip[cpt].addr.s_addr;
        !           158:        }
        !           159:        if (vr->auth_type == 1) {
        !           160:                password = (char *)&addr[vr->cnt_ip];
        !           161:                strncpy(password, vr->password, 8);
        !           162:        }
        !           163:        vp->csum = vrrp_misc_compute_checksum((u_short *) vp, vrrp_network_vrrphdr_len(vr));
        !           164: 
        !           165:        return;
        !           166: }
        !           167: 
        !           168: char 
        !           169: vrrp_network_send_advertisement(struct vrrp_vr * vr)
        !           170: {
        !           171:        u_char         *buffer;
        !           172: #ifdef ENABLE_VRRP_AH
        !           173:        u_int           len = sizeof(struct ip) + vrrp_ah_ahhdr_len(vr) + vrrp_network_vrrphdr_len(vr);
        !           174: #else
        !           175:        u_int           len = sizeof(struct ip) + vrrp_network_vrrphdr_len(vr);
        !           176: #endif
        !           177:        ssize_t         bytes = 0;
        !           178: 
        !           179:        buffer = (u_char *) malloc(len);
        !           180:        bzero(buffer, len);
        !           181: 
        !           182:        vrrp_network_init_iphdr(buffer, vr);
        !           183: #ifdef ENABLE_VRRP_AH
        !           184:        /* add AH adding code */
        !           185:        if (vr->AHencryption == 1) {
        !           186:            vrrp_ah_init_ahhdr(buffer,vr); 
        !           187:            vrrp_network_init_vrrphdr(&buffer[sizeof(struct ip)+vrrp_ah_ahhdr_len(vr)], vr); 
        !           188:            vrrp_ah_hmacmd5(buffer,vr);
        !           189:        } else 
        !           190:            vrrp_network_init_vrrphdr(&buffer[sizeof(struct ip)+vrrp_ah_ahhdr_len(vr)], vr); 
        !           191: #else
        !           192:        vrrp_network_init_vrrphdr(&buffer[sizeof(struct ip)], vr);
        !           193: #endif
        !           194: 
        !           195:        if (vr->fault)
        !           196:                bytes = vrrp_network_send_packet(buffer, len, vr->sd, 0);
        !           197:        else
        !           198:                bytes = vrrp_network_send_packet(buffer, len, vr->sd, 1);
        !           199: 
        !           200:        if (bytes < 0) {
        !           201:                syslog(LOG_ERR, "There is a big problem here !");
        !           202:                vr->fault = 1;
        !           203:                free(buffer);
        !           204:                return -1;
        !           205:        }
        !           206:        vr->fault = 0;
        !           207:        free(buffer);
        !           208: 
        !           209:        return 0;
        !           210: }
        !           211: 
        !           212: int
        !           213: vrrp_network_open_bpf(char *if_name)
        !           214: {
        !           215:         struct ifreq    ifr;
        !           216:         int             n = 0;
        !           217:         char            device[16];
        !           218:         int             sd = 0;
        !           219:         int             yes = 1;
        !           220:    
        !           221:         while ((sd <= 0) && (n < 100)) {
        !           222:                 snprintf(device, sizeof(device), "/dev/bpf%d", n++);
        !           223:                 sd = open(device, O_WRONLY);
        !           224:         }
        !           225:         if (sd < 0) { 
        !           226:                 syslog(LOG_ERR, "cannot found a valid /dev/bpf* entry, do you have bpf in kernel ?");
        !           227:                 syslog(LOG_ERR, "perhaps you've not created /dev entry on your chroot directory with bpf* entries");
        !           228:                 return -1;
        !           229:         }
        !           230:         bzero(&ifr, sizeof(ifr));
        !           231:         strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name));
        !           232:         if (ioctl(sd, BIOCSETIF, (caddr_t)&ifr) < 0) {
        !           233:                 syslog(LOG_ERR, "interface %s doesn't seem to exist, ioctl: %s\n", strerror(errno), ifr.ifr_name);
        !           234:                 syslog(LOG_ERR, "you must correct your configuration file with a good option for 'interface ='");
        !           235:                 return -1;
        !           236:         }
        !           237:         if (ioctl(sd, BIOCSHDRCMPLT, &yes) < 0) {
        !           238:                 syslog(LOG_ERR, "cannot do BIOCSHDRCMPLT: %s", strerror(errno));
        !           239:                 syslog(LOG_ERR, "something is terribly wrong, I can't continue");
        !           240:                 return -1;
        !           241:         }
        !           242: 
        !           243:        return sd;
        !           244: }
        !           245: 
        !           246: int 
        !           247: vrrp_network_send_gratuitous_arp(char *if_name, struct ether_addr *ethaddr, struct in_addr addr)
        !           248: {
        !           249:         char buffer[ETHER_HDR_LEN + sizeof(struct arp_header)];
        !           250:         struct ether_header *ethhdr = (struct ether_header *) buffer;
        !           251:         struct arp_header *arph = (struct arp_header *) & buffer[ETHER_HDR_LEN];
        !           252:        int sd;
        !           253: 
        !           254:         memset(ethhdr->ether_dhost, 0xFF, ETHER_ADDR_LEN);
        !           255:         bcopy(ethaddr, ethhdr->ether_shost, ETHER_ADDR_LEN);
        !           256:         ethhdr->ether_type = htons(ETHERTYPE_ARP);
        !           257:         bzero(arph, sizeof(*arph));
        !           258:         arph->ar_hrd = htons(ARPHRD_ETHER);
        !           259:         arph->ar_pro = htons(ETHERTYPE_IP);
        !           260:         arph->ar_hln = ETHER_ADDR_LEN;
        !           261:         arph->ar_pln = 4;
        !           262:         arph->ar_op = htons(ARPOP_REQUEST);
        !           263:         memcpy(arph->ar_sha, ethhdr->ether_shost, ETHER_ADDR_LEN);
        !           264:        sd = vrrp_network_open_bpf(if_name);
        !           265:         if (sd == -1)
        !           266:                 return -1;
        !           267:         memcpy(arph->ar_spa, &addr, sizeof(struct in_addr));
        !           268:         memcpy(arph->ar_tpa, &addr, sizeof(struct in_addr));
        !           269:         if (write(sd, buffer, ETHER_HDR_LEN + sizeof(struct arp_header)) == -1) {
        !           270:                 syslog(LOG_ERR, "cannot write on socket descriptor sd: %s", strerror(errno));
        !           271:                close(sd);
        !           272:                 return -1;
        !           273:         }
        !           274:        close(sd);
        !           275: 
        !           276:         return 0;
        !           277: }
        !           278: 
        !           279: int
        !           280: vrrp_network_send_gratuitous_arp_ips(struct vrrp_vr * vr, struct ether_addr * ethaddr)
        !           281: {
        !           282:         int             cpt = 0;
        !           283:         struct in_addr  addrs[MAX_IP_ALIAS];
        !           284:         int             size = MAX_IP_ALIAS;
        !           285:         char            coderet = 0;
        !           286: 
        !           287:         bzero(addrs, sizeof(addrs));
        !           288:         vrrp_misc_get_if_infos(vr->vr_if->if_name, NULL, addrs, &size);
        !           289:         while (addrs[cpt].s_addr) {
        !           290:                 coderet = vrrp_network_send_gratuitous_arp(vr->vr_if->if_name, ethaddr, addrs[cpt]);
        !           291:                 syslog(LOG_ERR, "send gratuitous arp %s -> %x:%x:%x:%x:%x:%x", inet_ntoa(addrs[cpt]), ethaddr->octet[0], ethaddr->octet[1], ethaddr->octet[2], ethaddr->octet[3], ethaddr->octet[4], ethaddr->octet[5]);
        !           292:                 cpt++;
        !           293:         }
        !           294: 
        !           295:         return coderet;
        !           296: }
        !           297: 
        !           298: #define rtm rtmsg.rthdr
        !           299: char 
        !           300: vrrp_network_delete_local_route(struct in_addr addr)
        !           301: {
        !           302:        struct routemsg rtmsg;
        !           303:        int             sd;
        !           304: 
        !           305:        sd = socket(PF_ROUTE, SOCK_RAW, 0);
        !           306:        if (sd == -1) {
        !           307:                close(sd);
        !           308:                return -1;
        !           309:        }
        !           310:        bzero(&rtmsg, sizeof(rtmsg));
        !           311:        rtm.rtm_type = RTM_DELETE;
        !           312:        rtm.rtm_version = RTM_VERSION;
        !           313: #ifdef __FreeBSD__
        !           314:        rtm.rtm_flags = RTF_UP | RTF_HOST | RTF_LOCAL;
        !           315: #endif
        !           316: #if __FreeBSD_version < 800059
        !           317:        rtm.rtm_flags |= RTF_WASCLONED;
        !           318: #endif
        !           319: #ifdef __NetBSD__
        !           320:        rtm.rtm_flags = RTF_UP | RTF_HOST | RTF_CLONED;
        !           321: #endif
        !           322:        rtm.rtm_addrs = RTA_DST;
        !           323:        rtm.rtm_msglen = sizeof(rtmsg);
        !           324:        rtmsg.addr.sin_len = sizeof(rtmsg.addr);
        !           325:        rtmsg.addr.sin_family = AF_INET;
        !           326:        rtmsg.addr.sin_addr = addr;
        !           327:        if (write(sd, &rtmsg, sizeof(rtmsg)) == -1) {
        !           328:                close(sd);
        !           329:                return -1;
        !           330:        }
        !           331:        close(sd);
        !           332: 
        !           333:        return 0;
        !           334: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>