Progress Today....
Marten Terpstra
Thu Feb 17 12:17:09 CET 1994
Andrew Adams <ala at merit.edu> writes * * Well, we made much great progress today installing RIPE db stuff * on a Merit machine here. Things have gone wonderfully so far. * Installation was smooth and we've been playing with adding a few * nets, people, ASs, etc to a copy of the ripe.db file using the * 'dbupdate' command. Congratulations to you guys for making the software * so easy to install! :-) Thank you. * So having gone though all this today, do you think we're ready * to play with the "guarded object" stuff? OK, first, I have made quite some changed this morning, because most of the guarded stuff was kind of hardcoded (mail messages and the like) and the database software has a habit of mailing out loads of things, so I included a testmode, which will cause all mails that would normally be send to people updating the database, or guardians etc, to be send to one configurable address, so you can test, and not bother other people with acknowledgement and other mails. I have included the changes below. What you do is unshar the shell archive below, replace dbupdate.pl, cleandb.pl, notify.pl and rconf.pl in the src directory by the new ones supplied in the shar file, go to the top directory and say "make install". Then there is a file with the additions you should make to the config, called conf.additions. Put this somewhere in the conf file, and modify where you need. * A more specific question concerns the MAILTXT lines in the conf * file. It's not clear from the comments that precede those lines * how exactly they should look. Where are the $ variables defined? There are not defined, but determined based on whatever the program is evaluating at the time. For instance, when dbupdate is handling an email message, $FROM will be set to the From or Reply-To field from the current mail message, $SUBJECT is set to the Subject line of the current mail message etc. These are things that cannot be determined in advance, but depend on the input. I thought it would be nice to put them in like this. MAILTXT simply takes the body of the acknowledgement message that will be send back to someone who did an update using email. Some more message coming up, mainly about the things that are still hardcoded (which are attributes that affect software behaviour) and the guarded stuff. I'll split them into bits (so I can also keeep them for my own documentation ;-) -Marten #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: conf.additions dbupdate.pl rconf.pl cleandb.pl notify.pl # Wrapped by marten at rijp.ripe.net on Thu Feb 17 12:05:08 1994 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f conf.additions -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"conf.additions\" else echo shar: Extracting \"conf.additions\" \(2010 characters\) sed "s/^X//" >conf.additions <<'END_OF_conf.additions' X# Run database sw in test mode? Testmode will cause ALL mail acks and other X# mail messages to be send to DEFMAIL defined further below. X XTESTMODE 1 X X# GRDCONFLICT - Text including header to be used in case of guardian X# conflicts. To field simply defaults to "guardian". It must be a X# local account/alias to mail to. X XGRDCONFLICT From: RIPE Database Conflict Handler <ripe-dbm at ripe.net> XGRDCONFLICT Subject: Guarded attributes conflicts found XGRDCONFLICT XGRDCONFLICT Dear Guardian, XGRDCONFLICT XGRDCONFLICT One or more conflicts have been found regarding guarded XGRDCONFLICT attributes in the RIPE database. Some of the conflicts XGRDCONFLICT concern the guarded values you are a guardian for. XGRDCONFLICT XGRDCONFLICT Please verify and correct the conflicts below. XGRDCONFLICT The guarded values for objects below have been set to XGRDCONFLICT the value they had in the database before this guarded XGRDCONFLICT attributes run. XGRDCONFLICT XGRDCONFLICT Kind Regards, XGRDCONFLICT RIPE Database Conflict Department XGRDCONFLICT ------ X X# SPLITMSG - Message (including header) to be send when a block of X# network numbers has been split due to guarded attribute addition. X# The To field is always the email address that last changed the X# network block. Some variables to be used here as well: X# $BEGINADDRESS - first address of the block that was split X# $ENDADDRESS - last address of the block that was split X XSPLITMSG From: RIPE Database Management <ripe-dbm at ripe.net> XSPLITMSG Subject: $BEGINADDRESS - $ENDADDRESS has been split XSPLITMSG XSPLITMSG XSPLITMSG Dear last changer of the RIPE database entry XSPLITMSG $BEGINADDRESS - $ENDADDRESS, XSPLITMSG XSPLITMSG This is to notify that network block $BEGINADDRESS - $ENDADDRESS XSPLITMSG has been split due to the addition of guarded attributes. It has XSPLITMSG been split into the objects displayed below in the RIPE database. XSPLITMSG XSPLITMSG Please update your local information accordingly, XSPLITMSG XSPLITMSG RIPE Database Maintenance Department END_OF_conf.additions if test 2010 -ne `wc -c <conf.additions`; then echo shar: \"conf.additions\" unpacked with wrong size! fi # end of overwriting check fi if test -f dbupdate.pl -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"dbupdate.pl\" else echo shar: Extracting \"dbupdate.pl\" \(9951 characters\) sed "s/^X//" >dbupdate.pl <<'END_OF_dbupdate.pl' X#!PERL X X# $RCSfile: dbupdate.pl,v $ X# $Revision: 0.26 $ X# $Author: marten $ X# $Date: 1994/02/17 09:39:43 $ X X# This is a client that will update objects read from a file directly X# in the database, without interference of updated. X# It will update the object in the database that is linked to the X# source field of the object, so better make sure you have a source field X# and that it has a database associated to it ... X X at INC = ("LIBDIR", @INC); X Xrequire "rfc822.pl"; Xrequire "enwrite.pl"; Xrequire "rconf.pl"; Xrequire "enparse.pl"; Xrequire "defines.pl"; Xrequire "dbadd.pl"; Xrequire "dbopen.pl"; Xrequire "adderror.pl"; Xrequire "getopts.pl"; Xrequire "entype.pl"; Xrequire "misc.pl"; Xrequire "syslog.pl"; Xrequire "handle.pl"; X X# Parse options: X# X# -l logfile - log output to file in stead of STDOUT X# -v - verbose output (LONGACK) X# -M - treat input file (or STDIN) as mail and compose X# and send ack mail back X# -A - assume "assign" mode, only add will be allowed X# usually set by parsing mail headers X# -H - handle assignment mode. Will only accept persons X# with nic-handle "assign" and return person entry X# with the handle assigned and filled in. X# (very RIPE database dependent) X X&Getopts('l:vMAH'); X X# Need this below for running perl in tainted mode. X X$ENV{"PATH"} = ""; X$ENV{"SHELL"} = "/bin/sh"; X$ENV{"IFS"} = ""; X X# Read config file from RIPEDBCNF, or set to default. X X$conffile=$ENV{"RIPEDBCNF"}; X$conffile= "DEFCONFIG" unless $conffile; X&rconf($conffile); X X# Save STDOUT X Xopen(SAVEOUT, ">&STDOUT"); X X# Open one ack file. Proper handling (stdout, logfile or mail) is handled X# all the way at the end .... But, we open the logfile if needed already X# because we need to exit if we cannot even create that file ... X# If -M option is specified, -l is overruled. X Xif ($opt_l) { X open(LOGFILE, ">$opt_l") || die "Cannot create $opt_l: $!"; X} X Xopen(STDOUT, ">$TMPDIR/dbupdack.$$") || X &syslog("ERRLOG", "cannot create tmp ack file: $!"); X X# Make STDOUT unbuffered X Xselect(STDOUT); $| = 1; X X# X# printstat ( arg ) X# X# int arg /* 0=failed, 1=ok, 2=noop */ X# X# prints verbose version of the update result. X# X Xsub printstat { X X local($stat) = @_; X local($type) = &entype(*entry); X X if (&hasdelete(*entry)) { X print "Delete "; X } else { X print "Update "; X } X if ($stat == 1) { print "OK: ";} X elsif ($stat == 2) { print "NOOP: ";} X else { print "FAILED: "; } X X print "[$ATTL{$type}] $entry{$type}\n\n"; X} X X X# X# doaction ( ) X# X# does all the work. X# X Xsub doaction { X X local($file) = @_; X local($donestat) = 0; X X while(1) { X X $donestat = 0; X X ($parsestat, %entry) = &enparse($file); X X # next if nothing was read X X next if $parsestat == $NOK; X X # return if only thing read was EOF X X return if $parsestat == $EOF; X X $somethingfound = 1; X X # object parsing generated an error, output object with X # errors and return. If we are deleting an object, then X # forget about it, we do not want to return with syntax X # errors X X local($type) = &entype(*entry); X X # now if we are running in -H mode, just next when we have X # not found a person. X X if ($opt_H) { X if ($type ne "pn") { X print "No person object found\n"; X next; X } else { X if ($entry{"nh"} !~ /^[aA][sS][sS][iI][gG][nN]$/) { X &adderror(*entry, "nichandle \"assign\" expected"); X print "\n" if &enwrite(*entry,1,1); X next; X } X } X } X X if (($parsestat == $O_ERROR) && (!&hasdelete(*entry))) { X if ($opt_v) { &printstat(0); } X# &adderror(*entry, "$MESSAGE[$parsestat]"); X $haserror = 1; X print "\n" if &enwrite(*entry,1,1); X next; X } X X X # If we have to delete, remove all parse errors and warnings X # and set status to OK: we do not want deletes to be checked X X if (&hasdelete(*entry)) { X &rmwarnings(*entry); X &rmerrors(*entry); X $parsestat= $O_OK; X } X X # object parsed OK or has only warnings X X if ($parsestat == $O_OK || $parsestat == $O_WARNING) { X X # open database file associated with "so" for writing X X local(*db) = 'currentdb'; X if (&dbopen(db, $DBFILE{$entry{"so"}}, 1)) { X X # do we delete or not ? X X if (&hasdelete(*entry)) { X X $dbstat = &dbdel(*db, *entry); X X # We do handle generation, so after a delete, we X # have to delete the handle from that database X # as well. X X if ($DOHANDLE && $HANDLEATTR{$type}) { X if ($dbstat == $OK) { X &DeleteHandle(*entry); X } X } X X } else { X X # We do handle generation, check whether we have X # to assign a nic handle (if nh value is "assign") X # Can be a request handle of form: assign handle X # Line has already been syntax checked, so no worries X # there. Errors are added by AssignHandle, so all we X # need is an extra check. X X if ($DOHANDLE && $HANDLEATTR{$type}) { X if ($entry{$HANDLEATTR{$type}} =~ /^[Aa][Ss][Ss][Ii][Gg][Nn]\s*(.*)$/) { X local($handle) = &AssignHandle(*entry, $1); X } else { X # new object, we may have to put the handle X # in the database. AddHandle will return if X # if the handle is already in handle database X X &AddHandle(*entry); X } X } X X if (!&haserror(*entry)) { X X # NEW assignments && !person X X if ($opt_A && ($type ne "pn")) { X $dbstat = &dbadd(*db, *entry); X } else { X $dbstat = &dbadd_or_modify(*db, *entry); X } X } else { X # Fake dbstat, has error due to handle X # generation ... X X $dbstat = $OK; X } X } X X # Totally yucky, but I do not know how to X # do this better right now. The thing is that X # every exit code but E_NOOP and OK are X # errors, so catch NOOP first, and print X # verbose warning if needed, then OK, and X # then handle all the others as errors. X X # noop, just print stat if verbose X X if ($dbstat == $E_NOOP && $opt_v) { X &printstat(2); X $donestat = 1; X } X elsif (($dbstat != $OK) && ($dbstat != $E_NOOP)){ X &adderror(*entry, "$MESSAGE[$dbstat]"); X } X X X # Object has errors, so print, and next X X if (&haserror(*entry)) { X $haserror = 1; X if ($opt_v) { &printstat(0); } X print "\n" if &enwrite(*entry,1,1); X next; X } X X # object has only warnings, so it must have X # been processed. print and next. X X elsif (&haswarning(*entry)) { X $haserror = 1; X if (!$donestat && $opt_v) { X &printstat(1); X } X print "\n" if &enwrite(*entry,1,1); X next; X } X X # all was OK, so only print stat if verbose X X if ($opt_v && !$donestat) { &printstat(1); } X X # all was OK, print object if nichandle assign mode X X if ($opt_H) { X &enwrite(*entry,1,1); X } X } X X else { X X # Not too good, probably permission problem X # if this is given as output ... X X print "Failed to open DB file: $!\n"; X } X } X } X close(TMP); X} X X# X# Main program X# X X# We want to make a local copy of the input, because we need to do mutliple X# things with it ... X Xopen(COPY, ">$TMPDIR/dbupdcopy.$$") || die "Cannot open copy file: $!"; Xselect(COPY); $| = 1; select(STDOUT); X Xwhile (<>) { X print COPY; X} X Xclose(COPY); X X# Now we open the copy to actually process X Xopen(COPY, "$TMPDIR/dbupdcopy.$$") || die "Cannot open copy: $!"; X X# We have a mail, so let's first parse the headers ... X Xif ($opt_M) { X X local($stat) = &parserfc822(COPY); X X # If we have at least a return address, compose the header of X # the ack mail X X if ($stat) { X X if ($TESTMODE) { X print "To: $DEFMAIL\n"; X } else { X print "To: $FROM\n"; X } X eval "print \"$MHEADER\";"; X eval "print \"$MAILTXT\";"; X X # If not we are in trouble once more ... X X } else { X print "Header could not be parsed ...\n"; X } X} X X# Take all the stuff from file COPY in doaction. It will process the X# whole stuff. X X&doaction(COPY); X Xif (!$somethingfound) { X print "** No objects were found in your message **\n"; X} Xelsif ($haserror) { X print "$ACKERR" unless $opt_H; X} else { X print "$ACKOK" unless $opt_H; X} X Xprint $ACKSIG unless $opt_H; X Xclose(COPY); Xclose(STDOUT); Xopen(STDOUT, ">&SAVEOUT"); X X# Output the ack, if -M specified then no logfile or stdout will be given. X Xif ($opt_M) { X system("$MAILCMD < $TMPDIR/dbupdack.$$"); X} else { X open(TMP, "$TMPDIR/dbupdack.$$"); X while (<TMP>) { X if ($opt_l) { X print LOGFILE; X } else { X print; X } X } X close(TMP); X} X X# We sent out the ack, now send out the notifications if needed X Xif (%notify) { X &SendNotifications(); X} X X# log all stuff to the right places X X# todays YYMMDD X Xlocal($s,$m,$h,$md,$mo,$y,$wd,$yd,$is) = localtime(time); X X$mo+=1; X X$mo = "0".$mo unless $mo > 9; X$md = "0".$md unless $md > 9; X$y = "0".$y unless $y > 9; X X$YYMMDD = "$y$mo$md"; X X# This may seem yucky, but is needed to untaint the filename ... X X$filename = $LOGFILE{"UPDLOG"}."/".$YYMMDD; X$filename =~ /(.*)/; X$realfile = $1; X X# first let's log the updates send in or via stdin X Xif (open(LOG, ">>$realfile")) { X &lock(LOG); X if ($opt_M) { X print LOG "\n>>> MAIL UPDATE <<<\n\n"; X } else { X print LOG "\n>>> STDIN UPDATE <<<\n\n"; X } X X open(TMP, "$TMPDIR/dbupdcopy.$$"); X X while (<TMP>) { X print LOG; X } X close(TMP); X close(LOG); X &unlock(LOG); X} else { X &syslog("ERRLOG", "dbupdate cannot open $LOGFILE{\"UPDLOG\"}/$YYMMDD"); X} X X X# then we log the acknowledgement X X$filename = $LOGFILE{"ACKLOG"}."/".$YYMMDD; X$filename =~ /(.*)/; X$realfile = $1; X Xif (open(LOG, ">>$realfile")) { X &lock(LOG); X if ($opt_M) { X print LOG "\n>>> MAIL ACK <<<\n\n"; X } else { X print LOG "\n>>> STDIN ACK <<<\n\n"; X } X open(TMP, "$TMPDIR/dbupdack.$$"); X while (<TMP>) { X print LOG; X } X close(TMP); X close(LOG); X &unlock(LOG); X} else { X &syslog("ERRLOG", "dbupdate cannot open $LOGFILE{\"ACKLOG\"}/$YYMMDD"); X} X X X# remove the temp stuff we made X Xunlink("$TMPDIR/dbtmp.$$"); Xunlink("$TMPDIR/dbupdcopy.$$"); Xunlink("$TMPDIR/dbupdack.$$"); X X X X X X X END_OF_dbupdate.pl if test 9951 -ne `wc -c <dbupdate.pl`; then echo shar: \"dbupdate.pl\" unpacked with wrong size! fi # end of overwriting check fi if test -f rconf.pl -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"rconf.pl\" else echo shar: Extracting \"rconf.pl\" \(4945 characters\) sed "s/^X//" >rconf.pl <<'END_OF_rconf.pl' X# rconf - read RIPE database configuration file X# X# $RCSfile: rconf.pl,v $ X# $Revision: 0.26 $ X# $Author: marten $ X# $Date: 1994/02/17 10:58:14 $ X# X# This routine reads all parameters from the configuration file X# into scalars or associative arrays of the same name (uppercase). X# Multi line texts are stored as scalar strings with embdded "\n"s. X# Note the special variable names for the OBJ configuration. X# X# Arguments: X# X# $confname name of the configuration file X Xrequire "defaults.pl"; # file containing some default configuration X # definitions. X Xsub rconf { X X local($confname) = @_; X local ($i); X X open(CONF, $confname) || die "rconf: cannot open config \"$confname\", $!"; X X while (<CONF>) { X next if (/^\#/); X next if (/^\s*$/); X last if (/^ENDCONF\w*$/); X X if (/^ALIAS\s+(\S+)\s+(\S+)/) { X $ALIAS{$2} = $1; X } X if (/^ATTA\s+(..)\s+(\S*)/) { $ATTR{$2}=$1; next;} X if (/^ATTR\s+(..)\s+(\S*)/) { X $ATTR{$1}=$1; $ATTR{$2}=$1; $ATTL{$1}=$2; X next; X } X if (/^CONGRAT\s+(.*)/) { $CONGRAT=$CONGRAT.$1."\n"; next;} X if (/^CONNECT\s+(\S+)/) { $CONNECT{$1}=$1; next;} X if (/^COUNTRY\s+(..)\s+(..)/) { X $COUNTRY{$1}=$1; $COUNTRY{$2}=$1; X next; X } X if (/^DOHANDLE\s+(\d+)/) {$DOHANDLE=$1+0; next;} X if (/^HANDLEPOSTFIX\s+(\S+)/) {$HANDLEPOSTFIX=$1; next;} X if (/^MAXHANDLE\s+(\d+)/) {$MAXHANDLE=$1; next;} X if (/^HANDLEATTR\s+(\S+)\s+(\S+)\s+(\S+)/) { X $HANDLEATTR{$1} = $2; X $HANDLEDB{$1} = $3; X next; X } X if (/^TESTMODE\s+(\d+)/) {$TESTMODE=$1; next;} X if (/^DEFMAIL\s+(\S+)/) { $DEFMAIL=$1; next;} X if (/^TMPDIR\s+(\S+)/) { $TMPDIR=$1; next;} X if (/^CURDB\s+(\S+)/) { $CURDB=$1; next;} X if (/^DEFSRC\s+(\S+)/) { $DEFSRC=$1; next;} X if (/^ACKERR\s+(.*)/) { $ACKERR=$ACKERR.$1."\n"; next;} X if (/^ACKOK\s+(.*)/) { $ACKOK=$ACKOK.$1."\n"; next;} X if (/^ACKSIG\s+(.*)/) { $ACKSIG=$ACKSIG.$1."\n"; next;} X if (/^INMAILS\s+(\S+)/) { $INMAILS=$1; next;} X if (/^MAILCMD\s+(.*)/) { $MAILCMD=$1; next;} X if (/^MAILTXT\s+(.*)/) { $MAILTXT=$MAILTXT.$1."\n"; next;} X if (/^MHEADER\s+(.*)/) { $MHEADER=$MHEADER.$1."\n"; next;} X if (/^NAMNORM\s+(.)\s+(.)/) { $NAMNORM{$1}=$2; next;} X if (/^NEWDB\s+(\S+)/) { $NEWDB=$1; next;} X X if (/^NHEADER\s+(.*)/) { $NHEADER.=$1."\n";next;} X if (/^NOTITXT\s+(.*)/) { $NOTITXT.=$1."\n";next;} X if (/^GRDCONFLICT\s+(.*)/) { $GRDCONFLICT.=$1."\n";next;} X if (/^SPLITMSG\s+(.*)/) { $SPLITMSG.=$1."\n";next;} X X if (/^OBJ\s+(\S\S)\s+ATSQ\s+/) { X $i = $1; X while ($' =~ /(\S\S)\s*/) { X $OBJATSQ{$i} = $OBJATSQ{$i}.$1." "; X } X next; X } X if (/^OBJ\s+(\S\S)\s+MAND\s+/) { X $i = $1; X while ($' =~ /(\S\S)\s*/) { X $OBJ{$i, $1} = "M"; X $OBJMAND{$i} = $OBJMAND{$i}.$1." "; X } X next; X } X if (/^OBJ\s+(\S\S)\s+MULT\s+/) { X $i = $1; X while ($' =~ /(\S\S)\s*/) { X $OBJMULT{$i} = $OBJMULT{$i}.$1." "; X } X next; X } X if (/^OBJ\s+(\S\S)\s+OPT\s+/) { X $i = $1; X while ($' =~ /(\S\S)\s*/) { X $OBJ{$i, $1} = "O"; X } X next; X } X if (/^OBJ\s+(\S\S)\s+KEYS\s+/) { X $i = $1; X while ($' =~ /(\S\S)\s*/) { X $KEYS{$i} .= $1." "; X } X next; X } X if (/^OBJ\s+(\S\S)\s+GRD\s+/) { X $i = $1; X while ($' =~ /(\S\S)\s*/) { X $GRD{$i} .= $1." "; X } X next; X } X if (/^OBJ\s+(\S\S)\s+REC\s+/) { X $i = $1; X while ($' =~ /(\S\S)\s*/) { X $RECUR{$i} .= $1." "; X } X next; X } X if (/^OBJ\s+(\S\S)\s+UNIQ\s+/) { X $i = $1; X while ($' =~ /(\S\S)\s*/) { X $UNIQ{$i} .= $1." "; X } X next; X } X X if (/^CANUPD\s+(.+)/) { X $_ = $1; X while (s/(\S+)\s*//) { X $CANUPD{$1} = 1; X } X next; X } X X if (/^DEFLOOK\s+(\S+)/) { $DEFLOOK=$1; next; } X if (/^ALLLOOK\s+(.*)/) { $ALLLOOK=$1; next; } X X if (/^DBFILE\s+(\S+)\s+(\S+)/) { $DBFILE{$1} = $2; next; } X if (/^AUTHFILE\s+(\S+)/) { $AUTHFILE = $1; next; } X if (/^PIDFILE\s+(\S+)/) { $PIDFILE = $1; next; } X if (/^GUARD\s+(\S+)\s+(\S+)\s+(\S+)/) { X $GUARD{$1} = $2; X $GUARDTYPE{$1} = $3; X next; X } X X if (/^OBJ\s+(\S\S)\s+SORT\s+(\S+)/) { $OBJSORT{$1} = $2; next;} X if (/^RIGHTS\s+(.*)/) { $RIGHTS=$RIGHTS.$1."\n"; next; } X if (/^NOMATCH\s+(.*)/) { $NOMATCH=$NOMATCH.$1."\n"; next; } X if (/^TOOMANY\s+(.*)/) { $TOOMANY=$TOOMANY.$1."\n"; next; } X if (/^SOURCE\s+(\S+)/) { $SOURCE{$1}=$1; next; } X if (/^STATS\s+(\S+)/) { $STATS=$1; next; } X if (/^HELP\s+(\S+)/) { $HELP=$1; next; } X if (/^QRYLOG\s+(\S+)/) { $LOGFILE{"QRYLOG"}=$1; next; } X if (/^ERRLOG\s+(\S+)/) { $LOGFILE{"ERRLOG"}=$1; next; } X if (/^AUTHLOG\s+(\S+)/) { $LOGFILE{"AUTHLOG"}=$1; next; } X if (/^UPDLOG\s+(\S+)/) { $LOGFILE{"UPDLOG"}=$1; next; } X if (/^ACKLOG\s+(\S+)/) { $LOGFILE{"ACKLOG"}=$1; next; } X if (/^CLEANLOCK\s+(\S+)/) {$CLEANLOCK = $1; next; } X } X foreach $i (keys %OBJATSQ) { chop($OBJATSQ{$i}); } X foreach $i (keys %OBJMAND) { chop($OBJMAND{$i}); } X foreach $i (keys %OBJMULT) { chop($OBJMULT{$i}); } X X return 1; X} X X1; # PC version of perl seems to require this for X # require () X END_OF_rconf.pl echo shar: 1 control character may be missing from \"rconf.pl\" if test 4945 -ne `wc -c <rconf.pl`; then echo shar: \"rconf.pl\" unpacked with wrong size! fi # end of overwriting check fi if test -f cleandb.pl -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"cleandb.pl\" else echo shar: Extracting \"cleandb.pl\" \(14983 characters\) sed "s/^X//" >cleandb.pl <<'END_OF_cleandb.pl' X#!PERL X# cleandb.pl - clean up the database, ie remove all the entries X# that have been deleted on the fly (*XX:) and X# rebuild the index. X# X# $RCSfile: cleandb.pl,v $ X# $Revision: 0.39 $ X# $Author: marten $ X# $Date: 1994/02/17 10:58:04 $ X X# $opt_v = 1; X X at INC = ("LIBDIR", @INC); X Xrequire "rconf.pl"; Xrequire "dblock.pl"; Xrequire "dbopen.pl"; Xrequire "dbclose.pl"; Xrequire "donetdbm.pl"; Xrequire "enread.pl"; Xrequire "enwrite.pl"; Xrequire "encmp.pl"; Xrequire "syslog.pl"; X X$CLASSA = &quad2int("128.0.0.0"); X$CLASSB = &quad2int("192.0.0.0"); X X# cleandbadd X# X# special version of dbadd. Basically the same, but some checks are X# taken out for the sake of speed. One can assume that there are no X# two entries with the same key, and the seek has been removed, since X# this file can only be used by one process at the same time, so it X# keep the current file position properly. X Xsub cleandbadd { X local(*db, *en) = @_; X X local($unikey) = &enukey(*en); X X select(db); X print "\n"; X local($offset) = tell(db); X &enwrite(*en); X &addkey(*db, $unikey, $offset); X X foreach $i (&enkeys(*en)) { X &addkey(*db, $i, $offset); X } X X return $OK; X} X X X# parsech X# X# Parse the changed field, and return the e-mail from associated with the X# last changed date. Used to notify the last changer of a block that his X# block has been split because of guarded field additions. X Xsub parsech { X X local($line) = @_; X local($em, $chdate) = ""; X local($rtem, $rtch) = ""; X X foreach $i (split(/\n/, $line)) { X ($em, $chdate) = split(/\s+/, $i); X if ($chdate gt $rtch) { X $rtch = $chdate; X $rtem = $em; X } X } X X $rtem = "$DEFMAIL" if $rtem eq ""; X $rtem = "$DEFMAIL" if $TESTMODE; X return $rtem; X} X X# AddConflict X# X# Builds a structure with all conflicts that can be walked and turned into X# mails later in MailConflicts. X Xsub AddConflict { X X local($attr, $key, $curvalue, $newvalue) = @_; X X if ($conflict{$key}) { X if ($curvalue ne "CONFLICT") { X if (!($conflict{$key} =~ s/(@$attr%)/$1$curvalue,/)) { X $conflict{$key} .= "@$attr%$curvalue"; X } X } X if (!($conflict{$key} =~ s/(@$attr%)/$1$newvalue,/)) { X $conflict{$key} .= "@$attr%$newvalue"; X } X } else { X $conflict{$key} = "@$attr%$curvalue,$newvalue"; X } X if ($opt_v) { X print STDERR "cleandb - \$conflict{$key} = $conflict{$key}\n"; X } X} X X# MailConflicts X# X# mail the conflicts out as built in AddConflict X# Mind you, this routine makes the assumption that the filename, which is X# the guarded value is also the e-mail address to mail the conflicts to !!! X# you'd better make sure these mailboxes exist. A nicer solution will be X# found later ... X Xsub MailConflicts { X X local($i, $j, $k, $n); X local($attr, $vals); X local(%guardianfile) = (); X local($nonexist) = 0; X X if ($opt_v) { X print STDERR "cleandb - mailing conflicts\n"; X } X X foreach $i (sort keys %conflict) { X foreach $j (split(/\@/, $conflict{$i})) { X next if $j eq ""; X ($attr, $vals) = split(/%/, $j); X foreach $k (split(/,/, $vals)) { X next if $k eq "NONEXIST"; X if (!$guardianfile{$k}) { X $guardianfile{$k} = &ConflictTmpFile($k); X &ConflictMailHeaders($guardianfile{$k}, $k); X } X local($newval) = $vals; X $nonexist = 0; X if ($newval =~ /NONEXIST/) { X $newval =~ s/^NONEXIST,|,NONEXIST$|^NONEXIST$//; X $newval =~ s/,NONEXIST,/,/; X $nonexist = 1; X } X $newval =~ s/^$k,|,$k$//; X $newval =~ s/,$k,/,/; X $newval =~ s/(.*),([^,]+)$/$1 and $2/; X $newval =~ s/,/, /g; X open(TMP, ">>$guardianfile{$k}"); X X print TMP "\"$i\" also appears in guardian files: $newval\n" if $newval && ($newval ne $k); X if ($nonexist) { X print TMP "\"$i\" not found in database !!\n"; X } X close(TMP); X } X } X } X foreach $i (keys %guardianfile) { X if ($opt_v) { X print STDERR "cleandb - send mail to $i\n"; X } X system("$MAILCMD < $guardianfile{$i}"); X# system("cat $guardianfile{$i}"); X unlink($guardianfile{$i}); X } X} X Xsub ConflictTmpFile { X X local($seed) = @_; X return "/tmp/dbconfl.$seed.$$"; X} X Xsub ConflictMailHeaders { X X local($filename, $guardedvalue) = @_; X $guardedvalue =~ tr/A-Z/a-z/; X X open(TMP, ">$filename") || X &syslog("ERRLOG", "cleandb cannot create conflict file $filename"); X select(TMP); X if ($TESTMODE) { X print TMP "To: \"$guardedvalue Guardian\" <$DEFMAIL>\n"; X } else { X print TMP "To: \"$guardedvalue Guardian\" <$guardedvalue>\n"; X } X eval "print \"$GRDCONFLICT\n\";"; X close(TMP); X select(STDOUT); X return; X} X X X# readguard X# X# read all the guarded values for a certain object type X# the values are stored in an associative array "guarded" with the X# index being the composition of "guarded attribute (short form)", "%" X# and the key mentioned in the guarded file. The value will be X# the file name, which is the guarded value. X# X# So, $guarded{"as%192.87.45.0"}="AS1104" would mean that the guarded X# attribute "as" for object with key "192.87.45.0" should be "AS1104"; X# X# There are two types of guarded attributes, SINGLE and MULTIPLE. SINGLE X# guarded attributes can only have one single value, and if a certain key X# appears in more than one guardian file, a special CONFLICT value is X# created, and the current value in the database is kept. CONFLICTS will X# then be mailed to the guardians of these values to resolve. X# MULTIPLE guarded attributes are not checked on conflicts, multiple values X# are allowed, and all these values are concatenated. X X Xsub readguard { X X local($type) = @_; X local($i); X local(%done) = (); X X foreach $i (split(/\s+/, $GRD{$type})) { X $curfield = $i; X opendir(A, "$GUARD{$i}") || X &syslog("ERRLOG", "cleandb cannot opendir $GUARD{$i}"); X local(@allfiles) = sort grep(!/^\./,readdir(A)); X closedir(A); X foreach $curfile (@allfiles) { X open (TMP2, "$GUARD{$i}/$curfile") || X &syslog("ERRLOG","cleandb cannot open $GUARD{$i}/$curfile"); X while (<TMP2>) { X chop; X X next if /^;/; X next if /^#/; X X s/^inetnum:\s*//; X X next if /^\s*$/; X X s/\s*$//; X X # This is hardwired a bit again, ranges of IP network numbers X # in guardian files ... X local($IPNUM) = "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+"; X X if (/^($IPNUM)\s+\-\s+($IPNUM)/) { X local($bot) = &quad2int($1); X local($top) = &quad2int($2); X if ($bot > $CLASSB) { X $inc = 256; X } elsif ($bot > $CLASSA) { X $inc = 256 ** 2; X } else { X $inc = 256 ** 3; X } X local($loop); X for ($loop=$bot; $loop<=$top; $loop+=$inc) { X local($value) = &int2quad($loop); X next if $done{$value}; X if ($GUARDTYPE{$curfield} eq "MULTIPLE") { X if ($guarded{"$curfield%$value"}) { X $guarded{"$curfield%$value"} .= " ".$curfile; X } else { X $guarded{"$curfield%$value"} = $curfile; X } X } else { X if ($guarded{"$curfield%$value"}) { X &AddConflict($curfield, X $value, X $guarded{"$curfield%$value"}, X $curfile); X $guarded{"$curfield%$value"} = "CONFLICT"; X } else { X $guarded{"$curfield%$value"} = $curfile; X } X } X $done{$value} = 1; X } X X } else { X X next if $done{$_}; X X if ($GUARDTYPE{$curfield} eq "MULTIPLE") { X if ($guarded{"$curfield%$_"}) { X $guarded{"$curfield%$_"} .= " ".$curfile; X } else { X $guarded{"$curfield%$_"} = $curfile; X } X } X else { X if ($guarded{"$curfield%$_"}) { X &AddConflict($curfield, X $_, X $guarded{"$curfield%$_"}, X $curfile); X $guarded{"$curfield%$_"} = "CONFLICT"; X } else { X $guarded{"$curfield%$_"} = $curfile; X } X } X $done{$_} = 1; X } X } X %done = (); X } X } X $guarddone{$type} = 1; X} X X# dosplit X# X# Kind of yucky routine needed for block splits. This is called when X# a block split is needed. It will make a block from $from to $to, and X# will reset all guarded attributes according to the guardian files. X Xsub dosplit { X X local(*en, $from, $to) = @_; X X local($begin) = &int2quad($from); X local($end) = &int2quad($to); X X if ($from eq $to) { X $en{"in"} = "$begin"; X } X else { X $en{"in"} = "$begin - $end"; X } X X foreach $j (split(/\s+/, $GRD{$type})) { X $en{"$j"} = $guarded{"$j%$begin"}; X if ($from >= $CLASSB) {$inc = 256;} X elsif ($from >= $CLASSA) {$inc = 256**2;} X else {$inc = 256**3;} X for ($p=$from;$p<=$to;$p+=$inc) { X local($num) = &int2quad($p); X delete $guarded{"$j%$num"}; X } X } X X &cleandbadd(*newdb, *en); X X if ($domail && $firstmail) { X $firstmail = 0; X $BEGINADDRESS = $beginaddr; X $ENDADDRESS = $endaddr; X open(MAIL, ">/tmp/domail.$$"); X $to = &parsech($en{"ch"}); X print MAIL "To: $to\n"; X select(MAIL); X eval "print \"$SPLITMSG\n\";"; X select(STDOUT); X } X if ($domail) { X select(MAIL); X print "\n" if &enwrite(*en, 1); X select(STDOUT); X } X} X X X X# This is the routine where guarded fields are checked and deleted or added X# if necessary. All changes are logged. X# Now, there is a special case for IP network numbers, hardcoded I am X# afraid to deal with splitting of blocks .... X Xsub checkguardandprint { X X local(*en) = @_; X X local($type) = &entype(*en); X X if (!$type) { X return 0; X } X X &readguard($type) unless ($guarddone{$type} || !$GRD{$type}); X X X# No guarded fields, just print and leave X X if (!$GRD{$type}) { X &cleandbadd(*newdb, *en); X return 1; X } X X# this is the hardcoded part ... X X X if ($type eq "in") { X X X# We have a range, if all guarded values are NOT the same for all nets X# in this block, then do an aggresive split, ie split into ALL different X# nets ... (I don't know a better way for now). X# Implementation is kind of disgusting, but it works. The block split X# certainly makes things slower than it is supposed to be .... X X if ($en{"in"} =~ /(\S+) - (\S+)/) { X X $firstmail = 1; X $domail = 0; X local($inc) = 0; X $beginaddr = $1; X $endaddr = $2; X $lo = &quad2int($1); X $hi = &quad2int($2); X if ($lo > $CLASSB) { X $inc=256; X } X elsif ($lo > $CLASSA) { X $inc=256**2; X } X else { X $inc = 256**3; X } X X $start = $lo; X $end = $lo; X X %grd = (); X for ($i=$lo;$i<=$hi;$i+=$inc) { X foreach $j (split(/\s+/, $GRD{$type})) { X $net = &int2quad($i); X if ($guarded{"$j%$net"} eq "CONFLICT") { X $grd{"$i"} .= " $j".$en{"$j"}; X $guarded{"$j%$net"} = $en{"$j"}; X } else { X $grd{"$i"} .= " $j".$guarded{"$j%$net"}; X } X } X next if $start eq $i; X if ($grd{$i} eq $grd{$start}) { X $end = $i; X if ($end == $hi) { X $domail = 1 if $start != $lo; X &dosplit(*en, $start, $end); X $hasbeendone{$end} = 1; X } X } else { X if (($start != $lo) || ($end != $hi)) { X $domail = 1; X } X &dosplit(*en, $start, $end); X $hasbeendone{$end} = 1; X $start = $i; X $end = $i; X } X } X if (!$hasbeendone{$hi}) { X if (($start != $lo) || ($end != $hi)) { X $domail = 1; X } X &dosplit(*en, $start, $hi); X } X X if ($domail) { X close(MAIL); X system("/usr/lib/sendmail -t < /tmp/domail.$$"); X unlink("/tmp/domail.$$"); X } X return 0; X } X } X X# We have no block, just an ordinary single entry X X $key = $en{$type}; X $key =~ s/\n*$//; X foreach $j (split(/\s+/, $GRD{$type})) { X # Conflict handling, set value to guarded X # value is there is no conflict. X # conflicts are reported in readguard() X if ($guarded{"$j%$key"} ne "CONFLICT") { X $en{"$j"} = $guarded{"$j%$key"}; X } X delete $guarded{"$j%$key"}; X } X &cleandbadd(*newdb, *en); X return 1; X} X X# Main program X Xif (!$ARGV[0]) { X print STDERR "Usage: $0 database\n"; X exit; X} X X# Read config file from RIPEDBCNF, or set to default. X Xif ($opt_v) { X print STDERR "cleandb - reading config\n"; X} X$conffile=$ENV{"RIPEDBCNF"}; X$conffile= "DEFCONFIG" unless $conffile; X&rconf($conffile); X X# Now we open the database file defined in $ARGV[0] X# Maybe later it is nice to open based on the SOURCE in stead of hard X# file names X Xif ($opt_v) { X print STDERR "cleandb - opening previous database\n"; X} X Xlocal(*i) = 'curdb'; X&dbopen(i, $ARGV[0]) || die "Cannot open $ARGV[0]"; X X# We are going to output the cleaned up database to "$ARGV[0].new" for now. X Xif ($opt_v) { X print STDERR "cleandb - opening new database\n"; X} X Xopen(TMP, ">$ARGV[0].new"); Xprint TMP "\n"; Xclose(TMP); Xlocal(*newdb) = 'new'; X&dbopen(newdb, "$ARGV[0].new", 1) || die "Cannot open $ARGV[0].new"; X X# Create the lock file, so that dbupdates are put on hold X# Put the process ID in the lockfile. This lockfile is created to X# avoid "rename" and "open" race conditions between cleandb and dbupdate X# or basically anything that wishes to write to the database file. X# dbopen in write mode checks to see if this file is there, and then X# holds the open. X Xif ($opt_v) { X print STDERR "cleandb - checking for lockfile\n"; X} X X$ARGV[0] =~ /([^\/]+)$/; X$fileext = $1; X Xif (-e "$CLEANLOCK.$fileext") { X &syslog("ERRLOG", "$CLEANLOCK.$fileext already exists"); X die "lockfile $CLEANLOCK.$fileext already exists"; X} X Xif ($opt_v) { X print STDERR "- Creating lock file $CLEANLOCK.$fileext\n"; X} Xopen(LOCKFILE, ">$CLEANLOCK.$fileext") || X die "cannot create $CLEANLOCK.$fileext"; Xprint LOCKFILE "$$\n"; Xclose(LOCKFILE); X X# Print generation date to database X Xlocal($s,$m,$h,$md,$mo,$y,$wd,$yd,$is) = localtime(time); X X$mo+=1; X X$mo = "0".$mo unless $mo > 9; X$md = "0".$md unless $md > 9; X$s = "0".$s unless $s > 9; X$m = "0".$m unless $m > 9; X$h = "0".$h unless $h > 9; X Xif ($opt_v) { X print STDERR "cleandb - printing date\n"; X} X Xprint newdb "#\n# $y$mo$md $h:$m:$s\n#\n"; X X# Print the copyright notice to the new file X Xif ($opt_v) { X print STDERR "cleandb - printing rights\n"; X} X Xlocal(@rights) = split(/\n/, $RIGHTS); Xforeach $m (@rights) { X print newdb "# ".$m."\n"; X} X X# Now we can simply read the database using enread() since it will skip X# objects that are not defined (like *XX:) so that is the basic cleanup X# operation. X X# Make sure the enwrite() output goes to the new file X Xselect(newdb); X X# Now, since we are going to clean up the database, we would not want X# some daemons to alter the database when we are working on it, so X# we lock it. X Xif ($opt_v) { X print STDERR "cleandb - locking files\n"; X} X X&dblock(*i); X&dblock(*newdb); X Xif ($opt_v) { X print STDERR "cleandb - main loop\n"; X} X Xwhile (%en = &enread(i)) { X X &checkguardandprint(*en); X} X X# Then we move the newly generated database to the original X# NOTE - this is DBM implementation specific .... X X&dbunlock(*newdb); X&dbclose(*newdb); X Xrename("$ARGV[0].new", $ARGV[0]); Xrename("$ARGV[0].new.dir", "$ARGV[0].dir"); Xrename("$ARGV[0].new.pag", "$ARGV[0].pag"); X X# That's it, we can safely unlock now and close both databases X X&dbunlock(*i); X&dbclose(*i); X X# now we can remove the lock file X Xunlink("$CLEANLOCK.$fileext"); X Xforeach $i (keys %guarded) { X local($attr, $key) = split(/%/, $i); X &AddConflict($attr, $key, "NONEXIST", $guarded{$i}); X} X X&MailConflicts; END_OF_cleandb.pl if test 14983 -ne `wc -c <cleandb.pl`; then echo shar: \"cleandb.pl\" unpacked with wrong size! fi # end of overwriting check fi if test -f notify.pl -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"notify.pl\" else echo shar: Extracting \"notify.pl\" \(2012 characters\) sed "s/^X//" >notify.pl <<'END_OF_notify.pl' X# $RCSfile: notify.pl,v $ X# $Revision: 1.5 $ X# $Author: marten $ X# $Date: 1994/02/17 09:36:56 $ X X# notify.pl - implements the notify function. X Xrequire "encmp.pl"; Xrequire "enwrite.pl"; Xrequire "entype.pl"; X X# It consists of two parts. One is the part that writes out the objects X# to temp files, one temp file per notifier, and this is called from X# updatecheck, the second part should be called at the end of an update X# from dbupdate, and will actually mail out the notify messages. X Xsub AddNotify { X X local(*new, *old) = @_; X local($i, $j); X X local($delete) = 1 if (!&entype(*new)); X local($type) = &entype(*old); X X if ($old{"ny"} && !&encmp(*new, *old)) { X local(@notifiers) = split(/\n/, $old{"ny"}); X X # If there is a delete, add all guardians as notifiers. X X if ($delete) { X foreach $i (split(/\s+/, $GRD{$type})) { X foreach $j (split(/\s+/, $old{$i})) { X @notifiers = (@notifiers, $j); X } X } X } X X foreach $i (@notifiers) { X if (!$notify{$i}) { X $notify{$i} = &NotifyTmpFile($i); X open(NOTIFY, ">$notify{$i}") || X &syslog("ERRLOG", "Cannot create notify file $notify{$i}"); X &WriteNotifyHeader(NOTIFY, $i); X } else { X open(NOTIFY, ">>$notify{$i}") || X &syslog("ERRLOG", "Cannot open notify file $notify{$i}"); X } X select(NOTIFY); X if ($delete) { # Deletion, gets dummy *new X print "** object below DELETED **\n\n"; X print "\n" if &enwrite(*old,1); X } else { X print "\n" if &enwrite(*new,1); X } X close(NOTIFY); X } X select(STDOUT); X } X} X X Xsub NotifyTmpFile { X X local($notifier) = @_; X X return "$TMPDIR/$notifier.$$"; X} X Xsub WriteNotifyHeader { X X local($filehandle, $notifier) = @_; X X select($filehandle); X X print $NHEADER; X $notifier = $DEFMAIL if $TESTMODE; X print "To: $notifier\n"; X print "\n"; X X eval "print \"$NOTITXT\n\";"; X X select(STDOUT); X} X X Xsub SendNotifications { X X local($i); X X foreach $i (keys %notify) { X system("$MAILCMD < $notify{$i}"); X unlink($notify{$i}); X } X} END_OF_notify.pl if test 2012 -ne `wc -c <notify.pl`; then echo shar: \"notify.pl\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of shell archive. exit 0 -------- Logged at Thu Feb 17 13:34:08 MET 1994 ---------
[ rr-impl Archive ]