Doing some debugging on an issue with the routes not working from gateway hosted IPs

This commit is contained in:
John Sharratt 2017-07-05 07:36:39 +02:00
parent 4ca86ef88e
commit a008fad5f4
12 changed files with 531 additions and 188 deletions

View File

@ -91,6 +91,13 @@ proxy eth0 {
auto auto
# autovia <yes|no|true|false>
# Any addresses updated using NDP advertisments will use a gateway to
# route traffic on this particular interface (only works wiith the iface
# rule type). Default is no
autovia no
# Note that before version 0.2.2 of 'ndppd', if you didn't choose a # Note that before version 0.2.2 of 'ndppd', if you didn't choose a
# method, it defaulted to 'static'. For compatibility reasons we choose # method, it defaulted to 'static'. For compatibility reasons we choose
# to keep this behavior - for now (it may be removed in a future version). # to keep this behavior - for now (it may be removed in a future version).

View File

@ -132,6 +132,21 @@ bool address::operator!=(const address& addr) const
((_addr.s6_addr32[3] ^ addr._addr.s6_addr32[3]) & _mask.s6_addr32[3])); ((_addr.s6_addr32[3] ^ addr._addr.s6_addr32[3]) & _mask.s6_addr32[3]));
} }
bool address::is_empty() const
{
if (_addr.s6_addr32[0] == 0 &&
_addr.s6_addr32[1] == 0 &&
_addr.s6_addr32[2] == 0 &&
_addr.s6_addr32[3] == 0 &&
_mask.s6_addr32[0] == 0xffffffff &&
_mask.s6_addr32[1] == 0xffffffff &&
_mask.s6_addr32[2] == 0xffffffff &&
_mask.s6_addr32[3] == 0xffffffff)
return true;
return false;
}
void address::reset() void address::reset()
{ {
_addr.s6_addr32[0] = 0; _addr.s6_addr32[0] = 0;
@ -321,6 +336,10 @@ bool address::is_multicast() const
bool address::is_unicast() const bool address::is_unicast() const
{ {
if (_addr.s6_addr32[2] == 0 &&
_addr.s6_addr32[3] == 0)
return false;
return _addr.s6_addr[0] != 0xff; return _addr.s6_addr[0] != 0xff;
} }
@ -360,7 +379,8 @@ void address::load(const std::string& path)
ifs.getline(buf, sizeof(buf)); ifs.getline(buf, sizeof(buf));
if (ifs.gcount() < 53) { if (ifs.gcount() < 53) {
logger::debug() << "skipping entry (size=" << ifs.gcount() << ")"; if (ifs.gcount() > 0)
logger::debug() << "skipping entry (size=" << ifs.gcount() << ")";
continue; continue;
} }

View File

@ -56,6 +56,8 @@ public:
bool operator!=(const address& addr) const; bool operator!=(const address& addr) const;
void reset(); void reset();
bool is_empty() const;
const std::string to_string() const; const std::string to_string() const;

View File

@ -40,6 +40,7 @@
#include <map> #include <map>
#include "ndppd.h" #include "ndppd.h"
#include "route.h"
NDPPD_NS_BEGIN NDPPD_NS_BEGIN
@ -72,6 +73,9 @@ iface::~iface()
} }
_map_dirty = true; _map_dirty = true;
_serves.clear();
_parents.clear();
} }
ptr<iface> iface::open_pfd(const std::string& name, bool promiscuous) ptr<iface> iface::open_pfd(const std::string& name, bool promiscuous)
@ -297,7 +301,7 @@ ptr<iface> iface::open_ifd(const std::string& name)
return ifa; return ifa;
} }
ssize_t iface::read(int fd, struct sockaddr* saddr, uint8_t* msg, size_t size) ssize_t iface::read(int fd, struct sockaddr* saddr, ssize_t saddr_size, uint8_t* msg, size_t size)
{ {
struct msghdr mhdr; struct msghdr mhdr;
struct iovec iov; struct iovec iov;
@ -311,17 +315,17 @@ ssize_t iface::read(int fd, struct sockaddr* saddr, uint8_t* msg, size_t size)
memset(&mhdr, 0, sizeof(mhdr)); memset(&mhdr, 0, sizeof(mhdr));
mhdr.msg_name = (caddr_t)saddr; mhdr.msg_name = (caddr_t)saddr;
mhdr.msg_namelen = sizeof(struct sockaddr); mhdr.msg_namelen = saddr_size;
mhdr.msg_iov =& iov; mhdr.msg_iov =& iov;
mhdr.msg_iovlen = 1; mhdr.msg_iovlen = 1;
logger::debug() << "iface::read() ifa=" << name() << ", len=" << len;
if ((len = recvmsg(fd,& mhdr, 0)) < 0) if ((len = recvmsg(fd,& mhdr, 0)) < 0)
{ {
logger::error() << "iface::read() failed! error=" << logger::err() << ", ifa=" << name(); logger::error() << "iface::read() failed! error=" << logger::err() << ", ifa=" << name();
return -1; return -1;
} }
logger::debug() << "iface::read() ifa=" << name() << ", len=" << len;
if (len < sizeof(struct icmp6_hdr)) if (len < sizeof(struct icmp6_hdr))
return -1; return -1;
@ -369,7 +373,7 @@ ssize_t iface::read_solicit(address& saddr, address& daddr, address& taddr)
uint8_t msg[256]; uint8_t msg[256];
ssize_t len; ssize_t len;
if ((len = read(_pfd, (struct sockaddr*)&t_saddr, msg, sizeof(msg))) < 0) { if ((len = read(_pfd, (struct sockaddr*)&t_saddr, sizeof(struct sockaddr_ll), msg, sizeof(msg))) < 0) {
logger::warning() << "iface::read_solicit() failed: " << logger::err(); logger::warning() << "iface::read_solicit() failed: " << logger::err();
return -1; return -1;
} }
@ -383,6 +387,11 @@ ssize_t iface::read_solicit(address& saddr, address& daddr, address& taddr)
taddr = ns->nd_ns_target; taddr = ns->nd_ns_target;
daddr = ip6h->ip6_dst; daddr = ip6h->ip6_dst;
saddr = ip6h->ip6_src; saddr = ip6h->ip6_src;
// Ignore packets sent from this machine
if (iface::is_local(saddr) == true) {
return 0;
}
logger::debug() << "iface::read_solicit() saddr=" << saddr.to_string() logger::debug() << "iface::read_solicit() saddr=" << saddr.to_string()
<< ", daddr=" << daddr.to_string() << ", taddr=" << taddr.to_string() << ", len=" << len; << ", daddr=" << daddr.to_string() << ", taddr=" << taddr.to_string() << ", len=" << len;
@ -465,13 +474,22 @@ ssize_t iface::read_advert(address& saddr, address& taddr)
struct sockaddr_in6 t_saddr; struct sockaddr_in6 t_saddr;
uint8_t msg[256]; uint8_t msg[256];
ssize_t len; ssize_t len;
memset(&t_saddr, 0, sizeof(struct sockaddr_in6));
t_saddr.sin6_family = AF_INET6;
t_saddr.sin6_port = htons(IPPROTO_ICMPV6); // Needed?
if ((len = read(_ifd, (struct sockaddr* )&t_saddr, msg, sizeof(msg))) < 0) { if ((len = read(_ifd, (struct sockaddr* )&t_saddr, sizeof(struct sockaddr_in6), msg, sizeof(msg))) < 0) {
logger::warning() << "iface::read_advert() failed: " << logger::err(); logger::warning() << "iface::read_advert() failed: " << logger::err();
return -1; return -1;
} }
saddr = t_saddr.sin6_addr; saddr = t_saddr.sin6_addr;
// Ignore packets sent from this machine
if (iface::is_local(saddr) == true) {
return 0;
}
if (((struct icmp6_hdr* )msg)->icmp6_type != ND_NEIGHBOR_ADVERT) if (((struct icmp6_hdr* )msg)->icmp6_type != ND_NEIGHBOR_ADVERT)
return -1; return -1;
@ -483,6 +501,79 @@ ssize_t iface::read_advert(address& saddr, address& taddr)
return len; return len;
} }
bool iface::is_local(const address& addr)
{
// 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() == addr)
return true;
}
return false;
}
bool iface::handle_local(const address& saddr, const address& taddr)
{
// 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)
{
// Loop through all the serves that are using this iface to respond to NDP solicitation requests
for (std::list<weak_ptr<proxy> >::iterator pit = serves_begin(); pit != serves_end(); pit++) {
ptr<proxy> pr = (*pit);
if (!pr) continue;
for (std::list<ptr<rule> >::iterator it = pr->rules_begin(); it != pr->rules_end(); it++) {
ptr<rule> ru = *it;
if (ru->daughter() && ru->daughter()->name() == (*ad)->ifname())
{
logger::debug() << "proxy::handle_solicit() found local taddr=" << taddr;
write_advert(saddr, taddr, false);
return true;
}
}
}
}
}
return false;
}
void iface::handle_reverse_advert(const address& saddr, const std::string& ifname)
{
if (!saddr.is_unicast())
return;
logger::debug()
<< "proxy::handle_reverse_advert()";
// Loop through all the parents that forward new NDP soliciation requests to this interface
for (std::list<weak_ptr<proxy> >::iterator pit = parents_begin(); pit != parents_end(); pit++) {
ptr<proxy> parent = (*pit);
if (!parent || !parent->ifa()) {
continue;
}
// Setup the reverse path on any proxies that are dealing
// with the reverse direction (this helps improve connectivity and
// latency in a full duplex setup)
for (std::list<ptr<rule> >::iterator it = parent->rules_begin(); it != parent->rules_end(); it++) {
ptr<rule> ru = *it;
if (ru->addr() == saddr &&
ru->daughter()->name() == ifname)
{
logger::debug() << " - generating artifical advertisement: " << ifname;
parent->handle_stateless_advert(saddr, saddr, ifname, ru->autovia());
}
}
}
}
void iface::fixup_pollfds() void iface::fixup_pollfds()
{ {
_pollfds.resize(_map.size()* 2); _pollfds.resize(_map.size()* 2);
@ -505,22 +596,6 @@ void iface::fixup_pollfds()
} }
} }
void iface::remove_session(const ptr<session>& se)
{
for (std::list<weak_ptr<session> >::iterator it = _sessions.begin();
it != _sessions.end(); it++) {
if (*it == se) {
_sessions.erase(it);
break;
}
}
}
void iface::add_session(const ptr<session>& se)
{
_sessions.push_back(se);
}
void iface::cleanup() void iface::cleanup()
{ {
for (std::map<std::string, weak_ptr<iface> >::iterator it = _map.begin(); for (std::map<std::string, weak_ptr<iface> >::iterator it = _map.begin();
@ -579,58 +654,95 @@ int iface::poll_all()
ptr<iface> ifa = i_it->second; ptr<iface> ifa = i_it->second;
address saddr, daddr, taddr; address saddr, daddr, taddr;
ssize_t size;
if (is_pfd) { if (is_pfd) {
if (ifa->read_solicit(saddr, daddr, taddr) < 0) { size = ifa->read_solicit(saddr, daddr, taddr);
if (size < 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();
continue; continue;
} }
if (size == 0) {
if (!saddr.is_unicast()/* || !daddr.is_multicast()*/) { logger::debug() << "iface::read_solicit() loopback received and ignored";
continue; continue;
} }
if (ifa->_pr) // Process any local addresses for interfaces that we are proxying
{ if (ifa->handle_local(saddr, taddr) == true) {
// Setup the reverse path continue;
if (saddr.is_unicast()) { }
ptr<session> se = ifa->_pr->find_or_create_session(saddr);
if (se) { // We have to handle all the parents who may be interested in
se->add_iface(ifa); // the reverse path towards the one who sent this solicit.
se->handle_advert(ifa); // In fact, the parent need to know the source address in order
} // to respond to NDP Solicitations
} ifa->handle_reverse_advert(saddr, ifa->name());
// Now process the solicit // Loop through all the proxies that are using this iface to respond to NDP solicitation requests
ifa->_pr->handle_solicit(saddr, taddr); bool handled = false;
for (std::list<weak_ptr<proxy> >::iterator pit = ifa->serves_begin(); pit != ifa->serves_end(); pit++) {
ptr<proxy> pr = (*pit);
if (!pr) continue;
// Process the solicitation request by relating it to other
// interfaces or lookup up any statics routes we have configured
handled = true;
pr->handle_solicit(saddr, taddr, ifa->name());
}
// If it was not handled then write an error message
if (handled == false) {
logger::debug() << " - solicit was ignored";
} }
} else { } else {
if (ifa->read_advert(saddr, taddr) < 0) { size = ifa->read_advert(saddr, taddr);
if (size < 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();
continue; continue;
} }
if (size == 0) {
bool found = false; logger::debug() << "iface::read_advert() loopback received and ignored";
for (std::list<weak_ptr<session> >::iterator s_it = ifa->_sessions.begin(); continue;
s_it != ifa->_sessions.end(); s_it++) {
assert(!s_it->is_null());
const ptr<session> sess = *s_it;
if ((sess->taddr() == taddr)) {
sess->handle_advert(ifa);
found = true;
break;
}
} }
if (found == false) { // Process the NDP advert
if (ifa->owner()) { bool handled = false;
ifa->owner()->handle_advert(taddr, ifa); for (std::list<weak_ptr<proxy> >::iterator pit = ifa->parents_begin(); pit != ifa->parents_end(); pit++) {
} else { ptr<proxy> pr = (*pit);
logger::debug() << "iface::poll_all - ignoring advert on proxy iface=" << ifa->name(); if (!pr || !pr->ifa()) {
continue;
} }
// The proxy must have a rule for this interface or it is not meant to receive
// any notifications and thus they must be ignored
bool autovia = false;
bool is_relevant = false;
for (std::list<ptr<rule> >::iterator it = pr->rules_begin(); it != pr->rules_end(); it++) {
ptr<rule> ru = *it;
if (ru->addr() == taddr &&
ru->daughter() &&
ru->daughter()->name() == ifa->name())
{
is_relevant = true;
autovia = ru->autovia();
break;
}
}
if (is_relevant == false) {
logger::debug() << "iface::read_advert() advert is not for " << ifa->name() << "...skipping";
continue;
}
// Process the NDP advertisement
handled = true;
pr->handle_advert(saddr, taddr, ifa->name(), autovia);
}
// If it was not handled then write an error message
if (handled == false) {
logger::debug() << " - advert was ignored";
} }
} }
} }
@ -721,24 +833,34 @@ const std::string& iface::name() const
return _name; return _name;
} }
void iface::pr(const ptr<proxy>& pr) void iface::add_serves(const ptr<proxy>& pr)
{ {
_pr = pr; _serves.push_back(pr);
} }
const ptr<proxy>& iface::pr() const std::list<weak_ptr<proxy> >::iterator iface::serves_begin()
{ {
return _pr; return _serves.begin();
} }
void iface::owner(const ptr<proxy>& pr) std::list<weak_ptr<proxy> >::iterator iface::serves_end()
{ {
_owner = pr; return _serves.end();
} }
const ptr<proxy>& iface::owner() const void iface::add_parent(const ptr<proxy>& pr)
{ {
return _owner; _parents.push_back(pr);
}
std::list<weak_ptr<proxy> >::iterator iface::parents_begin()
{
return _parents.begin();
}
std::list<weak_ptr<proxy> >::iterator iface::parents_end()
{
return _parents.end();
} }
NDPPD_NS_END NDPPD_NS_END

View File

@ -42,7 +42,7 @@ public:
static int poll_all(); static int poll_all();
ssize_t read(int fd, struct sockaddr* saddr, uint8_t* msg, size_t size); ssize_t read(int fd, struct sockaddr* saddr, ssize_t saddr_size, uint8_t* msg, size_t size);
ssize_t write(int fd, const address& daddr, const uint8_t* msg, size_t size); ssize_t write(int fd, const address& daddr, const uint8_t* msg, size_t size);
@ -57,25 +57,31 @@ public:
// Reads a NB_NEIGHBOR_ADVERT message from the _ifd socket; // Reads a NB_NEIGHBOR_ADVERT message from the _ifd socket;
ssize_t read_advert(address& saddr, address& taddr); ssize_t read_advert(address& saddr, address& taddr);
bool handle_local(const address& saddr, const address& taddr);
bool is_local(const address& addr);
void handle_reverse_advert(const address& saddr, const std::string& ifname);
// Returns the name of the interface. // Returns the name of the interface.
const std::string& name() const; const std::string& name() const;
// Adds a session to be monitored for ND_NEIGHBOR_ADVERT messages.
void add_session(const ptr<session>& se);
void remove_session(const ptr<session>& se);
void pr(const ptr<proxy>& pr);
const ptr<proxy>& pr() const; std::list<weak_ptr<proxy> >::iterator serves_begin();
void owner(const ptr<proxy>& pr); std::list<weak_ptr<proxy> >::iterator serves_end();
const ptr<proxy>& owner() const; void add_serves(const ptr<proxy>& proxy);
std::list<weak_ptr<proxy> >::iterator parents_begin();
std::list<weak_ptr<proxy> >::iterator parents_end();
void add_parent(const ptr<proxy>& parent);
static std::map<std::string, weak_ptr<iface> > _map;
private: private:
static std::map<std::string, weak_ptr<iface> > _map;
static bool _map_dirty; static bool _map_dirty;
@ -106,14 +112,10 @@ private:
// Name of this interface. // Name of this interface.
std::string _name; std::string _name;
// An array of sessions that are monitoring this interface for
// ND_NEIGHBOR_ADVERT messages.
std::list<weak_ptr<session> > _sessions;
weak_ptr<proxy> _pr;
weak_ptr<proxy> _owner; std::list<weak_ptr<proxy> > _serves;
std::list<weak_ptr<proxy> > _parents;
// The link-layer address of this interface. // The link-layer address of this interface.
struct ether_addr hwaddr; struct ether_addr hwaddr;

View File

@ -146,6 +146,8 @@ static bool configure(ptr<conf>& cf)
address::ttl(30000); address::ttl(30000);
else else
address::ttl(*x_cf); address::ttl(*x_cf);
std::list<ptr<rule> > myrules;
std::vector<ptr<conf> >::const_iterator p_it; std::vector<ptr<conf> >::const_iterator p_it;
@ -212,6 +214,12 @@ static bool configure(ptr<conf>& cf)
ptr<conf> ru_cf =* r_it; ptr<conf> ru_cf =* r_it;
address addr(*ru_cf); address addr(*ru_cf);
bool autovia = false;
if (!(x_cf = ru_cf->find("autovia")))
autovia = false;
else
autovia = *x_cf;
if (x_cf = ru_cf->find("iface")) if (x_cf = ru_cf->find("iface"))
{ {
@ -219,17 +227,58 @@ static bool configure(ptr<conf>& cf)
if (!ifa || ifa.is_null() == true) { if (!ifa || ifa.is_null() == true) {
return false; return false;
} }
ifa->owner(pr);
pr->add_rule(addr, ifa); ifa->add_parent(pr);
myrules.push_back(pr->add_rule(addr, ifa, autovia));
} else if (ru_cf->find("auto")) { } else if (ru_cf->find("auto")) {
pr->add_rule(addr, true); myrules.push_back(pr->add_rule(addr, true));
} else { } else {
pr->add_rule(addr, false); myrules.push_back(pr->add_rule(addr, false));
} }
} }
} }
// Print out all the topology
for (std::map<std::string, weak_ptr<iface> >::iterator i_it = iface::_map.begin(); i_it != iface::_map.end(); i_it++) {
ptr<iface> ifa = i_it->second;
logger::debug() << "iface " << ifa->name() << " {";
for (std::list<weak_ptr<proxy> >::iterator pit = ifa->serves_begin(); pit != ifa->serves_end(); pit++) {
ptr<proxy> pr = (*pit);
if (!pr) continue;
logger::debug() << " " << "proxy " << logger::format("%x", pr.get_pointer()) << " {";
for (std::list<ptr<rule> >::iterator rit = pr->rules_begin(); rit != pr->rules_end(); rit++) {
ptr<rule> ru = *rit;
logger::debug() << " " << "rule " << logger::format("%x", ru.get_pointer()) << " {";
logger::debug() << " " << "taddr " << ru->addr()<< ";";
if (ru->is_auto())
logger::debug() << " " << "auto;";
else if (!ru->daughter())
logger::debug() << " " << "static;";
else
logger::debug() << " " << "iface " << ru->daughter()->name() << ";";
logger::debug() << " }";
}
logger::debug() << " }";
}
logger::debug() << " " << "parents {";
for (std::list<weak_ptr<proxy> >::iterator pit = ifa->parents_begin(); pit != ifa->parents_end(); pit++) {
ptr<proxy> pr = (*pit);
logger::debug() << " " << "parent " << logger::format("%x", pr.get_pointer()) << ";";
}
logger::debug() << " }";
logger::debug() << "}";
}
return true; return true;
} }

View File

@ -36,6 +36,34 @@ proxy::proxy() :
{ {
} }
ptr<proxy> proxy::find_aunt(const std::string& ifname, const address& taddr)
{
for (std::list<ptr<proxy> >::iterator sit = _list.begin();
sit != _list.end(); sit++)
{
ptr<proxy> pr = (*sit);
bool has_addr = false;
for (std::list<ptr<rule> >::iterator it = pr->_rules.begin(); it != pr->_rules.end(); it++) {
ptr<rule> ru = *it;
if (ru->addr() == taddr) {
has_addr = true;
break;
}
}
if (has_addr == false) {
continue;
}
if (pr->ifa() && pr->ifa()->name() == ifname)
return pr;
}
return ptr<proxy>();
}
ptr<proxy> proxy::create(const ptr<iface>& ifa, bool promiscuous) ptr<proxy> proxy::create(const ptr<iface>& ifa, bool promiscuous)
{ {
ptr<proxy> pr(new proxy()); ptr<proxy> pr(new proxy());
@ -45,7 +73,7 @@ ptr<proxy> proxy::create(const ptr<iface>& ifa, bool promiscuous)
_list.push_back(pr); _list.push_back(pr);
ifa->pr(pr); ifa->add_serves(pr);
logger::debug() << "proxy::create() if=" << ifa->name(); logger::debug() << "proxy::create() if=" << ifa->name();
@ -99,11 +127,11 @@ ptr<session> proxy::find_or_create_session(const address& taddr)
} else { } else {
ptr<iface> ifa = rt->ifa(); ptr<iface> ifa = rt->ifa();
if (ifa && (ifa != ru->ifa())) { if (ifa && (ifa != ru->daughter())) {
se->add_iface(ifa); se->add_iface(ifa);
} }
} }
} else if (!ru->ifa()) { } else if (!ru->daughter()) {
// This rule doesn't have an interface, and thus we'll consider // This rule doesn't have an interface, and thus we'll consider
// it "static" and immediately send the response. // it "static" and immediately send the response.
se->handle_advert(); se->handle_advert();
@ -111,9 +139,9 @@ ptr<session> proxy::find_or_create_session(const address& taddr)
} else { } else {
ptr<iface> ifa = (*it)->ifa(); ptr<iface> ifa = ru->daughter();
se->add_iface(ifa); se->add_iface(ifa);
#ifdef WITH_ND_NETLINK #ifdef WITH_ND_NETLINK
if (if_addr_find(ifa->name(), &taddr.const_addr())) { if (if_addr_find(ifa->name(), &taddr.const_addr())) {
logger::debug() << "Sending NA out " << ifa->name(); logger::debug() << "Sending NA out " << ifa->name();
@ -132,64 +160,67 @@ ptr<session> proxy::find_or_create_session(const address& taddr)
return se; return se;
} }
void proxy::handle_advert(const address& taddr, const ptr<iface>& receiver) void proxy::handle_advert(const address& saddr, const address& taddr, const std::string& ifname, bool use_via)
{
// If a session exists then process the advert in the context of the session
for (std::list<ptr<session> >::iterator s_it = _sessions.begin();
s_it != _sessions.end(); s_it++)
{
const ptr<session> sess = *s_it;
if ((sess->taddr() == taddr)) {
sess->handle_advert(saddr, ifname, use_via);
}
}
}
void proxy::handle_stateless_advert(const address& saddr, const address& taddr, const std::string& ifname, bool use_via)
{ {
logger::debug() logger::debug()
<< "proxy::handle_advert() proxy=" << (ifa() ? ifa()->name() : "null") << ", receiver=" << (receiver ? receiver->name() : "null"); << "proxy::handle_stateless_advert() proxy=" << (ifa() ? ifa()->name() : "null") << ", taddr=" << taddr.to_string() << ", ifname=" << ifname;
ptr<session> se = find_or_create_session(taddr); ptr<session> se = find_or_create_session(taddr);
if (!se) return; if (!se) return;
se->handle_advert(receiver); if (_autowire == true && se->status() == session::WAITING) {
se->handle_auto_wire(saddr, ifname, use_via);
}
} }
void proxy::handle_solicit(const address& saddr, const address& taddr) void proxy::handle_solicit(const address& saddr, const address& taddr, const std::string& ifname)
{ {
logger::debug() logger::debug()
<< "proxy::handle_solicit() ifa=" << ((_ifa) ? _ifa->name() : "null"); << "proxy::handle_solicit()";
// 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 // Otherwise find or create a session to scan for this address
ptr<session> se = find_or_create_session(taddr); ptr<session> se = find_or_create_session(taddr);
if (!se) return; if (!se) return;
// Touching the session will cause an NDP advert to be transmitted to all
// the daughters
se->touch(); se->touch();
switch (se->status()) { // If our session is confirmed then we can respoond with an advert otherwise
case session::WAITING: // subscribe so that if it does become active we can notify everyone
case session::INVALID: if (saddr != taddr) {
se->add_pending(saddr); switch (se->status()) {
case session::WAITING:
case session::INVALID:
se->add_pending(saddr);
break;
case session::VALID: case session::VALID:
case session::RENEWING: case session::RENEWING:
se->send_advert(saddr); se->send_advert(saddr);
} break;
}
}
} }
ptr<rule> proxy::add_rule(const address& addr, const ptr<iface>& ifa) ptr<rule> proxy::add_rule(const address& addr, const ptr<iface>& ifa, bool autovia)
{ {
ptr<rule> ru(rule::create(_ptr, addr, ifa)); ptr<rule> ru(rule::create(_ptr, addr, ifa));
ru->autovia(autovia);
_rules.push_back(ru); _rules.push_back(ru);
return ru; return ru;
} }
@ -201,6 +232,16 @@ ptr<rule> proxy::add_rule(const address& addr, bool aut)
return ru; return ru;
} }
std::list<ptr<rule> >::iterator proxy::rules_begin()
{
return _rules.begin();
}
std::list<ptr<rule> >::iterator proxy::rules_end()
{
return _rules.end();
}
void proxy::remove_session(const ptr<session>& se) void proxy::remove_session(const ptr<session>& se)
{ {
_sessions.remove(se); _sessions.remove(se);

View File

@ -29,22 +29,30 @@ class iface;
class rule; class rule;
class proxy { class proxy {
public: public:
static ptr<proxy> create(const ptr<iface>& ifa, bool promiscuous); static ptr<proxy> create(const ptr<iface>& ifa, bool promiscuous);
static ptr<proxy> find_aunt(const std::string& ifname, const address& taddr);
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& taddr); ptr<session> find_or_create_session(const address& taddr);
void handle_advert(const address& taddr, const ptr<iface>& receiver); void handle_advert(const address& saddr, const address& taddr, const std::string& ifname, bool use_via);
void handle_solicit(const address& saddr, const address& taddr); void handle_stateless_advert(const address& saddr, const address& taddr, const std::string& ifname, bool use_via);
void handle_solicit(const address& saddr, const address& taddr, const std::string& ifname);
void remove_session(const ptr<session>& se); void remove_session(const ptr<session>& se);
ptr<rule> add_rule(const address& addr, const ptr<iface>& ifa); ptr<rule> add_rule(const address& addr, const ptr<iface>& ifa, bool autovia);
ptr<rule> add_rule(const address& addr, bool aut = false); ptr<rule> add_rule(const address& addr, bool aut = false);
std::list<ptr<rule> >::iterator rules_begin();
std::list<ptr<rule> >::iterator rules_end();
const ptr<iface>& ifa() const; const ptr<iface>& ifa() const;

View File

@ -31,6 +31,8 @@ bool rule::_any_aut = false;
bool rule::_any_iface = false; bool rule::_any_iface = false;
bool rule::_any_static = false;
rule::rule() rule::rule()
{ {
} }
@ -40,7 +42,7 @@ ptr<rule> rule::create(const ptr<proxy>& pr, const address& addr, const ptr<ifac
ptr<rule> ru(new rule()); ptr<rule> ru(new rule());
ru->_ptr = ru; ru->_ptr = ru;
ru->_pr = pr; ru->_pr = pr;
ru->_ifa = ifa; ru->_daughter = ifa;
ru->_addr = addr; ru->_addr = addr;
ru->_aut = false; ru->_aut = false;
_any_iface = true; _any_iface = true;
@ -68,6 +70,9 @@ ptr<rule> rule::create(const ptr<proxy>& pr, const address& addr, bool aut)
ru->_addr = addr; ru->_addr = addr;
ru->_aut = aut; ru->_aut = aut;
_any_aut = _any_aut || aut; _any_aut = _any_aut || aut;
if (aut == false)
_any_static = true;
logger::debug() logger::debug()
<< "rule::create() if=" << pr->ifa()->name().c_str() << ", addr=" << addr << "rule::create() if=" << pr->ifa()->name().c_str() << ", addr=" << addr
@ -81,9 +86,9 @@ const address& rule::addr() const
return _addr; return _addr;
} }
ptr<iface> rule::ifa() const ptr<iface> rule::daughter() const
{ {
return _ifa; return _daughter;
} }
bool rule::is_auto() const bool rule::is_auto() const
@ -91,6 +96,16 @@ bool rule::is_auto() const
return _aut; return _aut;
} }
bool rule::autovia() const
{
return _autovia;
}
void rule::autovia(bool val)
{
_autovia = val;
}
bool rule::any_auto() bool rule::any_auto()
{ {
return _any_aut; return _any_aut;
@ -101,6 +116,11 @@ bool rule::any_iface()
return _any_iface; return _any_iface;
} }
bool rule::any_static()
{
return _any_static;
}
bool rule::check(const address& addr) const bool rule::check(const address& addr) const
{ {
return _addr == addr; return _addr == addr;

View File

@ -37,7 +37,7 @@ public:
const address& addr() const; const address& addr() const;
ptr<iface> ifa() const; ptr<iface> daughter() const;
bool is_auto() const; bool is_auto() const;
@ -45,14 +45,20 @@ public:
static bool any_auto(); static bool any_auto();
static bool any_static();
static bool any_iface(); static bool any_iface();
bool autovia() const;
void autovia(bool val);
private: private:
weak_ptr<rule> _ptr; weak_ptr<rule> _ptr;
weak_ptr<proxy> _pr; weak_ptr<proxy> _pr;
ptr<iface> _ifa; ptr<iface> _daughter;
address _addr; address _addr;
@ -60,7 +66,11 @@ private:
static bool _any_aut; static bool _any_aut;
static bool _any_static;
static bool _any_iface; static bool _any_iface;
bool _autovia;
rule(); rule();
}; };

View File

@ -45,15 +45,18 @@ void session::update_all(int elapsed_time)
switch (se->_status) { switch (se->_status) {
case session::WAITING: case session::WAITING:
logger::debug() << "session is now invalid [taddr=" << se->_taddr << "]";
if (se->_fails < se->_retries) { if (se->_fails < se->_retries) {
logger::debug() << "session will keep trying [taddr=" << se->_taddr << "]";
se->_ttl = se->_pr->timeout(); se->_ttl = se->_pr->timeout();
se->_fails++; se->_fails++;
// Send another solicit // Send another solicit
se->send_solicit(); se->send_solicit();
} else { } else {
logger::debug() << "session is now invalid [taddr=" << se->_taddr << "]";
se->_status = session::INVALID; se->_status = session::INVALID;
se->_ttl = se->_pr->deadtime(); se->_ttl = se->_pr->deadtime();
} }
@ -103,15 +106,9 @@ session::~session()
if (_wired == true) { if (_wired == true) {
for (std::list<ptr<iface> >::iterator it = _ifaces.begin(); for (std::list<ptr<iface> >::iterator it = _ifaces.begin();
it != _ifaces.end(); it++) { it != _ifaces.end(); it++) {
handle_auto_unwire((*it)); handle_auto_unwire((*it)->name());
} }
} }
for (std::list<ptr<iface> >::iterator it = _ifaces.begin();
it != _ifaces.end(); it++)
{
(*it)->remove_session(_ptr);
}
} }
ptr<session> session::create(const ptr<proxy>& pr, 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)
@ -125,7 +122,7 @@ ptr<session> session::create(const ptr<proxy>& pr, const address& taddr, bool au
se->_keepalive = keepalive; se->_keepalive = keepalive;
se->_retries = retries; se->_retries = retries;
se->_wired = false; se->_wired = false;
se->_ttl = pr->timeout(); se->_ttl = pr->ttl();
se->_touched = false; se->_touched = false;
_sessions.push_back(se); _sessions.push_back(se);
@ -142,7 +139,6 @@ void session::add_iface(const ptr<iface>& ifa)
if (std::find(_ifaces.begin(), _ifaces.end(), ifa) != _ifaces.end()) if (std::find(_ifaces.begin(), _ifaces.end(), ifa) != _ifaces.end())
return; return;
ifa->add_session(_ptr);
_ifaces.push_back(ifa); _ifaces.push_back(ifa);
} }
@ -173,8 +169,13 @@ void session::touch()
{ {
_touched = true; _touched = true;
if (status() == session::WAITING || status() == session::INVALID) if (status() == session::WAITING || status() == session::INVALID) {
_ttl = _pr->timeout();
logger::debug() << "session is now probing [taddr=" << _taddr << "]";
send_solicit(); send_solicit();
}
} }
} }
@ -183,57 +184,110 @@ void session::send_advert(const address& daddr)
_pr->ifa()->write_advert(daddr, _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 address& saddr, const std::string& ifname, bool use_via)
{ {
if (_wired == true) if (_wired == true && (_wired_via.is_empty() || _wired_via == saddr))
return; return;
logger::debug() logger::debug()
<< "session::handle_auto_wire() taddr=" << _taddr << ", ifa=" << ifa->name(); << "session::handle_auto_wire() taddr=" << _taddr << ", ifname=" << ifname;
std::stringstream route_cmd; if (use_via == true &&
route_cmd << "ip"; _taddr != saddr &&
route_cmd << " " << "-6"; saddr.is_unicast() == true &&
route_cmd << " " << "route"; saddr.is_multicast() == false)
route_cmd << " " << "replace"; {
route_cmd << " " << std::string(_taddr); std::stringstream route_cmd;
route_cmd << " " << "dev"; route_cmd << "ip";
route_cmd << " " << ifa->name(); route_cmd << " " << "-6";
route_cmd << " " << "route";
logger::debug() route_cmd << " " << "replace";
<< "session::system(" << route_cmd.str() << ")"; route_cmd << " " << std::string(saddr);
route_cmd << " " << "dev";
route_cmd << " " << ifname;
logger::debug()
<< "session::system(" << route_cmd.str() << ")";
system(route_cmd.str().c_str());
_wired_via = saddr;
}
else
_wired_via.reset();
system(route_cmd.str().c_str()); {
std::stringstream route_cmd;
route_cmd << "ip";
route_cmd << " " << "-6";
route_cmd << " " << "route";
route_cmd << " " << "replace";
route_cmd << " " << std::string(_taddr);
if (_wired_via.is_empty() == false) {
route_cmd << " " << "via";
route_cmd << " " << std::string(_wired_via);
}
route_cmd << " " << "dev";
route_cmd << " " << ifname;
logger::debug()
<< "session::system(" << route_cmd.str() << ")";
system(route_cmd.str().c_str());
}
_wired = true; _wired = true;
} }
void session::handle_auto_unwire(const ptr<iface>& ifa) void session::handle_auto_unwire(const std::string& ifname)
{ {
logger::debug() logger::debug()
<< "session::handle_auto_unwire() taddr=" << _taddr << ", ifa=" << ifa->name(); << "session::handle_auto_unwire() taddr=" << _taddr << ", ifname=" << ifname;
std::stringstream route_cmd; {
route_cmd << "ip"; std::stringstream route_cmd;
route_cmd << " " << "-6"; route_cmd << "ip";
route_cmd << " " << "route"; route_cmd << " " << "-6";
route_cmd << " " << "flush"; route_cmd << " " << "route";
route_cmd << " " << std::string(_taddr); route_cmd << " " << "flush";
route_cmd << " " << "dev"; route_cmd << " " << std::string(_taddr);
route_cmd << " " << ifa->name(); if (_wired_via.is_empty() == false) {
route_cmd << " " << "via";
logger::debug() route_cmd << " " << std::string(_wired_via);
<< "session::system(" << route_cmd.str() << ")"; }
route_cmd << " " << "dev";
route_cmd << " " << ifname;
logger::debug()
<< "session::system(" << route_cmd.str() << ")";
system(route_cmd.str().c_str());
}
system(route_cmd.str().c_str()); if (_wired_via.is_empty() == false) {
std::stringstream route_cmd;
route_cmd << "ip";
route_cmd << " " << "-6";
route_cmd << " " << "route";
route_cmd << " " << "flush";
route_cmd << " " << std::string(_wired_via);
route_cmd << " " << "dev";
route_cmd << " " << ifname;
logger::debug()
<< "session::system(" << route_cmd.str() << ")";
system(route_cmd.str().c_str());
}
_wired = false; _wired = false;
_wired_via.reset();
} }
void session::handle_advert(const ptr<iface>& ifa) void session::handle_advert(const address& saddr, const std::string& ifname, bool use_via)
{ {
if (_autowire == true && _status == WAITING) { if (_autowire == true && _status == WAITING) {
handle_auto_wire(ifa); handle_auto_wire(saddr, ifname, use_via);
} }
handle_advert(); handle_advert();
@ -245,7 +299,12 @@ void session::handle_advert()
logger::debug() logger::debug()
<< "session::handle_advert() taddr=" << _taddr << ", ttl=" << _pr->ttl(); << "session::handle_advert() taddr=" << _taddr << ", ttl=" << _pr->ttl();
_status = VALID; if (_status != VALID) {
_status = VALID;
logger::debug() << "session is active [taddr=" << _taddr << "]";
}
_ttl = _pr->ttl(); _ttl = _pr->ttl();
_fails = 0; _fails = 0;

View File

@ -16,6 +16,7 @@
#pragma once #pragma once
#include <vector> #include <vector>
#include <string>
#include "ndppd.h" #include "ndppd.h"
@ -38,6 +39,8 @@ private:
bool _wired; bool _wired;
address _wired_via;
bool _touched; bool _touched;
// An array of interfaces this session is monitoring for // An array of interfaces this session is monitoring for
@ -102,11 +105,11 @@ public:
void handle_advert(); void handle_advert();
void handle_advert(const ptr<iface>& ifa); void handle_advert(const address& saddr, const std::string& ifname, bool use_via);
void handle_auto_wire(const ptr<iface>& ifa); void handle_auto_wire(const address& saddr, const std::string& ifname, bool use_via);
void handle_auto_unwire(const ptr<iface>& ifa); void handle_auto_unwire(const std::string& ifname);
void touch(); void touch();