jcs's openbsd hax
openbsd
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
34extern struct ospfd_conf *oeconf;
35
36void db_sum_list_next(struct nbr *);
37
38/* database description packet handling */
39int
40send_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);
157fail:
158 log_warn("%s", __func__);
159 ibuf_free(buf);
160 return (-1);
161}
162
163void
164recv_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
353void
354db_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
365void
366db_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
377void
378db_sum_list_clr(struct nbr *nbr)
379{
380 nbr->dd_end = NULL;
381 db_sum_list_next(nbr);
382}
383
384/* timers */
385void
386db_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
420void
421start_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
433void
434stop_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}