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