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
# 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
# method, it defaulted to 'static'. For compatibility reasons we choose
# 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]));
}
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()
{
_addr.s6_addr32[0] = 0;
@ -321,6 +336,10 @@ bool address::is_multicast() 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;
}
@ -360,7 +379,8 @@ void address::load(const std::string& path)
ifs.getline(buf, sizeof(buf));
if (ifs.gcount() < 53) {
logger::debug() << "skipping entry (size=" << ifs.gcount() << ")";
if (ifs.gcount() > 0)
logger::debug() << "skipping entry (size=" << ifs.gcount() << ")";
continue;
}

View File

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

View File

@ -40,6 +40,7 @@
#include <map>
#include "ndppd.h"
#include "route.h"
NDPPD_NS_BEGIN
@ -72,6 +73,9 @@ iface::~iface()
}
_map_dirty = true;
_serves.clear();
_parents.clear();
}
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;
}
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 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));
mhdr.msg_name = (caddr_t)saddr;
mhdr.msg_namelen = sizeof(struct sockaddr);
mhdr.msg_namelen = saddr_size;
mhdr.msg_iov =& iov;
mhdr.msg_iovlen = 1;
logger::debug() << "iface::read() ifa=" << name() << ", len=" << len;
if ((len = recvmsg(fd,& mhdr, 0)) < 0)
{
logger::error() << "iface::read() failed! error=" << logger::err() << ", ifa=" << name();
return -1;
}
logger::debug() << "iface::read() ifa=" << name() << ", len=" << len;
if (len < sizeof(struct icmp6_hdr))
return -1;
@ -369,7 +373,7 @@ ssize_t iface::read_solicit(address& saddr, address& daddr, address& taddr)
uint8_t msg[256];
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();
return -1;
}
@ -383,6 +387,11 @@ ssize_t iface::read_solicit(address& saddr, address& daddr, address& taddr)
taddr = ns->nd_ns_target;
daddr = ip6h->ip6_dst;
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()
<< ", 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;
uint8_t msg[256];
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();
return -1;
}
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)
return -1;
@ -483,6 +501,79 @@ ssize_t iface::read_advert(address& saddr, address& taddr)
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()
{
_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()
{
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;
address saddr, daddr, taddr;
ssize_t size;
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();
continue;
}
if (!saddr.is_unicast()/* || !daddr.is_multicast()*/) {
}
if (size == 0) {
logger::debug() << "iface::read_solicit() loopback received and ignored";
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);
}
}
// Process any local addresses for interfaces that we are proxying
if (ifa->handle_local(saddr, taddr) == true) {
continue;
}
// We have to handle all the parents who may be interested in
// the reverse path towards the one who sent this solicit.
// 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
ifa->_pr->handle_solicit(saddr, taddr);
// Loop through all the proxies that are using this iface to respond to NDP solicitation requests
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 {
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();
continue;
}
bool found = false;
for (std::list<weak_ptr<session> >::iterator s_it = ifa->_sessions.begin();
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 (size == 0) {
logger::debug() << "iface::read_advert() loopback received and ignored";
continue;
}
if (found == false) {
if (ifa->owner()) {
ifa->owner()->handle_advert(taddr, ifa);
} else {
logger::debug() << "iface::poll_all - ignoring advert on proxy iface=" << ifa->name();
// Process the NDP advert
bool handled = false;
for (std::list<weak_ptr<proxy> >::iterator pit = ifa->parents_begin(); pit != ifa->parents_end(); pit++) {
ptr<proxy> pr = (*pit);
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;
}
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

View File

@ -42,7 +42,7 @@ public:
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);
@ -57,25 +57,31 @@ public:
// Reads a NB_NEIGHBOR_ADVERT message from the _ifd socket;
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.
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:
static std::map<std::string, weak_ptr<iface> > _map;
static bool _map_dirty;
@ -106,14 +112,10 @@ private:
// Name of this interface.
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.
struct ether_addr hwaddr;

View File

@ -146,6 +146,8 @@ static bool configure(ptr<conf>& cf)
address::ttl(30000);
else
address::ttl(*x_cf);
std::list<ptr<rule> > myrules;
std::vector<ptr<conf> >::const_iterator p_it;
@ -212,6 +214,12 @@ static bool configure(ptr<conf>& cf)
ptr<conf> ru_cf =* r_it;
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"))
{
@ -219,17 +227,58 @@ static bool configure(ptr<conf>& cf)
if (!ifa || ifa.is_null() == true) {
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")) {
pr->add_rule(addr, true);
myrules.push_back(pr->add_rule(addr, true));
} 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;
}

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

View File

@ -29,22 +29,30 @@ class iface;
class rule;
class proxy {
public:
public:
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);
ptr<session> find_or_create_session(const address& taddr);
void handle_advert(const address& taddr, const ptr<iface>& receiver);
void handle_solicit(const address& saddr, const address& taddr);
void handle_advert(const address& saddr, const address& taddr, const std::string& ifname, bool use_via);
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);
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);
std::list<ptr<rule> >::iterator rules_begin();
std::list<ptr<rule> >::iterator rules_end();
const ptr<iface>& ifa() const;

View File

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

View File

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

View File

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

View File

@ -16,6 +16,7 @@
#pragma once
#include <vector>
#include <string>
#include "ndppd.h"
@ -38,6 +39,8 @@ private:
bool _wired;
address _wired_via;
bool _touched;
// An array of interfaces this session is monitoring for
@ -102,11 +105,11 @@ public:
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();