1*978e5cffSnorby /* $OpenBSD: packet.c,v 1.1 2006/06/01 14:12:20 norby Exp $ */ 2*978e5cffSnorby 3*978e5cffSnorby /* 4*978e5cffSnorby * Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org> 5*978e5cffSnorby * 6*978e5cffSnorby * Permission to use, copy, modify, and distribute this software for any 7*978e5cffSnorby * purpose with or without fee is hereby granted, provided that the above 8*978e5cffSnorby * copyright notice and this permission notice appear in all copies. 9*978e5cffSnorby * 10*978e5cffSnorby * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11*978e5cffSnorby * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12*978e5cffSnorby * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13*978e5cffSnorby * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14*978e5cffSnorby * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15*978e5cffSnorby * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16*978e5cffSnorby * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17*978e5cffSnorby */ 18*978e5cffSnorby 19*978e5cffSnorby #include <sys/types.h> 20*978e5cffSnorby #include <sys/socket.h> 21*978e5cffSnorby #include <sys/time.h> 22*978e5cffSnorby 23*978e5cffSnorby #include <netinet/in.h> 24*978e5cffSnorby #include <netinet/in_systm.h> 25*978e5cffSnorby #include <netinet/ip.h> 26*978e5cffSnorby #include <netinet/ip_mroute.h> 27*978e5cffSnorby #include <arpa/inet.h> 28*978e5cffSnorby 29*978e5cffSnorby #include <errno.h> 30*978e5cffSnorby #include <event.h> 31*978e5cffSnorby #include <stdlib.h> 32*978e5cffSnorby #include <strings.h> 33*978e5cffSnorby 34*978e5cffSnorby #include "igmp.h" 35*978e5cffSnorby #include "dvmrpd.h" 36*978e5cffSnorby #include "dvmrp.h" 37*978e5cffSnorby #include "log.h" 38*978e5cffSnorby #include "dvmrpe.h" 39*978e5cffSnorby 40*978e5cffSnorby int ip_hdr_sanity_check(const struct ip *, u_int16_t); 41*978e5cffSnorby int dvmrp_hdr_sanity_check(const struct ip *, struct dvmrp_hdr *, 42*978e5cffSnorby u_int16_t, const struct iface *); 43*978e5cffSnorby struct iface *find_iface(struct dvmrpd_conf *, struct in_addr); 44*978e5cffSnorby 45*978e5cffSnorby extern struct dvmrpd_conf *deconf; 46*978e5cffSnorby 47*978e5cffSnorby int 48*978e5cffSnorby gen_dvmrp_hdr(struct buf *buf, struct iface *iface, u_int8_t code) 49*978e5cffSnorby { 50*978e5cffSnorby struct dvmrp_hdr dvmrp_hdr; 51*978e5cffSnorby 52*978e5cffSnorby bzero(&dvmrp_hdr, sizeof(dvmrp_hdr)); 53*978e5cffSnorby dvmrp_hdr.type = PKT_TYPE_DVMRP; 54*978e5cffSnorby dvmrp_hdr.code = code; 55*978e5cffSnorby dvmrp_hdr.chksum = 0; /* updated later */ 56*978e5cffSnorby dvmrp_hdr.capabilities = DVMRP_CAP_DEFAULT; /* XXX update */ 57*978e5cffSnorby dvmrp_hdr.minor_version = DVMRP_MINOR_VERSION; 58*978e5cffSnorby dvmrp_hdr.major_version = DVMRP_MAJOR_VERSION; 59*978e5cffSnorby 60*978e5cffSnorby return (buf_add(buf, &dvmrp_hdr, sizeof(dvmrp_hdr))); 61*978e5cffSnorby } 62*978e5cffSnorby 63*978e5cffSnorby /* send and receive packets */ 64*978e5cffSnorby int 65*978e5cffSnorby send_packet(struct iface *iface, void *pkt, size_t len, struct sockaddr_in *dst) 66*978e5cffSnorby { 67*978e5cffSnorby if (iface->passive) { 68*978e5cffSnorby log_warnx("send_packet: cannot send packet on passive " 69*978e5cffSnorby "interface %s", iface->name); 70*978e5cffSnorby return (-1); 71*978e5cffSnorby } 72*978e5cffSnorby 73*978e5cffSnorby /* set outgoing interface for multicast traffic */ 74*978e5cffSnorby if (IN_MULTICAST(ntohl(dst->sin_addr.s_addr))) 75*978e5cffSnorby if (if_set_mcast(iface) == -1) { 76*978e5cffSnorby log_warn("send_packet: error setting multicast " 77*978e5cffSnorby "interface, %s", iface->name); 78*978e5cffSnorby return (-1); 79*978e5cffSnorby } 80*978e5cffSnorby 81*978e5cffSnorby if (sendto(iface->fd, pkt, len, 0, 82*978e5cffSnorby (struct sockaddr *)dst, sizeof(*dst)) == -1 ) { 83*978e5cffSnorby log_warn("send_packet: error sending packet on interface %s", 84*978e5cffSnorby iface->name); 85*978e5cffSnorby return (-1); 86*978e5cffSnorby } 87*978e5cffSnorby 88*978e5cffSnorby return (0); 89*978e5cffSnorby } 90*978e5cffSnorby 91*978e5cffSnorby void 92*978e5cffSnorby recv_packet(int fd, short event, void *bula) 93*978e5cffSnorby { 94*978e5cffSnorby struct dvmrpd_conf *xconf = bula; 95*978e5cffSnorby struct ip ip_hdr; 96*978e5cffSnorby struct dvmrp_hdr *dvmrp_hdr; 97*978e5cffSnorby struct iface *iface; 98*978e5cffSnorby struct nbr *nbr = NULL; 99*978e5cffSnorby struct in_addr addr; 100*978e5cffSnorby char *buf; 101*978e5cffSnorby ssize_t r; 102*978e5cffSnorby u_int16_t len; 103*978e5cffSnorby int l; 104*978e5cffSnorby 105*978e5cffSnorby if (event != EV_READ) 106*978e5cffSnorby return; 107*978e5cffSnorby 108*978e5cffSnorby /* setup buffer */ 109*978e5cffSnorby buf = pkt_ptr; 110*978e5cffSnorby 111*978e5cffSnorby if ((r = recvfrom(fd, buf, READ_BUF_SIZE, 0, NULL, NULL)) == -1) { 112*978e5cffSnorby if (errno != EAGAIN && errno != EINTR) 113*978e5cffSnorby log_debug("recv_packet: error receiving packet"); 114*978e5cffSnorby return; 115*978e5cffSnorby } 116*978e5cffSnorby 117*978e5cffSnorby len = (u_int16_t)r; 118*978e5cffSnorby 119*978e5cffSnorby /* IP header sanity checks */ 120*978e5cffSnorby if (len < sizeof(ip_hdr)) { 121*978e5cffSnorby log_warnx("recv_packet: bad packet size"); 122*978e5cffSnorby return; 123*978e5cffSnorby } 124*978e5cffSnorby 125*978e5cffSnorby memcpy(&ip_hdr, buf, sizeof(ip_hdr)); 126*978e5cffSnorby if ((l = ip_hdr_sanity_check(&ip_hdr, len)) == -1) 127*978e5cffSnorby return; 128*978e5cffSnorby buf += l; 129*978e5cffSnorby len -= l; 130*978e5cffSnorby 131*978e5cffSnorby /* find a matching interface */ 132*978e5cffSnorby if ((iface = find_iface(xconf, ip_hdr.ip_src)) == NULL) { 133*978e5cffSnorby log_debug("recv_packet: cannot find valid interface, ip src %s", 134*978e5cffSnorby inet_ntoa(ip_hdr.ip_src)); 135*978e5cffSnorby return; 136*978e5cffSnorby } 137*978e5cffSnorby 138*978e5cffSnorby /* header sanity checks */ 139*978e5cffSnorby if (len < sizeof(*dvmrp_hdr)) { 140*978e5cffSnorby log_warnx("recv_packet: bad packet size"); 141*978e5cffSnorby return; 142*978e5cffSnorby } 143*978e5cffSnorby dvmrp_hdr = (struct dvmrp_hdr *)buf; 144*978e5cffSnorby 145*978e5cffSnorby switch (dvmrp_hdr->type) { 146*978e5cffSnorby /* DVMRP */ 147*978e5cffSnorby case PKT_TYPE_DVMRP: 148*978e5cffSnorby if ((l = dvmrp_hdr_sanity_check(&ip_hdr, dvmrp_hdr, len, 149*978e5cffSnorby iface)) == -1) 150*978e5cffSnorby return; 151*978e5cffSnorby 152*978e5cffSnorby /* 153*978e5cffSnorby * mrouted compat 154*978e5cffSnorby * 155*978e5cffSnorby * Old mrouted versions, send route reports before establishing 156*978e5cffSnorby * 2-WAY neighbor relationships. 157*978e5cffSnorby */ 158*978e5cffSnorby if ((nbr_find_ip(iface, ip_hdr.ip_src.s_addr) == NULL) && 159*978e5cffSnorby (dvmrp_hdr->code == DVMRP_CODE_REPORT)) { 160*978e5cffSnorby log_debug("recv_packet: route report from neighbor" 161*978e5cffSnorby " ID %s, compat", inet_ntoa(ip_hdr.ip_src)); 162*978e5cffSnorby nbr = nbr_new(ip_hdr.ip_src.s_addr, iface, 0); 163*978e5cffSnorby nbr_fsm(nbr, NBR_EVT_PROBE_RCVD); 164*978e5cffSnorby nbr->compat = 1; 165*978e5cffSnorby nbr->addr = ip_hdr.ip_src; 166*978e5cffSnorby } 167*978e5cffSnorby 168*978e5cffSnorby if ((dvmrp_hdr->type == PKT_TYPE_DVMRP) && 169*978e5cffSnorby (dvmrp_hdr->code != DVMRP_CODE_PROBE)) 170*978e5cffSnorby /* find neighbor */ 171*978e5cffSnorby if ((nbr = nbr_find_ip(iface, ip_hdr.ip_src.s_addr)) 172*978e5cffSnorby == NULL) { 173*978e5cffSnorby log_debug("recv_packet: unknown neighbor ID"); 174*978e5cffSnorby return; 175*978e5cffSnorby } 176*978e5cffSnorby 177*978e5cffSnorby buf += sizeof(*dvmrp_hdr); 178*978e5cffSnorby len = l - sizeof(*dvmrp_hdr); 179*978e5cffSnorby 180*978e5cffSnorby inet_aton(AllDVMRPRouters, &addr); 181*978e5cffSnorby if ((ip_hdr.ip_dst.s_addr != addr.s_addr) && 182*978e5cffSnorby (ip_hdr.ip_dst.s_addr != iface->addr.s_addr)) { 183*978e5cffSnorby log_debug("recv_packet: interface %s, invalid" 184*978e5cffSnorby " destination IP address %s", iface->name, 185*978e5cffSnorby inet_ntoa(ip_hdr.ip_dst)); 186*978e5cffSnorby break; 187*978e5cffSnorby } 188*978e5cffSnorby 189*978e5cffSnorby switch (dvmrp_hdr->code) { 190*978e5cffSnorby case DVMRP_CODE_PROBE: 191*978e5cffSnorby recv_probe(iface, ip_hdr.ip_src, ip_hdr.ip_src.s_addr, 192*978e5cffSnorby dvmrp_hdr->capabilities, buf, len); 193*978e5cffSnorby break; 194*978e5cffSnorby case DVMRP_CODE_REPORT: 195*978e5cffSnorby recv_report(nbr, buf, len); 196*978e5cffSnorby break; 197*978e5cffSnorby case DVMRP_CODE_ASK_NBRS2: 198*978e5cffSnorby recv_ask_nbrs2(nbr, buf,len); 199*978e5cffSnorby break; 200*978e5cffSnorby case DVMRP_CODE_NBRS2: 201*978e5cffSnorby recv_nbrs2(nbr, buf,len); 202*978e5cffSnorby break; 203*978e5cffSnorby case DVMRP_CODE_PRUNE: 204*978e5cffSnorby recv_prune(nbr, buf, len); 205*978e5cffSnorby break; 206*978e5cffSnorby case DVMRP_CODE_GRAFT: 207*978e5cffSnorby recv_graft(nbr, buf,len); 208*978e5cffSnorby break; 209*978e5cffSnorby case DVMRP_CODE_GRAFT_ACK: 210*978e5cffSnorby recv_graft_ack(nbr, buf,len); 211*978e5cffSnorby break; 212*978e5cffSnorby default: 213*978e5cffSnorby log_debug("recv_packet: unknown DVMRP packet type, " 214*978e5cffSnorby "interface %s", iface->name); 215*978e5cffSnorby } 216*978e5cffSnorby break; 217*978e5cffSnorby /* IGMP */ 218*978e5cffSnorby case PKT_TYPE_MEMBER_QUERY: 219*978e5cffSnorby recv_igmp_query(iface, ip_hdr.ip_src, buf, len); 220*978e5cffSnorby break; 221*978e5cffSnorby case PKT_TYPE_MEMBER_REPORTv1: 222*978e5cffSnorby case PKT_TYPE_MEMBER_REPORTv2: 223*978e5cffSnorby recv_igmp_report(iface, ip_hdr.ip_src, buf, len, 224*978e5cffSnorby dvmrp_hdr->type); 225*978e5cffSnorby break; 226*978e5cffSnorby case PKT_TYPE_LEAVE_GROUPv2: 227*978e5cffSnorby recv_igmp_leave(iface, ip_hdr.ip_src, buf, len); 228*978e5cffSnorby break; 229*978e5cffSnorby default: 230*978e5cffSnorby log_debug("recv_packet: unknown IGMP packet type, interface %s", 231*978e5cffSnorby iface->name); 232*978e5cffSnorby } 233*978e5cffSnorby } 234*978e5cffSnorby 235*978e5cffSnorby int 236*978e5cffSnorby ip_hdr_sanity_check(const struct ip *ip_hdr, u_int16_t len) 237*978e5cffSnorby { 238*978e5cffSnorby if (ntohs(ip_hdr->ip_len) != len) { 239*978e5cffSnorby log_debug("recv_packet: invalid IP packet length %u", 240*978e5cffSnorby ntohs(ip_hdr->ip_len)); 241*978e5cffSnorby return (-1); 242*978e5cffSnorby } 243*978e5cffSnorby 244*978e5cffSnorby if (ip_hdr->ip_p != IPPROTO_IGMP) 245*978e5cffSnorby /* this is enforced by the socket itself */ 246*978e5cffSnorby fatalx("recv_packet: invalid IP proto"); 247*978e5cffSnorby 248*978e5cffSnorby return (ip_hdr->ip_hl << 2); 249*978e5cffSnorby } 250*978e5cffSnorby 251*978e5cffSnorby int 252*978e5cffSnorby dvmrp_hdr_sanity_check(const struct ip *ip_hdr, struct dvmrp_hdr *dvmrp_hdr, 253*978e5cffSnorby u_int16_t len, const struct iface *iface) 254*978e5cffSnorby { 255*978e5cffSnorby /* we only support DVMRPv3 */ 256*978e5cffSnorby if (dvmrp_hdr->major_version != DVMRP_MAJOR_VERSION) { 257*978e5cffSnorby log_debug("recv_packet: invalid DVMRP version"); 258*978e5cffSnorby return (-1); 259*978e5cffSnorby } 260*978e5cffSnorby 261*978e5cffSnorby /* XXX enforce minor version as well, but not yet */ 262*978e5cffSnorby 263*978e5cffSnorby /* XXX chksum */ 264*978e5cffSnorby 265*978e5cffSnorby return (len); 266*978e5cffSnorby } 267*978e5cffSnorby 268*978e5cffSnorby struct iface * 269*978e5cffSnorby find_iface(struct dvmrpd_conf *xconf, struct in_addr src) 270*978e5cffSnorby { 271*978e5cffSnorby struct iface *iface = NULL; 272*978e5cffSnorby 273*978e5cffSnorby /* returned interface needs to be active */ 274*978e5cffSnorby LIST_FOREACH(iface, &xconf->iface_list, entry) { 275*978e5cffSnorby if (iface->fd > 0 && 276*978e5cffSnorby (iface->type == IF_TYPE_POINTOPOINT) && 277*978e5cffSnorby (iface->dst.s_addr == src.s_addr) && 278*978e5cffSnorby !iface->passive) 279*978e5cffSnorby return (iface); 280*978e5cffSnorby 281*978e5cffSnorby if (iface->fd > 0 && (iface->addr.s_addr & 282*978e5cffSnorby iface->mask.s_addr) == (src.s_addr & 283*978e5cffSnorby iface->mask.s_addr) && !iface->passive) 284*978e5cffSnorby return (iface); 285*978e5cffSnorby } 286*978e5cffSnorby 287*978e5cffSnorby return (NULL); 288*978e5cffSnorby } 289