📄 port.cc
字号:
template <typename A>voidPort<A>::record_bad_auth_packet(const string& why, const Addr& host, uint16_t port, Peer<A>* p){ XLOG_INFO("RIP port %s/%s/%s authentication failed %s:%u - %s\n", this->_pio->ifname().c_str(), this->_pio->vifname().c_str(), this->_pio->address().str().c_str(), host.str().c_str(), port, why.c_str()); counters().incr_bad_auth_packets(); if (p) { p->counters().incr_bad_auth_packets(); }}template <typename A>voidPort<A>::record_bad_route(const string& why, const Addr& host, uint16_t port, Peer<A>* p){ XLOG_INFO("RIP port %s/%s/%s received bad route from %s:%u - %s\n", this->_pio->ifname().c_str(), this->_pio->vifname().c_str(), this->_pio->address().str().c_str(), host.str().c_str(), port, why.c_str()); counters().incr_bad_routes(); if (p) { p->counters().incr_bad_routes(); }}static voidnoop(){}template <typename A>voidPort<A>::block_queries(){ EventLoop& e = _pm.eventloop(); _query_blocked_timer = e.new_oneoff_after_ms(constants().interquery_delay_ms(), callback(noop));}template <typename A>boolPort<A>::queries_blocked() const{ return _query_blocked_timer.scheduled();}template <typename A>voidPort<A>::push_packets(){ if (this->io_handler()->pending()) return; const RipPacket<A>* head = _packet_queue->head(); if (head == 0) return; if (this->io_handler()->send(head->address(), head->port(), head->data())) { return; } XLOG_WARNING("Send failed: discarding outbound packets."); _packet_queue->flush_packets();}template <typename A>pair<A,uint16_t>Port<A>::route_policy(const RouteEntry<A>& r) const{ if (r.net() == RIP_AF_CONSTANTS<A>::DEFAULT_ROUTE() && advertise_default_route() == false) { return make_pair(A::ZERO(), RIP_MAX_COST); } uint16_t cost = r.cost(); const Peer<A>* peer = dynamic_cast<const Peer<A>*>(r.origin()); if (peer == 0) { // Route did not come from a peer: it's a static route or a // redist route. No horizon checking necessary. return make_pair(A::ZERO(), cost); } const Port<A>& peer_port = peer->port(); if (&peer_port != this) { // Route did not originate from this Port instance. No horizon // checking necessary. return make_pair(A::ZERO(), cost); } switch (horizon()) { case NONE: // No processing break; case SPLIT: // Don't advertise route back to source cost = RIP_MAX_COST; break; case SPLIT_POISON_REVERSE: // Advertise back at cost of infinity cost = RIP_INFINITY; break; } return make_pair(A::ZERO(), cost);}template <typename A>voidPort<A>::port_io_send_completion(bool success){ if (success == false) { XLOG_ERROR("Send failed\n"); } const RipPacket<A>* head = _packet_queue->head(); XLOG_ASSERT(head != 0); _packet_queue->pop_head(); push_packets();}template <typename A>voidPort<A>::port_io_enabled_change(bool en){ start_stop_output_processing(); if (en == false) kill_peer_routes();}template <typename A>voidPort<A>::start_stop_output_processing(){ if (output_allowed()) { start_request_table_timer(); start_output_processing(); request_table(); } else { stop_request_table_timer(); stop_output_processing(); }}template <typename A>voidPort<A>::kill_peer_routes(){#ifdef INSTANTIATE_IPV4 // Reset the authentication handler PortAFSpecState<IPv4>& pss = af_state(); if (pss.auth_handler() != NULL) pss.auth_handler()->reset();#endif typename PeerList::iterator pli = _peers.begin(); while (pli != _peers.end()) { vector<const RouteEntry<A>*> routes; Peer<A>* p = *pli; p->dump_routes(routes); typename vector<const RouteEntry<A>*>::const_iterator ri; for (ri = routes.begin(); ri != routes.end(); ++ri) { const RouteEntry<A>* r = *ri; p->update_route(r->net(), r->nexthop(), RIP_INFINITY, r->tag(), r->policytags()); } pli++; }}template <typename A>boolPort<A>::output_allowed() const{ return enabled() && this->port_io_enabled() && (passive() == false);}template <typename A>voidPort<A>::set_enabled(bool en){ bool old_allowed = output_allowed(); _en = en; bool allowed = output_allowed(); if (allowed != old_allowed) { start_stop_output_processing(); } if (en == false) kill_peer_routes();}template <typename A>voidPort<A>::set_passive(bool p){ bool old_allowed = output_allowed(); _passive = p; bool allowed = output_allowed(); if (allowed != old_allowed) { start_stop_output_processing(); }}template <typename A>voidPort<A>::set_advertise_default_route(bool en){ _adv_def_rt = en;}template <typename A>voidPort<A>::set_accept_default_route(bool en){ _acc_def_rt = en;}template <typename A>voidPort<A>::set_accept_non_rip_requests(bool en){ _acc_non_rip_reqs = en;}template <typename A>voidPort<A>::parse_request(const Addr& src_addr, uint16_t src_port, const uint8_t* entries_ptr, uint32_t n_entries){ if (this->port_io_enabled() == false) { debug_msg("Discarding RIP request: port io system not enabled."); return; } const PacketRouteEntry<A> pre(entries_ptr); if (n_entries == 1 && pre.is_table_request()) { if (src_port == RIP_AF_CONSTANTS<A>::IP_PORT) { Peer<A>* p = peer(src_addr); if (p == 0) { p = create_peer(src_addr); p->counters().incr_packets_recv(); p->counters().incr_table_requests_recv(); } // if already doing unsolicited dump, then ignore // set unsolicited timer timeout to zero to trigger port // route dump unsolicited_response_timeout(); } else { if (queries_blocked()) return; // if already doing a debug dump, then ignore // start debug route dump if (_su_out && _su_out->running()) return; // Delete existing solicited update output, which is just lying // around, and re-instantiate to reply to table dump request delete _su_out; EventLoop& e = _pm.eventloop(); RouteDB<A>& rdb = _pm.system().route_db(); _su_out = new OutputTable<A>(e, *this, *_packet_queue, rdb, src_addr, src_port); _su_out->start(); block_queries(); } return; } if (queries_blocked()) return; // // This is a query for a set of routes. Answer it. // uint32_t i = 0; ResponsePacketAssembler<A> rpa(*this); RouteDB<A>& rdb = _pm.system().route_db(); while (i != n_entries) { RipPacket<A>* pkt = new RipPacket<A>(src_addr, src_port); rpa.packet_start(pkt); while (rpa.packet_full() == false && i != n_entries) { const uint8_t* pre_ptr = entries_ptr + i * PacketRouteEntry<A>::size(); const PacketRouteEntry<A> pre(pre_ptr); if (pre.prefix_len() > A::ADDR_BITLEN) { // Route request has an address with a bad prefix length // Unfortunately it's non-trivial for us to propagate this // back to the offending enquirer so we just stop processing // the request. delete (pkt); break; } const RouteEntry<A>* r = rdb.find_route(pre.net()); if (r) { rpa.packet_add_route(r->net(), r->nexthop(), r->cost(), r->tag()); } else { rpa.packet_add_route(pre.net(), A::ZERO(), RIP_INFINITY, 0); } i++; } list<RipPacket<A>*> auth_packets; if (rpa.packet_finish(auth_packets) == true) { typename list<RipPacket<A>*>::iterator iter; for (iter = auth_packets.begin(); iter != auth_packets.end(); ++iter) { RipPacket<A>* auth_pkt = *iter; _packet_queue->enqueue_packet(auth_pkt); counters().incr_non_rip_updates_sent(); } delete pkt; } else { delete pkt; break; } } push_packets(); block_queries();}template <typename A>voidPort<A>::port_io_receive(const A& src_address, uint16_t src_port, const uint8_t* rip_packet, size_t rip_packet_bytes){ string why; static_assert(RipPacketHeader::SIZE == 4); static_assert(PacketRouteEntry<A>::SIZE == 20); if (enabled() == false) { debug_msg("Discarding RIP packet: Port not enabled."); return; } Peer<A>* p = 0; if (src_port == RIP_AF_CONSTANTS<A>::IP_PORT) { p = peer(src_address); } else { if (accept_non_rip_requests() == false) { return; } XLOG_ASSERT(p == 0); } record_packet(p); if (rip_packet_bytes < RIPv2_MIN_PACKET_BYTES) { why = c_format("Packet size less than minimum (%u < %u)", XORP_UINT_CAST(rip_packet_bytes), XORP_UINT_CAST(RIPv2_MIN_PACKET_BYTES)); record_bad_packet(why, src_address, src_port, p); return; } const RipPacketHeader rph(rip_packet); // // Basic RIP packet header validity checks // if (rph.valid_command() == false) { why = c_format("Invalid command"); record_bad_packet(why, src_address, src_port, p); return; } else if (rph.valid_version(RIP_AF_CONSTANTS<A>::PACKET_VERSION) == false) { why = c_format("Invalid version (%d)", rph.version()); record_bad_packet(why, src_address, src_port, p); return; } else if (rph.valid_padding() == false) { why = c_format("Invalid padding (%u,%u)", rph.unused0(), rph.unused1()); record_bad_packet(why,src_address, src_port, p); return; } // // Check this is not an attempt to inject routes from non-RIP port // if (rph.command() == RipPacketHeader::RESPONSE && src_port != RIP_AF_CONSTANTS<A>::IP_PORT) { why = c_format("RIP response originating on wrong port (%d != %d)", src_port, RIP_AF_CONSTANTS<A>::IP_PORT); record_bad_packet(why, src_address, src_port, p); return; }#if defined (INSTANTIATE_IPV4) const uint8_t* entries_ptr = NULL; uint32_t n_entries = 0; bool new_peer = (p == NULL); if ((p != NULL) && (p->route_count() == 0)) { // // XXX: If the peer hasn't been active for long enough, then // consider it a new peer for authentication purpose. // The reason we need this modification is because the idle // peer state may be kept for a little bit too long (e.g., 2*180 // seconds), and if the peer is restarted before that we won't // accept its initial packet with sequence number of zero. // With this modification we can accept the first authentication // packet with sequence number of zero immediately after // all routes have expired (e.g., after 300 seconds). // new_peer = true; } if (af_state().auth_handler()->authenticate_inbound(rip_packet,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -