Saturday, May 16, 2009

Manipulating the bash directory stack

There are occasions when you traverse through so many directories stopping in each directory to work on something. After a few stops you may want to go back to one or all of the direcoties you have traversed. I can't remember a generic example to give you but we all come across this scenario many times. Bash provides a facility for addressing such issues and that is called the "bash directory stack"

In simplest terms directory stack is a list of recently visited directories, like your browser's favorite list. It acts like a conventional stack where you can push and pop items, but you can manipulate it further to reorder and remove items from the middle of the stack. Bash provides three 'directory stack built-in' commands to manipulate this stack, wiz pushd,popd and dirs.

pushd:

With a directory as argument, pushd will save(push) the current directory to the stack and change to the directory given by the argument.

popd:

Without any arguments, popd will remove the top entry from the stack and move to that directory.

dirs:

Displays the stack entries. With optional arguments, it can display selected directories from the stack.


Example:

Am going to add a few directories to the stack first.

safeer@penguinpower:~/bin$ pushd /etc/apache2/
/etc/apache2 ~/bin
safeer@penguinpower:/etc/apache2$ pushd /etc/cvsd
/etc/cvsd /etc/apache2 ~/bin
safeer@penguinpower:/etc/cvsd$ pushd /etc/cups/
/etc/cups /etc/cvsd /etc/apache2 ~/bin
safeer@penguinpower:/etc/cups$ pushd /etc/ldap/
/etc/ldap /etc/cups /etc/cvsd /etc/apache2 ~/bin

In practice pusdhd is done after working in a directory and then moving to another directory. Now let us see the stack contents using dirs command.

safeer@penguinpower:/etc/ldap$ dirs -l -v
0 /etc/ldap
1 /etc/cups
2 /etc/cvsd
3 /etc/apache2
4 /home/safeer/bin

The number associated with each directory shows the index of the corresponding directory in the stack with index zero being the present working directory.

Now let us try moving through the stack with popd.

safeer@penguinpower:/etc/ldap$ popd
/etc/cups /etc/cvsd /etc/apache2 ~/bin
safeer@penguinpower:/etc/cups$ popd
/etc/cvsd /etc/apache2 ~/bin
safeer@enjoyfast-lx:/etc/cvsd$

So I popped two directories out of the stack and now the contents of the stack becomes:

safeer@penguinpower:/etc/cvsd$ dirs -v -l
0 /etc/cvsd
1 /etc/apache2
2 /home/safeer/bin

This will give you a basic idea about stack manipulation. To see the full options for pushd/popd/dirs visit the GNU page for directory stack built-ins
A few more shortcuts and shell variables exists for manipulating the stack.

"$PWD" OR "$DIRSTACK" OR "~+" - Present working directory - Stack index zero
"$OLDPWD" OR "~-" - Previous working directory - Stack index one.
"$HOME" OR "~" - User's home directory

cd : Move to user's home directory. Alternatively use cd ~.
cd - : Move to $OLDPWD - pushd without any arguments will do the same. Or use cd ~-

Examples

safeer@penguinpower:/etc/cvsd$ echo ~{,-,+}
/home/safeer /etc/apache2 /etc/cvsd

which is equivalent to:

safeer@penguinpower:/etc/cvsd$ echo $HOME $OLDPWD $PWD
/home/safeer /etc/apache2 /etc/cvsd

Thursday, May 7, 2009

Cisco kron - the Cisco job scheduler

Cisco provides a job scheduler called "kron" which is similar to the unix crontab service. It allows us to schedule and run certain exec mode commands once or recurringly. The feature was first introduced in IOS version 12.3(1). The prerequisite for using kron is that Cisco clock time must be set - either locally or using an NTP source.

Check your IOS version first:

R1_Balancer#show version | include ^Cisco IOS(.+)Version
Cisco IOS Software, 3700 Software (C3725-ADVENTERPRISEK9-M), Version 12.4(18), RELEASE SOFTWARE (fc1)

The "kron" configuration has two parts, configuring "Scheduler Policy List" and then setting "Scheduler Occurrences". A scheduler policy list is similar to a shell script in unix. Every policy list will have a name and will contain one or more exec cli commands added sequentially. A scheduler occurrence is the setting that tells you when a policy list should be executed. You can associate one or more policy lists to a policy schedule.

Now let us create a kron policy with policy name my_policy_1. The commands that can be added in a policy should not generate any prompt or have the ability to be terminated using keystrokes. The simplest command that I can remember is write, which will save the running config to startup config( you can't use "copy running-config startup-config" since it will ask you to confirm the destination file name )

R1_Balancer(config)#kron policy-list my_policy_1
R1_Balancer(config-kron-policy)#cli write
R1_Balancer(config-kron-policy)#exit

You can view the policy from running configuration.

R1_Balancer#sh run | section include kron
kron policy-list my_policy_1
cli write

Let us create a schedule called schedule_1 now. This is set to run once at next Sunday night 11.45

R1_Balancer(config)#kron occurrence schedule_1 at 23:45 sun oneshot
Clock currently not set it reads 02:58:44 UTC Fri Mar 1 2002

If the clock is not set properly you will get a message as above. So set the time.

R1_Balancer#clock set 22:14:20 may 10 2009
R1_Balancer#show clock
22:17:29.487 UTC Sun May 10 2009

R1_Balancer(config)#kron occurrence schedule_1 at 23:45 sun oneshot
R1_Balancer(config-kron-occurrence)#policy-list my_policy_1
R1_Balancer(config-kron-occurrence)#exit

In the schedule you can optionally specify a user under which the kron should run. Now let us see the full kron configurations.

R1_Balancer#show run | section include kron
kron occurrence schedule_1 at 23:45 Sun oneshot
policy-list my_policy_1
kron policy-list my_policy_1
cli write

To view the schedule you can run this command:

R1_Balancer#show kron schedule
Kron Occurrence Schedule
schedule_1 inactive, will run once in 0 days 01:24:51 at 23:45 on Sun

For detailed information on kron, visit this Cisco link.

Sunday, May 3, 2009

Connect GNS3 to your Linux desktop

This post assumes the reader has basic working knowledge with GNS3 GUI. For those who don't know about GNS3 - the graphical network simulator for Cisco platforms, please visit http://www.gns3.net/.

On windows GNS comes with a script for connecting to local machine, but it don't have a Linux equivalent. Here we will see how to achieve that.

First of all, create a basic network map with a single router. Here I am adding a 3600 series router with two slots, NM-1FE-TX ( one fast ethernet port) and NM-4E (four ethernet ports ). Once added, start the router and go to exec mode to list the router interfaces.

Router(config)#hostname R0
R0(config)#show ip interface brief
Interface IP-Address OK? Method Status Protocol
FastEthernet0/0 unassigned YES unset administratively down down
Ethernet1/0 unassigned YES unset administratively down down
Ethernet1/1 unassigned YES unset administratively down down
Ethernet1/2 unassigned YES unset administratively down down
Ethernet1/3 unassigned YES unset administratively down down

Now we need to connect any one of these interfaces to the local desktop. To do this, from the GUI save the map first. I am going to save my router to /home/safeer/GNS/local-connect.net. Now let us examine the contents of the saved network file.

safeer@penguinepower:~$ cat ~/GNS/local-connect.net
autostart = False
[localhost:7200]
workingdir = /tmp
[[3620]]
image = /home/safeer/.gns3/CiscoImages/c3620-i-mz.121-5.T92.bin
idlepc = 0x6012c108
ghostios = True
chassis = 3620
[[ROUTER R0]]
model = 3620
console = 2000
slot0 = NM-1FE-TX
slot1 = NM-4E
x = -29.0
y = -266.0


Now we need to connect this to the local machine using a virtual network interface. To create a virtual network adapter in linux, you need User Mode Linux. On my Ubuntu box, I can get it with apt-get.

safeer@penguinepower:~$ sudo apt-get install uml-utilities

On a Redhat based machines, you can get it via Yum. For more details visit the UML home page http://user-mode-linux.sourceforge.net/

Now add a virtual interface with name tap0 and assign an ip 172.16.1.1 to it.

safeer@penguinepower:~$ sudo tunctl -t tap0 -u safeer
Set 'tap0' persistent and owned by uid 1000
safeer@penguinepower:~$ sudo ifconfig tap0 172.16.1.1 up
safeer@penguinepower:~$ ifconfig tap0
tap0 Link encap:Ethernet HWaddr 72:e7:97:e6:e4:2c
inet addr:172.168.1.1 Bcast:172.168.255.255 Mask:255.255.0.0
inet6 addr: fe80::70e7:97ff:fee6:e42c/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:19 overruns:0 carrier:0
collisions:0 txqueuelen:500
RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

Now we going to connect this tap0 interface to router R0's fast ethernet 0/0 interface. For this, Close the network map in GUI and open its previously saved network file and add this line to the end of [ROUTER R0] section in the configuration.

f0/0 = nio_tap:tap0

The file will look like:

safeer@penguinepower:~$ cat ~/GNS/local-connect.net
autostart = False
[localhost:7200]
workingdir = /tmp
[[3620]]
image = /home/safeer/.gns3/CiscoImages/c3620-i-mz.121-5.T92.bin
idlepc = 0x6012c108
ghostios = True
chassis = 3620
[[ROUTER R0]]
model = 3620
console = 2000
slot0 = NM-1FE-TX
slot1 = NM-4E
x = -29.0
y = -266.0
f0/0 = nio_tap:tap0

Now save the file and open the network map in GUI. You will see a cloud connected to the f0/0 interface of the router. Now tap0 interface of the host machine is connected to f0/0 of R0 in GNS3. To complete the configuration, start R0 and configure an IP for f0/0 that belong to the same network as tap0.

R0(config)#interface f0/0
R0(config-if)#ip address 172.16.1.2 255.255.0.0
R0(config-if)#no shutdown

Now try pinging the local machine from R0.

R0#ping 172.16.1.1

Type escape sequence to abort.
Sending 5, 100-byte ICMP Echos to 172.16.1.1, timeout is 2 seconds:
.!!!!
Success rate is 80 percent (4/5), round-trip min/avg/max = 4/4/4 ms

That is all, you can access R0 ( and other routers connected to R0) from your local machine now. If you have enabled ip forwarding/routing on your local box, these routers will be accessible in your local network.

Note: Sometimes GNS may have permission issue in accessing tap0 interface, in that case launch GNS3 as sudo.

Saturday, April 11, 2009

FTP macros for automated ftp tasks

FTP macros are nothing but an ordered set of ftp commands grouped with a macro name, similar to a bash function/script. You can use the macro name like another command and execute the commands included with it. You can add a macro while inside an ftp session using the macdef command. Alternatively you can add it into the .netrc file inside your home directory. The usage of .netrc file is explained here.

Let us try creating a macro inside an ftp session. This macro will just change to a directory inside the ftp root and copy a file to local directory.

Each macro starts with a macro name on first line, followed by single ftp command on each line. The macro termination is given by a blank line.

ftp> macdef getmacro
Enter macro line by line, terminating it with a null line
cd /home/safeer/pub/site_backup/
get webdata.tar.gz



Once you create the macro run it from the ftp prompt with $ prepended to the macro name.
ftp> $getmacro
cd /home/safeer/pub/site_backup/
250 Directory successfully changed.
get webdata.tar.gz
local: webdata.tar.gz remote: webdata.tar.gz
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for webdata.tar.gz (0 bytes).
226 File send OK.


A macro defined in an ftp session remains active till the close command is issued. If you want re-usable macros, you need to add them to your netrc file. The above mentioned link has the details on how to set it up. A macro defined by the name "init" (in netrc file) will be run every time you login to the corresponding ftp host.

Macro Arguments


If you want to take arguments inside your macro, use $1,$2,$3 etc... where $1 will be the first argument, $2 will be the second argument and so on. If you want to iterate through each argument of the macro, use the special variable $i. The characters "$" and "\" are special in macros and need to be escaped with "\" if you want them "as it is" in the macros.

Eg:

ftp>macdef 2args
Enter macro line by line, terminating it with a null line
cd /home/safeer/docs
get $1
put $2


Above macro will now download local.txt and upload remote.txt

ftp>$2args local.txt remote.txt
cd /home/safeer/docs
250 Directory successfully changed.
get local.txt
local: local.txt remote: file1.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for local.txt (47 bytes).
226 File send OK.
47 bytes received in 0.00 secs (91.1 kB/s)
put remote.txt
local: remote.txt remote: remote.txt
200 PORT command successful. Consider using PASV.
150 Ok to send data.
226 File receive OK.
47 bytes sent in 0.00 secs (454.4 kB/s)


ftp>macdef getmulti
Enter macro line by line, terminating it with a null line
cd /home/safeer/docs
get $i


Above macro will now change to the directory docs in ftp root and recursively download the files given as arguments to macro

ftp> $getmulti file1.txt file2.txt file3.txt
cd /home/safeer/docs
250 Directory successfully changed.
get file1.txt
local: file1.txt remote: file1.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for file1.txt (47 bytes).
226 File send OK.
47 bytes received in 0.00 secs (82.3 kB/s)
cd /home/safeer/docs
250 Directory successfully changed.
get file2.txt
local: file2.txt remote: file2.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for file2.txt (47 bytes).
226 File send OK.
47 bytes received in 0.00 secs (118.6 kB/s)
cd /home/safeer/docs
250 Directory successfully changed.
get file3.txt
local: file3.txt remote: file3.txt
200 PORT command successful. Consider using PASV.
150 Opening BINARY mode data connection for file3.txt (47 bytes).
226 File send OK.
47 bytes received in 0.00 secs (154.5 kB/s)

There is an maximum 8 character limit for macro names defined on command line. In netrc file this restriction is not there. Per ftp session, there is a limit of 16 macros and 4096 total characters in all defined macros.

Automating ftp logins with netrc

If you are a regular ftp user, then netrc file can help you a lot in automating your logins and a few tasks you do via ftp.

Let us first consider automating ftp logins.

Create a ".netrc" file in your home directory. The access to this file should be restricted exclusively to you.

cd ~;touch .netrc;chmod u+rw,go= .netrc

Now assume you need to connect to an ftp server "myftp.safeer.in" with username 'safeer' and password 'password#123'. To automate this, add the following line to your .netrc file.

machine myftp.safeer.in login safeer password password#123

Here machine defines the host you want to login to, login is your username for the host and password is the password for this username.

safeer@my-lptp01:~$ ftp myftp.safeer.in
Connected to myftp.safeer.in.
220 (vsFTPd 2.0.7)
331 Please specify the password.
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp>


You can define a line for each of the host you want to login. If you use the same login for many of the ftp hosts, you can use the default entry like this.

default login safeer password password#123

With this entry, if you connect to an ftp host which is not explicitly defined in netrc with a "machine" entry, the login and password from the default line will be used. If you want to disable the autologin feature of netrc while running ftp program, use the option "-n", ie; "ftp -n [ftphost]"

safeer@my-lptp01:~$ ftp -n myftp.safeer.in
Connected to myftp.safeer.in.
220 (vsFTPd 2.0.7)
ftp> pwd
530 Please login with USER and PASS.


Thats all about auto logins, now let us see how to automate tasks. We use ftp "macros" for this. FTP macros are nothing but an ordered set of ftp commands grouped with a macro name, similar to a bash function/script. You can use the macro name like another command and execute the commands included with it.

Creating a macro with name "fmacro"

macdef fmacro
cd /home/safeer/pub/site_backup
put webdata.tar.gz


Now, run the macro:

ftp> $fmacro
cd /home/safeer/pub/site_backup
250 Directory successfully changed.
put webdata.tar.gz
local: webdata.tar.gz remote: webdata.tar.gz
200 PORT command successful. Consider using PASV.
150 Ok to send data.
226 File receive OK.

ftp>


A macro defined by the name "init" (in netrc file) will be run every time you login to the corresponding ftp host. Each macro definition is associated with the login entry preceding it and terminated by a blank line. You can't define global macros in netrc file. Macros associated with the" default" entry will work for all machines that are not explicitly defined in the file. To know more about ftp macros, visit this link.

For each "machine" line you can use one or more of the variables machine,login,password in order. ie: any of the following will work.

machine myftp.safeer.in login safeer password password#123 OR
machine myftp.safeer.in login safeer OR
machine myftp.safeer.in


The last option will be used only if you want to define some macros for this host, but don't want the autologin feature. While defining the default entry, make sure that it is defined as the last entry in the file. This is necessary as netrc is processed sequentially and accepts the first entry that matches the connecting host. For more information on netrc and macros, see man pages for netrc and ftp.