]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/rec-lua-conf.cc
implement delta() to show changes versus configuration, so you can store your 'just...
[thirdparty/pdns.git] / pdns / rec-lua-conf.cc
CommitLineData
6a99b9a4 1#include "config.h"
2#ifdef HAVE_LUA
3e61e7f7 3#include "ext/luawrapper/include/LuaContext.hpp"
6a99b9a4 4#endif
5
3e61e7f7 6#include <fstream>
ad42489c 7#include <thread>
3e61e7f7 8#include "namespaces.hh"
9#include "logger.hh"
f3c18728 10#include "rec-lua-conf.hh"
3e61e7f7 11#include "sortlist.hh"
ad42489c 12#include "filterpo.hh"
13#include "syncres.hh"
14#include "rpzloader.hh"
3e61e7f7 15
f3c18728 16GlobalStateHolder<LuaConfigItems> g_luaconfs;
17
18/* SO HOW DOES THIS WORK! AND PLEASE PAY ATTENTION!
19 This function can be called at any time. It is expected to overwrite all the contents
20 of LuaConfigItems, which is held in a GlobalStateHolder for RCU properties.
21
22 This function can be called again at a later date, so you must make sure that anything you
23 allow to be configured from here lives in g_luaconfs AND NOWHERE ELSE.
24
25 If someone loads an empty Lua file, the default LuaConfigItems struct MUST MAKE SENSE.
26
27 To make this easy on you, here is a LuaConfigItems constructor where you
28 can set sane defaults:
29*/
30
31LuaConfigItems::LuaConfigItems()
32{
2ac8ae89 33 auto ds=std::unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make("19036 8 2 49aac11d7b6f6446702e54a1607371607a1a41855200fd2ce1cdde32f24e8fb5")));
34 // this hurts physically
35 dsAnchors[DNSName(".")] = *ds;
f3c18728 36}
37
ad42489c 38/* DID YOU READ THE STORY ABOVE? */
39
40template <typename C>
41typename C::value_type::second_type constGet(const C& c, const std::string& name)
42{
43 auto iter = c.find(name);
44 if(iter == c.end())
45 return 0;
46 return iter->second;
47}
48
6a99b9a4 49#ifndef HAVE_LUA
50void loadRecursorLuaConfig(const std::string& fname)
51{
3c127bde 52 if(!fname.empty())
53 throw PDNSException("Asked to load a Lua configuration file '"+fname+"' in binary without Lua support");
6a99b9a4 54}
55#else
56
57
3e61e7f7 58void loadRecursorLuaConfig(const std::string& fname)
59{
f3c18728 60 LuaConfigItems lci;
61
3e61e7f7 62 LuaContext Lua;
63 if(fname.empty())
64 return;
65 ifstream ifs(fname);
66 if(!ifs) {
67 theL()<<"Unable to read configuration file from '"<<fname<<"': "<<strerror(errno)<<endl;
68 return;
69 }
f3c18728 70 Lua.writeFunction("clearSortlist", [&lci]() { lci.sortlist.clear(); });
3e61e7f7 71
72 /* we can get: "1.2.3.4"
73 {"1.2.3.4", "4.5.6.7"}
74 {"1.2.3.4", {"4.5.6.7", "8.9.10.11"}}
75 */
76
ad42489c 77 map<string,DNSFilterEngine::PolicyKind> pmap{
78 {"NoAction", DNSFilterEngine::PolicyKind::NoAction},
79 {"Drop", DNSFilterEngine::PolicyKind::Drop},
80 {"NXDOMAIN", DNSFilterEngine::PolicyKind::NXDOMAIN},
81 {"NODATA", DNSFilterEngine::PolicyKind::NODATA},
82 {"Truncate", DNSFilterEngine::PolicyKind::Truncate},
83 {"Custom", DNSFilterEngine::PolicyKind::Custom}
84 };
85 Lua.writeVariable("Policy", pmap);
86
87 Lua.writeFunction("rpzFile", [&lci](const string& fname, const boost::optional<std::unordered_map<string,boost::variant<int, string>>>& options) {
88 try {
89 boost::optional<DNSFilterEngine::Policy> defpol;
90 if(options) {
91 auto& have = *options;
92 if(have.count("defpol")) {
93 cout<<"Set a default policy"<<endl;
94 defpol=DNSFilterEngine::Policy();
95 defpol->d_kind = (DNSFilterEngine::PolicyKind)boost::get<int>(constGet(have, "defpol"));
96 if(defpol->d_kind == DNSFilterEngine::PolicyKind::Custom) {
97 cout<<"Setting a custom field even!"<<endl;
98 defpol->d_custom=
99 shared_ptr<DNSRecordContent>(
100 DNSRecordContent::mastermake(QType::CNAME, 1,
101 boost::get<string>(constGet(have,"defcontent"))
102 )
103 );
3876ee44 104
105 if(have.count("defttl"))
106 defpol->d_ttl = boost::get<int>(constGet(have, "defttl"));
107 else
108 defpol->d_ttl = -1; // get it from the zone
ad42489c 109 }
110 }
111
112 }
113 loadRPZFromFile(fname, lci.dfe, defpol, 0);
114 }
115 catch(std::exception& e) {
116 theL()<<Logger::Error<<"Unable to load RPZ zone from '"<<fname<<"': "<<e.what()<<endl;
117 }
118 });
119
120
121 Lua.writeFunction("rpzMaster", [&lci](const string& master_, const string& zone_, const boost::optional<std::unordered_map<string,boost::variant<int, string>>>& options) {
122 try {
123 boost::optional<DNSFilterEngine::Policy> defpol;
124 if(options) {
125 auto& have = *options;
126 if(have.count("defpol")) {
127 // cout<<"Set a default policy"<<endl;
128 defpol=DNSFilterEngine::Policy();
129 defpol->d_kind = (DNSFilterEngine::PolicyKind)boost::get<int>(constGet(have, "defpol"));
130 if(defpol->d_kind == DNSFilterEngine::PolicyKind::Custom) {
131 // cout<<"Setting a custom field even!"<<endl;
132 defpol->d_custom=
133 shared_ptr<DNSRecordContent>(
134 DNSRecordContent::mastermake(QType::CNAME, 1,
135 boost::get<string>(constGet(have,"defcontent"))
136 )
137 );
3876ee44 138 if(have.count("defttl"))
139 defpol->d_ttl = boost::get<int>(constGet(have, "defttl"));
140 else
141 defpol->d_ttl = -1; // get it from the zone
142
ad42489c 143 }
144 }
145
146 }
147 ComboAddress master(master_, 53);
148 DNSName zone(zone_);
149 auto sr=loadRPZFromServer(master,zone, lci.dfe, defpol, 0);
150 std::thread t(RPZIXFRTracker, master, zone, sr);
151 t.detach();
152 }
153 catch(std::exception& e) {
154 theL()<<Logger::Error<<"Unable to load RPZ zone '"<<zone_<<"' from '"<<master_<<"': "<<e.what()<<endl;
155 }
156 catch(PDNSException& e) {
157 theL()<<Logger::Error<<"Unable to load RPZ zone '"<<zone_<<"' from '"<<master_<<"': "<<e.reason<<endl;
158 }
159
160 });
161
3e61e7f7 162 typedef vector<pair<int,boost::variant<string, vector<pair<int, string> > > > > argvec_t;
163 Lua.writeFunction("addSortList",
f3c18728 164 [&lci](const std::string& formask_,
3e61e7f7 165 const boost::variant<string, argvec_t>& masks,
166 boost::optional<int> order_)
167 {
168 try {
169 Netmask formask(formask_);
f3c18728 170 int order = order_ ? (*order_) : lci.sortlist.getMaxOrder(formask)+1;
3e61e7f7 171 if(auto str = boost::get<string>(&masks))
f3c18728 172 lci.sortlist.addEntry(formask, Netmask(*str), order);
3e61e7f7 173 else {
174
175 auto vec = boost::get<argvec_t>(&masks);
176 for(const auto& e : *vec) {
177 if(auto s = boost::get<string>(&e.second)) {
f3c18728 178 lci.sortlist.addEntry(formask, Netmask(*s), order);
3e61e7f7 179 }
180 else {
181 const auto& v =boost::get<vector<pair<int, string> > >(e.second);
182 for(const auto& e : v)
f3c18728 183 lci.sortlist.addEntry(formask, Netmask(e.second), order);
3e61e7f7 184 }
185 ++order;
186 }
187 }
188 }
189 catch(std::exception& e) {
190 theL()<<Logger::Error<<"Error in addSortList: "<<e.what()<<endl;
191 }
192 });
2ac8ae89 193
194 Lua.writeFunction("addDS", [&lci](const std::string& who, const std::string& what) {
195 lci.dsAnchors[DNSName(who)]= *std::unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(what)));
196 });
197
198 Lua.writeFunction("clearDS", [&lci](boost::optional<string> who) {
199 if(who)
200 lci.dsAnchors.erase(DNSName(*who));
201 else
202 lci.dsAnchors.clear();
203 });
204
ad42489c 205 try {
206 Lua.executeCode(ifs);
207 g_luaconfs.setState(lci);
208 }
2ac8ae89 209 catch(const LuaContext::ExecutionErrorException& e) {
210 theL()<<Logger::Error<<"Unable to load Lua script from '"+fname+"': ";
211 try {
212 std::rethrow_if_nested(e);
213 } catch(const std::exception& e) {
214 // e is the exception that was thrown from inside the lambda
215 theL() << e.what() << std::endl;
216 }
217 catch(const PDNSException& e) {
218 // e is the exception that was thrown from inside the lambda
219 theL() << e.reason << std::endl;
220 }
221 throw;
222
223 }
ad42489c 224 catch(std::exception& err) {
225 theL()<<Logger::Error<<"Unable to load Lua script from '"+fname+"': "<<err.what()<<endl;
2ac8ae89 226 throw;
ad42489c 227 }
228
3e61e7f7 229}
6a99b9a4 230
231#endif