Added a fix to stop nasty NDP loops when being proactive on the NDP adverts
This commit is contained in:
parent
e8e3739126
commit
4ca86ef88e
@ -57,6 +57,19 @@ address::address(const address& addr)
|
|||||||
_mask.s6_addr32[3] = addr._mask.s6_addr32[3];
|
_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)
|
address::address(const std::string& str)
|
||||||
{
|
{
|
||||||
parse_string(str);
|
parse_string(str);
|
||||||
|
@ -31,6 +31,7 @@ class address {
|
|||||||
public:
|
public:
|
||||||
address();
|
address();
|
||||||
address(const address& addr);
|
address(const address& addr);
|
||||||
|
address(const ptr<address>& addr);
|
||||||
address(const std::string& str);
|
address(const std::string& str);
|
||||||
address(const char* str);
|
address(const char* str);
|
||||||
address(const in6_addr& addr);
|
address(const in6_addr& addr);
|
||||||
|
22
src/iface.cc
22
src/iface.cc
@ -385,7 +385,7 @@ ssize_t iface::read_solicit(address& saddr, address& daddr, address& taddr)
|
|||||||
saddr = ip6h->ip6_src;
|
saddr = ip6h->ip6_src;
|
||||||
|
|
||||||
logger::debug() << "iface::read_solicit() saddr=" << saddr.to_string()
|
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;
|
return len;
|
||||||
}
|
}
|
||||||
@ -589,10 +589,22 @@ int iface::poll_all()
|
|||||||
if (!saddr.is_unicast()/* || !daddr.is_multicast()*/) {
|
if (!saddr.is_unicast()/* || !daddr.is_multicast()*/) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (ifa->_pr) {
|
// Now process the solicit
|
||||||
ifa->_pr->handle_solicit(saddr, daddr, taddr);
|
ifa->_pr->handle_solicit(saddr, taddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if (ifa->read_advert(saddr, taddr) < 0) {
|
if (ifa->read_advert(saddr, taddr) < 0) {
|
||||||
logger::error() << "Failed to read from interface '%s'", ifa->_name.c_str();
|
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;
|
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);
|
sess->handle_advert(ifa);
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
@ -615,7 +627,7 @@ int iface::poll_all()
|
|||||||
|
|
||||||
if (found == false) {
|
if (found == false) {
|
||||||
if (ifa->owner()) {
|
if (ifa->owner()) {
|
||||||
ifa->owner()->handle_advert(saddr, taddr, ifa);
|
ifa->owner()->handle_advert(taddr, ifa);
|
||||||
} else {
|
} else {
|
||||||
logger::debug() << "iface::poll_all - ignoring advert on proxy iface=" << ifa->name();
|
logger::debug() << "iface::poll_all - ignoring advert on proxy iface=" << ifa->name();
|
||||||
}
|
}
|
||||||
|
90
src/proxy.cc
90
src/proxy.cc
@ -63,7 +63,7 @@ ptr<proxy> proxy::open(const std::string& ifname, bool promiscuous)
|
|||||||
return create(ifa, 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
|
// Let's check this proxy's list of sessions to see if we can
|
||||||
// find one with the same target address.
|
// 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);
|
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;
|
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
|
// 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.
|
// 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;
|
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 (ru->addr() == taddr) {
|
||||||
if (!se) {
|
if (!se) {
|
||||||
se = session::create(_ptr, saddr, daddr, taddr, _autowire, _keepalive, _retries);
|
se = session::create(_ptr, taddr, _autowire, _keepalive, _retries);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ru->is_auto()) {
|
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.
|
// it "static" and immediately send the response.
|
||||||
se->handle_advert();
|
se->handle_advert();
|
||||||
return se;
|
return se;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
ptr<iface> ifa = (*it)->ifa();
|
ptr<iface> ifa = (*it)->ifa();
|
||||||
@ -150,18 +121,6 @@ ptr<session> proxy::find_or_create_session(const address& saddr, const address&
|
|||||||
se->handle_advert();
|
se->handle_advert();
|
||||||
}
|
}
|
||||||
#endif
|
#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;
|
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()
|
logger::debug()
|
||||||
<< "proxy::handle_advert() proxy=" << (ifa() ? ifa()->name() : "null") << ", receiver=" << (receiver ? receiver->name() : "null")
|
<< "proxy::handle_advert() proxy=" << (ifa() ? ifa()->name() : "null") << ", receiver=" << (receiver ? receiver->name() : "null");
|
||||||
<< ", saddr=" << saddr.to_string()
|
|
||||||
<< ", taddr=" << taddr.to_string();
|
|
||||||
|
|
||||||
ptr<session> se = find_or_create_session(all_nodes, all_nodes, taddr, receiver);
|
ptr<session> se = find_or_create_session(taddr);
|
||||||
if (!se) return;
|
if (!se) return;
|
||||||
|
|
||||||
se->handle_advert(receiver);
|
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()
|
logger::debug()
|
||||||
<< "proxy::handle_solicit() ifa=" << ((_ifa) ? _ifa->name() : "null")
|
<< "proxy::handle_solicit() ifa=" << ((_ifa) ? _ifa->name() : "null");
|
||||||
<< ", saddr=" << saddr.to_string()
|
|
||||||
<< ", taddr=" << taddr.to_string();
|
|
||||||
|
|
||||||
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;
|
if (!se) return;
|
||||||
|
|
||||||
se->touch();
|
se->touch();
|
||||||
@ -201,11 +179,11 @@ void proxy::handle_solicit(const address& saddr, const address& daddr, const add
|
|||||||
switch (se->status()) {
|
switch (se->status()) {
|
||||||
case session::WAITING:
|
case session::WAITING:
|
||||||
case session::INVALID:
|
case session::INVALID:
|
||||||
return;
|
se->add_pending(saddr);
|
||||||
|
|
||||||
case session::VALID:
|
case session::VALID:
|
||||||
case session::RENEWING:
|
case session::RENEWING:
|
||||||
se->send_advert();
|
se->send_advert(saddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,11 +34,11 @@ public:
|
|||||||
|
|
||||||
static ptr<proxy> open(const std::string& ifn, bool promiscuous);
|
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);
|
void remove_session(const ptr<session>& se);
|
||||||
|
|
||||||
|
@ -114,16 +114,13 @@ session::~session()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr<session> session::create(const ptr<proxy>& pr, const address& saddr,
|
ptr<session> session::create(const ptr<proxy>& pr, const address& taddr, bool auto_wire, bool keepalive, int retries)
|
||||||
const address& daddr, const address& taddr, bool auto_wire, bool keepalive, int retries)
|
|
||||||
{
|
{
|
||||||
ptr<session> se(new session());
|
ptr<session> se(new session());
|
||||||
|
|
||||||
se->_ptr = se;
|
se->_ptr = se;
|
||||||
se->_pr = pr;
|
se->_pr = pr;
|
||||||
se->_saddr = address("::") == saddr ? all_nodes : saddr;
|
|
||||||
se->_taddr = taddr;
|
se->_taddr = taddr;
|
||||||
se->_daddr = daddr;
|
|
||||||
se->_autowire = auto_wire;
|
se->_autowire = auto_wire;
|
||||||
se->_keepalive = keepalive;
|
se->_keepalive = keepalive;
|
||||||
se->_retries = retries;
|
se->_retries = retries;
|
||||||
@ -134,8 +131,8 @@ ptr<session> session::create(const ptr<proxy>& pr, const address& saddr,
|
|||||||
_sessions.push_back(se);
|
_sessions.push_back(se);
|
||||||
|
|
||||||
logger::debug()
|
logger::debug()
|
||||||
<< "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", proxy=" << ((pr->ifa()) ? pr->ifa()->name() : "null") << ", saddr=" << saddr
|
<< "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", proxy=" << ((pr->ifa()) ? pr->ifa()->name() : "null")
|
||||||
<< ", daddr=" << daddr << ", taddr=" << taddr << " =" << logger::format("%x", (session* )se);
|
<< ", taddr=" << taddr << " =" << logger::format("%x", (session* )se);
|
||||||
|
|
||||||
return se;
|
return se;
|
||||||
}
|
}
|
||||||
@ -149,6 +146,16 @@ void session::add_iface(const ptr<iface>& ifa)
|
|||||||
_ifaces.push_back(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()
|
void session::send_solicit()
|
||||||
{
|
{
|
||||||
logger::debug() << "session::send_solicit() (_ifaces.size() = " << _ifaces.size() << ")";
|
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)
|
void session::handle_auto_wire(const ptr<iface>& ifa)
|
||||||
{
|
{
|
||||||
|
if (_wired == true)
|
||||||
|
return;
|
||||||
|
|
||||||
logger::debug()
|
logger::debug()
|
||||||
<< "session::handle_auto_wire() taddr=" << _taddr << ", ifa=" << ifa->name();
|
<< "session::handle_auto_wire() taddr=" << _taddr << ", ifa=" << ifa->name();
|
||||||
|
|
||||||
@ -238,8 +248,18 @@ void session::handle_advert()
|
|||||||
_status = VALID;
|
_status = VALID;
|
||||||
_ttl = _pr->ttl();
|
_ttl = _pr->ttl();
|
||||||
_fails = 0;
|
_fails = 0;
|
||||||
|
|
||||||
|
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();
|
send_advert(addr);
|
||||||
|
}
|
||||||
|
|
||||||
|
_pending.clear();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const address& session::taddr() const
|
const address& session::taddr() const
|
||||||
@ -247,16 +267,6 @@ const address& session::taddr() const
|
|||||||
return _taddr;
|
return _taddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const address& session::saddr() const
|
|
||||||
{
|
|
||||||
return _saddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const address& session::daddr() const
|
|
||||||
{
|
|
||||||
return _daddr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool session::autowire() const
|
bool session::autowire() const
|
||||||
{
|
{
|
||||||
return _autowire;
|
return _autowire;
|
||||||
|
@ -43,6 +43,8 @@ private:
|
|||||||
// An array of interfaces this session is monitoring for
|
// An array of interfaces this session is monitoring for
|
||||||
// ND_NEIGHBOR_ADVERT on.
|
// ND_NEIGHBOR_ADVERT on.
|
||||||
std::list<ptr<iface> > _ifaces;
|
std::list<ptr<iface> > _ifaces;
|
||||||
|
|
||||||
|
std::list<ptr<address> > _pending;
|
||||||
|
|
||||||
// The remaining time in miliseconds the object will stay in the
|
// The remaining time in miliseconds the object will stay in the
|
||||||
// interface's session array or cache.
|
// interface's session array or cache.
|
||||||
@ -70,10 +72,11 @@ public:
|
|||||||
// Destructor.
|
// Destructor.
|
||||||
~session();
|
~session();
|
||||||
|
|
||||||
static ptr<session> create(const ptr<proxy>& pr, const address& saddr,
|
static ptr<session> create(const ptr<proxy>& pr, const address& taddr, bool autowire, bool keepalive, int retries);
|
||||||
const address& daddr, const address& taddr, bool autowire, bool keepalive, int retries);
|
|
||||||
|
|
||||||
void add_iface(const ptr<iface>& ifa);
|
void add_iface(const ptr<iface>& ifa);
|
||||||
|
|
||||||
|
void add_pending(const address& addr);
|
||||||
|
|
||||||
const address& taddr() const;
|
const address& taddr() const;
|
||||||
|
|
||||||
@ -107,7 +110,7 @@ public:
|
|||||||
|
|
||||||
void touch();
|
void touch();
|
||||||
|
|
||||||
void send_advert();
|
void send_advert(const address& daddr);
|
||||||
|
|
||||||
void send_solicit();
|
void send_solicit();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user