Added a fix to stop nasty NDP loops when being proactive on the NDP adverts

This commit is contained in:
John Sharratt 2017-07-04 23:52:43 +02:00
parent e8e3739126
commit 4ca86ef88e
7 changed files with 103 additions and 86 deletions

View File

@ -57,6 +57,19 @@ address::address(const address& addr)
_mask.s6_addr32[3] = addr._mask.s6_addr32[3];
}
address::address(const ptr<address>& addr)
{
_addr.s6_addr32[0] = addr->_addr.s6_addr32[0];
_addr.s6_addr32[1] = addr->_addr.s6_addr32[1];
_addr.s6_addr32[2] = addr->_addr.s6_addr32[2];
_addr.s6_addr32[3] = addr->_addr.s6_addr32[3];
_mask.s6_addr32[0] = addr->_mask.s6_addr32[0];
_mask.s6_addr32[1] = addr->_mask.s6_addr32[1];
_mask.s6_addr32[2] = addr->_mask.s6_addr32[2];
_mask.s6_addr32[3] = addr->_mask.s6_addr32[3];
}
address::address(const std::string& str)
{
parse_string(str);

View File

@ -31,6 +31,7 @@ class address {
public:
address();
address(const address& addr);
address(const ptr<address>& addr);
address(const std::string& str);
address(const char* str);
address(const in6_addr& addr);

View File

@ -385,7 +385,7 @@ ssize_t iface::read_solicit(address& saddr, address& daddr, address& taddr)
saddr = ip6h->ip6_src;
logger::debug() << "iface::read_solicit() saddr=" << saddr.to_string()
<< ", daddr=" << daddr.to_string() << ", len=" << len;
<< ", daddr=" << daddr.to_string() << ", taddr=" << taddr.to_string() << ", len=" << len;
return len;
}
@ -590,9 +590,21 @@ int iface::poll_all()
continue;
}
if (ifa->_pr) {
ifa->_pr->handle_solicit(saddr, daddr, taddr);
if (ifa->_pr)
{
// Setup the reverse path
if (saddr.is_unicast()) {
ptr<session> se = ifa->_pr->find_or_create_session(saddr);
if (se) {
se->add_iface(ifa);
se->handle_advert(ifa);
}
}
// Now process the solicit
ifa->_pr->handle_solicit(saddr, taddr);
}
} else {
if (ifa->read_advert(saddr, taddr) < 0) {
logger::error() << "Failed to read from interface '%s'", ifa->_name.c_str();
@ -606,7 +618,7 @@ int iface::poll_all()
const ptr<session> sess = *s_it;
if ((sess->taddr() == taddr) && (sess->status() == session::WAITING || sess->status() == session::RENEWING)) {
if ((sess->taddr() == taddr)) {
sess->handle_advert(ifa);
found = true;
break;
@ -615,7 +627,7 @@ int iface::poll_all()
if (found == false) {
if (ifa->owner()) {
ifa->owner()->handle_advert(saddr, taddr, ifa);
ifa->owner()->handle_advert(taddr, ifa);
} else {
logger::debug() << "iface::poll_all - ignoring advert on proxy iface=" << ifa->name();
}

View File

@ -63,7 +63,7 @@ ptr<proxy> proxy::open(const std::string& ifname, bool promiscuous)
return create(ifa, promiscuous);
}
ptr<session> proxy::find_or_create_session(const address& saddr, const address& daddr, const address& taddr, const ptr<iface>& receiver)
ptr<session> proxy::find_or_create_session(const address& taddr)
{
// Let's check this proxy's list of sessions to see if we can
// find one with the same target address.
@ -75,31 +75,8 @@ ptr<session> proxy::find_or_create_session(const address& saddr, const address&
return (*sit);
}
// Check if there is an address for this specific interface it was received
// on (if so then immediately return a notice)
ptr<session> se;
if (receiver) {
for (std::list<ptr<route> >::iterator ad = address::addresses_begin();
ad != address::addresses_end(); ad++)
{
if ((*ad)->addr() == taddr && (*ad)->ifname() == receiver->name())
{
se = session::create(_ptr, saddr, daddr, taddr, _autowire, _keepalive, _retries);
if (se) {
se->add_iface(receiver);
_sessions.push_back(se);
logger::debug() << "proxy::handle_advert() found local taddr=" << taddr;
se->handle_advert(receiver);
return se;
}
}
}
}
// Since we couldn't find a session that matched, we'll try to find
// a matching rule instead, and then set up a new session.
@ -109,16 +86,9 @@ ptr<session> proxy::find_or_create_session(const address& saddr, const address&
logger::debug() << "checking " << ru->addr() << " against " << taddr;
if (!daddr.is_multicast() && ru->addr() != daddr && daddr != taddr) {
continue;
}
if (receiver && ru->ifa() && receiver->name() != ru->ifa()->name())
continue;
if (ru->addr() == taddr) {
if (!se) {
se = session::create(_ptr, saddr, daddr, taddr, _autowire, _keepalive, _retries);
se = session::create(_ptr, taddr, _autowire, _keepalive, _retries);
}
if (ru->is_auto()) {
@ -138,6 +108,7 @@ ptr<session> proxy::find_or_create_session(const address& saddr, const address&
// it "static" and immediately send the response.
se->handle_advert();
return se;
} else {
ptr<iface> ifa = (*it)->ifa();
@ -150,18 +121,6 @@ ptr<session> proxy::find_or_create_session(const address& saddr, const address&
se->handle_advert();
}
#endif
// If a local address exists and it is for the requested interface
// then we already have a valid session
for (std::list<ptr<route> >::iterator ad = address::addresses_begin();
ad != address::addresses_end(); ad++)
{
if ((*ad)->addr() == taddr && (*ad)->ifname() == ifa->name()) {
logger::debug() << "proxy::handle_advert() found local taddr=" << taddr;
se->handle_advert(ifa);
break;
}
}
}
}
}
@ -173,27 +132,46 @@ ptr<session> proxy::find_or_create_session(const address& saddr, const address&
return se;
}
void proxy::handle_advert(const address& saddr, const address& taddr, const ptr<iface>& receiver)
void proxy::handle_advert(const address& taddr, const ptr<iface>& receiver)
{
logger::debug()
<< "proxy::handle_advert() proxy=" << (ifa() ? ifa()->name() : "null") << ", receiver=" << (receiver ? receiver->name() : "null")
<< ", saddr=" << saddr.to_string()
<< ", taddr=" << taddr.to_string();
<< "proxy::handle_advert() proxy=" << (ifa() ? ifa()->name() : "null") << ", receiver=" << (receiver ? receiver->name() : "null");
ptr<session> se = find_or_create_session(all_nodes, all_nodes, taddr, receiver);
ptr<session> se = find_or_create_session(taddr);
if (!se) return;
se->handle_advert(receiver);
}
void proxy::handle_solicit(const address& saddr, const address& daddr, const address& taddr)
void proxy::handle_solicit(const address& saddr, const address& taddr)
{
logger::debug()
<< "proxy::handle_solicit() ifa=" << ((_ifa) ? _ifa->name() : "null")
<< ", saddr=" << saddr.to_string()
<< ", taddr=" << taddr.to_string();
<< "proxy::handle_solicit() ifa=" << ((_ifa) ? _ifa->name() : "null");
ptr<session> se = find_or_create_session(saddr, daddr, taddr, ptr<iface>());
// Check if the address is for an interface we own that is attached to
// one of the slave interfaces
for (std::list<ptr<route> >::iterator ad = address::addresses_begin(); ad != address::addresses_end(); ad++)
{
if ((*ad)->addr() == taddr)
{
for (std::list<ptr<rule> >::iterator it = _rules.begin(); it != _rules.end(); it++) {
ptr<rule> ru = *it;
if (ru->ifa() && ru->ifa()->name() == (*ad)->ifname())
{
logger::debug() << "proxy::handle_solicit() found local taddr=" << taddr;
if (_ifa)
_ifa->write_advert(saddr, taddr, router());
}
}
return;
}
}
// Otherwise find or create a session to scan for this address
ptr<session> se = find_or_create_session(taddr);
if (!se) return;
se->touch();
@ -201,11 +179,11 @@ void proxy::handle_solicit(const address& saddr, const address& daddr, const add
switch (se->status()) {
case session::WAITING:
case session::INVALID:
return;
se->add_pending(saddr);
case session::VALID:
case session::RENEWING:
se->send_advert();
se->send_advert(saddr);
}
}

View File

@ -34,11 +34,11 @@ public:
static ptr<proxy> open(const std::string& ifn, bool promiscuous);
ptr<session> find_or_create_session(const address& saddr, const address& daddr, const address& taddr, const ptr<iface>& receiver);
ptr<session> find_or_create_session(const address& taddr);
void handle_advert(const address& saddr, const address& taddr, const ptr<iface>& receiver);
void handle_advert(const address& taddr, const ptr<iface>& receiver);
void handle_solicit(const address& saddr, const address& daddr, const address& taddr);
void handle_solicit(const address& saddr, const address& taddr);
void remove_session(const ptr<session>& se);

View File

@ -114,16 +114,13 @@ session::~session()
}
}
ptr<session> session::create(const ptr<proxy>& pr, const address& saddr,
const address& daddr, const address& taddr, bool auto_wire, bool keepalive, int retries)
ptr<session> session::create(const ptr<proxy>& pr, const address& taddr, bool auto_wire, bool keepalive, int retries)
{
ptr<session> se(new session());
se->_ptr = se;
se->_pr = pr;
se->_saddr = address("::") == saddr ? all_nodes : saddr;
se->_taddr = taddr;
se->_daddr = daddr;
se->_autowire = auto_wire;
se->_keepalive = keepalive;
se->_retries = retries;
@ -134,8 +131,8 @@ ptr<session> session::create(const ptr<proxy>& pr, const address& saddr,
_sessions.push_back(se);
logger::debug()
<< "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", proxy=" << ((pr->ifa()) ? pr->ifa()->name() : "null") << ", saddr=" << saddr
<< ", daddr=" << daddr << ", taddr=" << taddr << " =" << logger::format("%x", (session* )se);
<< "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", proxy=" << ((pr->ifa()) ? pr->ifa()->name() : "null")
<< ", taddr=" << taddr << " =" << logger::format("%x", (session* )se);
return se;
}
@ -149,6 +146,16 @@ void session::add_iface(const ptr<iface>& ifa)
_ifaces.push_back(ifa);
}
void session::add_pending(const address& addr)
{
for (std::list<ptr<address> >::iterator ad = _pending.begin(); ad != _pending.end(); ad++) {
if (addr == (*ad))
return;
}
_pending.push_back(new address(addr));
}
void session::send_solicit()
{
logger::debug() << "session::send_solicit() (_ifaces.size() = " << _ifaces.size() << ")";
@ -171,13 +178,16 @@ void session::touch()
}
}
void session::send_advert()
void session::send_advert(const address& daddr)
{
_pr->ifa()->write_advert(_saddr, _taddr, _pr->router());
_pr->ifa()->write_advert(daddr, _taddr, _pr->router());
}
void session::handle_auto_wire(const ptr<iface>& ifa)
{
if (_wired == true)
return;
logger::debug()
<< "session::handle_auto_wire() taddr=" << _taddr << ", ifa=" << ifa->name();
@ -239,7 +249,17 @@ void session::handle_advert()
_ttl = _pr->ttl();
_fails = 0;
send_advert();
if (!_pending.empty()) {
for (std::list<ptr<address> >::iterator ad = _pending.begin();
ad != _pending.end(); ad++) {
ptr<address> addr = (*ad);
logger::debug() << " - forward to " << addr;
send_advert(addr);
}
_pending.clear();
}
}
const address& session::taddr() const
@ -247,16 +267,6 @@ const address& session::taddr() const
return _taddr;
}
const address& session::saddr() const
{
return _saddr;
}
const address& session::daddr() const
{
return _daddr;
}
bool session::autowire() const
{
return _autowire;

View File

@ -44,6 +44,8 @@ private:
// ND_NEIGHBOR_ADVERT on.
std::list<ptr<iface> > _ifaces;
std::list<ptr<address> > _pending;
// The remaining time in miliseconds the object will stay in the
// interface's session array or cache.
int _ttl;
@ -70,11 +72,12 @@ public:
// Destructor.
~session();
static ptr<session> create(const ptr<proxy>& pr, const address& saddr,
const address& daddr, const address& taddr, bool autowire, bool keepalive, int retries);
static ptr<session> create(const ptr<proxy>& pr, const address& taddr, bool autowire, bool keepalive, int retries);
void add_iface(const ptr<iface>& ifa);
void add_pending(const address& addr);
const address& taddr() const;
const address& daddr() const;
@ -107,7 +110,7 @@ public:
void touch();
void send_advert();
void send_advert(const address& daddr);
void send_solicit();