/[echolot]/trunk/pingd
ViewVC logotype

Contents of /trunk/pingd

Parent Directory Parent Directory | Revision Log Revision Log


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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.5