diff --git a/ndppd.conf-dist b/ndppd.conf-dist index 4ec1657..35a5db4 100644 --- a/ndppd.conf-dist +++ b/ndppd.conf-dist @@ -91,6 +91,13 @@ proxy eth0 { auto + # autovia + # 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). diff --git a/src/address.cc b/src/address.cc index 993a237..18be7ef 100644 --- a/src/address.cc +++ b/src/address.cc @@ -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; } diff --git a/src/address.h b/src/address.h index f320d49..c9b1a30 100644 --- a/src/address.h +++ b/src/address.h @@ -56,6 +56,8 @@ public: bool operator!=(const address& addr) const; void reset(); + + bool is_empty() const; const std::string to_string() const; diff --git a/src/iface.cc b/src/iface.cc index 56357e3..f569d3c 100644 --- a/src/iface.cc +++ b/src/iface.cc @@ -40,6 +40,7 @@ #include #include "ndppd.h" +#include "route.h" NDPPD_NS_BEGIN @@ -72,6 +73,9 @@ iface::~iface() } _map_dirty = true; + + _serves.clear(); + _parents.clear(); } ptr iface::open_pfd(const std::string& name, bool promiscuous) @@ -297,7 +301,7 @@ ptr 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 >::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 >::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 >::iterator pit = serves_begin(); pit != serves_end(); pit++) { + ptr pr = (*pit); + if (!pr) continue; + + for (std::list >::iterator it = pr->rules_begin(); it != pr->rules_end(); it++) { + ptr 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 >::iterator pit = parents_begin(); pit != parents_end(); pit++) { + ptr 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 >::iterator it = parent->rules_begin(); it != parent->rules_end(); it++) { + ptr 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& se) -{ - for (std::list >::iterator it = _sessions.begin(); - it != _sessions.end(); it++) { - if (*it == se) { - _sessions.erase(it); - break; - } - } -} - -void iface::add_session(const ptr& se) -{ - _sessions.push_back(se); -} - void iface::cleanup() { for (std::map >::iterator it = _map.begin(); @@ -579,58 +654,95 @@ int iface::poll_all() ptr 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 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 >::iterator pit = ifa->serves_begin(); pit != ifa->serves_end(); pit++) { + ptr 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 >::iterator s_it = ifa->_sessions.begin(); - s_it != ifa->_sessions.end(); s_it++) { - assert(!s_it->is_null()); - - const ptr 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 >::iterator pit = ifa->parents_begin(); pit != ifa->parents_end(); pit++) { + ptr 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 >::iterator it = pr->rules_begin(); it != pr->rules_end(); it++) { + ptr 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& pr) +void iface::add_serves(const ptr& pr) { - _pr = pr; + _serves.push_back(pr); } -const ptr& iface::pr() const +std::list >::iterator iface::serves_begin() { - return _pr; + return _serves.begin(); } -void iface::owner(const ptr& pr) +std::list >::iterator iface::serves_end() { - _owner = pr; + return _serves.end(); } -const ptr& iface::owner() const +void iface::add_parent(const ptr& pr) { - return _owner; + _parents.push_back(pr); +} + +std::list >::iterator iface::parents_begin() +{ + return _parents.begin(); +} + +std::list >::iterator iface::parents_end() +{ + return _parents.end(); } NDPPD_NS_END diff --git a/src/iface.h b/src/iface.h index 573b613..9db59ab 100644 --- a/src/iface.h +++ b/src/iface.h @@ -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& se); - - void remove_session(const ptr& se); - - void pr(const ptr& pr); - const ptr& pr() const; + std::list >::iterator serves_begin(); - void owner(const ptr& pr); + std::list >::iterator serves_end(); - const ptr& owner() const; + void add_serves(const ptr& proxy); + + std::list >::iterator parents_begin(); + + std::list >::iterator parents_end(); + + void add_parent(const ptr& parent); + + static std::map > _map; private: - static std::map > _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 > _sessions; - - weak_ptr _pr; - weak_ptr _owner; + std::list > _serves; + + std::list > _parents; // The link-layer address of this interface. struct ether_addr hwaddr; diff --git a/src/ndppd.cc b/src/ndppd.cc index 2d9d713..d54718f 100644 --- a/src/ndppd.cc +++ b/src/ndppd.cc @@ -146,6 +146,8 @@ static bool configure(ptr& cf) address::ttl(30000); else address::ttl(*x_cf); + + std::list > myrules; std::vector >::const_iterator p_it; @@ -212,6 +214,12 @@ static bool configure(ptr& cf) ptr 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& 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 >::iterator i_it = iface::_map.begin(); i_it != iface::_map.end(); i_it++) { + ptr ifa = i_it->second; + + logger::debug() << "iface " << ifa->name() << " {"; + + for (std::list >::iterator pit = ifa->serves_begin(); pit != ifa->serves_end(); pit++) { + ptr pr = (*pit); + if (!pr) continue; + + logger::debug() << " " << "proxy " << logger::format("%x", pr.get_pointer()) << " {"; + + for (std::list >::iterator rit = pr->rules_begin(); rit != pr->rules_end(); rit++) { + ptr 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 >::iterator pit = ifa->parents_begin(); pit != ifa->parents_end(); pit++) { + ptr pr = (*pit); + + logger::debug() << " " << "parent " << logger::format("%x", pr.get_pointer()) << ";"; + } + logger::debug() << " }"; + + logger::debug() << "}"; + } + return true; } diff --git a/src/proxy.cc b/src/proxy.cc index 5cbc81f..cfa4815 100644 --- a/src/proxy.cc +++ b/src/proxy.cc @@ -36,6 +36,34 @@ proxy::proxy() : { } +ptr proxy::find_aunt(const std::string& ifname, const address& taddr) +{ + for (std::list >::iterator sit = _list.begin(); + sit != _list.end(); sit++) + { + ptr pr = (*sit); + + bool has_addr = false; + for (std::list >::iterator it = pr->_rules.begin(); it != pr->_rules.end(); it++) { + ptr 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(); +} + ptr proxy::create(const ptr& ifa, bool promiscuous) { ptr pr(new proxy()); @@ -45,7 +73,7 @@ ptr proxy::create(const ptr& 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 proxy::find_or_create_session(const address& taddr) } else { ptr 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 proxy::find_or_create_session(const address& taddr) } else { - ptr ifa = (*it)->ifa(); + ptr 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 proxy::find_or_create_session(const address& taddr) return se; } -void proxy::handle_advert(const address& taddr, const ptr& 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 >::iterator s_it = _sessions.begin(); + s_it != _sessions.end(); s_it++) + { + const ptr 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 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 >::iterator ad = address::addresses_begin(); ad != address::addresses_end(); ad++) - { - if ((*ad)->addr() == taddr) - { - for (std::list >::iterator it = _rules.begin(); it != _rules.end(); it++) { - ptr 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 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 proxy::add_rule(const address& addr, const ptr& ifa) +ptr proxy::add_rule(const address& addr, const ptr& ifa, bool autovia) { ptr ru(rule::create(_ptr, addr, ifa)); + ru->autovia(autovia); _rules.push_back(ru); return ru; } @@ -201,6 +232,16 @@ ptr proxy::add_rule(const address& addr, bool aut) return ru; } +std::list >::iterator proxy::rules_begin() +{ + return _rules.begin(); +} + +std::list >::iterator proxy::rules_end() +{ + return _rules.end(); +} + void proxy::remove_session(const ptr& se) { _sessions.remove(se); diff --git a/src/proxy.h b/src/proxy.h index d045e52..8141b2a 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -29,22 +29,30 @@ class iface; class rule; class proxy { -public: +public: static ptr create(const ptr& ifa, bool promiscuous); + + static ptr find_aunt(const std::string& ifname, const address& taddr); static ptr open(const std::string& ifn, bool promiscuous); ptr find_or_create_session(const address& taddr); - void handle_advert(const address& taddr, const ptr& 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& se); - ptr add_rule(const address& addr, const ptr& ifa); + ptr add_rule(const address& addr, const ptr& ifa, bool autovia); ptr add_rule(const address& addr, bool aut = false); + + std::list >::iterator rules_begin(); + + std::list >::iterator rules_end(); const ptr& ifa() const; diff --git a/src/rule.cc b/src/rule.cc index 50ddbfe..ad64710 100644 --- a/src/rule.cc +++ b/src/rule.cc @@ -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::create(const ptr& pr, const address& addr, const ptr 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::create(const ptr& 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 rule::ifa() const +ptr 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; diff --git a/src/rule.h b/src/rule.h index 14912b4..0c2f79a 100644 --- a/src/rule.h +++ b/src/rule.h @@ -37,7 +37,7 @@ public: const address& addr() const; - ptr ifa() const; + ptr 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 _ptr; weak_ptr _pr; - ptr _ifa; + ptr _daughter; address _addr; @@ -60,7 +66,11 @@ private: static bool _any_aut; + static bool _any_static; + static bool _any_iface; + + bool _autovia; rule(); }; diff --git a/src/session.cc b/src/session.cc index 1159a60..4a2465c 100644 --- a/src/session.cc +++ b/src/session.cc @@ -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 >::iterator it = _ifaces.begin(); it != _ifaces.end(); it++) { - handle_auto_unwire((*it)); + handle_auto_unwire((*it)->name()); } } - - for (std::list >::iterator it = _ifaces.begin(); - it != _ifaces.end(); it++) - { - (*it)->remove_session(_ptr); - } } ptr session::create(const ptr& pr, const address& taddr, bool auto_wire, bool keepalive, int retries) @@ -125,7 +122,7 @@ ptr session::create(const ptr& 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& 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& 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& 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& 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; diff --git a/src/session.h b/src/session.h index 08eb73d..b4d9ac1 100644 --- a/src/session.h +++ b/src/session.h @@ -16,6 +16,7 @@ #pragma once #include +#include #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& ifa); + void handle_advert(const address& saddr, const std::string& ifname, bool use_via); - void handle_auto_wire(const ptr& ifa); + void handle_auto_wire(const address& saddr, const std::string& ifname, bool use_via); - void handle_auto_unwire(const ptr& ifa); + void handle_auto_unwire(const std::string& ifname); void touch();