ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/pxys2-2.0.0/pxyservd/src/scan.c
Revision: 3252
Committed: Wed Apr 2 20:41:43 2014 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 14764 byte(s)
Log Message:
- Imported pxys2-2.0.0

File Contents

# Content
1 /* Copyright (C) 2003, 2004 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: scan.c,v 1.7 2004/01/12 12:31:03 mbuna Exp $"
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #ifndef IP_L1_CACHE_SIZE
27 #define IP_L1_CACHE_SIZE 10000
28 #endif
29 #ifndef IP_L1_CACHE_EXPIRE_DELAY
30 #define IP_L1_CACHE_EXPIRE_DELAY 21600
31 #endif
32
33 #define IP4_L1_CACHE_SIZE IP_L1_CACHE_SIZE
34 #define IP6_L1_CACHE_SIZE IP_L1_CACHE_SIZE
35
36 /* SCAN_TIMER_DELAY defines the delay of which pxyservd will check if
37 * some queries have failed (timeout) in order to retry.
38 */
39 #define SCAN_TIMER_DELAY 10
40
41 /* SCAN_QUERY_TIMEOUT defines a minimal timeout delay in seconds for a query.
42 * A query won't be resent until this time is elapsed.
43 * Should not be too low, or pxyscand will receive each time
44 * several queries for the same IP, for example.
45 * Shouldn't be too high, or it will alter the reactivity, when for
46 * example, pxyscand restarts.
47 * 3-5 minutes is probably a good value.
48 */
49 #define SCAN_QUERY_TIMEOUT 200
50
51 #include <assert.h>
52 #include <errno.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <unistd.h>
57
58 #include "scan.h"
59 #include <arpa/inet.h>
60
61 #include <opas/opas.h>
62 #include <peak/peak.h>
63
64 #include "opas_support.h"
65 #include "cfgloader.h"
66 #include "debug.h"
67 #include "evreg.h"
68 #include "ipcache.h"
69 #include "irc_gline.h"
70 #include "irc_network.h"
71 #include "irc_numnicks.h"
72 #include "irc_send.h"
73 #include "irc_userbase.h"
74 #include "irc_yxx.h"
75 #include "match.h"
76 #include "pxyservd_log.h"
77
78 #include "PXServiceMsg.h"
79
80 extern void cmd_status_reply(struct Client *cptr, PXSStatus *status,
81 size_t length);
82 extern void cmd_pxstats_reply(struct Client *cptr, PXSStats *stats);
83 extern void cmd_grem_reply(struct Client *cptr, PXSRemove4 *rem_reply);
84 extern void cmd_recheck_reply(struct Client *cptr, PXSRemove4 *rem_reply);
85
86 static void scan_timer_callback(peak_timer ti, void *context);
87 static int scan_check_cache(unsigned int flags, void *addrData,
88 time_t *out_scan_ts);
89 static void scan_query(unsigned int flags, const void *addrData,
90 uint32_t user_data);
91 static void scan_client_add(struct Client *cptr);
92
93 uint32_t l1_cache_hits; /* stats */
94
95 /* no-proxy little caches */
96 static ipcache_t ipcache4;
97 #ifdef ENABLE_IPV6
98 static ipcache_t ipcache6;
99 #endif
100 static struct Client *scan_client_head, **scan_client_tail_p;
101 static int scan_client_count;
102 static int unscannable_client_count;
103 static peak_timer scan_timer;
104
105 void
106 scan_init()
107 {
108 ipcache4 = ipcache_create_in4(IP4_L1_CACHE_SIZE, 0);
109 #ifdef ENABLE_IPV6
110 ipcache6 = ipcache_create_in6(IP6_L1_CACHE_SIZE, 0);
111 #endif
112 if (opas_support_init() == -1)
113 {
114 Debug((DL_BASIC, "scan_init: opas_support_init failed!"));
115 /* XXX */
116 abort();
117 }
118
119 scan_client_head = NULL;
120 scan_client_tail_p = NULL;
121 scan_client_count = 0;
122 l1_cache_hits = 0;
123 unscannable_client_count = 0;
124
125 scan_timer = peak_timer_create(SCAN_TIMER_DELAY, SCAN_TIMER_DELAY,
126 scan_timer_callback, NULL);
127 peak_task_timer_add(peak_task_self(), scan_timer);
128 peak_release(scan_timer); /* so that peak_task_timer_remove() releases it */
129 }
130
131 void
132 scan_finalize()
133 {
134 peak_task_timer_remove(peak_task_self(), scan_timer); /* implicit release */
135
136 opas_support_finalize();
137
138 #ifdef ENABLE_IPV6
139 ipcache_dispose(ipcache6);
140 #endif
141 ipcache_dispose(ipcache4);
142 }
143
144 static void
145 scan_timer_callback(peak_timer ti, void *context)
146 {
147 struct Client *cptr, *cnext;
148 time_t now = peak_time();
149
150 if (!scan_client_count)
151 return;
152
153 /* Check for timed out scan queries.
154 */
155 for (cptr = scan_client_head; cptr; cptr = cnext)
156 {
157 cnext = cptr->scan_next;
158
159 /* List is ordered, we know we can break. */
160 if (cptr->scan_timestamp + SCAN_QUERY_TIMEOUT > now)
161 break;
162
163 /* Try again ! It's our job damnit. */
164 scan_client_remove(cptr);
165 scan_start(cptr);
166 }
167 }
168
169 static int
170 scan_check_cache(unsigned int flags, void *addrData, time_t *out_scan_ts)
171 {
172 time_t ts = 0;
173
174 if (!(flags & CLIENT_FLAG_IPV6))
175 ts = ipcache_find_in4(ipcache4, (struct in_addr *)addrData, NULL);
176 #ifdef ENABLE_IPV6
177 else
178 ts = ipcache_find_in6(ipcache6, (struct in6_addr *)addrData, NULL);
179 #endif
180
181 if (ts > 0 && (peak_time() - ts <= IP_L1_CACHE_EXPIRE_DELAY))
182 {
183 *out_scan_ts = ts;
184 return 1;
185 }
186 return 0;
187 }
188
189 int
190 scan_check_noscan_server(struct Server *sptr)
191 {
192 CNoScanLink *lk;
193
194 for (lk = gConfig->noscanlist; lk; lk = lk->next)
195 {
196 if (lk->noscan.type == NOSCAN_TYPE_SERVER
197 && !match(lk->noscan.u.server, sptr->name))
198 return 1; /* noscan! */
199 }
200 return 0;
201 }
202
203 int
204 scan_check_noscan(const struct Client *cptr)
205 {
206 CNoScanLink *lk;
207 struct Server *sptr;
208
209 for (lk = gConfig->noscanlist; lk; lk = lk->next)
210 {
211 switch (lk->noscan.type)
212 {
213 case NOSCAN_TYPE_SERVER:
214 sptr = irc_network_get_server(cptr->nserv);
215 if (!match(lk->noscan.u.server, sptr->name))
216 return 1; /* noscan! */
217 break;
218
219 case NOSCAN_TYPE_USERIP:
220 {
221 if (cptr->flags & CLIENT_FLAG_IPV6)
222 break; /* No IPv6 noscan support yet */
223
224 if ((cptr->addr.ip4.s_addr & lk->noscan.u.userip.netmask.s_addr)
225 == (lk->noscan.u.userip.network.s_addr
226 & lk->noscan.u.userip.netmask.s_addr))
227 return 1; /* noscan! */
228 break;
229 }
230 }
231 }
232 return 0;
233 }
234
235 static void
236 scan_query(unsigned int flags, const void *addrData, uint32_t user_data)
237 {
238 int res;
239
240 if (!(flags & CLIENT_FLAG_IPV6))
241 res = opas_support_query((struct in_addr *)addrData, user_data);
242 else
243 res = opas_support_query6((struct in6_addr *)addrData, user_data);
244
245 if (res == -1)
246 {
247 char ipbuf[32];
248
249 inet_ntop(flags & CLIENT_FLAG_IPV6 ? AF_INET6 : AF_INET, addrData,
250 ipbuf, sizeof(ipbuf));
251 Debug((DL_BASIC, "scan_query: opas_support_query failed for %s\n",
252 ipbuf));
253 }
254 }
255
256 static void
257 scan_client_add(struct Client *cptr)
258 {
259 assert(!(cptr->flags & CLIENT_FLAG_SCANNING));
260
261 /* Set scanning flag for this client. */
262 cptr->flags |= CLIENT_FLAG_SCANNING;
263
264 /* Link at tail */
265 cptr->scan_next = NULL;
266 cptr->scan_prev_p = scan_client_tail_p;
267
268 if (cptr->scan_prev_p)
269 *cptr->scan_prev_p = cptr;
270 else
271 scan_client_head = cptr;
272 scan_client_tail_p = &cptr->scan_next;
273
274 scan_client_count++;
275 }
276
277 void
278 scan_client_remove(struct Client *cptr)
279 {
280 if (cptr->flags & CLIENT_FLAG_SCANFAIL)
281 unscannable_client_count--;
282
283 if (!(cptr->flags & CLIENT_FLAG_SCANNING))
284 return;
285
286 if (cptr->scan_prev_p)
287 *cptr->scan_prev_p = cptr->scan_next;
288 else
289 scan_client_head = cptr->scan_next;
290
291 if (cptr->scan_next)
292 cptr->scan_next->scan_prev_p = cptr->scan_prev_p;
293 else
294 scan_client_tail_p = cptr->scan_prev_p;
295
296 cptr->scan_next = NULL;
297 cptr->scan_prev_p = NULL;
298
299 scan_client_count--;
300
301 cptr->flags &= ~CLIENT_FLAG_SCANNING;
302 }
303
304 int
305 scan_client_get_count()
306 {
307 return scan_client_count;
308 }
309
310 int
311 scan_client_get_unscannable_count()
312 {
313 return unscannable_client_count;
314 }
315
316 /* External method scan_new_user()
317 * A new user has just connected to the network.
318 */
319 void
320 scan_new_user(struct Client *cptr)
321 {
322 /* First, check the noscan list and ignore user if it matchs
323 */
324 if (scan_check_noscan(cptr))
325 return;
326
327 /* Then, check our local "level one" cache of scanned IPs.
328 */
329 if (scan_check_cache(cptr->flags, &cptr->addr, &cptr->scan_timestamp))
330 {
331 l1_cache_hits++;
332 return;
333 }
334
335 /* Lame notice? ;)
336 */
337 if (gConfig->noticelist &&
338 !irc_network_server_is_bursting(irc_network_get_server(cptr->nserv)))
339 {
340 CNoticeLink *notice;
341
342 for (notice = gConfig->noticelist; notice; notice = notice->next)
343 {
344 char dst[6];
345 inttobase64(dst, cptr->nserv, 2);
346 inttobase64(dst + 2, cptr->nnick, 3);
347 dst[5] = '\0';
348 send_to_one(dst, "%s", notice->line);
349 }
350 }
351
352 /* No luck, start scan procedure.
353 */
354 scan_start(cptr);
355 }
356
357 void
358 scan_start(struct Client *cptr)
359 {
360 cptr->scan_timestamp = peak_time();
361 scan_client_add(cptr);
362
363 if (opas_support_is_ready())
364 scan_query(cptr->flags, &cptr->addr, yxx_pack_int(cptr->nserv,
365 cptr->nnick));
366 }
367
368 int
369 scan_send_command(struct Client *cptr, uint32_t sig, uint32_t cmd,
370 const void *data, size_t length)
371 {
372 PXSHeader *hp = (PXSHeader *)data;
373
374 #if 0
375 if (cptr->flags & CLIENT_FLAG_COMMAND)
376 return 0;
377 #endif
378
379 if (!opas_support_is_ready())
380 return -1; /* failure */
381
382 cptr->flags |= CLIENT_FLAG_COMMAND;
383
384 hp->sig = htonl(sig);
385 hp->ver = htonl(PX_VERSION);
386 hp->cmd = htonl(cmd);
387
388 opas_support_send_msg_user(hp, length, yxx_pack_int(cptr->nserv,
389 cptr->nnick));
390 return 0;
391 }
392
393 int
394 scan_send_simple_command(struct Client *cptr, uint32_t sig, uint32_t cmd)
395 {
396 PXSHeader head;
397 return scan_send_command(cptr, sig, cmd, &head, sizeof(head));
398 }
399
400 /* Replies from opas_support module.. */
401 void
402 scan_reply_noproxy(const struct in_addr *addrp, uint32_t ud, int cached)
403 {
404 struct Client *cptr = irc_network_find_client(yxx_unpack(ud));
405 /* Verify that, if a client still exists for this numeric, he has the same
406 * IP that we've just scanned.
407 */
408 if (cptr && cptr->addr.ip4.s_addr == addrp->s_addr
409 && (cptr->flags & CLIENT_FLAG_SCANNING))
410 {
411 scan_client_remove(cptr);
412 ipcache_add_in4(ipcache4, addrp, peak_time(), NULL);
413 Debug((DL_BASIC, "scan_reply_noproxy: scan took %d secs",
414 peak_time() - cptr->scan_timestamp));
415 }
416 }
417
418 void
419 scan_reply_proxy(const struct in_addr *addrp, uint32_t ud, int cached,
420 int proxy_type, uint16_t proxy_port, const char *proxy_descr)
421 {
422 const char *reason;
423 struct Client *cptr = irc_network_find_client(yxx_unpack(ud));
424
425 /* Verify that, if a client still exists for this numeric, he has the same
426 * IP that we've just scanned.
427 */
428 if (cptr && cptr->addr.ip4.s_addr == addrp->s_addr
429 && (cptr->flags & CLIENT_FLAG_SCANNING))
430 {
431 char ipbuf[16];
432 int cnt;
433 time_t scantime;
434
435 scan_client_remove(cptr);
436
437 scantime = peak_time() - cptr->scan_timestamp;
438
439 if (!inet_ntop(AF_INET, &cptr->addr.ip4, ipbuf, sizeof(ipbuf)))
440 return;
441
442 /* /!\ O(n) count but everyone likes it...
443 * Used for proxytop's stats too.
444 */
445 cnt = irc_userbase_proxycount(&cptr->addr.ip4);
446
447 if (cached)
448 {
449 log_write(LOGID_CURRENT, "*@%s [%ld] %s (%d) cached", ipbuf, cnt,
450 proxy_descr, proxy_port);
451
452 if (gConfig->client.show_cached)
453 send_msg_client_to_console("PG *@%s [%ld] %s at port %u (cached)",
454 ipbuf, cnt, proxy_descr, proxy_port);
455
456 evreg_broadcast(EVREG_FLAG_CACHED,
457 "[EV] PG *@%s [%ld] %s at port %u (cached)",
458 ipbuf, cnt, proxy_descr, proxy_port);
459 }
460 else
461 {
462 /* Logging */
463 log_write(LOGID_CURRENT, "*@%s [%ld] %s (%d)", ipbuf, cnt,
464 proxy_descr, proxy_port);
465
466 /* Console channel */
467 send_msg_client_to_console("PG *@%s [%ld] %s at port %u (%ds)", ipbuf,
468 cnt, proxy_descr, proxy_port, scantime);
469
470 /* Private event notification */
471 evreg_broadcast(EVREG_FLAG_NEWPROXY,
472 "[EV] PG *@%s [%ld] %s at port %u (%ds)",
473 ipbuf, cnt, proxy_descr, proxy_port, scantime);
474 }
475
476 if (proxy_type >= 0 && proxy_type < 8)
477 reason = gConfig->gline.reason[proxy_type];
478 else
479 reason = gConfig->gline.reason[0];
480
481 irc_gline_send(addrp, cnt, reason);
482 }
483 }
484
485 void
486 scan_reply_error(const struct in_addr *addrp, uint32_t ud, uint32_t error)
487 {
488 /* Ok, can't scan this IP.. no luck ! */
489 struct Client *cptr = irc_network_find_client(yxx_unpack(ud));
490
491 if (cptr && cptr->addr.ip4.s_addr == addrp->s_addr
492 && (cptr->flags & CLIENT_FLAG_SCANNING) && error != 1000)
493 {
494 char ipbuf[16];
495
496 scan_client_remove(cptr);
497 cptr->flags |= CLIENT_FLAG_SCANFAIL;
498 unscannable_client_count++;
499
500 /* Log it. */
501 if (!inet_ntop(AF_INET, &cptr->addr.ip4, ipbuf, sizeof(ipbuf)))
502 return;
503
504 log_write(LOGID_UNREACH, "%ld,%s", peak_time(), ipbuf);
505 }
506 }
507
508 void
509 scan_reply6_noproxy(const struct in6_addr *addrp, uint32_t ud, int cached)
510 {
511 /* Unused for now (who could we blame ?? :) */
512 }
513
514 void
515 scan_reply6_proxy(const struct in6_addr *addrp, uint32_t ud, int cached,
516 int proxy_type, uint16_t proxy_port, const char *proxy_descr)
517 {
518 /* Unused for now */
519 }
520
521 void
522 scan_reply6_error(const struct in6_addr *addrp, uint32_t ud, uint32_t error)
523 {
524 /* Unused for now */
525 }
526
527 void
528 scan_reply_command(void *data, size_t length, uint32_t ud)
529 {
530 struct Client *cptr = irc_network_find_client(yxx_unpack(ud));
531
532 if (cptr && (cptr->flags & CLIENT_FLAG_COMMAND)
533 && (length > sizeof(PXSHeader)))
534 {
535 PXSHeader *head = (PXSHeader *)data;
536
537 head->sig = ntohl(head->sig);
538 head->ver = ntohl(head->ver);
539 head->cmd = ntohl(head->cmd);
540
541 cptr->flags &= ~CLIENT_FLAG_COMMAND;
542
543 if (head->sig != PXYSCAND_SIG || head->ver != PX_VERSION)
544 return;
545
546 /* Reply looks fine */
547 switch (head->cmd)
548 {
549 case PX_CMD_STATUS:
550 cmd_status_reply(cptr, (PXSStatus *)data, length);
551 break;
552 case PX_CMD_STATS:
553 cmd_pxstats_reply(cptr, (PXSStats *)data);
554 break;
555 case PX_CMD_REMOVE:
556 if (cptr->flags & CLIENT_FLAG_GREM)
557 cmd_grem_reply(cptr, (PXSRemove4 *)data);
558 else
559 cmd_recheck_reply(cptr, (PXSRemove4 *)data);
560 break;
561 default:
562 break;
563 }
564 }
565 }