]>
Commit | Line | Data |
---|---|---|
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 | 16 | GlobalStateHolder<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 | ||
31 | LuaConfigItems::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 | ||
40 | template <typename C> | |
41 | typename 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 |
50 | void 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 | 58 | void 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 |