Annotation of embedaddon/bird/proto/ospf/packet.c, revision 1.1
1.1 ! misho 1: /*
! 2: * BIRD -- OSPF
! 3: *
! 4: * (c) 1999--2005 Ondrej Filip <feela@network.cz>
! 5: * (c) 2009--2014 Ondrej Zajicek <santiago@crfreenet.org>
! 6: * (c) 2009--2014 CZ.NIC z.s.p.o.
! 7: *
! 8: * Can be freely distributed and used under the terms of the GNU GPL.
! 9: */
! 10:
! 11: #include "ospf.h"
! 12: #include "nest/password.h"
! 13: #include "lib/md5.h"
! 14: #include "lib/mac.h"
! 15: #include "lib/socket.h"
! 16:
! 17: void
! 18: ospf_pkt_fill_hdr(struct ospf_iface *ifa, void *buf, u8 h_type)
! 19: {
! 20: struct ospf_proto *p = ifa->oa->po;
! 21: struct ospf_packet *pkt;
! 22:
! 23: pkt = (struct ospf_packet *) buf;
! 24:
! 25: pkt->version = ospf_get_version(p);
! 26: pkt->type = h_type;
! 27: pkt->length = htons(ospf_pkt_maxsize(ifa));
! 28: pkt->routerid = htonl(p->router_id);
! 29: pkt->areaid = htonl(ifa->oa->areaid);
! 30: pkt->checksum = 0;
! 31: pkt->instance_id = ifa->instance_id;
! 32: pkt->autype = ifa->autype;
! 33: }
! 34:
! 35: /* We assume OSPFv2 in ospf_pkt_finalize() */
! 36: static void
! 37: ospf_pkt_finalize(struct ospf_iface *ifa, struct ospf_packet *pkt, uint *plen)
! 38: {
! 39: struct password_item *pass = NULL;
! 40: union ospf_auth *auth = (void *) (pkt + 1);
! 41:
! 42: pkt->checksum = 0;
! 43: pkt->autype = ifa->autype;
! 44: bzero(auth, sizeof(union ospf_auth));
! 45:
! 46: /* Compatibility note: auth may contain anything if autype is
! 47: none, but nonzero values do not work with Mikrotik OSPF */
! 48:
! 49: switch (ifa->autype)
! 50: {
! 51: case OSPF_AUTH_SIMPLE:
! 52: pass = password_find(ifa->passwords, 1);
! 53: if (!pass)
! 54: {
! 55: log(L_ERR "No suitable password found for authentication");
! 56: return;
! 57: }
! 58: strncpy(auth->password, pass->password, sizeof(auth->password));
! 59:
! 60: case OSPF_AUTH_NONE:
! 61: {
! 62: void *body = (void *) (auth + 1);
! 63: uint blen = *plen - sizeof(struct ospf_packet) - sizeof(union ospf_auth);
! 64: pkt->checksum = ipsum_calculate(pkt, sizeof(struct ospf_packet), body, blen, NULL);
! 65: }
! 66: break;
! 67:
! 68: case OSPF_AUTH_CRYPT:
! 69: pass = password_find(ifa->passwords, 0);
! 70: if (!pass)
! 71: {
! 72: log(L_ERR "No suitable password found for authentication");
! 73: return;
! 74: }
! 75:
! 76: /* Perhaps use random value to prevent replay attacks after
! 77: reboot when system does not have independent RTC? */
! 78: if (!ifa->csn)
! 79: {
! 80: ifa->csn = (u32) now;
! 81: ifa->csn_use = now;
! 82: }
! 83:
! 84: /* We must have sufficient delay between sending a packet and increasing
! 85: CSN to prevent reordering of packets (in a network) with different CSNs */
! 86: if ((now - ifa->csn_use) > 1)
! 87: ifa->csn++;
! 88:
! 89: ifa->csn_use = now;
! 90:
! 91: uint auth_len = mac_type_length(pass->alg);
! 92: byte *auth_tail = ((byte *) pkt + *plen);
! 93: *plen += auth_len;
! 94:
! 95: ASSERT(*plen < ifa->sk->tbsize);
! 96:
! 97: auth->c32.zero = 0;
! 98: auth->c32.keyid = pass->id;
! 99: auth->c32.len = auth_len;
! 100: auth->c32.csn = htonl(ifa->csn);
! 101:
! 102: /* Append key for keyed hash, append padding for HMAC (RFC 5709 3.3) */
! 103: if (pass->alg < ALG_HMAC)
! 104: strncpy(auth_tail, pass->password, auth_len);
! 105: else
! 106: memset32(auth_tail, HMAC_MAGIC, auth_len / 4);
! 107:
! 108: mac_fill(pass->alg, pass->password, pass->length,
! 109: (byte *) pkt, *plen, auth_tail);
! 110: break;
! 111:
! 112: default:
! 113: bug("Unknown authentication type");
! 114: }
! 115: }
! 116:
! 117:
! 118: /* We assume OSPFv2 in ospf_pkt_checkauth() */
! 119: static int
! 120: ospf_pkt_checkauth(struct ospf_neighbor *n, struct ospf_iface *ifa, struct ospf_packet *pkt, uint len)
! 121: {
! 122: struct ospf_proto *p = ifa->oa->po;
! 123: union ospf_auth *auth = (void *) (pkt + 1);
! 124: struct password_item *pass = NULL;
! 125: const char *err_dsc = NULL;
! 126: uint err_val = 0;
! 127:
! 128: uint plen = ntohs(pkt->length);
! 129: u8 autype = pkt->autype;
! 130:
! 131: if (autype != ifa->autype)
! 132: DROP("authentication method mismatch", autype);
! 133:
! 134: switch (autype)
! 135: {
! 136: case OSPF_AUTH_NONE:
! 137: return 1;
! 138:
! 139: case OSPF_AUTH_SIMPLE:
! 140: pass = password_find(ifa->passwords, 1);
! 141: if (!pass)
! 142: DROP1("no password found");
! 143:
! 144: if (!password_verify(pass, auth->password, sizeof(auth->password)))
! 145: DROP("wrong password", pass->id);
! 146:
! 147: return 1;
! 148:
! 149: case OSPF_AUTH_CRYPT:
! 150: pass = password_find_by_id(ifa->passwords, auth->c32.keyid);
! 151: if (!pass)
! 152: DROP("no suitable password found", auth->c32.keyid);
! 153:
! 154: uint auth_len = mac_type_length(pass->alg);
! 155:
! 156: if (plen + auth->c32.len > len)
! 157: DROP("packet length mismatch", len);
! 158:
! 159: if (auth->c32.len != auth_len)
! 160: DROP("wrong authentication length", auth->c32.len);
! 161:
! 162: u32 rcv_csn = ntohl(auth->c32.csn);
! 163: if (n && (rcv_csn < n->csn))
! 164: // DROP("lower sequence number", rcv_csn);
! 165: {
! 166: /* We want to report both new and old CSN */
! 167: LOG_PKT_AUTH("Authentication failed for nbr %R on %s - "
! 168: "lower sequence number (rcv %u, old %u)",
! 169: n->rid, ifa->ifname, rcv_csn, n->csn);
! 170: return 0;
! 171: }
! 172:
! 173: byte *auth_tail = ((byte *) pkt) + plen;
! 174: byte *auth_data = alloca(auth_len);
! 175: memcpy(auth_data, auth_tail, auth_len);
! 176:
! 177: /* Append key for keyed hash, append padding for HMAC (RFC 5709 3.3) */
! 178: if (pass->alg < ALG_HMAC)
! 179: strncpy(auth_tail, pass->password, auth_len);
! 180: else
! 181: memset32(auth_tail, HMAC_MAGIC, auth_len / 4);
! 182:
! 183: if (!mac_verify(pass->alg, pass->password, pass->length,
! 184: (byte *) pkt, plen + auth_len, auth_data))
! 185: DROP("wrong authentication code", pass->id);
! 186:
! 187: if (n)
! 188: n->csn = rcv_csn;
! 189:
! 190: return 1;
! 191:
! 192: default:
! 193: bug("Unknown authentication type");
! 194: }
! 195:
! 196: drop:
! 197: LOG_PKT_AUTH("Authentication failed for nbr %R on %s - %s (%u)",
! 198: (n ? n->rid : ntohl(pkt->routerid)), ifa->ifname, err_dsc, err_val);
! 199:
! 200: return 0;
! 201: }
! 202:
! 203: /**
! 204: * ospf_rx_hook
! 205: * @sk: socket we received the packet.
! 206: * @len: size of the packet
! 207: *
! 208: * This is the entry point for messages from neighbors. Many checks (like
! 209: * authentication, checksums, size) are done before the packet is passed to
! 210: * non generic functions.
! 211: */
! 212: int
! 213: ospf_rx_hook(sock *sk, uint len)
! 214: {
! 215: /* We want just packets from sk->iface. Unfortunately, on BSD we cannot filter
! 216: out other packets at kernel level and we receive all packets on all sockets */
! 217: if (sk->lifindex != sk->iface->index)
! 218: return 1;
! 219:
! 220: DBG("OSPF: RX hook called (iface %s, src %I, dst %I)\n",
! 221: sk->iface->name, sk->faddr, sk->laddr);
! 222:
! 223: /* Initially, the packet is associated with the 'master' iface */
! 224: struct ospf_iface *ifa = sk->data;
! 225: struct ospf_proto *p = ifa->oa->po;
! 226: const char *err_dsc = NULL;
! 227: uint err_val = 0;
! 228:
! 229: /* Should not happen */
! 230: if (ifa->state <= OSPF_IS_LOOP)
! 231: return 1;
! 232:
! 233: int src_local, dst_local, dst_mcast;
! 234: src_local = ipa_in_net(sk->faddr, ifa->addr->prefix, ifa->addr->pxlen);
! 235: dst_local = ipa_equal(sk->laddr, ifa->addr->ip);
! 236: dst_mcast = ipa_equal(sk->laddr, ifa->all_routers) || ipa_equal(sk->laddr, ifa->des_routers);
! 237:
! 238: if (ospf_is_v2(p))
! 239: {
! 240: /* First, we eliminate packets with strange address combinations.
! 241: * In OSPFv2, they might be for other ospf_ifaces (with different IP
! 242: * prefix) on the same real iface, so we don't log it. We enforce
! 243: * that (src_local || dst_local), therefore we are eliminating all
! 244: * such cases.
! 245: */
! 246: if (dst_mcast && !src_local)
! 247: return 1;
! 248: if (!dst_mcast && !dst_local)
! 249: return 1;
! 250:
! 251: /* Ignore my own broadcast packets */
! 252: if (ifa->cf->real_bcast && ipa_equal(sk->faddr, ifa->addr->ip))
! 253: return 1;
! 254: }
! 255: else
! 256: {
! 257: /* In OSPFv3, src_local and dst_local mean link-local.
! 258: * RFC 5340 says that local (non-vlink) packets use
! 259: * link-local src address, but does not enforce it. Strange.
! 260: */
! 261: if (dst_mcast && !src_local)
! 262: LOG_PKT_WARN("Multicast packet received from non-link-local %I via %s",
! 263: sk->faddr, ifa->ifname);
! 264: }
! 265:
! 266: /* Second, we check packet length, checksum, and the protocol version */
! 267: struct ospf_packet *pkt = (void *) sk_rx_buffer(sk, &len);
! 268:
! 269:
! 270: if (pkt == NULL)
! 271: DROP("bad IP header", len);
! 272:
! 273: if (ifa->check_ttl && (sk->rcv_ttl < 255))
! 274: DROP("wrong TTL", sk->rcv_ttl);
! 275:
! 276: if (len < sizeof(struct ospf_packet))
! 277: DROP("too short", len);
! 278:
! 279: if (pkt->version != ospf_get_version(p))
! 280: DROP("version mismatch", pkt->version);
! 281:
! 282: uint plen = ntohs(pkt->length);
! 283: if ((plen < sizeof(struct ospf_packet)) || ((plen % 4) != 0))
! 284: DROP("invalid length", plen);
! 285:
! 286: if (sk->flags & SKF_TRUNCATED)
! 287: {
! 288: /* If we have dynamic buffers and received truncated message, we expand RX buffer */
! 289:
! 290: uint bs = plen + 256;
! 291: bs = BIRD_ALIGN(bs, 1024);
! 292:
! 293: if (!ifa->cf->rx_buffer && (bs > sk->rbsize))
! 294: sk_set_rbsize(sk, bs);
! 295:
! 296: DROP("truncated", plen);
! 297: }
! 298:
! 299: if (plen > len)
! 300: DROP("length mismatch", plen);
! 301:
! 302: if (ospf_is_v2(p) && (pkt->autype != OSPF_AUTH_CRYPT))
! 303: {
! 304: uint hlen = sizeof(struct ospf_packet) + sizeof(union ospf_auth);
! 305: uint blen = plen - hlen;
! 306: void *body = ((void *) pkt) + hlen;
! 307:
! 308: if (!ipsum_verify(pkt, sizeof(struct ospf_packet), body, blen, NULL))
! 309: DROP1("invalid checksum");
! 310: }
! 311:
! 312: /* Third, we resolve associated iface and handle vlinks. */
! 313:
! 314: u32 areaid = ntohl(pkt->areaid);
! 315: u32 rid = ntohl(pkt->routerid);
! 316: u8 instance_id = pkt->instance_id;
! 317:
! 318: if (areaid == ifa->oa->areaid)
! 319: {
! 320: /* Matching area ID */
! 321:
! 322: if (instance_id != ifa->instance_id)
! 323: return 1;
! 324:
! 325: /* It is real iface, source should be local (in OSPFv2) */
! 326: if (ospf_is_v2(p) && !src_local)
! 327: DROP1("strange source address");
! 328:
! 329: goto found;
! 330: }
! 331: else if ((areaid == 0) && !dst_mcast)
! 332: {
! 333: /* Backbone area ID and possible vlink packet */
! 334:
! 335: if ((p->areano == 1) || !oa_is_ext(ifa->oa))
! 336: return 1;
! 337:
! 338: struct ospf_iface *iff = NULL;
! 339: WALK_LIST(iff, p->iface_list)
! 340: {
! 341: if ((iff->type == OSPF_IT_VLINK) &&
! 342: (iff->voa == ifa->oa) &&
! 343: (iff->instance_id == instance_id) &&
! 344: (iff->vid == rid))
! 345: {
! 346: /* Vlink should be UP */
! 347: if (iff->state != OSPF_IS_PTP)
! 348: return 1;
! 349:
! 350: ifa = iff;
! 351: goto found;
! 352: }
! 353: }
! 354:
! 355: /*
! 356: * Cannot find matching vlink. It is either misconfigured vlink; NBMA or
! 357: * PtMP with misconfigured area ID, or packet for some other instance (that
! 358: * is possible even if instance_id == ifa->instance_id, because it may be
! 359: * also vlink packet in the other instance, which is different namespace).
! 360: */
! 361:
! 362: return 1;
! 363: }
! 364: else
! 365: {
! 366: /* Non-matching area ID but cannot be vlink packet */
! 367:
! 368: if (instance_id != ifa->instance_id)
! 369: return 1;
! 370:
! 371: DROP("area mismatch", areaid);
! 372: }
! 373:
! 374:
! 375: found:
! 376: if (ifa->stub) /* This shouldn't happen */
! 377: return 1;
! 378:
! 379: if (ipa_equal(sk->laddr, ifa->des_routers) && (ifa->sk_dr == 0))
! 380: return 1;
! 381:
! 382: if (rid == p->router_id)
! 383: DROP1("my own router ID");
! 384:
! 385: if (rid == 0)
! 386: DROP1("zero router ID");
! 387:
! 388: /* In OSPFv2, neighbors are identified by either IP or Router ID, based on network type */
! 389: uint t = ifa->type;
! 390: struct ospf_neighbor *n;
! 391: if (ospf_is_v2(p) && ((t == OSPF_IT_BCAST) || (t == OSPF_IT_NBMA) || (t == OSPF_IT_PTMP)))
! 392: n = find_neigh_by_ip(ifa, sk->faddr);
! 393: else
! 394: n = find_neigh(ifa, rid);
! 395:
! 396: if (!n && (pkt->type != HELLO_P))
! 397: {
! 398: OSPF_TRACE(D_PACKETS, "Non-HELLO packet received from unknown nbr %R on %s, src %I",
! 399: rid, ifa->ifname, sk->faddr);
! 400: return 1;
! 401: }
! 402:
! 403: /* ospf_pkt_checkauth() has its own error logging */
! 404: if (ospf_is_v2(p) && !ospf_pkt_checkauth(n, ifa, pkt, len))
! 405: return 1;
! 406:
! 407: switch (pkt->type)
! 408: {
! 409: case HELLO_P:
! 410: ospf_receive_hello(pkt, ifa, n, sk->faddr);
! 411: break;
! 412:
! 413: case DBDES_P:
! 414: ospf_receive_dbdes(pkt, ifa, n);
! 415: break;
! 416:
! 417: case LSREQ_P:
! 418: ospf_receive_lsreq(pkt, ifa, n);
! 419: break;
! 420:
! 421: case LSUPD_P:
! 422: ospf_receive_lsupd(pkt, ifa, n);
! 423: break;
! 424:
! 425: case LSACK_P:
! 426: ospf_receive_lsack(pkt, ifa, n);
! 427: break;
! 428:
! 429: default:
! 430: DROP("invalid packet type", pkt->type);
! 431: };
! 432: return 1;
! 433:
! 434: drop:
! 435: LOG_PKT("Bad packet from %I via %s - %s (%u)",
! 436: sk->faddr, ifa->ifname, err_dsc, err_val);
! 437:
! 438: return 1;
! 439: }
! 440:
! 441: /*
! 442: void
! 443: ospf_tx_hook(sock * sk)
! 444: {
! 445: struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
! 446: // struct proto *p = (struct proto *) (ifa->oa->p);
! 447: log(L_ERR "OSPF: TX hook called on %s", ifa->ifname);
! 448: }
! 449: */
! 450:
! 451: void
! 452: ospf_err_hook(sock * sk, int err)
! 453: {
! 454: struct ospf_iface *ifa= (struct ospf_iface *) (sk->data);
! 455: struct ospf_proto *p = ifa->oa->po;
! 456: log(L_ERR "%s: Socket error on %s: %M", p->p.name, ifa->ifname, err);
! 457: }
! 458:
! 459: void
! 460: ospf_verr_hook(sock *sk, int err)
! 461: {
! 462: struct ospf_proto *p = (struct ospf_proto *) (sk->data);
! 463: log(L_ERR "%s: Vlink socket error: %M", p->p.name, err);
! 464: }
! 465:
! 466: void
! 467: ospf_send_to(struct ospf_iface *ifa, ip_addr dst)
! 468: {
! 469: sock *sk = ifa->sk;
! 470: struct ospf_packet *pkt = (struct ospf_packet *) sk->tbuf;
! 471: uint plen = ntohs(pkt->length);
! 472:
! 473: if (ospf_is_v2(ifa->oa->po))
! 474: ospf_pkt_finalize(ifa, pkt, &plen);
! 475:
! 476: int done = sk_send_to(sk, plen, dst, 0);
! 477: if (!done)
! 478: log(L_WARN "OSPF: TX queue full on %s", ifa->ifname);
! 479: }
! 480:
! 481: void
! 482: ospf_send_to_agt(struct ospf_iface *ifa, u8 state)
! 483: {
! 484: struct ospf_neighbor *n;
! 485:
! 486: WALK_LIST(n, ifa->neigh_list)
! 487: if (n->state >= state)
! 488: ospf_send_to(ifa, n->ip);
! 489: }
! 490:
! 491: void
! 492: ospf_send_to_bdr(struct ospf_iface *ifa)
! 493: {
! 494: if (ipa_nonzero(ifa->drip))
! 495: ospf_send_to(ifa, ifa->drip);
! 496: if (ipa_nonzero(ifa->bdrip))
! 497: ospf_send_to(ifa, ifa->bdrip);
! 498: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>