1 /* $OpenBSD: packet.c,v 1.9 2024/08/21 09:18:47 florian 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 <stddef.h> 31 #include <stdlib.h> 32 #include <string.h> 33 34 #include "igmp.h" 35 #include "dvmrpd.h" 36 #include "dvmrp.h" 37 #include "log.h" 38 #include "dvmrpe.h" 39 40 int ip_hdr_sanity_check(const struct ip *, u_int16_t); 41 int dvmrp_hdr_sanity_check(const struct ip *, struct dvmrp_hdr *, 42 u_int16_t, const struct iface *); 43 struct iface *find_iface(struct dvmrpd_conf *, struct in_addr); 44 45 static u_int8_t *recv_buf; 46 47 int 48 gen_dvmrp_hdr(struct ibuf *buf, struct iface *iface, u_int8_t code) 49 { 50 struct dvmrp_hdr dvmrp_hdr; 51 52 memset(&dvmrp_hdr, 0, sizeof(dvmrp_hdr)); 53 dvmrp_hdr.type = PKT_TYPE_DVMRP; 54 dvmrp_hdr.code = code; 55 dvmrp_hdr.chksum = 0; /* updated later */ 56 dvmrp_hdr.capabilities = DVMRP_CAP_DEFAULT; /* XXX update */ 57 dvmrp_hdr.minor_version = DVMRP_MINOR_VERSION; 58 dvmrp_hdr.major_version = DVMRP_MAJOR_VERSION; 59 60 return (ibuf_add(buf, &dvmrp_hdr, sizeof(dvmrp_hdr))); 61 } 62 63 /* send and receive packets */ 64 int 65 send_packet(struct iface *iface, struct ibuf *pkt, struct sockaddr_in *dst) 66 { 67 u_int16_t chksum; 68 69 if (iface->passive) { 70 log_warnx("send_packet: cannot send packet on passive " 71 "interface %s", iface->name); 72 return (-1); 73 } 74 75 /* set outgoing interface for multicast traffic */ 76 if (IN_MULTICAST(ntohl(dst->sin_addr.s_addr))) 77 if (if_set_mcast(iface) == -1) { 78 log_warn("send_packet: error setting multicast " 79 "interface, %s", iface->name); 80 return (-1); 81 } 82 83 /* update chksum */ 84 chksum = in_cksum(ibuf_data(pkt), ibuf_size(pkt)); 85 if (ibuf_set(pkt, offsetof(struct dvmrp_hdr, chksum), 86 &chksum, sizeof(chksum)) == -1) { 87 log_warn("send_packet: failed to update checksum"); 88 return (-1); 89 } 90 91 if (sendto(iface->fd, ibuf_data(pkt), ibuf_size(pkt), 0, 92 (struct sockaddr *)dst, sizeof(*dst)) == -1 ) { 93 log_warn("send_packet: error sending packet on interface %s", 94 iface->name); 95 return (-1); 96 } 97 98 return (0); 99 } 100 101 void 102 recv_packet(int fd, short event, void *bula) 103 { 104 struct dvmrpd_conf *xconf = bula; 105 struct ip ip_hdr; 106 struct dvmrp_hdr *dvmrp_hdr; 107 struct iface *iface; 108 struct nbr *nbr = NULL; 109 struct in_addr addr; 110 char *buf; 111 ssize_t r; 112 u_int16_t len; 113 int l; 114 115 if (event != EV_READ) 116 return; 117 118 if (recv_buf == NULL) 119 if ((recv_buf = malloc(READ_BUF_SIZE)) == NULL) 120 fatal(__func__); 121 122 buf = recv_buf; 123 if ((r = recvfrom(fd, buf, READ_BUF_SIZE, 0, NULL, NULL)) == -1) { 124 if (errno != EAGAIN && errno != EINTR) 125 log_debug("recv_packet: error receiving packet"); 126 return; 127 } 128 129 len = (u_int16_t)r; 130 131 /* IP header sanity checks */ 132 if (len < sizeof(ip_hdr)) { 133 log_warnx("recv_packet: bad packet size"); 134 return; 135 } 136 137 memcpy(&ip_hdr, buf, sizeof(ip_hdr)); 138 if ((l = ip_hdr_sanity_check(&ip_hdr, len)) == -1) 139 return; 140 buf += l; 141 len -= l; 142 143 /* find a matching interface */ 144 if ((iface = find_iface(xconf, ip_hdr.ip_src)) == NULL) { 145 log_debug("recv_packet: cannot find valid interface, ip src %s", 146 inet_ntoa(ip_hdr.ip_src)); 147 return; 148 } 149 150 /* header sanity checks */ 151 if (len < sizeof(*dvmrp_hdr)) { 152 log_warnx("recv_packet: bad packet size"); 153 return; 154 } 155 dvmrp_hdr = (struct dvmrp_hdr *)buf; 156 157 switch (dvmrp_hdr->type) { 158 /* DVMRP */ 159 case PKT_TYPE_DVMRP: 160 if ((l = dvmrp_hdr_sanity_check(&ip_hdr, dvmrp_hdr, len, 161 iface)) == -1) 162 return; 163 164 /* 165 * mrouted compat 166 * 167 * Old mrouted versions, send route reports before establishing 168 * 2-WAY neighbor relationships. 169 */ 170 if ((nbr_find_ip(iface, ip_hdr.ip_src.s_addr) == NULL) && 171 (dvmrp_hdr->code == DVMRP_CODE_REPORT)) { 172 log_debug("recv_packet: route report from neighbor" 173 " ID %s, compat", inet_ntoa(ip_hdr.ip_src)); 174 nbr = nbr_new(ip_hdr.ip_src.s_addr, iface, 0); 175 nbr_fsm(nbr, NBR_EVT_PROBE_RCVD); 176 nbr->compat = 1; 177 nbr->addr = ip_hdr.ip_src; 178 } 179 180 if ((dvmrp_hdr->type == PKT_TYPE_DVMRP) && 181 (dvmrp_hdr->code != DVMRP_CODE_PROBE)) 182 /* find neighbor */ 183 if ((nbr = nbr_find_ip(iface, ip_hdr.ip_src.s_addr)) 184 == NULL) { 185 log_debug("recv_packet: unknown neighbor ID"); 186 return; 187 } 188 189 buf += sizeof(*dvmrp_hdr); 190 len = l - sizeof(*dvmrp_hdr); 191 192 inet_pton(AF_INET, AllDVMRPRouters, &addr); 193 if ((ip_hdr.ip_dst.s_addr != addr.s_addr) && 194 (ip_hdr.ip_dst.s_addr != iface->addr.s_addr)) { 195 log_debug("recv_packet: interface %s, invalid" 196 " destination IP address %s", iface->name, 197 inet_ntoa(ip_hdr.ip_dst)); 198 break; 199 } 200 201 switch (dvmrp_hdr->code) { 202 case DVMRP_CODE_PROBE: 203 recv_probe(iface, ip_hdr.ip_src, ip_hdr.ip_src.s_addr, 204 dvmrp_hdr->capabilities, buf, len); 205 break; 206 case DVMRP_CODE_REPORT: 207 recv_report(nbr, buf, len); 208 break; 209 case DVMRP_CODE_ASK_NBRS2: 210 recv_ask_nbrs2(nbr, buf,len); 211 break; 212 case DVMRP_CODE_NBRS2: 213 recv_nbrs2(nbr, buf,len); 214 break; 215 case DVMRP_CODE_PRUNE: 216 recv_prune(nbr, buf, len); 217 break; 218 case DVMRP_CODE_GRAFT: 219 recv_graft(nbr, buf,len); 220 break; 221 case DVMRP_CODE_GRAFT_ACK: 222 recv_graft_ack(nbr, buf,len); 223 break; 224 default: 225 log_debug("recv_packet: unknown DVMRP packet type, " 226 "interface %s", iface->name); 227 } 228 break; 229 /* IGMP */ 230 case PKT_TYPE_MEMBER_QUERY: 231 recv_igmp_query(iface, ip_hdr.ip_src, buf, len); 232 break; 233 case PKT_TYPE_MEMBER_REPORTv1: 234 case PKT_TYPE_MEMBER_REPORTv2: 235 recv_igmp_report(iface, ip_hdr.ip_src, buf, len, 236 dvmrp_hdr->type); 237 break; 238 case PKT_TYPE_LEAVE_GROUPv2: 239 recv_igmp_leave(iface, ip_hdr.ip_src, buf, len); 240 break; 241 default: 242 log_debug("recv_packet: unknown IGMP packet type, interface %s", 243 iface->name); 244 } 245 } 246 247 int 248 ip_hdr_sanity_check(const struct ip *ip_hdr, u_int16_t len) 249 { 250 if (ntohs(ip_hdr->ip_len) != len) { 251 log_debug("recv_packet: invalid IP packet length %u", 252 ntohs(ip_hdr->ip_len)); 253 return (-1); 254 } 255 256 if (ip_hdr->ip_p != IPPROTO_IGMP) 257 /* this is enforced by the socket itself */ 258 fatalx("recv_packet: invalid IP proto"); 259 260 return (ip_hdr->ip_hl << 2); 261 } 262 263 int 264 dvmrp_hdr_sanity_check(const struct ip *ip_hdr, struct dvmrp_hdr *dvmrp_hdr, 265 u_int16_t len, const struct iface *iface) 266 { 267 /* we only support DVMRPv3 */ 268 if (dvmrp_hdr->major_version != DVMRP_MAJOR_VERSION) { 269 log_debug("recv_packet: invalid DVMRP version"); 270 return (-1); 271 } 272 273 /* XXX enforce minor version as well, but not yet */ 274 275 /* XXX chksum */ 276 277 return (len); 278 } 279 280 struct iface * 281 find_iface(struct dvmrpd_conf *xconf, struct in_addr src) 282 { 283 struct iface *iface = NULL; 284 285 /* returned interface needs to be active */ 286 LIST_FOREACH(iface, &xconf->iface_list, entry) { 287 if (iface->fd > 0 && 288 (iface->type == IF_TYPE_POINTOPOINT) && 289 (iface->dst.s_addr == src.s_addr) && 290 !iface->passive) 291 return (iface); 292 293 if (iface->fd > 0 && (iface->addr.s_addr & 294 iface->mask.s_addr) == (src.s_addr & 295 iface->mask.s_addr) && !iface->passive) 296 return (iface); 297 } 298 299 return (NULL); 300 } 301