1 /* $OpenBSD: packet.c,v 1.37 2023/07/03 09:40:47 claudio Exp $ */ 2 3 /* 4 * Copyright (c) 2004, 2005 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/uio.h> 22 23 #include <netinet/in.h> 24 #include <netinet/ip.h> 25 #include <arpa/inet.h> 26 #include <net/if_dl.h> 27 28 #include <errno.h> 29 #include <event.h> 30 #include <stdlib.h> 31 #include <string.h> 32 33 #include "ospfd.h" 34 #include "ospf.h" 35 #include "log.h" 36 #include "ospfe.h" 37 38 int ip_hdr_sanity_check(const struct ip *, u_int16_t); 39 int ospf_hdr_sanity_check(const struct ip *, 40 struct ospf_hdr *, u_int16_t, const struct iface *); 41 struct iface *find_iface(struct ospfd_conf *, unsigned int, struct in_addr); 42 43 static u_int8_t *recv_buf; 44 45 int 46 gen_ospf_hdr(struct ibuf *buf, struct iface *iface, u_int8_t type) 47 { 48 struct ospf_hdr ospf_hdr; 49 50 bzero(&ospf_hdr, sizeof(ospf_hdr)); 51 ospf_hdr.version = OSPF_VERSION; 52 ospf_hdr.type = type; 53 ospf_hdr.rtr_id = ospfe_router_id(); 54 if (iface->type != IF_TYPE_VIRTUALLINK) 55 ospf_hdr.area_id = iface->area->id.s_addr; 56 ospf_hdr.auth_type = htons(iface->auth_type); 57 58 return (ibuf_add(buf, &ospf_hdr, sizeof(ospf_hdr))); 59 } 60 61 /* send and receive packets */ 62 int 63 send_packet(struct iface *iface, struct ibuf *buf, struct sockaddr_in *dst) 64 { 65 struct msghdr msg; 66 struct iovec iov[2]; 67 struct ip ip_hdr; 68 69 /* setup IP hdr */ 70 bzero(&ip_hdr, sizeof(ip_hdr)); 71 ip_hdr.ip_v = IPVERSION; 72 ip_hdr.ip_hl = sizeof(ip_hdr) >> 2; 73 ip_hdr.ip_tos = IPTOS_PREC_INTERNETCONTROL; 74 ip_hdr.ip_len = htons(ibuf_size(buf) + sizeof(ip_hdr)); 75 ip_hdr.ip_id = 0; /* 0 means kernel set appropriate value */ 76 ip_hdr.ip_off = 0; 77 ip_hdr.ip_ttl = iface->type != IF_TYPE_VIRTUALLINK ? 78 IP_DEFAULT_MULTICAST_TTL : MAXTTL; 79 ip_hdr.ip_p = IPPROTO_OSPF; 80 ip_hdr.ip_sum = 0; 81 ip_hdr.ip_src = iface->addr; 82 ip_hdr.ip_dst = dst->sin_addr; 83 84 /* setup buffer */ 85 bzero(&msg, sizeof(msg)); 86 iov[0].iov_base = &ip_hdr; 87 iov[0].iov_len = sizeof(ip_hdr); 88 iov[1].iov_base = ibuf_data(buf); 89 iov[1].iov_len = ibuf_size(buf); 90 msg.msg_name = dst; 91 msg.msg_namelen = sizeof(*dst); 92 msg.msg_iov = iov; 93 msg.msg_iovlen = 2; 94 95 /* set outgoing interface for multicast traffic */ 96 if (IN_MULTICAST(ntohl(dst->sin_addr.s_addr))) 97 if (if_set_mcast(iface) == -1) 98 return (-1); 99 100 if (sendmsg(iface->fd, &msg, 0) == -1) { 101 log_warn("%s: error sending packet to %s on interface %s", 102 __func__, inet_ntoa(ip_hdr.ip_dst), iface->name); 103 return (-1); 104 } 105 106 return (0); 107 } 108 109 void 110 recv_packet(int fd, short event, void *bula) 111 { 112 union { 113 struct cmsghdr hdr; 114 char buf[CMSG_SPACE(sizeof(struct sockaddr_dl))]; 115 } cmsgbuf; 116 struct msghdr msg; 117 struct iovec iov; 118 struct ip ip_hdr; 119 struct in_addr addr; 120 struct ospfd_conf *xconf = bula; 121 struct ospf_hdr *ospf_hdr; 122 struct iface *iface; 123 struct nbr *nbr = NULL; 124 char *buf; 125 struct cmsghdr *cmsg; 126 ssize_t r; 127 u_int16_t len; 128 int l; 129 unsigned int ifindex = 0; 130 131 if (event != EV_READ) 132 return; 133 134 if (recv_buf == NULL) 135 if ((recv_buf = malloc(READ_BUF_SIZE)) == NULL) 136 fatal(__func__); 137 138 /* setup buffer */ 139 bzero(&msg, sizeof(msg)); 140 iov.iov_base = buf = recv_buf; 141 iov.iov_len = READ_BUF_SIZE; 142 msg.msg_iov = &iov; 143 msg.msg_iovlen = 1; 144 msg.msg_control = &cmsgbuf.buf; 145 msg.msg_controllen = sizeof(cmsgbuf.buf); 146 147 if ((r = recvmsg(fd, &msg, 0)) == -1) { 148 if (errno != EAGAIN && errno != EINTR) 149 log_debug("recv_packet: read error: %s", 150 strerror(errno)); 151 return; 152 } 153 for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; 154 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 155 if (cmsg->cmsg_level == IPPROTO_IP && 156 cmsg->cmsg_type == IP_RECVIF) { 157 ifindex = ((struct sockaddr_dl *) 158 CMSG_DATA(cmsg))->sdl_index; 159 break; 160 } 161 } 162 163 len = (u_int16_t)r; 164 165 /* IP header sanity checks */ 166 if (len < sizeof(ip_hdr)) { 167 log_warnx("recv_packet: bad packet size"); 168 return; 169 } 170 memcpy(&ip_hdr, buf, sizeof(ip_hdr)); 171 if ((l = ip_hdr_sanity_check(&ip_hdr, len)) == -1) 172 return; 173 buf += l; 174 len -= l; 175 176 /* find a matching interface */ 177 if ((iface = find_iface(xconf, ifindex, ip_hdr.ip_src)) == NULL) { 178 /* XXX add a counter here */ 179 return; 180 } 181 182 /* 183 * Packet needs to be sent to AllSPFRouters or AllDRouters 184 * or to the address of the interface itself. 185 * AllDRouters is only valid for DR and BDR but this is checked later. 186 */ 187 inet_aton(AllSPFRouters, &addr); 188 if (ip_hdr.ip_dst.s_addr != addr.s_addr) { 189 inet_aton(AllDRouters, &addr); 190 if (ip_hdr.ip_dst.s_addr != addr.s_addr) { 191 if (ip_hdr.ip_dst.s_addr != iface->addr.s_addr) { 192 log_debug("recv_packet: packet sent to wrong " 193 "address %s, interface %s", 194 inet_ntoa(ip_hdr.ip_dst), iface->name); 195 return; 196 } 197 } 198 } 199 200 /* OSPF header sanity checks */ 201 if (len < sizeof(*ospf_hdr)) { 202 log_debug("recv_packet: bad packet size"); 203 return; 204 } 205 ospf_hdr = (struct ospf_hdr *)buf; 206 207 if ((l = ospf_hdr_sanity_check(&ip_hdr, ospf_hdr, len, iface)) == -1) 208 return; 209 210 nbr = nbr_find_id(iface, ospf_hdr->rtr_id); 211 if (ospf_hdr->type != PACKET_TYPE_HELLO && nbr == NULL) { 212 log_debug("recv_packet: unknown neighbor ID"); 213 return; 214 } 215 216 if (auth_validate(buf, len, iface, nbr)) { 217 if (nbr == NULL) 218 log_warnx("recv_packet: authentication error, " 219 "interface %s", iface->name); 220 else 221 log_warnx("recv_packet: authentication error, " 222 "neighbor ID %s interface %s", 223 inet_ntoa(nbr->id), iface->name); 224 return; 225 } 226 227 buf += sizeof(*ospf_hdr); 228 len = l - sizeof(*ospf_hdr); 229 230 /* switch OSPF packet type */ 231 switch (ospf_hdr->type) { 232 case PACKET_TYPE_HELLO: 233 inet_aton(AllSPFRouters, &addr); 234 if (iface->type == IF_TYPE_BROADCAST || 235 iface->type == IF_TYPE_POINTOPOINT) 236 if (ip_hdr.ip_dst.s_addr != addr.s_addr) { 237 log_warnx("%s: hello ignored on interface %s, " 238 "invalid destination IP address %s", 239 __func__, iface->name, 240 inet_ntoa(ip_hdr.ip_dst)); 241 break; 242 } 243 244 recv_hello(iface, ip_hdr.ip_src, ospf_hdr->rtr_id, buf, len); 245 break; 246 case PACKET_TYPE_DD: 247 recv_db_description(nbr, buf, len); 248 break; 249 case PACKET_TYPE_LS_REQUEST: 250 recv_ls_req(nbr, buf, len); 251 break; 252 case PACKET_TYPE_LS_UPDATE: 253 recv_ls_update(nbr, buf, len); 254 break; 255 case PACKET_TYPE_LS_ACK: 256 recv_ls_ack(nbr, buf, len); 257 break; 258 default: 259 log_debug("recv_packet: unknown OSPF packet type, interface %s", 260 iface->name); 261 } 262 } 263 264 int 265 ip_hdr_sanity_check(const struct ip *ip_hdr, u_int16_t len) 266 { 267 if (ntohs(ip_hdr->ip_len) != len) { 268 log_debug("recv_packet: invalid IP packet length %u", 269 ntohs(ip_hdr->ip_len)); 270 return (-1); 271 } 272 273 if (ip_hdr->ip_p != IPPROTO_OSPF) 274 /* this is enforced by the socket itself */ 275 fatalx("recv_packet: invalid IP proto"); 276 277 return (ip_hdr->ip_hl << 2); 278 } 279 280 int 281 ospf_hdr_sanity_check(const struct ip *ip_hdr, struct ospf_hdr *ospf_hdr, 282 u_int16_t len, const struct iface *iface) 283 { 284 struct in_addr addr; 285 286 if (ospf_hdr->version != OSPF_VERSION) { 287 log_debug("recv_packet: invalid OSPF version %d", 288 ospf_hdr->version); 289 return (-1); 290 } 291 292 if (ntohs(ospf_hdr->len) > len || 293 len <= sizeof(struct ospf_hdr)) { 294 log_debug("recv_packet: invalid OSPF packet length %d", 295 ntohs(ospf_hdr->len)); 296 return (-1); 297 } 298 299 if (iface->type != IF_TYPE_VIRTUALLINK) { 300 if (ospf_hdr->area_id != iface->area->id.s_addr) { 301 addr.s_addr = ospf_hdr->area_id; 302 log_debug("recv_packet: invalid area ID %s, " 303 "interface %s", inet_ntoa(addr), iface->name); 304 return (-1); 305 } 306 } else { 307 if (ospf_hdr->area_id != 0) { 308 addr.s_addr = ospf_hdr->area_id; 309 log_debug("recv_packet: invalid area ID %s, " 310 "interface %s", inet_ntoa(addr), iface->name); 311 return (-1); 312 } 313 } 314 315 if (iface->type == IF_TYPE_BROADCAST || iface->type == IF_TYPE_NBMA) { 316 if (inet_aton(AllDRouters, &addr) == 0) 317 fatalx("recv_packet: inet_aton"); 318 if (ip_hdr->ip_dst.s_addr == addr.s_addr && 319 (iface->state & IF_STA_DRORBDR) == 0) { 320 log_debug("recv_packet: invalid destination IP in " 321 "state %s, interface %s", 322 if_state_name(iface->state), iface->name); 323 return (-1); 324 } 325 } 326 327 return (ntohs(ospf_hdr->len)); 328 } 329 330 struct iface * 331 find_iface(struct ospfd_conf *xconf, unsigned int ifindex, struct in_addr src) 332 { 333 struct area *area = NULL; 334 struct iface *iface = NULL; 335 336 /* returned interface needs to be active */ 337 LIST_FOREACH(area, &xconf->area_list, entry) { 338 LIST_FOREACH(iface, &area->iface_list, entry) { 339 switch (iface->type) { 340 case IF_TYPE_VIRTUALLINK: 341 if ((src.s_addr == iface->dst.s_addr) && 342 !iface->passive) 343 return (iface); 344 break; 345 case IF_TYPE_POINTOPOINT: 346 if (ifindex == iface->ifindex && 347 !iface->passive) 348 return (iface); 349 break; 350 default: 351 if (ifindex == iface->ifindex && 352 (iface->addr.s_addr & iface->mask.s_addr) == 353 (src.s_addr & iface->mask.s_addr) && 354 !iface->passive) 355 return (iface); 356 break; 357 } 358 } 359 } 360 361 return (NULL); 362 } 363