1 |
/* Copyright (C) 2003 Stephane Thiell |
2 |
* |
3 |
* This file is part of pxyservd (from pxys) |
4 |
* |
5 |
* This program is free software; you can redistribute it and/or |
6 |
* modify it under the terms of the GNU General Public License |
7 |
* as published by the Free Software Foundation; either version 2 |
8 |
* of the License, or (at your option) any later version. |
9 |
* |
10 |
* This program is distributed in the hope that it will be useful, |
11 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 |
* GNU General Public License for more details. |
14 |
* |
15 |
* You should have received a copy of the GNU General Public License |
16 |
* along with this program; if not, write to the Free Software |
17 |
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
18 |
* |
19 |
*/ |
20 |
#define RCSID "$Id: PXConfigLoader.cc,v 1.7 2006/09/11 22:02:54 spale Exp $" |
21 |
|
22 |
#ifdef HAVE_CONFIG_H |
23 |
#include "config.h" |
24 |
#endif |
25 |
|
26 |
#include "PXConfigLoader.h" |
27 |
#include "PXConfig.h" |
28 |
|
29 |
#include <cassert> |
30 |
#include <iostream> |
31 |
|
32 |
#include <arpa/inet.h> |
33 |
|
34 |
// XPaths... |
35 |
|
36 |
#define XP_OPAS "/pxyscand/opas" |
37 |
#define XP_OPAS_PORT "port" |
38 |
#define XP_OPAS_BIND_ADDRESS "bind-address" |
39 |
#define XP_OPAS_PROTOCOL "protocol" |
40 |
#define XP_OPAS_ALLOW "allow" |
41 |
// TODO: deny |
42 |
#define XP_OPAS_LIMIT "limit" |
43 |
|
44 |
#define XP_SCANNER "/pxyscand/scanner" |
45 |
#define XP_SCANNER_MAXSCANS "maxscans" |
46 |
#define XP_SCANNER_MODULE_TYPE_ATTR "module/@type" |
47 |
#define XP_SCANNER_MODULE "module[@type]" |
48 |
#define XP_SCANNER_SOURCE_POOL "source-pool" |
49 |
#define XP_SCANNER_SOURCE_POOL_ADDRESS "address" |
50 |
#define XP_SCANNER_TARGET "target" |
51 |
#define XP_SCANNER_TARGET_ADDRESS "address" |
52 |
#define XP_SCANNER_TARGET_PORT "port" |
53 |
#define XP_SCANNER_TARGET_CHECK "target-check" |
54 |
#define XP_SCANNER_TARGET_SECRET "secret" |
55 |
#define XP_SCANNER_LOG_AGENT "log-agent" |
56 |
#define XP_SCANNER_TIMEOUT "timeout" |
57 |
|
58 |
#define XP_CACHE "/pxyscand/cache" |
59 |
#define XP_CACHE_DIRECTORY "directory" |
60 |
#define XP_CACHE_EXPIRE "expire" |
61 |
#define XP_CACHE_PROXY_EXPIRE "proxy-expire" |
62 |
#define XP_CACHE_MAXIPS "maxips" |
63 |
|
64 |
#define XP_NOSCAN "/pxyscand/noscan" |
65 |
#define XP_NOSCAN_ADDRESS "address" |
66 |
|
67 |
using std::clog; |
68 |
using std::cout; |
69 |
using std::endl; |
70 |
|
71 |
PXConfigLoader::PXConfigLoader(const char *inFile) |
72 |
: PXXMLXPathLoaderImp(inFile) |
73 |
{ |
74 |
} |
75 |
|
76 |
PXConfigLoader::~PXConfigLoader() |
77 |
{ |
78 |
} |
79 |
|
80 |
|
81 |
bool |
82 |
PXConfigLoader::StringToNetworkNetmask(const char *str, |
83 |
in_addr &oNet, |
84 |
in_addr &oMask) |
85 |
{ |
86 |
char ipbuf[16]; |
87 |
size_t len, j; |
88 |
int k, dot = 0; |
89 |
char *p; |
90 |
|
91 |
if ((p = strchr(str, '/')) == NULL) |
92 |
oMask.s_addr = htonl(0xffffffff); |
93 |
else |
94 |
{ |
95 |
*p++ = '\0'; |
96 |
if (!strchr(p, '.')) |
97 |
{ |
98 |
int nbits; |
99 |
|
100 |
if ((nbits = atoi(p)) > 0 && nbits <= 32) |
101 |
oMask.s_addr = htonl(~(0xffffffff >> nbits)); |
102 |
} |
103 |
else if (inet_pton(AF_INET, p, &oNet) == -1) |
104 |
return false; |
105 |
} |
106 |
|
107 |
len = strlen(str); |
108 |
len = len < sizeof(ipbuf) ? len : sizeof(ipbuf) - 1; |
109 |
for (j = 0; j < len; j++) |
110 |
{ |
111 |
if (str[j] == '.') |
112 |
dot++; |
113 |
ipbuf[j] = str[j]; |
114 |
} |
115 |
if (dot > 4 || len >= sizeof(ipbuf) - ((3 - dot) * 2)) |
116 |
return false; |
117 |
|
118 |
for (k = 0; k < 3 - dot; k++) |
119 |
{ |
120 |
ipbuf[j++] = '.'; |
121 |
ipbuf[j++] = '0'; |
122 |
} |
123 |
|
124 |
assert(j < sizeof(ipbuf)); |
125 |
ipbuf[j] = '\0'; |
126 |
|
127 |
if (inet_pton(AF_INET, ipbuf, &oNet) == -1) |
128 |
return false; |
129 |
|
130 |
return true; |
131 |
} |
132 |
|
133 |
PXConfig * |
134 |
PXConfigLoader::Load() |
135 |
{ |
136 |
PXConfig *cfg = new PXConfig; |
137 |
try |
138 |
{ |
139 |
this->DoLoad(cfg); |
140 |
} |
141 |
catch (...) |
142 |
{ |
143 |
delete cfg; |
144 |
throw; |
145 |
} |
146 |
return cfg; |
147 |
} |
148 |
|
149 |
void |
150 |
PXConfigLoader::DoLoad(PXConfig *cfg) |
151 |
{ |
152 |
xmlXPathObjectPtr o, o2; |
153 |
|
154 |
if ((o = this->EvalUnique(XP_OPAS))) |
155 |
{ |
156 |
StPXXPathContextNode cxNode(&mCx->node, o->nodesetval->nodeTab[0]); |
157 |
|
158 |
/* OPAS Port */ |
159 |
cfg->opas.port = this->GetInteger(XP_OPAS_PORT, 0, 1); |
160 |
|
161 |
/* OPAS local address (bind) */ |
162 |
this->GetAddress(XP_OPAS_BIND_ADDRESS, 0, 0, "opas/bind-address", |
163 |
&cfg->opas.local_address); |
164 |
|
165 |
/* Protocol(s) to enable (tcp, udp) */ |
166 |
o2 = this->Eval(XP_OPAS_PROTOCOL); |
167 |
if (!o2 || !o2->nodesetval->nodeNr) |
168 |
PXXMLException::Throw("Missing parameter", "opas/protocol"); |
169 |
cfg->opas.proto.reserve(o2->nodesetval->nodeNr); |
170 |
for (int i = 0; i < o2->nodesetval->nodeNr; i++) |
171 |
{ |
172 |
xmlChar *s; |
173 |
xmlNodePtr n; |
174 |
n = o2->nodesetval->nodeTab[i]->xmlChildrenNode; |
175 |
if (!(s = xmlNodeListGetString(mDoc, n, 1))) |
176 |
PXXMLException::Throw("Empty protocol, use: tcp or udp", |
177 |
"opas/protocol"); |
178 |
if (!strcmp((char *)s, "tcp")) |
179 |
cfg->opas.proto.push_back(PXOPAS_PROTO_TCP); |
180 |
else if (!strcmp((char *)s, "udp")) |
181 |
cfg->opas.proto.push_back(PXOPAS_PROTO_UDP); |
182 |
else |
183 |
{ |
184 |
xmlFree(s); |
185 |
PXXMLException::Throw("Unknown protocol (use: tcp or udp)", |
186 |
"opas/protocol"); |
187 |
} |
188 |
xmlFree(s); |
189 |
} |
190 |
xmlXPathFreeObject(o2); |
191 |
|
192 |
/* Allowed IPs */ |
193 |
o2 = this->Eval(XP_OPAS_ALLOW); |
194 |
if (!o2 || !o2->nodesetval->nodeNr) |
195 |
PXXMLException::Throw("Missing parameter", "opas/allow"); |
196 |
cfg->opas.allow.reserve(o2->nodesetval->nodeNr); |
197 |
for (int i = 0; i < o2->nodesetval->nodeNr; i++) |
198 |
{ |
199 |
xmlChar *s; |
200 |
xmlNodePtr n; |
201 |
in_addr addr; |
202 |
|
203 |
n = o2->nodesetval->nodeTab[i]->xmlChildrenNode; |
204 |
if (!(s = xmlNodeListGetString(mDoc, n, 1))) |
205 |
PXXMLException::Throw("Empty allow field", "opas/allow"); |
206 |
int res = inet_pton(AF_INET, (char *)s, &addr); |
207 |
xmlFree(s); |
208 |
if (res == -1) |
209 |
PXXMLException::Throw("Bad IP address", "opas/allow"); |
210 |
cfg->opas.allow.push_back(addr); |
211 |
} |
212 |
xmlXPathFreeObject(o2); |
213 |
|
214 |
/* OPAS limit */ |
215 |
cfg->opas.limit = this->GetInteger(XP_OPAS_LIMIT, 0, 1); |
216 |
|
217 |
xmlXPathFreeObject(o); |
218 |
} |
219 |
|
220 |
if ((o = this->EvalUnique(XP_SCANNER))) |
221 |
{ |
222 |
StPXXPathContextNode cxNode(&mCx->node, o->nodesetval->nodeTab[0]); |
223 |
|
224 |
cfg->scanner.maxscans = this->GetInteger(XP_SCANNER_MAXSCANS, 0, 1); |
225 |
if (cfg->scanner.maxscans <= 0) |
226 |
cfg->scanner.maxscans = 100; // bah |
227 |
|
228 |
if (!(o2 = this->Eval(XP_SCANNER_MODULE_TYPE_ATTR))) |
229 |
PXXMLException::Throw("Missing parameter", "scanner/module"); |
230 |
else |
231 |
{ |
232 |
cfg->scanner.modules.reserve(o2->nodesetval->nodeNr); |
233 |
for (int i = 0; i < o2->nodesetval->nodeNr; i++) |
234 |
{ |
235 |
PXConfigModule m; |
236 |
xmlChar *s; |
237 |
xmlNodePtr n = o2->nodesetval->nodeTab[i]->xmlChildrenNode; |
238 |
|
239 |
if (!(s = xmlNodeListGetString(mDoc, n, 1))) |
240 |
PXXMLException::Throw("Empty type attribute not allowed", |
241 |
"scanner/module"); |
242 |
|
243 |
m.port = 0; // only used for http scan module |
244 |
|
245 |
if (!xmlStrcasecmp(s, (xmlChar*)"wingate")) |
246 |
m.id = CONFIG_MODULE_WINGATE; |
247 |
else if (!xmlStrcasecmp(s, (xmlChar*)"socks")) |
248 |
{ |
249 |
m.id = CONFIG_MODULE_SOCKS; |
250 |
try { |
251 |
m.port = this->GetInteger(XP_SCANNER_MODULE, i, 65536); |
252 |
} catch (PXXMLException &e) { |
253 |
clog << "Please note that socks ports are now mandatory and must be specified in the config file" << endl; |
254 |
throw; |
255 |
} |
256 |
// Note: port 0 not allowed for convenience. |
257 |
if (m.port <= 0 || m.port >= 65536) |
258 |
PXXMLException::Throw("Bad socks port number", "scanner/module"); |
259 |
} |
260 |
else if (!xmlStrcmp(s, (xmlChar*)"http")) |
261 |
{ |
262 |
m.id = CONFIG_MODULE_HTTP; |
263 |
m.port = this->GetInteger(XP_SCANNER_MODULE, i, 65536); |
264 |
// Note: port 0 not allowed for convenience. |
265 |
if (m.port <= 0 || m.port >= 65536) |
266 |
PXXMLException::Throw("Bad proxy port number", "scanner/module"); |
267 |
} |
268 |
else if (!xmlStrcasecmp(s, (xmlChar*)"crazybandit")) |
269 |
m.id = CONFIG_MODULE_CRAZYBANDIT; |
270 |
|
271 |
/* Handle new module type here. */ |
272 |
|
273 |
else |
274 |
PXXMLException::Throw("Unknown scanner/module type attribute", |
275 |
"scanner/module"); |
276 |
|
277 |
cfg->scanner.modules.push_back(m); |
278 |
} |
279 |
xmlXPathFreeObject(o2); |
280 |
} |
281 |
|
282 |
|
283 |
if ((o2 = this->Eval(XP_SCANNER_SOURCE_POOL))) |
284 |
{ |
285 |
StPXXPathContextNode cxNode(&mCx->node, o2->nodesetval->nodeTab[0]); |
286 |
|
287 |
xmlXPathObjectPtr o3 = this->Eval(XP_SCANNER_TARGET_ADDRESS); |
288 |
if (o3) |
289 |
{ |
290 |
int cnt = o3->nodesetval->nodeNr; |
291 |
cfg->scanner.source_pool.reserve(cnt); |
292 |
xmlXPathFreeObject(o3); |
293 |
for (int i = 0; i < cnt; i++) |
294 |
{ |
295 |
sockaddr_in sin; |
296 |
memset(&sin, 0, sizeof(sin)); |
297 |
sin.sin_family = AF_INET; |
298 |
sin.sin_port = htons(0); |
299 |
|
300 |
this->GetAddress(XP_SCANNER_TARGET_ADDRESS, i, 0, |
301 |
"scanner/source-pool/address", &sin.sin_addr); |
302 |
|
303 |
// Test the local address now. |
304 |
int testFD = socket(AF_INET, SOCK_STREAM, 0); |
305 |
if (testFD == -1) // doh ! |
306 |
PXXMLException::Throw("Source pool address test failed", |
307 |
"socket() failed!"); |
308 |
if (bind(testFD, (sockaddr *)&sin, sizeof(sin)) == -1) |
309 |
PXXMLException::Throw("Source pool address test failed", |
310 |
"bind() failed!"); |
311 |
close(testFD); |
312 |
cfg->scanner.source_pool.push_back(sin.sin_addr); |
313 |
} |
314 |
} |
315 |
xmlXPathFreeObject(o2); |
316 |
} |
317 |
|
318 |
if (!(o2 = this->Eval(XP_SCANNER_TARGET))) |
319 |
PXXMLException::Throw("Missing parameter", "scanner/target"); |
320 |
|
321 |
cfg->scanner.targets.reserve(o2->nodesetval->nodeNr); |
322 |
for (int i = 0; i < o2->nodesetval->nodeNr; i++) |
323 |
{ |
324 |
StPXXPathContextNode cxNodeTarget(&mCx->node, |
325 |
o2->nodesetval->nodeTab[i]); |
326 |
PXConfigScannerTarget target; |
327 |
|
328 |
this->GetAddress(XP_SCANNER_TARGET_ADDRESS, 0, 1, |
329 |
"scanner/target/address", &target.address); |
330 |
target.port = this->GetInteger(XP_SCANNER_TARGET_PORT, 0, 1); |
331 |
|
332 |
target.secret = (char*)CopyString(XP_SCANNER_TARGET_SECRET, 0, 1); |
333 |
|
334 |
cfg->scanner.targets.push_back(target); |
335 |
} |
336 |
xmlXPathFreeObject(o2); |
337 |
|
338 |
cfg->scanner.target_check = (time_t)this->GetInteger( |
339 |
XP_SCANNER_TARGET_CHECK, 0, 1); |
340 |
cfg->scanner.log_agent = (char *)this->CopyString(XP_SCANNER_LOG_AGENT, |
341 |
0, 0); |
342 |
cfg->scanner.timeout = (time_t)this->GetInteger(XP_SCANNER_TIMEOUT, 0, 1); |
343 |
if (cfg->scanner.timeout <= 0) |
344 |
cfg->scanner.timeout = 30; |
345 |
|
346 |
xmlXPathFreeObject(o); |
347 |
} |
348 |
|
349 |
if ((o = this->EvalUnique(XP_CACHE))) |
350 |
{ |
351 |
StPXXPathContextNode cxNode(&mCx->node, o->nodesetval->nodeTab[0]); |
352 |
|
353 |
// Cache directory |
354 |
cfg->cache.dir = (char *)this->CopyString(XP_CACHE_DIRECTORY, 0, 1); |
355 |
// Cache expire seconds |
356 |
cfg->cache.expire = this->GetInteger(XP_CACHE_EXPIRE, 0, 1); |
357 |
// Proxy cache expire seconds |
358 |
cfg->cache.proxy_expire = this->GetInteger(XP_CACHE_PROXY_EXPIRE, 0, 1); |
359 |
// Cache max IPs |
360 |
cfg->cache.maxips = this->GetInteger(XP_CACHE_MAXIPS, 0, 1); |
361 |
|
362 |
xmlXPathFreeObject(o); |
363 |
} |
364 |
|
365 |
if ((o = this->EvalUnique(XP_NOSCAN))) |
366 |
{ |
367 |
StPXXPathContextNode cxNode(&mCx->node, o->nodesetval->nodeTab[0]); |
368 |
|
369 |
o2 = this->Eval(XP_NOSCAN_ADDRESS); |
370 |
if (o2) |
371 |
{ |
372 |
cfg->noscan.address.reserve(o2->nodesetval->nodeNr); |
373 |
for (int i = 0; i < o2->nodesetval->nodeNr; i++) |
374 |
{ |
375 |
xmlChar *s; |
376 |
xmlNodePtr n; |
377 |
n = o2->nodesetval->nodeTab[i]->xmlChildrenNode; |
378 |
if (!(s = xmlNodeListGetString(mDoc, n, 1))) |
379 |
PXXMLException::Throw("Empty allow field", "noscan/address"); |
380 |
|
381 |
NetworkNetmask nwnm; |
382 |
bool res = StringToNetworkNetmask((char *)s, nwnm.network, |
383 |
nwnm.netmask); |
384 |
xmlFree(s); |
385 |
if (!res) |
386 |
PXXMLException::Throw("Invalid address", "noscan/address"); |
387 |
cfg->noscan.address.push_back(nwnm); |
388 |
} |
389 |
xmlXPathFreeObject(o2); |
390 |
} |
391 |
xmlXPathFreeObject(o); |
392 |
} |
393 |
} |
394 |
|
395 |
void |
396 |
PXConfigLoader::Dump(PXConfig *cfg) |
397 |
{ |
398 |
size_t i; |
399 |
|
400 |
cout << "OPAS config" << endl; |
401 |
cout << "port: " << cfg->opas.port << endl; |
402 |
cout << "local_address: "; |
403 |
if (cfg->opas.local_address.s_addr == INADDR_ANY) |
404 |
cout << "default (any)"; |
405 |
else |
406 |
cout << inet_ntoa(cfg->opas.local_address); |
407 |
cout << endl; |
408 |
cout << "proto: "; |
409 |
for (i = 0; i < cfg->opas.proto.size(); i++) |
410 |
if (cfg->opas.proto[i] == PXOPAS_PROTO_TCP) |
411 |
cout << "tcp "; |
412 |
else |
413 |
cout << "udp"; |
414 |
cout << endl; |
415 |
|
416 |
cout << "allow: "; |
417 |
for (size_t i = 0; i < cfg->opas.allow.size(); i++) |
418 |
cout << inet_ntoa(cfg->opas.allow[i]) << " "; |
419 |
cout << endl; |
420 |
|
421 |
cout << "limit: "; |
422 |
if (cfg->opas.limit == 0) |
423 |
cout << "unlimited"; |
424 |
else |
425 |
cout << cfg->opas.limit; |
426 |
cout << endl << endl; |
427 |
|
428 |
cout << "SCANNER config" << endl; |
429 |
cout << "maxscans: " << cfg->scanner.maxscans << endl; |
430 |
if (cfg->scanner.modules.size() == 0) |
431 |
{ |
432 |
cout << "NO SCANNER MODULE ENABLED !!!" << endl; |
433 |
exit(1); |
434 |
} |
435 |
else |
436 |
{ |
437 |
cout << "Scanner modules (" << cfg->scanner.modules.size() << "):" << endl; |
438 |
for (i = 0; i < cfg->scanner.modules.size(); i++) |
439 |
{ |
440 |
cout << "id: " << cfg->scanner.modules[i].id << endl; |
441 |
if (cfg->scanner.modules[i].id == CONFIG_MODULE_SOCKS || cfg->scanner.modules[i].id == CONFIG_MODULE_HTTP) |
442 |
{ |
443 |
if (cfg->scanner.modules[i].port > 0 && cfg->scanner.modules[i].port < 65536) |
444 |
cout << "port: " << cfg->scanner.modules[i].port << endl; |
445 |
else |
446 |
{ |
447 |
cout << "BAD PORT NUMBER: " << cfg->scanner.modules[i].port << endl; |
448 |
exit(1); |
449 |
} |
450 |
} |
451 |
} |
452 |
} |
453 |
if (cfg->scanner.source_pool.size() == 0) |
454 |
cout << "No source pool." << endl; |
455 |
else |
456 |
{ |
457 |
cout << "Source pool (" << cfg->scanner.source_pool.size() << "):" << endl; |
458 |
for (i = 0; i < cfg->scanner.source_pool.size(); i++) |
459 |
cout << "address: " << inet_ntoa(cfg->scanner.source_pool[i]) << endl; |
460 |
} |
461 |
cout << "Targets (" << cfg->scanner.targets.size() << "):" << endl; |
462 |
for (i = 0; i < cfg->scanner.targets.size(); i++) |
463 |
{ |
464 |
cout << "address: " << inet_ntoa(cfg->scanner.targets[i].address); |
465 |
cout << " port: " << cfg->scanner.targets[i].port; |
466 |
cout << endl; |
467 |
} |
468 |
cout << "target_check: " << cfg->scanner.target_check << endl; |
469 |
|
470 |
cout << "CACHE config:" << endl; |
471 |
cout << "expire: " << cfg->cache.expire << " (seconds)" << endl; |
472 |
cout << "maxips: " << cfg->cache.maxips << endl << endl; |
473 |
|
474 |
cout << "NOSCAN config:" << endl; |
475 |
for (i = 0; i < cfg->noscan.address.size(); i++) |
476 |
{ |
477 |
cout << "noscan: " << inet_ntoa(cfg->noscan.address[i].network); |
478 |
cout << "/" << inet_ntoa(cfg->noscan.address[i].netmask) << endl; |
479 |
} |
480 |
} |