Merge pull request #30 from john-sharratt/master
Feature to automatically wire the routes for a gateway
This commit is contained in:
commit
6ef7a57b2e
41
ChangeLog
41
ChangeLog
@ -1,3 +1,44 @@
|
||||
2017-01-07 Johnathan Sharratt <johnathan.sharratt@gmail.com>
|
||||
|
||||
* Version 0.2.6
|
||||
|
||||
* Added a new configuration setting named "deadtime" which allows
|
||||
sessions that never made it the VALID to have a different (i.e.
|
||||
shorter) life before they are removed (and potentially retried)
|
||||
(defauilt is the same value as usual TTL for backwards compatibility)
|
||||
|
||||
* Added a new configuration setting named "autowire" in the proxy
|
||||
section (default is off)
|
||||
|
||||
* If the "autowire" setting is on, then upon receiving a NDP
|
||||
Neighbor Advertisment from one of the rule interfaces, a route will
|
||||
be automatically added into the linux IP routing tables thus allowing
|
||||
for a full featured gateway when IPv6 forwarding is turned on.
|
||||
Note: Be careful as "accept_ra" may need to be set to 2 on the
|
||||
interface during testing for the routing tables to retain their
|
||||
default route (unrelated to this patch but took me a while to
|
||||
discover).
|
||||
|
||||
* When a session ends then anything that was "autowired" will be
|
||||
automatically removed thus ensuring the routing tables are in a
|
||||
similar state to before the daemon (or session) made any changes
|
||||
|
||||
* Added a feature where the session will attempt to renew itself
|
||||
(with a new NDP Solicitation) before it self-terminates, this is
|
||||
required otherwise packets could be lost when the session terminates
|
||||
triggering the automatically removal of the route table entry.
|
||||
|
||||
* Ensured that renew operations only take place if the session has
|
||||
been recently touched by an external solicitation - this ensures
|
||||
that sessions that become IDLE are cleaned up quickly
|
||||
|
||||
* Moved the daemonizing step till after the system executed the
|
||||
configure step so that the error exit codes are returned to the daemon
|
||||
caller.
|
||||
|
||||
* No longer continuing to load the daemon if any of the interfaces fail
|
||||
to load which should give a more predictable behaviour and better user experience.
|
||||
|
||||
2016-04-18 Daniel Adolfsson <daniel@priv.nu>
|
||||
|
||||
* Version 0.2.5
|
||||
|
@ -4,6 +4,12 @@
|
||||
|
||||
route-ttl 30000
|
||||
|
||||
# address-ttl <integer> (NEW)
|
||||
# This tells 'ndppd' how often to reload the IP address file /proc/net/if_inet6
|
||||
# Default value is '30000' (30 seconds).
|
||||
|
||||
address-ttl 30000
|
||||
|
||||
# proxy <interface>
|
||||
# This sets up a listener, that will listen for any Neighbor Solicitation
|
||||
# messages, and respond to them according to a set of rules (see below).
|
||||
@ -22,6 +28,36 @@ proxy eth0 {
|
||||
# invalidating the entry, in milliseconds. Default value is '500'.
|
||||
|
||||
timeout 500
|
||||
|
||||
# autowire <yes|no|true|false>
|
||||
# Controls whether ndppd will automatically create host entries
|
||||
# in the routing tables when it receives Neighbor Advertisements on a
|
||||
# listening interface. The the default value is no.
|
||||
# Note: Autowire will ignore all rules with 'auto' or 'static' given it
|
||||
# is expected that the routes are already defined for these paths
|
||||
|
||||
autowire no
|
||||
|
||||
# keepalive <yes|no|true|false>
|
||||
# Controls whether ndppd will automatically attempt to keep routing
|
||||
# sessions alive by actively sending out NDP Solicitations before the the
|
||||
# session is expired. The the default value is yes.
|
||||
|
||||
keepalive yes
|
||||
|
||||
# retries <integer>
|
||||
# Number of times a NDP Solicitation will be sent out before the daemon
|
||||
# considers a route unreachable. The default value is 3
|
||||
|
||||
retries 3
|
||||
|
||||
# promiscuous <yes|no|true|false>
|
||||
# Controls whether ndppd will put the proxy listening interface into promiscuous
|
||||
# mode and hence will react to inbound and outbound NDP commands. This is
|
||||
# required for machines behind the gateway to talk to each other in more
|
||||
# complex topology scenarios. The the default value is no.
|
||||
|
||||
promiscuous no
|
||||
|
||||
# ttl <integer>
|
||||
# Controls how long a valid or invalid entry remains in the cache, in
|
||||
@ -55,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).
|
||||
|
14
ndppd.conf.5
14
ndppd.conf.5
@ -48,6 +48,20 @@ Controls how long
|
||||
.B ndppd
|
||||
will cache an entry. This is in milliseconds, and the default value
|
||||
is 30000 (30 seconds).
|
||||
.IP "autowire <yes|no>"
|
||||
Controls whether
|
||||
.B ndppd
|
||||
will automatically create host entries in the routing tables when
|
||||
.B ndppd receives Neighbor Advertisements on a listening interface.
|
||||
The default value is no.
|
||||
.IP "promiscuous <yes|no>"
|
||||
Controls whether
|
||||
.B ndppd
|
||||
will put the proxy listening interface into promiscuous mode and
|
||||
hence will react to inbound and outbound NDP commands. This is
|
||||
required for machines behind the gateway to talk to each other in
|
||||
more complex topology scenarios.
|
||||
The the default value is no.
|
||||
.IP "timeout <value>"
|
||||
Controls how long
|
||||
.B ndppd
|
||||
|
123
src/address.cc
123
src/address.cc
@ -15,6 +15,8 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <list>
|
||||
#include <map>
|
||||
|
||||
#include <cstring>
|
||||
@ -27,9 +29,16 @@
|
||||
|
||||
#include "ndppd.h"
|
||||
#include "address.h"
|
||||
#include "route.h"
|
||||
|
||||
NDPPD_NS_BEGIN
|
||||
|
||||
std::list<ptr<route> > address::_addresses;
|
||||
|
||||
int address::_ttl;
|
||||
|
||||
int address::_c_ttl;
|
||||
|
||||
address::address()
|
||||
{
|
||||
reset();
|
||||
@ -48,6 +57,19 @@ address::address(const address& addr)
|
||||
_mask.s6_addr32[3] = addr._mask.s6_addr32[3];
|
||||
}
|
||||
|
||||
address::address(const ptr<address>& addr)
|
||||
{
|
||||
_addr.s6_addr32[0] = addr->_addr.s6_addr32[0];
|
||||
_addr.s6_addr32[1] = addr->_addr.s6_addr32[1];
|
||||
_addr.s6_addr32[2] = addr->_addr.s6_addr32[2];
|
||||
_addr.s6_addr32[3] = addr->_addr.s6_addr32[3];
|
||||
|
||||
_mask.s6_addr32[0] = addr->_mask.s6_addr32[0];
|
||||
_mask.s6_addr32[1] = addr->_mask.s6_addr32[1];
|
||||
_mask.s6_addr32[2] = addr->_mask.s6_addr32[2];
|
||||
_mask.s6_addr32[3] = addr->_mask.s6_addr32[3];
|
||||
}
|
||||
|
||||
address::address(const std::string& str)
|
||||
{
|
||||
parse_string(str);
|
||||
@ -110,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;
|
||||
@ -299,7 +336,93 @@ 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;
|
||||
}
|
||||
|
||||
void address::add(const address& addr, const std::string& ifname)
|
||||
{
|
||||
ptr<route> rt(new route(addr, ifname));
|
||||
// logger::debug() << "address::create() addr=" << addr << ", ifname=" << ifname;
|
||||
_addresses.push_back(rt);
|
||||
}
|
||||
|
||||
std::list<ptr<route> >::iterator address::addresses_begin()
|
||||
{
|
||||
return _addresses.begin();
|
||||
}
|
||||
|
||||
std::list<ptr<route> >::iterator address::addresses_end()
|
||||
{
|
||||
return _addresses.end();
|
||||
}
|
||||
|
||||
void address::load(const std::string& path)
|
||||
{
|
||||
// Hack to make sure the addresses are not freed prematurely.
|
||||
std::list<ptr<route> > tmp_addresses(_addresses);
|
||||
_addresses.clear();
|
||||
|
||||
logger::debug() << "reading IP addresses";
|
||||
|
||||
try {
|
||||
std::ifstream ifs;
|
||||
ifs.exceptions(std::ifstream::badbit | std::ifstream::failbit);
|
||||
ifs.open(path.c_str(), std::ios::in);
|
||||
ifs.exceptions(std::ifstream::badbit);
|
||||
|
||||
while (!ifs.eof()) {
|
||||
char buf[1024];
|
||||
ifs.getline(buf, sizeof(buf));
|
||||
|
||||
if (ifs.gcount() < 53) {
|
||||
if (ifs.gcount() > 0)
|
||||
logger::debug() << "skipping entry (size=" << ifs.gcount() << ")";
|
||||
continue;
|
||||
}
|
||||
|
||||
address addr;
|
||||
|
||||
if (route::hexdec(buf, (unsigned char* )&addr.addr(), 16) != 16) {
|
||||
logger::warning() << "failed to load address (" << buf << ")";
|
||||
continue;
|
||||
}
|
||||
|
||||
addr.prefix(128);
|
||||
|
||||
std::string iface = route::token(buf + 45);
|
||||
|
||||
address::add(addr, iface);
|
||||
|
||||
logger::debug() << "found local addr=" << addr << ", iface=" << iface;
|
||||
}
|
||||
} catch (std::ifstream::failure e) {
|
||||
logger::warning() << "Failed to parse IPv6 address data from '" << path << "'";
|
||||
logger::error() << e.what();
|
||||
}
|
||||
|
||||
logger::debug() << "completed IP addresses load";
|
||||
}
|
||||
|
||||
void address::update(int elapsed_time)
|
||||
{
|
||||
if ((_c_ttl -= elapsed_time) <= 0) {
|
||||
load("/proc/net/if_inet6");
|
||||
_c_ttl = _ttl;
|
||||
}
|
||||
}
|
||||
|
||||
int address::ttl()
|
||||
{
|
||||
return _ttl;
|
||||
}
|
||||
|
||||
void address::ttl(int ttl)
|
||||
{
|
||||
_ttl = ttl;
|
||||
}
|
||||
|
||||
NDPPD_NS_END
|
||||
|
@ -16,6 +16,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <netinet/ip6.h>
|
||||
|
||||
#include "ndppd.h"
|
||||
@ -24,15 +25,24 @@ NDPPD_NS_BEGIN
|
||||
|
||||
class iface;
|
||||
|
||||
class route;
|
||||
|
||||
class address {
|
||||
public:
|
||||
address();
|
||||
address(const address& addr);
|
||||
address(const ptr<address>& addr);
|
||||
address(const std::string& str);
|
||||
address(const char* str);
|
||||
address(const in6_addr& addr);
|
||||
address(const in6_addr& addr, const in6_addr& mask);
|
||||
address(const in6_addr& addr, int prefix);
|
||||
|
||||
static void update(int elapsed_time);
|
||||
|
||||
static int ttl();
|
||||
|
||||
static void ttl(int ttl);
|
||||
|
||||
struct in6_addr& addr();
|
||||
|
||||
@ -46,6 +56,8 @@ public:
|
||||
bool operator!=(const address& addr) const;
|
||||
|
||||
void reset();
|
||||
|
||||
bool is_empty() const;
|
||||
|
||||
const std::string to_string() const;
|
||||
|
||||
@ -60,8 +72,22 @@ public:
|
||||
bool is_multicast() const;
|
||||
|
||||
operator std::string() const;
|
||||
|
||||
static void add(const address& addr, const std::string& ifname);
|
||||
|
||||
static void load(const std::string& path);
|
||||
|
||||
static std::list<ptr<route> >::iterator addresses_begin();
|
||||
|
||||
static std::list<ptr<route> >::iterator addresses_end();
|
||||
|
||||
private:
|
||||
static int _ttl;
|
||||
|
||||
static int _c_ttl;
|
||||
|
||||
static std::list<ptr<route> > _addresses;
|
||||
|
||||
struct in6_addr _addr, _mask;
|
||||
};
|
||||
|
||||
|
310
src/iface.cc
310
src/iface.cc
@ -40,6 +40,7 @@
|
||||
#include <map>
|
||||
|
||||
#include "ndppd.h"
|
||||
#include "route.h"
|
||||
|
||||
NDPPD_NS_BEGIN
|
||||
|
||||
@ -65,13 +66,19 @@ iface::~iface()
|
||||
if (_prev_allmulti >= 0) {
|
||||
allmulti(_prev_allmulti);
|
||||
}
|
||||
if (_prev_promiscuous >= 0) {
|
||||
promiscuous(_prev_promiscuous);
|
||||
}
|
||||
close(_pfd);
|
||||
}
|
||||
|
||||
_map_dirty = true;
|
||||
|
||||
_serves.clear();
|
||||
_parents.clear();
|
||||
}
|
||||
|
||||
ptr<iface> iface::open_pfd(const std::string& name)
|
||||
ptr<iface> iface::open_pfd(const std::string& name, bool promiscuous)
|
||||
{
|
||||
int fd = 0;
|
||||
|
||||
@ -169,6 +176,13 @@ ptr<iface> iface::open_pfd(const std::string& name)
|
||||
|
||||
// Eh. Allmulti.
|
||||
ifa->_prev_allmulti = ifa->allmulti(1);
|
||||
|
||||
// Eh. Promiscuous
|
||||
if (promiscuous == true) {
|
||||
ifa->_prev_promiscuous = ifa->promiscuous(1);
|
||||
} else {
|
||||
ifa->_prev_promiscuous = -1;
|
||||
}
|
||||
|
||||
_map_dirty = true;
|
||||
|
||||
@ -287,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;
|
||||
@ -301,18 +315,21 @@ 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;
|
||||
|
||||
|
||||
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;
|
||||
|
||||
logger::debug() << "iface::read() len=" << len;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
@ -336,15 +353,14 @@ ssize_t iface::write(int fd, const address& daddr, const uint8_t* msg, size_t si
|
||||
mhdr.msg_iov =& iov;
|
||||
mhdr.msg_iovlen = 1;
|
||||
|
||||
logger::debug() << "iface::write() daddr=" << daddr.to_string() << ", len="
|
||||
logger::debug() << "iface::write() ifa=" << name() << ", daddr=" << daddr.to_string() << ", len="
|
||||
<< size;
|
||||
|
||||
int len;
|
||||
|
||||
if ((len = sendmsg(fd,& mhdr, 0)) < 0)
|
||||
{
|
||||
int e = errno;
|
||||
logger::error() << "iface::write() failed! errno=" << e;
|
||||
logger::error() << "iface::write() failed! error=" << logger::err() << ", ifa=" << name() << ", daddr=" << daddr.to_string();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -357,8 +373,10 @@ 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;
|
||||
}
|
||||
|
||||
struct ip6_hdr* ip6h =
|
||||
(struct ip6_hdr* )(msg + ETH_HLEN);
|
||||
@ -369,9 +387,14 @@ 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() << ", len=" << len;
|
||||
<< ", daddr=" << daddr.to_string() << ", taddr=" << taddr.to_string() << ", len=" << len;
|
||||
|
||||
return len;
|
||||
}
|
||||
@ -451,11 +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;
|
||||
@ -467,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);
|
||||
@ -489,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();
|
||||
@ -534,6 +625,7 @@ int iface::poll_all()
|
||||
int len;
|
||||
|
||||
if ((len = ::poll(&_pollfds[0], _pollfds.size(), 50)) < 0) {
|
||||
logger::error() << "Failed to poll interfaces: " << logger::err();
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -562,36 +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) {
|
||||
ifa->_pr->handle_solicit(saddr, daddr, taddr);
|
||||
|
||||
// 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());
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
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->status() == session::WAITING)) {
|
||||
sess->handle_advert();
|
||||
break;
|
||||
if (size == 0) {
|
||||
logger::debug() << "iface::read_advert() loopback received and ignored";
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -638,19 +789,78 @@ int iface::allmulti(int state)
|
||||
return old_state;
|
||||
}
|
||||
|
||||
int iface::promiscuous(int state)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
|
||||
logger::debug()
|
||||
<< "iface::promiscuous() state="
|
||||
<< state << ", _name=\"" << _name << "\"";
|
||||
|
||||
state = !!state;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
|
||||
strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ);
|
||||
|
||||
if (ioctl(_pfd, SIOCGIFFLAGS, &ifr) < 0) {
|
||||
logger::error() << "Failed to get promiscuous: " << logger::err();
|
||||
return -1;
|
||||
}
|
||||
|
||||
int old_state = !!(ifr.ifr_flags &IFF_PROMISC);
|
||||
|
||||
if (state == old_state) {
|
||||
return old_state;
|
||||
}
|
||||
|
||||
if (state) {
|
||||
ifr.ifr_flags |= IFF_PROMISC;
|
||||
} else {
|
||||
ifr.ifr_flags &= ~IFF_PROMISC;
|
||||
}
|
||||
|
||||
if (ioctl(_pfd, SIOCSIFFLAGS, &ifr) < 0) {
|
||||
logger::error() << "Failed to set promiscuous: " << logger::err();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return old_state;
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
std::list<weak_ptr<proxy> >::iterator iface::serves_end()
|
||||
{
|
||||
return _serves.end();
|
||||
}
|
||||
|
||||
void iface::add_parent(const ptr<proxy>& pr)
|
||||
{
|
||||
_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
|
||||
|
53
src/iface.h
53
src/iface.h
@ -38,13 +38,13 @@ public:
|
||||
|
||||
static ptr<iface> open_ifd(const std::string& name);
|
||||
|
||||
static ptr<iface> open_pfd(const std::string& name);
|
||||
static ptr<iface> open_pfd(const std::string& name, bool promiscuous);
|
||||
|
||||
static int poll_all();
|
||||
|
||||
static 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);
|
||||
|
||||
static 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);
|
||||
|
||||
// Writes a NB_NEIGHBOR_SOLICIT message to the _ifd socket.
|
||||
ssize_t write_solicit(const address& taddr);
|
||||
@ -57,21 +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();
|
||||
|
||||
std::list<weak_ptr<proxy> >::iterator serves_end();
|
||||
|
||||
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;
|
||||
|
||||
@ -96,15 +106,16 @@ private:
|
||||
|
||||
// Previous state of ALLMULTI for the interface.
|
||||
int _prev_allmulti;
|
||||
|
||||
// Previous state of PROMISC for the interface
|
||||
int _prev_promiscuous;
|
||||
|
||||
// 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;
|
||||
|
||||
std::list<weak_ptr<proxy> > _serves;
|
||||
|
||||
std::list<weak_ptr<proxy> > _parents;
|
||||
|
||||
// The link-layer address of this interface.
|
||||
struct ether_addr hwaddr;
|
||||
@ -112,6 +123,10 @@ private:
|
||||
// Turns on/off ALLMULTI for this interface - returns the previous state
|
||||
// or -1 if there was an error.
|
||||
int allmulti(int state);
|
||||
|
||||
// Turns on/off PROMISC for this interface - returns the previous state
|
||||
// or -1 if there was an error
|
||||
int promiscuous(int state);
|
||||
|
||||
// Constructor.
|
||||
iface();
|
||||
|
131
src/ndppd.cc
131
src/ndppd.cc
@ -36,9 +36,10 @@ using namespace ndppd;
|
||||
static int daemonize()
|
||||
{
|
||||
pid_t pid = fork();
|
||||
|
||||
if (pid < 0)
|
||||
if (pid < 0) {
|
||||
logger::error() << "Failed to fork during daemonize: " << logger::err();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pid > 0)
|
||||
exit(0);
|
||||
@ -46,12 +47,15 @@ static int daemonize()
|
||||
umask(0);
|
||||
|
||||
pid_t sid = setsid();
|
||||
|
||||
if (sid < 0)
|
||||
if (sid < 0) {
|
||||
logger::error() << "Failed to setsid during daemonize: " << logger::err();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (chdir("/") < 0)
|
||||
if (chdir("/") < 0) {
|
||||
logger::error() << "Failed to change path during daemonize: " << logger::err();
|
||||
return -1;
|
||||
}
|
||||
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
@ -137,6 +141,13 @@ static bool configure(ptr<conf>& cf)
|
||||
route::ttl(30000);
|
||||
else
|
||||
route::ttl(*x_cf);
|
||||
|
||||
if (!(x_cf = cf->find("address-ttl")))
|
||||
address::ttl(30000);
|
||||
else
|
||||
address::ttl(*x_cf);
|
||||
|
||||
std::list<ptr<rule> > myrules;
|
||||
|
||||
std::vector<ptr<conf> >::const_iterator p_it;
|
||||
|
||||
@ -148,22 +159,47 @@ static bool configure(ptr<conf>& cf)
|
||||
if (pr_cf->empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool promiscuous = false;
|
||||
if (!(x_cf = pr_cf->find("promiscuous")))
|
||||
promiscuous = false;
|
||||
else
|
||||
promiscuous = *x_cf;
|
||||
|
||||
ptr<proxy> pr = proxy::open(*pr_cf);
|
||||
|
||||
if (!pr) {
|
||||
return true;
|
||||
ptr<proxy> pr = proxy::open(*pr_cf, promiscuous);
|
||||
if (!pr || pr.is_null() == true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(x_cf = pr_cf->find("router")))
|
||||
pr->router(true);
|
||||
else
|
||||
pr->router(*x_cf);
|
||||
|
||||
if (!(x_cf = pr_cf->find("autowire")))
|
||||
pr->autowire(false);
|
||||
else
|
||||
pr->autowire(*x_cf);
|
||||
|
||||
if (!(x_cf = pr_cf->find("keepalive")))
|
||||
pr->keepalive(true);
|
||||
else
|
||||
pr->keepalive(*x_cf);
|
||||
|
||||
if (!(x_cf = pr_cf->find("retries")))
|
||||
pr->retries(3);
|
||||
else
|
||||
pr->retries(*x_cf);
|
||||
|
||||
if (!(x_cf = pr_cf->find("ttl")))
|
||||
pr->ttl(30000);
|
||||
else
|
||||
pr->ttl(*x_cf);
|
||||
|
||||
if (!(x_cf = pr_cf->find("deadtime")))
|
||||
pr->deadtime(pr->ttl());
|
||||
else
|
||||
pr->deadtime(*x_cf);
|
||||
|
||||
if (!(x_cf = pr_cf->find("timeout")))
|
||||
pr->timeout(500);
|
||||
@ -178,17 +214,71 @@ 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")) {
|
||||
pr->add_rule(addr, iface::open_ifd(*x_cf));
|
||||
if (x_cf = ru_cf->find("iface"))
|
||||
{
|
||||
ptr<iface> ifa = iface::open_ifd(*x_cf);
|
||||
if (!ifa || ifa.is_null() == true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -261,18 +351,16 @@ int main(int argc, char* argv[], char* env[])
|
||||
if (cf.is_null())
|
||||
return -1;
|
||||
|
||||
if (!configure(cf))
|
||||
return -1;
|
||||
|
||||
if (daemon) {
|
||||
logger::syslog(true);
|
||||
|
||||
if (daemonize() < 0) {
|
||||
logger::error() << "Failed to daemonize process";
|
||||
if (daemonize() < 0)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!configure(cf))
|
||||
return -1;
|
||||
|
||||
if (!pidfile.empty()) {
|
||||
std::ofstream pf;
|
||||
pf.open(pidfile.c_str(), std::ios::out | std::ios::trunc);
|
||||
@ -310,6 +398,9 @@ int main(int argc, char* argv[], char* env[])
|
||||
|
||||
if (rule::any_auto())
|
||||
route::update(elapsed_time);
|
||||
|
||||
if (rule::any_iface())
|
||||
address::update(elapsed_time);
|
||||
|
||||
session::update_all(elapsed_time);
|
||||
}
|
||||
|
220
src/proxy.cc
220
src/proxy.cc
@ -26,87 +26,99 @@
|
||||
#include "session.h"
|
||||
|
||||
NDPPD_NS_BEGIN
|
||||
|
||||
|
||||
static address all_nodes = address("ff02::1");
|
||||
|
||||
std::list<ptr<proxy> > proxy::_list;
|
||||
|
||||
proxy::proxy() :
|
||||
_router(true), _ttl(30000), _timeout(500)
|
||||
_router(true), _ttl(30000), _deadtime(3000), _timeout(500), _autowire(false), _keepalive(true), _promiscuous(false), _retries(3)
|
||||
{
|
||||
}
|
||||
|
||||
ptr<proxy> proxy::create(const ptr<iface>& ifa)
|
||||
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());
|
||||
pr->_ptr = pr;
|
||||
pr->_ifa = ifa;
|
||||
pr->_promiscuous = promiscuous;
|
||||
|
||||
_list.push_back(pr);
|
||||
|
||||
ifa->pr(pr);
|
||||
ifa->add_serves(pr);
|
||||
|
||||
logger::debug() << "proxy::create() if=" << ifa->name();
|
||||
|
||||
return pr;
|
||||
}
|
||||
|
||||
ptr<proxy> proxy::open(const std::string& ifname)
|
||||
ptr<proxy> proxy::open(const std::string& ifname, bool promiscuous)
|
||||
{
|
||||
ptr<iface> ifa = iface::open_pfd(ifname);
|
||||
ptr<iface> ifa = iface::open_pfd(ifname, promiscuous);
|
||||
|
||||
if (!ifa) {
|
||||
return ptr<proxy>();
|
||||
}
|
||||
|
||||
return create(ifa);
|
||||
return create(ifa, promiscuous);
|
||||
}
|
||||
|
||||
void proxy::handle_solicit(const address& saddr, const address& daddr,
|
||||
const address& taddr)
|
||||
ptr<session> proxy::find_or_create_session(const address& taddr)
|
||||
{
|
||||
logger::debug()
|
||||
<< "proxy::handle_solicit() saddr=" << saddr.to_string()
|
||||
<< ", taddr=" << taddr.to_string();
|
||||
|
||||
// Let's check this proxy's list of sessions to see if we can
|
||||
// find one with the same target address.
|
||||
|
||||
for (std::list<ptr<session> >::iterator sit = _sessions.begin();
|
||||
sit != _sessions.end(); sit++) {
|
||||
|
||||
if ((*sit)->taddr() == taddr) {
|
||||
switch ((*sit)->status()) {
|
||||
case session::WAITING:
|
||||
case session::INVALID:
|
||||
break;
|
||||
|
||||
case session::VALID:
|
||||
(*sit)->send_advert();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if ((*sit)->taddr() == taddr)
|
||||
return (*sit);
|
||||
}
|
||||
|
||||
|
||||
ptr<session> se;
|
||||
|
||||
// Since we couldn't find a session that matched, we'll try to find
|
||||
// a matching rule instead, and then set up a new session.
|
||||
|
||||
ptr<session> se;
|
||||
|
||||
|
||||
for (std::list<ptr<rule> >::iterator it = _rules.begin();
|
||||
it != _rules.end(); it++) {
|
||||
ptr<rule> ru = *it;
|
||||
|
||||
logger::debug() << "checking " << ru->addr() << " against " << taddr;
|
||||
|
||||
if (!daddr.is_multicast() && ru->addr() != daddr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ru->addr() == taddr) {
|
||||
if (!se) {
|
||||
se = session::create(_ptr, saddr, daddr, taddr);
|
||||
se = session::create(_ptr, taddr, _autowire, _keepalive, _retries);
|
||||
}
|
||||
|
||||
|
||||
if (ru->is_auto()) {
|
||||
ptr<route> rt = route::find(taddr);
|
||||
|
||||
@ -115,20 +127,24 @@ void proxy::handle_solicit(const address& saddr, const address& daddr,
|
||||
} 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();
|
||||
return;
|
||||
return se;
|
||||
|
||||
} else {
|
||||
se->add_iface((*it)->ifa());
|
||||
|
||||
ptr<iface> ifa = ru->daughter();
|
||||
se->add_iface(ifa);
|
||||
|
||||
#ifdef WITH_ND_NETLINK
|
||||
if (if_addr_find((*it)->ifa()->name(), &taddr.const_addr())) {
|
||||
logger::debug() << "Sending NA out " << (*it)->ifa()->name();
|
||||
if (if_addr_find(ifa->name(), &taddr.const_addr())) {
|
||||
logger::debug() << "Sending NA out " << ifa->name();
|
||||
se->add_iface(_ifa);
|
||||
se->handle_advert();
|
||||
}
|
||||
@ -136,16 +152,75 @@ void proxy::handle_solicit(const address& saddr, const address& daddr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (se) {
|
||||
_sessions.push_back(se);
|
||||
se->send_solicit();
|
||||
}
|
||||
|
||||
return se;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ptr<rule> proxy::add_rule(const address& addr, const ptr<iface>& ifa)
|
||||
void proxy::handle_stateless_advert(const address& saddr, const address& taddr, const std::string& ifname, bool use_via)
|
||||
{
|
||||
logger::debug()
|
||||
<< "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;
|
||||
|
||||
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, const std::string& ifname)
|
||||
{
|
||||
logger::debug()
|
||||
<< "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();
|
||||
|
||||
// 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);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
@ -157,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);
|
||||
@ -167,6 +252,11 @@ const ptr<iface>& proxy::ifa() const
|
||||
return _ifa;
|
||||
}
|
||||
|
||||
bool proxy::promiscuous() const
|
||||
{
|
||||
return _promiscuous;
|
||||
}
|
||||
|
||||
bool proxy::router() const
|
||||
{
|
||||
return _router;
|
||||
@ -177,6 +267,36 @@ void proxy::router(bool val)
|
||||
_router = val;
|
||||
}
|
||||
|
||||
bool proxy::autowire() const
|
||||
{
|
||||
return _autowire;
|
||||
}
|
||||
|
||||
void proxy::autowire(bool val)
|
||||
{
|
||||
_autowire = val;
|
||||
}
|
||||
|
||||
int proxy::retries() const
|
||||
{
|
||||
return _retries;
|
||||
}
|
||||
|
||||
void proxy::retries(int val)
|
||||
{
|
||||
_retries = val;
|
||||
}
|
||||
|
||||
bool proxy::keepalive() const
|
||||
{
|
||||
return _keepalive;
|
||||
}
|
||||
|
||||
void proxy::keepalive(bool val)
|
||||
{
|
||||
_keepalive = val;
|
||||
}
|
||||
|
||||
int proxy::ttl() const
|
||||
{
|
||||
return _ttl;
|
||||
@ -187,6 +307,16 @@ void proxy::ttl(int val)
|
||||
_ttl = (val >= 0) ? val : 30000;
|
||||
}
|
||||
|
||||
int proxy::deadtime() const
|
||||
{
|
||||
return _deadtime;
|
||||
}
|
||||
|
||||
void proxy::deadtime(int val)
|
||||
{
|
||||
_deadtime = (val >= 0) ? val : 30000;
|
||||
}
|
||||
|
||||
int proxy::timeout() const
|
||||
{
|
||||
return _timeout;
|
||||
|
53
src/proxy.h
53
src/proxy.h
@ -29,25 +29,50 @@ class iface;
|
||||
class rule;
|
||||
|
||||
class proxy {
|
||||
public:
|
||||
static ptr<proxy> create(const ptr<iface>& ifa);
|
||||
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);
|
||||
|
||||
void handle_solicit(const address& saddr, const address& daddr,
|
||||
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& 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;
|
||||
|
||||
bool promiscuous() const;
|
||||
|
||||
bool router() const;
|
||||
|
||||
void router(bool val);
|
||||
|
||||
bool autowire() const;
|
||||
|
||||
void autowire(bool val);
|
||||
|
||||
int retries() const;
|
||||
|
||||
void retries(int val);
|
||||
|
||||
bool keepalive() const;
|
||||
|
||||
void keepalive(bool val);
|
||||
|
||||
int timeout() const;
|
||||
|
||||
@ -56,6 +81,10 @@ public:
|
||||
int ttl() const;
|
||||
|
||||
void ttl(int val);
|
||||
|
||||
int deadtime() const;
|
||||
|
||||
void deadtime(int val);
|
||||
|
||||
private:
|
||||
static std::list<ptr<proxy> > _list;
|
||||
@ -67,10 +96,18 @@ private:
|
||||
std::list<ptr<rule> > _rules;
|
||||
|
||||
std::list<ptr<session> > _sessions;
|
||||
|
||||
bool _promiscuous;
|
||||
|
||||
bool _router;
|
||||
|
||||
bool _autowire;
|
||||
|
||||
int _retries;
|
||||
|
||||
bool _keepalive;
|
||||
|
||||
int _ttl, _timeout;
|
||||
int _ttl, _deadtime, _timeout;
|
||||
|
||||
proxy();
|
||||
};
|
||||
|
@ -105,19 +105,19 @@ void route::load(const std::string& path)
|
||||
|
||||
unsigned char pfx;
|
||||
|
||||
if (hexdec(buf, (unsigned char* )&addr.addr(), 16) != 16) {
|
||||
if (route::hexdec(buf, (unsigned char* )&addr.addr(), 16) != 16) {
|
||||
// TODO: Warn here?
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hexdec(buf + 33,& pfx, 1) != 1) {
|
||||
if (route::hexdec(buf + 33,& pfx, 1) != 1) {
|
||||
// TODO: Warn here?
|
||||
continue;
|
||||
}
|
||||
|
||||
addr.prefix((int)pfx);
|
||||
|
||||
route::create(addr, token(buf + 141));
|
||||
route::create(addr, route::token(buf + 141));
|
||||
}
|
||||
} catch (std::ifstream::failure e) {
|
||||
logger::warning() << "Failed to parse IPv6 routing data from '" << path << "'";
|
||||
|
12
src/route.h
12
src/route.h
@ -44,6 +44,12 @@ public:
|
||||
const address& addr() const;
|
||||
|
||||
ptr<iface> ifa();
|
||||
|
||||
route(const address& addr, const std::string& ifname);
|
||||
|
||||
static size_t hexdec(const char* str, unsigned char* buf, size_t size);
|
||||
|
||||
static std::string token(const char* str);
|
||||
|
||||
private:
|
||||
static int _ttl;
|
||||
@ -56,14 +62,8 @@ private:
|
||||
|
||||
ptr<iface> _ifa;
|
||||
|
||||
static size_t hexdec(const char* str, unsigned char* buf, size_t size);
|
||||
|
||||
static std::string token(const char* str);
|
||||
|
||||
static std::list<ptr<route> > _routes;
|
||||
|
||||
route(const address& addr, const std::string& ifname);
|
||||
|
||||
};
|
||||
|
||||
NDPPD_NS_END
|
||||
|
36
src/rule.cc
36
src/rule.cc
@ -29,6 +29,10 @@ std::vector<interface> interfaces;
|
||||
|
||||
bool rule::_any_aut = false;
|
||||
|
||||
bool rule::_any_iface = false;
|
||||
|
||||
bool rule::_any_static = false;
|
||||
|
||||
rule::rule()
|
||||
{
|
||||
}
|
||||
@ -38,9 +42,10 @@ 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;
|
||||
unsigned int ifindex;
|
||||
|
||||
ifindex = if_nametoindex(pr->ifa()->name().c_str());
|
||||
@ -52,7 +57,7 @@ ptr<rule> rule::create(const ptr<proxy>& pr, const address& addr, const ptr<ifac
|
||||
if_add_to_list(ifindex, ifa);
|
||||
#endif
|
||||
|
||||
logger::debug() << "rule::create() if=" << pr->ifa()->name() << ", addr=" << addr;
|
||||
logger::debug() << "rule::create() if=" << pr->ifa()->name() << ", slave=" << ifa->name() << ", addr=" << addr;
|
||||
|
||||
return ru;
|
||||
}
|
||||
@ -65,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
|
||||
@ -78,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
|
||||
@ -88,11 +96,31 @@ 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;
|
||||
}
|
||||
|
||||
bool rule::any_iface()
|
||||
{
|
||||
return _any_iface;
|
||||
}
|
||||
|
||||
bool rule::any_static()
|
||||
{
|
||||
return _any_static;
|
||||
}
|
||||
|
||||
bool rule::check(const address& addr) const
|
||||
{
|
||||
return _addr == addr;
|
||||
|
18
src/rule.h
18
src/rule.h
@ -37,26 +37,40 @@ public:
|
||||
|
||||
const address& addr() const;
|
||||
|
||||
ptr<iface> ifa() const;
|
||||
ptr<iface> daughter() const;
|
||||
|
||||
bool is_auto() const;
|
||||
|
||||
bool check(const address& addr) const;
|
||||
|
||||
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;
|
||||
|
||||
bool _aut;
|
||||
|
||||
static bool _any_aut;
|
||||
|
||||
static bool _any_static;
|
||||
|
||||
static bool _any_iface;
|
||||
|
||||
bool _autovia;
|
||||
|
||||
rule();
|
||||
};
|
||||
|
273
src/session.cc
273
src/session.cc
@ -14,6 +14,7 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "ndppd.h"
|
||||
#include "proxy.h"
|
||||
@ -42,10 +43,54 @@ void session::update_all(int elapsed_time)
|
||||
}
|
||||
|
||||
switch (se->_status) {
|
||||
|
||||
case session::WAITING:
|
||||
logger::debug() << "session is now invalid";
|
||||
se->_status = session::INVALID;
|
||||
se->_ttl = se->_pr->ttl();
|
||||
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();
|
||||
}
|
||||
break;
|
||||
|
||||
case session::RENEWING:
|
||||
logger::debug() << "session is became invalid [taddr=" << se->_taddr << "]";
|
||||
|
||||
if (se->_fails < se->_retries) {
|
||||
se->_ttl = se->_pr->timeout();
|
||||
se->_fails++;
|
||||
|
||||
// Send another solicit
|
||||
se->send_solicit();
|
||||
} else {
|
||||
se->_pr->remove_session(se);
|
||||
}
|
||||
break;
|
||||
|
||||
case session::VALID:
|
||||
if (se->touched() == true ||
|
||||
se->keepalive() == true)
|
||||
{
|
||||
logger::debug() << "session is renewing [taddr=" << se->_taddr << "]";
|
||||
se->_status = session::RENEWING;
|
||||
se->_ttl = se->_pr->timeout();
|
||||
se->_fails = 0;
|
||||
se->_touched = false;
|
||||
|
||||
// Send another solicit to make sure the route is still valid
|
||||
se->send_solicit();
|
||||
} else {
|
||||
se->_pr->remove_session(se);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -57,30 +102,34 @@ void session::update_all(int elapsed_time)
|
||||
session::~session()
|
||||
{
|
||||
logger::debug() << "session::~session() this=" << logger::format("%x", this);
|
||||
|
||||
for (std::list<ptr<iface> >::iterator it = _ifaces.begin();
|
||||
|
||||
if (_wired == true) {
|
||||
for (std::list<ptr<iface> >::iterator it = _ifaces.begin();
|
||||
it != _ifaces.end(); it++) {
|
||||
(*it)->remove_session(_ptr);
|
||||
handle_auto_unwire((*it)->name());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ptr<session> session::create(const ptr<proxy>& pr, const address& saddr,
|
||||
const address& daddr, const address& taddr)
|
||||
ptr<session> session::create(const ptr<proxy>& pr, const address& taddr, bool auto_wire, bool keepalive, int retries)
|
||||
{
|
||||
ptr<session> se(new session());
|
||||
|
||||
se->_ptr = se;
|
||||
se->_pr = pr;
|
||||
se->_saddr = address("::") == saddr ? all_nodes : saddr;
|
||||
se->_taddr = taddr;
|
||||
se->_daddr = daddr;
|
||||
se->_ttl = pr->timeout();
|
||||
se->_ptr = se;
|
||||
se->_pr = pr;
|
||||
se->_taddr = taddr;
|
||||
se->_autowire = auto_wire;
|
||||
se->_keepalive = keepalive;
|
||||
se->_retries = retries;
|
||||
se->_wired = false;
|
||||
se->_ttl = pr->ttl();
|
||||
se->_touched = false;
|
||||
|
||||
_sessions.push_back(se);
|
||||
|
||||
logger::debug()
|
||||
<< "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", saddr=" << saddr
|
||||
<< ", daddr=" << daddr << ", taddr=" << taddr << " =" << logger::format("%x", (session* )se);
|
||||
<< "session::create() pr=" << logger::format("%x", (proxy* )pr) << ", proxy=" << ((pr->ifa()) ? pr->ifa()->name() : "null")
|
||||
<< ", taddr=" << taddr << " =" << logger::format("%x", (session* )se);
|
||||
|
||||
return se;
|
||||
}
|
||||
@ -90,10 +139,19 @@ 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);
|
||||
}
|
||||
|
||||
void session::add_pending(const address& addr)
|
||||
{
|
||||
for (std::list<ptr<address> >::iterator ad = _pending.begin(); ad != _pending.end(); ad++) {
|
||||
if (addr == (*ad))
|
||||
return;
|
||||
}
|
||||
|
||||
_pending.push_back(new address(addr));
|
||||
}
|
||||
|
||||
void session::send_solicit()
|
||||
{
|
||||
logger::debug() << "session::send_solicit() (_ifaces.size() = " << _ifaces.size() << ")";
|
||||
@ -105,17 +163,162 @@ void session::send_solicit()
|
||||
}
|
||||
}
|
||||
|
||||
void session::send_advert()
|
||||
void session::touch()
|
||||
{
|
||||
_pr->ifa()->write_advert(_saddr, _taddr, _pr->router());
|
||||
if (_touched == false)
|
||||
{
|
||||
_touched = true;
|
||||
|
||||
if (status() == session::WAITING || status() == session::INVALID) {
|
||||
_ttl = _pr->timeout();
|
||||
|
||||
logger::debug() << "session is now probing [taddr=" << _taddr << "]";
|
||||
|
||||
send_solicit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void session::send_advert(const address& daddr)
|
||||
{
|
||||
_pr->ifa()->write_advert(daddr, _taddr, _pr->router());
|
||||
}
|
||||
|
||||
void session::handle_auto_wire(const address& saddr, const std::string& ifname, bool use_via)
|
||||
{
|
||||
if (_wired == true && (_wired_via.is_empty() || _wired_via == saddr))
|
||||
return;
|
||||
|
||||
logger::debug()
|
||||
<< "session::handle_auto_wire() taddr=" << _taddr << ", ifname=" << ifname;
|
||||
|
||||
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();
|
||||
|
||||
{
|
||||
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 std::string& ifname)
|
||||
{
|
||||
logger::debug()
|
||||
<< "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);
|
||||
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());
|
||||
}
|
||||
|
||||
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 address& saddr, const std::string& ifname, bool use_via)
|
||||
{
|
||||
if (_autowire == true && _status == WAITING) {
|
||||
handle_auto_wire(saddr, ifname, use_via);
|
||||
}
|
||||
|
||||
handle_advert();
|
||||
}
|
||||
|
||||
|
||||
void session::handle_advert()
|
||||
{
|
||||
_status = VALID;
|
||||
logger::debug()
|
||||
<< "session::handle_advert() taddr=" << _taddr << ", ttl=" << _pr->ttl();
|
||||
|
||||
if (_status != VALID) {
|
||||
_status = VALID;
|
||||
|
||||
logger::debug() << "session is active [taddr=" << _taddr << "]";
|
||||
}
|
||||
|
||||
_ttl = _pr->ttl();
|
||||
_fails = 0;
|
||||
|
||||
if (!_pending.empty()) {
|
||||
for (std::list<ptr<address> >::iterator ad = _pending.begin();
|
||||
ad != _pending.end(); ad++) {
|
||||
ptr<address> addr = (*ad);
|
||||
logger::debug() << " - forward to " << addr;
|
||||
|
||||
send_advert();
|
||||
send_advert(addr);
|
||||
}
|
||||
|
||||
_pending.clear();
|
||||
}
|
||||
}
|
||||
|
||||
const address& session::taddr() const
|
||||
@ -123,14 +326,34 @@ const address& session::taddr() const
|
||||
return _taddr;
|
||||
}
|
||||
|
||||
const address& session::saddr() const
|
||||
bool session::autowire() const
|
||||
{
|
||||
return _saddr;
|
||||
return _autowire;
|
||||
}
|
||||
|
||||
const address& session::daddr() const
|
||||
bool session::keepalive() const
|
||||
{
|
||||
return _daddr;
|
||||
return _keepalive;
|
||||
}
|
||||
|
||||
int session::retries() const
|
||||
{
|
||||
return _retries;
|
||||
}
|
||||
|
||||
int session::fails() const
|
||||
{
|
||||
return _fails;
|
||||
}
|
||||
|
||||
bool session::wired() const
|
||||
{
|
||||
return _wired;
|
||||
}
|
||||
|
||||
bool session::touched() const
|
||||
{
|
||||
return _touched;
|
||||
}
|
||||
|
||||
int session::status() const
|
||||
|
@ -16,6 +16,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#include "ndppd.h"
|
||||
|
||||
@ -31,14 +32,30 @@ private:
|
||||
weak_ptr<proxy> _pr;
|
||||
|
||||
address _saddr, _daddr, _taddr;
|
||||
|
||||
bool _autowire;
|
||||
|
||||
bool _keepalive;
|
||||
|
||||
bool _wired;
|
||||
|
||||
address _wired_via;
|
||||
|
||||
bool _touched;
|
||||
|
||||
// An array of interfaces this session is monitoring for
|
||||
// ND_NEIGHBOR_ADVERT on.
|
||||
std::list<ptr<iface> > _ifaces;
|
||||
|
||||
std::list<ptr<address> > _pending;
|
||||
|
||||
// The remaining time in miliseconds the object will stay in the
|
||||
// interface's session array or cache.
|
||||
int _ttl;
|
||||
|
||||
int _fails;
|
||||
|
||||
int _retries;
|
||||
|
||||
int _status;
|
||||
|
||||
@ -47,9 +64,10 @@ private:
|
||||
public:
|
||||
enum
|
||||
{
|
||||
WAITING, // Waiting for an advert response.
|
||||
VALID, // Valid;
|
||||
INVALID // Invalid;
|
||||
WAITING, // Waiting for an advert response.
|
||||
RENEWING, // Renewing;
|
||||
VALID, // Valid;
|
||||
INVALID // Invalid;
|
||||
};
|
||||
|
||||
static void update_all(int elapsed_time);
|
||||
@ -57,24 +75,45 @@ public:
|
||||
// Destructor.
|
||||
~session();
|
||||
|
||||
static ptr<session> create(const ptr<proxy>& pr, const address& saddr,
|
||||
const address& daddr, const address& taddr);
|
||||
static ptr<session> create(const ptr<proxy>& pr, const address& taddr, bool autowire, bool keepalive, int retries);
|
||||
|
||||
void add_iface(const ptr<iface>& ifa);
|
||||
|
||||
void add_pending(const address& addr);
|
||||
|
||||
const address& taddr() const;
|
||||
|
||||
const address& daddr() const;
|
||||
|
||||
const address& saddr() const;
|
||||
|
||||
bool autowire() const;
|
||||
|
||||
int retries() const;
|
||||
|
||||
int fails() const;
|
||||
|
||||
bool keepalive() const;
|
||||
|
||||
bool wired() const;
|
||||
|
||||
bool touched() const;
|
||||
|
||||
int status() const;
|
||||
|
||||
void status(int val);
|
||||
|
||||
|
||||
void handle_advert();
|
||||
|
||||
void send_advert();
|
||||
void handle_advert(const address& saddr, const std::string& ifname, bool use_via);
|
||||
|
||||
void handle_auto_wire(const address& saddr, const std::string& ifname, bool use_via);
|
||||
|
||||
void handle_auto_unwire(const std::string& ifname);
|
||||
|
||||
void touch();
|
||||
|
||||
void send_advert(const address& daddr);
|
||||
|
||||
void send_solicit();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user