#pragma once
+#include <string_view>
#include <lmdb.h>
#include <iostream>
#include <fstream>
/* open issues:
*
* - missing convenience functions (string_view, string)
- */
+ */
/*
The error strategy. Anything that "should never happen" turns into an exception. But things like 'duplicate entry' or 'no such key' are for you to deal with.
*/
/*
- Thread safety: we are as safe as lmdb. You can talk to MDBEnv from as many threads as you want
+ Thread safety: we are as safe as lmdb. You can talk to MDBEnv from as many threads as you want
*/
/** MDBDbi is our only 'value type' object, as 1) a dbi is actually an integer
MDBDbi(): d_dbi(-1)
{
}
- explicit MDBDbi(MDB_env* env, MDB_txn* txn, string_view dbname, int flags);
+ explicit MDBDbi(MDB_env* env, MDB_txn* txn, string_view dbname, int flags);
operator const MDB_dbi&() const
{
return d_dbi;
}
-
+
MDB_dbi d_dbi;
};
}
MDBDbi openDB(const string_view dbname, int flags);
-
+
MDBRWTransaction getRWTransaction();
MDBROTransaction getROTransaction();
T ret;
if(d_mdbval.mv_size != sizeof(T))
throw std::runtime_error("MDB data has wrong length for type");
-
+
memcpy(&ret, d_mdbval.mv_data, sizeof(T));
return ret;
}
T ret;
if(d_mdbval.mv_size != sizeof(T))
throw std::runtime_error("MDB data has wrong length for type");
-
+
memcpy(&ret, d_mdbval.mv_data, sizeof(T));
return ret;
}
{
if(d_mdbval.mv_size != sizeof(T))
throw std::runtime_error("MDB data has wrong length for type");
-
+
return reinterpret_cast<const T*>(d_mdbval.mv_data);
}
-
-
+
+
MDB_val d_mdbval;
};
template <class T,
typename std::enable_if<std::is_arithmetic<T>::value,
T>::type* = nullptr>
- MDBInVal(T i)
+ MDBInVal(T i)
{
memcpy(&d_memory[0], &i, sizeof(i));
d_mdbval.mv_size = sizeof(T);
d_mdbval.mv_size = strlen(s);
d_mdbval.mv_data = (void*)s;
}
-
- MDBInVal(const string_view& v)
+
+ MDBInVal(const string_view& v)
{
d_mdbval.mv_size = v.size();
d_mdbval.mv_data = (void*)&v[0];
}
- MDBInVal(const std::string& v)
+ MDBInVal(const std::string& v)
{
d_mdbval.mv_size = v.size();
d_mdbval.mv_data = (void*)&v[0];
}
-
+
template<typename T>
static MDBInVal fromStruct(const T& t)
{
ret.d_mdbval.mv_data = (void*)&t;
return ret;
}
-
+
operator MDB_val&()
{
return d_mdbval;
const_cast<MDB_val*>(&val.d_mdbval));
if(rc && rc != MDB_NOTFOUND)
throw std::runtime_error("getting data: " + std::string(mdb_strerror(rc)));
-
+
return rc;
}
return rc;
}
-
+
// this is something you can do, readonly
MDBDbi openDB(string_view dbname, int flags)
{
MDBROCursor getCursor(const MDBDbi&);
MDBROCursor getROCursor(const MDBDbi&);
-
+
operator MDB_txn*()
{
return d_txn;
}
};
-/*
- A cursor in a read-only transaction must be closed explicitly, before or after its transaction ends. It can be reused with mdb_cursor_renew() before finally closing it.
+/*
+ A cursor in a read-only transaction must be closed explicitly, before or after its transaction ends. It can be reused with mdb_cursor_renew() before finally closing it.
"If the parent transaction commits, the cursor must not be used again."
*/
throw std::runtime_error("Unable to find from cursor: " + std::string(mdb_strerror(rc)));
return rc;
}
-
+
int lower_bound(const MDBInVal& in, MDBOutVal& key, MDBOutVal& data)
{
key.d_mdbval = in.d_mdbval;
return rc;
}
-
+
int nextprev(MDBOutVal& key, MDBOutVal& data, MDB_cursor_op op)
{
int rc = mdb_cursor_get(d_cursor, const_cast<MDB_val*>(&key.d_mdbval), &data.d_mdbval, op);
MDBRWTransactionImpl &operator=(MDBRWTransactionImpl&& rhs) = delete;
~MDBRWTransactionImpl() override;
-
+
void commit() override;
void abort() override;
void clear(MDB_dbi dbi);
-
+
void put(MDB_dbi dbi, const MDBInVal& key, const MDBInVal& val, int flags=0)
{
if(!d_txn)
return rc;
}
-
+
int get(MDBDbi& dbi, const MDBInVal& key, MDBOutVal& val)
{
if(!d_txn)
val = out.get<string_view>();
return rc;
}
-
+
MDBDbi openDB(string_view dbname, int flags)
{
return MDBDbi(environment().d_env, d_txn, dbname, flags);
MDBROTransaction getROTransaction();
};
-/* "A cursor in a write-transaction can be closed before its transaction ends, and will otherwise be closed when its transaction ends"
+/* "A cursor in a write-transaction can be closed before its transaction ends, and will otherwise be closed when its transaction ends"
This is a problem for us since it may means we are closing the cursor twice, which is bad
*/
class MDBRWCursor : public MDBGenCursor<MDBRWTransactionImpl, MDBRWCursor>
throw std::runtime_error("mdb_cursor_put: " + std::string(mdb_strerror(rc)));
}
-
+
int put(const MDBOutVal& key, const MDBOutVal& data, int flags=0)
{
// XXX check errors
}
};
-
#pragma once
+#include <string_view>
#include <iostream>
#include "lmdb-safe.hh"
#include <boost/archive/binary_oarchive.hpp>
// using std::endl;
-/*
+/*
Open issues:
Everything should go into a namespace
/** Return the highest ID used in a database. Returns 0 for an empty DB.
- This makes us start everything at ID=1, which might make it possible to
+ This makes us start everything at ID=1, which might make it possible to
treat id 0 as special
*/
unsigned int MDBGetMaxID(MDBRWTransaction& txn, MDBDbi& dbi);
boost::iostreams::back_insert_device<std::string> inserter(serial_str);
boost::iostreams::stream<boost::iostreams::back_insert_device<std::string> > s(inserter);
boost::archive::binary_oarchive oa(s, boost::archive::no_header | boost::archive::no_codecvt);
-
+
oa << t;
return serial_str;
}
return std::string((char*)&t, sizeof(t));
}
-// this is how to override specific types.. it is ugly
+// this is how to override specific types.. it is ugly
template<class T, typename std::enable_if<std::is_same<T, std::string>::value,T>::type* = nullptr>
inline std::string keyConv(const T& t)
{
}
-/** This is a struct that implements index operations, but
+/** This is a struct that implements index operations, but
only the operations that are broadcast to all indexes.
Specifically, to deal with databases with less than the maximum
number of interfaces, this only includes calls that should be
{
return c.*PtrToMember;
}
-
+
typedef Type type;
};
return f(c);
}
- typedef Type type;
+ typedef Type type;
};
/** nop index, so we can fill our N indexes, even if you don't use them all */
template<typename Class>
void del(MDBRWTransaction& txn, const Class& t, uint32_t id)
{}
-
+
void openDB(std::shared_ptr<MDBEnv>& env, string_view str, int flags)
{
-
+
}
typedef uint32_t type; // dummy
};
#undef openMacro
}
-
+
// we get a lot of our smarts from this tuple, it enables get<0> etc
- typedef std::tuple<I1, I2, I3, I4> tuple_t;
+ typedef std::tuple<I1, I2, I3, I4> tuple_t;
tuple_t d_tuple;
// We support readonly and rw transactions. Here we put the Readonly operations
MDBOutVal data;
if((*d_parent.d_txn)->get(d_parent.d_parent->d_main, id, data))
return false;
-
+
serFromString(data.get<std::string>(), t);
return true;
}
if(d_end)
return;
d_prefix.clear();
-
+
if(d_cursor.get(d_key, d_id, MDB_GET_CURRENT)) {
d_end = true;
return;
d_cursor(std::move(cursor)),
d_on_index(true), // is this an iterator on main database or on index?
d_one_key(false),
- d_prefix(prefix),
+ d_prefix(prefix),
d_end(false)
{
if(d_end)
serFromString(d_id.get<std::string>(), d_t);
}
-
+
std::function<bool(const MDBOutVal&)> filter;
void del()
{
d_cursor.del();
}
-
+
bool operator!=(const eiter_t& rhs) const
{
return !d_end;
}
-
+
bool operator==(const eiter_t& rhs) const
{
return d_end;
}
-
+
const T& operator*()
{
return d_t;
}
-
+
const T* operator->()
{
return &d_t;
throw std::runtime_error("Missing id field");
if(filter && !filter(data))
goto next;
-
+
serFromString(data.get<std::string>(), d_t);
}
else {
if(filter && !filter(data))
goto next;
-
+
serFromString(d_id.get<std::string>(), d_t);
}
}
{
return d_key;
}
-
-
+
+
// transaction we are part of
Parent* d_parent;
typename Parent::cursor_t d_cursor;
iter_t genbegin(MDB_cursor_op op)
{
typename Parent::cursor_t cursor = (*d_parent.d_txn)->getCursor(std::get<N>(d_parent.d_parent->d_tuple).d_idx);
-
+
MDBOutVal out, id;
-
+
if(cursor.get(out, id, op)) {
// on_index, one_key, end
return iter_t{&d_parent, std::move(cursor), true, false, true};
iter_t begin()
{
typename Parent::cursor_t cursor = (*d_parent.d_txn)->getCursor(d_parent.d_parent->d_main);
-
+
MDBOutVal out, id;
-
+
if(cursor.get(out, id, MDB_FIRST)) {
- // on_index, one_key, end
+ // on_index, one_key, end
return iter_t{&d_parent, std::move(cursor), false, false, true};
}
MDBInVal in(keystr);
MDBOutVal out, id;
out.d_mdbval = in.d_mdbval;
-
+
if(cursor.get(out, id, op)) {
- // on_index, one_key, end
+ // on_index, one_key, end
return iter_t{&d_parent, std::move(cursor), true, false, true};
}
MDBInVal in(keyString);
MDBOutVal out, id;
out.d_mdbval = in.d_mdbval;
-
+
if(cursor.get(out, id, MDB_SET)) {
- // on_index, one_key, end
+ // on_index, one_key, end
return {iter_t{&d_parent, std::move(cursor), true, true, true}, eiter_t()};
}
MDBInVal in(keyString);
MDBOutVal out, id;
out.d_mdbval = in.d_mdbval;
-
+
if(cursor.get(out, id, MDB_SET_RANGE)) {
- // on_index, one_key, end
+ // on_index, one_key, end
return {iter_t{&d_parent, std::move(cursor), true, true, true}, eiter_t()};
}
return {iter_t(&d_parent, std::move(cursor), keyString), eiter_t()};
};
-
+
Parent& d_parent;
};
-
+
class ROTransaction : public ReadonlyOperations<ROTransaction>
{
public:
- explicit ROTransaction(TypedDBI* parent) : ReadonlyOperations<ROTransaction>(*this), d_parent(parent), d_txn(std::make_shared<MDBROTransaction>(d_parent->d_env->getROTransaction()))
+ explicit ROTransaction(TypedDBI* parent) : ReadonlyOperations<ROTransaction>(*this), d_parent(parent), d_txn(std::make_shared<MDBROTransaction>(d_parent->d_env->getROTransaction()))
{
}
- explicit ROTransaction(TypedDBI* parent, std::shared_ptr<MDBROTransaction> txn) : ReadonlyOperations<ROTransaction>(*this), d_parent(parent), d_txn(txn)
+ explicit ROTransaction(TypedDBI* parent, std::shared_ptr<MDBROTransaction> txn) : ReadonlyOperations<ROTransaction>(*this), d_parent(parent), d_txn(txn)
{
}
-
+
ROTransaction(ROTransaction&& rhs) :
ReadonlyOperations<ROTransaction>(*this), d_parent(rhs.d_parent),d_txn(std::move(rhs.d_txn))
-
+
{
rhs.d_parent = 0;
}
{
return d_txn;
}
-
+
typedef MDBROCursor cursor_t;
TypedDBI* d_parent;
- std::shared_ptr<MDBROTransaction> d_txn;
- };
+ std::shared_ptr<MDBROTransaction> d_txn;
+ };
+
-
class RWTransaction : public ReadonlyOperations<RWTransaction>
{
public:
{
}
-
+
RWTransaction(RWTransaction&& rhs) :
ReadonlyOperations<RWTransaction>(*this),
d_parent(rhs.d_parent), d_txn(std::move(rhs.d_txn))
void modify(uint32_t id, std::function<void(T&)> func)
{
T t;
- if(!this->get(id, t))
+ if(!this->get(id, t))
throw std::runtime_error("Could not modify id "+std::to_string(id));
func(t);
-
+
del(id); // this is the lazy way. We could test for changed index fields
put(t, id);
}
void del(uint32_t id)
{
T t;
- if(!this->get(id, t))
+ if(!this->get(id, t))
return;
-
+
(*d_txn)->del(d_parent->d_main, id);
clearIndex(id, t);
}
return d_txn;
}
-
+
private:
// clear this ID from all indexes
void clearIndex(uint32_t id, const T& t)
clearMacro(1);
clearMacro(2);
clearMacro(3);
-#undef clearMacro
+#undef clearMacro
}
public:
{
return d_env;
}
-
+
private:
std::shared_ptr<MDBEnv> d_env;
MDBDbi d_main;
std::string d_name;
};
-
-
-
-
-
//#include <ext/vstring.h>
-/* Quest in life:
+/* Quest in life:
accept escaped ascii presentations of DNS names and store them "natively"
accept a DNS packet with an offset, and extract a DNS name from it
build up DNSNames with prepend and append of 'raw' unescaped labels
Be able to turn them into ASCII and "DNS name in a packet" again on request
- Provide some common operators for comparison, detection of being part of another domain
+ Provide some common operators for comparison, detection of being part of another domain
NOTE: For now, everything MUST be . terminated, otherwise it is an error
*/
explicit DNSName(const char* p, size_t len); //!< Constructs from a human formatted, escaped presentation
explicit DNSName(const std::string& str) : DNSName(str.c_str(), str.length()) {}; //!< Constructs from a human formatted, escaped presentation
DNSName(const char* p, int len, int offset, bool uncompress, uint16_t* qtype=nullptr, uint16_t* qclass=nullptr, unsigned int* consumed=nullptr, uint16_t minOffset=0); //!< Construct from a DNS Packet, taking the first question if offset=12. If supplied, consumed is set to the number of bytes consumed from the packet, which will not be equal to the wire length of the resulting name in case of compression.
-
+
bool isPartOf(const DNSName& rhs) const; //!< Are we part of the rhs name? Note that name.isPartOf(name).
inline bool operator==(const DNSName& rhs) const; //!< DNS-native comparison (case insensitive) - empty compares to empty
bool operator!=(const DNSName& other) const { return !(*this == other); }
bool operator<(const DNSName& rhs) const // this delivers _some_ kind of ordering, but not one useful in a DNS context. Really fast though.
{
- return std::lexicographical_compare(d_storage.rbegin(), d_storage.rend(),
+ return std::lexicographical_compare(d_storage.rbegin(), d_storage.rend(),
rhs.d_storage.rbegin(), rhs.d_storage.rend(),
[](const unsigned char& a, const unsigned char& b) {
return dns_tolower(a) < dns_tolower(b);
}
inline bool canonCompare(const DNSName& rhs) const;
- bool slowCanonCompare(const DNSName& rhs) const;
+ bool slowCanonCompare(const DNSName& rhs) const;
#if BOOST_VERSION >= 105300
typedef boost::container::string string_t;
//
// 0,2,6,a
// 0,4,a
-
+
uint8_t ourpos[64], rhspos[64];
uint8_t ourcount=0, rhscount=0;
//cout<<"Asked to compare "<<toString()<<" to "<<rhs.toString()<<endl;
if(ourcount == sizeof(ourpos) || rhscount==sizeof(rhspos)) {
return slowCanonCompare(rhs);
}
-
+
for(;;) {
if(ourcount == 0 && rhscount != 0)
return true;
rhscount--;
bool res=std::lexicographical_compare(
- d_storage.c_str() + ourpos[ourcount] + 1,
+ d_storage.c_str() + ourpos[ourcount] + 1,
d_storage.c_str() + ourpos[ourcount] + 1 + *(d_storage.c_str() + ourpos[ourcount]),
- rhs.d_storage.c_str() + rhspos[rhscount] + 1,
+ rhs.d_storage.c_str() + rhspos[rhscount] + 1,
rhs.d_storage.c_str() + rhspos[rhscount] + 1 + *(rhs.d_storage.c_str() + rhspos[rhscount]),
[](const unsigned char& a, const unsigned char& b) {
return dns_tolower(a) < dns_tolower(b);
});
-
+
// cout<<"Forward: "<<res<<endl;
if(res)
return true;
- res=std::lexicographical_compare( rhs.d_storage.c_str() + rhspos[rhscount] + 1,
+ res=std::lexicographical_compare( rhs.d_storage.c_str() + rhspos[rhscount] + 1,
rhs.d_storage.c_str() + rhspos[rhscount] + 1 + *(rhs.d_storage.c_str() + rhspos[rhscount]),
- d_storage.c_str() + ourpos[ourcount] + 1,
+ d_storage.c_str() + ourpos[ourcount] + 1,
d_storage.c_str() + ourpos[ourcount] + 1 + *(d_storage.c_str() + ourpos[ourcount]),
[](const unsigned char& a, const unsigned char& b) {
return dns_tolower(a) < dns_tolower(b);
{
return strcasecmp(d_name.c_str(), rhs.d_name.c_str()) < 0;
}
-
+
std::string d_name;
mutable std::set<SuffixMatchTree, std::less<>> children;
mutable bool endNode;
}
DNSName::string_t segmentDNSNameRaw(const char* input, size_t inputlen); // from ragel
+
bool DNSName::operator==(const DNSName& rhs) const
{
- if(rhs.empty() != empty() || rhs.d_storage.size() != d_storage.size())
+ if (rhs.empty() != empty() || rhs.d_storage.size() != d_storage.size()) {
return false;
+ }
- auto us = d_storage.cbegin();
- auto p = rhs.d_storage.cbegin();
- for(; us != d_storage.cend() && p != rhs.d_storage.cend(); ++us, ++p) {
- if(dns_tolower(*p) != dns_tolower(*us))
+ const auto* us = d_storage.cbegin();
+ const auto* p = rhs.d_storage.cbegin();
+ for (; us != d_storage.cend() && p != rhs.d_storage.cend(); ++us, ++p) {
+ if (dns_tolower(*p) != dns_tolower(*us)) {
return false;
+ }
}
return true;
}
#include <stdexcept>
#include <iostream>
#include <vector>
-#include <errno.h>
+#include <cerrno>
// #include <netinet/in.h>
#include "misc.hh"
return lzrp < rzrp;
}
-
bool operator==(const DNSRecord& rhs) const
{
- if(d_type != rhs.d_type || d_class != rhs.d_class || d_name != rhs.d_name)
+ if (d_type != rhs.d_type || d_class != rhs.d_class || d_name != rhs.d_name) {
return false;
+ }
return *d_content == *rhs.d_content;
}
= 15
*/
const dnsheader_aligned dnsheaderdata(query.data());
- const struct dnsheader* dh = dnsheaderdata.get();
+ const struct dnsheader* dh = dnsheaderdata.get();
if (ntohs(dh->qdcount) != 1 || ntohs(dh->ancount) != 0 || ntohs(dh->nscount) != 0 || ntohs(dh->arcount) != 1 || (pos + 15) >= querySize || optionsToIgnore.empty()) {
return cachedQuery.compare(pos, cachedQuerySize - pos, query, pos, querySize - pos) == 0;
}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
+
#include "syncres.hh"
#include "arguments.hh"
#include "zoneparser-tng.hh"
ad.d_servers.clear();
vector<string> addresses;
- for (vector<string>::const_iterator iter = servers.begin(); iter != servers.end(); ++iter) {
- ComboAddress addr = parseIPAndPort(*iter, 53);
+ for (auto server = servers.begin(); server != servers.end(); ++server) {
+ ComboAddress addr = parseIPAndPort(*server, 53);
ad.d_servers.push_back(addr);
if (verbose) {
addresses.push_back(addr.toStringWithPort());
newSet->insert(ad.d_name);
}
}
- SLOG(g_log << Logger::Warning << "Done parsing " << newMap->size() - before << " forwarding instructions from file '" << ::arg()["forward-zones-file"] << "'" << endl,
- log->info(Logr::Notice, "Done parsing forwarding instructions from file", "file", Logging::Loggable(::arg()["forward-zones-file"]), "count", Logging::Loggable(newMap->size() - before)));
+ SLOG(g_log << Logger::Warning << "Done parsing " << newMap->size() - before
+ << " forwarding instructions from file '"
+ << ::arg()["forward-zones-file"] << "'" << endl,
+ log->info(Logr::Notice, "Done parsing forwarding instructions from file", "file",
+ Logging::Loggable(::arg()["forward-zones-file"]), "count",
+ Logging::Loggable(newMap->size() - before)));
}
if (::arg().mustDo("export-etc-hosts")) {
parts.clear();
stringtok(parts, ::arg()["allow-notify-for"], " ,\t\n\r");
- for (parts_t::const_iterator iter = parts.begin(); iter != parts.end(); ++iter) {
- newSet->insert(DNSName(*iter));
+ for (auto& part : parts) {
+ newSet->insert(DNSName(part));
}
if (auto anff = ::arg()["allow-notify-for-file"]; !anff.empty()) {
ordered_non_unique<tag<time_t>, member<EDNSStatus, time_t, &EDNSStatus::modeSetAt>>
>> {
void reset(index<ComboAddress>::type &ind, iterator it) {
- ind.modify(it, [](EDNSStatus &s) { s.mode = EDNSStatus::EDNSMode::UNKNOWN; s.modeSetAt = 0; });
+ ind.modify(it, [](EDNSStatus &s) { s.mode = EDNSStatus::EDNSMode::UNKNOWN; s.modeSetAt = 0; });
}
void setMode(index<ComboAddress>::type &ind, iterator it, EDNSStatus::EDNSMode mode) {
it->mode = mode;
static const int event_trace_to_log = 2;
static int s_event_trace_enabled;
static bool s_save_parent_ns_set;
-
+
std::unordered_map<std::string,bool> d_discardedPolicies;
DNSFilterEngine::Policy d_appliedPolicy;
std::unordered_set<std::string> d_policyTags;
return *this;
}
};
-