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>