Saturday, February 11, 2012

Enable timestamp logging in bash commands history

Bash has the built-in feature to support timestamp in history command , but it is not enabled by default in Red Hat Linux(ksh doesn’t have the feature at all)
It is recommended to tune two environment variables for history command to tighten audit.
1.Enable timestamp in command history
2.Increase the default  history file size
Enable timestamp in command history
Just need to set HISTTIMEFORMAT env variable, e.g.  HISTTIMEFORMAT="[%F %T %Z] "
The time format is the same as that of date command.
Increase the default history file size
There are two environment variables  for history size.
HISTSIZE: How many lines to keep in memory for current bash session, commands in current session are appended to ~/.bash_history on quitting.
HISTFILESIZE: How many lines to keep in history file ~/.bash_history
Both HISTSIZE and HISTFILESIZE seem to be 1000 by default, HISTSIZE=1000 is ok for current session, but HISTFILESIZE=1000 is too small to log enough commands for any past login session.
Both environment variables  are to be enabled for all users,  they can be put in global profile /etc/profile , but user defined global profile in /etc/profile.d/ is a better option.
For example, create a user global profile in /etc/profile.d
$cat /etc/profile.d/user.sh 
HISTSIZE=1000
HISTFILESIZE=40000
HISTTIMEFORMAT="[%F %T %Z] "
export HISTSIZE HISTFILESIZE HISTTIMEFORMAT
#With timestamp enabled, the history command output looks like this
$history 
19  [2012-02-03 13:41:56 EST] history
20  [2012-02-03 13:42:58 EST] date
22  [2012-02-03 13:42:55 EST] pwd

You may notice that the commands was not sorted by the time order, it is because, even “pwd” was executed  before date, but  it is was in different session and the “pwd session” was terminated after the “date session”, so the “pwd” command was appended after “date”.

To view all 40000 lines in ~/.bash_history for tracing very old commands, you need to temporarily increase HISTSIZE to 40000 before run “history”.  You can set the default HISTSIZE is 4000, but it takes too long to process for history command used in daily basis.

Other useful history related commands

#clear commands history in current session 
$history -c
#disable logging history commands
$set +o history 
#enable logging history commands
$set –o history 
#fc (fix command) 
#open last 4 commands in an editor and re-execute them after closing the editor
#it is useful if you need to re-execute more than one command
$fc -4 -1

Wednesday, February 1, 2012

nsupdate,the command line tool to manage BIND DNS records

nsupdate can submit Dynamic DNS Update requests as defined in RFC2136 to a name server, it is provided by “bind-utils” package.
Authentication for DNS updates
Transaction signatures (TSIG) can be used to authenticate the Dynamic DNS updates, The only supported encryption algorithm for TSIG is HMAC-MD5.
The TSIG public key is stored in a KEY record in a zone served by the name server, the TSIG private key is used by nsupdate to get authenticated.
$mkdir  /var/named/keys; cd /var/named/keys
$dnssec-keygen -a HMAC-MD5 -b 256 -n USER  server1-ddns-key
Kserver1-ddns-key.+157+00575.key 
Kserver1-ddns-key.+157+00575.private 
#Since HMAC-MD5 is symmetric encryption algorithm, the “key string” in private key and public key are equivalent, the public key can be deleted.
$ rm Kserver1-ddns-key.+157+00575.key 
$ cat Kserver1-ddns-key.+157+00575.private 
Private-key-format: v1.2
Algorithm: 157 (HMAC_MD5)
Key: x3NLKprWMvSMaPx75At6zA+DiWb2SvzpFzPFowc7SBU=

#Create a BIND configuration file to be included in /etc/named.conf (it is optional, the statements can be specified in /etc/named.conf directly)
$cat keys.conf
#the key name is arbitrary , but  must be the same name  specified in dnssec-keygen command line
key server1-ddns-key {
algorithm HMAC-MD5;
secret "x3NLKprWMvSMaPx75At6zA+DiWb2SvzpFzPFowc7SBU=";
};
$cat /etc/named.conf
include "/var/named/keys/keys.conf";
...
#zone example.com allow the key to do update
zone "example.com" IN {
type master;
file "example.zone";
allow-update { key server1-ddns-key ; };
};

The journal file for dynamic Update
All changes made to a zone using dynamic update are stored in the zone's journal file.
The name of the journal file is formed by appending the extension .jnl to the name of the corresponding zone file.
The updated entries are saved in .jnl file, the entries are merged to the zone file on the following conditions
1.Every 15 minutes
2."rndc freeze zone" command is issued
3.Service restart
However, the updated record in memory become effective immediately without waiting to be merged to the zone file.
In order for named process to write the journal file, the zone directory /var/named/ must be writable by named user or group
$chown root:named /var/named; chmod g+rw /var/named
nsupdate sample commands
$nsupdate -k Kserver1-ddns-key.+157+00575.private 
> server localhost
> zone example.com
> update add www1.example.com 86400 A 172.16.1.11
> send
Suspend dynamic DNS update
#sometimes it is necessary to update the zone file manually, follow this order to edit zone file manually
$rndc freeze example.com 
$vi example.com.zone
$rndc thaw example.com 

#if your zone exists in multiple views, you may get this error.
$rndc freeze example.com
rndc: 'freeze' failed: not found
#You have to specify class name (IN) and the view name in full.
$rndc freeze example.com  IN myview-name

A wrapper script to make DNS update even easier
$./dnscmd.sh add example.com www5 172.16.1.11
==> Checking result: www5.example.com. ...
Using domain server:
Name: localhost
Address: 127.0.0.1#53
Aliases: 
www5.example.com has address 172.16.1.11

#script content
$cat dnscmd.sh 
#!/bin/ksh
SERVER='localhost'
TTL='86400'
KEY='/var/named/keys/server1-ddns-key.key'
cmd=$1
zone=$2
node=$3
data=$4
if [[ $# -ne 4  ]]; then
cat <<END 
Usage $0 add|delete zone-name node-name data
For example:
- Add A record: $0  add  example.com web 192.168.100.34
- Add PTR record: $0  add  100.168.192.in-addr.arpa  34 web.example.com.
- Delete record: replace add with delete
*** It only supports A and PTR record, for other records,edit zone file manually: rndc free zone-name; vi zonefile; rndc thaw zone-name
END
exit
fi
if [[ "$node" = {1,3}(\d) ]]; then
class='PTR'
else
class='A'
fi
tmpfile=$(mktemp)
cat >$tmpfile <<END
server $SERVER
update $cmd ${node}.${zone} $TTL $class $data
send
END
nsupdate -k $KEY -v $tmpfile
rm -f $tmpfile
record=${node}.${zone}
[[ ${zone} = *in-addr.arpa ]] && record=$(echo ${node}.${zone}  | awk -F"." '{ print $4"."$3"."$2"."$1} ' )
echo -e "\n ==> Checking result: ${record}. ..."
host $record $SERVER