]> git.ipfire.org Git - thirdparty/bird.git/blame - proto/ospf/dbdes.c
OSPF: Reject DBDES packets with non-matching MTU
[thirdparty/bird.git] / proto / ospf / dbdes.c
CommitLineData
4364b47e
OF
1/*
2 * BIRD -- OSPF
3 *
f158bb71 4 * (c) 1999--2004 Ondrej Filip <feela@network.cz>
70945cb6
OZ
5 * (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
6 * (c) 2009--2014 CZ.NIC z.s.p.o.
4364b47e
OF
7 *
8 * Can be freely distributed and used under the terms of the GNU GPL.
9 */
10
11#include "ospf.h"
12
c3226991 13
70945cb6 14struct ospf_dbdes2_packet
c3226991 15{
70945cb6 16 struct ospf_packet hdr;
4727d1db 17 union ospf_auth2 auth;
70945cb6 18
c3226991
OZ
19 u16 iface_mtu;
20 u8 options;
70945cb6 21 u8 imms; /* I, M, MS bits */
c3226991 22 u32 ddseq;
c3226991 23
70945cb6
OZ
24 struct ospf_lsa_header lsas[];
25};
c3226991 26
70945cb6 27struct ospf_dbdes3_packet
c3226991 28{
70945cb6
OZ
29 struct ospf_packet hdr;
30
c3226991
OZ
31 u32 options;
32 u16 iface_mtu;
33 u8 padding;
70945cb6 34 u8 imms; /* I, M, MS bits */
c3226991 35 u32 ddseq;
70945cb6
OZ
36
37 struct ospf_lsa_header lsas[];
c3226991
OZ
38};
39
c3226991 40
4727d1db
OZ
41uint
42ospf_dbdes3_options(struct ospf_packet *pkt)
43{
44 struct ospf_dbdes3_packet *ps = (void *) pkt;
45 return ntohl(ps->options);
46}
47
70945cb6
OZ
48static inline uint
49ospf_dbdes_hdrlen(struct ospf_proto *p)
50{
51 return ospf_is_v2(p) ?
52 sizeof(struct ospf_dbdes2_packet) : sizeof(struct ospf_dbdes3_packet);
53}
54
70945cb6
OZ
55static void
56ospf_dbdes_body(struct ospf_proto *p, struct ospf_packet *pkt,
57 struct ospf_lsa_header **body, uint *count)
58{
59 uint plen = ntohs(pkt->length);
60 uint hlen = ospf_dbdes_hdrlen(p);
61
62 *body = ((void *) pkt) + hlen;
63 *count = (plen - hlen) / sizeof(struct ospf_lsa_header);
64}
742029eb 65
70945cb6
OZ
66static void
67ospf_dump_dbdes(struct ospf_proto *p, struct ospf_packet *pkt)
8298d780 68{
70945cb6
OZ
69 struct ospf_lsa_header *lsas;
70 uint i, lsa_count;
71 u32 pkt_ddseq;
72 u16 pkt_iface_mtu;
73 u8 pkt_imms;
8298d780 74
70945cb6
OZ
75 ASSERT(pkt->type == DBDES_P);
76 ospf_dump_common(p, pkt);
8298d780 77
70945cb6
OZ
78 if (ospf_is_v2(p))
79 {
80 struct ospf_dbdes2_packet *ps = (void *) pkt;
81 pkt_iface_mtu = ntohs(ps->iface_mtu);
82 pkt_imms = ps->imms;
83 pkt_ddseq = ntohl(ps->ddseq);
84 }
85 else /* OSPFv3 */
86 {
87 struct ospf_dbdes3_packet *ps = (void *) pkt;
88 pkt_iface_mtu = ntohs(ps->iface_mtu);
89 pkt_imms = ps->imms;
90 pkt_ddseq = ntohl(ps->ddseq);
91 }
8298d780 92
70945cb6
OZ
93 log(L_TRACE "%s: mtu %u", p->p.name, pkt_iface_mtu);
94 log(L_TRACE "%s: imms %s%s%s", p->p.name,
95 (pkt_imms & DBDES_I) ? "I " : "",
96 (pkt_imms & DBDES_M) ? "M " : "",
97 (pkt_imms & DBDES_MS) ? "MS" : "");
98 log(L_TRACE "%s: ddseq %u", p->p.name, pkt_ddseq);
8298d780 99
70945cb6
OZ
100 ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
101 for (i = 0; i < lsa_count; i++)
102 ospf_dump_lsahdr(p, lsas + i);
8298d780
OZ
103}
104
105
70945cb6 106static void
f8fefde3 107ospf_prepare_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
70945cb6
OZ
108{
109 struct ospf_iface *ifa = n->ifa;
110 struct ospf_packet *pkt;
111 uint length;
112
113 u16 iface_mtu = (ifa->type == OSPF_IT_VLINK) ? 0 : ifa->iface->mtu;
114
f8fefde3 115 /* Update DBDES buffer */
70945cb6
OZ
116 if (n->ldd_bsize != ifa->tx_length)
117 {
118 mb_free(n->ldd_buffer);
119 n->ldd_buffer = mb_allocz(n->pool, ifa->tx_length);
120 n->ldd_bsize = ifa->tx_length;
121 }
122
123 pkt = n->ldd_buffer;
124 ospf_pkt_fill_hdr(ifa, pkt, DBDES_P);
125
126 if (ospf_is_v2(p))
127 {
128 struct ospf_dbdes2_packet *ps = (void *) pkt;
129 ps->iface_mtu = htons(iface_mtu);
5a50a989 130 ps->options = ifa->oa->options | OPT_O;
70945cb6
OZ
131 ps->imms = 0; /* Will be set later */
132 ps->ddseq = htonl(n->dds);
133 length = sizeof(struct ospf_dbdes2_packet);
134 }
135 else /* OSPFv3 */
136 {
137 struct ospf_dbdes3_packet *ps = (void *) pkt;
4727d1db 138 ps->options = htonl(ifa->oa->options | (ifa->autype == OSPF_AUTH_CRYPT ? OPT_AT : 0));
70945cb6
OZ
139 ps->iface_mtu = htons(iface_mtu);
140 ps->padding = 0;
141 ps->imms = 0; /* Will be set later */
142 ps->ddseq = htonl(n->dds);
143 length = sizeof(struct ospf_dbdes3_packet);
144 }
145
f8fefde3
OZ
146 /* Prepare DBDES body */
147 if (!(n->myimms & DBDES_I) && (n->myimms & DBDES_M))
70945cb6
OZ
148 {
149 struct ospf_lsa_header *lsas;
150 struct top_hash_entry *en;
151 uint i = 0, lsa_max;
152
153 ospf_dbdes_body(p, pkt, &lsas, &lsa_max);
154 en = (void *) s_get(&(n->dbsi));
155
156 while (i < lsa_max)
157 {
158 if (!SNODE_VALID(en))
159 {
160 n->myimms &= ~DBDES_M; /* Unset More bit */
161 break;
162 }
163
164 if ((en->lsa.age < LSA_MAXAGE) &&
5a50a989
OZ
165 lsa_flooding_allowed(en->lsa_type, en->domain, ifa) &&
166 lsa_is_acceptable(en->lsa_type, n, p))
70945cb6
OZ
167 {
168 lsa_hton_hdr(&(en->lsa), lsas + i);
169 i++;
170 }
171
172 en = SNODE_NEXT(en);
173 }
174
175 s_put(&(n->dbsi), SNODE en);
176
177 length += i * sizeof(struct ospf_lsa_header);
178 }
179
180 if (ospf_is_v2(p))
181 ((struct ospf_dbdes2_packet *) pkt)->imms = n->myimms;
182 else
183 ((struct ospf_dbdes3_packet *) pkt)->imms = n->myimms;
184
185 pkt->length = htons(length);
186}
187
188static void
189ospf_do_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
190{
191 struct ospf_iface *ifa = n->ifa;
192
193 OSPF_PACKET(ospf_dump_dbdes, n->ldd_buffer,
f8fefde3 194 "DBDES packet sent to nbr %R on %s", n->rid, ifa->ifname);
70945cb6
OZ
195 sk_set_tbuf(ifa->sk, n->ldd_buffer);
196 ospf_send_to(ifa, n->ip);
197 sk_set_tbuf(ifa->sk, NULL);
198}
199
eee9cefd 200/**
70945cb6 201 * ospf_send_dbdes - transmit database description packet
8e433d6a 202 * @p: OSPF protocol instance
eee9cefd
OF
203 * @n: neighbor
204 *
c3226991 205 * Sending of a database description packet is described in 10.8 of RFC 2328.
baa5dd6c
OF
206 * Reception of each packet is acknowledged in the sequence number of another.
207 * When I send a packet to a neighbor I keep a copy in a buffer. If the neighbor
208 * does not reply, I don't create a new packet but just send the content
209 * of the buffer.
eee9cefd 210 */
4364b47e 211void
f8fefde3 212ospf_send_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
4364b47e 213{
70945cb6 214 /* RFC 2328 10.8 */
4364b47e 215
f8fefde3
OZ
216 ASSERT((n->state == NEIGHBOR_EXSTART) || (n->state == NEIGHBOR_EXCHANGE));
217
a7a7372a 218 if (n->ifa->oa->rt == NULL)
70945cb6 219 return;
054a3524 220
f8fefde3
OZ
221 ospf_prepare_dbdes(p, n);
222 ospf_do_send_dbdes(p, n);
f8fefde3 223}
12bed559 224
f8fefde3
OZ
225void
226ospf_rxmt_dbdes(struct ospf_proto *p, struct ospf_neighbor *n)
227{
228 ASSERT(n->state > NEIGHBOR_EXSTART);
e7ef86a5 229
f8fefde3
OZ
230 if (!n->ldd_buffer)
231 {
232 log(L_WARN "%s: No DBDES packet for retransmit", p->p.name);
233 ospf_neigh_sm(n, INM_SEQMIS);
234 return;
70945cb6 235 }
04c6319a 236
f8fefde3
OZ
237 /* Send last packet */
238 ospf_do_send_dbdes(p, n);
239}
48e5f32d 240
70945cb6
OZ
241static int
242ospf_process_dbdes(struct ospf_proto *p, struct ospf_packet *pkt, struct ospf_neighbor *n)
243{
244 struct ospf_iface *ifa = n->ifa;
f8fefde3
OZ
245 struct ospf_lsa_header *lsas, lsa;
246 struct top_hash_entry *en, *req;
247 const char *err_dsc = NULL;
248 u32 lsa_type, lsa_domain;
70945cb6
OZ
249 uint i, lsa_count;
250
251 ospf_dbdes_body(p, pkt, &lsas, &lsa_count);
252
253 for (i = 0; i < lsa_count; i++)
254 {
70945cb6
OZ
255 lsa_ntoh_hdr(lsas + i, &lsa);
256 lsa_get_type_domain(&lsa, ifa, &lsa_type, &lsa_domain);
b1f7229a 257
70945cb6 258 /* RFC 2328 10.6 and RFC 5340 4.2.2 */
b1f7229a 259
70945cb6 260 if (!lsa_type)
f8fefde3 261 DROP1("LSA of unknown type");
4364b47e 262
70945cb6 263 if (!oa_is_ext(ifa->oa) && (LSA_SCOPE(lsa_type) == LSA_SCOPE_AS))
f8fefde3 264 DROP1("LSA with AS scope in stub area");
4364b47e 265
70945cb6
OZ
266 /* Errata 3746 to RFC 2328 - rt-summary-LSAs forbidden in stub areas */
267 if (!oa_is_ext(ifa->oa) && (lsa_type == LSA_T_SUM_RT))
f8fefde3 268 DROP1("rt-summary-LSA in stub area");
910e557b 269
70945cb6
OZ
270 /* Not explicitly mentioned in RFC 5340 4.2.2 but makes sense */
271 if (LSA_SCOPE(lsa_type) == LSA_SCOPE_RES)
f8fefde3 272 DROP1("LSA with invalid scope");
910e557b 273
70945cb6
OZ
274 en = ospf_hash_find(p->gr, lsa_domain, lsa.id, lsa.rt, lsa_type);
275 if (!en || (lsa_comp(&lsa, &(en->lsa)) == CMP_NEWER))
276 {
6f8bbaa1 277 /* This should be splitted to ospf_lsa_lsrq_up() */
70945cb6 278 req = ospf_hash_get(n->lsrqh, lsa_domain, lsa.id, lsa.rt, lsa_type);
6d2b3211 279
70945cb6
OZ
280 if (!SNODE_VALID(req))
281 s_add_tail(&n->lsrql, SNODE req);
6d2b3211 282
6f8bbaa1
OZ
283 if (!SNODE_VALID(n->lsrqi))
284 n->lsrqi = req;
285
70945cb6 286 req->lsa = lsa;
a7a7372a 287 req->lsa_body = LSA_BODY_DUMMY;
6f8bbaa1 288
a6f79ca5
OZ
289 if (!tm_active(n->lsrq_timer))
290 tm_start(n->lsrq_timer, 0);
95eb1dba 291 }
6d2b3211 292 }
70945cb6
OZ
293
294 return 0;
295
f8fefde3
OZ
296drop:
297 LOG_LSA1("Bad LSA (Type: %04x, Id: %R, Rt: %R) in DBDES", lsa_type, lsa.id, lsa.rt);
298 LOG_LSA2(" received from nbr %R on %s - %s", n->rid, ifa->ifname, err_dsc);
299
70945cb6
OZ
300 ospf_neigh_sm(n, INM_SEQMIS);
301 return -1;
4364b47e
OF
302}
303
304void
70945cb6 305ospf_receive_dbdes(struct ospf_packet *pkt, struct ospf_iface *ifa,
c3226991 306 struct ospf_neighbor *n)
4364b47e 307{
70945cb6 308 struct ospf_proto *p = ifa->oa->po;
f8fefde3 309 const char *err_dsc = NULL;
70945cb6
OZ
310 u32 rcv_ddseq, rcv_options;
311 u16 rcv_iface_mtu;
312 u8 rcv_imms;
6f8bbaa1 313 uint plen, err_val = 0;
4364b47e 314
70945cb6
OZ
315 /* RFC 2328 10.6 */
316
317 plen = ntohs(pkt->length);
318 if (plen < ospf_dbdes_hdrlen(p))
6f8bbaa1
OZ
319 {
320 LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)", n->rid, ifa->ifname, "too short", plen);
321 return;
322 }
a6bc04d5 323
f8fefde3 324 OSPF_PACKET(ospf_dump_dbdes, pkt, "DBDES packet received from nbr %R on %s", n->rid, ifa->ifname);
b1f7229a 325
4bb9ce56 326 ospf_neigh_sm(n, INM_HELLOREC);
353f3261 327
70945cb6
OZ
328 if (ospf_is_v2(p))
329 {
330 struct ospf_dbdes2_packet *ps = (void *) pkt;
331 rcv_iface_mtu = ntohs(ps->iface_mtu);
332 rcv_options = ps->options;
333 rcv_imms = ps->imms;
334 rcv_ddseq = ntohl(ps->ddseq);
335 }
336 else /* OSPFv3 */
337 {
338 struct ospf_dbdes3_packet *ps = (void *) pkt;
339 rcv_options = ntohl(ps->options);
340 rcv_iface_mtu = ntohs(ps->iface_mtu);
341 rcv_imms = ps->imms;
342 rcv_ddseq = ntohl(ps->ddseq);
343 }
742029eb 344
267da813
OZ
345 /* Reject packets with non-matching MTU */
346 if ((ifa->type != OSPF_IT_VLINK) &&
347 (rcv_iface_mtu != ifa->iface->mtu) &&
348 (rcv_iface_mtu != 0) && (ifa->iface->mtu != 0))
349 {
350 LOG_PKT("MTU mismatch with nbr %R on %s (remote %d, local %d)",
351 n->rid, ifa->ifname, rcv_iface_mtu, ifa->iface->mtu);
352 return;
353 }
354
12bed559 355 switch (n->state)
4364b47e 356 {
12bed559
OF
357 case NEIGHBOR_DOWN:
358 case NEIGHBOR_ATTEMPT:
359 case NEIGHBOR_2WAY:
f8fefde3 360 OSPF_TRACE(D_PACKETS, "DBDES packet ignored - lesser state than ExStart");
12bed559 361 return;
70945cb6 362
12bed559
OF
363 case NEIGHBOR_INIT:
364 ospf_neigh_sm(n, INM_2WAYREC);
365 if (n->state != NEIGHBOR_EXSTART)
366 return;
d4cebc6b 367 /* fallthrough */
9f1500f5 368
70945cb6 369 case NEIGHBOR_EXSTART:
d3f4f92b 370 if (((rcv_imms & DBDES_IMMS) == DBDES_IMMS) &&
70945cb6
OZ
371 (n->rid > p->router_id) &&
372 (plen == ospf_dbdes_hdrlen(p)))
12bed559
OF
373 {
374 /* I'm slave! */
70945cb6
OZ
375 n->dds = rcv_ddseq;
376 n->ddr = rcv_ddseq;
377 n->options = rcv_options;
378 n->myimms &= ~DBDES_MS;
379 n->imms = rcv_imms;
a6f79ca5 380 tm_stop(n->dbdes_timer);
12bed559 381 ospf_neigh_sm(n, INM_NEGDONE);
f8fefde3 382 ospf_send_dbdes(p, n);
4364b47e 383 break;
12bed559 384 }
b1f7229a 385
70945cb6
OZ
386 if (!(rcv_imms & DBDES_I) &&
387 !(rcv_imms & DBDES_MS) &&
742029eb 388 (n->rid < p->router_id) &&
70945cb6 389 (n->dds == rcv_ddseq))
12bed559 390 {
b1f7229a 391 /* I'm master! */
70945cb6
OZ
392 n->options = rcv_options;
393 n->ddr = rcv_ddseq - 1; /* It will be set corectly a few lines down */
394 n->imms = rcv_imms;
b1f7229a 395 ospf_neigh_sm(n, INM_NEGDONE);
6f8bbaa1 396 /* Continue to the NEIGHBOR_EXCHANGE case */
12bed559 397 }
b1f7229a
OF
398 else
399 {
70945cb6 400 DBG("%s: Nothing happend to %I (imms=%d)\n", p->name, n->ip, rcv_imms);
12bed559 401 break;
b1f7229a 402 }
70945cb6 403
12bed559 404 case NEIGHBOR_EXCHANGE:
70945cb6
OZ
405 if ((rcv_imms == n->imms) &&
406 (rcv_options == n->options) &&
407 (rcv_ddseq == n->ddr))
f8fefde3 408 goto duplicate;
910e557b 409
f8fefde3
OZ
410 if ((rcv_imms & DBDES_MS) != (n->imms & DBDES_MS))
411 DROP("MS-bit mismatch", rcv_imms);
12bed559 412
f8fefde3
OZ
413 if (rcv_imms & DBDES_I)
414 DROP("I-bit mismatch", rcv_imms);
415
416 if (rcv_options != n->options)
417 DROP("options mismatch", rcv_options);
4364b47e 418
70945cb6
OZ
419 n->ddr = rcv_ddseq;
420 n->imms = rcv_imms;
421
422 if (n->myimms & DBDES_MS)
12bed559 423 {
f8fefde3
OZ
424 /* MASTER */
425
426 if (rcv_ddseq != n->dds)
427 DROP("DD sequence number mismatch", rcv_ddseq);
70945cb6 428
12bed559 429 n->dds++;
70945cb6
OZ
430
431 if (ospf_process_dbdes(p, pkt, n) < 0)
432 return;
433
434 if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
6f8bbaa1 435 {
a6f79ca5 436 tm_stop(n->dbdes_timer);
12bed559 437 ospf_neigh_sm(n, INM_EXDONE);
6f8bbaa1
OZ
438 break;
439 }
440
441 ospf_send_dbdes(p, n);
a6f79ca5 442 tm_start(n->dbdes_timer, n->ifa->rxmtint S);
12bed559
OF
443 }
444 else
445 {
f8fefde3
OZ
446 /* SLAVE */
447
448 if (rcv_ddseq != (n->dds + 1))
449 DROP("DD sequence number mismatch", rcv_ddseq);
12bed559 450
70945cb6
OZ
451 n->ddr = rcv_ddseq;
452 n->dds = rcv_ddseq;
453
454 if (ospf_process_dbdes(p, pkt, n) < 0)
455 return;
456
f8fefde3 457 ospf_send_dbdes(p, n);
6f8bbaa1
OZ
458
459 if (!(n->myimms & DBDES_M) && !(n->imms & DBDES_M))
460 ospf_neigh_sm(n, INM_EXDONE);
70945cb6 461 }
12bed559 462 break;
70945cb6 463
12bed559
OF
464 case NEIGHBOR_LOADING:
465 case NEIGHBOR_FULL:
70945cb6
OZ
466 if ((rcv_imms == n->imms) &&
467 (rcv_options == n->options) &&
468 (rcv_ddseq == n->ddr))
f8fefde3
OZ
469 goto duplicate;
470
f8fefde3 471 DROP("too late for DD exchange", n->state);
70945cb6 472
189dab54 473 default:
f8fefde3 474 bug("Undefined interface state");
12bed559 475 }
f8fefde3
OZ
476 return;
477
478duplicate:
479 OSPF_TRACE(D_PACKETS, "DBDES packet is duplicate");
480
481 /* Slave should retransmit DBDES packet */
482 if (!(n->myimms & DBDES_MS))
483 ospf_rxmt_dbdes(p, n);
484 return;
485
486drop:
487 LOG_PKT("Bad DBDES packet from nbr %R on %s - %s (%u)",
488 n->rid, ifa->ifname, err_dsc, err_val);
489
6f8bbaa1 490 ospf_neigh_sm(n, INM_SEQMIS);
f8fefde3 491 return;
12bed559 492}