1 /* $OpenBSD: database.c,v 1.35 2021/11/03 21:40:03 sthen Exp $ */ 2 3 /* 4 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> 5 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/socket.h> 22 #include <netinet/in.h> 23 #include <netinet/ip.h> 24 #include <arpa/inet.h> 25 #include <stdlib.h> 26 #include <string.h> 27 #include <unistd.h> 28 29 #include "ospfd.h" 30 #include "ospf.h" 31 #include "log.h" 32 #include "ospfe.h" 33 34 extern struct ospfd_conf *oeconf; 35 36 void db_sum_list_next(struct nbr *); 37 38 /* database description packet handling */ 39 int 40 send_db_description(struct nbr *nbr) 41 { 42 struct sockaddr_in dst; 43 struct db_dscrp_hdr dd_hdr; 44 struct lsa_entry *le, *nle; 45 struct ibuf *buf; 46 u_int8_t bits = 0; 47 48 if ((buf = ibuf_open(nbr->iface->mtu - sizeof(struct ip))) == NULL) 49 fatal("send_db_description"); 50 51 /* OSPF header */ 52 if (gen_ospf_hdr(buf, nbr->iface, PACKET_TYPE_DD)) 53 goto fail; 54 55 /* reserve space for database description header */ 56 if (ibuf_reserve(buf, sizeof(dd_hdr)) == NULL) 57 goto fail; 58 59 switch (nbr->state) { 60 case NBR_STA_DOWN: 61 case NBR_STA_ATTEMPT: 62 case NBR_STA_INIT: 63 case NBR_STA_2_WAY: 64 case NBR_STA_SNAP: 65 log_debug("send_db_description: neighbor ID %s (%s): " 66 "cannot send packet in state %s", inet_ntoa(nbr->id), 67 nbr->iface->name, nbr_state_name(nbr->state)); 68 goto fail; 69 case NBR_STA_XSTRT: 70 bits |= OSPF_DBD_MS | OSPF_DBD_M | OSPF_DBD_I; 71 nbr->dd_more = 1; 72 break; 73 case NBR_STA_XCHNG: 74 if (nbr->dd_master) 75 bits |= OSPF_DBD_MS; 76 else 77 bits &= ~OSPF_DBD_MS; 78 79 if (TAILQ_EMPTY(&nbr->db_sum_list)) { 80 bits &= ~OSPF_DBD_M; 81 nbr->dd_more = 0; 82 } else { 83 bits |= OSPF_DBD_M; 84 nbr->dd_more = 1; 85 } 86 87 bits &= ~OSPF_DBD_I; 88 89 /* build LSA list, keep space for a possible md5 sum */ 90 for (le = TAILQ_FIRST(&nbr->db_sum_list); le != NULL && 91 ibuf_left(buf) >= MD5_DIGEST_LENGTH + sizeof(struct lsa_hdr); 92 le = nle) { 93 nbr->dd_end = nle = TAILQ_NEXT(le, entry); 94 if (ibuf_add(buf, le->le_lsa, sizeof(struct lsa_hdr))) 95 goto fail; 96 } 97 break; 98 case NBR_STA_LOAD: 99 case NBR_STA_FULL: 100 if (nbr->dd_master) 101 bits |= OSPF_DBD_MS; 102 else 103 bits &= ~OSPF_DBD_MS; 104 bits &= ~OSPF_DBD_M; 105 bits &= ~OSPF_DBD_I; 106 107 nbr->dd_more = 0; 108 break; 109 default: 110 fatalx("send_db_description: unknown neighbor state"); 111 } 112 113 /* set destination */ 114 dst.sin_family = AF_INET; 115 dst.sin_len = sizeof(struct sockaddr_in); 116 117 switch (nbr->iface->type) { 118 case IF_TYPE_POINTOPOINT: 119 inet_aton(AllSPFRouters, &dst.sin_addr); 120 dd_hdr.iface_mtu = htons(nbr->iface->mtu); 121 break; 122 case IF_TYPE_BROADCAST: 123 dst.sin_addr = nbr->addr; 124 dd_hdr.iface_mtu = htons(nbr->iface->mtu); 125 break; 126 case IF_TYPE_NBMA: 127 case IF_TYPE_POINTOMULTIPOINT: 128 /* XXX not supported */ 129 break; 130 case IF_TYPE_VIRTUALLINK: 131 dst.sin_addr = nbr->iface->dst; 132 dd_hdr.iface_mtu = 0; 133 break; 134 default: 135 fatalx("send_db_description: unknown interface type"); 136 } 137 138 /* XXX button or not for opaque LSA? */ 139 dd_hdr.opts = area_ospf_options(nbr->iface->area) | OSPF_OPTION_O; 140 dd_hdr.bits = bits; 141 dd_hdr.dd_seq_num = htonl(nbr->dd_seq_num); 142 143 memcpy(ibuf_seek(buf, sizeof(struct ospf_hdr), sizeof(dd_hdr)), 144 &dd_hdr, sizeof(dd_hdr)); 145 146 /* update authentication and calculate checksum */ 147 if (auth_gen(buf, nbr->iface)) 148 goto fail; 149 150 /* transmit packet */ 151 if (send_packet(nbr->iface, buf, &dst) == -1) 152 goto fail; 153 154 ibuf_free(buf); 155 return (0); 156 fail: 157 log_warn("%s", __func__); 158 ibuf_free(buf); 159 return (-1); 160 } 161 162 void 163 recv_db_description(struct nbr *nbr, char *buf, u_int16_t len) 164 { 165 struct db_dscrp_hdr dd_hdr; 166 int dupe = 0; 167 168 if (len < sizeof(dd_hdr)) { 169 log_warnx("recv_db_description: neighbor ID %s (%s): " 170 "bad packet size", inet_ntoa(nbr->id), nbr->iface->name); 171 return; 172 } 173 memcpy(&dd_hdr, buf, sizeof(dd_hdr)); 174 buf += sizeof(dd_hdr); 175 len -= sizeof(dd_hdr); 176 177 /* db description packet sanity checks */ 178 if (ntohs(dd_hdr.iface_mtu) > nbr->iface->mtu) { 179 log_warnx("recv_db_description: neighbor ID %s (%s): " 180 "invalid MTU %d expected %d", inet_ntoa(nbr->id), 181 nbr->iface->name, ntohs(dd_hdr.iface_mtu), 182 nbr->iface->mtu); 183 return; 184 } 185 186 if (nbr->last_rx_options == dd_hdr.opts && 187 nbr->last_rx_bits == dd_hdr.bits && 188 ntohl(dd_hdr.dd_seq_num) == nbr->dd_seq_num - nbr->dd_master ? 189 1 : 0) { 190 log_debug("recv_db_description: dupe from " 191 "neighbor ID %s (%s)", inet_ntoa(nbr->id), 192 nbr->iface->name); 193 dupe = 1; 194 } 195 196 switch (nbr->state) { 197 case NBR_STA_DOWN: 198 case NBR_STA_ATTEMPT: 199 case NBR_STA_2_WAY: 200 case NBR_STA_SNAP: 201 log_debug("recv_db_description: neighbor ID %s (%s): " 202 "packet ignored in state %s", inet_ntoa(nbr->id), 203 nbr->iface->name, nbr_state_name(nbr->state)); 204 return; 205 case NBR_STA_INIT: 206 /* evaluate dr and bdr after issuing a 2-Way event */ 207 nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD); 208 if_fsm(nbr->iface, IF_EVT_NBR_CHNG); 209 if (nbr->state != NBR_STA_XSTRT) 210 return; 211 /* FALLTHROUGH */ 212 case NBR_STA_XSTRT: 213 if (dupe) 214 return; 215 nbr->capa_options = dd_hdr.opts; 216 if ((nbr->capa_options & nbr->options) != nbr->options) { 217 log_warnx("recv_db_description: neighbor ID %s (%s) " 218 "sent inconsistent options %x vs. %x", 219 inet_ntoa(nbr->id), nbr->iface->name, 220 nbr->capa_options, nbr->options); 221 } 222 /* 223 * check bits: either I,M,MS or only M 224 */ 225 if (dd_hdr.bits == (OSPF_DBD_I | OSPF_DBD_M | OSPF_DBD_MS)) { 226 /* if nbr Router ID is larger than own -> slave */ 227 if ((ntohl(nbr->id.s_addr)) > 228 ntohl(ospfe_router_id())) { 229 /* slave */ 230 nbr->dd_master = 0; 231 nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num); 232 233 /* event negotiation done */ 234 nbr_fsm(nbr, NBR_EVT_NEG_DONE); 235 } 236 } else if (!(dd_hdr.bits & (OSPF_DBD_I | OSPF_DBD_MS))) { 237 /* M only case: we are master */ 238 if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) { 239 log_warnx("recv_db_description: " 240 "neighbor ID %s (%s): " 241 "invalid seq num, mine %x his %x", 242 inet_ntoa(nbr->id), nbr->iface->name, 243 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num)); 244 return; 245 } 246 nbr->dd_seq_num++; 247 248 /* event negotiation done */ 249 nbr_fsm(nbr, NBR_EVT_NEG_DONE); 250 251 /* this packet may already have data so pass it on */ 252 if (len > 0) { 253 nbr->dd_pending++; 254 ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 255 0, buf, len); 256 } 257 } else { 258 /* ignore packet */ 259 log_debug("recv_db_description: neighbor ID %s (%s): " 260 "packet ignored in state %s (bad flags)", 261 inet_ntoa(nbr->id), nbr->iface->name, 262 nbr_state_name(nbr->state)); 263 } 264 break; 265 case NBR_STA_XCHNG: 266 case NBR_STA_LOAD: 267 case NBR_STA_FULL: 268 if (dd_hdr.bits & OSPF_DBD_I || 269 !(dd_hdr.bits & OSPF_DBD_MS) == !nbr->dd_master) { 270 log_warnx("recv_db_description: neighbor ID %s (%s): " 271 "seq num mismatch, bad flags", inet_ntoa(nbr->id), 272 nbr->iface->name); 273 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); 274 return; 275 } 276 277 if (nbr->last_rx_options != dd_hdr.opts) { 278 log_warnx("recv_db_description: neighbor ID %s (%s): " 279 "seq num mismatch, bad options", 280 inet_ntoa(nbr->id), nbr->iface->name); 281 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); 282 return; 283 } 284 285 if (dupe) { 286 if (!nbr->dd_master) 287 /* retransmit */ 288 start_db_tx_timer(nbr); 289 return; 290 } 291 292 if (nbr->state != NBR_STA_XCHNG) { 293 log_warnx("recv_db_description: neighbor ID %s (%s): " 294 "invalid seq num, mine %x his %x", 295 inet_ntoa(nbr->id), nbr->iface->name, 296 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num)); 297 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); 298 return; 299 } 300 301 /* sanity check dd seq number */ 302 if (nbr->dd_master) { 303 /* master */ 304 if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) { 305 log_warnx("recv_db_description: " 306 "neighbor ID %s (%s): " 307 "invalid seq num, mine %x his %x, master", 308 inet_ntoa(nbr->id), nbr->iface->name, 309 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num)); 310 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); 311 return; 312 } 313 nbr->dd_seq_num++; 314 } else { 315 /* slave */ 316 if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num + 1) { 317 log_warnx("recv_db_description: " 318 "neighbor ID %s (%s): " 319 "invalid seq num, mine %x his %x, slave", 320 inet_ntoa(nbr->id), nbr->iface->name, 321 nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num)); 322 nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS); 323 return; 324 } 325 nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num); 326 } 327 328 /* forward to RDE and let it decide which LSAs to request */ 329 if (len > 0) { 330 nbr->dd_pending++; 331 ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 0, 332 buf, len); 333 } 334 335 /* next packet */ 336 db_sum_list_next(nbr); 337 start_db_tx_timer(nbr); 338 339 if (!(dd_hdr.bits & OSPF_DBD_M) && 340 TAILQ_EMPTY(&nbr->db_sum_list)) 341 if (!nbr->dd_master || !nbr->dd_more) 342 nbr_fsm(nbr, NBR_EVT_XCHNG_DONE); 343 break; 344 default: 345 fatalx("recv_db_description: unknown neighbor state"); 346 } 347 348 nbr->last_rx_options = dd_hdr.opts; 349 nbr->last_rx_bits = dd_hdr.bits; 350 } 351 352 void 353 db_sum_list_add(struct nbr *nbr, struct lsa_hdr *lsa) 354 { 355 struct lsa_entry *le; 356 357 if ((le = calloc(1, sizeof(*le))) == NULL) 358 fatal("db_sum_list_add"); 359 360 TAILQ_INSERT_TAIL(&nbr->db_sum_list, le, entry); 361 le->le_lsa = lsa; 362 } 363 364 void 365 db_sum_list_next(struct nbr *nbr) 366 { 367 struct lsa_entry *le; 368 369 while ((le = TAILQ_FIRST(&nbr->db_sum_list)) != nbr->dd_end) { 370 TAILQ_REMOVE(&nbr->db_sum_list, le, entry); 371 free(le->le_lsa); 372 free(le); 373 } 374 } 375 376 void 377 db_sum_list_clr(struct nbr *nbr) 378 { 379 nbr->dd_end = NULL; 380 db_sum_list_next(nbr); 381 } 382 383 /* timers */ 384 /* ARGSUSED */ 385 void 386 db_tx_timer(int fd, short event, void *arg) 387 { 388 struct nbr *nbr = arg; 389 struct timeval tv; 390 391 switch (nbr->state) { 392 case NBR_STA_DOWN: 393 case NBR_STA_ATTEMPT: 394 case NBR_STA_INIT: 395 case NBR_STA_2_WAY: 396 case NBR_STA_SNAP: 397 return ; 398 case NBR_STA_XSTRT: 399 case NBR_STA_XCHNG: 400 case NBR_STA_LOAD: 401 case NBR_STA_FULL: 402 send_db_description(nbr); 403 break; 404 default: 405 log_debug("db_tx_timer: neighbor ID %s (%s): " 406 "unknown neighbor state", 407 inet_ntoa(nbr->id), nbr->iface->name); 408 break; 409 } 410 411 /* reschedule db_tx_timer but only in master mode */ 412 if (nbr->dd_master) { 413 timerclear(&tv); 414 tv.tv_sec = nbr->iface->rxmt_interval; 415 if (evtimer_add(&nbr->db_tx_timer, &tv) == -1) 416 fatal("db_tx_timer"); 417 } 418 } 419 420 void 421 start_db_tx_timer(struct nbr *nbr) 422 { 423 struct timeval tv; 424 425 if (nbr == nbr->iface->self) 426 return; 427 428 timerclear(&tv); 429 if (evtimer_add(&nbr->db_tx_timer, &tv) == -1) 430 fatal("start_db_tx_timer"); 431 } 432 433 void 434 stop_db_tx_timer(struct nbr *nbr) 435 { 436 if (nbr == nbr->iface->self) 437 return; 438 439 if (evtimer_del(&nbr->db_tx_timer) == -1) 440 fatal("stop_db_tx_timer"); 441 } 442