xref: /openbsd-src/usr.sbin/ospfd/database.c (revision 4f4fe40bc9d06de09f4af934b87299ab1ee3cc66)
1 /*	$OpenBSD: database.c,v 1.38 2024/08/21 15:18:00 florian 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_add_zero(buf, sizeof(dd_hdr)) == -1)
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_pton(AF_INET, 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 	if (ibuf_set(buf, sizeof(struct ospf_hdr), &dd_hdr,
144 	    sizeof(dd_hdr)) == -1)
145 		goto fail;
146 
147 	/* update authentication and calculate checksum */
148 	if (auth_gen(buf, nbr->iface))
149 		goto fail;
150 
151 	/* transmit packet */
152 	if (send_packet(nbr->iface, buf, &dst) == -1)
153 		goto fail;
154 
155 	ibuf_free(buf);
156 	return (0);
157 fail:
158 	log_warn("%s", __func__);
159 	ibuf_free(buf);
160 	return (-1);
161 }
162 
163 void
164 recv_db_description(struct nbr *nbr, char *buf, u_int16_t len)
165 {
166 	struct db_dscrp_hdr	 dd_hdr;
167 	int			 dupe = 0;
168 
169 	if (len < sizeof(dd_hdr)) {
170 		log_warnx("recv_db_description: neighbor ID %s (%s): "
171 		    "bad packet size", inet_ntoa(nbr->id), nbr->iface->name);
172 		return;
173 	}
174 	memcpy(&dd_hdr, buf, sizeof(dd_hdr));
175 	buf += sizeof(dd_hdr);
176 	len -= sizeof(dd_hdr);
177 
178 	/* db description packet sanity checks */
179 	if (ntohs(dd_hdr.iface_mtu) > nbr->iface->mtu) {
180 		log_warnx("recv_db_description: neighbor ID %s (%s): "
181 		    "invalid MTU %d expected %d", inet_ntoa(nbr->id),
182 		    nbr->iface->name, ntohs(dd_hdr.iface_mtu),
183 		    nbr->iface->mtu);
184 		return;
185 	}
186 
187 	if (nbr->last_rx_options == dd_hdr.opts &&
188 	    nbr->last_rx_bits == dd_hdr.bits &&
189 	    ntohl(dd_hdr.dd_seq_num) == nbr->dd_seq_num - nbr->dd_master ?
190 	    1 : 0) {
191 		log_debug("recv_db_description: dupe from "
192 		    "neighbor ID %s (%s)", inet_ntoa(nbr->id),
193 		    nbr->iface->name);
194 		dupe = 1;
195 	}
196 
197 	switch (nbr->state) {
198 	case NBR_STA_DOWN:
199 	case NBR_STA_ATTEMPT:
200 	case NBR_STA_2_WAY:
201 	case NBR_STA_SNAP:
202 		log_debug("recv_db_description: neighbor ID %s (%s): "
203 		    "packet ignored in state %s", inet_ntoa(nbr->id),
204 		    nbr->iface->name, nbr_state_name(nbr->state));
205 		return;
206 	case NBR_STA_INIT:
207 		/* evaluate dr and bdr after issuing a 2-Way event */
208 		nbr_fsm(nbr, NBR_EVT_2_WAY_RCVD);
209 		if_fsm(nbr->iface, IF_EVT_NBR_CHNG);
210 		if (nbr->state != NBR_STA_XSTRT)
211 			return;
212 		/* FALLTHROUGH */
213 	case NBR_STA_XSTRT:
214 		if (dupe)
215 			return;
216 		nbr->capa_options = dd_hdr.opts;
217 		if ((nbr->capa_options & nbr->options) != nbr->options) {
218 			log_warnx("recv_db_description: neighbor ID %s (%s) "
219 			    "sent inconsistent options %x vs. %x",
220 			    inet_ntoa(nbr->id), nbr->iface->name,
221 			    nbr->capa_options, nbr->options);
222 		}
223 		/*
224 		 * check bits: either I,M,MS or only M
225 		 */
226 		if (dd_hdr.bits == (OSPF_DBD_I | OSPF_DBD_M | OSPF_DBD_MS)) {
227 			/* if nbr Router ID is larger than own -> slave */
228 			if ((ntohl(nbr->id.s_addr)) >
229 			    ntohl(ospfe_router_id())) {
230 				/* slave */
231 				nbr->dd_master = 0;
232 				nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
233 
234 				/* event negotiation done */
235 				nbr_fsm(nbr, NBR_EVT_NEG_DONE);
236 			}
237 		} else if (!(dd_hdr.bits & (OSPF_DBD_I | OSPF_DBD_MS))) {
238 			/* M only case: we are master */
239 			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
240 				log_warnx("recv_db_description: "
241 				    "neighbor ID %s (%s): "
242 				    "invalid seq num, mine %x his %x",
243 				    inet_ntoa(nbr->id), nbr->iface->name,
244 				    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
245 				return;
246 			}
247 			nbr->dd_seq_num++;
248 
249 			/* event negotiation done */
250 			nbr_fsm(nbr, NBR_EVT_NEG_DONE);
251 
252 			/* this packet may already have data so pass it on */
253 			if (len > 0) {
254 				nbr->dd_pending++;
255 				ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid,
256 				    0, buf, len);
257 			}
258 		} else {
259 			/* ignore packet */
260 			log_debug("recv_db_description: neighbor ID %s (%s): "
261 			    "packet ignored in state %s (bad flags)",
262 			    inet_ntoa(nbr->id), nbr->iface->name,
263 			    nbr_state_name(nbr->state));
264 		}
265 		break;
266 	case NBR_STA_XCHNG:
267 	case NBR_STA_LOAD:
268 	case NBR_STA_FULL:
269 		if (dd_hdr.bits & OSPF_DBD_I ||
270 		    !(dd_hdr.bits & OSPF_DBD_MS) == !nbr->dd_master) {
271 			log_warnx("recv_db_description: neighbor ID %s (%s): "
272 			    "seq num mismatch, bad flags", inet_ntoa(nbr->id),
273 			    nbr->iface->name);
274 			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
275 			return;
276 		}
277 
278 		if (nbr->last_rx_options != dd_hdr.opts) {
279 			log_warnx("recv_db_description: neighbor ID %s (%s): "
280 			    "seq num mismatch, bad options",
281 			    inet_ntoa(nbr->id), nbr->iface->name);
282 			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
283 			return;
284 		}
285 
286 		if (dupe) {
287 			if (!nbr->dd_master)
288 				/* retransmit */
289 				start_db_tx_timer(nbr);
290 			return;
291 		}
292 
293 		if (nbr->state != NBR_STA_XCHNG) {
294 			log_warnx("recv_db_description: neighbor ID %s (%s): "
295 			    "invalid seq num, mine %x his %x",
296 			    inet_ntoa(nbr->id), nbr->iface->name,
297 			    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
298 			nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
299 			return;
300 		}
301 
302 		/* sanity check dd seq number */
303 		if (nbr->dd_master) {
304 			/* master */
305 			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num) {
306 				log_warnx("recv_db_description: "
307 				    "neighbor ID %s (%s): "
308 				    "invalid seq num, mine %x his %x, master",
309 				    inet_ntoa(nbr->id), nbr->iface->name,
310 				    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
311 				nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
312 				return;
313 			}
314 			nbr->dd_seq_num++;
315 		} else {
316 			/* slave */
317 			if (ntohl(dd_hdr.dd_seq_num) != nbr->dd_seq_num + 1) {
318 				log_warnx("recv_db_description: "
319 				    "neighbor ID %s (%s): "
320 				    "invalid seq num, mine %x his %x, slave",
321 				    inet_ntoa(nbr->id), nbr->iface->name,
322 				    nbr->dd_seq_num, ntohl(dd_hdr.dd_seq_num));
323 				nbr_fsm(nbr, NBR_EVT_SEQ_NUM_MIS);
324 				return;
325 			}
326 			nbr->dd_seq_num = ntohl(dd_hdr.dd_seq_num);
327 		}
328 
329 		/* forward to RDE and let it decide which LSAs to request */
330 		if (len > 0) {
331 			nbr->dd_pending++;
332 			ospfe_imsg_compose_rde(IMSG_DD, nbr->peerid, 0,
333 			    buf, len);
334 		}
335 
336 		/* next packet */
337 		db_sum_list_next(nbr);
338 		start_db_tx_timer(nbr);
339 
340 		if (!(dd_hdr.bits & OSPF_DBD_M) &&
341 		    TAILQ_EMPTY(&nbr->db_sum_list))
342 			if (!nbr->dd_master || !nbr->dd_more)
343 				nbr_fsm(nbr, NBR_EVT_XCHNG_DONE);
344 		break;
345 	default:
346 		fatalx("recv_db_description: unknown neighbor state");
347 	}
348 
349 	nbr->last_rx_options = dd_hdr.opts;
350 	nbr->last_rx_bits = dd_hdr.bits;
351 }
352 
353 void
354 db_sum_list_add(struct nbr *nbr, struct lsa_hdr *lsa)
355 {
356 	struct lsa_entry	*le;
357 
358 	if ((le = calloc(1, sizeof(*le))) == NULL)
359 		fatal("db_sum_list_add");
360 
361 	TAILQ_INSERT_TAIL(&nbr->db_sum_list, le, entry);
362 	le->le_lsa = lsa;
363 }
364 
365 void
366 db_sum_list_next(struct nbr *nbr)
367 {
368 	struct lsa_entry	*le;
369 
370 	while ((le = TAILQ_FIRST(&nbr->db_sum_list)) != nbr->dd_end) {
371 		TAILQ_REMOVE(&nbr->db_sum_list, le, entry);
372 		free(le->le_lsa);
373 		free(le);
374 	}
375 }
376 
377 void
378 db_sum_list_clr(struct nbr *nbr)
379 {
380 	nbr->dd_end = NULL;
381 	db_sum_list_next(nbr);
382 }
383 
384 /* timers */
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