Building a Better Bash Script

I often find myself writing a lot of bash scripts that wrap functionality of my services and programs in ways that make my job easier. While bash doesn’t lend itself well to traditional “inheriting” of program elements, it still is very helpful to build a toolbox of snippets, templates, and bits of script that let me assemble new scripts with tried and true methods to get things done.

One of the hardest things to do well in bash is parsing command line options in a consistent cross platform way. The template below shows an example of how to do this that allows for short, long and positional options.

The template uses getopt to normalize short options after parsing long options in a two pass approach. Using getopt transforms options into their canonical form – for example, the option string “-c foobar -laht -v” after being parsed by getopt, becomes “-c foobar -l -a -h -t -v”, allowing them to be handled more consistently.

The getopt string (stored in the variable “opts” below) consists of all the short option letters, with letters that take an argument (e.g. cmd -a foo) being followed by a colon. So if I had short options “a” and “b”, and “b” took an argument, my getopt string would be “ab:”.

# Option defaults
OPT="value"

# Gets the command name without path
cmd(){ echo `basename $0`; }

# Help command output
usage(){
echo "\
`cmd` [OPTION...]
-f, --flag; Set a flag
-o, --opt; Set an option with argument (default: $OPT)
-v, --verbose; Enable verbose output (include multiple times for more
             ; verbosity, e.g. -vvv)
" | column -t -s ";"
}

# Error message
error(){
    echo "`cmd`: invalid option -- '$1'";
    echo "Try '`cmd` -h' for more information.";
    exit 1;
}

# getopt string
opts="fvo:"

# There's two passes here. The first pass handles the long options and
# any short option that is already in canonical form. The second pass
# uses `getopt` to canonicalize any remaining short options and handle
# them
for pass in 1 2; do
    while [ -n "$1" ]; do
        case $1 in
            --) shift; break;;
            -*) case $1 in
                -f|--flag)     FLAG=1;;
                -o|--opt)      OPT=$2; shift;;
                -v|--verbose)  VERBOSE=$(($VERBOSE + 1));;
                --*)           error $1;;
                -*)            if [ $pass -eq 1 ]; then ARGS="$ARGS $1";
                               else error $1; fi;;
                esac;;
            *)  if [ $pass -eq 1 ]; then ARGS="$ARGS $1";
                else error $1; fi;;
        esac
        shift
    done
    if [ $pass -eq 1 ]; then ARGS=`getopt $opts $ARGS`
        if [ $? != 0 ]; then usage; exit 2; fi; set -- $ARGS
    fi
done

# Handle positional arguments
if [ -n "$*" ]; then
    echo "`cmd`: Extra arguments -- $*"
    echo "Try '`cmd` -h' for more information."
    exit 1
fi

# Set verbosity
if [ "0$VERBOSE" -eq 0 ]; then
    # Default, quiet
elif [ $VERBOSE -eq 1 ]; then
    # Enable log messages
elif [ $VERBOSE -ge 2 ]; then
    # Enable high verbosity
elif [ $VERBOSE -ge 3 ]; then
    # Enable debug verbosity
fi

The other interesting thing is that this template allows for multiple verbose flags (-v, -vv, -vvv, etc.) to specify different levels of verbosity – which can be a very handy thing for debugging a misbehaving script or controlling output from a subcommand.

Have other good tips for bash scripting? Share them in the comments!

View this template as a gist on github: https://gist.github.com/2765260

Read More

Disable Windows Firewall and IE ESC

I just wanted to make a post for disabling the Windows firewall from the command line on new server builds because I always manage to forget and this is pretty much the quickest, easiest way.  From the command prompt just type:

netsh advfirewall set allprofiles state off

and voila, no more wasted time trying to figure out weird network issues, super simple.

To disable each firewall individually adjust your command as follows:

netsh advfirewall set domainprofile state off
netsh advfirewall set privateprofile state off
netsh advfirewall set publicprofile state off

I also like to disable IE ESC from blocking websites by default because it is such a pain if I need to troubleshoot.  Unfortunately there isn’t a very graceful way to disable this function from the command line so I usually will just go through the Server Manager GUI to take care of this.  Server Manager -> Server Summary -> Security Information -> Configure IE ESC

On new server builds I manage to overlook these so taking the time to go through and disable these 2 items is a great time saver.

Read More

Using Google Voice as a FREE VoIP Solution

This post will go over the basics in getting basic VoIP inbound and outbound calling to work using Google Voice as a SIP trunk in your home or lab environment.  I believe this solution will work with domestic calling (I live in the United States) so I’m not sure about international calling, from what I’ve read it doesn’t sound like this solution will work out of the box.  Since I just got this working myself so there is much to be learned as I have no prior background experience in the world of voice.  But I do have to say though, I’m super excited to get this working, how cool is it to say that you have your own free phone commercial grade phone system working at home!  Ok, maybe its just the nerd in me talking.

The first step is head over to Google and create an account to associate this phone number with.  From what I’ve read it is good practice to separate this account from your main, day to day account to avoid unsolicited messages and spam to your main account.  By no means is it absolutely necessary, but it is the way I chose to do things so that is how this the direction this tutorial will follow.  Once the account has been created and you log in the first time you will need to associate a Google Voice number with the new account.  After that is done you will need to adjust your Voice settings in your new account.  Make sure your phone allows Google Chat, otherwise inbound calling won’t work.

Also make sure your Calls settings look similar if not the same as the following:

Ok, now we need to adjust the settings on our voice server.  I will not be going over the details of getting your voice server up in running in this tutorial so if you need help getting to this point let me know and I will write something up to help.  Suffice it to say, there isn’t much difficulty getting to this point, just install the ISO image and configure the networking, accounts and passwords and you will be ready.  I used PBX in a Flash for my setup (box.net 64-bit version), so grab the latest ISO and get started on the install!

Once you have completed the installation and configuration go ahead and open up a browser and head to the address you configured when setting your environment up.  If you can’t remember, run a status command from the PBXiaF command line to check the address as well as other important information.

You need to ensure that you have the Google Voice module installed by first checking to verify that it is installed and enabled (Admin -> Module Admin -> Third Party Addon -> Google Voice).

Then go take a look at the configuration page (Main Page -> Third Party Addon -> Google Voice).  Here we need to configure our settings to match the new account we just created with Google.  Make sure your settings look similar to the following:

Phone Number: The 10-digit Google Voice phone number we created.
Username: The uername we created through Google.  Only use the first part witouth the @gmail.com.
Password: The matching username password for your Google account.
Add Trunk: Checked
Add Routes: Checked
Agree to TOS: Checked

Next, we need to create an extension to route incoming/outgoing traffic to.  I chose 701 for mine (kinda borrowed it from another tutorial).  These settings can be found by going to Basic -> Extensions and choosing “Add Extensions” on the top right of the page.  There are tons of options to configure here but I am focused on basic functionality I picked a display name of 701 and a secret for that extension.  These settings are what your phone uses to talk to the server.

After that is done, add in inbound route (Inbound Call Control -> Inbound Routes) and configure it to use your Google Voice phone number and point it to the extension you just created.  The settings should look similar to the following:

Now we need to install and configure a phone to test out our new VoIP connection.  Since I don’t have a hard phone to test with I decided to sample a few different Linux options, finally settling on Qutecom.  It is relatively painless to install and configure and looks the best out of all the options I tried IMO.  To install, sudo apt-get install qutecom from command line.  Once it is installed open up the program and adjust the soft phone setting to point to your voice server, the secret you created and your newly created extension.

It is finally time to test!  At this point, I had outbound calls working through my SIP phone but incoming calls weren’t working. hmm, ok after some research I found that there was a patch for the Google Voice Addon that I needed.  From the command line on your voice server issue the update-programs and update-fixes commands to update your programs and software fixes, pretty self explanatory but was pretty much impossible to find.

In my case this step was VERY IMPORTANT and was what allowed me to receive incoming calls.  Make sure you don’t overlook this step if your are having problems receiving calls.  There are still a ton of things to work on with this setup but I was just excited I got it to work to begin with.  I hope you get som use out of this tutorial and try it for yourself.

Resources:
http://pbxinaflash.com/community/index.php?threads/2nd-google-voice-account-no-inbound.13152/#post-84527
http://www.pbxinaflash.com/community/index.php?threads/bad-week-for-google-voice.12396/
http://nerdvittles.com/?tag=google-voice

Read More

Setting up a Linux based DNS server with BIND

As my home lab continues to grow and becomes increasingly complicated I need an easy way to access my servers and network resources by their name rather than their addresses on the network.  By using DNS I can quickly and efficiently access these network resources by  their given host names, not having to worry about the growing complexity of the network.  I looked into a few different options for accomplishing this task but ultimately decided to go with the tried and true Linux BIND implementation.  The installation and configuration isn’t all that complicated to get up and running, so in this post I will go through some of the high points of my experience in standing up this service.  Let’s get going.

First, we need to install the proper packages.  By the way I was using a Debain 6.0 minimal VM for my server in this project.  So to install this stuff you need to update your repos to look for the packages.

apt-get update

Then the necessary packages

apt-get install bind9 dnsutils resolvconf

We need to configure the correct files to make our DNS function properly.  Everything that we need to configure (for Debian distros) should be located in /etc/bind.  So the first thing to change is the named.conf.local file to create the zones for our local network.  We need a zone for resolving names to IP addresses as well as a zone reverse DNS.  If you don’t know what that is, you can find more here.  In my configuration psa.local is my local domain so any hostname will resolve to hostname.psa.local in DNS.  Here is what my named.conf.local configuration file looks like:

Next, we need to set up our zones to point to the correct hosts.  The easiest way is to use the db.local as a template and copy it to a new file.  cp /etc/bind/db.local /etc/bind/db.psa.local Here is what my db.psa.local file looks like:

We need to do the same thing with our reverse records.  For me, his file is located in db.192 and we will use db.127 as the template for this file.  cp /etc/bind/db.127 /etc/bind/db.192. If you are using a different type of network layout adjust accordingly.  For example if your network is a 172.x.x.x network just name the file as db.172 or whatever the network is.  Here is what the configuration looks like, it is similar to our forward lookup zone.

Now we should be able to resolve host names (both forward and reverse) to the entries we’ve added to these configuration files.  Next we need to edit our resolv.conf file to get our host name resolution to work smoothly.  So edit /etc/resolv.conf with your favorite text editor and make the necessary changes.  Here is what mine looks like after the necesary tweaks.  NOTE I haven’t figured out why yet, but every time you restart your bind service it wipes this config out, I will update this when I figure out how to make these changes persistent.

Finally, and most importantly, here is my final named.conf.options file, with all the troubleshooting done.  This file tells bind where to forward DNS queries externally as well as other important configuration options.  You can adjust the forwarders to whichever public DNS server you choose.  I chose two well known DNS servers.  There are a few things to note here.  If you are having issues with anything check the log files 🙂  At first I had strange resolution errors for anything that was external to my domain.  The logs helped me pinpoint where the problems were and to make the necessary changes.  The most important iformation for troubleshooting is located in /var/log/syslog.

The last few entires in this file are very important for getting external DNS to resolve and is not part of the default configuration file.  You will have to add these in yourself.

allow-recursion { any; };
21 allow-query { any; };
22 allow-query-cache { any; };

Start/restart your DNS service for these configuration files to get loaded in.  /etc/init.d/bind9 restart and you should be able to ping your newly added entries by host name.

That’s it.  You can test these settings for yourself, host -l psa.local will list the hosts in your zone file.  I should also note, machines that were already on the network will need to have their DNS configurations adjusted to point to the new DNS server by editing the /etc/resolv.conf file like we did on the server itself.  Piece of cake.  With local DNS in place it makes things much easier for me to remember, just don’t forget to add new network devices to your zone files when bringing them onto your network.

Read More

Updating Ubuntu (10.04 and up) to use Sun Java

I am in the middle of a home project to build a virtual environment using Proxmox and running into Java issues. Since Proxmox uses java as a VNC console it is necessary to use the correct version (of Java) to access VM’s.  By using the wrong version you can cause instability issues and thus bad things to happen.

This is not just a problem with Proxmox either, there are a few other programs and apps that behave poorly with this version of Java, notably for me, Minecraft. Apparently newer versions of Ubuntu have shipped with the OpenJDK version as their default version and in this post I will discuss how to use to the Sun Java 6 version.

Switch to the appropriate directory, in my case I used my home directory and either punch these commands in or copy/past them to get get Ubuntu to see the correct repos.

cd ~/
wget https://raw.github.com/flexiondotorg/oab-java6/master/oab-java6.sh -O oab-java6.sh
chmod +x oab-java6.sh
sudo ./oab-java6.sh

Once this script goes through and does its thing you should have access to the old sun-java6 repos.  So to install the correct pieces for Proxmox use apt-get to install the appropriate packages.

sudo apt-get install sun-java6-jre sun-java6-fonts sun-java6-plugin

To set system settings to prefer Sun Java over the OpenJDK version type the following commands:

sudo update-alternatives --set java /usr/lib/jvm/java-6-sun/jre/bin/java
sudo update-alternatives --set javaws /usr/lib/jvm/java-6-sun/jre/bin/javaws
sudo update-alternatives --set mozilla-javaplugin.so /usr/lib/jvm/java-6-sun/jre/lib/*/libnpjp2.so

Now you should have a much more stable experience using Proxmox and the console to take a look at your VM’s!  I can’t take the credit for this but I can ease the burden for anybody that comes across this post.

References:
https://github.com/flexiondotorg/oab-java6
http://pve.proxmox.com/wiki/Java_Console_(Ubuntu)

Read More