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:
parent
6fda405a59
commit
bc70f587ef
4
Makefile
4
Makefile
@ -1,7 +1,7 @@
|
||||
ifdef DEBUG
|
||||
CXXFLAGS ?= -g -DDEBUG
|
||||
CXXFLAGS ?= -g -std=c++0x -DDEBUG
|
||||
else
|
||||
CXXFLAGS ?= -O3
|
||||
CXXFLAGS ?= -O3 -std=c++0x
|
||||
endif
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
|
288
src/address.cc
288
src/address.cc
@ -32,265 +32,245 @@ __NDPPD_NS_BEGIN
|
||||
|
||||
address::address()
|
||||
{
|
||||
_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;
|
||||
reset();
|
||||
}
|
||||
|
||||
address::address(const 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];
|
||||
_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];
|
||||
_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)
|
||||
{
|
||||
if(!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;
|
||||
}
|
||||
parse_string(str);
|
||||
}
|
||||
|
||||
address::address(const char *str)
|
||||
{
|
||||
if(!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;
|
||||
}
|
||||
parse_string(str);
|
||||
}
|
||||
|
||||
address::address(const in6_addr& addr)
|
||||
{
|
||||
_addr.s6_addr32[0] = addr.s6_addr32[0];
|
||||
_addr.s6_addr32[1] = addr.s6_addr32[1];
|
||||
_addr.s6_addr32[2] = addr.s6_addr32[2];
|
||||
_addr.s6_addr32[3] = addr.s6_addr32[3];
|
||||
_addr.s6_addr32[0] = addr.s6_addr32[0];
|
||||
_addr.s6_addr32[1] = addr.s6_addr32[1];
|
||||
_addr.s6_addr32[2] = addr.s6_addr32[2];
|
||||
_addr.s6_addr32[3] = addr.s6_addr32[3];
|
||||
|
||||
_mask.s6_addr32[0] = 0xffffffff;
|
||||
_mask.s6_addr32[1] = 0xffffffff;
|
||||
_mask.s6_addr32[2] = 0xffffffff;
|
||||
_mask.s6_addr32[3] = 0xffffffff;
|
||||
_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, const in6_addr& mask)
|
||||
{
|
||||
_addr.s6_addr32[0] = addr.s6_addr32[0];
|
||||
_addr.s6_addr32[1] = addr.s6_addr32[1];
|
||||
_addr.s6_addr32[2] = addr.s6_addr32[2];
|
||||
_addr.s6_addr32[3] = addr.s6_addr32[3];
|
||||
_addr.s6_addr32[0] = addr.s6_addr32[0];
|
||||
_addr.s6_addr32[1] = addr.s6_addr32[1];
|
||||
_addr.s6_addr32[2] = addr.s6_addr32[2];
|
||||
_addr.s6_addr32[3] = addr.s6_addr32[3];
|
||||
|
||||
_mask.s6_addr32[0] = mask.s6_addr32[0];
|
||||
_mask.s6_addr32[1] = mask.s6_addr32[1];
|
||||
_mask.s6_addr32[2] = mask.s6_addr32[2];
|
||||
_mask.s6_addr32[3] = mask.s6_addr32[3];
|
||||
_mask.s6_addr32[0] = mask.s6_addr32[0];
|
||||
_mask.s6_addr32[1] = mask.s6_addr32[1];
|
||||
_mask.s6_addr32[2] = mask.s6_addr32[2];
|
||||
_mask.s6_addr32[3] = mask.s6_addr32[3];
|
||||
}
|
||||
|
||||
address::address(const in6_addr& addr, int pf)
|
||||
{
|
||||
_addr.s6_addr32[0] = addr.s6_addr32[0];
|
||||
_addr.s6_addr32[1] = addr.s6_addr32[1];
|
||||
_addr.s6_addr32[2] = addr.s6_addr32[2];
|
||||
_addr.s6_addr32[3] = addr.s6_addr32[3];
|
||||
_addr.s6_addr32[0] = addr.s6_addr32[0];
|
||||
_addr.s6_addr32[1] = addr.s6_addr32[1];
|
||||
_addr.s6_addr32[2] = addr.s6_addr32[2];
|
||||
_addr.s6_addr32[3] = addr.s6_addr32[3];
|
||||
|
||||
prefix(pf);
|
||||
prefix(pf);
|
||||
}
|
||||
|
||||
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]));
|
||||
}
|
||||
|
||||
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[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
|
||||
{
|
||||
if(!_mask.s6_addr[0])
|
||||
return 0;
|
||||
if (!_mask.s6_addr[0])
|
||||
return 0;
|
||||
|
||||
for(int p = 0; p < 128; p++)
|
||||
{
|
||||
int byi = p / 8, bii = 7 - (p % 8);
|
||||
if(!(_mask.s6_addr[byi] & (1 << bii)))
|
||||
return p;
|
||||
}
|
||||
for (int p = 0; p < 128; p++) {
|
||||
int byi = p / 8, bii = 7 - (p % 8);
|
||||
if (!(_mask.s6_addr[byi] & (1 << bii)))
|
||||
return p;
|
||||
}
|
||||
|
||||
return 128;
|
||||
return 128;
|
||||
}
|
||||
|
||||
void address::prefix(int pf)
|
||||
{
|
||||
if((pf < 0) || (pf > 128))
|
||||
return;
|
||||
if ((pf < 0) || (pf > 128))
|
||||
return;
|
||||
|
||||
_mask.s6_addr32[0] = 0;
|
||||
_mask.s6_addr32[1] = 0;
|
||||
_mask.s6_addr32[2] = 0;
|
||||
_mask.s6_addr32[3] = 0;
|
||||
_mask.s6_addr32[0] = 0;
|
||||
_mask.s6_addr32[1] = 0;
|
||||
_mask.s6_addr32[2] = 0;
|
||||
_mask.s6_addr32[3] = 0;
|
||||
|
||||
while(pf--)
|
||||
{
|
||||
int byi = pf / 8, bii = 7 - (pf % 8);
|
||||
_mask.s6_addr[byi] |= 1 << bii;
|
||||
}
|
||||
while (pf--) {
|
||||
int byi = pf / 8, bii = 7 - (pf % 8);
|
||||
_mask.s6_addr[byi] |= 1 << bii;
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
return "::1";
|
||||
if (!inet_ntop(AF_INET6, &_addr, buf, INET6_ADDRSTRLEN))
|
||||
return "::1";
|
||||
|
||||
// TODO: What to do about invalid ip?
|
||||
// TODO: What to do about invalid ip?
|
||||
|
||||
int p;
|
||||
int p;
|
||||
|
||||
if((p = prefix()) < 128)
|
||||
sprintf(buf + strlen(buf), "/%d", p);
|
||||
if ((p = prefix()) < 128)
|
||||
sprintf(buf + strlen(buf), "/%d", p);
|
||||
|
||||
return buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool address::parse_string(const std::string& str)
|
||||
{
|
||||
char buf[INET6_ADDRSTRLEN], *b;
|
||||
int sz, pfx;
|
||||
char buf[INET6_ADDRSTRLEN], *b;
|
||||
int sz, pfx;
|
||||
|
||||
sz = 0;
|
||||
b = buf;
|
||||
sz = 0;
|
||||
b = buf;
|
||||
|
||||
const char *p = str.c_str();
|
||||
reset();
|
||||
|
||||
while(*p && isspace(*p))
|
||||
p++;
|
||||
const char *p = str.c_str();
|
||||
|
||||
while(*p)
|
||||
{
|
||||
if((*p == '/') || isspace(*p))
|
||||
break;
|
||||
while (*p && isspace(*p))
|
||||
p++;
|
||||
|
||||
if((*p != ':') && !isxdigit(*p))
|
||||
return false;
|
||||
while (*p) {
|
||||
if ((*p == '/') || isspace(*p))
|
||||
break;
|
||||
|
||||
if(sz >= (INET6_ADDRSTRLEN - 1))
|
||||
return false;
|
||||
if ((*p != ':') && !isxdigit(*p))
|
||||
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)
|
||||
return false;
|
||||
*b = '\0';
|
||||
|
||||
while(*p && isspace(*p))
|
||||
p++;
|
||||
if (inet_pton(AF_INET6, buf, &_addr) <= 0)
|
||||
return false;
|
||||
|
||||
if(*p == '\0')
|
||||
{
|
||||
_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))
|
||||
p++;
|
||||
|
||||
if(*p++ != '/')
|
||||
return false;
|
||||
if (*p == '\0') {
|
||||
_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))
|
||||
p++;
|
||||
if (*p++ != '/')
|
||||
return false;
|
||||
|
||||
sz = 0;
|
||||
b = buf;
|
||||
while (*p && isspace(*p))
|
||||
p++;
|
||||
|
||||
while(*p)
|
||||
{
|
||||
if(!isdigit(*p))
|
||||
return false;
|
||||
sz = 0;
|
||||
b = buf;
|
||||
|
||||
if(sz > 3)
|
||||
return false;
|
||||
while (*p) {
|
||||
if (!isdigit(*p))
|
||||
return false;
|
||||
|
||||
*b++ = *p++;
|
||||
sz++;
|
||||
}
|
||||
if (sz > 3)
|
||||
return false;
|
||||
|
||||
*b = '\0';
|
||||
*b++ = *p++;
|
||||
sz++;
|
||||
}
|
||||
|
||||
prefix(atoi(buf));
|
||||
*b = '\0';
|
||||
|
||||
return true;
|
||||
prefix(atoi(buf));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
address::operator std::string() const
|
||||
{
|
||||
return to_string();
|
||||
return to_string();
|
||||
}
|
||||
|
||||
struct in6_addr& address::addr()
|
||||
{
|
||||
return _addr;
|
||||
return _addr;
|
||||
}
|
||||
|
||||
const struct in6_addr& address::const_addr() const
|
||||
{
|
||||
return _addr;
|
||||
return _addr;
|
||||
}
|
||||
|
||||
struct in6_addr& address::mask()
|
||||
{
|
||||
return _mask;
|
||||
return _mask;
|
||||
}
|
||||
|
||||
bool address::is_multicast() const
|
||||
{
|
||||
return _addr.s6_addr[0] == 0xff;
|
||||
return _addr.s6_addr[0] == 0xff;
|
||||
}
|
||||
|
||||
bool address::is_unicast() const
|
||||
{
|
||||
return _addr.s6_addr[0] != 0xff;
|
||||
return _addr.s6_addr[0] != 0xff;
|
||||
}
|
||||
|
||||
__NDPPD_NS_END
|
||||
|
@ -29,41 +29,43 @@ class iface;
|
||||
class address
|
||||
{
|
||||
private:
|
||||
struct in6_addr _addr, _mask;
|
||||
struct in6_addr _addr, _mask;
|
||||
|
||||
public:
|
||||
address();
|
||||
address(const 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);
|
||||
address();
|
||||
address(const 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);
|
||||
|
||||
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.
|
||||
bool operator==(const address& addr) const;
|
||||
// Compare _a/_m against a._a.
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
|
165
src/conf.cc
165
src/conf.cc
@ -24,131 +24,126 @@ __NDPPD_NS_BEGIN
|
||||
|
||||
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)
|
||||
return;
|
||||
if (vsnprintf(buf, sizeof(buf), fmt, ap) <= 0)
|
||||
return;
|
||||
|
||||
ERR("[Config] %s", buf);
|
||||
ERR("[Config] %s", buf);
|
||||
}
|
||||
|
||||
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)
|
||||
return -1;
|
||||
if (!rule_cfg)
|
||||
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)
|
||||
{
|
||||
int i;
|
||||
int i;
|
||||
|
||||
for(i = 0; i < cfg_size(cfg, "proxy"); i++)
|
||||
{
|
||||
cfg_t *proxy_cfg = cfg_getnsec(cfg, "proxy", i);
|
||||
for (i = 0; i < cfg_size(cfg, "proxy"); i++) {
|
||||
cfg_t *proxy_cfg = cfg_getnsec(cfg, "proxy", i);
|
||||
|
||||
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++)
|
||||
{
|
||||
if (proxy_cfg) {
|
||||
cfg_t *rule_cfg;
|
||||
int i2;
|
||||
|
||||
if(!(rule_cfg = cfg_getnsec(proxy_cfg, "rule", i2)))
|
||||
continue;
|
||||
std::shared_ptr<proxy> pr = proxy::open(cfg_title(proxy_cfg));
|
||||
|
||||
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())
|
||||
{
|
||||
if(addr.prefix() <= 120)
|
||||
NCE("Static rule prefix /%d <= 120 - is this what you want?", addr.prefix());
|
||||
pr->ttl(cfg_getint(proxy_cfg, "ttl"));
|
||||
|
||||
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)
|
||||
{
|
||||
cfg_t *cfg;
|
||||
int i, sz;
|
||||
cfg_t *cfg;
|
||||
int i, sz;
|
||||
|
||||
#define _S (char *)
|
||||
#define _S (char *)
|
||||
|
||||
static cfg_opt_t rule_opts[] =
|
||||
{
|
||||
CFG_STR (_S "iface", _S "", CFGF_NONE),
|
||||
CFG_END ()
|
||||
};
|
||||
static cfg_opt_t rule_opts[] =
|
||||
{
|
||||
CFG_STR (_S "iface", _S "", CFGF_NONE),
|
||||
CFG_END ()
|
||||
};
|
||||
|
||||
static cfg_opt_t proxy_opts[] =
|
||||
{
|
||||
CFG_SEC (_S "rule", rule_opts, CFGF_MULTI | CFGF_TITLE),
|
||||
CFG_BOOL (_S "router", cfg_true, CFGF_NONE),
|
||||
CFG_INT (_S "ttl", 30000, CFGF_NONE),
|
||||
CFG_INT (_S "timeout", 500, CFGF_NONE),
|
||||
CFG_END ()
|
||||
};
|
||||
static cfg_opt_t proxy_opts[] =
|
||||
{
|
||||
CFG_SEC (_S "rule", rule_opts, CFGF_MULTI | CFGF_TITLE),
|
||||
CFG_BOOL (_S "router", cfg_true, CFGF_NONE),
|
||||
CFG_INT (_S "ttl", 30000, CFGF_NONE),
|
||||
CFG_INT (_S "timeout", 500, CFGF_NONE),
|
||||
CFG_END ()
|
||||
};
|
||||
|
||||
static cfg_opt_t opts[] =
|
||||
{
|
||||
CFG_SEC (_S "proxy", proxy_opts, CFGF_MULTI | CFGF_TITLE),
|
||||
CFG_FUNC (_S "include", &cfg_include),
|
||||
CFG_END()
|
||||
};
|
||||
static cfg_opt_t opts[] =
|
||||
{
|
||||
CFG_SEC (_S "proxy", proxy_opts, CFGF_MULTI | CFGF_TITLE),
|
||||
CFG_FUNC (_S "include", &cfg_include),
|
||||
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()))
|
||||
{
|
||||
case CFG_SUCCESS:
|
||||
break;
|
||||
switch (cfg_parse(cfg, path.c_str())) {
|
||||
case CFG_SUCCESS:
|
||||
break;
|
||||
|
||||
default:
|
||||
ERR("Failed to load configuration file '%s'", path.c_str());
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
ERR("Failed to load configuration file '%s'", path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
setup(cfg);
|
||||
setup(cfg);
|
||||
|
||||
cfg_free(cfg);
|
||||
cfg_free(cfg);
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
__NDPPD_NS_END
|
||||
|
@ -30,11 +30,11 @@ __NDPPD_NS_BEGIN
|
||||
class conf
|
||||
{
|
||||
private:
|
||||
static bool setup(::cfg_t *cfg);
|
||||
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 bool setup(::cfg_t *cfg);
|
||||
static void error_printf(::cfg_t *cfg, const char *fmt, va_list ap);
|
||||
static int validate_rule(::cfg_t *cfg, ::cfg_opt_t *opt);
|
||||
public:
|
||||
static bool load(const std::string& path);
|
||||
static bool load(const std::string& path);
|
||||
};
|
||||
|
||||
__NDPPD_NS_END
|
||||
|
733
src/iface.cc
733
src/iface.cc
@ -42,583 +42,560 @@
|
||||
|
||||
__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;
|
||||
|
||||
iface::iface() :
|
||||
_ifd(-1), _pfd(-1)
|
||||
_ifd(-1), _pfd(-1)
|
||||
{
|
||||
}
|
||||
|
||||
iface::~iface()
|
||||
{
|
||||
DBG("iface::~iface()");
|
||||
DBG("iface::~iface()");
|
||||
|
||||
if(_ifd >= 0)
|
||||
close(_ifd);
|
||||
if (_ifd >= 0)
|
||||
close(_ifd);
|
||||
|
||||
if(_pfd >= 0)
|
||||
{
|
||||
allmulti(_prev_allmulti);
|
||||
close(_pfd);
|
||||
}
|
||||
if (_pfd >= 0) {
|
||||
allmulti(_prev_allmulti);
|
||||
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->second->_pfd >= 0)
|
||||
return it->second;
|
||||
if (it != _map.end()) {
|
||||
if (it->second->_pfd >= 0)
|
||||
return it->second;
|
||||
|
||||
ifa = it->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We need an _ifs, so let's set one up.
|
||||
ifa = open_ifd(name);
|
||||
}
|
||||
ifa = it->second;
|
||||
} else {
|
||||
// We need an _ifs, so let's set one up.
|
||||
ifa = open_ifd(name);
|
||||
}
|
||||
|
||||
if(ifa.is_null())
|
||||
return strong_ptr<iface>();
|
||||
if (!ifa)
|
||||
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)
|
||||
{
|
||||
ERR("Unable to create socket");
|
||||
return strong_ptr<iface>();
|
||||
}
|
||||
// Bind to the specified interface.
|
||||
|
||||
// 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));
|
||||
lladdr.sll_family = AF_PACKET;
|
||||
lladdr.sll_protocol = htons(ETH_P_IPV6);
|
||||
if (!(lladdr.sll_ifindex = if_nametoindex(name.c_str()))) {
|
||||
close(fd);
|
||||
ERR("Failed to bind to interface '%s'", name.c_str());
|
||||
return std::shared_ptr<iface>();
|
||||
}
|
||||
|
||||
if(!(lladdr.sll_ifindex = if_nametoindex(name.c_str())))
|
||||
{
|
||||
close(fd);
|
||||
ERR("Failed to bind to interface '%s'", name.c_str());
|
||||
return strong_ptr<iface>();
|
||||
}
|
||||
if (bind(fd, (struct sockaddr *)&lladdr, sizeof(struct sockaddr_ll)) < 0) {
|
||||
close(fd);
|
||||
ERR("Failed to bind to interface '%s'", name.c_str());
|
||||
return std::shared_ptr<iface>();
|
||||
}
|
||||
|
||||
if(bind(fd, (struct sockaddr *)&lladdr, sizeof(struct sockaddr_ll)) < 0)
|
||||
{
|
||||
close(fd);
|
||||
ERR("Failed to bind to interface '%s'", name.c_str());
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
close(fd);
|
||||
ERR("Failed to switch to non-blocking on interface '%s'", name.c_str());
|
||||
return strong_ptr<iface>();
|
||||
}
|
||||
// Set up filter.
|
||||
|
||||
// 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[] =
|
||||
{
|
||||
// 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;
|
||||
fprog.len = 8;
|
||||
|
||||
fprog.filter = (struct sock_filter *)filter;
|
||||
fprog.len = 8;
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0) {
|
||||
ERR("Failed to set filter");
|
||||
return std::shared_ptr<iface>();
|
||||
}
|
||||
|
||||
if(setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0)
|
||||
{
|
||||
ERR("Failed to set filter");
|
||||
return strong_ptr<iface>();
|
||||
}
|
||||
// Set up an instance of '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)
|
||||
return it->second;
|
||||
if ((it != _map.end()) && it->second->_ifd)
|
||||
return it->second;
|
||||
|
||||
// Create a socket.
|
||||
// Create a socket.
|
||||
|
||||
if((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
|
||||
{
|
||||
ERR("Unable to create socket");
|
||||
return strong_ptr<iface>();
|
||||
}
|
||||
if ((fd = socket(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0) {
|
||||
ERR("Unable to create socket");
|
||||
return std::shared_ptr<iface>();
|
||||
}
|
||||
|
||||
// Bind to the specified interface.
|
||||
// Bind to the specified interface.
|
||||
|
||||
struct ifreq ifr;
|
||||
struct ifreq ifr;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, name.c_str(), IFNAMSIZ - 1);
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, name.c_str(), IFNAMSIZ - 1);
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
|
||||
|
||||
if(setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0)
|
||||
{
|
||||
close(fd);
|
||||
ERR("Failed to bind to interface '%s'", name.c_str());
|
||||
return strong_ptr<iface>();
|
||||
}
|
||||
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) < 0) {
|
||||
close(fd);
|
||||
ERR("Failed to bind to interface '%s'", name.c_str());
|
||||
return std::shared_ptr<iface>();
|
||||
}
|
||||
|
||||
// Detect the link-layer address.
|
||||
// Detect the link-layer address.
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, name.c_str(), IFNAMSIZ - 1);
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strncpy(ifr.ifr_name, name.c_str(), IFNAMSIZ - 1);
|
||||
ifr.ifr_name[IFNAMSIZ - 1] = '\0';
|
||||
|
||||
if(ioctl(fd, SIOCGIFHWADDR, &ifr) < 0)
|
||||
{
|
||||
close(fd);
|
||||
ERR("Failed to detect link-layer address for interface '%s'", name.c_str());
|
||||
return strong_ptr<iface>();
|
||||
}
|
||||
if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) {
|
||||
close(fd);
|
||||
ERR("Failed to detect link-layer address for interface '%s'", name.c_str());
|
||||
return std::shared_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)
|
||||
{
|
||||
close(fd);
|
||||
ERR("iface::open_ifd() failed IPV6_MULTICAST_HOPS");
|
||||
return strong_ptr<iface>();
|
||||
}
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, sizeof(hops)) < 0) {
|
||||
close(fd);
|
||||
ERR("iface::open_ifd() failed IPV6_MULTICAST_HOPS");
|
||||
return std::shared_ptr<iface>();
|
||||
}
|
||||
|
||||
if(setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, sizeof(hops)) < 0)
|
||||
{
|
||||
close(fd);
|
||||
ERR("iface::open_ifd() failed IPV6_UNICAST_HOPS");
|
||||
return strong_ptr<iface>();
|
||||
}
|
||||
if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, sizeof(hops)) < 0) {
|
||||
close(fd);
|
||||
ERR("iface::open_ifd() failed IPV6_UNICAST_HOPS");
|
||||
return std::shared_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)
|
||||
{
|
||||
close(fd);
|
||||
ERR("Failed to switch to non-blocking on interface '%s'", name.c_str());
|
||||
return strong_ptr<iface>();
|
||||
}
|
||||
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>();
|
||||
}
|
||||
|
||||
// Set up filter.
|
||||
// Set up filter.
|
||||
|
||||
struct icmp6_filter filter;
|
||||
ICMP6_FILTER_SETBLOCKALL(&filter);
|
||||
ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filter);
|
||||
struct icmp6_filter filter;
|
||||
ICMP6_FILTER_SETBLOCKALL(&filter);
|
||||
ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filter);
|
||||
|
||||
if(setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) < 0)
|
||||
{
|
||||
ERR("Failed to set filter");
|
||||
return strong_ptr<iface>();
|
||||
}
|
||||
if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof(filter)) < 0) {
|
||||
ERR("Failed to set filter");
|
||||
return std::shared_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())
|
||||
{
|
||||
ifa = new iface();
|
||||
if (it == _map.end()) {
|
||||
ifa.reset(new iface());
|
||||
ifa->_name = name;
|
||||
ifa->_ptr = ifa;
|
||||
|
||||
ifa->_name = name;
|
||||
ifa->_ptr = ifa;
|
||||
_map[name] = ifa;
|
||||
} else {
|
||||
ifa = it->second;
|
||||
}
|
||||
|
||||
_map[name] = ifa;
|
||||
}
|
||||
else
|
||||
{
|
||||
ifa = it->second;
|
||||
}
|
||||
ifa->_ifd = fd;
|
||||
|
||||
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)
|
||||
{
|
||||
struct msghdr mhdr;
|
||||
struct iovec iov;
|
||||
char cbuf[256];
|
||||
int len;
|
||||
struct msghdr mhdr;
|
||||
struct iovec iov;
|
||||
char cbuf[256];
|
||||
int len;
|
||||
|
||||
if(!msg || (size < 0))
|
||||
return -1;
|
||||
if (!msg || (size < 0))
|
||||
return -1;
|
||||
|
||||
iov.iov_len = size;
|
||||
iov.iov_base = (caddr_t)msg;
|
||||
iov.iov_len = size;
|
||||
iov.iov_base = (caddr_t)msg;
|
||||
|
||||
memset(&mhdr, 0, sizeof(mhdr));
|
||||
mhdr.msg_name = (caddr_t)saddr;
|
||||
mhdr.msg_namelen = sizeof(struct sockaddr);
|
||||
mhdr.msg_iov = &iov;
|
||||
mhdr.msg_iovlen = 1;
|
||||
memset(&mhdr, 0, sizeof(mhdr));
|
||||
mhdr.msg_name = (caddr_t)saddr;
|
||||
mhdr.msg_namelen = sizeof(struct sockaddr);
|
||||
mhdr.msg_iov = &iov;
|
||||
mhdr.msg_iovlen = 1;
|
||||
|
||||
if((len = recvmsg(fd, &mhdr, 0)) < 0)
|
||||
return -1;
|
||||
if ((len = recvmsg(fd, &mhdr, 0)) < 0)
|
||||
return -1;
|
||||
|
||||
if(len < sizeof(struct icmp6_hdr))
|
||||
return -1;
|
||||
if (len < sizeof(struct icmp6_hdr))
|
||||
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)
|
||||
{
|
||||
struct sockaddr_in6 daddr_tmp;
|
||||
struct msghdr mhdr;
|
||||
struct iovec iov;
|
||||
struct sockaddr_in6 daddr_tmp;
|
||||
struct msghdr mhdr;
|
||||
struct iovec iov;
|
||||
|
||||
memset(&daddr_tmp, 0, sizeof(struct sockaddr_in6));
|
||||
daddr_tmp.sin6_family = AF_INET6;
|
||||
daddr_tmp.sin6_port = htons(IPPROTO_ICMPV6); // Needed?
|
||||
memcpy(&daddr_tmp.sin6_addr, &daddr.const_addr(), sizeof(struct in6_addr));
|
||||
memset(&daddr_tmp, 0, sizeof(struct sockaddr_in6));
|
||||
daddr_tmp.sin6_family = AF_INET6;
|
||||
daddr_tmp.sin6_port = htons(IPPROTO_ICMPV6); // Needed?
|
||||
memcpy(&daddr_tmp.sin6_addr, &daddr.const_addr(), sizeof(struct in6_addr));
|
||||
|
||||
iov.iov_len = size;
|
||||
iov.iov_base = (caddr_t)msg;
|
||||
iov.iov_len = size;
|
||||
iov.iov_base = (caddr_t)msg;
|
||||
|
||||
memset(&mhdr, 0, sizeof(mhdr));
|
||||
mhdr.msg_name = (caddr_t)&daddr_tmp;
|
||||
mhdr.msg_namelen = sizeof(sockaddr_in6);
|
||||
mhdr.msg_iov = &iov;
|
||||
mhdr.msg_iovlen = 1;
|
||||
memset(&mhdr, 0, sizeof(mhdr));
|
||||
mhdr.msg_name = (caddr_t)&daddr_tmp;
|
||||
mhdr.msg_namelen = sizeof(sockaddr_in6);
|
||||
mhdr.msg_iov = &iov;
|
||||
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)
|
||||
return -1;
|
||||
if ((len = sendmsg(fd, &mhdr, 0)) < 0)
|
||||
return -1;
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
ssize_t iface::read_solicit(address& saddr, address& daddr, address& taddr)
|
||||
{
|
||||
struct sockaddr_ll t_saddr;
|
||||
uint8_t msg[256];
|
||||
ssize_t len;
|
||||
struct sockaddr_ll t_saddr;
|
||||
uint8_t msg[256];
|
||||
ssize_t len;
|
||||
|
||||
if((len = read(_pfd, (struct sockaddr *)&t_saddr, msg, sizeof(msg))) < 0)
|
||||
return -1;
|
||||
if ((len = read(_pfd, (struct sockaddr *)&t_saddr, msg, sizeof(msg))) < 0)
|
||||
return -1;
|
||||
|
||||
struct ip6_hdr *ip6h =
|
||||
(struct ip6_hdr *)(msg + ETH_HLEN);
|
||||
struct ip6_hdr *ip6h =
|
||||
(struct ip6_hdr *)(msg + ETH_HLEN);
|
||||
|
||||
struct icmp6_hdr *icmph =
|
||||
(struct icmp6_hdr *)(msg + ETH_HLEN + sizeof( struct ip6_hdr));
|
||||
struct icmp6_hdr *icmph =
|
||||
(struct icmp6_hdr *)(msg + ETH_HLEN + sizeof( struct ip6_hdr));
|
||||
|
||||
struct nd_neighbor_solicit *ns =
|
||||
(struct nd_neighbor_solicit *)(msg + ETH_HLEN + sizeof( struct ip6_hdr));
|
||||
struct nd_neighbor_solicit *ns =
|
||||
(struct nd_neighbor_solicit *)(msg + ETH_HLEN + sizeof( struct ip6_hdr));
|
||||
|
||||
taddr = ns->nd_ns_target;
|
||||
daddr = ip6h->ip6_dst;
|
||||
saddr = ip6h->ip6_src;
|
||||
taddr = ns->nd_ns_target;
|
||||
daddr = ip6h->ip6_dst;
|
||||
saddr = ip6h->ip6_src;
|
||||
|
||||
DBG("iface::read_solicit() saddr=%s, daddr=%s, taddr=%s, len=%d",
|
||||
saddr.to_string().c_str(), daddr.to_string().c_str(),
|
||||
taddr.to_string().c_str(), len);
|
||||
DBG("iface::read_solicit() saddr=%s, daddr=%s, taddr=%s, len=%d",
|
||||
saddr.to_string().c_str(), daddr.to_string().c_str(),
|
||||
taddr.to_string().c_str(), len);
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
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 *)&buf[0];
|
||||
struct nd_neighbor_solicit *ns =
|
||||
(struct nd_neighbor_solicit *)&buf[0];
|
||||
|
||||
struct nd_opt_hdr *opt =
|
||||
(struct nd_opt_hdr *)&buf[sizeof(struct nd_neighbor_solicit)];
|
||||
struct nd_opt_hdr *opt =
|
||||
(struct nd_opt_hdr *)&buf[sizeof(struct nd_neighbor_solicit)];
|
||||
|
||||
opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
|
||||
opt->nd_opt_len = 1;
|
||||
opt->nd_opt_type = ND_OPT_SOURCE_LINKADDR;
|
||||
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.
|
||||
static address multicast("ff02::1:ff00:0000");
|
||||
// FIXME: Alright, I'm lazy.
|
||||
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[14] = taddr.const_addr().s6_addr[14];
|
||||
daddr.addr().s6_addr[15] = taddr.const_addr().s6_addr[15];
|
||||
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[15] = taddr.const_addr().s6_addr[15];
|
||||
|
||||
DBG("iface::write_solicit() taddr=%s, daddr=%s",
|
||||
taddr.to_string().c_str(), daddr.to_string().c_str());
|
||||
DBG("iface::write_solicit() taddr=%s, daddr=%s",
|
||||
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)
|
||||
{
|
||||
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 *)&buf[0];
|
||||
struct nd_neighbor_advert *na =
|
||||
(struct nd_neighbor_advert *)&buf[0];
|
||||
|
||||
struct nd_opt_hdr *opt =
|
||||
(struct nd_opt_hdr *)&buf[sizeof(struct nd_neighbor_advert)];
|
||||
struct nd_opt_hdr *opt =
|
||||
(struct nd_opt_hdr *)&buf[sizeof(struct nd_neighbor_advert)];
|
||||
|
||||
opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
|
||||
opt->nd_opt_len = 1;
|
||||
opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
|
||||
opt->nd_opt_len = 1;
|
||||
|
||||
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_type = ND_NEIGHBOR_ADVERT;
|
||||
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",
|
||||
daddr.to_string().c_str(), taddr.to_string().c_str());
|
||||
DBG("iface::write_advert() daddr=%s, taddr=%s",
|
||||
daddr.to_string().c_str(), taddr.to_string().c_str());
|
||||
|
||||
return write(_ifd, daddr, (uint8_t *)buf, sizeof(struct nd_neighbor_advert) +
|
||||
sizeof(struct nd_opt_hdr) + 6);
|
||||
return write(_ifd, daddr, (uint8_t *)buf, sizeof(struct nd_neighbor_advert) +
|
||||
sizeof(struct nd_opt_hdr) + 6);
|
||||
}
|
||||
|
||||
ssize_t iface::read_advert(address& saddr, address& taddr)
|
||||
{
|
||||
struct sockaddr_in6 t_saddr;
|
||||
uint8_t msg[256];
|
||||
ssize_t len;
|
||||
struct sockaddr_in6 t_saddr;
|
||||
uint8_t msg[256];
|
||||
ssize_t len;
|
||||
|
||||
if((len = read(_ifd, (struct sockaddr *)&t_saddr, msg, sizeof(msg))) < 0)
|
||||
return -1;
|
||||
if ((len = read(_ifd, (struct sockaddr *)&t_saddr, msg, sizeof(msg))) < 0)
|
||||
return -1;
|
||||
|
||||
saddr = t_saddr.sin6_addr;
|
||||
saddr = t_saddr.sin6_addr;
|
||||
|
||||
if(((struct icmp6_hdr *)msg)->icmp6_type != ND_NEIGHBOR_ADVERT)
|
||||
return -1;
|
||||
if (((struct icmp6_hdr *)msg)->icmp6_type != ND_NEIGHBOR_ADVERT)
|
||||
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",
|
||||
saddr.to_string().c_str(), taddr.to_string().c_str(), len);
|
||||
DBG("iface::read_advert() saddr=%s, taddr=%s, len=%d",
|
||||
saddr.to_string().c_str(), taddr.to_string().c_str(), len);
|
||||
|
||||
return len;
|
||||
return len;
|
||||
}
|
||||
|
||||
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();
|
||||
it != _map.end(); it++)
|
||||
{
|
||||
_pollfds[i].fd = it->second->_ifd;
|
||||
_pollfds[i].events = POLLIN;
|
||||
_pollfds[i].revents = 0;
|
||||
i++;
|
||||
for (std::map<std::string, std::shared_ptr<iface> >::iterator it = _map.begin();
|
||||
it != _map.end(); it++) {
|
||||
_pollfds[i].fd = it->second->_ifd;
|
||||
_pollfds[i].events = POLLIN;
|
||||
_pollfds[i].revents = 0;
|
||||
i++;
|
||||
|
||||
_pollfds[i].fd = it->second->_pfd;
|
||||
_pollfds[i].events = POLLIN;
|
||||
_pollfds[i].revents = 0;
|
||||
i++;
|
||||
}
|
||||
_pollfds[i].fd = it->second->_pfd;
|
||||
_pollfds[i].events = POLLIN;
|
||||
_pollfds[i].revents = 0;
|
||||
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()
|
||||
{
|
||||
if(_pollfds.size() == 0)
|
||||
{
|
||||
::sleep(1);
|
||||
return 0;
|
||||
}
|
||||
if (_pollfds.size() == 0) {
|
||||
::sleep(1);
|
||||
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)
|
||||
return -1;
|
||||
if ((len = ::poll(&_pollfds[0], _pollfds.size(), 50)) < 0)
|
||||
return -1;
|
||||
|
||||
if(len == 0)
|
||||
return 0;
|
||||
if (len == 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();
|
||||
f_it != _pollfds.end(); f_it++)
|
||||
{
|
||||
assert(i_it != _map.end());
|
||||
for (std::vector<struct pollfd>::iterator f_it = _pollfds.begin();
|
||||
f_it != _pollfds.end(); f_it++) {
|
||||
assert(i_it != _map.end());
|
||||
|
||||
if(i && !(i % 2))
|
||||
i_it++;
|
||||
if (i && !(i % 2))
|
||||
i_it++;
|
||||
|
||||
bool is_pfd = i++ % 2;
|
||||
bool is_pfd = i++ % 2;
|
||||
|
||||
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())
|
||||
if (!(f_it->revents & POLLIN))
|
||||
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;
|
||||
}
|
||||
std::shared_ptr<iface> ifa = i_it->second;
|
||||
|
||||
for(std::list<weak_ptr<session> >::iterator s_it = ifa->_sessions.begin();
|
||||
s_it != ifa->_sessions.end(); s_it++)
|
||||
{
|
||||
if(((*s_it)->taddr() == taddr) && ((*s_it)->status() == session::WAITING))
|
||||
{
|
||||
(*s_it)->handle_advert();
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct ifreq ifr;
|
||||
struct ifreq ifr;
|
||||
|
||||
DBG("iface::allmulti() state=%d, _name=\"%s\"",
|
||||
state, _name.c_str());
|
||||
DBG("iface::allmulti() state=%d, _name=\"%s\"",
|
||||
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)
|
||||
return -1;
|
||||
if (ioctl(_pfd, SIOCGIFFLAGS, &ifr) < 0)
|
||||
return -1;
|
||||
|
||||
int old_state = !!(ifr.ifr_flags & IFF_ALLMULTI);
|
||||
int old_state = !!(ifr.ifr_flags & IFF_ALLMULTI);
|
||||
|
||||
if(state == old_state)
|
||||
return old_state;
|
||||
if (state == old_state)
|
||||
return old_state;
|
||||
|
||||
if(state)
|
||||
ifr.ifr_flags |= IFF_ALLMULTI;
|
||||
else
|
||||
ifr.ifr_flags &= ~IFF_ALLMULTI;
|
||||
if (state)
|
||||
ifr.ifr_flags |= IFF_ALLMULTI;
|
||||
else
|
||||
ifr.ifr_flags &= ~IFF_ALLMULTI;
|
||||
|
||||
if(ioctl(_pfd, SIOCSIFFLAGS, &ifr) < 0)
|
||||
return -1;
|
||||
if (ioctl(_pfd, SIOCSIFFLAGS, &ifr) < 0)
|
||||
return -1;
|
||||
|
||||
return old_state;
|
||||
return old_state;
|
||||
}
|
||||
|
||||
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
|
||||
|
100
src/iface.h
100
src/iface.h
@ -34,85 +34,85 @@ class proxy;
|
||||
class iface
|
||||
{
|
||||
private:
|
||||
// Weak pointer so this object can reference itself.
|
||||
weak_ptr<iface> _ptr;
|
||||
// Weak pointer so this object can reference itself.
|
||||
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.
|
||||
static std::vector<struct pollfd> _pollfds;
|
||||
// An array of objects used with ::poll.
|
||||
static std::vector<struct pollfd> _pollfds;
|
||||
|
||||
// Updates the array above.
|
||||
static void fixup_pollfds();
|
||||
// Updates the array above.
|
||||
static void fixup_pollfds();
|
||||
|
||||
// The "generic" ICMPv6 socket for reading/writing NB_NEIGHBOR_ADVERT
|
||||
// messages as well as writing NB_NEIGHBOR_SOLICIT messages.
|
||||
int _ifd;
|
||||
// The "generic" ICMPv6 socket for reading/writing NB_NEIGHBOR_ADVERT
|
||||
// messages as well as writing NB_NEIGHBOR_SOLICIT messages.
|
||||
int _ifd;
|
||||
|
||||
// This is the PF_PACKET socket we use in order to read
|
||||
// NB_NEIGHBOR_SOLICIT messages.
|
||||
int _pfd;
|
||||
// This is the PF_PACKET socket we use in order to read
|
||||
// NB_NEIGHBOR_SOLICIT messages.
|
||||
int _pfd;
|
||||
|
||||
// Previous state of ALLMULTI for the interface.
|
||||
int _prev_allmulti;
|
||||
// Previous state of ALLMULTI for the interface.
|
||||
int _prev_allmulti;
|
||||
|
||||
// Name of this interface.
|
||||
std::string _name;
|
||||
// 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;
|
||||
// An array of sessions that are monitoring this interface for
|
||||
// ND_NEIGHBOR_ADVERT messages.
|
||||
std::list<std::weak_ptr<session> > _sessions;
|
||||
|
||||
strong_ptr<proxy> _pr;
|
||||
std::shared_ptr<proxy> _pr;
|
||||
|
||||
// The link-layer address of this interface.
|
||||
struct ether_addr hwaddr;
|
||||
// The link-layer address of this interface.
|
||||
struct ether_addr hwaddr;
|
||||
|
||||
// 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 ALLMULTI for this interface - returns the previous state
|
||||
// or -1 if there was an error.
|
||||
int allmulti(int state);
|
||||
|
||||
// Constructor.
|
||||
iface();
|
||||
// Constructor.
|
||||
iface();
|
||||
|
||||
public:
|
||||
|
||||
// Destructor.
|
||||
~iface();
|
||||
// Destructor.
|
||||
~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.
|
||||
ssize_t write_solicit(const address& taddr);
|
||||
// Writes a NB_NEIGHBOR_SOLICIT message to the _ifd socket.
|
||||
ssize_t write_solicit(const address& taddr);
|
||||
|
||||
// Writes a NB_NEIGHBOR_ADVERT message to the _ifd socket;
|
||||
ssize_t write_advert(const address& daddr, const address& taddr, bool router);
|
||||
// Writes a NB_NEIGHBOR_ADVERT message to the _ifd socket;
|
||||
ssize_t write_advert(const address& daddr, const address& taddr, bool router);
|
||||
|
||||
// Reads a NB_NEIGHBOR_SOLICIT message from the _pfd socket.
|
||||
ssize_t read_solicit(address& saddr, address& daddr, address& taddr);
|
||||
// Reads a NB_NEIGHBOR_SOLICIT message from the _pfd socket.
|
||||
ssize_t read_solicit(address& saddr, address& daddr, address& taddr);
|
||||
|
||||
// Reads a NB_NEIGHBOR_ADVERT message from the _ifd socket;
|
||||
ssize_t read_advert(address& saddr, address& taddr);
|
||||
// Reads a NB_NEIGHBOR_ADVERT message from the _ifd socket;
|
||||
ssize_t read_advert(address& saddr, address& taddr);
|
||||
|
||||
// Returns the name of the interface.
|
||||
const std::string& name() const;
|
||||
// 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 strong_ptr<session>& se);
|
||||
// Adds a session to be monitored for ND_NEIGHBOR_ADVERT messages.
|
||||
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
|
||||
|
76
src/log.cc
76
src/log.cc
@ -25,68 +25,66 @@ __NDPPD_NS_BEGIN
|
||||
|
||||
const char *log::_level_str[] =
|
||||
{
|
||||
"fatal",
|
||||
"alert",
|
||||
"critical",
|
||||
"error",
|
||||
"warning",
|
||||
"notice",
|
||||
"info",
|
||||
"debug"
|
||||
"fatal",
|
||||
"alert",
|
||||
"critical",
|
||||
"error",
|
||||
"warning",
|
||||
"notice",
|
||||
"info",
|
||||
"debug"
|
||||
};
|
||||
|
||||
bool log::_syslog = false;
|
||||
|
||||
void log::puts(int level, const char *str)
|
||||
{
|
||||
const char *ls;
|
||||
const char *ls;
|
||||
|
||||
if((level < 0) || (level > LOG_DEBUG))
|
||||
ls = "unknown";
|
||||
else
|
||||
ls = _level_str[level];
|
||||
if ((level < 0) || (level > LOG_DEBUG))
|
||||
ls = "unknown";
|
||||
else
|
||||
ls = _level_str[level];
|
||||
|
||||
if(_syslog)
|
||||
::syslog(level, "(%s) %s", ls, str);
|
||||
else
|
||||
fprintf(stderr, "(% 8s) %s\n", ls, str);
|
||||
if (_syslog)
|
||||
::syslog(level, "(%s) %s", ls, str);
|
||||
else
|
||||
fprintf(stderr, "(% 8s) %s\n", ls, str);
|
||||
}
|
||||
|
||||
void log::printf(int level, const char *fmt, ...)
|
||||
{
|
||||
char buf[256];
|
||||
va_list args;
|
||||
int ret;
|
||||
char buf[256];
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, fmt);
|
||||
va_start(args, fmt);
|
||||
|
||||
if(vsnprintf(buf, sizeof(buf), fmt, args) > 0)
|
||||
{
|
||||
puts(level, buf);
|
||||
}
|
||||
if (vsnprintf(buf, sizeof(buf), fmt, args) > 0) {
|
||||
puts(level, buf);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void log::syslog(bool sl)
|
||||
{
|
||||
if(sl == _syslog)
|
||||
return;
|
||||
if (sl == _syslog)
|
||||
return;
|
||||
|
||||
if(_syslog = sl)
|
||||
{
|
||||
if (_syslog = sl) {
|
||||
#ifdef DEBUG
|
||||
setlogmask(LOG_UPTO(LOG_DEBUG));
|
||||
openlog("ndppd", LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
|
||||
setlogmask(LOG_UPTO(LOG_DEBUG));
|
||||
openlog("ndppd", LOG_CONS | LOG_NDELAY | LOG_PERROR | LOG_PID, LOG_USER);
|
||||
#else
|
||||
setlogmask(LOG_UPTO(LOG_INFO));
|
||||
openlog("ndppd", LOG_CONS, LOG_USER);
|
||||
setlogmask(LOG_UPTO(LOG_INFO));
|
||||
openlog("ndppd", LOG_CONS, LOG_USER);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
closelog();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
closelog();
|
||||
}
|
||||
}
|
||||
|
||||
__NDPPD_NS_END
|
||||
|
10
src/log.h
10
src/log.h
@ -35,16 +35,16 @@ __NDPPD_NS_BEGIN
|
||||
class log
|
||||
{
|
||||
private:
|
||||
static const char *_level_str[];
|
||||
static const char *_level_str[];
|
||||
|
||||
static bool _syslog;
|
||||
static bool _syslog;
|
||||
|
||||
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
|
||||
|
144
src/ndppd.cc
144
src/ndppd.cc
@ -29,111 +29,105 @@ using namespace ndppd;
|
||||
|
||||
int daemonize()
|
||||
{
|
||||
pid_t pid = fork();
|
||||
pid_t pid = fork();
|
||||
|
||||
if(pid < 0)
|
||||
return -1;
|
||||
if (pid < 0)
|
||||
return -1;
|
||||
|
||||
if(pid > 0)
|
||||
exit(0);
|
||||
if (pid > 0)
|
||||
exit(0);
|
||||
|
||||
pid_t sid = setsid();
|
||||
pid_t sid = setsid();
|
||||
|
||||
if(sid < 0)
|
||||
return -1;
|
||||
if (sid < 0)
|
||||
return -1;
|
||||
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
close(STDIN_FILENO);
|
||||
close(STDOUT_FILENO);
|
||||
close(STDERR_FILENO);
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[], char *env[])
|
||||
{
|
||||
std::string config_path("/etc/ndppd.conf");
|
||||
std::string pidfile;
|
||||
bool daemon = false;
|
||||
std::string config_path("/etc/ndppd.conf");
|
||||
std::string pidfile;
|
||||
bool daemon = false;
|
||||
|
||||
while(1)
|
||||
{
|
||||
int c, opt;
|
||||
while (1) {
|
||||
int c, opt;
|
||||
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{ "config", 1, 0, 'c' },
|
||||
{ "daemon", 0, 0, 'd' },
|
||||
{ 0, 0, 0, 0}
|
||||
};
|
||||
static struct option long_options[] =
|
||||
{
|
||||
{ "config", 1, 0, 'c' },
|
||||
{ "daemon", 0, 0, 'd' },
|
||||
{ 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)
|
||||
break;
|
||||
if (c == -1)
|
||||
break;
|
||||
|
||||
switch(c)
|
||||
{
|
||||
case 'c':
|
||||
config_path = optarg;
|
||||
break;
|
||||
switch (c) {
|
||||
case 'c':
|
||||
config_path = optarg;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
daemon = true;
|
||||
break;
|
||||
case 'd':
|
||||
daemon = true;
|
||||
break;
|
||||
|
||||
case 'p':
|
||||
pidfile = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
case 'p':
|
||||
pidfile = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(daemon)
|
||||
{
|
||||
log::syslog(true);
|
||||
if (daemon) {
|
||||
log::syslog(true);
|
||||
|
||||
if(daemonize() < 0)
|
||||
{
|
||||
ERR("Failed to daemonize process");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (daemonize() < 0) {
|
||||
ERR("Failed to daemonize process");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if(!pidfile.empty())
|
||||
{
|
||||
std::ofstream pf;
|
||||
pf.open(pidfile.c_str(), std::ios::out | std::ios::trunc);
|
||||
pf << getpid() << std::endl;
|
||||
pf.close();
|
||||
}
|
||||
if (!pidfile.empty()) {
|
||||
std::ofstream pf;
|
||||
pf.open(pidfile.c_str(), std::ios::out | std::ios::trunc);
|
||||
pf << getpid() << std::endl;
|
||||
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))
|
||||
return -1;
|
||||
if (!conf::load(config_path))
|
||||
return -1;
|
||||
|
||||
struct timeval t1, t2;
|
||||
struct timeval t1, t2;
|
||||
|
||||
gettimeofday(&t1, 0);
|
||||
gettimeofday(&t1, 0);
|
||||
|
||||
while(iface::poll_all() >= 0)
|
||||
{
|
||||
int elapsed_time;
|
||||
gettimeofday(&t2, 0);
|
||||
while (iface::poll_all() >= 0) {
|
||||
int elapsed_time;
|
||||
gettimeofday(&t2, 0);
|
||||
|
||||
elapsed_time =
|
||||
((t2.tv_sec - t1.tv_sec) * 1000) +
|
||||
((t2.tv_usec - t1.tv_usec) / 1000);
|
||||
elapsed_time =
|
||||
((t2.tv_sec - t1.tv_sec) * 1000) +
|
||||
((t2.tv_usec - t1.tv_usec) / 1000);
|
||||
|
||||
t1.tv_sec = t2.tv_sec;
|
||||
t1.tv_usec = t2.tv_usec;
|
||||
t1.tv_sec = t2.tv_sec;
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
#define __NDPPD_H
|
||||
|
||||
#include <netinet/ip6.h>
|
||||
#include <memory>
|
||||
|
||||
#define __NDPPD_NS_BEGIN namespace ndppd {
|
||||
#define __NDPPD_NS_END }
|
||||
@ -26,7 +27,6 @@
|
||||
#include <assert.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "ptr.h"
|
||||
#include "conf.h"
|
||||
#include "address.h"
|
||||
|
||||
|
166
src/proxy.cc
166
src/proxy.cc
@ -27,151 +27,145 @@
|
||||
__NDPPD_NS_BEGIN
|
||||
|
||||
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());
|
||||
pr->_ptr = pr;
|
||||
pr->_ifa = ifa;
|
||||
std::shared_ptr<proxy> pr(new proxy());
|
||||
pr->_ptr = pr;
|
||||
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())
|
||||
return strong_ptr<proxy>();
|
||||
if (!ifa)
|
||||
return std::shared_ptr<proxy>();
|
||||
|
||||
return create(ifa);
|
||||
return create(ifa);
|
||||
}
|
||||
|
||||
void proxy::handle_solicit(const address& saddr, const address& daddr,
|
||||
const address& taddr)
|
||||
const address& taddr)
|
||||
{
|
||||
DBG("proxy::handle_solicit() saddr=%s, taddr=%s",
|
||||
saddr.to_string().c_str(), taddr.to_string().c_str());
|
||||
DBG("proxy::handle_solicit() saddr=%s, taddr=%s",
|
||||
saddr.to_string().c_str(), taddr.to_string().c_str());
|
||||
|
||||
// Let's check this proxy's list of sessions to see if we can
|
||||
// find one with the same target address.
|
||||
// Let's check this proxy's list of sessions to see if we can
|
||||
// find one with the same target address.
|
||||
|
||||
for(std::list<strong_ptr<session> >::iterator sit = _sessions.begin();
|
||||
sit != _sessions.end(); sit++)
|
||||
{
|
||||
if((*sit)->taddr() == taddr)
|
||||
{
|
||||
switch((*sit)->status())
|
||||
{
|
||||
case session::WAITING:
|
||||
case session::INVALID:
|
||||
break;
|
||||
for (std::list<std::shared_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();
|
||||
}
|
||||
case session::VALID:
|
||||
(*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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
_sessions.push_back(se);
|
||||
se->send_solicit();
|
||||
}
|
||||
std::shared_ptr<session> se;
|
||||
|
||||
for (std::list<std::shared_ptr<rule> >::iterator it = _rules.begin();
|
||||
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));
|
||||
_rules.push_back(ru);
|
||||
return ru;
|
||||
std::shared_ptr<rule> ru(rule::create(_ptr.lock(), addr, ifa));
|
||||
_rules.push_back(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));
|
||||
_rules.push_back(ru);
|
||||
return ru;
|
||||
std::shared_ptr<rule> ru(rule::create(_ptr.lock(), addr));
|
||||
_rules.push_back(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
|
||||
{
|
||||
return _router;
|
||||
return _router;
|
||||
}
|
||||
|
||||
void proxy::router(bool val)
|
||||
{
|
||||
_router = val;
|
||||
_router = val;
|
||||
}
|
||||
|
||||
int proxy::ttl() const
|
||||
{
|
||||
return _ttl;
|
||||
return _ttl;
|
||||
}
|
||||
|
||||
void proxy::ttl(int val)
|
||||
{
|
||||
_ttl = (val >= 0) ? val : 30000;
|
||||
_ttl = (val >= 0) ? val : 30000;
|
||||
}
|
||||
|
||||
int proxy::timeout() const
|
||||
{
|
||||
return _timeout;
|
||||
return _timeout;
|
||||
}
|
||||
|
||||
void proxy::timeout(int val)
|
||||
{
|
||||
_timeout = (val >= 0) ? val : 500;
|
||||
_timeout = (val >= 0) ? val : 500;
|
||||
}
|
||||
|
||||
__NDPPD_NS_END
|
||||
|
42
src/proxy.h
42
src/proxy.h
@ -32,47 +32,47 @@ class rule;
|
||||
class proxy
|
||||
{
|
||||
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:
|
||||
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,
|
||||
const address& taddr);
|
||||
void handle_solicit(const address& saddr, const address& daddr,
|
||||
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
|
||||
|
243
src/ptr.h
243
src/ptr.h
@ -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
|
44
src/rule.cc
44
src/rule.cc
@ -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());
|
||||
ru->_ptr = ru;
|
||||
ru->_pr = pr;
|
||||
ru->_ifa = ifa;
|
||||
ru->_addr = addr;
|
||||
std::shared_ptr<rule> ru(new rule());
|
||||
ru->_ptr = ru;
|
||||
ru->_pr = pr;
|
||||
ru->_ifa = ifa;
|
||||
ru->_addr = addr;
|
||||
|
||||
DBG("rule::create() if=%s, addr=%s",
|
||||
pr->ifa()->name().c_str(), addr.to_string().c_str());
|
||||
DBG("rule::create() if=%s, addr=%s",
|
||||
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());
|
||||
ru->_ptr = ru;
|
||||
ru->_pr = pr;
|
||||
ru->_addr = addr;
|
||||
std::shared_ptr<rule> ru(new rule());
|
||||
ru->_ptr = ru;
|
||||
ru->_pr = pr;
|
||||
ru->_addr = addr;
|
||||
|
||||
DBG("rule::create() if=%s, addr=%s",
|
||||
pr->ifa()->name().c_str(), addr.to_string().c_str());
|
||||
DBG("rule::create() if=%s, addr=%s",
|
||||
pr->ifa()->name().c_str(), addr.to_string().c_str());
|
||||
|
||||
return ru;
|
||||
return ru;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
return !!_ifa;
|
||||
return !!_ifa;
|
||||
}
|
||||
|
||||
bool rule::check(const address& addr) const
|
||||
{
|
||||
return _addr == addr;
|
||||
return _addr == addr;
|
||||
}
|
||||
|
||||
__NDPPD_NS_END
|
||||
|
22
src/rule.h
22
src/rule.h
@ -32,28 +32,28 @@ class proxy;
|
||||
class rule
|
||||
{
|
||||
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:
|
||||
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;
|
||||
|
||||
};
|
||||
|
||||
|
122
src/session.cc
122
src/session.cc
@ -22,123 +22,125 @@
|
||||
|
||||
__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)
|
||||
{
|
||||
for(std::list<weak_ptr<session> >::iterator it = _sessions.begin();
|
||||
it != _sessions.end(); )
|
||||
{
|
||||
strong_ptr<session> se = *it++;
|
||||
for (std::list<std::weak_ptr<session> >::iterator it = _sessions.begin();
|
||||
it != _sessions.end(); ) {
|
||||
std::shared_ptr<session> se = (*it++).lock();
|
||||
|
||||
if((se->_ttl -= elapsed_time) >= 0)
|
||||
continue;
|
||||
if ((se->_ttl -= elapsed_time) >= 0)
|
||||
continue;
|
||||
|
||||
switch(se->_status)
|
||||
{
|
||||
case session::WAITING:
|
||||
DBG("session is now invalid");
|
||||
se->_status = session::INVALID;
|
||||
se->_ttl = se->_pr->ttl();
|
||||
break;
|
||||
switch (se->_status) {
|
||||
case session::WAITING:
|
||||
DBG("session is now invalid");
|
||||
se->_status = session::INVALID;
|
||||
se->_ttl = se->_pr->ttl();
|
||||
break;
|
||||
|
||||
default:
|
||||
se->_pr->remove_session(se);
|
||||
}
|
||||
}
|
||||
default:
|
||||
se->_pr->remove_session(se);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
it != _ifaces.end(); it++)
|
||||
{
|
||||
(*it)->remove_session(_ptr);
|
||||
}
|
||||
for (std::list<std::shared_ptr<iface> >::iterator it = _ifaces.begin();
|
||||
it != _ifaces.end(); it++) {
|
||||
(*it)->remove_session(_ptr.lock());
|
||||
}
|
||||
}
|
||||
|
||||
strong_ptr<session> session::create(const strong_ptr<proxy>& pr, const address& saddr,
|
||||
const address& daddr, const address& taddr)
|
||||
std::shared_ptr<session> session::create(const std::shared_ptr<proxy>& pr, const address& saddr,
|
||||
const address& daddr, const address& taddr)
|
||||
{
|
||||
strong_ptr<session> se(new session());
|
||||
std::shared_ptr<session> se(new session());
|
||||
|
||||
se->_ptr = se;
|
||||
se->_pr = pr;
|
||||
se->_saddr = saddr;
|
||||
se->_taddr = taddr;
|
||||
se->_daddr = daddr;
|
||||
se->_ttl = pr->timeout();
|
||||
se->_ptr = se;
|
||||
se->_pr = pr;
|
||||
se->_saddr = saddr;
|
||||
se->_taddr = taddr;
|
||||
se->_daddr = daddr;
|
||||
se->_ttl = pr->timeout();
|
||||
|
||||
_sessions.push_back(se);
|
||||
_sessions.push_back(se);
|
||||
|
||||
DBG("session::create() pr=%x, saddr=%s, daddr=%s, taddr=%s, =%x",
|
||||
(proxy *)pr, saddr.to_string().c_str(), daddr.to_string().c_str(),
|
||||
taddr.to_string().c_str(), (session *)se);
|
||||
DBG("session::create() pr=%x, saddr=%s, daddr=%s, taddr=%s, =%x",
|
||||
(proxy *)pr, saddr.to_string().c_str(), daddr.to_string().c_str(),
|
||||
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())
|
||||
return;
|
||||
if (std::find(_ifaces.begin(), _ifaces.end(), ifa) != _ifaces.end())
|
||||
return;
|
||||
|
||||
ifa->add_session(_ptr);
|
||||
_ifaces.push_back(ifa);
|
||||
ifa->add_session(_ptr.lock());
|
||||
_ifaces.push_back(ifa);
|
||||
}
|
||||
|
||||
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();
|
||||
it != _ifaces.end(); it++)
|
||||
{
|
||||
DBG(" - %s", (*it)->name().c_str());
|
||||
(*it)->write_solicit(_taddr);
|
||||
}
|
||||
for (std::list<std::shared_ptr<iface> >::iterator it = _ifaces.begin();
|
||||
it != _ifaces.end(); it++) {
|
||||
DBG(" - %s", (*it)->name().c_str());
|
||||
(*it)->write_solicit(_taddr);
|
||||
}
|
||||
}
|
||||
|
||||
void session::send_advert()
|
||||
{
|
||||
_pr->ifa()->write_advert(_saddr, _taddr, _pr->router());
|
||||
_pr->ifa()->write_advert(_saddr, _taddr, _pr->router());
|
||||
}
|
||||
|
||||
void session::handle_advert()
|
||||
{
|
||||
_status = VALID;
|
||||
_ttl = _pr->ttl();
|
||||
_status = VALID;
|
||||
_ttl = _pr->ttl();
|
||||
|
||||
send_advert();
|
||||
send_advert();
|
||||
}
|
||||
|
||||
const address& session::taddr() const
|
||||
{
|
||||
return _taddr;
|
||||
return _taddr;
|
||||
}
|
||||
|
||||
const address& session::saddr() const
|
||||
{
|
||||
return _saddr;
|
||||
return _saddr;
|
||||
}
|
||||
|
||||
const address& session::daddr() const
|
||||
{
|
||||
return _daddr;
|
||||
return _daddr;
|
||||
}
|
||||
|
||||
int session::status() const
|
||||
{
|
||||
return _status;
|
||||
return _status;
|
||||
}
|
||||
|
||||
void session::status(int val)
|
||||
{
|
||||
_status = val;
|
||||
_status = val;
|
||||
}
|
||||
|
||||
__NDPPD_NS_END
|
||||
|
@ -28,59 +28,59 @@ class iface;
|
||||
class session
|
||||
{
|
||||
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
|
||||
// ND_NEIGHBOR_ADVERT on.
|
||||
std::list<strong_ptr<iface> > _ifaces;
|
||||
// An array of interfaces this session is monitoring for
|
||||
// ND_NEIGHBOR_ADVERT on.
|
||||
std::list<std::shared_ptr<iface> > _ifaces;
|
||||
|
||||
// The remaining time in miliseconds the object will stay in the
|
||||
// interface's session array or cache.
|
||||
int _ttl;
|
||||
// The remaining time in miliseconds the object will stay in the
|
||||
// interface's session array or cache.
|
||||
int _ttl;
|
||||
|
||||
int _status;
|
||||
int _status;
|
||||
|
||||
static std::list<weak_ptr<session> > _sessions;
|
||||
static std::list<std::weak_ptr<session> > _sessions;
|
||||
|
||||
public:
|
||||
enum
|
||||
{
|
||||
WAITING, // Waiting for an advert response.
|
||||
VALID, // Valid;
|
||||
INVALID // Invalid;
|
||||
};
|
||||
enum
|
||||
{
|
||||
WAITING, // Waiting for an advert response.
|
||||
VALID, // Valid;
|
||||
INVALID // Invalid;
|
||||
};
|
||||
|
||||
static void update_all(int elapsed_time);
|
||||
static void update_all(int elapsed_time);
|
||||
|
||||
// Destructor.
|
||||
~session();
|
||||
// Destructor.
|
||||
~session();
|
||||
|
||||
static strong_ptr<session> create(const strong_ptr<proxy>& pr, const address& saddr,
|
||||
const address& daddr, const address& taddr);
|
||||
static std::shared_ptr<session> create(const std::shared_ptr<proxy>& pr, const address& saddr,
|
||||
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();
|
||||
|
||||
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user