]> git.ipfire.org Git - thirdparty/bird.git/blame - proto/ospf/packet.c
Fixes a nasty bug in OSPF.
[thirdparty/bird.git] / proto / ospf / packet.c
CommitLineData
4364b47e
OF
1/*
2 * BIRD -- OSPF
3 *
e6ea2e37 4 * (c) 1999--2005 Ondrej Filip <feela@network.cz>
4364b47e
OF
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9#include "ospf.h"
3e2bd0f1
OF
10#include "nest/password.h"
11#include "lib/md5.h"
4364b47e
OF
12
13void
3e2bd0f1 14ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
4364b47e 15{
8a70a13e 16 struct proto_ospf *po = ifa->oa->po;
4364b47e 17 struct ospf_packet *pkt;
4364b47e 18
00bd27a1 19 pkt = (struct ospf_packet *) buf;
4364b47e 20
00bd27a1 21 pkt->version = OSPF_VERSION;
4364b47e 22
00bd27a1
OF
23 pkt->type = h_type;
24
8a70a13e 25 pkt->routerid = htonl(po->router_id);
3b16080c 26 pkt->areaid = htonl(ifa->oa->areaid);
c3226991
OZ
27
28#ifdef OSPFv3
29 pkt->instance_id = ifa->instance_id;
30#endif
31
32#ifdef OSPFv2
2e10a170 33 pkt->autype = htons(ifa->autype);
c3226991
OZ
34#endif
35
00bd27a1 36 pkt->checksum = 0;
4364b47e
OF
37}
38
3e2bd0f1
OF
39unsigned
40ospf_pkt_maxsize(struct ospf_iface *ifa)
41{
e6ea2e37 42 unsigned mtu = (ifa->type == OSPF_IT_VLINK) ? OSPF_VLINK_MTU : ifa->iface->mtu;
d5356072 43 unsigned headers = SIZE_OF_IP_HEADER;
c3226991
OZ
44
45#ifdef OSPFv2
d5356072
OZ
46 if (ifa->autype == OSPF_AUTH_CRYPT)
47 headers += OSPF_AUTH_CRYPT_SIZE;
c3226991
OZ
48#endif
49
d5356072 50 return mtu - headers;
3e2bd0f1
OF
51}
52
c3226991
OZ
53#ifdef OSPFv2
54
55static void
3e2bd0f1 56ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
4364b47e 57{
b21f68b4 58 struct password_item *passwd = NULL;
3e2bd0f1
OF
59 void *tail;
60 struct MD5Context ctxt;
61 char password[OSPF_AUTH_CRYPT_SIZE];
62
2e10a170 63 pkt->autype = htons(ifa->autype);
3e2bd0f1
OF
64
65 switch(ifa->autype)
66 {
3e2bd0f1 67 case OSPF_AUTH_SIMPLE:
32d3228d 68 bzero(&pkt->u, sizeof(union ospf_auth));
b21f68b4 69 passwd = password_find(ifa->passwords, 1);
32d3228d
OF
70 if (!passwd)
71 {
72 log( L_ERR "No suitable password found for authentication" );
73 return;
74 }
75 password_cpy(pkt->u.password, passwd->password, sizeof(union ospf_auth));
69b27ed6 76 case OSPF_AUTH_NONE:
7969ea3b 77 pkt->checksum = 0;
32d3228d
OF
78 pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet) -
79 sizeof(union ospf_auth), (pkt + 1),
3e2bd0f1
OF
80 ntohs(pkt->length) -
81 sizeof(struct ospf_packet), NULL);
3e2bd0f1
OF
82 break;
83 case OSPF_AUTH_CRYPT:
b21f68b4 84 passwd = password_find(ifa->passwords, 0);
3e2bd0f1
OF
85 if (!passwd)
86 {
87 log( L_ERR "No suitable password found for authentication" );
88 return;
89 }
90
91 pkt->checksum = 0;
92
024c310b
OZ
93 /* Perhaps use random value to prevent replay attacks after
94 reboot when system does not have independent RTC? */
3e2bd0f1 95 if (!ifa->csn)
024c310b
OZ
96 {
97 ifa->csn = (u32) now;
98 ifa->csn_use = now;
99 }
100
101 /* We must have sufficient delay between sending a packet and increasing
102 CSN to prevent reordering of packets (in a network) with different CSNs */
103 if ((now - ifa->csn_use) > 1)
104 ifa->csn++;
105
106 ifa->csn_use = now;
3e2bd0f1
OF
107
108 pkt->u.md5.keyid = passwd->id;
109 pkt->u.md5.len = OSPF_AUTH_CRYPT_SIZE;
110 pkt->u.md5.zero = 0;
024c310b 111 pkt->u.md5.csn = htonl(ifa->csn);
3e2bd0f1
OF
112 tail = ((void *)pkt) + ntohs(pkt->length);
113 MD5Init(&ctxt);
114 MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
115 password_cpy(password, passwd->password, OSPF_AUTH_CRYPT_SIZE);
116 MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
117 MD5Final(tail, &ctxt);
3e2bd0f1
OF
118 break;
119 default:
120 bug("Unknown authentication type");
121 }
4364b47e
OF
122}
123
9831e591 124static int
69b27ed6 125ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size)
c1824c4d 126{
86c84d76 127 struct proto_ospf *po = ifa->oa->po;
3e2bd0f1
OF
128 struct proto *p = &po->proto;
129 struct password_item *pass = NULL, *ptmp;
130 void *tail;
131 char md5sum[OSPF_AUTH_CRYPT_SIZE];
132 char password[OSPF_AUTH_CRYPT_SIZE];
133 struct MD5Context ctxt;
134
135
2e10a170 136 if (pkt->autype != htons(ifa->autype))
2e10a170 137 {
3e2bd0f1
OF
138 OSPF_TRACE(D_PACKETS, "OSPF_auth: Method differs (%d)", ntohs(pkt->autype));
139 return 0;
2e10a170 140 }
c1824c4d 141
3e2bd0f1
OF
142 switch(ifa->autype)
143 {
144 case OSPF_AUTH_NONE:
145 return 1;
146 break;
147 case OSPF_AUTH_SIMPLE:
b21f68b4 148 pass = password_find(ifa->passwords, 1);
3b108f18 149 if (!pass)
3e2bd0f1
OF
150 {
151 OSPF_TRACE(D_PACKETS, "OSPF_auth: no password found");
152 return 0;
153 }
32d3228d 154 password_cpy(password, pass->password, sizeof(union ospf_auth));
4364b47e 155
32d3228d 156 if (memcmp(pkt->u.password, password, sizeof(union ospf_auth)))
3e2bd0f1 157 {
32d3228d
OF
158 char ppass[sizeof(union ospf_auth) + 1];
159 bzero(ppass, (sizeof(union ospf_auth) + 1));
160 memcpy(ppass, pkt->u.password, sizeof(union ospf_auth));
161 OSPF_TRACE(D_PACKETS, "OSPF_auth: different passwords (%s)", ppass);
3e2bd0f1
OF
162 return 0;
163 }
32d3228d 164 return 1;
3e2bd0f1
OF
165 break;
166 case OSPF_AUTH_CRYPT:
167 if (pkt->u.md5.len != OSPF_AUTH_CRYPT_SIZE)
168 {
169 OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong size of md5 digest");
170 return 0;
171 }
3b108f18 172
885b3d61 173 if (ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE > size)
3e2bd0f1 174 {
f39e3bfd 175 OSPF_TRACE(D_PACKETS, "OSPF_auth: size mismatch (%d vs %d)",
5d3f5552 176 ntohs(pkt->length) + OSPF_AUTH_CRYPT_SIZE, size);
3e2bd0f1
OF
177 return 0;
178 }
179
3e2bd0f1
OF
180 tail = ((void *)pkt) + ntohs(pkt->length);
181
3b108f18 182 if (ifa->passwords)
3e2bd0f1 183 {
3b108f18
OZ
184 WALK_LIST(ptmp, *(ifa->passwords))
185 {
186 if (pkt->u.md5.keyid != ptmp->id) continue;
187 if ((ptmp->accfrom > now_real) || (ptmp->accto < now_real)) continue;
188 pass = ptmp;
189 break;
190 }
3e2bd0f1
OF
191 }
192
3b108f18 193 if (!pass)
3e2bd0f1
OF
194 {
195 OSPF_TRACE(D_PACKETS, "OSPF_auth: no suitable md5 password found");
196 return 0;
197 }
198
3b108f18 199 if (n)
3e2bd0f1 200 {
024c310b
OZ
201 u32 rcv_csn = ntohl(pkt->u.md5.csn);
202 if(rcv_csn < n->csn)
203 {
204 OSPF_TRACE(D_PACKETS, "OSPF_auth: lower sequence number (rcv %d, old %d)", rcv_csn, n->csn);
205 return 0;
206 }
207
208 n->csn = rcv_csn;
3e2bd0f1
OF
209 }
210
211 MD5Init(&ctxt);
212 MD5Update(&ctxt, (char *) pkt, ntohs(pkt->length));
213 password_cpy(password, pass->password, OSPF_AUTH_CRYPT_SIZE);
214 MD5Update(&ctxt, password, OSPF_AUTH_CRYPT_SIZE);
215 MD5Final(md5sum, &ctxt);
bc956fca 216 if (memcmp(md5sum, tail, OSPF_AUTH_CRYPT_SIZE))
3e2bd0f1
OF
217 {
218 OSPF_TRACE(D_PACKETS, "OSPF_auth: wrong md5 digest");
219 return 0;
220 }
221 return 1;
222 break;
223 default:
224 OSPF_TRACE(D_PACKETS, "OSPF_auth: unknown auth type");
225 return 0;
226 }
4364b47e
OF
227}
228
c3226991
OZ
229#else
230
231/* OSPFv3 authentication not yet supported */
232
233static inline void
234ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt)
235{ }
236
237static int
238ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, int size)
239{ return 1; }
353729f5
OZ
240
241#endif
242
c3226991 243
351feeb5
OF
244/**
245 * ospf_rx_hook
353729f5 246 * @sk: socket we received the packet.
351feeb5
OF
247 * @size: size of the packet
248 *
baa5dd6c
OF
249 * This is the entry point for messages from neighbors. Many checks (like
250 * authentication, checksums, size) are done before the packet is passed to
351feeb5
OF
251 * non generic functions.
252 */
4364b47e 253int
353729f5 254ospf_rx_hook(sock *sk, int size)
4364b47e 255{
353729f5 256 char *mesg = "OSPF: Bad packet from ";
4364b47e 257
e7b76b97
OZ
258 /* We want just packets from sk->iface. Unfortunately, on BSD we
259 cannot filter out other packets at kernel level and we receive
260 all packets on all sockets */
261 if (sk->lifindex != sk->iface->index)
262 return 1;
263
264 DBG("OSPF: RX hook called (iface %s, src %I, dst %I)\n",
265 sk->iface->name, sk->faddr, sk->laddr);
266
267 /* Initially, the packet is associated with the 'master' iface */
268 struct ospf_iface *ifa = sk->data;
269 struct proto_ospf *po = ifa->oa->po;
54305181 270 // struct proto *p = &po->proto;
e7b76b97 271
ab164971
OZ
272 int src_local, dst_local UNUSED, dst_mcast;
273 src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen);
274 dst_local = ipa_equal(sk->laddr, ifa->addr->ip);
275 dst_mcast = ipa_equal(sk->laddr, AllSPFRouters) || ipa_equal(sk->laddr, AllDRouters);
e7b76b97
OZ
276
277#ifdef OSPFv2
278 /* First, we eliminate packets with strange address combinations.
279 * In OSPFv2, they might be for other ospf_ifaces (with different IP
280 * prefix) on the same real iface, so we don't log it. We enforce
281 * that (src_local || dst_local), therefore we are eliminating all
282 * such cases.
283 */
284 if (dst_mcast && !src_local)
285 return 1;
286 if (!dst_mcast && !dst_local)
287 return 1;
00bd27a1 288
e7b76b97
OZ
289#else /* OSPFv3 */
290
291 /* In OSPFv3, src_local and dst_local mean link-local.
292 * RFC 5340 says that local (non-vlink) packets use
293 * link-local src address, but does not enforce it. Strange.
294 */
295 if (dst_mcast && !src_local)
296 log(L_WARN "OSPF: Received multicast packet from %I (not link-local)", sk->faddr);
297#endif
298
299 /* Second, we check packet size, checksum, and the protocol version */
353729f5 300 struct ospf_packet *ps = (struct ospf_packet *) ip_skip_header(sk->rbuf, &size);
3b16080c 301
0e9617e4
OZ
302 if (ps == NULL)
303 {
304 log(L_ERR "%s%I - bad IP header", mesg, sk->faddr);
305 return 1;
306 }
307
2e10a170
OF
308 if ((unsigned) size < sizeof(struct ospf_packet))
309 {
5e3436d2
OF
310 log(L_ERR "%s%I - too short (%u bytes)", mesg, sk->faddr, size);
311 return 1;
2e10a170 312 }
00bd27a1 313
353729f5 314 int osize = ntohs(ps->length);
a6bc04d5 315 if ((osize > size) || ((osize % 4) != 0))
2e10a170 316 {
a6bc04d5 317 log(L_ERR "%s%I - size field does not match (%d/%d)", mesg, sk->faddr, osize, size);
5e3436d2 318 return 1;
2e10a170 319 }
00bd27a1 320
353729f5
OZ
321 if ((unsigned) size > sk->rbsize)
322 {
323 log(L_ERR "%s%I - too large (%d vs %d)", mesg, sk->faddr, size, sk->rbsize);
324 return 1;
325 }
326
00bd27a1 327 if (ps->version != OSPF_VERSION)
2e10a170 328 {
5e3436d2
OF
329 log(L_ERR "%s%I - version %u", mesg, sk->faddr, ps->version);
330 return 1;
2e10a170 331 }
00bd27a1 332
c3226991 333#ifdef OSPFv2
bc956fca
OF
334 if ((ps->autype != htons(OSPF_AUTH_CRYPT)) &&
335 (!ipsum_verify(ps, 16, (void *) ps + sizeof(struct ospf_packet),
a6bc04d5 336 osize - sizeof(struct ospf_packet), NULL)))
2e10a170 337 {
5e3436d2
OF
338 log(L_ERR "%s%I - bad checksum", mesg, sk->faddr);
339 return 1;
2e10a170 340 }
c3226991 341#endif
00bd27a1 342
353729f5 343
e7b76b97
OZ
344 /* Third, we resolve associated iface and handle vlinks. */
345
346 u32 areaid = ntohl(ps->areaid);
347 u32 rid = ntohl(ps->routerid);
348
349 if ((areaid == ifa->oa->areaid)
350#ifdef OSPFv3
bed41728 351 && (ps->instance_id == ifa->instance_id)
e7b76b97
OZ
352#endif
353 )
354 {
355 /* It is real iface, source should be local (in OSPFv2) */
356#ifdef OSPFv2
357 if (!src_local)
358 return 1;
359#endif
360 }
361 else if (dst_mcast || (areaid != 0))
362 {
363 /* Obvious mismatch */
364
365#ifdef OSPFv2
366 /* We ignore mismatch in OSPFv3, because there might be
367 other instance with different instance ID */
368 log(L_ERR "%s%I - area does not match (%R vs %R)",
369 mesg, sk->faddr, areaid, ifa->oa->areaid);
370#endif
371 return 1;
372 }
373 else
2e10a170 374 {
e7b76b97
OZ
375 /* Some vlink? */
376 struct ospf_iface *iff = NULL;
377
378 WALK_LIST(iff, po->iface_list)
353729f5 379 {
e7b76b97
OZ
380 if ((iff->type == OSPF_IT_VLINK) &&
381 (iff->voa == ifa->oa) &&
382#ifdef OSPFv3
383 (iff->instance_id == ps->instance_id) &&
384#endif
385 (iff->vid == rid))
386 {
387 /* Vlink should be UP */
388 if (iff->state != OSPF_IS_PTP)
389 return 1;
390
391 ifa = iff;
392 goto found;
393 }
353729f5
OZ
394 }
395
e7b76b97 396#ifdef OSPFv2
ed76033c 397 log(L_WARN "OSPF: Received packet for unknown vlink (ID %R, IP %I)", rid, sk->faddr);
e7b76b97 398#endif
5e3436d2 399 return 1;
2e10a170 400 }
00bd27a1 401
e7b76b97 402 found:
353729f5
OZ
403 if (ifa->stub) /* This shouldn't happen */
404 return 1;
405
406 if (ipa_equal(sk->laddr, AllDRouters) && (ifa->sk_dr == 0))
c3226991 407 return 1;
c3226991 408
e7b76b97 409 if (rid == po->router_id)
2e10a170 410 {
5e3436d2
OF
411 log(L_ERR "%s%I - received my own router ID!", mesg, sk->faddr);
412 return 1;
2e10a170 413 }
00bd27a1 414
e7b76b97 415 if (rid == 0)
2e10a170 416 {
5e3436d2
OF
417 log(L_ERR "%s%I - router id = 0.0.0.0", mesg, sk->faddr);
418 return 1;
419 }
420
9d1ee138
OZ
421#ifdef OSPFv2
422 /* In OSPFv2, neighbors are identified by either IP or Router ID, base on network type */
423 struct ospf_neighbor *n;
919f5411 424 if ((ifa->type == OSPF_IT_BCAST) || (ifa->type == OSPF_IT_NBMA) || (ifa->type == OSPF_IT_PTMP))
9d1ee138
OZ
425 n = find_neigh_by_ip(ifa, sk->faddr);
426 else
427 n = find_neigh(ifa, rid);
428#else
e7b76b97 429 struct ospf_neighbor *n = find_neigh(ifa, rid);
9d1ee138 430#endif
5e3436d2
OF
431
432 if(!n && (ps->type != HELLO_P))
433 {
ed76033c 434 log(L_WARN "OSPF: Received non-hello packet from unknown neighbor (src %I, iface %s)",
353729f5 435 sk->faddr, ifa->iface->name);
5e3436d2 436 return 1;
2e10a170 437 }
00bd27a1 438
69b27ed6 439 if (!ospf_pkt_checkauth(n, ifa, ps, size))
3e2bd0f1 440 {
ed76033c 441 log(L_ERR "%s%I - authentication failed", mesg, sk->faddr);
3e2bd0f1
OF
442 return 1;
443 }
444
351feeb5 445 /* Dump packet
00bd27a1
OF
446 pu8=(u8 *)(sk->rbuf+5*4);
447 for(i=0;i<ntohs(ps->length);i+=4)
448 DBG("%s: received %u,%u,%u,%u\n",p->name, pu8[i+0], pu8[i+1], pu8[i+2],
449 pu8[i+3]);
450 DBG("%s: received size: %u\n",p->name,size);
451 */
452
453 switch (ps->type)
2e10a170
OF
454 {
455 case HELLO_P:
456 DBG("%s: Hello received.\n", p->name);
c3226991 457 ospf_hello_receive(ps, ifa, n, sk->faddr);
2e10a170
OF
458 break;
459 case DBDES_P:
460 DBG("%s: Database description received.\n", p->name);
c3226991 461 ospf_dbdes_receive(ps, ifa, n);
2e10a170
OF
462 break;
463 case LSREQ_P:
464 DBG("%s: Link state request received.\n", p->name);
c3226991 465 ospf_lsreq_receive(ps, ifa, n);
2e10a170
OF
466 break;
467 case LSUPD_P:
468 DBG("%s: Link state update received.\n", p->name);
c3226991 469 ospf_lsupd_receive(ps, ifa, n);
2e10a170
OF
470 break;
471 case LSACK_P:
472 DBG("%s: Link state ack received.\n", p->name);
c3226991 473 ospf_lsack_receive(ps, ifa, n);
2e10a170
OF
474 break;
475 default:
5e3436d2
OF
476 log(L_ERR "%s%I - wrong type %u", mesg, sk->faddr, ps->type);
477 return 1;
2e10a170 478 };
5e3436d2 479 return 1;
4364b47e
OF
480}
481
482void
2e10a170 483ospf_tx_hook(sock * sk)
4364b47e 484{
353729f5
OZ
485// struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
486// struct proto *p = (struct proto *) (ifa->oa->po);
487 log(L_ERR "OSPF: TX_Hook called");
4364b47e
OF
488}
489
490void
2eef9e88 491ospf_err_hook(sock * sk, int err)
4364b47e 492{
353729f5
OZ
493// struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
494// struct proto *p = (struct proto *) (ifa->oa->po);
495 log(L_ERR "OSPF: Socket error: %m", err);
4364b47e
OF
496}
497
67315ef6 498void
f9c799a0 499ospf_send_to_agt(struct ospf_iface *ifa, u8 state)
67315ef6
OF
500{
501 struct ospf_neighbor *n;
502
353729f5
OZ
503 WALK_LIST(n, ifa->neigh_list)
504 if (n->state >= state)
505 ospf_send_to(ifa, n->ip);
00bd27a1 506}
eb436e16
OF
507
508void
f9c799a0 509ospf_send_to_bdr(struct ospf_iface *ifa)
eb436e16 510{
3b16080c 511 if (!ipa_equal(ifa->drip, IPA_NONE))
f9c799a0 512 ospf_send_to(ifa, ifa->drip);
3b16080c 513 if (!ipa_equal(ifa->bdrip, IPA_NONE))
f9c799a0 514 ospf_send_to(ifa, ifa->bdrip);
eb436e16 515}
98ac6176
OF
516
517void
353729f5 518ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
98ac6176 519{
f9c799a0 520 sock *sk = ifa->sk;
3e2bd0f1 521 struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
c3226991 522 int len = ntohs(pkt->length);
3e2bd0f1 523
c3226991
OZ
524#ifdef OSPFv2
525 if (ifa->autype == OSPF_AUTH_CRYPT)
526 len += OSPF_AUTH_CRYPT_SIZE;
527#endif
528
529 ospf_pkt_finalize(ifa, pkt);
f15cb99c 530 if (sk->tbuf != sk->tpos)
353729f5 531 log(L_ERR "Aiee, old packet was overwritten in TX buffer");
f15cb99c 532
353729f5 533 sk_send_to(sk, len, dst, 0);
98ac6176
OF
534}
535