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>