📄 spfifc.c
字号:
if (ntoh32(spfpkt->p_aid) != BACKBONE || tap == 0) return(0); // Check instead for virtual link // Start with endpoint, and see whether a virtual links // is configured for the particular transit area endpt = tap->find_abr(ntoh32(spfpkt->srcid)); if (endpt && (vif = endpt->VL)) return(vif); return(0);}/* Find the interface to which a configured neighbor * attaches. */SpfIfc *OSPF::find_nbr_ifc(InAddr nbr_addr) const{ IfcIterator iter(this); SpfIfc *ip; while ((ip = iter.get_next())) { if (!ip->is_multi_access()) continue; if ((nbr_addr & ip->mask()) == ip->net()) return(ip); } return(0);}/* Add or delete an MD5 key. Interface must already be present. */void OSPF::cfgAuKey(struct CfgAuKey *m, int status){ SpfIfc *ip; CryptK *key; CryptK **prevk; if (!(ip = find_ifc(m->address, m->phyint))) return; // Search for current key for (prevk = &ip->if_keys; (key = *prevk); prevk = &key->link) { if (key->key_id == m->key_id) break; } // If delete, free to heap if (status == DELETE_ITEM) { if (key) { *prevk = key->link; delete key; } return; } // Add or modify key // If new, allocate and link into list of keys if (!key) { key = new CryptK(m->key_id); key->ip = ip; key->link = ip->if_keys; ip->if_keys = key; } // Copy in new data memcpy(key->key, m->auth_key, 16); key->start_accept = m->start_accept; key->stop_accept = m->stop_accept; key->stop_accept_specified = m->stop_accept_specified; key->start_generate = m->start_generate; key->stop_generate = m->stop_generate; key->stop_generate_specified = m->stop_generate_specified; key->updated = true;}/* Transfer key data to CfgAuKey structure/ */static void key_to_cfg(const CryptK& key, CfgAuKey& msg){ msg.address = key.interface()->if_addr; msg.phyint = key.interface()->if_phyint; msg.key_id = key.id(); memcpy(msg.auth_key, key.key_data(), sizeof(msg.auth_key)); msg.start_accept = key.accept_start(); msg.stop_accept = key.accept_stop(); msg.stop_accept_specified = key.stop_accept_set(); msg.start_generate = key.generate_start(); msg.stop_generate = key.generate_stop(); msg.stop_generate_specified = key.stop_generate_set();}/* Get key. */bool OSPF::qryAuKey(struct CfgAuKey& msg, byte key_id, InAddr address, int phyint) const{ SpfIfc* ip = find_ifc(address, phyint); if (ip == 0) return false; CryptK *key; CryptK **prevk; // Search for current key for (prevk = &ip->if_keys; (key = *prevk); prevk = &key->link) { if (key->key_id == key_id) { key_to_cfg(*key, msg); return true; } } return false;}/* Get all keys associated with interface. */void OSPF::getAuKeys(std::list<CfgAuKey>& l, InAddr address, int phyint) const{ SpfIfc* ip = find_ifc(address, phyint); if (ip == 0) return; CryptK *key; CryptK **prevk; for (prevk = &ip->if_keys; (key = *prevk); prevk = &key->link) { CfgAuKey msg; key_to_cfg(*key, msg); l.push_back(msg); }}/* Key has not been mentioned in the reconfig, so delete it. */void CryptK::clear_config(){ CryptK *ptr; CryptK **prevk; for (prevk = &ip->if_keys; (ptr = *prevk); prevk = &ptr->link) { if (ptr == this) break; } if (ptr) *prevk = link; delete this;}/* Add the authentication fields to a packet that is to * be transmitted. Returns whether the packet needs to * be checksummed. */void SpfIfc::generate_message(Pkt *pdesc){ SpfPkt *spfpkt; int length; spfpkt = pdesc->spfpkt; length = ntoh16(spfpkt->plen); spfpkt->xsum = 0; spfpkt->autype = hton16(if_autype); memset(spfpkt->un.aubytes, 0, 8); switch (if_autype) { case AUT_NONE: // No authentication if (!pdesc->xsummed) spfpkt->xsum = ~incksum((uns16 *) spfpkt, length); else spfpkt->xsum = ~incksum((uns16 *) spfpkt, sizeof(SpfPkt), pdesc->body_xsum); break; case AUT_PASSWD: // Simple cleartext password if (!pdesc->xsummed) spfpkt->xsum = ~incksum((uns16 *) spfpkt, length); else spfpkt->xsum = ~incksum((uns16 *) spfpkt, sizeof(SpfPkt), pdesc->body_xsum); memcpy(spfpkt->un.aubytes, if_passwd, 8); break; case AUT_CRYPT: // Cryptographic authentication (e.g., MD5) md5_generate(pdesc); break; default: sys->halt(HALT_AUTYPE, "Bad authtype on transmit"); }}/* Set the MD5 authentication fields in a packet that we * are going to transmit. * Bumps Pkt::dptr by the size of the digest, so the digest * will be included as part of the IP packet. */void SpfIfc::md5_generate(Pkt *pdesc){ SpfPkt *spfpkt; int length; CryptK *key; KeyIterator key_iter(this); byte digest[16]; MD5_CTX context; CryptK *best_key; byte *spfend; SPFtime now; spfpkt = pdesc->spfpkt; length = ntoh16(spfpkt->plen); spfend = ((byte *) spfpkt) + length; best_key = 0; // Locate correct key now = sys_etime; while ((key = key_iter.get_next())) { if (time_less(now, key->start_generate)) continue; if (key->stop_generate_specified && !time_less(now, key->stop_generate)) continue; if (!best_key || time_less(best_key->start_generate, key->start_generate)) best_key = key; } if (!best_key) return; // Set MD5 parameters spfpkt->un.crypt.crypt_mbz = 0; spfpkt->un.crypt.keyid = best_key->key_id; spfpkt->un.crypt.audlen = 16; spfpkt->un.crypt.seqno = hton32(now.sec); // Calculate digest with our secret key memcpy(spfend, best_key->key, 16); MD5_Init(&context); MD5_Update(&context, (byte *) spfpkt, length + 16); MD5_Final(digest, &context); // Append digest to end of packet memcpy(spfend, digest, 16); // Make sure that we transmit digest pdesc->dptr += 16;}/* Authenticate the packet. * Coming into this routine, pdesc->end points to the * end of the encapsulating IP packet. After * authentication, end is adjusted to be the end of * the OSPF packet. */int SpfIfc::verify(Pkt *pdesc, SpfNbr *np){ SpfPkt *spfpkt; byte *spfend; spfpkt = pdesc->spfpkt; if (ntoh16(spfpkt->autype) != if_autype) return(false); spfend = ((byte *) spfpkt) + ntoh16(spfpkt->plen); switch (if_autype) { case AUT_NONE: // No authentication if (incksum((uns16 *) spfpkt, ntoh16(spfpkt->plen)) != 0) return(false); break; case AUT_PASSWD: // Simple cleartext password if (memcmp(spfpkt->un.aubytes, if_passwd, 8) != 0) return(false); memset(spfpkt->un.aubytes, 0, 8); if (incksum((uns16 *) spfpkt, ntoh16(spfpkt->plen)) != 0) return(false); break; case AUT_CRYPT: // Cryptographic authentication (e.g., MD5) if (!md5_verify(pdesc, np)) return(false); break; default: return(false); } // Packet authenticates // Strip IP trailer pdesc->end = spfend; return(true);}/* Verify the cryptographic authentication for a received * packet. First locate the key based on the Key ID. Then, * check for replays by verifying the sequence number. * Finally, run the cryptographic hash using our secret key, * and check that the generated digest matches the one appended * to the received packet. * Packet checksum is not used when we're doing cryptographic * authentication. */int SpfIfc::md5_verify(Pkt *pdesc, SpfNbr *np){ SpfPkt *spfpkt; byte *spfend; CryptK *key; KeyIterator key_iter(this); byte saved_digest[16]; byte digest[16]; MD5_CTX context; SPFtime now; spfpkt = pdesc->spfpkt; spfend = ((byte *) spfpkt) + ntoh16(spfpkt->plen); // Check that digest actually appended if ((spfend + 16) > pdesc->end) return(false); // Locate correct key now = sys_etime; while ((key = key_iter.get_next())) { if (time_less(now, key->start_accept)) continue; if (key->stop_accept_specified && !time_less(now, key->stop_accept)) continue; if (key->key_id == spfpkt->un.crypt.keyid) break; } if (!key) return(false); // Verify sequence number of live nighbors if (np != 0 && np->state() > NBS_ATTEMPT) if (np->md5_seqno > ntoh32(spfpkt->un.crypt.seqno)) return(false); // Save received digest memcpy(saved_digest, spfend, 16); // Calculate digest with our secret key memcpy(spfend, key->key, 16); MD5_Init(&context); MD5_Update(&context, (byte *) spfpkt, ntoh16(spfpkt->plen) + 16); MD5_Final(digest, &context); // Compare to saved copy if (memcmp(digest, saved_digest, 16) != 0) return(false); // Save sequence number if (np) np->md5_seqno = ntoh32(spfpkt->un.crypt.seqno); return(true);}/* Find the neighbor representing the source of the received * OSPF packet. Identified by IP source address. Overriden * by point-to-point interfaces and virtual links, where neighbor * is identified by Router ID in the received OSPF header. */SpfNbr *SpfIfc::find_nbr(InAddr addr, rtid_t){ NbrIterator iter(this); SpfNbr *np; while ((np = iter.get_next())) { if (np->addr() == addr) break; } return(np);}/* On point-to-point and virtual links, the neighbor is * identified by its OSPF Router ID. */SpfNbr *PPIfc::find_nbr(InAddr, rtid_t id){ NbrIterator iter(this); SpfNbr *np; while ((np = iter.get_next())) { if (np->id() == id) break; } return(np);}/* Upon receiving a Hello, may set the neighbor's Router ID * or IP address, or neither, depending on interface type. */// Set router ID on multi-access interfacesvoid SpfIfc::set_id_or_addr(SpfNbr *np, rtid_t _id, InAddr){ np->n_id = _id;}// Set IP address on point-to-point interfacesvoid PPIfc::set_id_or_addr(SpfNbr *np, rtid_t, InAddr _addr){ np->n_addr = _addr;}/* Functions that multicast OSPF packets out the given interface * types. * Unicast packets are handled by SpfIfc::nbr_send(). *//* Generic multicast send function, used by broadcast and point-to-point * interfaces. Simply send the IP packet out the correct * physical interface, specifying the next hop or multicast * address. */void SpfIfc::if_send(Pkt *pdesc, InAddr addr){ InPkt *pkt; if (!pdesc->iphdr) return; finish_pkt(pdesc, addr); pkt = pdesc->iphdr; if (pkt->i_src != 0) { if (ospf->spflog(LOG_TXPKT, 1)) { ospf->log(pdesc); ospf->log(this); } sys->sendpkt(pkt, if_phyint); } else if (ospf->spflog(ERR_NOADDR, 5)) { ospf->log(pdesc); ospf->log(this); } ospf->ospf_freepkt(pdesc);}/* Send a multicast packet out a point-to-point link. Packet is * always sent to the AllSPFRouters address. */void PPIfc::if_send(Pkt *pdesc, InAddr){ if (!pdesc->iphdr) return; SpfIfc::if_send(pdesc, AllSPFRouters);}/* Send a multicast packet out a virtual link. Packet is sent directly * to the IP address of the other end of the link. */void VLIfc::if_send(Pkt *pdesc, InAddr){ InPkt *pkt; if (!pdesc->iphdr) return; finish_pkt(pdesc, if_rmtaddr); pkt = pdesc->iphdr; if (ospf->spflog(LOG_TXPKT, 1)) { ospf->log(pdesc); ospf->log(this); } sys->sendpkt(pkt); ospf->ospf_freepkt(pdesc);}/* Send the multicast packet out an NBMA or ptmp interface. Packet is sent * separately to each neighbor. This function is only called * by flooding (Hellos have a separate function), and so packets * are only sent to those neighbors in states Exchange or greater. */void SpfIfc::nonbroadcast_send(Pkt *pdesc, InAddr addr){ InPkt *pkt; SpfNbr *np; NbrIterator nbrIter(this); if (!pdesc->iphdr) return; finish_pkt(pdesc, addr); pkt = pdesc->iphdr; while ((np = nbrIter.get_next())) { if (np->state() < NBS_EXCH) continue; if (ospf->spflog(LOG_TXPKT, 1)) { ospf->log(pdesc); ospf->log(np); } sys->sendpkt(pkt, if_phyint, np->addr()); } ospf->ospf_freepkt(pdesc);}/* Hello interval has changed. Restart the hello timer on each * of a non-broadcast networks nighbors. Using restart, we don't * have to worry about whether we should be sending them a hello * or not. */void SpfIfc::nonbroadcast_restart_hellos(){ NbrIterator iter(this); SpfNbr *np; while ((np = iter.get_next())) np->nbr_fsm(NBE_EVAL);}/* Interface has gone down. Stop sending Hellos to all * neighbors. */void SpfIfc::nonbroadcast_stop_hellos(){ NbrIterator iter(this); SpfNbr *np; while ((np = iter.get_next())) np->n_htim.stop();}/* If OSPF::PPAdjLimit is non-zero, we limit the number * of point-to-point links which will become adjacent * to a particular neighbor. If the "enlist" parameter * is true, and there are insufficient adjacencies, we * add all the 2-Way point-to-point interfaces to the * pending adjacency list, since we don't know which * ones we will be able to advance. */bool SpfIfc::more_adjacencies_needed(rtid_t){ return(true);}bool VLIfc::more_adjacencies_needed(rtid_t){ return(true);}bool PPIfc::more_adjacencies_needed(rtid_t nbr_id){ PPAdjAggr *adjaggr; if (ospf->PPAdjLimit == 0) return(true); if (!(adjaggr = (PPAdjAggr *)if_area->AdjAggr.find(nbr_id, 0))) return(true); return ((ospf->my_id() >nbr_id) && (adjaggr->n_adjs< ospf->PPAdjLimit));}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -