New features, and bugfix for faimond
Jonas Eriksson
zqad at hpc2n.umu.se
Wed Aug 29 10:17:16 CEST 2007
On Tue, Aug 28, 2007 at 09:31:47PM +0200 Thomas Lange wrote:
> >>>>> On Tue, 28 Aug 2007 17:53:35 +0200, Jonas Eriksson <zqad at hpc2n.umu.se> said:
>
> OK, I'm wondering, because the command die normally kill the whole
> script. I did not test it but from the code it should die IMO.
The model for this is not always that obvious, but it's a short
and simple way to solve the problem.
http://www.sunsite.ualberta.ca/Documentation/Misc/perl-5.6.1/pod/perlfunc/eval.html
has a quite interesting write-up on the subject if you are
intresed in more detailed information.
> > So, how should i design the patch? Should the standard behaviour
> > of faimond be to not fork and not print timestamps?
> Yep.
>
> Ah now I understand. It seems that the Proc::Daemon creates a new
> process for every connection. Then the die command will not kill the
> daemon but IMO it a little bit overhead. But anyhow, if you like to
> use Proc::Daemon then do it.
No, Proc::Daemon just forks twice, closes all file descripors
and all things that is supposed to happen when daemonizing.
> The only thing I need for faimond-gui is that faimond prints the
> messages from all install clients without timestamps to stdout. If this
> is possible (or the default) I'm happy with your faimond version.
> Please check the indentation of the code. Sometimes you are using 8
> spaces instead of two.
Fixed in included patch. Had some problems with vim settings, but
it should all be ok now.
> Please tell them to fill out the FAI questionnaire.
I will ask them to do that, and be sure to do it myself. Actually
I've missed it totally, but it's a good idea and will honour it.
> > in this case should start an own instance of faimond and read
> AFAIK it's not possible that tow process are listening on the same
> port.
Well, not at the same time. I was probably just thinking our a
bit too loud, and will not interfere with the faimond-gui
development.
> And please update the man page for faimond (send me a patch for this).
Ah, the documentation. All to easy to forget. This diff includes
the faimond man page as well.
The updates to faimond required some changes in the
init.d-script, so I'm including an updated version of that as
well.
I have continued to work on some security measures, and added a
-i option to send the ip address of the connecting host instead
of the reported hostname to fai-chboot. This does not affect the
default behaviour, but makes other hosts unable to change status
for other hosts then itself, granted that you use the same ip
when fai:ing as live and supply faimond with -i.
Also, I discovered a serious security hole in the faimond when
using -b:
1. Start "faimond -b"
2. Telnet to the computer running faimond and type:
";echo TASKEND install 0", without " and press enter.
3. Note the extra line that the "faimond -b"-terminal outputs.
Imagine what would happen if you replace "echo" with "reboot"
(Don't try this part on a production server).
I've solved this in my latest faimond-patch by instead sending a
list to the system()-call. If we pass a list to system() it will
just use the list as an argument vector.
Given this, I recommend a security update as soon as possible.
Best regards,
Jonas
-------------------------------------
- Jonas Eriksson, zqad at hpc2n.umu.se -
- sysadmin @ hpc2n.umu.se -
-------------------------------------
-------------- next part --------------
Index: bin/faimond
===================================================================
--- bin/faimond (revision 4532)
+++ bin/faimond (working copy)
@@ -1,4 +1,5 @@
#!/usr/bin/perl -w
+# vim:et:ts=2:sw=2:
# $Id$
#*********************************************************************
@@ -14,38 +15,126 @@
use strict;
use Socket;
use Getopt::Std;
+use Proc::Daemon;
$| = 1;
-my $port;
-our ($opt_b,$opt_h,$opt_p);
+my ($port, $timeout, $daemon, $timestamp);
+my $pidfile = '/var/run/faimond.pid';
+my $logfile = '-';
+my $daemonlogfile = '/var/log/faimond.log';
+my $useip;
+
+our ($opt_b,$opt_h,$opt_p,$opt_l,$opt_t,$opt_d,$opt_P,$opt_T,$opt_i);
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+sub logline(@) {
+ open(LOGFILE, $logfile) or return 0;
+ print LOGFILE (scalar localtime(), ' - ') if ($timestamp);
+ print LOGFILE @_ or return 0;
+ close(LOGFILE);
+ return 1;
+}
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+sub signal_die(@) {
+ logline(@_);
+ unlink($pidfile);
+ exit(1);
+}
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+sub signal_warn(@) {
+ logline(@_) or die "log: $!";
+}
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+sub signal_deadly(@) {
+ # Use the die-handler
+ signal_die('Caught deadly signal ' . shift() . "\n");
+}
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub server_init() {
+ logline("FAI monitoring daemon starting..\n") or die "log: $!";
+ # Init signals
+ $SIG{INT} = \&signal_deadly;
+ $SIG{QUIT} = \&signal_deadly;
+ $SIG{TERM} = \&signal_deadly;
+ $SIG{__DIE__} = \&signal_die;
+ $SIG{__WARN__} = \&signal_warn;
+ # HUP is usually used to reopen log files. This is not a problem
+ # in this design.
+ $SIG{HUP} = 'IGNORE';
+
+ if ($daemon) {
+ if (-e $pidfile) {
+ # Pid file already exists. Check if it's a valid pid.
+ open(PIDFILE, '<', "$pidfile") or die "open $pidfile: $!";
+ my $pid = <PIDFILE>;
+ chomp($pid);
+ if ($pid ne '') {
+ # Kill -0 exits with value 0 if pid is alive
+ system("kill -0 $pid 2> /dev/null");
+ if ($? == 0) {
+ logline("Pidfile $pidfile exists and contains an existing pid. Exiting.\n");
+ exit(1);
+ }
+ }
+ close(PIDFILE);
+ }
+ Proc::Daemon::Init;
+ umask 022;
+
+ open(PIDFILE, '>', "$pidfile") or die "open $pidfile: $!";
+ print PIDFILE $$ or die "print $pidfile: $!";
+ close(PIDFILE);
+ }
+
+ # Listen
my $proto = getprotobyname('tcp');
socket(SERVER, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
- setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1) or die "setsock: $!";
+ setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1) or die "setsockopt: $!";
my $paddr = sockaddr_in($port, INADDR_ANY);
bind(SERVER, $paddr) or die "bind: $!";
listen(SERVER, SOMAXCONN) or die "listen: $!";
- print "FAI monitoring daemon started on port $port\n";
+ logline("FAI monitoring daemon started on port $port with pid $$\n") or die "log: $!";
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sub big_loop() {
# accept a connection, print message received and close
- my ($client_addr,$inp);
+ my ($client_addr);
while ($client_addr = accept(CLIENT, SERVER)) {
- $inp = <CLIENT>;
+ my ($port, $iaddr) = sockaddr_in($client_addr);
+ my $ip = inet_ntoa($iaddr);
+
+ my $inp = '';
+
+ eval {
+ local $SIG{__DIE__};
+ local $SIG{__WARN__};
+ local $SIG{'ALRM'} = sub { die("Timeout"); };
+
+ alarm($timeout);
+ $inp = <CLIENT>;
+ alarm(0);
+ };
+
close CLIENT;
+ if (!defined($inp) || $inp eq '') {
+ # Client did not send anything, or alarm went off
+ logline("$ip:$port: No data or timeout.\n") or die "log: $!";
+ next;
+ }
+
if ($inp =~ /^(\S+)\s+TASKEND install 0/ && $opt_b) {
my $cname = $1;
- system("fai-chboot -d $cname");
- # warn "Disabling pxelinux configuration for $cname\n";
- }
- print "$inp";
+ if ($useip) {
+ $cname = $ip;
+ }
+ system('fai-chboot', '-d', $cname);
+ logline("$ip:$port: Disabling pxelinux configuration for $cname\n") or die "log: $!";
+ }
+ logline("$ip:$port: $inp") or die "log: $!";
}
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -54,21 +143,56 @@
print << "EOF";
faimond, FAI monitor daemon.
- Copyright (C) 2003-2007 by Thomas Lange
+ Copyright (C) 2003-2007 by Thomas Lange
-Usage: faimond [OPTION]
+Usage: faimond [OPTIONS]
- -b Call fai-chboot to change boot parameter.
- -p PORT Set port to listen to. Default is 4711.
+ -b Call fai-chboot to change boot parameter.
+ -p PORT Set port to listen to. Default is 4711.
+ -l FILE Logfile. Default is standard out and
+ '$daemonlogfile' in daemon mode.
+ -t TIMEOUT Timeout for bad clients. 0 to disable.
+ -d Daemon mode.
+ -P FILE PID-file. Default is '$pidfile'.
+ Used only if starting in daemon mode.
+ -T Print timestamps in the log.
+ -i When using -b: send IP of client to fai-choot
+ instead of the hostname the host reports.
EOF
exit 0;
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-getopts('bhp:') || usage;
+getopts('bhTp:l:t:dP:i') || usage;
$opt_h && usage;
$port = $opt_p || 4711;
+$timeout = $opt_t || 5;
+$daemon = $opt_d || 0;
+$timestamp = $opt_T || 0;
+$useip = $opt_i || 0;
+if (defined($opt_P)) {
+ $pidfile = $opt_P;
+}
+
+if (defined($opt_d)) {
+ # If in daemon mode, use standard daemon log file
+ $logfile = $daemonlogfile;
+}
+
+if (defined($opt_l)) {
+ $logfile = $opt_l;
+}
+
+# Constuct a $logfile that open can take as an argument
+if ($logfile eq '-') {
+ $logfile = ">&STDOUT";
+}
+else {
+ $logfile = ">>$logfile";
+}
+
+
server_init;
big_loop;
Index: man/faimond.8
===================================================================
--- man/faimond.8 (revision 4532)
+++ man/faimond.8 (working copy)
@@ -17,6 +17,28 @@
.B "-b "
Call fai-chboot for the install client if it task install was finished
properly. Default is not to call fai-chboot.
+.TP
+.B "-i"
+Use IP address of connecting host when calling fai-chboot. This can only be used
+if the hosts has the same IP when installning as when running.
+.TP
+.B "-l FILE"
+Logfile. Default is standard out in non-daemon mode and "/var/log/faimond.log"
+in daemon mode.
+.TP
+.B "-t TIMEOUT"
+Timeout for bad clients. 0 to disable.
+.TP
+.B "-d"
+Daemon mode.
+.TP
+.B "-P FILE"
+PID-file. Default is "/var/run/faimond.pid". Used only if starting in daemon
+mode.
+.TP
+.B "-T"
+Print timestamps in the log.
+.TP
.SH NOTES
Normally, the output will be piped to a GUI interface which displays
all information.
-------------- next part --------------
#! /bin/sh
# /etc/init.d/faimond: start/stop/restart faimond
# vim:et:sw=4:ts=4:
PATH=/bin:/sbin:/usr/bin:/usr/sbin
pidfile=/var/run/faimond.pid
binpath=/usr/sbin/faimond
test -x $binpath || exit 0
# Options for start/restart of the daemon
# Add "-b" to let faimond do a fai-chboot -d on installed clients
# Add "-T" to add timestamps to the log
# Add "-i" to use the connectors ip adress instead of reported host
# name.
# -d is required for daemon mode
FAIMOND="-d -T"
start() {
echo -n "Starting fai monitoring daemon: faimond"
start-stop-daemon --start --quiet --exec $binpath -- $FAIMOND
echo "."
}
stop() {
echo -n "Stopping fai monitoring daemon: faimond"
start-stop-daemon --stop --pidfile $pidfile
echo "."
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
sleep 1
start
;;
*)
echo "Usage: /etc/init.d/faimond {start|stop|restart}"
exit 1
esac
exit 0
More information about the linux-fai-devel
mailing list