diff --git a/Makefile b/Makefile index 2c6a297..fc49401 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ DEBUG=1 ifdef DEBUG -CXXFLAGS ?= -g -std=c++0x -DDEBUG +CXXFLAGS ?= -g -DDEBUG else -CXXFLAGS ?= -O3 -std=c++0x +CXXFLAGS ?= -O3 endif PREFIX ?= /usr/local @@ -12,7 +12,7 @@ GZIP ?= /bin/gzip MANDIR ?= ${DESTDIR}${PREFIX}/share/man SBINDIR ?= ${DESTDIR}${PREFIX}/sbin -LIBS = -lconfuse +LIBS = OBJS = src/logger.o src/ndppd.o src/iface.o src/proxy.o src/address.o \ src/rule.o src/session.o src/conf.o diff --git a/src/conf.cc b/src/conf.cc index e885756..0ede487 100644 --- a/src/conf.cc +++ b/src/conf.cc @@ -17,7 +17,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -55,18 +57,17 @@ void conf::value(const std::string &value) _value = value; } -std::shared_ptr conf::load(const std::string &path) +ptr conf::load(const std::string &path) { - std::ifstream ifs; - ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); - try { - ifs.open(path, std::ios::in); + std::ifstream ifs; + ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit); + ifs.open(path.c_str(), std::ios::in); std::string buf((std::istreambuf_iterator(ifs)), std::istreambuf_iterator()); - ifs.close(); + const char *c_buf = buf.c_str(); - std::shared_ptr cf(new conf); + ptr cf(new conf); if (cf->parse_block(&c_buf)) { logger l(LOG_DEBUG); @@ -79,7 +80,7 @@ std::shared_ptr conf::load(const std::string &path) logger::error() << "Failed to load configuration file '" << path << "'"; } - return std::shared_ptr(); + return ptr(); } bool conf::is_block() const @@ -152,10 +153,10 @@ bool conf::parse_block(const char **str) p++; } - std::shared_ptr cf(new conf); + ptr cf(new conf); if (cf->parse(&p)) { - _map.insert(std::pair >(ss.str(), cf)); + _map.insert(std::pair >(ss.str(), cf)); } } @@ -224,7 +225,7 @@ void conf::dump(logger &l, int level) const if (_is_block) { l << "{" << logger::endl; - std::multimap >::const_iterator it; + std::multimap >::const_iterator it; for (it = _map.begin(); it != _map.end(); it++) { l << pfx << " " << it->first << " "; @@ -237,20 +238,20 @@ void conf::dump(logger &l, int level) const l << logger::endl; } -std::shared_ptr conf::operator[](const std::string& name) const +ptr conf::operator[](const std::string& name) const { - std::multimap >::const_iterator it; + std::multimap >::const_iterator it; if ((it = _map.find(name)) == _map.end()) - return std::shared_ptr(); + return ptr(); else return it->second; } -std::vector > conf::find(const std::string& name) const +std::vector > conf::find(const std::string& name) const { - std::vector > vec; - std::multimap >::const_iterator it; + std::vector > vec; + std::multimap >::const_iterator it; for (it = _map.find(name); it != _map.end(); it++) { vec.push_back(it->second); } diff --git a/src/conf.h b/src/conf.h index 9b72ab3..4e75d8c 100644 --- a/src/conf.h +++ b/src/conf.h @@ -34,7 +34,7 @@ private: bool _is_block; - std::multimap > _map; + std::multimap > _map; void dump(logger &l, int level) const; @@ -55,12 +55,12 @@ public: void value(const std::string &value); - static std::shared_ptr load(const std::string &path); + static ptr load(const std::string &path); bool is_block() const; - std::shared_ptr operator[](const std::string &name) const; - std::vector > find(const std::string &name) const; + ptr operator[](const std::string &name) const; + std::vector > find(const std::string &name) const; void dump() const; diff --git a/src/iface.cc b/src/iface.cc index c66c0c1..905c07e 100644 --- a/src/iface.cc +++ b/src/iface.cc @@ -42,7 +42,7 @@ NDPPD_NS_BEGIN -std::map > iface::_map; +std::map > iface::_map; std::vector iface::_pollfds; @@ -64,13 +64,13 @@ iface::~iface() } } -std::shared_ptr iface::open_pfd(const std::string& name) +ptr iface::open_pfd(const std::string& name) { int fd; - std::map >::iterator it = _map.find(name); + std::map >::iterator it = _map.find(name); - std::shared_ptr ifa; + ptr ifa; if (it != _map.end()) { if (it->second->_pfd >= 0) @@ -83,13 +83,13 @@ std::shared_ptr iface::open_pfd(const std::string& name) } if (!ifa) - return std::shared_ptr(); + return ptr(); // Create a socket. if ((fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IPV6))) < 0) { logger::error() << "Unable to create socket"; - return std::shared_ptr(); + return ptr(); } // Bind to the specified interface. @@ -103,13 +103,13 @@ std::shared_ptr iface::open_pfd(const std::string& name) if (!(lladdr.sll_ifindex = if_nametoindex(name.c_str()))) { close(fd); logger::error() << "Failed to bind to interface '" << name << "'"; - return std::shared_ptr(); + return ptr(); } if (bind(fd, (struct sockaddr *)&lladdr, sizeof(struct sockaddr_ll)) < 0) { close(fd); logger::error() << "Failed to bind to interface '" << name << "'"; - return std::shared_ptr(); + return ptr(); } // Switch to non-blocking mode. @@ -119,7 +119,7 @@ std::shared_ptr iface::open_pfd(const std::string& name) if (ioctl(fd, FIONBIO, (char *)&on) < 0) { close(fd); logger::error() << "Failed to switch to non-blocking on interface '" << name << "'"; - return std::shared_ptr(); + return ptr(); } // Set up filter. @@ -154,7 +154,7 @@ std::shared_ptr iface::open_pfd(const std::string& name) if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0) { logger::error() << "Failed to set filter"; - return std::shared_ptr(); + return ptr(); } // Set up an instance of 'iface'. @@ -166,11 +166,11 @@ std::shared_ptr iface::open_pfd(const std::string& name) return ifa; } -std::shared_ptr iface::open_ifd(const std::string& name) +ptr iface::open_ifd(const std::string& name) { int fd; - std::map >::iterator it = _map.find(name); + std::map >::iterator it = _map.find(name); if ((it != _map.end()) && it->second->_ifd) return it->second; @@ -179,7 +179,7 @@ std::shared_ptr iface::open_ifd(const std::string& name) if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) { logger::error() << "Unable to create socket"; - return std::shared_ptr(); + return ptr(); } // Bind to the specified interface. @@ -193,7 +193,7 @@ std::shared_ptr iface::open_ifd(const std::string& name) if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) { close(fd); logger::error() << "Failed to bind to interface '" << name << "'"; - return std::shared_ptr(); + return ptr(); } // Detect the link-layer address. @@ -205,7 +205,7 @@ std::shared_ptr iface::open_ifd(const std::string& name) if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { close(fd); logger::error() << "Failed to detect link-layer address for interface '" << name << "'"; - return std::shared_ptr(); + return ptr(); } logger::debug() << "fd=" << fd << ", hwaddr=" << ether_ntoa((const struct ether_addr *)&ifr.ifr_hwaddr.sa_data);; @@ -217,13 +217,13 @@ std::shared_ptr iface::open_ifd(const std::string& name) if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)) < 0) { close(fd); logger::error() << "iface::open_ifd() failed IPV6_MULTICAST_HOPS"; - return std::shared_ptr(); + return ptr(); } if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, sizeof(hops)) < 0) { close(fd); logger::error() << "iface::open_ifd() failed IPV6_UNICAST_HOPS"; - return std::shared_ptr(); + return ptr(); } // Switch to non-blocking mode. @@ -233,7 +233,7 @@ std::shared_ptr iface::open_ifd(const std::string& name) if (ioctl(fd, FIONBIO, (char *)&on) < 0) { close(fd); logger::error() << "Failed to switch to non-blocking on interface '" << name << "'"; - return std::shared_ptr(); + return ptr(); } // Set up filter. @@ -244,15 +244,15 @@ std::shared_ptr iface::open_ifd(const std::string& name) if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) < 0) { logger::error() << "Failed to set filter"; - return std::shared_ptr(); + return ptr(); } // Set up an instance of 'iface'. - std::shared_ptr ifa; + ptr ifa; if (it == _map.end()) { - ifa.reset(new iface()); + ifa = new iface(); ifa->_name = name; ifa->_ptr = ifa; @@ -451,7 +451,7 @@ void iface::fixup_pollfds() logger::debug() << "iface::fixup_pollfds() _map.size()=" << _map.size(); - for (std::map >::iterator it = _map.begin(); + for (std::map >::iterator it = _map.begin(); it != _map.end(); it++) { _pollfds[i].fd = it->second->_ifd; _pollfds[i].events = POLLIN; @@ -465,18 +465,18 @@ void iface::fixup_pollfds() } } -void iface::remove_session(const std::shared_ptr& se) +void iface::remove_session(const ptr& se) { - for (std::list >::iterator it = _sessions.begin(); + for (std::list >::iterator it = _sessions.begin(); it != _sessions.end(); it++) { - if (it->lock() == se) { + if (*it == se) { _sessions.erase(it); break; } } } -void iface::add_session(const std::shared_ptr& se) +void iface::add_session(const ptr& se) { _sessions.push_back(se); } @@ -498,7 +498,7 @@ int iface::poll_all() if (len == 0) return 0; - std::map >::iterator i_it = _map.begin(); + std::map >::iterator i_it = _map.begin(); int i = 0; @@ -514,7 +514,7 @@ int iface::poll_all() if (!(f_it->revents & POLLIN)) continue; - std::shared_ptr ifa = i_it->second; + ptr ifa = i_it->second; address saddr, daddr, taddr; @@ -534,9 +534,9 @@ int iface::poll_all() continue; } - for (std::list >::iterator s_it = ifa->_sessions.begin(); + for (std::list >::iterator s_it = ifa->_sessions.begin(); s_it != ifa->_sessions.end(); s_it++) { - const std::shared_ptr sess = s_it->lock(); + const ptr sess = *s_it; if ((sess->taddr() == taddr) && (sess->status() == session::WAITING)) { sess->handle_advert(); break; @@ -582,12 +582,12 @@ const std::string& iface::name() const return _name; } -void iface::pr(const std::shared_ptr& pr) +void iface::pr(const ptr& pr) { _pr = pr; } -const std::shared_ptr& iface::pr() const +const ptr& iface::pr() const { return _pr; } diff --git a/src/iface.h b/src/iface.h index 0084496..a3b870b 100644 --- a/src/iface.h +++ b/src/iface.h @@ -34,9 +34,9 @@ class iface { private: // Weak pointer so this object can reference itself. - std::weak_ptr _ptr; + weak_ptr _ptr; - static std::map > _map; + static std::map > _map; // An array of objects used with ::poll. static std::vector _pollfds; @@ -60,9 +60,9 @@ private: // An array of sessions that are monitoring this interface for // ND_NEIGHBOR_ADVERT messages. - std::list > _sessions; + std::list > _sessions; - std::shared_ptr _pr; + ptr _pr; // The link-layer address of this interface. struct ether_addr hwaddr; @@ -79,9 +79,9 @@ public: // Destructor. ~iface(); - static std::shared_ptr open_ifd(const std::string& name); + static ptr open_ifd(const std::string& name); - static std::shared_ptr open_pfd(const std::string& name); + static ptr open_pfd(const std::string& name); static int poll_all(); @@ -105,13 +105,13 @@ public: const std::string& name() const; // Adds a session to be monitored for ND_NEIGHBOR_ADVERT messages. - void add_session(const std::shared_ptr& se); + void add_session(const ptr& se); - void remove_session(const std::shared_ptr& se); + void remove_session(const ptr& se); - void pr(const std::shared_ptr& pr); + void pr(const ptr& pr); - const std::shared_ptr& pr() const; + const ptr& pr() const; }; NDPPD_NS_END diff --git a/src/logger.cc b/src/logger.cc index c500226..87d3ab0 100644 --- a/src/logger.cc +++ b/src/logger.cc @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include diff --git a/src/ndppd.cc b/src/ndppd.cc index d5bc120..e21e9f4 100644 --- a/src/ndppd.cc +++ b/src/ndppd.cc @@ -13,6 +13,8 @@ // // You should have received a copy of the GNU General Public License // along with this program. If not, see . +#include + #include #include #include @@ -52,24 +54,24 @@ int daemonize() bool configure(const std::string &path) { - std::shared_ptr cf; + ptr cf; if (!(cf = conf::load(path))) return false; - std::vector >::const_iterator p_it; + std::vector >::const_iterator p_it; - std::vector > proxies(cf->find("proxy")); + std::vector > proxies(cf->find("proxy")); for (p_it = proxies.begin(); p_it != proxies.end(); p_it++) { - std::shared_ptr pr_cf = *p_it, x_cf; + ptr pr_cf = *p_it, x_cf; if (pr_cf->value() == "") { logger::error() << "'proxy' section is missing interface name"; return false; } - std::shared_ptr pr = proxy::open(pr_cf->value()); + ptr pr = proxy::open(pr_cf->value()); if (!pr) { logger::error() << "Configuration failed for proxy '" << pr_cf->value() << "'"; @@ -91,12 +93,12 @@ bool configure(const std::string &path) else pr->timeout(x_cf->int_value()); - std::vector >::const_iterator r_it; + std::vector >::const_iterator r_it; - std::vector > rules(pr_cf->find("rule")); + std::vector > rules(pr_cf->find("rule")); for (r_it = rules.begin(); r_it != rules.end(); r_it++) { - std::shared_ptr ru_cf = *r_it; + ptr ru_cf = *r_it; if (ru_cf->value() == "") { logger::error() << "'rule' is missing an IPv6 address/net"; diff --git a/src/ndppd.h b/src/ndppd.h index 3126da9..6bc712e 100644 --- a/src/ndppd.h +++ b/src/ndppd.h @@ -25,6 +25,8 @@ #include +#include "ptr.h" + #include "logger.h" #include "conf.h" #include "address.h" diff --git a/src/proxy.cc b/src/proxy.cc index 2d5c0f2..34e06f4 100644 --- a/src/proxy.cc +++ b/src/proxy.cc @@ -31,9 +31,9 @@ proxy::proxy() : { } -std::shared_ptr proxy::create(const std::shared_ptr& ifa) +ptr proxy::create(const ptr& ifa) { - std::shared_ptr pr(new proxy()); + ptr pr(new proxy()); pr->_ptr = pr; pr->_ifa = ifa; @@ -44,12 +44,12 @@ std::shared_ptr proxy::create(const std::shared_ptr& ifa) return pr; } -std::shared_ptr proxy::open(const std::string& ifname) +ptr proxy::open(const std::string& ifname) { - std::shared_ptr ifa = iface::open_pfd(ifname); + ptr ifa = iface::open_pfd(ifname); if (!ifa) - return std::shared_ptr(); + return ptr(); return create(ifa); } @@ -63,7 +63,7 @@ void proxy::handle_solicit(const address& saddr, const address& daddr, // Let's check this proxy's list of sessions to see if we can // find one with the same target address. - for (std::list >::iterator sit = _sessions.begin(); + for (std::list >::iterator sit = _sessions.begin(); sit != _sessions.end(); sit++) { if ((*sit)->taddr() == taddr) { @@ -83,17 +83,17 @@ void proxy::handle_solicit(const address& saddr, const address& daddr, // 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. - std::shared_ptr se; + ptr se; - for (std::list >::iterator it = _rules.begin(); + for (std::list >::iterator it = _rules.begin(); it != _rules.end(); it++) { - std::shared_ptr ru = *it; + ptr ru = *it; logger::debug() << "checking " << ru->addr().to_string() << " against " << taddr; if (ru->addr() == taddr) { if (!se) - se = session::create(_ptr.lock(), saddr, daddr, taddr); + se = session::create(_ptr, saddr, daddr, taddr); if (!ru->ifa()) { // This rule doesn't have an interface, and thus we'll consider @@ -113,26 +113,26 @@ void proxy::handle_solicit(const address& saddr, const address& daddr, } } -std::shared_ptr proxy::add_rule(const address& addr, const std::shared_ptr& ifa) +ptr proxy::add_rule(const address& addr, const ptr& ifa) { - std::shared_ptr ru(rule::create(_ptr.lock(), addr, ifa)); + ptr ru(rule::create(_ptr, addr, ifa)); _rules.push_back(ru); return ru; } -std::shared_ptr proxy::add_rule(const address& addr) +ptr proxy::add_rule(const address& addr) { - std::shared_ptr ru(rule::create(_ptr.lock(), addr)); + ptr ru(rule::create(_ptr, addr)); _rules.push_back(ru); return ru; } -void proxy::remove_session(const std::shared_ptr& se) +void proxy::remove_session(const ptr& se) { _sessions.remove(se); } -const std::shared_ptr& proxy::ifa() const +const ptr& proxy::ifa() const { return _ifa; } diff --git a/src/proxy.h b/src/proxy.h index 7a28e13..18dffd5 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -31,13 +31,13 @@ class rule; class proxy { private: - std::weak_ptr _ptr; + weak_ptr _ptr; - std::shared_ptr _ifa; + ptr _ifa; - std::list > _rules; + std::list > _rules; - std::list > _sessions; + std::list > _sessions; bool _router; @@ -46,20 +46,20 @@ private: proxy(); public: - static std::shared_ptr create(const std::shared_ptr& ifa); + static ptr create(const ptr& ifa); - static std::shared_ptr open(const std::string& ifn); + static ptr open(const std::string& ifn); void handle_solicit(const address& saddr, const address& daddr, const address& taddr); - void remove_session(const std::shared_ptr& se); + void remove_session(const ptr& se); - std::shared_ptr add_rule(const address& addr, const std::shared_ptr& ifa); + ptr add_rule(const address& addr, const ptr& ifa); - std::shared_ptr add_rule(const address& addr); + ptr add_rule(const address& addr); - const std::shared_ptr& ifa() const; + const ptr& ifa() const; bool router() const; diff --git a/src/rule.cc b/src/rule.cc index 24adb12..76adabb 100644 --- a/src/rule.cc +++ b/src/rule.cc @@ -28,9 +28,9 @@ rule::rule() { } -std::shared_ptr rule::create(const std::shared_ptr& pr, const address& addr, const std::shared_ptr& ifa) +ptr rule::create(const ptr& pr, const address& addr, const ptr& ifa) { - std::shared_ptr ru(new rule()); + ptr ru(new rule()); ru->_ptr = ru; ru->_pr = pr; ru->_ifa = ifa; @@ -41,9 +41,9 @@ std::shared_ptr rule::create(const std::shared_ptr& pr, const addre return ru; } -std::shared_ptr rule::create(const std::shared_ptr& pr, const address& addr) +ptr rule::create(const ptr& pr, const address& addr) { - std::shared_ptr ru(new rule()); + ptr ru(new rule()); ru->_ptr = ru; ru->_pr = pr; ru->_addr = addr; @@ -58,7 +58,7 @@ const address& rule::addr() const return _addr; } -std::shared_ptr rule::ifa() const +ptr rule::ifa() const { return _ifa; } diff --git a/src/rule.h b/src/rule.h index 4ccefaf..e35bf02 100644 --- a/src/rule.h +++ b/src/rule.h @@ -31,24 +31,24 @@ class proxy; class rule { private: - std::weak_ptr _ptr; + weak_ptr _ptr; - std::shared_ptr _pr; + ptr _pr; - std::shared_ptr _ifa; + ptr _ifa; address _addr; rule(); public: - static std::shared_ptr create(const std::shared_ptr& pr, const address& addr, const std::shared_ptr& ifa); + static ptr create(const ptr& pr, const address& addr, const ptr& ifa); - static std::shared_ptr create(const std::shared_ptr& pr, const address& addr); + static ptr create(const ptr& pr, const address& addr); const address& addr() const; - std::shared_ptr ifa() const; + ptr ifa() const; bool is_static() const; diff --git a/src/session.cc b/src/session.cc index 7631ab7..0618152 100644 --- a/src/session.cc +++ b/src/session.cc @@ -22,13 +22,13 @@ NDPPD_NS_BEGIN -std::list > session::_sessions; +std::list > session::_sessions; void session::update_all(int elapsed_time) { - for (std::list >::iterator it = _sessions.begin(); + for (std::list >::iterator it = _sessions.begin(); it != _sessions.end(); ) { - std::shared_ptr se = (*it++).lock(); + ptr se = (*it++); if ((se->_ttl -= elapsed_time) >= 0) continue; @@ -50,24 +50,24 @@ session::~session() { logger::debug() << "session::~session() this=" << logger::format("%x", this); - for (std::list >::iterator it = _sessions.begin(); + for (std::list >::iterator it = _sessions.begin(); it != _sessions.end(); it++) { - if (it->lock() == _ptr.lock()) { + if (*it == _ptr) { _sessions.erase(it); break; } } - for (std::list >::iterator it = _ifaces.begin(); + for (std::list >::iterator it = _ifaces.begin(); it != _ifaces.end(); it++) { - (*it)->remove_session(_ptr.lock()); + (*it)->remove_session(_ptr); } } -std::shared_ptr session::create(const std::shared_ptr& pr, const address& saddr, +ptr session::create(const ptr& pr, const address& saddr, const address& daddr, const address& taddr) { - std::shared_ptr se(new session()); + ptr se(new session()); se->_ptr = se; se->_pr = pr; @@ -78,18 +78,19 @@ std::shared_ptr session::create(const std::shared_ptr& pr, const _sessions.push_back(se); - logger::debug() << "session::create() pr=" << logger::format("%x", pr.get()) << ", saddr=" << saddr - << ", daddr=" << daddr << ", taddr=" << taddr << " =" << logger::format("%x", se.get()); + logger::debug() + << "session::create() pr=" << logger::format("%x", (proxy *)pr) << ", saddr=" << saddr + << ", daddr=" << daddr << ", taddr=" << taddr << " =" << logger::format("%x", (session *)se); return se; } -void session::add_iface(const std::shared_ptr& ifa) +void session::add_iface(const ptr& ifa) { if (std::find(_ifaces.begin(), _ifaces.end(), ifa) != _ifaces.end()) return; - ifa->add_session(_ptr.lock()); + ifa->add_session(_ptr); _ifaces.push_back(ifa); } @@ -97,7 +98,7 @@ void session::send_solicit() { logger::debug() << "session::send_solicit() (" << _ifaces.size() << ")"; - for (std::list >::iterator it = _ifaces.begin(); + for (std::list >::iterator it = _ifaces.begin(); it != _ifaces.end(); it++) { logger::debug() << " - %s" << (*it)->name(); (*it)->write_solicit(_taddr); diff --git a/src/session.h b/src/session.h index f058bf6..8db7e79 100644 --- a/src/session.h +++ b/src/session.h @@ -27,15 +27,15 @@ class iface; class session { private: - std::weak_ptr _ptr; + weak_ptr _ptr; - std::shared_ptr _pr; + ptr _pr; address _saddr, _daddr, _taddr; // An array of interfaces this session is monitoring for // ND_NEIGHBOR_ADVERT on. - std::list > _ifaces; + std::list > _ifaces; // The remaining time in miliseconds the object will stay in the // interface's session array or cache. @@ -43,7 +43,7 @@ private: int _status; - static std::list > _sessions; + static std::list > _sessions; public: enum @@ -58,10 +58,10 @@ public: // Destructor. ~session(); - static std::shared_ptr create(const std::shared_ptr& pr, const address& saddr, + static ptr create(const ptr& pr, const address& saddr, const address& daddr, const address& taddr); - void add_iface(const std::shared_ptr& ifa); + void add_iface(const ptr& ifa); const address& taddr() const;