/[echolot]/branches/snapshot-2003-02-17-branch/pingd
ViewVC logotype

Contents of /branches/snapshot-2003-02-17-branch/pingd

Parent Directory Parent Directory | Revision Log Revision Log


Revision 234 - (show annotations) (download)
Sun Aug 11 14:57:23 2002 UTC (10 years, 9 months ago) by weasel
Original Path: trunk/pingd
File size: 18165 byte(s)
Make that /etc/echolot/pingd.conf
1 #!/usr/bin/perl -w
2
3 $| = 1;
4
5 # (c) 2002 Peter Palfrader <peter@palfrader.org>
6 # $Id: pingd,v 1.59 2002/08/11 14:57:23 weasel Exp $
7 #
8
9 =pod
10
11 =head1 NAME
12
13 pingd - echolot ping daemon
14
15 =head1 SYNOPSIS
16
17 =over
18
19 =item B<pingd> B<start>
20
21 =item B<pingd> B<stop>
22
23 =item B<pingd> B<process>
24
25 =item B<pingd> B<add> I<address> [I<address> ...]
26
27 =item B<pingd> B<delete> I<address> [I<address> ...]
28
29 =item B<pingd> B<set> option=value [option=value..] I<address> [I<address> ...]
30
31 =item B<pingd> B<setremailercaps> I<capsstring>
32
33 =item B<pingd> B<deleteremailercaps> I<address>
34
35 =item B<pingd> B<getkeyconf> [I<address> [I<address> ...]]
36
37 =item B<pingd> B<buildstats>
38
39 =item B<pingd> B<buildkeys>
40
41 =item B<pingd> B<buildthesaurus>
42
43 =item B<pingd> B<dumpconf>
44
45 =back
46
47 =head1 DESCRIPTION
48
49 pingd is a the heart of echolot. Echolot is a pinger for anonymous remailers.
50
51 A Pinger in the context of anonymous remailers is a program that regularily
52 sends messages through remailers to check their reliability. It then calculates
53 reliability statistics which are used by remailer clients to choose the chain
54 of remailers to use.
55
56 Additionally it collects configuration parameters and keys of all remailers and
57 offers them in a format readable by remailer clients.
58
59 When called without parameters pingd schedules tasks like sending pings,
60 processing incoming mail and requesting remailer-xxx data and runs them in
61 configurable intervalls.
62
63 =head1 COMMANDS
64
65 =over
66
67 =item B<start>
68
69 Start the ping daemon.
70
71 =item B<stop>
72
73 Send the running pingd process a SIGTERM.
74
75 =item B<process>
76
77 Sends a HUP signal to the daemon which instructs it to process the commands.
78
79 For other affects of sending the HUP Signal see the SIGNALS section below.
80
81 =item B<add> I<address> [I<address> ...]
82
83 Add I<address> to the list of remailers to query for
84 keys and confs.
85
86 =item B<delete> I<address> [I<address> ...]
87
88 Delete I<address> from the list of remailers to query for
89 keys and confs. Delete all statistics and keys for that remailer.
90
91 =item B<set> option=value [option=value..] I<address> [I<address> ...]
92
93 Possible options and values:
94
95 =over
96
97 =item B<showit=>{B<on>,B<off>}
98
99 Set B<showit> (show remailer in mlist, rlist etc.) for remailer I<address> to
100 either B<on> or B<off>.
101
102 =item B<pingit=>{B<on>,B<off>}
103
104 Set B<pingit> (send out pings to that remailer) for remailer I<address> to
105 either B<on> or B<off>.
106
107 =item B<fetch=>{B<on>,B<off>}
108
109 Set B<fetch> (fetch remailer-key and remailer-conf) for remailer I<address> to
110 either B<on> or B<off>.
111
112 =back
113
114 =item B<setremailercaps> I<capsstring>
115
116 Some remailers (Mixmaster V2 - currently lcs and passthru2) don't return a
117 useable remailer-conf message. For such remailers you need to set it manually.
118
119 For instance:
120
121 ./pingd setremailercaps '$remailer{"passthru2"} = "<mixer@immd1.informatik.uni-erlangen.de> mix middle";'
122 ./pingd setremailercaps '$remailer{"lcs"} = "<mix@anon.lcs.mit.edu> mix klen1000";'
123
124 =item B<deleteremailercaps> I<address>
125
126 Delete remailer-conf data for I<address>. The config data will be reset from
127 the next valid remailer-conf reply by the remailer.
128
129 =item B<getkeyconf> [I<address> [I<address> ...]]
130
131 Send a command to immediatly request keys and configuration from remailers.
132 If no addresses are given, then requests will be sent to all remailers.
133
134 =item B<buildstats>
135
136 Send a command to immediatly rebuild stats.
137
138 =item B<buildkeys>
139
140 Send a command to immediatly rebuild the keyrings.
141
142 =item B<buildthesaurus>
143
144 Send a command to immediatly rebuild the Thesaurus.
145
146 =item B<dumpconf>
147
148 Dumps the current configuration to standard output.
149
150 =back
151
152 =head1 OPTIONS
153
154 =over
155
156 =item B<--basedir>
157
158 The home directory to which everything else is relative to. See the BASE
159 DIRECTORY section below.
160
161 =item B<--verbose>
162
163 Verbose mode. Causes B<pingd> to print debugging messages about its progress.
164
165 =item B<--help>
166
167 Print a short help and exit sucessfully.
168
169 =item B<--version>
170
171 Print version number and exit sucessfully.
172
173 =item B<--nohup>
174
175 Usefull only with the B<add>, B<set>, B<setremailercaps>,
176 B<deleteremailercaps>, B<getkeyconf>, B<buildstats>, B<buildkeys>,
177 or B<buildthesaurus> command.
178
179 Don't send a HUP signal to the daemon which instructs it to process the
180 commands after adding the command to the task list.
181
182 Per default such a signal is sent.
183
184 =item B<--process>
185
186 Usefull only with the B<start> command.
187
188 Read and process the commands file on startup.
189
190 =item B<--detach>
191
192 Usefull only with the B<start> command.
193
194 Tell B<pingd> to detach.
195
196 =back
197
198 =head1 BASE DIRECTORY
199
200 The home directory to which everything else is relative to.
201
202 Basedir defaults to whatever directory the B<pingd> binary is located. It can
203 get overridden by the B<ECHOLOT_HOME> environment variable which in turn is
204 weaker than the B<--basedir> setting.
205
206 This directory is then used to locate the configuration file B<pingd.conf> (see
207 FILES below).
208
209 The B<homedir> setting in B<pingd.conf> finally sets the base directory.
210
211 =head1 FILES
212
213 The configuration file is searched in those places in that order:
214
215 =over
216
217 =item the file pointed to by the B<ECHOLOT_CONF> environment variable
218
219 =item <basedir>/pingd.conf
220
221 =item $HOME/echolot/pingd.conf
222
223 =item $HOME/pingd.conf
224
225 =item $HOME/.pingd.conf
226
227 =item /etc/echolot/pingd.conf
228
229 =item /etc/pingd.conf
230
231 =back
232
233 =head1 ENVIRONMENT
234
235 =over
236
237 =item ECHOLOT_CONF echolot config file (see section FILES)
238
239 =item ECHOLOT_HOME echolot base directory (see section BASE DIRECTORY)
240
241 =back
242
243 =head1 SIGNALS
244
245 On B<SIGINT>, B<SIGQUIT>, and B<SIGTERM> B<pingd> will schedule a shutdown
246 for as soon as the current actions are finished or immediatly if no actions are
247 currently beeing processed. It will then write all metadata and pingdata to
248 disk and close all files cleanly before exiting.
249
250 On B<SIGHUP> <pingd> will execute any pending commands from the commands file
251 (B<commands.txt> per default). It also closes and reopens the file 'output'
252 which is used for stdout and stderr in case the daemon was told to detach.
253 This can be used if you want to rotate that file.
254
255 =head1 AUTHOR
256
257 Peter Palfrader E<lt>peter@palfrader.orgE<gt>
258
259 =head1 BUGS
260
261 Please report them at E<lt>URL:http://savannah.gnu.org/bugs/?group=echolotE<gt>
262
263 =cut
264
265 use strict;
266 use FindBin qw{ $Bin };
267 use lib ( $Bin, "$Bin/lib" );
268 use Getopt::Long;
269 use English;
270 use Carp;
271 use Echolot::Config;
272 use Echolot::Globals;
273 use Echolot::Storage::File;
274 use Echolot::Scheduler;
275 use Echolot::Conf;
276 use Echolot::Mailin;
277 use Echolot::Pinger;
278 use Echolot::Stats;
279 use Echolot::Commands;
280 use Echolot::Thesaurus;
281 use POSIX qw(setsid);
282
283 delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
284
285
286 my $VERSION = '2.0beta25';
287
288
289 my $redirected_stdio = 0;
290
291 sub setSigHandlers() {
292 $SIG{'HUP'} = sub {
293 print "Got SIGHUP. scheduling readcommands\n";
294 Echolot::Globals::get()->{'scheduler'}->schedule('readcommands', time() );
295 if ($redirected_stdio) {
296 close STDOUT;
297 close STDERR;
298 open (STDOUT, ">>output") or die ("Cannot open 'output' as STDOUT\n");
299 open (STDERR, ">&STDOUT") or die ("Cannot dup STDOUT as STDERR\n");
300 };
301 };
302 $SIG{'INT'} = sub {
303 print "Got SIGINT. scheduling exit\n";
304 Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() );
305 };
306 $SIG{'QUIT'} = sub {
307 print "Got SIGQUIT. scheduling exit\n";
308 Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() );
309 };
310 $SIG{'TERM'} = sub {
311 print "Got SIGTERM. scheduling exit\n";
312 Echolot::Globals::get()->{'scheduler'}->schedule('exit', time() );
313 };
314 };
315
316
317
318 sub commit_prospective_address() {
319 Echolot::Globals::get()->{'storage'}->commit_prospective_address();
320 };
321 sub expire() {
322 Echolot::Globals::get()->{'storage'}->expire();
323 };
324
325
326
327
328
329 sub command_adddelete(@) {
330 my $command = shift @_;
331 my @argv = @_;
332
333 die ("command_adddelete requires command\n") unless defined $command;
334 die ("add requires argument <address>\n") unless scalar @argv;
335 my @addresses;
336 for my $address (@argv) {
337 die ("argument <address> is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ );
338 push @addresses, $address;
339 };
340 for my $address (@addresses) {
341 Echolot::Commands::addCommand("$command $address");
342 };
343 };
344
345 sub command_set(@) {
346 my @argv = @_;
347
348 my @settings;
349 while (scalar @argv && $argv[0] =~ /^(showit|pingit|fetch)=(on|off)$/) {
350 push @settings, $argv[0];
351 shift @argv;
352 };
353
354 my @addresses;
355 for my $address (@argv) {
356 die ("argument $address is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ );
357 push @addresses, $address;
358 };
359
360 for my $address (@argv) {
361 for my $setting (@settings) {
362 Echolot::Commands::addCommand("set $address $setting");
363 };
364 };
365 };
366
367 sub command_setremailercaps(@) {
368 my @argv = @_;
369
370 my @caps;
371 for my $caps (@argv) {
372 my ($remailer_nick, $remailer_address) = ($caps =~ /^\s* \$remailer{"(.*)"} \s*=\s* "<(.*@.*)>.*"; \s*$/ix);
373 die ("caps '$caps' is not a valid remailer caps line\n") unless (defined $remailer_nick && defined $remailer_address);
374 push @caps, {
375 address => $remailer_address,
376 caps => $caps };
377 };
378 for my $caps (@caps) {
379 Echolot::Commands::addCommand("setremailercaps ".$caps->{'address'}." ".$caps->{'caps'});
380 };
381 };
382
383 sub command_deleteremailercaps(@) {
384 my @argv = @_;
385
386 my @addresses;
387 for my $address (@argv) {
388 die ("argument $address is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ );
389 push @addresses, $address;
390 };
391
392 for my $address (@addresses) {
393 Echolot::Commands::addCommand("deleteremailercaps $address");
394 };
395 };
396
397 sub command_getkeyconf(@) {
398 my @argv = @_;
399
400 my @addresses;
401 for my $address (@argv) {
402 die ("argument $address is not a valid email address\n") unless ($address =~ /^[a-zA-Z0-9+._-]+\@[a-zA-Z0-9+.-]+$/ );
403 push @addresses, $address;
404 };
405
406 push @addresses, 'all' unless (scalar @addresses);
407
408 for my $address (@addresses) {
409 Echolot::Commands::addCommand("getkeyconf $address");
410 };
411 };
412
413
414 sub pid_exists() {
415 return (-e Echolot::Config::get()->{'pidfile'});
416 };
417
418 sub daemon_run($) {
419 my ($process) = @_;
420
421 die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' exists\n")
422 if pid_exists();
423 open (PIDFILE, '>'.Echolot::Config::get()->{'pidfile'}) or
424 confess ("Cannot open pidfile '".Echolot::Config::get()->{'pidfile'}."': $!\n");
425 print PIDFILE "$PROCESS_ID ".Echolot::Globals::get()->{'hostname'}." ".time()."\n";
426 close PIDFILE;
427
428 Echolot::Globals::initStorage();
429 setSigHandlers();
430
431 Echolot::Globals::get()->{'scheduler'} = new Echolot::Scheduler;
432 my $scheduler = Echolot::Globals::get()->{'scheduler'};
433 $scheduler->add('exit' , -1 , 0, 'exit' );
434 $scheduler->add('readcommands' , -1 , 0, \&Echolot::Commands::processCommands );
435
436 $scheduler->add('processmail' , Echolot::Config::get()->{'processmail'} , 0, \&Echolot::Mailin::process );
437 $scheduler->add('ping' , Echolot::Config::get()->{'pinger_interval'} , 0, \&Echolot::Pinger::send_pings );
438 $scheduler->add('buildstats' , Echolot::Config::get()->{'buildstats'} , 0, \&Echolot::Stats::build_stats );
439 $scheduler->add('buildkeys' , Echolot::Config::get()->{'buildkeys'} , 0, \&Echolot::Stats::build_keys );
440 $scheduler->add('buildthesaurus' , Echolot::Config::get()->{'buildthesaurus'} , 0, \&Echolot::Thesaurus::build_thesaurus );
441
442 $scheduler->add('commitprospectives' , Echolot::Config::get()->{'commitprospectives'} , 0, \&commit_prospective_address );
443 $scheduler->add('expire' , Echolot::Config::get()->{'expire'} , 0, \&expire );
444 $scheduler->add('getkeyconf' , Echolot::Config::get()->{'getkeyconf_interval'}, 0, \&Echolot::Conf::send_requests );
445 $scheduler->add('check_resurrection' , Echolot::Config::get()->{'check_resurrection'} , 0, \&Echolot::Conf::check_resurrection );
446
447 Echolot::Globals::get()->{'scheduler'}->schedule('readcommands', time() )
448 if ($process);
449
450 $scheduler->run();
451
452 Echolot::Globals::get()->{'storage'}->commit();
453 Echolot::Globals::get()->{'storage'}->finish();
454
455 unlink (Echolot::Config::get()->{'pidfile'}) or
456 cluck ("Cannot unlink pidfile ".Echolot::Config::get()->{'pidfile'});
457 };
458
459 sub send_sig($) {
460 my ($sig) = @_;
461
462 die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' does not exist\n")
463 unless pid_exists();
464 open (PIDFILE, '<'.Echolot::Config::get()->{'pidfile'}) or
465 confess ("Cannot open pidfile '".Echolot::Config::get()->{'pidfile'}."': $!\n");
466 my $line = <PIDFILE>;
467 close PIDFILE;
468
469 my ($pid, $host, $time) = $line =~ /^(\d+) \s+ (\S+) \s+ (\d+) \s* $/x or
470 confess ("Cannot parse pidfile '$line'\n");
471 my $sent = kill $sig, $pid;
472 ($sent == 1) or
473 confess ("Did not send signal $sig to exactly one process but $sent. (pidfile reads $line)\n");
474 };
475
476 sub daemon_hup() {
477 send_sig(1);
478 };
479
480 sub daemon_stop() {
481 send_sig(15);
482 };
483
484 sub make_dirs() {
485 for my $dir (
486 Echolot::Config::get()->{'resultdir'},
487 Echolot::Config::get()->{'thesaurusdir'},
488 Echolot::Config::get()->{'private_resultdir'},
489 Echolot::Config::get()->{'gnupghome'},
490 Echolot::Config::get()->{'mixhome'},
491 Echolot::Config::get()->{'tmpdir'},
492 Echolot::Config::get()->{'storage'}->{'File'}->{'basedir'}
493 ) {
494 if ( ! -d $dir ) {
495 mkdir ($dir, 0755) or
496 confess ("Cannot create directory $dir: $!\n");
497 };
498 };
499 for my $dir (
500 Echolot::Config::get()->{'mailindir'},
501 Echolot::Config::get()->{'mailindir'}.'/cur',
502 Echolot::Config::get()->{'mailindir'}.'/tmp',
503 Echolot::Config::get()->{'mailindir'}.'/new',
504 Echolot::Config::get()->{'mailerrordir'},
505 Echolot::Config::get()->{'mailerrordir'}.'/cur',
506 Echolot::Config::get()->{'mailerrordir'}.'/tmp',
507 Echolot::Config::get()->{'mailerrordir'}.'/new'
508 ) {
509 if ( ! -d $dir ) {
510 mkdir ($dir, 0700) or
511 confess ("Cannot create directory $dir: $!\n");
512 };
513 };
514 };
515
516 sub hup_if_wanted($) {
517 my ($nohup) = @_;
518 if (!$nohup && pid_exists()) {
519 daemon_hup()
520 } else {
521 print "Don't forget to run $PROGRAM_NAME process.\n";
522 };
523 };
524
525
526
527
528
529
530
531
532
533
534 my $params = { basedir => $Bin };
535 $params->{'basedir'} = $ENV{'ECHOLOT_HOME'} if (defined $ENV{'ECHOLOT_HOME'});
536
537 Getopt::Long::config('bundling');
538 if (!GetOptions (
539 'help' => \$params->{'help'},
540 'version' => \$params->{'version'},
541 'verbose+' => \$params->{'verbose'},
542 'nohup' => \$params->{'nohup'},
543 'detach' => \$params->{'detach'},
544 'process' => \$params->{'process'},
545 'basedir' => \$params->{'basedir'},
546 )) {
547 die ("$PROGRAM_NAME: Usage: $PROGRAM_NAME [-fwhv]\n");
548 };
549 if ($params->{'help'}) {
550 print ("Usage: $PROGRAM_NAME [options] command\n");
551 print ("See man pingd or perldoc pingd for more info.\n");
552 print ("echolot $VERSION - (c) 2002 Peter Palfrader <peter\@palfrader.org>\n");
553 print ("http://savannah.gnu.org/projects/echolot/\n");
554 print ("\n");
555 print ("Commands:\n");
556 print (" start starts echolot pingd\n");
557 print (" signals pingd to ... \n");
558 print (" stop ... shutdown\n");
559 print (" process ... reopen outfile and process commands\n");
560 print (" add ... add a remailer address\n");
561 print (" delete ... delete a remailer address\n");
562 print (" set ... set remailer options\n");
563 print (" setremailercaps ... set remailer capabilities manually\n");
564 print (" deleteremailercaps ... delete remailer capabilities manually\n");
565 print (" getkeyconf ... request remailer-xxx data immediatly\n");
566 print (" buildstats ... build remailer stats immediatly\n");
567 print (" buildkeys ... buid keyrings immediatly\n");
568 print (" buildthesaurus ... build thesaurus immediatly\n");
569 print (" dumpconf dump configuration\n");
570 exit 0;
571 };
572 if ($params->{'version'}) {
573 print ("echolot $VERSION\n");
574 print ("(c) 2002 Peter Palfrader <peter\@palfrader.org>\n");
575 print ("http://savannah.gnu.org/projects/echolot/\n");
576 exit 0;
577 };
578
579 my $COMMAND = shift @ARGV;
580 die ("command required\n") unless defined $COMMAND;
581
582
583 Echolot::Config::init( $params );
584 chdir( Echolot::Config::get()->{'homedir'} );
585 Echolot::Globals::init( version => $VERSION);
586
587
588 if ($COMMAND eq 'add' || $COMMAND eq 'delete') {
589 command_adddelete($COMMAND, @ARGV);
590 hup_if_wanted($params->{'nohup'});
591 } elsif ($COMMAND eq 'set') {
592 command_set(@ARGV);
593 hup_if_wanted($params->{'nohup'});
594 } elsif ($COMMAND eq 'deleteremailercaps') {
595 command_deleteremailercaps(@ARGV);
596 hup_if_wanted($params->{'nohup'});
597 } elsif ($COMMAND eq 'setremailercaps') {
598 command_setremailercaps(@ARGV);
599 hup_if_wanted($params->{'nohup'});
600 } elsif ($COMMAND eq 'getkeyconf') {
601 command_getkeyconf(@ARGV);
602 hup_if_wanted($params->{'nohup'});
603 } elsif ($COMMAND eq 'buildstats') {
604 Echolot::Commands::addCommand("buildstats");
605 hup_if_wanted($params->{'nohup'});
606 } elsif ($COMMAND eq 'buildkeys') {
607 Echolot::Commands::addCommand("buildkeys");
608 hup_if_wanted($params->{'nohup'});
609 } elsif ($COMMAND eq 'buildthesaurus') {
610 Echolot::Commands::addCommand("buildthesaurus");
611 hup_if_wanted($params->{'nohup'});
612 } elsif ($COMMAND eq 'process') {
613 daemon_hup();
614 } elsif ($COMMAND eq 'stop') {
615 daemon_stop();
616 } elsif ($COMMAND eq 'start') {
617 die ("Pidfile '".Echolot::Config::get()->{'pidfile'}."' exists\n")
618 if pid_exists();
619 make_dirs();
620 if ($params->{'detach'}) {
621 print "Detaching.\n";
622 exit(0) if (fork());
623 POSIX::setsid();
624 exit(0) if (fork());
625 close STDOUT;
626 close STDERR;
627 open (STDOUT, ">>output") or die ("Cannot open 'output' as STDOUT\n");
628 open (STDERR, ">&STDOUT") or die ("Cannot dup STDOUT as STDERR\n");
629 close STDIN;
630 $redirected_stdio = 1;
631 print "Startup at ".scalar localtime().".\n";
632 daemon_run( $params->{'process'} );
633 print "done at ".scalar localtime().".\n";
634 } else {
635 daemon_run( $params->{'process'} );
636 };
637 } elsif ($COMMAND eq 'dumpconf') {
638 Echolot::Config::dump();
639 } elsif ($COMMAND eq 'convert') {
640 Echolot::Globals::initStorage();
641 setSigHandlers();
642
643 Echolot::Globals::get()->{'storage'}->convert();
644
645 Echolot::Globals::get()->{'storage'}->commit();
646 Echolot::Globals::get()->{'storage'}->finish();
647 } else {
648 die ("Command $COMMAND unknown");
649 };
650
651 exit 0;
652
653 # vim: set ts=4 shiftwidth=4:

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.5