/* * This file is part of PowerDNS or dnsdist. * Copyright -- PowerDNS.COM B.V. and its contributors * * This program is free software; you can redistribute it and/or modify * it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation. * * In addition, for the avoidance of any doubt, permission is granted to * link this program with OpenSSL and to (re)distribute the binaries * produced as the result of such linking. * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::boost::multi_index; #include "dns.hh" #include #include #include #include #include #include #include #include #include #include #include #include "namespaces.hh" #include "dnsname.hh" typedef enum { TSIG_MD5, TSIG_SHA1, TSIG_SHA224, TSIG_SHA256, TSIG_SHA384, TSIG_SHA512, TSIG_GSS } TSIGHashEnum; string nowTime(); const string unquotify(const string &item); string humanDuration(time_t passed); bool stripDomainSuffix(string *qname, const string &domain); void stripLine(string &line); string getHostname(); string urlEncode(const string &text); int waitForData(int fd, int seconds, int useconds=0); int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fd); int waitForMultiData(const set& fds, const int seconds, const int useconds, int* fd); int waitForRWData(int fd, bool waitForRead, int seconds, int useconds, bool* error=nullptr, bool* disconnected=nullptr); uint16_t getShort(const unsigned char *p); uint16_t getShort(const char *p); uint32_t getLong(const unsigned char *p); uint32_t getLong(const char *p); bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum); DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum); int logFacilityToLOG(unsigned int facility); struct ServiceTuple { string host; uint16_t port; }; void parseService(const string &descr, ServiceTuple &st); template void stringtok (Container &container, string const &in, const char * const delimiters = " \t\n") { const string::size_type len = in.length(); string::size_type i = 0; while (i bool rfc1982LessThan(T a, T b) { static_assert(std::is_unsigned::value, "rfc1982LessThan only works for unsigned types"); typedef typename std::make_signed::type signed_t; return static_cast(a - b) < 0; } // fills container with ranges, so {posbegin,posend} template void vstringtok (Container &container, string const &in, const char * const delimiters = " \t\n") { const string::size_type len = in.length(); string::size_type i = 0; while (i AtomicCounter ; // FIXME400 this should probably go? struct CIStringCompare { bool operator()(const string& a, const string& b) const { return pdns_ilexicographical_compare(a, b); } }; struct CIStringComparePOSIX { bool operator() (const std::string& lhs, const std::string& rhs) { std::string::const_iterator a,b; const std::locale &loc = std::locale("POSIX"); a=lhs.begin();b=rhs.begin(); while(a!=lhs.end()) { if (b==rhs.end() || std::tolower(*b,loc)& a, const pair& b) const { if(pdns_ilexicographical_compare(a.first, b.first)) return true; if(pdns_ilexicographical_compare(b.first, a.first)) return false; return a.second < b.second; } }; inline size_t pdns_ci_find(const string& haystack, const string& needle) { string::const_iterator it = std::search(haystack.begin(), haystack.end(), needle.begin(), needle.end(), pdns_iequals_ch); if (it == haystack.end()) { // not found return string::npos; } else { return it - haystack.begin(); } } pair splitField(const string& inp, char sepa); inline bool isCanonical(const string& qname) { if(qname.empty()) return false; return qname[qname.size()-1]=='.'; } inline DNSName toCanonic(const DNSName& zone, const string& qname) { if(qname.size()==1 && qname[0]=='@') return zone; if(isCanonical(qname)) return DNSName(qname); return DNSName(qname) += zone; } string stripDot(const string& dom); int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret); int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret); int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret); bool stringfgets(FILE* fp, std::string& line); template std::pair replacing_insert(Index& i,const typename Index::value_type& x) { std::pair res=i.insert(x); if(!res.second)res.second=i.replace(res.first,x); return res; } /** very small regex wrapper */ class Regex { public: /** constructor that accepts the expression to regex */ Regex(const string &expr); ~Regex() { regfree(&d_preg); } /** call this to find out if 'line' matches your expression */ bool match(const string &line) const { return regexec(&d_preg,line.c_str(),0,0,0)==0; } bool match(const DNSName& name) const { return match(name.toStringNoDot()); } private: regex_t d_preg; }; class SimpleMatch { public: SimpleMatch(const string &mask, bool caseFold = false): d_mask(mask), d_fold(caseFold) { } bool match(string::const_iterator mi, string::const_iterator mend, string::const_iterator vi, string::const_iterator vend) const { for(;;++mi) { if (mi == mend) { return vi == vend; } else if (*mi == '?') { if (vi == vend) return false; ++vi; } else if (*mi == '*') { while(mi != mend && *mi == '*') ++mi; if (mi == mend) return true; while(vi != vend) { if (match(mi,mend,vi,vend)) return true; ++vi; } return false; } else { if ((mi == mend && vi != vend)|| (mi != mend && vi == vend)) return false; if (d_fold) { if (dns_tolower(*mi) != dns_tolower(*vi)) return false; } else { if (*mi != *vi) return false; } ++vi; } } } bool match(const string& value) const { return match(d_mask.begin(), d_mask.end(), value.begin(), value.end()); } bool match(const DNSName& name) const { return match(name.toStringNoDot()); } private: const string d_mask; const bool d_fold; }; union ComboAddress; // An aligned type to hold cmsgbufs. See https://man.openbsd.org/CMSG_DATA typedef union { struct cmsghdr hdr; char buf[256]; } cmsgbuf_aligned; /* itfIndex is an interface index, as returned by if_nametoindex(). 0 means default. */ void addCMsgSrcAddr(struct msghdr* msgh, cmsgbuf_aligned* cbuf, const ComboAddress* source, int itfIndex); unsigned int getFilenumLimit(bool hardOrSoft=0); void setFilenumLimit(unsigned int lim); bool readFileIfThere(const char* fname, std::string* line); uint32_t burtle(const unsigned char* k, uint32_t length, uint32_t init); bool setSocketTimestamps(int fd); //! Sets the socket into blocking mode. bool setBlocking( int sock ); //! Sets the socket into non-blocking mode. bool setNonBlocking( int sock ); bool setTCPNoDelay(int sock); bool setReuseAddr(int sock); bool isNonBlocking(int sock); bool setReceiveSocketErrors(int sock, int af); int closesocket(int fd); bool setCloseOnExec(int sock); size_t getPipeBufferSize(int fd); bool setPipeBufferSize(int fd, size_t size); uint64_t udpErrorStats(const std::string& str); uint64_t udp6ErrorStats(const std::string& str); uint64_t tcpErrorStats(const std::string& str); uint64_t getRealMemoryUsage(const std::string&); uint64_t getSpecialMemoryUsage(const std::string&); uint64_t getOpenFileDescriptors(const std::string&); uint64_t getCPUTimeUser(const std::string&); uint64_t getCPUTimeSystem(const std::string&); uint64_t getCPUIOWait(const std::string&); uint64_t getCPUSteal(const std::string&); std::string getMACAddress(const ComboAddress& ca); template const T& defTer(const T& a, const T& b) { return a ? a : b; } template T valueOrEmpty(const P val) { if (!val) return T{}; return T(val); } // I'm not very OCD, but I appreciate loglines like "processing 1 delta", "processing 2 deltas" :-) template ::value, bool> = true> const char* addS(Integer siz, const char* singular = "", const char *plural = "s") { if (siz == 1) { return singular; } return plural; } template ::value, bool> = true> const char* addS(const C& c, const char* singular = "", const char *plural = "s") { return addS(c.size(), singular, plural); } template const typename C::value_type::second_type* rplookup(const C& c, const typename C::value_type::first_type& key) { auto fnd = c.find(key); if(fnd == c.end()) return 0; return &fnd->second; } double DiffTime(const struct timespec& first, const struct timespec& second); double DiffTime(const struct timeval& first, const struct timeval& second); uid_t strToUID(const string &str); gid_t strToGID(const string &str); unsigned int pdns_stou(const std::string& str, size_t * idx = 0, int base = 10); bool isSettingThreadCPUAffinitySupported(); int mapThreadToCPUList(pthread_t tid, const std::set& cpus); std::vector getResolvers(const std::string& resolvConfPath); DNSName reverseNameFromIP(const ComboAddress& ip); std::string getCarbonHostName(); size_t parseRFC1035CharString(const std::string &in, std::string &val); // from ragel size_t parseSVCBValueListFromParsedRFC1035CharString(const std::string &in, vector &val); // from ragel size_t parseSVCBValueList(const std::string &in, vector &val); std::string makeLuaString(const std::string& in); bool constantTimeStringEquals(const std::string& a, const std::string& b); // Used in NID and L64 records struct NodeOrLocatorID { uint8_t content[8]; }; struct FDWrapper { FDWrapper() { } FDWrapper(int desc): d_fd(desc) { } ~FDWrapper() { if (d_fd != -1) { close(d_fd); d_fd = -1; } } FDWrapper(FDWrapper&& rhs): d_fd(rhs.d_fd) { rhs.d_fd = -1; } FDWrapper& operator=(FDWrapper&& rhs) { if (d_fd != -1) { close(d_fd); } d_fd = rhs.d_fd; rhs.d_fd = -1; return *this; } int getHandle() const { return d_fd; } operator int() const { return d_fd; } private: int d_fd{-1}; };