1 // Copyright (C) 2021 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7 #include <config.h>
8
9 #include <run_script.h>
10
11 using namespace isc::asiolink;
12 using namespace isc::data;
13 using namespace isc::hooks;
14 using namespace isc::util;
15 using namespace isc::dhcp;
16 using namespace std;
17
18 namespace isc {
19 namespace run_script {
20
21 IOServicePtr RunScriptImpl::io_service_;
22
RunScriptImpl()23 RunScriptImpl::RunScriptImpl() : name_(), sync_(false) {
24 }
25
26 void
configure(LibraryHandle & handle)27 RunScriptImpl::configure(LibraryHandle& handle) {
28 ConstElementPtr name = handle.getParameter("name");
29 if (!name) {
30 isc_throw(NotFound, "The 'name' parameter is mandatory");
31 }
32 if (name->getType() != Element::string) {
33 isc_throw(InvalidParameter, "The 'name' parameter must be a string");
34 }
35 try {
36 ProcessSpawn process(IOServicePtr(), name->stringValue());
37 } catch (const isc::Exception& ex) {
38 isc_throw(InvalidParameter, "Invalid 'name' parameter: " << ex.what());
39 }
40 setName(name->stringValue());
41 ConstElementPtr sync = handle.getParameter("sync");
42 if (sync) {
43 if (sync->getType() != Element::boolean) {
44 isc_throw(InvalidParameter, "The 'sync' parameter must be a boolean");
45 }
46 setSync(sync->boolValue());
47 }
48 }
49
50 void
runScript(const ProcessArgs & args,const ProcessEnvVars & vars)51 RunScriptImpl::runScript(const ProcessArgs& args, const ProcessEnvVars& vars) {
52 ProcessSpawn process(getIOService(), name_, args, vars);
53 process.spawn(true);
54 }
55
56 void
extractBoolean(ProcessEnvVars & vars,const bool value,const string & prefix,const string & suffix)57 RunScriptImpl::extractBoolean(ProcessEnvVars& vars,
58 const bool value,
59 const string& prefix,
60 const string& suffix) {
61 string data;
62 if (value) {
63 data = "true";
64 } else {
65 data = "false";
66 }
67 string exported_data = prefix + suffix + "=" + data;
68 vars.push_back(exported_data);
69 }
70
71 void
extractInteger(ProcessEnvVars & vars,const uint64_t value,const string & prefix,const string & suffix)72 RunScriptImpl::extractInteger(ProcessEnvVars& vars,
73 const uint64_t value,
74 const string& prefix,
75 const string& suffix) {
76 string exported_data = prefix + suffix + "=" + boost::lexical_cast<string>(value);
77 vars.push_back(exported_data);
78 }
79
80 void
extractString(ProcessEnvVars & vars,const string & value,const string & prefix,const string & suffix)81 RunScriptImpl::extractString(ProcessEnvVars& vars,
82 const string& value,
83 const string& prefix,
84 const string& suffix) {
85 string exported_data = prefix + suffix + "=" + value;
86 vars.push_back(exported_data);
87 }
88
89 void
extractHWAddr(ProcessEnvVars & vars,const HWAddrPtr & hwaddr,const string & prefix,const string & suffix)90 RunScriptImpl::extractHWAddr(ProcessEnvVars& vars,
91 const HWAddrPtr& hwaddr,
92 const string& prefix,
93 const string& suffix) {
94 if (hwaddr) {
95 RunScriptImpl::extractString(vars, hwaddr->toText(false), prefix, suffix);
96 RunScriptImpl::extractInteger(vars, hwaddr->htype_, prefix + "_TYPE", suffix);
97 } else {
98 RunScriptImpl::extractString(vars, "", prefix, suffix);
99 RunScriptImpl::extractString(vars, "", prefix + "_TYPE", suffix);
100 }
101 }
102
103 void
extractDUID(ProcessEnvVars & vars,const DuidPtr duid,const string & prefix,const string & suffix)104 RunScriptImpl::extractDUID(ProcessEnvVars& vars,
105 const DuidPtr duid,
106 const string& prefix,
107 const string& suffix) {
108 if (duid) {
109 RunScriptImpl::extractString(vars, duid->toText(),
110 prefix, suffix);
111 } else {
112 RunScriptImpl::extractString(vars, "", prefix, suffix);
113 }
114 }
115
116 void
extractOption(ProcessEnvVars & vars,const OptionPtr option,const string & prefix,const string & suffix)117 RunScriptImpl::extractOption(ProcessEnvVars& vars,
118 const OptionPtr option,
119 const string& prefix,
120 const string& suffix) {
121 if (option) {
122 RunScriptImpl::extractString(vars, option->toHexString(),
123 prefix + "_OPTION_" +
124 boost::lexical_cast<string>(option->getType()),
125 suffix);
126 }
127 }
128
129 void
extractSubOption(ProcessEnvVars & vars,const OptionPtr option,uint16_t code,const string & prefix,const string & suffix)130 RunScriptImpl::extractSubOption(ProcessEnvVars& vars,
131 const OptionPtr option,
132 uint16_t code,
133 const string& prefix,
134 const string& suffix) {
135 if (option) {
136 RunScriptImpl::extractOption(vars, option->getOption(code),
137 prefix + "_OPTION_" +
138 boost::lexical_cast<string>(option->getType()) +
139 "_SUB", suffix);
140 }
141 }
142
143 void
extractOptionIA(ProcessEnvVars & vars,const Option6IAPtr option6IA,const string & prefix,const string & suffix)144 RunScriptImpl::extractOptionIA(ProcessEnvVars& vars,
145 const Option6IAPtr option6IA,
146 const string& prefix,
147 const string& suffix) {
148 if (option6IA) {
149 RunScriptImpl::extractInteger(vars, option6IA->getIAID(),
150 prefix + "_IAID", suffix);
151 RunScriptImpl::extractInteger(vars, option6IA->getType(),
152 prefix + "_IA_TYPE", suffix);
153 RunScriptImpl::extractInteger(vars, option6IA->getT1(),
154 prefix + "_IA_T1", suffix);
155 RunScriptImpl::extractInteger(vars, option6IA->getT2(),
156 prefix + "_IA_T2", suffix);
157 } else {
158 RunScriptImpl::extractString(vars, "", prefix + "_IAID", suffix);
159 RunScriptImpl::extractString(vars, "", prefix + "_IA_TYPE", suffix);
160 RunScriptImpl::extractString(vars, "", prefix + "_IA_T1", suffix);
161 RunScriptImpl::extractString(vars, "", prefix + "_IA_T2", suffix);
162 }
163 }
164
165 void
extractSubnet4(ProcessEnvVars & vars,const Subnet4Ptr subnet4,const string & prefix,const string & suffix)166 RunScriptImpl::extractSubnet4(ProcessEnvVars& vars,
167 const Subnet4Ptr subnet4,
168 const string& prefix,
169 const string& suffix) {
170 if (subnet4) {
171 RunScriptImpl::extractInteger(vars, subnet4->getID(),
172 prefix + "_ID", suffix);
173 RunScriptImpl::extractString(vars, subnet4->toText(),
174 prefix + "_NAME", suffix);
175 auto prefix_data = subnet4->get();
176 RunScriptImpl::extractString(vars, prefix_data.first.toText(),
177 prefix + "_PREFIX", suffix);
178 RunScriptImpl::extractInteger(vars, prefix_data.second,
179 prefix + "_PREFIX_LEN", suffix);
180 } else {
181 RunScriptImpl::extractString(vars, "", prefix + "_ID", suffix);
182 RunScriptImpl::extractString(vars, "", prefix + "_NAME", suffix);
183 RunScriptImpl::extractString(vars, "", prefix + "_PREFIX", suffix);
184 RunScriptImpl::extractString(vars, "", prefix + "_PREFIX_LEN", suffix);
185 }
186 }
187
188 void
extractSubnet6(ProcessEnvVars & vars,const Subnet6Ptr subnet6,const string & prefix,const string & suffix)189 RunScriptImpl::extractSubnet6(ProcessEnvVars& vars,
190 const Subnet6Ptr subnet6,
191 const string& prefix,
192 const string& suffix) {
193 if (subnet6) {
194 RunScriptImpl::extractInteger(vars, subnet6->getID(),
195 prefix + "_ID", suffix);
196 RunScriptImpl::extractString(vars, subnet6->toText(),
197 prefix + "_NAME", suffix);
198 auto prefix_data = subnet6->get();
199 RunScriptImpl::extractString(vars, prefix_data.first.toText(),
200 prefix + "_PREFIX", suffix);
201 RunScriptImpl::extractInteger(vars, prefix_data.second,
202 prefix + "_PREFIX_LEN", suffix);
203 } else {
204 RunScriptImpl::extractString(vars, "", prefix + "_ID", suffix);
205 RunScriptImpl::extractString(vars, "", prefix + "_NAME", suffix);
206 RunScriptImpl::extractString(vars, "", prefix + "_PREFIX", suffix);
207 RunScriptImpl::extractString(vars, "", prefix + "_PREFIX_LEN", suffix);
208 }
209 }
210
211 void
extractLease4(ProcessEnvVars & vars,const Lease4Ptr & lease4,const string & prefix,const string & suffix)212 RunScriptImpl::extractLease4(ProcessEnvVars& vars,
213 const Lease4Ptr& lease4,
214 const string& prefix,
215 const string& suffix) {
216 if (lease4) {
217 RunScriptImpl::extractString(vars, lease4->addr_.toText(),
218 prefix + "_ADDRESS", suffix);
219 RunScriptImpl::extractInteger(vars, static_cast<uint64_t>(lease4->cltt_),
220 prefix + "_CLTT", suffix);
221 RunScriptImpl::extractString(vars, lease4->hostname_,
222 prefix + "_HOSTNAME", suffix);
223 RunScriptImpl::extractHWAddr(vars, lease4->hwaddr_,
224 prefix + "_HWADDR", suffix);
225 RunScriptImpl::extractString(vars, Lease4::statesToText(lease4->state_),
226 prefix + "_STATE", suffix);
227 RunScriptImpl::extractInteger(vars, lease4->subnet_id_,
228 prefix + "_SUBNET_ID", suffix);
229 RunScriptImpl::extractInteger(vars, lease4->valid_lft_,
230 prefix + "_VALID_LIFETIME", suffix);
231 RunScriptImpl::extractDUID(vars, lease4->client_id_,
232 prefix + "_CLIENT_ID", suffix);
233 } else {
234 RunScriptImpl::extractString(vars, "", prefix + "_ADDRESS", suffix);
235 RunScriptImpl::extractString(vars, "", prefix + "_CLTT", suffix);
236 RunScriptImpl::extractString(vars, "", prefix + "_HOSTNAME", suffix);
237 RunScriptImpl::extractHWAddr(vars, HWAddrPtr(), prefix + "_HWADDR", suffix);
238 RunScriptImpl::extractString(vars, "", prefix + "_STATE", suffix);
239 RunScriptImpl::extractString(vars, "", prefix + "_SUBNET_ID", suffix);
240 RunScriptImpl::extractString(vars, "", prefix + "_VALID_LIFETIME", suffix);
241 RunScriptImpl::extractDUID(vars, DuidPtr(), prefix + "_CLIENT_ID", suffix);
242 }
243 }
244
245 void
extractLease6(ProcessEnvVars & vars,const Lease6Ptr & lease6,const string & prefix,const string & suffix)246 RunScriptImpl::extractLease6(ProcessEnvVars& vars,
247 const Lease6Ptr& lease6,
248 const string& prefix,
249 const string& suffix) {
250 if (lease6) {
251 RunScriptImpl::extractString(vars, lease6->addr_.toText(),
252 prefix + "_ADDRESS", suffix);
253 RunScriptImpl::extractInteger(vars, static_cast<uint64_t>(lease6->cltt_),
254 prefix + "_CLTT", suffix);
255 RunScriptImpl::extractString(vars, lease6->hostname_,
256 prefix + "_HOSTNAME", suffix);
257 RunScriptImpl::extractHWAddr(vars, lease6->hwaddr_,
258 prefix + "_HWADDR", suffix);
259 RunScriptImpl::extractString(vars, Lease6::statesToText(lease6->state_),
260 prefix + "_STATE", suffix);
261 RunScriptImpl::extractInteger(vars, lease6->subnet_id_,
262 prefix + "_SUBNET_ID", suffix);
263 RunScriptImpl::extractInteger(vars, lease6->valid_lft_,
264 prefix + "_VALID_LIFETIME", suffix);
265 RunScriptImpl::extractDUID(vars, lease6->duid_,
266 prefix + "_DUID", suffix);
267 RunScriptImpl::extractInteger(vars, lease6->iaid_,
268 prefix + "_IAID", suffix);
269 RunScriptImpl::extractInteger(vars, lease6->preferred_lft_,
270 prefix + "_PREFERRED_LIFETIME", suffix);
271 RunScriptImpl::extractInteger(vars, lease6->prefixlen_,
272 prefix + "_PREFIX_LEN", suffix);
273 RunScriptImpl::extractString(vars, Lease::typeToText(lease6->type_),
274 prefix + "_TYPE", suffix);
275 } else {
276 RunScriptImpl::extractString(vars, "", prefix + "_ADDRESS", suffix);
277 RunScriptImpl::extractString(vars, "", prefix + "_CLTT", suffix);
278 RunScriptImpl::extractString(vars, "", prefix + "_HOSTNAME", suffix);
279 RunScriptImpl::extractHWAddr(vars, HWAddrPtr(), prefix + "_HWADDR", suffix);
280 RunScriptImpl::extractString(vars, "", prefix + "_STATE", suffix);
281 RunScriptImpl::extractString(vars, "", prefix + "_SUBNET_ID", suffix);
282 RunScriptImpl::extractString(vars, "", prefix + "_VALID_LIFETIME", suffix);
283 RunScriptImpl::extractDUID(vars, DuidPtr(), prefix + "_DUID", suffix);
284 RunScriptImpl::extractString(vars, "", prefix + "_IAID", suffix);
285 RunScriptImpl::extractString(vars, "", prefix + "_PREFERRED_LIFETIME", suffix);
286 RunScriptImpl::extractString(vars, "", prefix + "_PREFIX_LEN", suffix);
287 RunScriptImpl::extractString(vars, "", prefix + "_TYPE", suffix);
288 }
289 }
290
291 void
extractLeases4(ProcessEnvVars & vars,const Lease4CollectionPtr & leases4,const string & prefix,const string & suffix)292 RunScriptImpl::extractLeases4(ProcessEnvVars& vars,
293 const Lease4CollectionPtr& leases4,
294 const string& prefix,
295 const string& suffix) {
296 if (leases4) {
297 RunScriptImpl::extractInteger(vars, leases4->size(),
298 prefix + "_SIZE", suffix);
299 for (size_t i = 0; i < leases4->size(); ++i) {
300 RunScriptImpl::extractLease4(vars, leases4->at(i),
301 prefix + "_AT" +
302 boost::lexical_cast<string>(i),
303 suffix);
304 }
305 } else {
306 RunScriptImpl::extractString(vars, "0", prefix + "_SIZE", suffix);
307 }
308 }
309
310 void
extractLeases6(ProcessEnvVars & vars,const Lease6CollectionPtr & leases6,const string & prefix,const string & suffix)311 RunScriptImpl::extractLeases6(ProcessEnvVars& vars,
312 const Lease6CollectionPtr& leases6,
313 const string& prefix,
314 const string& suffix) {
315 if (leases6) {
316 RunScriptImpl::extractInteger(vars, leases6->size(),
317 prefix + "_SIZE", suffix);
318 for (size_t i = 0; i < leases6->size(); ++i) {
319 RunScriptImpl::extractLease6(vars, leases6->at(i),
320 prefix + "_AT" +
321 boost::lexical_cast<string>(i),
322 suffix);
323 }
324 } else {
325 RunScriptImpl::extractString(vars, "0", prefix + "_SIZE", suffix);
326 }
327 }
328
329 void
extractPkt4(ProcessEnvVars & vars,const Pkt4Ptr & pkt4,const string & prefix,const string & suffix)330 RunScriptImpl::extractPkt4(ProcessEnvVars& vars,
331 const Pkt4Ptr& pkt4,
332 const string& prefix,
333 const string& suffix) {
334 if (pkt4) {
335 RunScriptImpl::extractString(vars, pkt4->getName(pkt4->getType()),
336 prefix + "_TYPE", suffix);
337 RunScriptImpl::extractInteger(vars, pkt4->getTransid(),
338 prefix + "_TXID", suffix);
339 RunScriptImpl::extractString(vars, pkt4->getLocalAddr().toText(),
340 prefix + "_LOCAL_ADDR", suffix);
341 RunScriptImpl::extractInteger(vars, pkt4->getLocalPort(),
342 prefix + "_LOCAL_PORT", suffix);
343 RunScriptImpl::extractString(vars, pkt4->getRemoteAddr().toText(),
344 prefix + "_REMOTE_ADDR", suffix);
345 RunScriptImpl::extractInteger(vars, pkt4->getRemotePort(),
346 prefix + "_REMOTE_PORT", suffix);
347 RunScriptImpl::extractInteger(vars, pkt4->getIndex(),
348 prefix + "_IFACE_INDEX", suffix);
349 RunScriptImpl::extractString(vars, pkt4->getIface(),
350 prefix + "_IFACE_NAME", suffix);
351 RunScriptImpl::extractInteger(vars, pkt4->getHops(),
352 prefix + "_HOPS", suffix);
353 RunScriptImpl::extractInteger(vars, pkt4->getSecs(),
354 prefix + "_SECS", suffix);
355 RunScriptImpl::extractInteger(vars, pkt4->getFlags(),
356 prefix + "_FLAGS", suffix);
357 RunScriptImpl::extractString(vars, pkt4->getCiaddr().toText(),
358 prefix + "_CIADDR", suffix);
359 RunScriptImpl::extractString(vars, pkt4->getSiaddr().toText(),
360 prefix + "_SIADDR", suffix);
361 RunScriptImpl::extractString(vars, pkt4->getYiaddr().toText(),
362 prefix + "_YIADDR", suffix);
363 RunScriptImpl::extractString(vars, pkt4->getGiaddr().toText(),
364 prefix + "_GIADDR", suffix);
365 RunScriptImpl::extractBoolean(vars, pkt4->isRelayed(),
366 prefix + "_RELAYED", suffix);
367 RunScriptImpl::extractHWAddr(vars, pkt4->getHWAddr(),
368 prefix + "_HWADDR", suffix);
369 RunScriptImpl::extractHWAddr(vars, pkt4->getLocalHWAddr(),
370 prefix + "_LOCAL_HWADDR", suffix);
371 RunScriptImpl::extractHWAddr(vars, pkt4->getRemoteHWAddr(),
372 prefix + "_REMOTE_HWADDR", suffix);
373 RunScriptImpl::extractOption(vars,
374 pkt4->getOption(DHO_DHCP_AGENT_OPTIONS),
375 prefix, suffix);
376 RunScriptImpl::extractSubOption(vars,
377 pkt4->getOption(DHO_DHCP_AGENT_OPTIONS),
378 RAI_OPTION_AGENT_CIRCUIT_ID,
379 prefix, suffix);
380 RunScriptImpl::extractSubOption(vars,
381 pkt4->getOption(DHO_DHCP_AGENT_OPTIONS),
382 RAI_OPTION_REMOTE_ID,
383 prefix, suffix);
384 } else {
385 RunScriptImpl::extractString(vars, "", prefix + "_TYPE", suffix);
386 RunScriptImpl::extractString(vars, "", prefix + "_TXID", suffix);
387 RunScriptImpl::extractString(vars, "", prefix + "_LOCAL_ADDR", suffix);
388 RunScriptImpl::extractString(vars, "", prefix + "_LOCAL_PORT", suffix);
389 RunScriptImpl::extractString(vars, "", prefix + "_REMOTE_ADDR", suffix);
390 RunScriptImpl::extractString(vars, "", prefix + "_REMOTE_PORT", suffix);
391 RunScriptImpl::extractString(vars, "", prefix + "_IFACE_INDEX", suffix);
392 RunScriptImpl::extractString(vars, "", prefix + "_IFACE_NAME", suffix);
393 RunScriptImpl::extractString(vars, "", prefix + "_HOPS", suffix);
394 RunScriptImpl::extractString(vars, "", prefix + "_SECS", suffix);
395 RunScriptImpl::extractString(vars, "", prefix + "_FLAGS", suffix);
396 RunScriptImpl::extractString(vars, "", prefix + "_CIADDR", suffix);
397 RunScriptImpl::extractString(vars, "", prefix + "_SIADDR", suffix);
398 RunScriptImpl::extractString(vars, "", prefix + "_YIADDR", suffix);
399 RunScriptImpl::extractString(vars, "", prefix + "_GIADDR", suffix);
400 RunScriptImpl::extractString(vars, "", prefix + "_RELAYED", suffix);
401 RunScriptImpl::extractHWAddr(vars, HWAddrPtr(),
402 prefix + "_HWADDR", suffix);
403 RunScriptImpl::extractHWAddr(vars, HWAddrPtr(),
404 prefix + "_LOCAL_HWADDR", suffix);
405 RunScriptImpl::extractHWAddr(vars, HWAddrPtr(),
406 prefix + "_REMOTE_HWADDR", suffix);
407 }
408 }
409
410 void
extractPkt6(ProcessEnvVars & vars,const Pkt6Ptr & pkt6,const string & prefix,const string & suffix)411 RunScriptImpl::extractPkt6(ProcessEnvVars& vars,
412 const Pkt6Ptr& pkt6,
413 const string& prefix,
414 const string& suffix) {
415 if (pkt6) {
416 RunScriptImpl::extractString(vars, pkt6->getName(pkt6->getType()),
417 prefix + "_TYPE", suffix);
418 RunScriptImpl::extractInteger(vars, pkt6->getTransid(),
419 prefix + "_TXID", suffix);
420 RunScriptImpl::extractString(vars, pkt6->getLocalAddr().toText(),
421 prefix + "_LOCAL_ADDR", suffix);
422 RunScriptImpl::extractInteger(vars, pkt6->getLocalPort(),
423 prefix + "_LOCAL_PORT", suffix);
424 RunScriptImpl::extractString(vars, pkt6->getRemoteAddr().toText(),
425 prefix + "_REMOTE_ADDR", suffix);
426 RunScriptImpl::extractInteger(vars, pkt6->getRemotePort(),
427 prefix + "_REMOTE_PORT", suffix);
428 RunScriptImpl::extractInteger(vars, pkt6->getIndex(),
429 prefix + "_IFACE_INDEX", suffix);
430 RunScriptImpl::extractString(vars, pkt6->getIface(),
431 prefix + "_IFACE_NAME", suffix);
432 RunScriptImpl::extractHWAddr(vars, pkt6->getRemoteHWAddr(),
433 prefix + "_REMOTE_HWADDR", suffix);
434 string proto_data = (pkt6->getProto() == Pkt6::UDP ? "UDP" : "TCP");
435 RunScriptImpl::extractString(vars, proto_data,
436 prefix + "_PROTO", suffix);
437 RunScriptImpl::extractDUID(vars, pkt6->getClientId(),
438 prefix + "_CLIENT_ID", suffix);
439 } else {
440 RunScriptImpl::extractString(vars, "", prefix + "_TYPE", suffix);
441 RunScriptImpl::extractString(vars, "", prefix + "_TXID", suffix);
442 RunScriptImpl::extractString(vars, "", prefix + "_LOCAL_ADDR", suffix);
443 RunScriptImpl::extractString(vars, "", prefix + "_LOCAL_PORT", suffix);
444 RunScriptImpl::extractString(vars, "", prefix + "_REMOTE_ADDR", suffix);
445 RunScriptImpl::extractString(vars, "", prefix + "_REMOTE_PORT", suffix);
446 RunScriptImpl::extractString(vars, "", prefix + "_IFACE_INDEX", suffix);
447 RunScriptImpl::extractString(vars, "", prefix + "_IFACE_NAME", suffix);
448 RunScriptImpl::extractHWAddr(vars, HWAddrPtr(),
449 prefix + "_REMOTE_HWADDR", suffix);
450 RunScriptImpl::extractString(vars, "", prefix + "_PROTO", suffix);
451 RunScriptImpl::extractDUID(vars, DuidPtr(),
452 prefix + "_CLIENT_ID", suffix);
453 }
454 }
455
456 } // namespace run_script
457 } // namespace isc
458