You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

777 lines
22 KiB

  1. /*
  2. * This file is part of PowerDNS or dnsdist.
  3. * Copyright -- PowerDNS.COM B.V. and its contributors
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of version 2 of the GNU General Public License as
  7. * published by the Free Software Foundation.
  8. *
  9. * In addition, for the avoidance of any doubt, permission is granted to
  10. * link this program with OpenSSL and to (re)distribute the binaries
  11. * produced as the result of such linking.
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. */
  22. #include <cinttypes>
  23. #include <iostream>
  24. #include "filterpo.hh"
  25. #include "namespaces.hh"
  26. #include "dnsrecords.hh"
  27. // Names below are RPZ Actions and end with a dot (except "Local Data")
  28. static const std::string rpzDropName("rpz-drop."),
  29. rpzTruncateName("rpz-tcp-only."),
  30. rpzNoActionName("rpz-passthru."),
  31. rpzCustomName("Local Data");
  32. // Names below are (part) of RPZ Trigger names and do NOT end with a dot
  33. static const std::string rpzClientIPName("rpz-client-ip"),
  34. rpzIPName("rpz-ip"),
  35. rpzNSDnameName("rpz-nsdname"),
  36. rpzNSIPName("rpz-nsip");
  37. DNSFilterEngine::DNSFilterEngine()
  38. {
  39. }
  40. bool DNSFilterEngine::Zone::findExactQNamePolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const
  41. {
  42. return findExactNamedPolicy(d_qpolName, qname, pol);
  43. }
  44. bool DNSFilterEngine::Zone::findExactNSPolicy(const DNSName& qname, DNSFilterEngine::Policy& pol) const
  45. {
  46. return findExactNamedPolicy(d_propolName, qname, pol);
  47. }
  48. bool DNSFilterEngine::Zone::findNSIPPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const
  49. {
  50. if (const auto fnd = d_propolNSAddr.lookup(addr)) {
  51. pol = fnd->second;
  52. return true;
  53. }
  54. return false;
  55. }
  56. bool DNSFilterEngine::Zone::findResponsePolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const
  57. {
  58. if (const auto fnd = d_postpolAddr.lookup(addr)) {
  59. pol = fnd->second;
  60. return true;
  61. }
  62. return false;
  63. }
  64. bool DNSFilterEngine::Zone::findClientPolicy(const ComboAddress& addr, DNSFilterEngine::Policy& pol) const
  65. {
  66. if (const auto fnd = d_qpolAddr.lookup(addr)) {
  67. pol = fnd->second;
  68. return true;
  69. }
  70. return false;
  71. }
  72. bool DNSFilterEngine::Zone::findNamedPolicy(const std::unordered_map<DNSName, DNSFilterEngine::Policy>& polmap, const DNSName& qname, DNSFilterEngine::Policy& pol)
  73. {
  74. if (polmap.empty()) {
  75. return false;
  76. }
  77. /* for www.powerdns.com, we need to check:
  78. www.powerdns.com.
  79. *.powerdns.com.
  80. *.com.
  81. *.
  82. */
  83. std::unordered_map<DNSName, DNSFilterEngine::Policy>::const_iterator iter;
  84. iter = polmap.find(qname);
  85. if(iter != polmap.end()) {
  86. pol=iter->second;
  87. return true;
  88. }
  89. DNSName s(qname);
  90. while(s.chopOff()){
  91. iter = polmap.find(g_wildcarddnsname+s);
  92. if(iter != polmap.end()) {
  93. pol=iter->second;
  94. pol.d_trigger = iter->first;
  95. pol.d_hit = qname.toStringNoDot();
  96. return true;
  97. }
  98. }
  99. return false;
  100. }
  101. bool DNSFilterEngine::Zone::findExactNamedPolicy(const std::unordered_map<DNSName, DNSFilterEngine::Policy>& polmap, const DNSName& qname, DNSFilterEngine::Policy& pol)
  102. {
  103. if (polmap.empty()) {
  104. return false;
  105. }
  106. const auto& it = polmap.find(qname);
  107. if (it != polmap.end()) {
  108. pol = it->second;
  109. pol.d_trigger = qname;
  110. pol.d_hit = qname.toStringNoDot();
  111. return true;
  112. }
  113. return false;
  114. }
  115. bool DNSFilterEngine::getProcessingPolicy(const DNSName& qname, const std::unordered_map<std::string,bool>& discardedPolicies, Policy& pol) const
  116. {
  117. // cout<<"Got question for nameserver name "<<qname<<endl;
  118. std::vector<bool> zoneEnabled(d_zones.size());
  119. size_t count = 0;
  120. bool allEmpty = true;
  121. for (const auto& z : d_zones) {
  122. bool enabled = true;
  123. const auto& zoneName = z->getName();
  124. if (z->getPriority() >= pol.getPriority()) {
  125. enabled = false;
  126. }
  127. else if (discardedPolicies.find(zoneName) != discardedPolicies.end()) {
  128. enabled = false;
  129. }
  130. else {
  131. if (z->hasNSPolicies()) {
  132. allEmpty = false;
  133. }
  134. else {
  135. enabled = false;
  136. }
  137. }
  138. zoneEnabled[count] = enabled;
  139. ++count;
  140. }
  141. if (allEmpty) {
  142. return false;
  143. }
  144. /* prepare the wildcard-based names */
  145. std::vector<DNSName> wcNames;
  146. wcNames.reserve(qname.countLabels());
  147. DNSName s(qname);
  148. while (s.chopOff()){
  149. wcNames.emplace_back(g_wildcarddnsname+s);
  150. }
  151. count = 0;
  152. for(const auto& z : d_zones) {
  153. if (!zoneEnabled[count]) {
  154. ++count;
  155. continue;
  156. }
  157. if (z->findExactNSPolicy(qname, pol)) {
  158. // cerr<<"Had a hit on the nameserver ("<<qname<<") used to process the query"<<endl;
  159. pol.d_trigger = qname;
  160. pol.d_trigger.appendRawLabel(rpzNSDnameName);
  161. pol.d_hit = qname.toStringNoDot();
  162. return true;
  163. }
  164. for (const auto& wc : wcNames) {
  165. if (z->findExactNSPolicy(wc, pol)) {
  166. // cerr<<"Had a hit on the nameserver ("<<qname<<") used to process the query"<<endl;
  167. pol.d_trigger = wc;
  168. pol.d_trigger.appendRawLabel(rpzNSDnameName);
  169. pol.d_hit = qname.toStringNoDot();
  170. return true;
  171. }
  172. }
  173. ++count;
  174. }
  175. return false;
  176. }
  177. bool DNSFilterEngine::getProcessingPolicy(const ComboAddress& address, const std::unordered_map<std::string,bool>& discardedPolicies, Policy& pol) const
  178. {
  179. // cout<<"Got question for nameserver IP "<<address.toString()<<endl;
  180. for(const auto& z : d_zones) {
  181. if (z->getPriority() >= pol.getPriority()) {
  182. break;
  183. }
  184. const auto& zoneName = z->getName();
  185. if (discardedPolicies.find(zoneName) != discardedPolicies.end()) {
  186. continue;
  187. }
  188. if(z->findNSIPPolicy(address, pol)) {
  189. // cerr<<"Had a hit on the nameserver ("<<address.toString()<<") used to process the query"<<endl;
  190. // XXX should use ns RPZ
  191. pol.d_trigger = Zone::maskToRPZ(address);
  192. pol.d_trigger.appendRawLabel(rpzNSIPName);
  193. pol.d_hit = address.toString();
  194. return true;
  195. }
  196. }
  197. return false;
  198. }
  199. bool DNSFilterEngine::getClientPolicy(const ComboAddress& ca, const std::unordered_map<std::string,bool>& discardedPolicies, Policy& pol) const
  200. {
  201. // cout<<"Got question from "<<ca.toString()<<endl;
  202. for (const auto& z : d_zones) {
  203. if (z->getPriority() >= pol.getPriority()) {
  204. break;
  205. }
  206. const auto& zoneName = z->getName();
  207. if (discardedPolicies.find(zoneName) != discardedPolicies.end()) {
  208. continue;
  209. }
  210. if (z->findClientPolicy(ca, pol)) {
  211. // cerr<<"Had a hit on the IP address ("<<ca.toString()<<") of the client"<<endl;
  212. return true;
  213. }
  214. }
  215. return false;
  216. }
  217. bool DNSFilterEngine::getQueryPolicy(const DNSName& qname, const std::unordered_map<std::string,bool>& discardedPolicies, Policy& pol) const
  218. {
  219. //cerr<<"Got question for "<<qname<<' '<< pol.getPriority()<< endl;
  220. std::vector<bool> zoneEnabled(d_zones.size());
  221. size_t count = 0;
  222. bool allEmpty = true;
  223. for (const auto& z : d_zones) {
  224. bool enabled = true;
  225. if (z->getPriority() >= pol.getPriority()) {
  226. enabled = false;
  227. } else {
  228. const auto& zoneName = z->getName();
  229. if (discardedPolicies.find(zoneName) != discardedPolicies.end()) {
  230. enabled = false;
  231. }
  232. else {
  233. if (z->hasQNamePolicies()) {
  234. allEmpty = false;
  235. }
  236. else {
  237. enabled = false;
  238. }
  239. }
  240. }
  241. zoneEnabled[count] = enabled;
  242. ++count;
  243. }
  244. if (allEmpty) {
  245. return false;
  246. }
  247. /* prepare the wildcard-based names */
  248. std::vector<DNSName> wcNames;
  249. wcNames.reserve(qname.countLabels());
  250. DNSName s(qname);
  251. while (s.chopOff()){
  252. wcNames.emplace_back(g_wildcarddnsname+s);
  253. }
  254. count = 0;
  255. for (const auto& z : d_zones) {
  256. if (!zoneEnabled[count]) {
  257. ++count;
  258. continue;
  259. }
  260. if (z->findExactQNamePolicy(qname, pol)) {
  261. // cerr<<"Had a hit on the name of the query"<<endl;
  262. pol.d_trigger = qname;
  263. pol.d_hit = qname.toStringNoDot();
  264. return true;
  265. }
  266. for (const auto& wc : wcNames) {
  267. if (z->findExactQNamePolicy(wc, pol)) {
  268. // cerr<<"Had a hit on the name of the query"<<endl;
  269. pol.d_trigger = wc;
  270. pol.d_hit = qname.toStringNoDot();
  271. return true;
  272. }
  273. }
  274. ++count;
  275. }
  276. return false;
  277. }
  278. bool DNSFilterEngine::getPostPolicy(const vector<DNSRecord>& records, const std::unordered_map<std::string,bool>& discardedPolicies, Policy& pol) const
  279. {
  280. for (const auto& record : records) {
  281. if (getPostPolicy(record, discardedPolicies, pol)) {
  282. return true;
  283. }
  284. }
  285. return false;
  286. }
  287. bool DNSFilterEngine::getPostPolicy(const DNSRecord& record, const std::unordered_map<std::string,bool>& discardedPolicies, Policy& pol) const
  288. {
  289. ComboAddress ca;
  290. if (record.d_place != DNSResourceRecord::ANSWER) {
  291. return false;
  292. }
  293. if (record.d_type == QType::A) {
  294. if (auto rec = getRR<ARecordContent>(record)) {
  295. ca = rec->getCA();
  296. }
  297. }
  298. else if(record.d_type == QType::AAAA) {
  299. if (auto rec = getRR<AAAARecordContent>(record)) {
  300. ca = rec->getCA();
  301. }
  302. }
  303. else {
  304. return false;
  305. }
  306. for (const auto& z : d_zones) {
  307. if (z->getPriority() >= pol.getPriority()) {
  308. break;
  309. }
  310. const auto& zoneName = z->getName();
  311. if (discardedPolicies.find(zoneName) != discardedPolicies.end()) {
  312. return false;
  313. }
  314. if (z->findResponsePolicy(ca, pol)) {
  315. pol.d_trigger = Zone::maskToRPZ(ca);
  316. pol.d_trigger.appendRawLabel(rpzIPName);
  317. pol.d_hit = ca.toString();
  318. return true;
  319. }
  320. }
  321. return false;
  322. }
  323. void DNSFilterEngine::assureZones(size_t zone)
  324. {
  325. if(d_zones.size() <= zone)
  326. d_zones.resize(zone+1);
  327. }
  328. void DNSFilterEngine::Zone::addNameTrigger(std::unordered_map<DNSName,Policy>& map, const DNSName& n, Policy&& pol, bool ignoreDuplicate, PolicyType ptype)
  329. {
  330. auto it = map.find(n);
  331. if (it != map.end()) {
  332. auto& existingPol = it->second;
  333. if (pol.d_kind != PolicyKind::Custom && !ignoreDuplicate) {
  334. throw std::runtime_error("Adding a " + getTypeToString(ptype) + "-based filter policy of kind " + getKindToString(pol.d_kind) + " but a policy of kind " + getKindToString(existingPol.d_kind) + " already exists for the following name: " + n.toLogString());
  335. }
  336. if (existingPol.d_kind != PolicyKind::Custom && ignoreDuplicate) {
  337. throw std::runtime_error("Adding a " + getTypeToString(ptype) + "-based filter policy of kind " + getKindToString(existingPol.d_kind) + " but there was already an existing policy for the following name: " + n.toLogString());
  338. }
  339. existingPol.d_custom.reserve(existingPol.d_custom.size() + pol.d_custom.size());
  340. std::move(pol.d_custom.begin(), pol.d_custom.end(), std::back_inserter(existingPol.d_custom));
  341. }
  342. else {
  343. auto& qpol = map.insert({n, std::move(pol)}).first->second;
  344. qpol.d_zoneData = d_zoneData;
  345. qpol.d_type = ptype;
  346. }
  347. }
  348. void DNSFilterEngine::Zone::addNetmaskTrigger(NetmaskTree<Policy>& nmt, const Netmask& nm, Policy&& pol, bool ignoreDuplicate, PolicyType ptype)
  349. {
  350. bool exists = nmt.has_key(nm);
  351. if (exists) {
  352. // XXX NetMaskTree's node_type has a non-const second, but lookup() returns a const node_type *, so we cannot modify second
  353. // Should look into making lookup) return a non-const node_type *...
  354. auto& existingPol = const_cast<Policy&>(nmt.lookup(nm)->second);
  355. if (pol.d_kind != PolicyKind::Custom && !ignoreDuplicate) {
  356. throw std::runtime_error("Adding a " + getTypeToString(ptype) + "-based filter policy of kind " + getKindToString(pol.d_kind) + " but a policy of kind " + getKindToString(existingPol.d_kind) + " already exists for the following netmask: " + nm.toString());
  357. }
  358. if (existingPol.d_kind != PolicyKind::Custom && ignoreDuplicate) {
  359. throw std::runtime_error("Adding a " + getTypeToString(ptype) + "-based filter policy of kind " + getKindToString(existingPol.d_kind) + " but there was already an existing policy for the following netmask: " + nm.toString());
  360. }
  361. existingPol.d_custom.reserve(existingPol.d_custom.size() + pol.d_custom.size());
  362. std::move(pol.d_custom.begin(), pol.d_custom.end(), std::back_inserter(existingPol.d_custom));
  363. }
  364. else {
  365. pol.d_zoneData = d_zoneData;
  366. pol.d_type = ptype;
  367. nmt.insert(nm).second = std::move(pol);
  368. }
  369. }
  370. bool DNSFilterEngine::Zone::rmNameTrigger(std::unordered_map<DNSName,Policy>& map, const DNSName& n, const Policy& pol)
  371. {
  372. auto found = map.find(n);
  373. if (found == map.end()) {
  374. return false;
  375. }
  376. auto& existing = found->second;
  377. if (existing.d_kind != DNSFilterEngine::PolicyKind::Custom) {
  378. map.erase(found);
  379. return true;
  380. }
  381. /* for custom types, we might have more than one type,
  382. and then we need to remove only the right ones. */
  383. bool result = false;
  384. for (auto& toRemove : pol.d_custom) {
  385. for (auto it = existing.d_custom.begin(); it != existing.d_custom.end(); ++it) {
  386. if (**it == *toRemove) {
  387. existing.d_custom.erase(it);
  388. result = true;
  389. break;
  390. }
  391. }
  392. }
  393. // No records left for this trigger?
  394. if (existing.d_custom.size() == 0) {
  395. map.erase(found);
  396. return true;
  397. }
  398. return result;
  399. }
  400. bool DNSFilterEngine::Zone::rmNetmaskTrigger(NetmaskTree<Policy>& nmt, const Netmask& nm, const Policy& pol)
  401. {
  402. bool found = nmt.has_key(nm);
  403. if (!found) {
  404. return false;
  405. }
  406. // XXX NetMaskTree's node_type has a non-const second, but lookup() returns a const node_type *, so we cannot modify second
  407. // Should look into making lookup) return a non-const node_type *...
  408. auto& existing = const_cast<Policy&>(nmt.lookup(nm)->second);
  409. if (existing.d_kind != DNSFilterEngine::PolicyKind::Custom) {
  410. nmt.erase(nm);
  411. return true;
  412. }
  413. /* for custom types, we might have more than one type,
  414. and then we need to remove only the right ones. */
  415. bool result = false;
  416. for (auto& toRemove : pol.d_custom) {
  417. for (auto it = existing.d_custom.begin(); it != existing.d_custom.end(); ++it) {
  418. if (**it == *toRemove) {
  419. existing.d_custom.erase(it);
  420. result = true;
  421. break;
  422. }
  423. }
  424. }
  425. // No records left for this trigger?
  426. if (existing.d_custom.size() == 0) {
  427. nmt.erase(nm);
  428. return true;
  429. }
  430. return result;
  431. }
  432. void DNSFilterEngine::Zone::addClientTrigger(const Netmask& nm, Policy&& pol, bool ignoreDuplicate)
  433. {
  434. addNetmaskTrigger(d_qpolAddr, nm, std::move(pol), ignoreDuplicate, PolicyType::ClientIP);
  435. }
  436. void DNSFilterEngine::Zone::addResponseTrigger(const Netmask& nm, Policy&& pol, bool ignoreDuplicate)
  437. {
  438. addNetmaskTrigger(d_postpolAddr, nm, std::move(pol), ignoreDuplicate, PolicyType::ResponseIP);
  439. }
  440. void DNSFilterEngine::Zone::addQNameTrigger(const DNSName& n, Policy&& pol, bool ignoreDuplicate)
  441. {
  442. addNameTrigger(d_qpolName, n, std::move(pol), ignoreDuplicate, PolicyType::QName);
  443. }
  444. void DNSFilterEngine::Zone::addNSTrigger(const DNSName& n, Policy&& pol, bool ignoreDuplicate)
  445. {
  446. addNameTrigger(d_propolName, n, std::move(pol), ignoreDuplicate, PolicyType::NSDName);
  447. }
  448. void DNSFilterEngine::Zone::addNSIPTrigger(const Netmask& nm, Policy&& pol, bool ignoreDuplicate)
  449. {
  450. addNetmaskTrigger(d_propolNSAddr, nm, std::move(pol), ignoreDuplicate, PolicyType::NSIP);
  451. }
  452. bool DNSFilterEngine::Zone::rmClientTrigger(const Netmask& nm, const Policy& pol)
  453. {
  454. return rmNetmaskTrigger(d_qpolAddr, nm, pol);
  455. }
  456. bool DNSFilterEngine::Zone::rmResponseTrigger(const Netmask& nm, const Policy& pol)
  457. {
  458. return rmNetmaskTrigger(d_postpolAddr, nm, pol);
  459. }
  460. bool DNSFilterEngine::Zone::rmQNameTrigger(const DNSName& n, const Policy& pol)
  461. {
  462. return rmNameTrigger(d_qpolName, n, pol);
  463. }
  464. bool DNSFilterEngine::Zone::rmNSTrigger(const DNSName& n, const Policy& pol)
  465. {
  466. return rmNameTrigger(d_propolName, n, pol);
  467. }
  468. bool DNSFilterEngine::Zone::rmNSIPTrigger(const Netmask& nm, const Policy& pol)
  469. {
  470. return rmNetmaskTrigger(d_propolNSAddr, nm, pol);
  471. }
  472. std::string DNSFilterEngine::Policy::getLogString() const {
  473. return ": RPZ Hit; PolicyName=" + getName() + "; Trigger=" + d_trigger.toLogString() + "; Hit=" + d_hit + "; Type=" + getTypeToString(d_type) + "; Kind=" + getKindToString(d_kind);
  474. }
  475. DNSRecord DNSFilterEngine::Policy::getRecordFromCustom(const DNSName& qname, const std::shared_ptr<DNSRecordContent>& custom) const
  476. {
  477. DNSRecord dr;
  478. dr.d_name = qname;
  479. dr.d_type = custom->getType();
  480. dr.d_ttl = d_ttl;
  481. dr.d_class = QClass::IN;
  482. dr.d_place = DNSResourceRecord::ANSWER;
  483. dr.d_content = custom;
  484. if (dr.d_type == QType::CNAME) {
  485. const auto content = std::dynamic_pointer_cast<CNAMERecordContent>(custom);
  486. if (content) {
  487. DNSName target = content->getTarget();
  488. if (target.isWildcard()) {
  489. target.chopOff();
  490. dr.d_content = std::make_shared<CNAMERecordContent>(qname + target);
  491. }
  492. }
  493. }
  494. return dr;
  495. }
  496. std::vector<DNSRecord> DNSFilterEngine::Policy::getCustomRecords(const DNSName& qname, uint16_t qtype) const
  497. {
  498. if (d_kind != PolicyKind::Custom) {
  499. throw std::runtime_error("Asking for a custom record from a filtering policy of a non-custom type");
  500. }
  501. std::vector<DNSRecord> result;
  502. for (const auto& custom : d_custom) {
  503. if (qtype != QType::ANY && qtype != custom->getType() && custom->getType() != QType::CNAME) {
  504. continue;
  505. }
  506. DNSRecord dr;
  507. dr.d_name = qname;
  508. dr.d_type = custom->getType();
  509. dr.d_ttl = d_ttl;
  510. dr.d_class = QClass::IN;
  511. dr.d_place = DNSResourceRecord::ANSWER;
  512. dr.d_content = custom;
  513. if (dr.d_type == QType::CNAME) {
  514. const auto content = std::dynamic_pointer_cast<CNAMERecordContent>(custom);
  515. if (content) {
  516. DNSName target = content->getTarget();
  517. if (target.isWildcard()) {
  518. target.chopOff();
  519. dr.d_content = std::make_shared<CNAMERecordContent>(qname + target);
  520. }
  521. }
  522. }
  523. result.emplace_back(getRecordFromCustom(qname, custom));
  524. }
  525. return result;
  526. }
  527. std::string DNSFilterEngine::getKindToString(DNSFilterEngine::PolicyKind kind)
  528. {
  529. //static const std::string rpzPrefix("rpz-");
  530. switch(kind) {
  531. case DNSFilterEngine::PolicyKind::NoAction:
  532. return rpzNoActionName;
  533. case DNSFilterEngine::PolicyKind::Drop:
  534. return rpzDropName;
  535. case DNSFilterEngine::PolicyKind::NXDOMAIN:
  536. return g_rootdnsname.toString();
  537. case PolicyKind::NODATA:
  538. return g_wildcarddnsname.toString();
  539. case DNSFilterEngine::PolicyKind::Truncate:
  540. return rpzTruncateName;
  541. case DNSFilterEngine::PolicyKind::Custom:
  542. return rpzCustomName;
  543. default:
  544. throw std::runtime_error("Unexpected DNSFilterEngine::Policy kind");
  545. }
  546. }
  547. std::string DNSFilterEngine::getTypeToString(DNSFilterEngine::PolicyType type)
  548. {
  549. switch(type) {
  550. case DNSFilterEngine::PolicyType::None:
  551. return "none";
  552. case DNSFilterEngine::PolicyType::QName:
  553. return "QName";
  554. case DNSFilterEngine::PolicyType::ClientIP:
  555. return "Client IP";
  556. case DNSFilterEngine::PolicyType::ResponseIP:
  557. return "Response IP";
  558. case DNSFilterEngine::PolicyType::NSDName:
  559. return "Name Server Name";
  560. case DNSFilterEngine::PolicyType::NSIP:
  561. return "Name Server IP";
  562. default:
  563. throw std::runtime_error("Unexpected DNSFilterEngine::Policy type");
  564. }
  565. }
  566. std::vector<DNSRecord> DNSFilterEngine::Policy::getRecords(const DNSName& qname) const
  567. {
  568. std::vector<DNSRecord> result;
  569. if (d_kind == PolicyKind::Custom) {
  570. result = getCustomRecords(qname, QType::ANY);
  571. }
  572. else {
  573. DNSRecord dr;
  574. dr.d_name = qname;
  575. dr.d_ttl = static_cast<uint32_t>(d_ttl);
  576. dr.d_type = QType::CNAME;
  577. dr.d_class = QClass::IN;
  578. dr.d_content = DNSRecordContent::mastermake(QType::CNAME, QClass::IN, getKindToString(d_kind));
  579. result.push_back(std::move(dr));
  580. }
  581. return result;
  582. }
  583. void DNSFilterEngine::Zone::dumpNamedPolicy(FILE* fp, const DNSName& name, const Policy& pol)
  584. {
  585. auto records = pol.getRecords(name);
  586. for (const auto& dr : records) {
  587. fprintf(fp, "%s %" PRIu32 " IN %s %s\n", dr.d_name.toString().c_str(), dr.d_ttl, QType(dr.d_type).getName().c_str(), dr.d_content->getZoneRepresentation().c_str());
  588. }
  589. }
  590. DNSName DNSFilterEngine::Zone::maskToRPZ(const Netmask& nm)
  591. {
  592. int bits = nm.getBits();
  593. DNSName res(std::to_string(bits));
  594. const auto& addr = nm.getNetwork();
  595. if (addr.isIPv4()) {
  596. const uint8_t* bytes = reinterpret_cast<const uint8_t*>(&addr.sin4.sin_addr.s_addr);
  597. res += DNSName(std::to_string(bytes[3]) + "." + std::to_string(bytes[2]) + "." + std::to_string(bytes[1]) + "." + std::to_string(bytes[0]));
  598. }
  599. else {
  600. DNSName temp;
  601. const auto str = addr.toString();
  602. const auto len = str.size();
  603. std::string::size_type begin = 0;
  604. while (begin < len) {
  605. std::string::size_type end = str.find(":", begin);
  606. std::string sub;
  607. if (end != string::npos) {
  608. sub = str.substr(begin, end - begin);
  609. }
  610. else {
  611. sub = str.substr(begin);
  612. }
  613. if (sub.empty()) {
  614. temp = DNSName("zz") + temp;
  615. }
  616. else {
  617. temp = DNSName(sub) + temp;
  618. }
  619. if (end == string::npos) {
  620. break;
  621. }
  622. begin = end + 1;
  623. }
  624. res += temp;
  625. }
  626. return res;
  627. }
  628. void DNSFilterEngine::Zone::dumpAddrPolicy(FILE* fp, const Netmask& nm, const DNSName& name, const Policy& pol)
  629. {
  630. DNSName full = maskToRPZ(nm);
  631. full += name;
  632. auto records = pol.getRecords(full);
  633. for (const auto& dr : records) {
  634. fprintf(fp, "%s %" PRIu32 " IN %s %s\n", dr.d_name.toString().c_str(), dr.d_ttl, QType(dr.d_type).getName().c_str(), dr.d_content->getZoneRepresentation().c_str());
  635. }
  636. }
  637. void DNSFilterEngine::Zone::dump(FILE* fp) const
  638. {
  639. /* fake the SOA record */
  640. auto soa = DNSRecordContent::mastermake(QType::SOA, QClass::IN, "fake.RPZ. hostmaster.fake.RPZ. " + std::to_string(d_serial) + " " + std::to_string(d_refresh) + " 600 3600000 604800");
  641. fprintf(fp, "%s IN SOA %s\n", d_domain.toString().c_str(), soa->getZoneRepresentation().c_str());
  642. for (const auto& pair : d_qpolName) {
  643. dumpNamedPolicy(fp, pair.first + d_domain, pair.second);
  644. }
  645. for (const auto& pair : d_propolName) {
  646. dumpNamedPolicy(fp, pair.first + DNSName(rpzNSDnameName) + d_domain, pair.second);
  647. }
  648. for (const auto& pair : d_qpolAddr) {
  649. dumpAddrPolicy(fp, pair.first, DNSName(rpzClientIPName) + d_domain, pair.second);
  650. }
  651. for (const auto& pair : d_propolNSAddr) {
  652. dumpAddrPolicy(fp, pair.first, DNSName(rpzNSIPName) + d_domain, pair.second);
  653. }
  654. for (const auto& pair : d_postpolAddr) {
  655. dumpAddrPolicy(fp, pair.first, DNSName(rpzIPName) + d_domain, pair.second);
  656. }
  657. }
  658. void mergePolicyTags(std::unordered_set<std::string>& tags, const std::unordered_set<std::string>& newTags)
  659. {
  660. for (const auto& tag : newTags) {
  661. tags.insert(tag);
  662. }
  663. }