1 /* $OpenBSD: packet.c,v 1.19 2006/02/19 18:52:06 norby 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 22 #include <netinet/in.h> 23 #include <netinet/in_systm.h> 24 #include <netinet/ip.h> 25 #include <arpa/inet.h> 26 27 #include <errno.h> 28 #include <event.h> 29 #include <stdlib.h> 30 #include <string.h> 31 32 #include "ospfd.h" 33 #include "ospf.h" 34 #include "log.h" 35 #include "ospfe.h" 36 37 int ip_hdr_sanity_check(const struct ip *, u_int16_t); 38 int ospf_hdr_sanity_check(const struct ip *, 39 struct ospf_hdr *, u_int16_t, const struct iface *); 40 struct iface *find_iface(struct ospfd_conf *, struct in_addr); 41 42 int 43 gen_ospf_hdr(struct buf *buf, struct iface *iface, u_int8_t type) 44 { 45 struct ospf_hdr ospf_hdr; 46 47 bzero(&ospf_hdr, sizeof(ospf_hdr)); 48 ospf_hdr.version = OSPF_VERSION; 49 ospf_hdr.type = type; 50 ospf_hdr.rtr_id = ospfe_router_id(); 51 if (iface->type != IF_TYPE_VIRTUALLINK) 52 ospf_hdr.area_id = iface->area->id.s_addr; 53 ospf_hdr.auth_type = htons(iface->auth_type); 54 55 return (buf_add(buf, &ospf_hdr, sizeof(ospf_hdr))); 56 } 57 58 /* send and receive packets */ 59 int 60 send_packet(struct iface *iface, char *pkt, int len, struct sockaddr_in *dst) 61 { 62 /* set outgoing interface for multicast traffic */ 63 if (IN_MULTICAST(ntohl(dst->sin_addr.s_addr))) 64 if (if_set_mcast(iface) == -1) { 65 log_warn("send_packet: error setting multicast " 66 "interface, %s", iface->name); 67 return (-1); 68 } 69 70 if (sendto(iface->fd, pkt, len, 0, 71 (struct sockaddr *)dst, sizeof(*dst)) == -1 ) { 72 log_warn("send_packet: error sending packet on interface %s", 73 iface->name); 74 return (-1); 75 } 76 77 return (0); 78 } 79 80 void 81 recv_packet(int fd, short event, void *bula) 82 { 83 struct ospfd_conf *xconf = bula; 84 struct ip ip_hdr; 85 struct ospf_hdr *ospf_hdr; 86 struct iface *iface; 87 struct nbr *nbr = NULL; 88 struct in_addr addr; 89 char *buf; 90 ssize_t r; 91 u_int16_t len; 92 int l; 93 94 if (event != EV_READ) 95 return; 96 97 /* setup buffer */ 98 buf = pkt_ptr; 99 100 if ((r = recvfrom(fd, buf, READ_BUF_SIZE, 0, NULL, NULL)) == -1) { 101 if (errno != EAGAIN && errno != EINTR) 102 log_debug("recv_packet: error receiving packet"); 103 return; 104 } 105 106 len = (u_int16_t)r; 107 108 /* IP header sanity checks */ 109 if (len < sizeof(ip_hdr)) { 110 log_warnx("recv_packet: bad packet size"); 111 return; 112 } 113 memcpy(&ip_hdr, buf, sizeof(ip_hdr)); 114 if ((l = ip_hdr_sanity_check(&ip_hdr, len)) == -1) 115 return; 116 buf += l; 117 len -= l; 118 119 /* find a matching interface */ 120 if ((iface = find_iface(xconf, ip_hdr.ip_src)) == NULL) { 121 log_debug("recv_packet: cannot find valid interface"); 122 return; 123 } 124 125 /* 126 * Packet needs to be sent to AllSPFRouters or AllDRouters 127 * or to the address of the interface itself. 128 * AllDRouters is only valid for DR and BDR but this is checked later. 129 */ 130 inet_aton(AllSPFRouters, &addr); 131 if (ip_hdr.ip_dst.s_addr != addr.s_addr) { 132 inet_aton(AllDRouters, &addr); 133 if (ip_hdr.ip_dst.s_addr != addr.s_addr) { 134 if (ip_hdr.ip_dst.s_addr != iface->addr.s_addr) { 135 log_debug("recv_packet: packet sent to wrong " 136 "address %s, interface %s", 137 inet_ntoa(ip_hdr.ip_dst), iface->name); 138 return; 139 } 140 } 141 } 142 143 /* OSPF header sanity checks */ 144 if (len < sizeof(*ospf_hdr)) { 145 log_warnx("recv_packet: bad packet size"); 146 return; 147 } 148 ospf_hdr = (struct ospf_hdr *)buf; 149 150 if ((l = ospf_hdr_sanity_check(&ip_hdr, ospf_hdr, len, iface)) == -1) 151 return; 152 153 nbr = nbr_find_id(iface, ospf_hdr->rtr_id); 154 if (ospf_hdr->type != PACKET_TYPE_HELLO && nbr == NULL) { 155 log_debug("recv_packet: unknown neighbor ID"); 156 return; 157 } 158 159 if (auth_validate(buf, len, iface, nbr)) { 160 log_warnx("recv_packet: authentication error, " 161 "interface %s", iface->name); 162 return; 163 } 164 165 buf += sizeof(*ospf_hdr); 166 len = l - sizeof(*ospf_hdr); 167 168 /* switch OSPF packet type */ 169 switch (ospf_hdr->type) { 170 case PACKET_TYPE_HELLO: 171 inet_aton(AllDRouters, &addr); 172 if (ip_hdr.ip_dst.s_addr == addr.s_addr) { 173 log_debug("recv_packet: invalid destination IP " 174 "address"); 175 break; 176 } 177 178 recv_hello(iface, ip_hdr.ip_src, ospf_hdr->rtr_id, buf, len); 179 break; 180 case PACKET_TYPE_DD: 181 recv_db_description(nbr, buf, len); 182 break; 183 case PACKET_TYPE_LS_REQUEST: 184 recv_ls_req(nbr, buf, len); 185 break; 186 case PACKET_TYPE_LS_UPDATE: 187 recv_ls_update(nbr, buf, len); 188 break; 189 case PACKET_TYPE_LS_ACK: 190 recv_ls_ack(nbr, buf, len); 191 break; 192 default: 193 log_debug("recv_packet: unknown OSPF packet type, interface %s", 194 iface->name); 195 } 196 } 197 198 int 199 ip_hdr_sanity_check(const struct ip *ip_hdr, u_int16_t len) 200 { 201 if (ntohs(ip_hdr->ip_len) != len) { 202 log_debug("recv_packet: invalid IP packet length %u", 203 ntohs(ip_hdr->ip_len)); 204 return (-1); 205 } 206 207 if (ip_hdr->ip_p != IPPROTO_OSPF) 208 /* this is enforced by the socket itself */ 209 fatalx("recv_packet: invalid IP proto"); 210 211 return (ip_hdr->ip_hl << 2); 212 } 213 214 int 215 ospf_hdr_sanity_check(const struct ip *ip_hdr, struct ospf_hdr *ospf_hdr, 216 u_int16_t len, const struct iface *iface) 217 { 218 struct in_addr addr; 219 220 if (ospf_hdr->version != OSPF_VERSION) { 221 log_debug("recv_packet: invalid OSPF version %d", 222 ospf_hdr->version); 223 return (-1); 224 } 225 226 if (ntohs(ospf_hdr->len) > len || 227 len <= sizeof(struct ospf_hdr)) { 228 log_debug("recv_packet: invalid OSPF packet length %d", 229 ntohs(ospf_hdr->len)); 230 return (-1); 231 } 232 233 if (iface->type != IF_TYPE_VIRTUALLINK) { 234 if (ospf_hdr->area_id != iface->area->id.s_addr) { 235 addr.s_addr = ospf_hdr->area_id; 236 log_debug("recv_packet: invalid area ID %s, " 237 "interface %s", inet_ntoa(addr), iface->name); 238 return (-1); 239 } 240 } else { 241 if (ospf_hdr->area_id != 0) { 242 addr.s_addr = ospf_hdr->area_id; 243 log_debug("recv_packet: invalid area ID %s, " 244 "interface %s", inet_ntoa(addr), iface->name); 245 return (-1); 246 } 247 } 248 249 if (iface->type == IF_TYPE_BROADCAST || iface->type == IF_TYPE_NBMA) { 250 if (inet_aton(AllDRouters, &addr) == 0) 251 fatalx("recv_packet: inet_aton"); 252 if (ip_hdr->ip_dst.s_addr == addr.s_addr && 253 (iface->state & IF_STA_DRORBDR) == 0) { 254 log_debug("recv_packet: invalid destination IP in " 255 "state %s, interface %s", 256 if_state_name(iface->state), iface->name); 257 return (-1); 258 } 259 } 260 261 return (ntohs(ospf_hdr->len)); 262 } 263 264 struct iface * 265 find_iface(struct ospfd_conf *xconf, struct in_addr src) 266 { 267 struct area *area = NULL; 268 struct iface *iface = NULL; 269 270 /* returned interface needs to be active */ 271 LIST_FOREACH(area, &xconf->area_list, entry) { 272 LIST_FOREACH(iface, &area->iface_list, entry) { 273 if (iface->fd > 0 && 274 (iface->type == IF_TYPE_POINTOPOINT) && 275 (iface->dst.s_addr == src.s_addr) && 276 !iface->passive) 277 return (iface); 278 279 if (iface->fd > 0 && (iface->addr.s_addr & 280 iface->mask.s_addr) == (src.s_addr & 281 iface->mask.s_addr) && !iface->passive && 282 iface->type != IF_TYPE_VIRTUALLINK) { 283 return (iface); 284 } 285 } 286 } 287 288 LIST_FOREACH(area, &xconf->area_list, entry) 289 LIST_FOREACH(iface, &area->iface_list, entry) 290 if ((iface->type == IF_TYPE_VIRTUALLINK) && 291 (src.s_addr == iface->dst.s_addr)) { 292 return (iface); 293 } 294 295 return (NULL); 296 } 297