Refactor source

- Change coding style

- Switch from own implementation of smart pointers to std::smart_ptr
  and std::weak_ptr
This commit is contained in:
Daniel Adolfsson 2012-01-28 20:25:57 +01:00
parent 6fda405a59
commit bc70f587ef
18 changed files with 988 additions and 1289 deletions

View File

@ -1,7 +1,7 @@
ifdef DEBUG ifdef DEBUG
CXXFLAGS ?= -g -DDEBUG CXXFLAGS ?= -g -std=c++0x -DDEBUG
else else
CXXFLAGS ?= -O3 CXXFLAGS ?= -O3 -std=c++0x
endif endif
PREFIX ?= /usr/local PREFIX ?= /usr/local

View File

@ -32,265 +32,245 @@ __NDPPD_NS_BEGIN
address::address() address::address()
{ {
_addr.s6_addr32[0] = 0; reset();
_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;
} }
address::address(const address& addr) address::address(const address& addr)
{ {
_addr.s6_addr32[0] = addr._addr.s6_addr32[0]; _addr.s6_addr32[0] = addr._addr.s6_addr32[0];
_addr.s6_addr32[1] = addr._addr.s6_addr32[1]; _addr.s6_addr32[1] = addr._addr.s6_addr32[1];
_addr.s6_addr32[2] = addr._addr.s6_addr32[2]; _addr.s6_addr32[2] = addr._addr.s6_addr32[2];
_addr.s6_addr32[3] = addr._addr.s6_addr32[3]; _addr.s6_addr32[3] = addr._addr.s6_addr32[3];
_mask.s6_addr32[0] = addr._mask.s6_addr32[0]; _mask.s6_addr32[0] = addr._mask.s6_addr32[0];
_mask.s6_addr32[1] = addr._mask.s6_addr32[1]; _mask.s6_addr32[1] = addr._mask.s6_addr32[1];
_mask.s6_addr32[2] = addr._mask.s6_addr32[2]; _mask.s6_addr32[2] = addr._mask.s6_addr32[2];
_mask.s6_addr32[3] = addr._mask.s6_addr32[3]; _mask.s6_addr32[3] = addr._mask.s6_addr32[3];
} }
address::address(const std::string& str) address::address(const std::string& str)
{ {
if(!parse_string(str)) parse_string(str);
{
_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;
}
} }
address::address(const char *str) address::address(const char *str)
{ {
if(!parse_string(str)) parse_string(str);
{
_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;
}
} }
address::address(const in6_addr& addr) address::address(const in6_addr& addr)
{ {
_addr.s6_addr32[0] = addr.s6_addr32[0]; _addr.s6_addr32[0] = addr.s6_addr32[0];
_addr.s6_addr32[1] = addr.s6_addr32[1]; _addr.s6_addr32[1] = addr.s6_addr32[1];
_addr.s6_addr32[2] = addr.s6_addr32[2]; _addr.s6_addr32[2] = addr.s6_addr32[2];
_addr.s6_addr32[3] = addr.s6_addr32[3]; _addr.s6_addr32[3] = addr.s6_addr32[3];
_mask.s6_addr32[0] = 0xffffffff; _mask.s6_addr32[0] = 0xffffffff;
_mask.s6_addr32[1] = 0xffffffff; _mask.s6_addr32[1] = 0xffffffff;
_mask.s6_addr32[2] = 0xffffffff; _mask.s6_addr32[2] = 0xffffffff;
_mask.s6_addr32[3] = 0xffffffff; _mask.s6_addr32[3] = 0xffffffff;
} }
address::address(const in6_addr& addr, const in6_addr& mask) address::address(const in6_addr& addr, const in6_addr& mask)
{ {
_addr.s6_addr32[0] = addr.s6_addr32[0]; _addr.s6_addr32[0] = addr.s6_addr32[0];
_addr.s6_addr32[1] = addr.s6_addr32[1]; _addr.s6_addr32[1] = addr.s6_addr32[1];
_addr.s6_addr32[2] = addr.s6_addr32[2]; _addr.s6_addr32[2] = addr.s6_addr32[2];
_addr.s6_addr32[3] = addr.s6_addr32[3]; _addr.s6_addr32[3] = addr.s6_addr32[3];
_mask.s6_addr32[0] = mask.s6_addr32[0]; _mask.s6_addr32[0] = mask.s6_addr32[0];
_mask.s6_addr32[1] = mask.s6_addr32[1]; _mask.s6_addr32[1] = mask.s6_addr32[1];
_mask.s6_addr32[2] = mask.s6_addr32[2]; _mask.s6_addr32[2] = mask.s6_addr32[2];
_mask.s6_addr32[3] = mask.s6_addr32[3]; _mask.s6_addr32[3] = mask.s6_addr32[3];
} }
address::address(const in6_addr& addr, int pf) address::address(const in6_addr& addr, int pf)
{ {
_addr.s6_addr32[0] = addr.s6_addr32[0]; _addr.s6_addr32[0] = addr.s6_addr32[0];
_addr.s6_addr32[1] = addr.s6_addr32[1]; _addr.s6_addr32[1] = addr.s6_addr32[1];
_addr.s6_addr32[2] = addr.s6_addr32[2]; _addr.s6_addr32[2] = addr.s6_addr32[2];
_addr.s6_addr32[3] = addr.s6_addr32[3]; _addr.s6_addr32[3] = addr.s6_addr32[3];
prefix(pf); prefix(pf);
} }
bool address::operator==(const address& addr) const bool address::operator==(const address& addr) const
{ {
return !(((_addr.s6_addr32[0] ^ addr._addr.s6_addr32[0]) & _mask.s6_addr32[0]) | return !(((_addr.s6_addr32[0] ^ addr._addr.s6_addr32[0]) & _mask.s6_addr32[0]) |
((_addr.s6_addr32[1] ^ addr._addr.s6_addr32[1]) & _mask.s6_addr32[1]) |
((_addr.s6_addr32[2] ^ addr._addr.s6_addr32[2]) & _mask.s6_addr32[2]) |
((_addr.s6_addr32[3] ^ addr._addr.s6_addr32[3]) & _mask.s6_addr32[3]));
}
bool address::operator!=(const address& addr) const
{
return !!(((_addr.s6_addr32[0] ^ addr._addr.s6_addr32[0]) & _mask.s6_addr32[0]) |
((_addr.s6_addr32[1] ^ addr._addr.s6_addr32[1]) & _mask.s6_addr32[1]) | ((_addr.s6_addr32[1] ^ addr._addr.s6_addr32[1]) & _mask.s6_addr32[1]) |
((_addr.s6_addr32[2] ^ addr._addr.s6_addr32[2]) & _mask.s6_addr32[2]) | ((_addr.s6_addr32[2] ^ addr._addr.s6_addr32[2]) & _mask.s6_addr32[2]) |
((_addr.s6_addr32[3] ^ addr._addr.s6_addr32[3]) & _mask.s6_addr32[3])); ((_addr.s6_addr32[3] ^ addr._addr.s6_addr32[3]) & _mask.s6_addr32[3]));
} }
bool address::operator!=(const address& addr) const
{
return !!(((_addr.s6_addr32[0] ^ addr._addr.s6_addr32[0]) & _mask.s6_addr32[0]) |
((_addr.s6_addr32[1] ^ addr._addr.s6_addr32[1]) & _mask.s6_addr32[1]) |
((_addr.s6_addr32[2] ^ addr._addr.s6_addr32[2]) & _mask.s6_addr32[2]) |
((_addr.s6_addr32[3] ^ addr._addr.s6_addr32[3]) & _mask.s6_addr32[3]));
}
void address::reset()
{
_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;
}
int address::prefix() const int address::prefix() const
{ {
if(!_mask.s6_addr[0]) if (!_mask.s6_addr[0])
return 0; return 0;
for(int p = 0; p < 128; p++) for (int p = 0; p < 128; p++) {
{ int byi = p / 8, bii = 7 - (p % 8);
int byi = p / 8, bii = 7 - (p % 8); if (!(_mask.s6_addr[byi] & (1 << bii)))
if(!(_mask.s6_addr[byi] & (1 << bii))) return p;
return p; }
}
return 128; return 128;
} }
void address::prefix(int pf) void address::prefix(int pf)
{ {
if((pf < 0) || (pf > 128)) if ((pf < 0) || (pf > 128))
return; return;
_mask.s6_addr32[0] = 0; _mask.s6_addr32[0] = 0;
_mask.s6_addr32[1] = 0; _mask.s6_addr32[1] = 0;
_mask.s6_addr32[2] = 0; _mask.s6_addr32[2] = 0;
_mask.s6_addr32[3] = 0; _mask.s6_addr32[3] = 0;
while(pf--) while (pf--) {
{ int byi = pf / 8, bii = 7 - (pf % 8);
int byi = pf / 8, bii = 7 - (pf % 8); _mask.s6_addr[byi] |= 1 << bii;
_mask.s6_addr[byi] |= 1 << bii; }
}
} }
const std::string address::to_string() const const std::string address::to_string() const
{ {
char buf[INET6_ADDRSTRLEN + 8]; char buf[INET6_ADDRSTRLEN + 8];
if(!inet_ntop(AF_INET6, &_addr, buf, INET6_ADDRSTRLEN)) if (!inet_ntop(AF_INET6, &_addr, buf, INET6_ADDRSTRLEN))
return "::1"; return "::1";
// TODO: What to do about invalid ip? // TODO: What to do about invalid ip?
int p; int p;
if((p = prefix()) < 128) if ((p = prefix()) < 128)
sprintf(buf + strlen(buf), "/%d", p); sprintf(buf + strlen(buf), "/%d", p);
return buf; return buf;
} }
bool address::parse_string(const std::string& str) bool address::parse_string(const std::string& str)
{ {
char buf[INET6_ADDRSTRLEN], *b; char buf[INET6_ADDRSTRLEN], *b;
int sz, pfx; int sz, pfx;
sz = 0; sz = 0;
b = buf; b = buf;
const char *p = str.c_str(); reset();
while(*p && isspace(*p)) const char *p = str.c_str();
p++;
while(*p) while (*p && isspace(*p))
{ p++;
if((*p == '/') || isspace(*p))
break;
if((*p != ':') && !isxdigit(*p)) while (*p) {
return false; if ((*p == '/') || isspace(*p))
break;
if(sz >= (INET6_ADDRSTRLEN - 1)) if ((*p != ':') && !isxdigit(*p))
return false; return false;
*b++ = *p++; if (sz >= (INET6_ADDRSTRLEN - 1))
return false;
sz++; *b++ = *p++;
}
*b = '\0'; sz++;
}
if(inet_pton(AF_INET6, buf, &_addr) <= 0) *b = '\0';
return false;
while(*p && isspace(*p)) if (inet_pton(AF_INET6, buf, &_addr) <= 0)
p++; return false;
if(*p == '\0') while (*p && isspace(*p))
{ p++;
_mask.s6_addr32[0] = 0xffffffff;
_mask.s6_addr32[1] = 0xffffffff;
_mask.s6_addr32[2] = 0xffffffff;
_mask.s6_addr32[3] = 0xffffffff;
return true;
}
if(*p++ != '/') if (*p == '\0') {
return false; _mask.s6_addr32[0] = 0xffffffff;
_mask.s6_addr32[1] = 0xffffffff;
_mask.s6_addr32[2] = 0xffffffff;
_mask.s6_addr32[3] = 0xffffffff;
return true;
}
while(*p && isspace(*p)) if (*p++ != '/')
p++; return false;
sz = 0; while (*p && isspace(*p))
b = buf; p++;
while(*p) sz = 0;
{ b = buf;
if(!isdigit(*p))
return false;
if(sz > 3) while (*p) {
return false; if (!isdigit(*p))
return false;
*b++ = *p++; if (sz > 3)
sz++; return false;
}
*b = '\0'; *b++ = *p++;
sz++;
}
prefix(atoi(buf)); *b = '\0';
return true; prefix(atoi(buf));
return true;
} }
address::operator std::string() const address::operator std::string() const
{ {
return to_string(); return to_string();
} }
struct in6_addr& address::addr() struct in6_addr& address::addr()
{ {
return _addr; return _addr;
} }
const struct in6_addr& address::const_addr() const const struct in6_addr& address::const_addr() const
{ {
return _addr; return _addr;
} }
struct in6_addr& address::mask() struct in6_addr& address::mask()
{ {
return _mask; return _mask;
} }
bool address::is_multicast() const bool address::is_multicast() const
{ {
return _addr.s6_addr[0] == 0xff; return _addr.s6_addr[0] == 0xff;
} }
bool address::is_unicast() const bool address::is_unicast() const
{ {
return _addr.s6_addr[0] != 0xff; return _addr.s6_addr[0] != 0xff;
} }
__NDPPD_NS_END __NDPPD_NS_END

View File

@ -29,41 +29,43 @@ class iface;
class address class address
{ {
private: private:
struct in6_addr _addr, _mask; struct in6_addr _addr, _mask;
public: public:
address(); address();
address(const address& addr); address(const address& addr);
address(const std::string& str); address(const std::string& str);
address(const char *str); address(const char *str);
address(const in6_addr& addr); address(const in6_addr& addr);
address(const in6_addr& addr, const in6_addr& mask); address(const in6_addr& addr, const in6_addr& mask);
address(const in6_addr& addr, int prefix); address(const in6_addr& addr, int prefix);
struct in6_addr& addr(); struct in6_addr& addr();
const struct in6_addr& const_addr() const; const struct in6_addr& const_addr() const;
struct in6_addr& mask(); struct in6_addr& mask();
// Compare _a/_m against a._a. // Compare _a/_m against a._a.
bool operator==(const address& addr) const; bool operator==(const address& addr) const;
bool operator!=(const address& addr) const; bool operator!=(const address& addr) const;
const std::string to_string() const; void reset();
bool parse_string(const std::string& str); const std::string to_string() const;
int prefix() const; bool parse_string(const std::string& str);
void prefix(int n); int prefix() const;
bool is_unicast() const; void prefix(int n);
bool is_multicast() const; bool is_unicast() const;
operator std::string() const; bool is_multicast() const;
operator std::string() const;
}; };

View File

@ -24,131 +24,126 @@ __NDPPD_NS_BEGIN
void conf::error_printf(cfg_t *cfg, const char *fmt, va_list ap) void conf::error_printf(cfg_t *cfg, const char *fmt, va_list ap)
{ {
char buf[256]; char buf[256];
if(vsnprintf(buf, sizeof(buf), fmt, ap) <= 0) if (vsnprintf(buf, sizeof(buf), fmt, ap) <= 0)
return; return;
ERR("[Config] %s", buf); ERR("[Config] %s", buf);
} }
int conf::validate_rule(cfg_t *cfg, cfg_opt_t *opt) int conf::validate_rule(cfg_t *cfg, cfg_opt_t *opt)
{ {
struct in6_addr addr, mask; struct in6_addr addr, mask;
cfg_t *rule_cfg = cfg_opt_getnsec(opt, cfg_opt_size(opt) - 1); cfg_t *rule_cfg = cfg_opt_getnsec(opt, cfg_opt_size(opt) - 1);
if(!rule_cfg) if (!rule_cfg)
return -1; return -1;
// TODO: Maybe we should validate IP here? // TODO: Maybe we should validate IP here?
return 0; return 0;
} }
bool conf::setup(cfg_t *cfg) bool conf::setup(cfg_t *cfg)
{ {
int i; int i;
for(i = 0; i < cfg_size(cfg, "proxy"); i++) for (i = 0; i < cfg_size(cfg, "proxy"); i++) {
{ cfg_t *proxy_cfg = cfg_getnsec(cfg, "proxy", i);
cfg_t *proxy_cfg = cfg_getnsec(cfg, "proxy", i);
if(proxy_cfg) if (proxy_cfg) {
{
cfg_t *rule_cfg;
int i2;
strong_ptr<proxy> pr = proxy::open(cfg_title(proxy_cfg));
if(pr.is_null())
continue;
pr->router(cfg_getbool(proxy_cfg, "router"));
pr->ttl(cfg_getint(proxy_cfg, "ttl"));
pr->timeout(cfg_getint(proxy_cfg, "timeout"));
for(i2 = 0; i2 < cfg_size(proxy_cfg, "rule"); i2++)
{
cfg_t *rule_cfg; cfg_t *rule_cfg;
int i2;
if(!(rule_cfg = cfg_getnsec(proxy_cfg, "rule", i2))) std::shared_ptr<proxy> pr = proxy::open(cfg_title(proxy_cfg));
continue;
address addr(cfg_title(rule_cfg)); if (!pr)
continue;
std::string ifname(cfg_getstr(rule_cfg, "iface")); pr->router(cfg_getbool(proxy_cfg, "router"));
if(ifname.empty()) pr->ttl(cfg_getint(proxy_cfg, "ttl"));
{
if(addr.prefix() <= 120)
NCE("Static rule prefix /%d <= 120 - is this what you want?", addr.prefix());
pr->add_rule(addr); pr->timeout(cfg_getint(proxy_cfg, "timeout"));
for (i2 = 0; i2 < cfg_size(proxy_cfg, "rule"); i2++) {
cfg_t *rule_cfg;
if (!(rule_cfg = cfg_getnsec(proxy_cfg, "rule", i2)))
continue;
address addr(cfg_title(rule_cfg));
std::string ifname(cfg_getstr(rule_cfg, "iface"));
if (ifname.empty()) {
if (addr.prefix() <= 120)
NCE("Static rule prefix /%d <= 120 - is this what you want?", addr.prefix());
pr->add_rule(addr);
}
else
{
pr->add_rule(addr, iface::open_ifd(ifname));
}
} }
else }
{ }
pr->add_rule(addr, iface::open_ifd(ifname));
}
}
}
}
return 0; return 0;
} }
bool conf::load(const std::string& path) bool conf::load(const std::string& path)
{ {
cfg_t *cfg; cfg_t *cfg;
int i, sz; int i, sz;
#define _S (char *) #define _S (char *)
static cfg_opt_t rule_opts[] = static cfg_opt_t rule_opts[] =
{ {
CFG_STR (_S "iface", _S "", CFGF_NONE), CFG_STR (_S "iface", _S "", CFGF_NONE),
CFG_END () CFG_END ()
}; };
static cfg_opt_t proxy_opts[] = static cfg_opt_t proxy_opts[] =
{ {
CFG_SEC (_S "rule", rule_opts, CFGF_MULTI | CFGF_TITLE), CFG_SEC (_S "rule", rule_opts, CFGF_MULTI | CFGF_TITLE),
CFG_BOOL (_S "router", cfg_true, CFGF_NONE), CFG_BOOL (_S "router", cfg_true, CFGF_NONE),
CFG_INT (_S "ttl", 30000, CFGF_NONE), CFG_INT (_S "ttl", 30000, CFGF_NONE),
CFG_INT (_S "timeout", 500, CFGF_NONE), CFG_INT (_S "timeout", 500, CFGF_NONE),
CFG_END () CFG_END ()
}; };
static cfg_opt_t opts[] = static cfg_opt_t opts[] =
{ {
CFG_SEC (_S "proxy", proxy_opts, CFGF_MULTI | CFGF_TITLE), CFG_SEC (_S "proxy", proxy_opts, CFGF_MULTI | CFGF_TITLE),
CFG_FUNC (_S "include", &cfg_include), CFG_FUNC (_S "include", &cfg_include),
CFG_END() CFG_END()
}; };
cfg = cfg_init(opts, CFGF_NOCASE); cfg = cfg_init(opts, CFGF_NOCASE);
cfg_set_error_function(cfg, &error_printf); cfg_set_error_function(cfg, &error_printf);
cfg_set_validate_func(cfg, "proxy|rule", &validate_rule); cfg_set_validate_func(cfg, "proxy|rule", &validate_rule);
switch(cfg_parse(cfg, path.c_str())) switch (cfg_parse(cfg, path.c_str())) {
{ case CFG_SUCCESS:
case CFG_SUCCESS: break;
break;
default: default:
ERR("Failed to load configuration file '%s'", path.c_str()); ERR("Failed to load configuration file '%s'", path.c_str());
return false; return false;
} }
setup(cfg); setup(cfg);
cfg_free(cfg); cfg_free(cfg);
return true; return true;
} }
__NDPPD_NS_END __NDPPD_NS_END

View File

@ -30,11 +30,11 @@ __NDPPD_NS_BEGIN
class conf class conf
{ {
private: private:
static bool setup(::cfg_t *cfg); static bool setup(::cfg_t *cfg);
static void error_printf(::cfg_t *cfg, const char *fmt, va_list ap); static void error_printf(::cfg_t *cfg, const char *fmt, va_list ap);
static int validate_rule(::cfg_t *cfg, ::cfg_opt_t *opt); static int validate_rule(::cfg_t *cfg, ::cfg_opt_t *opt);
public: public:
static bool load(const std::string& path); static bool load(const std::string& path);
}; };
__NDPPD_NS_END __NDPPD_NS_END

View File

@ -42,583 +42,560 @@
__NDPPD_NS_BEGIN __NDPPD_NS_BEGIN
std::map<std::string, strong_ptr<iface> > iface::_map; std::map<std::string, std::shared_ptr<iface> > iface::_map;
std::vector<struct pollfd> iface::_pollfds; std::vector<struct pollfd> iface::_pollfds;
iface::iface() : iface::iface() :
_ifd(-1), _pfd(-1) _ifd(-1), _pfd(-1)
{ {
} }
iface::~iface() iface::~iface()
{ {
DBG("iface::~iface()"); DBG("iface::~iface()");
if(_ifd >= 0) if (_ifd >= 0)
close(_ifd); close(_ifd);
if(_pfd >= 0) if (_pfd >= 0) {
{ allmulti(_prev_allmulti);
allmulti(_prev_allmulti); close(_pfd);
close(_pfd); }
}
} }
strong_ptr<iface> iface::open_pfd(const std::string& name) std::shared_ptr<iface> iface::open_pfd(const std::string& name)
{ {
int fd; int fd;
std::map<std::string, strong_ptr<iface> >::iterator it = _map.find(name); std::map<std::string, std::shared_ptr<iface> >::iterator it = _map.find(name);
strong_ptr<iface> ifa; std::shared_ptr<iface> ifa;
if(it != _map.end()) if (it != _map.end()) {
{ if (it->second->_pfd >= 0)
if(it->second->_pfd >= 0) return it->second;
return it->second;
ifa = it->second; ifa = it->second;
} } else {
else // We need an _ifs, so let's set one up.
{ ifa = open_ifd(name);
// We need an _ifs, so let's set one up. }
ifa = open_ifd(name);
}
if(ifa.is_null()) if (!ifa)
return strong_ptr<iface>(); return std::shared_ptr<iface>();
// Create a socket.
// Create a socket. if ((fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IPV6))) < 0) {
ERR("Unable to create socket");
return std::shared_ptr<iface>();
}
if((fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IPV6))) < 0) // Bind to the specified interface.
{
ERR("Unable to create socket");
return strong_ptr<iface>();
}
// Bind to the specified interface. struct sockaddr_ll lladdr;
struct sockaddr_ll lladdr; memset(&lladdr, 0, sizeof(struct sockaddr_ll));
lladdr.sll_family = AF_PACKET;
lladdr.sll_protocol = htons(ETH_P_IPV6);
memset(&lladdr, 0, sizeof(struct sockaddr_ll)); if (!(lladdr.sll_ifindex = if_nametoindex(name.c_str()))) {
lladdr.sll_family = AF_PACKET; close(fd);
lladdr.sll_protocol = htons(ETH_P_IPV6); ERR("Failed to bind to interface '%s'", name.c_str());
return std::shared_ptr<iface>();
}
if(!(lladdr.sll_ifindex = if_nametoindex(name.c_str()))) if (bind(fd, (struct sockaddr *)&lladdr, sizeof(struct sockaddr_ll)) < 0) {
{ close(fd);
close(fd); ERR("Failed to bind to interface '%s'", name.c_str());
ERR("Failed to bind to interface '%s'", name.c_str()); return std::shared_ptr<iface>();
return strong_ptr<iface>(); }
}
if(bind(fd, (struct sockaddr *)&lladdr, sizeof(struct sockaddr_ll)) < 0) // Switch to non-blocking mode.
{
close(fd);
ERR("Failed to bind to interface '%s'", name.c_str());
return strong_ptr<iface>();
}
// Switch to non-blocking mode. int on = 1;
int on = 1; if (ioctl(fd, FIONBIO, (char *)&on) < 0) {
close(fd);
ERR("Failed to switch to non-blocking on interface '%s'", name.c_str());
return std::shared_ptr<iface>();
}
if(ioctl(fd, FIONBIO, (char *)&on) < 0) // Set up filter.
{
close(fd);
ERR("Failed to switch to non-blocking on interface '%s'", name.c_str());
return strong_ptr<iface>();
}
// Set up filter. struct sock_fprog fprog;
struct sock_fprog fprog; static const struct sock_filter filter[] =
{
// Load the ether_type.
BPF_STMT(BPF_LD | BPF_H | BPF_ABS,
offsetof(struct ether_header, ether_type)),
// Bail if it's *not* ETHERTYPE_IPV6.
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IPV6, 0, 5),
// Load the next header type.
BPF_STMT(BPF_LD | BPF_B | BPF_ABS,
sizeof(struct ether_header) + offsetof(struct ip6_hdr, ip6_nxt)),
// Bail if it's *not* IPPROTO_ICMPV6.
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
// Load the ICMPv6 type.
BPF_STMT(BPF_LD | BPF_B | BPF_ABS,
sizeof(struct ether_header) + sizeof(ip6_hdr) + offsetof(struct icmp6_hdr, icmp6_type)),
// Bail if it's *not* ND_NEIGHBOR_SOLICIT.
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_NEIGHBOR_SOLICIT, 0, 1),
// Keep packet.
BPF_STMT(BPF_RET | BPF_K, -1),
// Drop packet.
BPF_STMT(BPF_RET | BPF_K, 0)
};
static const struct sock_filter filter[] = fprog.filter = (struct sock_filter *)filter;
{ fprog.len = 8;
// Load the ether_type.
BPF_STMT(BPF_LD | BPF_H | BPF_ABS,
offsetof(struct ether_header, ether_type)),
// Bail if it's *not* ETHERTYPE_IPV6.
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ETHERTYPE_IPV6, 0, 5),
// Load the next header type.
BPF_STMT(BPF_LD | BPF_B | BPF_ABS,
sizeof(struct ether_header) + offsetof(struct ip6_hdr, ip6_nxt)),
// Bail if it's *not* IPPROTO_ICMPV6.
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
// Load the ICMPv6 type.
BPF_STMT(BPF_LD | BPF_B | BPF_ABS,
sizeof(struct ether_header) + sizeof(ip6_hdr) + offsetof(struct icmp6_hdr, icmp6_type)),
// Bail if it's *not* ND_NEIGHBOR_SOLICIT.
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, ND_NEIGHBOR_SOLICIT, 0, 1),
// Keep packet.
BPF_STMT(BPF_RET | BPF_K, -1),
// Drop packet.
BPF_STMT(BPF_RET | BPF_K, 0)
};
fprog.filter = (struct sock_filter *)filter; if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0) {
fprog.len = 8; ERR("Failed to set filter");
return std::shared_ptr<iface>();
}
if(setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0) // Set up an instance of 'iface'.
{
ERR("Failed to set filter");
return strong_ptr<iface>();
}
// Set up an instance of 'iface'. ifa->_pfd = fd;
ifa->_pfd = fd; fixup_pollfds();
fixup_pollfds(); return ifa;
return ifa;
} }
strong_ptr<iface> iface::open_ifd(const std::string& name) std::shared_ptr<iface> iface::open_ifd(const std::string& name)
{ {
int fd; int fd;
std::map<std::string, strong_ptr<iface> >::iterator it = _map.find(name); std::map<std::string, std::shared_ptr<iface> >::iterator it = _map.find(name);
if((it != _map.end()) && it->second->_ifd) if ((it != _map.end()) && it->second->_ifd)
return it->second; return it->second;
// Create a socket. // Create a socket.
if((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
{ ERR("Unable to create socket");
ERR("Unable to create socket"); return std::shared_ptr<iface>();
return strong_ptr<iface>(); }
}
// Bind to the specified interface. // Bind to the specified interface.
struct ifreq ifr; struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, name.c_str(), IFNAMSIZ - 1); strncpy(ifr.ifr_name, name.c_str(), IFNAMSIZ - 1);
ifr.ifr_name[IFNAMSIZ - 1] = '\0'; ifr.ifr_name[IFNAMSIZ - 1] = '\0';
if(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) {
{ close(fd);
close(fd); ERR("Failed to bind to interface '%s'", name.c_str());
ERR("Failed to bind to interface '%s'", name.c_str()); return std::shared_ptr<iface>();
return strong_ptr<iface>(); }
}
// Detect the link-layer address. // Detect the link-layer address.
memset(&ifr, 0, sizeof(ifr)); memset(&ifr, 0, sizeof(ifr));
strncpy(ifr.ifr_name, name.c_str(), IFNAMSIZ - 1); strncpy(ifr.ifr_name, name.c_str(), IFNAMSIZ - 1);
ifr.ifr_name[IFNAMSIZ - 1] = '\0'; ifr.ifr_name[IFNAMSIZ - 1] = '\0';
if(ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
{ close(fd);
close(fd); ERR("Failed to detect link-layer address for interface '%s'", name.c_str());
ERR("Failed to detect link-layer address for interface '%s'", name.c_str()); return std::shared_ptr<iface>();
return strong_ptr<iface>(); }
}
DBG("fd=%d, hwaddr=%s", fd, ether_ntoa((const struct ether_addr *)&ifr.ifr_hwaddr.sa_data)); DBG("fd=%d, hwaddr=%s", fd, ether_ntoa((const struct ether_addr *)&ifr.ifr_hwaddr.sa_data));
// Set max hops. // Set max hops.
int hops = 255; int hops = 255;
if(setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)) < 0) if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)) < 0) {
{ close(fd);
close(fd); ERR("iface::open_ifd() failed IPV6_MULTICAST_HOPS");
ERR("iface::open_ifd() failed IPV6_MULTICAST_HOPS"); return std::shared_ptr<iface>();
return strong_ptr<iface>(); }
}
if(setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, sizeof(hops)) < 0) if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, sizeof(hops)) < 0) {
{ close(fd);
close(fd); ERR("iface::open_ifd() failed IPV6_UNICAST_HOPS");
ERR("iface::open_ifd() failed IPV6_UNICAST_HOPS"); return std::shared_ptr<iface>();
return strong_ptr<iface>(); }
}
// Switch to non-blocking mode. // Switch to non-blocking mode.
int on = 1; int on = 1;
if(ioctl(fd, FIONBIO, (char *)&on) < 0) if (ioctl(fd, FIONBIO, (char *)&on) < 0) {
{ close(fd);
close(fd); ERR("Failed to switch to non-blocking on interface '%s'", name.c_str());
ERR("Failed to switch to non-blocking on interface '%s'", name.c_str()); return std::shared_ptr<iface>();
return strong_ptr<iface>(); }
}
// Set up filter. // Set up filter.
struct icmp6_filter filter; struct icmp6_filter filter;
ICMP6_FILTER_SETBLOCKALL(&filter); ICMP6_FILTER_SETBLOCKALL(&filter);
ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filter); ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filter);
if(setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) < 0) if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) < 0) {
{ ERR("Failed to set filter");
ERR("Failed to set filter"); return std::shared_ptr<iface>();
return strong_ptr<iface>(); }
}
// Set up an instance of 'iface'. // Set up an instance of 'iface'.
strong_ptr<iface> ifa; std::shared_ptr<iface> ifa;
if(it == _map.end()) if (it == _map.end()) {
{ ifa.reset(new iface());
ifa = new iface(); ifa->_name = name;
ifa->_ptr = ifa;
ifa->_name = name; _map[name] = ifa;
ifa->_ptr = ifa; } else {
ifa = it->second;
}
_map[name] = ifa; ifa->_ifd = fd;
}
else
{
ifa = it->second;
}
ifa->_ifd = fd; memcpy(&ifa->hwaddr, ifr.ifr_hwaddr.sa_data, sizeof(struct ether_addr));
memcpy(&ifa->hwaddr, ifr.ifr_hwaddr.sa_data, sizeof(struct ether_addr)); fixup_pollfds();
fixup_pollfds(); return ifa;
return ifa;
} }
ssize_t iface::read(int fd, struct sockaddr *saddr, uint8_t *msg, size_t size) ssize_t iface::read(int fd, struct sockaddr *saddr, uint8_t *msg, size_t size)
{ {
struct msghdr mhdr; struct msghdr mhdr;
struct iovec iov; struct iovec iov;
char cbuf[256]; char cbuf[256];
int len; int len;
if(!msg || (size < 0)) if (!msg || (size < 0))
return -1; return -1;
iov.iov_len = size; iov.iov_len = size;
iov.iov_base = (caddr_t)msg; iov.iov_base = (caddr_t)msg;
memset(&mhdr, 0, sizeof(mhdr)); memset(&mhdr, 0, sizeof(mhdr));
mhdr.msg_name = (caddr_t)saddr; mhdr.msg_name = (caddr_t)saddr;
mhdr.msg_namelen = sizeof(struct sockaddr); mhdr.msg_namelen = sizeof(struct sockaddr);
mhdr.msg_iov = &iov; mhdr.msg_iov = &iov;
mhdr.msg_iovlen = 1; mhdr.msg_iovlen = 1;
if((len = recvmsg(fd, &mhdr, 0)) < 0) if ((len = recvmsg(fd, &mhdr, 0)) < 0)
return -1; return -1;
if(len < sizeof(struct icmp6_hdr)) if (len < sizeof(struct icmp6_hdr))
return -1; return -1;
DBG("iface::read() len=%d", len); DBG("iface::read() len=%d", len);
return len; return len;
} }
ssize_t iface::write(int fd, const address& daddr, const uint8_t *msg, size_t size) ssize_t iface::write(int fd, const address& daddr, const uint8_t *msg, size_t size)
{ {
struct sockaddr_in6 daddr_tmp; struct sockaddr_in6 daddr_tmp;
struct msghdr mhdr; struct msghdr mhdr;
struct iovec iov; struct iovec iov;
memset(&daddr_tmp, 0, sizeof(struct sockaddr_in6)); memset(&daddr_tmp, 0, sizeof(struct sockaddr_in6));
daddr_tmp.sin6_family = AF_INET6; daddr_tmp.sin6_family = AF_INET6;
daddr_tmp.sin6_port = htons(IPPROTO_ICMPV6); // Needed? daddr_tmp.sin6_port = htons(IPPROTO_ICMPV6); // Needed?
memcpy(&daddr_tmp.sin6_addr, &daddr.const_addr(), sizeof(struct in6_addr)); memcpy(&daddr_tmp.sin6_addr, &daddr.const_addr(), sizeof(struct in6_addr));
iov.iov_len = size; iov.iov_len = size;
iov.iov_base = (caddr_t)msg; iov.iov_base = (caddr_t)msg;
memset(&mhdr, 0, sizeof(mhdr)); memset(&mhdr, 0, sizeof(mhdr));
mhdr.msg_name = (caddr_t)&daddr_tmp; mhdr.msg_name = (caddr_t)&daddr_tmp;
mhdr.msg_namelen = sizeof(sockaddr_in6); mhdr.msg_namelen = sizeof(sockaddr_in6);
mhdr.msg_iov = &iov; mhdr.msg_iov = &iov;
mhdr.msg_iovlen = 1; mhdr.msg_iovlen = 1;
DBG("iface::write() daddr=%s, len=%d", daddr.to_string().c_str(), size); DBG("iface::write() daddr=%s, len=%d", daddr.to_string().c_str(), size);
int len; int len;
if((len = sendmsg(fd, &mhdr, 0)) < 0) if ((len = sendmsg(fd, &mhdr, 0)) < 0)
return -1; return -1;
return len; return len;
} }
ssize_t iface::read_solicit(address& saddr, address& daddr, address& taddr) ssize_t iface::read_solicit(address& saddr, address& daddr, address& taddr)
{ {
struct sockaddr_ll t_saddr; struct sockaddr_ll t_saddr;
uint8_t msg[256]; uint8_t msg[256];
ssize_t len; ssize_t len;
if((len = read(_pfd, (struct sockaddr *)&t_saddr, msg, sizeof(msg))) < 0) if ((len = read(_pfd, (struct sockaddr *)&t_saddr, msg, sizeof(msg))) < 0)
return -1; return -1;
struct ip6_hdr *ip6h = struct ip6_hdr *ip6h =
(struct ip6_hdr *)(msg + ETH_HLEN); (struct ip6_hdr *)(msg + ETH_HLEN);
struct icmp6_hdr *icmph = struct icmp6_hdr *icmph =
(struct icmp6_hdr *)(msg + ETH_HLEN + sizeof( struct ip6_hdr)); (struct icmp6_hdr *)(msg + ETH_HLEN + sizeof( struct ip6_hdr));
struct nd_neighbor_solicit *ns = struct nd_neighbor_solicit *ns =
(struct nd_neighbor_solicit *)(msg + ETH_HLEN + sizeof( struct ip6_hdr)); (struct nd_neighbor_solicit *)(msg + ETH_HLEN + sizeof( struct ip6_hdr));
taddr = ns->nd_ns_target; taddr = ns->nd_ns_target;
daddr = ip6h->ip6_dst; daddr = ip6h->ip6_dst;
saddr = ip6h->ip6_src; saddr = ip6h->ip6_src;
DBG("iface::read_solicit() saddr=%s, daddr=%s, taddr=%s, len=%d", DBG("iface::read_solicit() saddr=%s, daddr=%s, taddr=%s, len=%d",
saddr.to_string().c_str(), daddr.to_string().c_str(), saddr.to_string().c_str(), daddr.to_string().c_str(),
taddr.to_string().c_str(), len); taddr.to_string().c_str(), len);
return len; return len;
} }
ssize_t iface::write_solicit(const address& taddr) ssize_t iface::write_solicit(const address& taddr)
{ {
char buf[128]; char buf[128];
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
struct nd_neighbor_solicit *ns = struct nd_neighbor_solicit *ns =
(struct nd_neighbor_solicit *)&buf[0]; (struct nd_neighbor_solicit *)&buf[0];
struct nd_opt_hdr *opt = struct nd_opt_hdr *opt =
(struct nd_opt_hdr *)&buf[sizeof(struct nd_neighbor_solicit)]; (struct nd_opt_hdr *)&buf[sizeof(struct nd_neighbor_solicit)];
opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR; opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
opt->nd_opt_len = 1; opt->nd_opt_len = 1;
ns->nd_ns_type = ND_NEIGHBOR_SOLICIT; ns->nd_ns_type = ND_NEIGHBOR_SOLICIT;
memcpy(&ns->nd_ns_target, &taddr.const_addr(), sizeof(struct in6_addr)); memcpy(&ns->nd_ns_target, &taddr.const_addr(), sizeof(struct in6_addr));
memcpy(buf + sizeof(struct nd_neighbor_solicit) + sizeof(struct nd_opt_hdr), &hwaddr, 6); memcpy(buf + sizeof(struct nd_neighbor_solicit) + sizeof(struct nd_opt_hdr), &hwaddr, 6);
// FIXME: Alright, I'm lazy. // FIXME: Alright, I'm lazy.
static address multicast("ff02::1:ff00:0000"); static address multicast("ff02::1:ff00:0000");
address daddr; address daddr;
daddr = multicast; daddr = multicast;
daddr.addr().s6_addr[13] = taddr.const_addr().s6_addr[13]; daddr.addr().s6_addr[13] = taddr.const_addr().s6_addr[13];
daddr.addr().s6_addr[14] = taddr.const_addr().s6_addr[14]; daddr.addr().s6_addr[14] = taddr.const_addr().s6_addr[14];
daddr.addr().s6_addr[15] = taddr.const_addr().s6_addr[15]; daddr.addr().s6_addr[15] = taddr.const_addr().s6_addr[15];
DBG("iface::write_solicit() taddr=%s, daddr=%s", DBG("iface::write_solicit() taddr=%s, daddr=%s",
taddr.to_string().c_str(), daddr.to_string().c_str()); taddr.to_string().c_str(), daddr.to_string().c_str());
return write(_ifd, daddr, (uint8_t *)buf, sizeof(struct nd_neighbor_solicit) + sizeof(struct nd_opt_hdr) + 6); return write(_ifd, daddr, (uint8_t *)buf, sizeof(struct nd_neighbor_solicit) + sizeof(struct nd_opt_hdr) + 6);
} }
ssize_t iface::write_advert(const address& daddr, const address& taddr, bool router) ssize_t iface::write_advert(const address& daddr, const address& taddr, bool router)
{ {
char buf[128]; char buf[128];
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
struct nd_neighbor_advert *na = struct nd_neighbor_advert *na =
(struct nd_neighbor_advert *)&buf[0]; (struct nd_neighbor_advert *)&buf[0];
struct nd_opt_hdr *opt = struct nd_opt_hdr *opt =
(struct nd_opt_hdr *)&buf[sizeof(struct nd_neighbor_advert)]; (struct nd_opt_hdr *)&buf[sizeof(struct nd_neighbor_advert)];
opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
opt->nd_opt_len = 1; opt->nd_opt_len = 1;
na->nd_na_type = ND_NEIGHBOR_ADVERT; na->nd_na_type = ND_NEIGHBOR_ADVERT;
na->nd_na_flags_reserved = ND_NA_FLAG_SOLICITED | (router ? ND_NA_FLAG_ROUTER : 0); na->nd_na_flags_reserved = ND_NA_FLAG_SOLICITED | (router ? ND_NA_FLAG_ROUTER : 0);
memcpy(&na->nd_na_target, &taddr.const_addr(), sizeof(struct in6_addr)); memcpy(&na->nd_na_target, &taddr.const_addr(), sizeof(struct in6_addr));
memcpy(buf + sizeof(struct nd_neighbor_advert) + sizeof(struct nd_opt_hdr), &hwaddr, 6); memcpy(buf + sizeof(struct nd_neighbor_advert) + sizeof(struct nd_opt_hdr), &hwaddr, 6);
DBG("iface::write_advert() daddr=%s, taddr=%s", DBG("iface::write_advert() daddr=%s, taddr=%s",
daddr.to_string().c_str(), taddr.to_string().c_str()); daddr.to_string().c_str(), taddr.to_string().c_str());
return write(_ifd, daddr, (uint8_t *)buf, sizeof(struct nd_neighbor_advert) + return write(_ifd, daddr, (uint8_t *)buf, sizeof(struct nd_neighbor_advert) +
sizeof(struct nd_opt_hdr) + 6); sizeof(struct nd_opt_hdr) + 6);
} }
ssize_t iface::read_advert(address& saddr, address& taddr) ssize_t iface::read_advert(address& saddr, address& taddr)
{ {
struct sockaddr_in6 t_saddr; struct sockaddr_in6 t_saddr;
uint8_t msg[256]; uint8_t msg[256];
ssize_t len; ssize_t len;
if((len = read(_ifd, (struct sockaddr *)&t_saddr, msg, sizeof(msg))) < 0) if ((len = read(_ifd, (struct sockaddr *)&t_saddr, msg, sizeof(msg))) < 0)
return -1; return -1;
saddr = t_saddr.sin6_addr; saddr = t_saddr.sin6_addr;
if(((struct icmp6_hdr *)msg)->icmp6_type != ND_NEIGHBOR_ADVERT) if (((struct icmp6_hdr *)msg)->icmp6_type != ND_NEIGHBOR_ADVERT)
return -1; return -1;
taddr = ((struct nd_neighbor_solicit *)msg)->nd_ns_target; taddr = ((struct nd_neighbor_solicit *)msg)->nd_ns_target;
DBG("iface::read_advert() saddr=%s, taddr=%s, len=%d", DBG("iface::read_advert() saddr=%s, taddr=%s, len=%d",
saddr.to_string().c_str(), taddr.to_string().c_str(), len); saddr.to_string().c_str(), taddr.to_string().c_str(), len);
return len; return len;
} }
void iface::fixup_pollfds() void iface::fixup_pollfds()
{ {
_pollfds.resize(_map.size() * 2); _pollfds.resize(_map.size() * 2);
int i = 0; int i = 0;
DBG("iface::fixup_pollfds() _map.size()=%d", _map.size()); DBG("iface::fixup_pollfds() _map.size()=%d", _map.size());
for(std::map<std::string, strong_ptr<iface> >::iterator it = _map.begin(); for (std::map<std::string, std::shared_ptr<iface> >::iterator it = _map.begin();
it != _map.end(); it++) it != _map.end(); it++) {
{ _pollfds[i].fd = it->second->_ifd;
_pollfds[i].fd = it->second->_ifd; _pollfds[i].events = POLLIN;
_pollfds[i].events = POLLIN; _pollfds[i].revents = 0;
_pollfds[i].revents = 0; i++;
i++;
_pollfds[i].fd = it->second->_pfd; _pollfds[i].fd = it->second->_pfd;
_pollfds[i].events = POLLIN; _pollfds[i].events = POLLIN;
_pollfds[i].revents = 0; _pollfds[i].revents = 0;
i++; i++;
} }
} }
void iface::remove_session(const strong_ptr<session>& se) void iface::remove_session(const std::shared_ptr<session>& se)
{ {
_sessions.remove(se); for (std::list<std::weak_ptr<session> >::iterator it = _sessions.begin();
it != _sessions.end(); it++) {
if (it->lock() == se) {
_sessions.erase(it);
break;
}
}
} }
void iface::add_session(const strong_ptr<session>& se) void iface::add_session(const std::shared_ptr<session>& se)
{ {
_sessions.push_back(se); _sessions.push_back(se);
} }
int iface::poll_all() int iface::poll_all()
{ {
if(_pollfds.size() == 0) if (_pollfds.size() == 0) {
{ ::sleep(1);
::sleep(1); return 0;
return 0; }
}
assert(_pollfds.size() == _map.size() * 2); assert(_pollfds.size() == _map.size() * 2);
int len; int len;
if((len = ::poll(&_pollfds[0], _pollfds.size(), 50)) < 0) if ((len = ::poll(&_pollfds[0], _pollfds.size(), 50)) < 0)
return -1; return -1;
if(len == 0) if (len == 0)
return 0; return 0;
std::map<std::string, strong_ptr<iface> >::iterator i_it = _map.begin(); std::map<std::string, std::shared_ptr<iface> >::iterator i_it = _map.begin();
int i = 0; int i = 0;
for(std::vector<struct pollfd>::iterator f_it = _pollfds.begin(); for (std::vector<struct pollfd>::iterator f_it = _pollfds.begin();
f_it != _pollfds.end(); f_it++) f_it != _pollfds.end(); f_it++) {
{ assert(i_it != _map.end());
assert(i_it != _map.end());
if(i && !(i % 2)) if (i && !(i % 2))
i_it++; i_it++;
bool is_pfd = i++ % 2; bool is_pfd = i++ % 2;
if(!(f_it->revents & POLLIN)) if (!(f_it->revents & POLLIN))
continue;
strong_ptr<iface> ifa = i_it->second;
address saddr, daddr, taddr;
if(is_pfd)
{
if(ifa->read_solicit(saddr, daddr, taddr) < 0)
{
ERR("Failed to read from interface '%s'", ifa->_name.c_str());
continue;
}
if(!saddr.is_unicast() || !daddr.is_multicast())
continue; continue;
ifa->_pr->handle_solicit(saddr, daddr, taddr); std::shared_ptr<iface> ifa = i_it->second;
}
else
{
if(ifa->read_advert(saddr, taddr) < 0)
{
ERR("Failed to read from interface '%s'", ifa->_name.c_str());
continue;
}
for(std::list<weak_ptr<session> >::iterator s_it = ifa->_sessions.begin(); address saddr, daddr, taddr;
s_it != ifa->_sessions.end(); s_it++)
{ if (is_pfd) {
if(((*s_it)->taddr() == taddr) && ((*s_it)->status() == session::WAITING)) if (ifa->read_solicit(saddr, daddr, taddr) < 0) {
{ ERR("Failed to read from interface '%s'", ifa->_name.c_str());
(*s_it)->handle_advert(); continue;
break;
} }
}
}
}
return 0; if (!saddr.is_unicast() || !daddr.is_multicast())
continue;
ifa->_pr->handle_solicit(saddr, daddr, taddr);
} else {
if (ifa->read_advert(saddr, taddr) < 0) {
ERR("Failed to read from interface '%s'", ifa->_name.c_str());
continue;
}
for (std::list<std::weak_ptr<session> >::iterator s_it = ifa->_sessions.begin();
s_it != ifa->_sessions.end(); s_it++) {
const std::shared_ptr<session> sess = s_it->lock();
if ((sess->taddr() == taddr) && (sess->status() == session::WAITING)) {
sess->handle_advert();
break;
}
}
}
}
return 0;
} }
int iface::allmulti(int state) int iface::allmulti(int state)
{ {
struct ifreq ifr; struct ifreq ifr;
DBG("iface::allmulti() state=%d, _name=\"%s\"", DBG("iface::allmulti() state=%d, _name=\"%s\"",
state, _name.c_str()); state, _name.c_str());
state = !!state; state = !!state;
strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ); strncpy(ifr.ifr_name, _name.c_str(), IFNAMSIZ);
if(ioctl(_pfd, SIOCGIFFLAGS, &ifr) < 0) if (ioctl(_pfd, SIOCGIFFLAGS, &ifr) < 0)
return -1; return -1;
int old_state = !!(ifr.ifr_flags & IFF_ALLMULTI); int old_state = !!(ifr.ifr_flags & IFF_ALLMULTI);
if(state == old_state) if (state == old_state)
return old_state; return old_state;
if(state) if (state)
ifr.ifr_flags |= IFF_ALLMULTI; ifr.ifr_flags |= IFF_ALLMULTI;
else else
ifr.ifr_flags &= ~IFF_ALLMULTI; ifr.ifr_flags &= ~IFF_ALLMULTI;
if(ioctl(_pfd, SIOCSIFFLAGS, &ifr) < 0) if (ioctl(_pfd, SIOCSIFFLAGS, &ifr) < 0)
return -1; return -1;
return old_state; return old_state;
} }
const std::string& iface::name() const const std::string& iface::name() const
{ {
return _name; return _name;
} }
void iface::pr(const strong_ptr<proxy>& pr) void iface::pr(const std::shared_ptr<proxy>& pr)
{ {
_pr = pr; _pr = pr;
} }
const strong_ptr<proxy>& iface::pr() const const std::shared_ptr<proxy>& iface::pr() const
{ {
return _pr; return _pr;
} }
__NDPPD_NS_END __NDPPD_NS_END

View File

@ -34,85 +34,85 @@ class proxy;
class iface class iface
{ {
private: private:
// Weak pointer so this object can reference itself. // Weak pointer so this object can reference itself.
weak_ptr<iface> _ptr; std::weak_ptr<iface> _ptr;
static std::map<std::string, strong_ptr<iface> > _map; static std::map<std::string, std::shared_ptr<iface> > _map;
// An array of objects used with ::poll. // An array of objects used with ::poll.
static std::vector<struct pollfd> _pollfds; static std::vector<struct pollfd> _pollfds;
// Updates the array above. // Updates the array above.
static void fixup_pollfds(); static void fixup_pollfds();
// The "generic" ICMPv6 socket for reading/writing NB_NEIGHBOR_ADVERT // The "generic" ICMPv6 socket for reading/writing NB_NEIGHBOR_ADVERT
// messages as well as writing NB_NEIGHBOR_SOLICIT messages. // messages as well as writing NB_NEIGHBOR_SOLICIT messages.
int _ifd; int _ifd;
// This is the PF_PACKET socket we use in order to read // This is the PF_PACKET socket we use in order to read
// NB_NEIGHBOR_SOLICIT messages. // NB_NEIGHBOR_SOLICIT messages.
int _pfd; int _pfd;
// Previous state of ALLMULTI for the interface. // Previous state of ALLMULTI for the interface.
int _prev_allmulti; int _prev_allmulti;
// Name of this interface. // Name of this interface.
std::string _name; std::string _name;
// An array of sessions that are monitoring this interface for // An array of sessions that are monitoring this interface for
// ND_NEIGHBOR_ADVERT messages. // ND_NEIGHBOR_ADVERT messages.
std::list<weak_ptr<session> > _sessions; std::list<std::weak_ptr<session> > _sessions;
strong_ptr<proxy> _pr; std::shared_ptr<proxy> _pr;
// The link-layer address of this interface. // The link-layer address of this interface.
struct ether_addr hwaddr; struct ether_addr hwaddr;
// Turns on/off ALLMULTI for this interface - returns the previous state // Turns on/off ALLMULTI for this interface - returns the previous state
// or -1 if there was an error. // or -1 if there was an error.
int allmulti(int state); int allmulti(int state);
// Constructor. // Constructor.
iface(); iface();
public: public:
// Destructor. // Destructor.
~iface(); ~iface();
static strong_ptr<iface> open_ifd(const std::string& name); static std::shared_ptr<iface> open_ifd(const std::string& name);
static strong_ptr<iface> open_pfd(const std::string& name); static std::shared_ptr<iface> open_pfd(const std::string& name);
static int poll_all(); static int poll_all();
static ssize_t read(int fd, struct sockaddr *saddr, uint8_t *msg, size_t size); static ssize_t read(int fd, struct sockaddr *saddr, uint8_t *msg, size_t size);
static ssize_t write(int fd, const address& daddr, const uint8_t *msg, size_t size); static 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. // Writes a NB_NEIGHBOR_SOLICIT message to the _ifd socket.
ssize_t write_solicit(const address& taddr); ssize_t write_solicit(const address& taddr);
// Writes a NB_NEIGHBOR_ADVERT message to the _ifd socket; // Writes a NB_NEIGHBOR_ADVERT message to the _ifd socket;
ssize_t write_advert(const address& daddr, const address& taddr, bool router); ssize_t write_advert(const address& daddr, const address& taddr, bool router);
// Reads a NB_NEIGHBOR_SOLICIT message from the _pfd socket. // Reads a NB_NEIGHBOR_SOLICIT message from the _pfd socket.
ssize_t read_solicit(address& saddr, address& daddr, address& taddr); ssize_t read_solicit(address& saddr, address& daddr, address& taddr);
// Reads a NB_NEIGHBOR_ADVERT message from the _ifd socket; // Reads a NB_NEIGHBOR_ADVERT message from the _ifd socket;
ssize_t read_advert(address& saddr, address& taddr); ssize_t read_advert(address& saddr, address& taddr);
// Returns the name of the interface. // Returns the name of the interface.
const std::string& name() const; const std::string& name() const;
// Adds a session to be monitored for ND_NEIGHBOR_ADVERT messages. // Adds a session to be monitored for ND_NEIGHBOR_ADVERT messages.
void add_session(const strong_ptr<session>& se); void add_session(const std::shared_ptr<session>& se);
void remove_session(const strong_ptr<session>& se); void remove_session(const std::shared_ptr<session>& se);
void pr(const strong_ptr<proxy>& pr); void pr(const std::shared_ptr<proxy>& pr);
const strong_ptr<proxy>& pr() const; const std::shared_ptr<proxy>& pr() const;
}; };
__NDPPD_NS_END __NDPPD_NS_END

View File

@ -25,68 +25,66 @@ __NDPPD_NS_BEGIN
const char *log::_level_str[] = const char *log::_level_str[] =
{ {
"fatal", "fatal",
"alert", "alert",
"critical", "critical",
"error", "error",
"warning", "warning",
"notice", "notice",
"info", "info",
"debug" "debug"
}; };
bool log::_syslog = false; bool log::_syslog = false;
void log::puts(int level, const char *str) void log::puts(int level, const char *str)
{ {
const char *ls; const char *ls;
if((level < 0) || (level > LOG_DEBUG)) if ((level < 0) || (level > LOG_DEBUG))
ls = "unknown"; ls = "unknown";
else else
ls = _level_str[level]; ls = _level_str[level];
if(_syslog) if (_syslog)
::syslog(level, "(%s) %s", ls, str); ::syslog(level, "(%s) %s", ls, str);
else else
fprintf(stderr, "(% 8s) %s\n", ls, str); fprintf(stderr, "(% 8s) %s\n", ls, str);
} }
void log::printf(int level, const char *fmt, ...) void log::printf(int level, const char *fmt, ...)
{ {
char buf[256]; char buf[256];
va_list args; va_list args;
int ret; int ret;
va_start(args, fmt); va_start(args, fmt);
if(vsnprintf(buf, sizeof(buf), fmt, args) > 0) if (vsnprintf(buf, sizeof(buf), fmt, args) > 0) {
{ puts(level, buf);
puts(level, buf); }
}
va_end(args); va_end(args);
} }
void log::syslog(bool sl) void log::syslog(bool sl)
{ {
if(sl == _syslog) if (sl == _syslog)
return; return;
if(_syslog = sl) if (_syslog = sl) {
{
#ifdef DEBUG #ifdef DEBUG
setlogmask(LOG_UPTO(LOG_DEBUG)); setlogmask(LOG_UPTO(LOG_DEBUG));
openlog("ndppd", LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER); openlog("ndppd", LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
#else #else
setlogmask(LOG_UPTO(LOG_INFO)); setlogmask(LOG_UPTO(LOG_INFO));
openlog("ndppd", LOG_CONS, LOG_USER); openlog("ndppd", LOG_CONS, LOG_USER);
#endif #endif
} }
else else
{ {
closelog(); closelog();
} }
} }
__NDPPD_NS_END __NDPPD_NS_END

View File

@ -35,16 +35,16 @@ __NDPPD_NS_BEGIN
class log class log
{ {
private: private:
static const char *_level_str[]; static const char *_level_str[];
static bool _syslog; static bool _syslog;
public: public:
static void puts(int level, const char *str); static void puts(int level, const char *str);
static void printf(int level, const char *fmt, ...); static void printf(int level, const char *fmt, ...);
static void syslog(bool enable); static void syslog(bool enable);
}; };
__NDPPD_NS_END __NDPPD_NS_END

View File

@ -29,111 +29,105 @@ using namespace ndppd;
int daemonize() int daemonize()
{ {
pid_t pid = fork(); pid_t pid = fork();
if(pid < 0) if (pid < 0)
return -1; return -1;
if(pid > 0) if (pid > 0)
exit(0); exit(0);
pid_t sid = setsid(); pid_t sid = setsid();
if(sid < 0) if (sid < 0)
return -1; return -1;
close(STDIN_FILENO); close(STDIN_FILENO);
close(STDOUT_FILENO); close(STDOUT_FILENO);
close(STDERR_FILENO); close(STDERR_FILENO);
return 0; return 0;
} }
int main(int argc, char *argv[], char *env[]) int main(int argc, char *argv[], char *env[])
{ {
std::string config_path("/etc/ndppd.conf"); std::string config_path("/etc/ndppd.conf");
std::string pidfile; std::string pidfile;
bool daemon = false; bool daemon = false;
while(1) while (1) {
{ int c, opt;
int c, opt;
static struct option long_options[] = static struct option long_options[] =
{ {
{ "config", 1, 0, 'c' }, { "config", 1, 0, 'c' },
{ "daemon", 0, 0, 'd' }, { "daemon", 0, 0, 'd' },
{ 0, 0, 0, 0} { 0, 0, 0, 0}
}; };
c = getopt_long(argc, argv, "c:dp:", long_options, &opt); c = getopt_long(argc, argv, "c:dp:", long_options, &opt);
if(c == -1) if (c == -1)
break; break;
switch(c) switch (c) {
{ case 'c':
case 'c': config_path = optarg;
config_path = optarg; break;
break;
case 'd': case 'd':
daemon = true; daemon = true;
break; break;
case 'p': case 'p':
pidfile = optarg; pidfile = optarg;
break; break;
} }
} }
if(daemon) if (daemon) {
{ log::syslog(true);
log::syslog(true);
if(daemonize() < 0) if (daemonize() < 0) {
{ ERR("Failed to daemonize process");
ERR("Failed to daemonize process"); return 1;
return 1; }
} }
}
if(!pidfile.empty()) if (!pidfile.empty()) {
{ std::ofstream pf;
std::ofstream pf; pf.open(pidfile.c_str(), std::ios::out | std::ios::trunc);
pf.open(pidfile.c_str(), std::ios::out | std::ios::trunc); pf << getpid() << std::endl;
pf << getpid() << std::endl; pf.close();
pf.close(); }
}
NFO("ndppd (NDP Proxy Daemon) version " NDPPD_VERSION); NFO("ndppd (NDP Proxy Daemon) version " NDPPD_VERSION);
NFO("Using configuration file '%s'", config_path.c_str()); NFO("Using configuration file '%s'", config_path.c_str());
if(!conf::load(config_path)) if (!conf::load(config_path))
return -1; return -1;
struct timeval t1, t2; struct timeval t1, t2;
gettimeofday(&t1, 0); gettimeofday(&t1, 0);
while(iface::poll_all() >= 0) while (iface::poll_all() >= 0) {
{ int elapsed_time;
int elapsed_time; gettimeofday(&t2, 0);
gettimeofday(&t2, 0);
elapsed_time = elapsed_time =
((t2.tv_sec - t1.tv_sec) * 1000) + ((t2.tv_sec - t1.tv_sec) * 1000) +
((t2.tv_usec - t1.tv_usec) / 1000); ((t2.tv_usec - t1.tv_usec) / 1000);
t1.tv_sec = t2.tv_sec; t1.tv_sec = t2.tv_sec;
t1.tv_usec = t2.tv_usec; t1.tv_usec = t2.tv_usec;
session::update_all(elapsed_time); session::update_all(elapsed_time);
} }
ERR("iface::poll_all() failed"); ERR("iface::poll_all() failed");
return 0; return 0;
} }

View File

@ -17,6 +17,7 @@
#define __NDPPD_H #define __NDPPD_H
#include <netinet/ip6.h> #include <netinet/ip6.h>
#include <memory>
#define __NDPPD_NS_BEGIN namespace ndppd { #define __NDPPD_NS_BEGIN namespace ndppd {
#define __NDPPD_NS_END } #define __NDPPD_NS_END }
@ -26,7 +27,6 @@
#include <assert.h> #include <assert.h>
#include "log.h" #include "log.h"
#include "ptr.h"
#include "conf.h" #include "conf.h"
#include "address.h" #include "address.h"

View File

@ -27,151 +27,145 @@
__NDPPD_NS_BEGIN __NDPPD_NS_BEGIN
proxy::proxy() : proxy::proxy() :
_router(true), _ttl(30000), _timeout(500) _router(true), _ttl(30000), _timeout(500)
{ {
} }
strong_ptr<proxy> proxy::create(const strong_ptr<iface>& ifa) std::shared_ptr<proxy> proxy::create(const std::shared_ptr<iface>& ifa)
{ {
strong_ptr<proxy> pr(new proxy()); std::shared_ptr<proxy> pr(new proxy());
pr->_ptr = pr; pr->_ptr = pr;
pr->_ifa = ifa; pr->_ifa = ifa;
ifa->pr(pr); ifa->pr(pr);
DBG("proxy::create() if=%x", ifa->name().c_str()); DBG("proxy::create() if=%x", ifa->name().c_str());
return pr; return pr;
} }
strong_ptr<proxy> proxy::open(const std::string& ifname) std::shared_ptr<proxy> proxy::open(const std::string& ifname)
{ {
strong_ptr<iface> ifa = iface::open_pfd(ifname); std::shared_ptr<iface> ifa = iface::open_pfd(ifname);
if(ifa.is_null()) if (!ifa)
return strong_ptr<proxy>(); return std::shared_ptr<proxy>();
return create(ifa); return create(ifa);
} }
void proxy::handle_solicit(const address& saddr, const address& daddr, void proxy::handle_solicit(const address& saddr, const address& daddr,
const address& taddr) const address& taddr)
{ {
DBG("proxy::handle_solicit() saddr=%s, taddr=%s", DBG("proxy::handle_solicit() saddr=%s, taddr=%s",
saddr.to_string().c_str(), taddr.to_string().c_str()); saddr.to_string().c_str(), taddr.to_string().c_str());
// Let's check this proxy's list of sessions to see if we can // Let's check this proxy's list of sessions to see if we can
// find one with the same target address. // find one with the same target address.
for(std::list<strong_ptr<session> >::iterator sit = _sessions.begin(); for (std::list<std::shared_ptr<session> >::iterator sit = _sessions.begin();
sit != _sessions.end(); sit++) sit != _sessions.end(); sit++) {
{
if((*sit)->taddr() == taddr) if ((*sit)->taddr() == taddr) {
{ switch ((*sit)->status()) {
switch((*sit)->status()) case session::WAITING:
{ case session::INVALID:
case session::WAITING: break;
case session::INVALID:
break;
case session::VALID: case session::VALID:
(*sit)->send_advert(); (*sit)->send_advert();
} }
return;
}
}
// 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.
strong_ptr<session> se;
for(std::list<strong_ptr<rule> >::iterator it = _rules.begin();
it != _rules.end(); it++)
{
strong_ptr<rule> ru = *it;
DBG("comparing %s against %s",
ru->addr().to_string().c_str(), taddr.to_string().c_str());
if(ru->addr() == taddr)
{
if(se.is_null())
se = session::create(_ptr, saddr, daddr, taddr);
if(ru->ifa().is_null())
{
// 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->add_iface((*it)->ifa()); // 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.
}
if(se) std::shared_ptr<session> se;
{
_sessions.push_back(se); for (std::list<std::shared_ptr<rule> >::iterator it = _rules.begin();
se->send_solicit(); it != _rules.end(); it++) {
} std::shared_ptr<rule> ru = *it;
DBG("comparing %s against %s",
ru->addr().to_string().c_str(), taddr.to_string().c_str());
if (ru->addr() == taddr) {
if (!se)
se = session::create(_ptr.lock(), saddr, daddr, taddr);
if (!ru->ifa()) {
// This rule doesn't have an interface, and thus we'll consider
// it "static" and immediately send the response.
se->handle_advert();
return;
}
se->add_iface((*it)->ifa());
}
}
if (se) {
_sessions.push_back(se);
se->send_solicit();
}
} }
strong_ptr<rule> proxy::add_rule(const address& addr, const strong_ptr<iface>& ifa) std::shared_ptr<rule> proxy::add_rule(const address& addr, const std::shared_ptr<iface>& ifa)
{ {
strong_ptr<rule> ru(rule::create(_ptr, addr, ifa)); std::shared_ptr<rule> ru(rule::create(_ptr.lock(), addr, ifa));
_rules.push_back(ru); _rules.push_back(ru);
return ru; return ru;
} }
strong_ptr<rule> proxy::add_rule(const address& addr) std::shared_ptr<rule> proxy::add_rule(const address& addr)
{ {
strong_ptr<rule> ru(rule::create(_ptr, addr)); std::shared_ptr<rule> ru(rule::create(_ptr.lock(), addr));
_rules.push_back(ru); _rules.push_back(ru);
return ru; return ru;
} }
void proxy::remove_session(const strong_ptr<session>& se) void proxy::remove_session(const std::shared_ptr<session>& se)
{ {
_sessions.remove(se); _sessions.remove(se);
} }
const strong_ptr<iface>& proxy::ifa() const const std::shared_ptr<iface>& proxy::ifa() const
{ {
return _ifa; return _ifa;
} }
bool proxy::router() const bool proxy::router() const
{ {
return _router; return _router;
} }
void proxy::router(bool val) void proxy::router(bool val)
{ {
_router = val; _router = val;
} }
int proxy::ttl() const int proxy::ttl() const
{ {
return _ttl; return _ttl;
} }
void proxy::ttl(int val) void proxy::ttl(int val)
{ {
_ttl = (val >= 0) ? val : 30000; _ttl = (val >= 0) ? val : 30000;
} }
int proxy::timeout() const int proxy::timeout() const
{ {
return _timeout; return _timeout;
} }
void proxy::timeout(int val) void proxy::timeout(int val)
{ {
_timeout = (val >= 0) ? val : 500; _timeout = (val >= 0) ? val : 500;
} }
__NDPPD_NS_END __NDPPD_NS_END

View File

@ -32,47 +32,47 @@ class rule;
class proxy class proxy
{ {
private: private:
weak_ptr<proxy> _ptr; std::weak_ptr<proxy> _ptr;
strong_ptr<iface> _ifa; std::shared_ptr<iface> _ifa;
std::list<strong_ptr<rule> > _rules; std::list<std::shared_ptr<rule> > _rules;
std::list<strong_ptr<session> > _sessions; std::list<std::shared_ptr<session> > _sessions;
bool _router; bool _router;
int _ttl, _timeout; int _ttl, _timeout;
proxy(); proxy();
public: public:
static strong_ptr<proxy> create(const strong_ptr<iface>& ifa); static std::shared_ptr<proxy> create(const std::shared_ptr<iface>& ifa);
static strong_ptr<proxy> open(const std::string& ifn); static std::shared_ptr<proxy> open(const std::string& ifn);
void handle_solicit(const address& saddr, const address& daddr, void handle_solicit(const address& saddr, const address& daddr,
const address& taddr); const address& taddr);
void remove_session(const strong_ptr<session>& se); void remove_session(const std::shared_ptr<session>& se);
strong_ptr<rule> add_rule(const address& addr, const strong_ptr<iface>& ifa); std::shared_ptr<rule> add_rule(const address& addr, const std::shared_ptr<iface>& ifa);
strong_ptr<rule> add_rule(const address& addr); std::shared_ptr<rule> add_rule(const address& addr);
const strong_ptr<iface>& ifa() const; const std::shared_ptr<iface>& ifa() const;
bool router() const; bool router() const;
void router(bool val); void router(bool val);
int timeout() const; int timeout() const;
void timeout(int val); void timeout(int val);
int ttl() const; int ttl() const;
void ttl(int val); void ttl(int val);
}; };
__NDPPD_NS_END __NDPPD_NS_END

243
src/ptr.h
View File

@ -1,243 +0,0 @@
// ndppd - NDP Proxy Daemon
// Copyright (C) 2011 Daniel Adolfsson <daniel@priv.nu>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef __NDPPD_PTR_H
#define __NDPPD_PTR_H
#include <stdlib.h>
__NDPPD_NS_BEGIN
// This template class simplifies the usage of pointers. It's basically
// a reference-counting smart pointer that supports both weak and
// strong references.
template <typename T>
class ptr
{
protected:
struct ref
{
public:
T* p;
int n_strong;
int n_weak;
};
ref *_ref;
bool _strong;
void acquire(T* p)
{
if(_ref)
release();
if(p)
{
_ref = new ref;
_ref->p = p;
_ref->n_strong = _strong ? 1 : 0;
_ref->n_weak = _strong ? 0 : 1;
}
}
void acquire(const ptr<T>& p)
{
if(_ref)
release();
if(p._ref && p._ref->n_strong)
{
_ref = p._ref;
if(_strong)
_ref->n_strong++;
else
_ref->n_weak++;
}
}
void release()
{
if(!_ref)
return;
if(_strong)
{
// Assert _ref->n_strong > 0.
if(_ref->n_strong == 1)
{
delete _ref->p;
_ref->p = 0;
}
_ref->n_strong--;
}
else
{
_ref->n_weak--;
}
if(!_ref->n_weak && !_ref->n_strong)
delete _ref;
_ref = 0;
}
ptr(bool strong) :
_strong(strong), _ref(0)
{
}
ptr(bool strong, T* p) :
_strong(strong), _ref(0)
{
if(p)
acquire(p);
}
ptr(bool strong, const ptr<T>& p) :
_strong(strong), _ref(0)
{
acquire(p);
}
virtual ~ptr()
{
if(_ref)
release();
}
public:
void operator=(T* p)
{
acquire(p);
}
void operator=(const ptr<T>& p)
{
acquire(p);
}
bool operator==(const ptr<T>& other) const
{
return other._ref == _ref;
}
bool operator!=(const ptr<T>& other) const
{
return other._ref != _ref;
}
bool is_null() const
{
return !((_ref != 0) && (_ref->p != 0));
}
T& operator*() const
{
return *_ref.p;
}
T* operator->() const
{
return _ref ? _ref->p : 0;
}
operator T*() const
{
return _ref->p;
}
operator bool() const
{
return !is_null();
}
bool is_strong() const
{
return _strong;
}
bool is_weak() const
{
return !_strong;
}
void reset(T *p = 0)
{
acquire(p);
}
};
template <typename T>
class weak_ptr;
template <typename T>
class strong_ptr : public ptr<T>
{
public:
strong_ptr() : ptr<T>(true)
{
}
strong_ptr(T* p) : ptr<T>(true, p)
{
}
strong_ptr(const ptr<T>& p) : ptr<T>(true, p)
{
}
strong_ptr(const strong_ptr<T>& p) : ptr<T>(true, p)
{
}
strong_ptr(const weak_ptr<T>& p) : ptr<T>(true, p)
{
}
};
template <typename T>
class weak_ptr : public ptr<T>
{
public:
weak_ptr() : ptr<T>(false)
{
}
weak_ptr(T* p) : ptr<T>(false, p)
{
}
weak_ptr(const ptr<T>& p) : ptr<T>(false, p)
{
}
weak_ptr(const strong_ptr<T>& p) : ptr<T>(false, p)
{
}
weak_ptr(const weak_ptr<T>& p) : ptr<T>(false, p)
{
}
};
__NDPPD_NS_END
#endif // __NDPPD_PTR_H

View File

@ -28,51 +28,51 @@ rule::rule()
{ {
} }
strong_ptr<rule> rule::create(const strong_ptr<proxy>& pr, const address& addr, const strong_ptr<iface>& ifa) std::shared_ptr<rule> rule::create(const std::shared_ptr<proxy>& pr, const address& addr, const std::shared_ptr<iface>& ifa)
{ {
strong_ptr<rule> ru(new rule()); std::shared_ptr<rule> ru(new rule());
ru->_ptr = ru; ru->_ptr = ru;
ru->_pr = pr; ru->_pr = pr;
ru->_ifa = ifa; ru->_ifa = ifa;
ru->_addr = addr; ru->_addr = addr;
DBG("rule::create() if=%s, addr=%s", DBG("rule::create() if=%s, addr=%s",
pr->ifa()->name().c_str(), addr.to_string().c_str()); pr->ifa()->name().c_str(), addr.to_string().c_str());
return ru; return ru;
} }
strong_ptr<rule> rule::create(const strong_ptr<proxy>& pr, const address& addr) std::shared_ptr<rule> rule::create(const std::shared_ptr<proxy>& pr, const address& addr)
{ {
strong_ptr<rule> ru(new rule()); std::shared_ptr<rule> ru(new rule());
ru->_ptr = ru; ru->_ptr = ru;
ru->_pr = pr; ru->_pr = pr;
ru->_addr = addr; ru->_addr = addr;
DBG("rule::create() if=%s, addr=%s", DBG("rule::create() if=%s, addr=%s",
pr->ifa()->name().c_str(), addr.to_string().c_str()); pr->ifa()->name().c_str(), addr.to_string().c_str());
return ru; return ru;
} }
const address& rule::addr() const const address& rule::addr() const
{ {
return _addr; return _addr;
} }
strong_ptr<iface> rule::ifa() const std::shared_ptr<iface> rule::ifa() const
{ {
return _ifa; return _ifa;
} }
bool rule::is_static() const bool rule::is_static() const
{ {
return !!_ifa; return !!_ifa;
} }
bool rule::check(const address& addr) const bool rule::check(const address& addr) const
{ {
return _addr == addr; return _addr == addr;
} }
__NDPPD_NS_END __NDPPD_NS_END

View File

@ -32,28 +32,28 @@ class proxy;
class rule class rule
{ {
private: private:
weak_ptr<rule> _ptr; std::weak_ptr<rule> _ptr;
strong_ptr<proxy> _pr; std::shared_ptr<proxy> _pr;
strong_ptr<iface> _ifa; std::shared_ptr<iface> _ifa;
address _addr; address _addr;
rule(); rule();
public: public:
static strong_ptr<rule> create(const strong_ptr<proxy>& pr, const address& addr, const strong_ptr<iface>& ifa); static std::shared_ptr<rule> create(const std::shared_ptr<proxy>& pr, const address& addr, const std::shared_ptr<iface>& ifa);
static strong_ptr<rule> create(const strong_ptr<proxy>& pr, const address& addr); static std::shared_ptr<rule> create(const std::shared_ptr<proxy>& pr, const address& addr);
const address& addr() const; const address& addr() const;
strong_ptr<iface> ifa() const; std::shared_ptr<iface> ifa() const;
bool is_static() const; bool is_static() const;
bool check(const address& addr) const; bool check(const address& addr) const;
}; };

View File

@ -22,123 +22,125 @@
__NDPPD_NS_BEGIN __NDPPD_NS_BEGIN
std::list<weak_ptr<session> > session::_sessions; std::list<std::weak_ptr<session> > session::_sessions;
void session::update_all(int elapsed_time) void session::update_all(int elapsed_time)
{ {
for(std::list<weak_ptr<session> >::iterator it = _sessions.begin(); for (std::list<std::weak_ptr<session> >::iterator it = _sessions.begin();
it != _sessions.end(); ) it != _sessions.end(); ) {
{ std::shared_ptr<session> se = (*it++).lock();
strong_ptr<session> se = *it++;
if((se->_ttl -= elapsed_time) >= 0) if ((se->_ttl -= elapsed_time) >= 0)
continue; continue;
switch(se->_status) switch (se->_status) {
{ case session::WAITING:
case session::WAITING: DBG("session is now invalid");
DBG("session is now invalid"); se->_status = session::INVALID;
se->_status = session::INVALID; se->_ttl = se->_pr->ttl();
se->_ttl = se->_pr->ttl(); break;
break;
default: default:
se->_pr->remove_session(se); se->_pr->remove_session(se);
} }
} }
} }
session::~session() session::~session()
{ {
DBG("session::~session() this=%x", this); DBG("session::~session() this=%x", this);
_sessions.remove(_ptr); for (std::list<std::weak_ptr<session> >::iterator it = _sessions.begin();
it != _sessions.end(); it++) {
if (it->lock() == _ptr.lock()) {
_sessions.erase(it);
break;
}
}
for(std::list<strong_ptr<iface> >::iterator it = _ifaces.begin(); for (std::list<std::shared_ptr<iface> >::iterator it = _ifaces.begin();
it != _ifaces.end(); it++) it != _ifaces.end(); it++) {
{ (*it)->remove_session(_ptr.lock());
(*it)->remove_session(_ptr); }
}
} }
strong_ptr<session> session::create(const strong_ptr<proxy>& pr, const address& saddr, std::shared_ptr<session> session::create(const std::shared_ptr<proxy>& pr, const address& saddr,
const address& daddr, const address& taddr) const address& daddr, const address& taddr)
{ {
strong_ptr<session> se(new session()); std::shared_ptr<session> se(new session());
se->_ptr = se; se->_ptr = se;
se->_pr = pr; se->_pr = pr;
se->_saddr = saddr; se->_saddr = saddr;
se->_taddr = taddr; se->_taddr = taddr;
se->_daddr = daddr; se->_daddr = daddr;
se->_ttl = pr->timeout(); se->_ttl = pr->timeout();
_sessions.push_back(se); _sessions.push_back(se);
DBG("session::create() pr=%x, saddr=%s, daddr=%s, taddr=%s, =%x", DBG("session::create() pr=%x, saddr=%s, daddr=%s, taddr=%s, =%x",
(proxy *)pr, saddr.to_string().c_str(), daddr.to_string().c_str(), (proxy *)pr, saddr.to_string().c_str(), daddr.to_string().c_str(),
taddr.to_string().c_str(), (session *)se); taddr.to_string().c_str(), (session *)se);
return se; return se;
} }
void session::add_iface(const strong_ptr<iface>& ifa) void session::add_iface(const std::shared_ptr<iface>& ifa)
{ {
if(std::find(_ifaces.begin(), _ifaces.end(), ifa) != _ifaces.end()) if (std::find(_ifaces.begin(), _ifaces.end(), ifa) != _ifaces.end())
return; return;
ifa->add_session(_ptr); ifa->add_session(_ptr.lock());
_ifaces.push_back(ifa); _ifaces.push_back(ifa);
} }
void session::send_solicit() void session::send_solicit()
{ {
DBG("session::send_solicit() (%d)", _ifaces.size()); DBG("session::send_solicit() (%d)", _ifaces.size());
for(std::list<strong_ptr<iface> >::iterator it = _ifaces.begin(); for (std::list<std::shared_ptr<iface> >::iterator it = _ifaces.begin();
it != _ifaces.end(); it++) it != _ifaces.end(); it++) {
{ DBG(" - %s", (*it)->name().c_str());
DBG(" - %s", (*it)->name().c_str()); (*it)->write_solicit(_taddr);
(*it)->write_solicit(_taddr); }
}
} }
void session::send_advert() void session::send_advert()
{ {
_pr->ifa()->write_advert(_saddr, _taddr, _pr->router()); _pr->ifa()->write_advert(_saddr, _taddr, _pr->router());
} }
void session::handle_advert() void session::handle_advert()
{ {
_status = VALID; _status = VALID;
_ttl = _pr->ttl(); _ttl = _pr->ttl();
send_advert(); send_advert();
} }
const address& session::taddr() const const address& session::taddr() const
{ {
return _taddr; return _taddr;
} }
const address& session::saddr() const const address& session::saddr() const
{ {
return _saddr; return _saddr;
} }
const address& session::daddr() const const address& session::daddr() const
{ {
return _daddr; return _daddr;
} }
int session::status() const int session::status() const
{ {
return _status; return _status;
} }
void session::status(int val) void session::status(int val)
{ {
_status = val; _status = val;
} }
__NDPPD_NS_END __NDPPD_NS_END

View File

@ -28,59 +28,59 @@ class iface;
class session class session
{ {
private: private:
weak_ptr<session> _ptr; std::weak_ptr<session> _ptr;
strong_ptr<proxy> _pr; std::shared_ptr<proxy> _pr;
address _saddr, _daddr, _taddr; address _saddr, _daddr, _taddr;
// An array of interfaces this session is monitoring for // An array of interfaces this session is monitoring for
// ND_NEIGHBOR_ADVERT on. // ND_NEIGHBOR_ADVERT on.
std::list<strong_ptr<iface> > _ifaces; std::list<std::shared_ptr<iface> > _ifaces;
// The remaining time in miliseconds the object will stay in the // The remaining time in miliseconds the object will stay in the
// interface's session array or cache. // interface's session array or cache.
int _ttl; int _ttl;
int _status; int _status;
static std::list<weak_ptr<session> > _sessions; static std::list<std::weak_ptr<session> > _sessions;
public: public:
enum enum
{ {
WAITING, // Waiting for an advert response. WAITING, // Waiting for an advert response.
VALID, // Valid; VALID, // Valid;
INVALID // Invalid; INVALID // Invalid;
}; };
static void update_all(int elapsed_time); static void update_all(int elapsed_time);
// Destructor. // Destructor.
~session(); ~session();
static strong_ptr<session> create(const strong_ptr<proxy>& pr, const address& saddr, static std::shared_ptr<session> create(const std::shared_ptr<proxy>& pr, const address& saddr,
const address& daddr, const address& taddr); const address& daddr, const address& taddr);
void add_iface(const strong_ptr<iface>& ifa); void add_iface(const std::shared_ptr<iface>& ifa);
const address& taddr() const; const address& taddr() const;
const address& daddr() const; const address& daddr() const;
const address& saddr() const; const address& saddr() const;
int status() const; int status() const;
void status(int val); void status(int val);
void handle_advert(); void handle_advert();
void send_advert(); void send_advert();
void send_solicit(); void send_solicit();
void refesh(); void refesh();
}; };