Set Gmail as Default Mail Client in Ubuntu

Posted on June 23rd, 2008 by dandavis
Tags: , ,

A year ago at the How-To Geek: Set Gmail as Default Mail Client in Ubuntu.

I just started using Ubuntu in the past few days and found this post useful. But, because I'm me, I had to make a minor change.

My version is based upon a version in the comments of the original post with additions to support Google Apps for Your Domain.

#!/bin/bash

[[ $2 == "" ]] && domain="mail" || domain="a/$2/"
uri=`echo "$1" | sed -e 's/subject=/su=/' -e 's/^mailto:\([^&?]\+\)[?&]\?\(.*\)$/\1\&\2/'`
firefox "https://mail.google.com/${domain}?view=cm&tf=0&to=$uri"
Download open_mailto.sh.

To use it, reference the original post with one small change. If you need to specify a Google Apps domain, add it after the '%s':

/home/username/open_mailto.sh %s dandavis.com

Hope it helps.

Wanna know how to AWK it up?

Posted on June 16th, 2008 by dandavis
Tags: ,

A friend (I have lots of friends [no, really, I do]) recently asked how to use AWK to parse a really long file looking for specific strings and combinations of strings.

Unlike some of my friends, this friend knew that AWK was the right tool for job, so that was good. He just doesn't know it quite well enough to build a script to do what he wanted.

Almost everyone knows how to use AWK to extract a specific field from a line (or lines) of text… you do know how to do that, right?

awk -F: '{print $6}' /etc/passwd

This will print out the home directories of all the users in /etc/passwd:

$ awk -F: '{print $6}' /etc/passwd
/root
/bin
/sbin
/var/adm
/var/spool/lpd

And you can print multiple fields at the same time:

awk -F: '{print "User: "$1", Home Directory: "$6} /etc/passwd'

Will give a potentially more useful output showing the username and the home directory:

$ awk -F: '{print "User: "$1", Home Directory: "$6}' /etc/passwd
User: root, Home Directory: /root
User: bin, Home Directory: /bin
User: daemon, Home Directory: /sbin
User: adm, Home Directory: /var/adm
User: lp, Home Directory: /var/spool/lpd

OK, so now to the more interesting stuff…

My friend has a big ole CSV formatted log file exported from a Check Point firewall. It's got a whole bunch of useful information interspersed with some not so useful information… and it's frackin' huge. What he wants to do is search for accepted packets that are sourced from a number of subnets, destined to a single subnet, and are DNS requests. Actually a pretty straightforward parse.

Requirements:

  • Field 6 is the action: accept
  • Field 12 is the source: 192.168.*.*, 172.16.8.*
  • Field 13 is the destination: 10.11.12.*
  • Field 16 is the service: domain-udp

So, our AWK would look like:

gzcat exportedlog.csv.gz | awk -F, '\
      $6~/^accept$/ && \
      ($12~/^192\.168\./ || $12~/^172\.16\.8\./) && \
      $13~/^10\.11\.12\./ && \
      $16~/^domain/\
      {print}'

(Sorry, I don't have any output to put here, but if there were any hits from either of the two source subnets to the destination subnet, you'd see the lines printed out. Trust me… It works.)

You don't need to use the '\' and put each piece onto its own line… I just did that for readability.

I'm no AWK expert, nor do I claim to be, but hopefully you found this useful. There is a load of useful information at the GNU Awk User's Guide.

Cisco FWSM locked context restoration

Posted on June 15th, 2008 by dandavis
Tags: ,

OK, so you have a Cisco Firewall Service Module installed in a 6509 or 6513, whatev, and it's setup in multi context mode. It's running, it's got multiple contexts configured, it's passing production traffic and everything is honky dory.

Well, you decide to futz around in a new context and lock yourself out when you try to update the AAA config or some such thing… there are tons of ways you could do this… trust me… been there, done that. Now, if it weren't for all those production contexts running, you can just reload the blade and get back to your last known good config. But how can you recover without reloading the whole dag-blamed thing?

Well, assuming that you did not lock yourself out of the SYSTEM context and the ADMIN context still has IP connectivity to a TFTP server, then you can try to force feed some corrective commands into the context.

First, create a config file (e.g., BROKENCONTEXTNAME-restore.cfg) on your TFTP server that has the commands needed to correct the problem… I sure hope you know what they are… you do know what you did to screw it up and how to fix it right?

Then, once that's done, TFTP the restoration config file up to the FWSM:

host-FWSM# copy tftp://192.168.1.1/restore.cfg disk:/BROKENCONTEXTNAME-restore.cfg

Now, just cram that file down the context's throat… (This assumes that the context's regular and working start-config is saved in BROKENCONTEXTNAME.cfg):

host-FWSM# conf t
host-FWSM# context BROKENCONTEXTNAME
host-FWSM# config-url disk:/BROKENCONTEXTNAME-restore.cfg
host-FWSM# config-url disk:/BROKENCONTEXTNAME.cfg
host-FWSM# delete disk:/BROKENCONTEXTNAME-restore.cfg

At this point, all should be well. Go ahead, try it. If it didn't work, well, you screwed it up worse than you thought. You might just need to reload the blade… to hell with the production traffic.

Multiple concurrent rsyncs over a single SSH tunnel

Posted on June 14th, 2008 by dandavis
Tags: , ,

This might not have much of an audience, but I needed to write it so I decided to share it…

I had a need to download log files from a number of security appliances out on a network. The problem was that I needed to access these appliances from a specific server (let's call it the Management Server [192.168.1.1]). Well, I guess that wasn't the real problem… the real problem was that the management server did not have enough hard drive space and the server that did have the space did not have direct access to the appliances.

What's a lazy scripter to do? I mean, sure, I could've put in requests to the network guys to get my storage machine routed to the appliances… and then there are the firewall requests to go with that… oh, screw it.

My management server and security appliances all accept require SSH with public key authentication. How can I leverage that into something that means less work for me?

Well, first I make sure that my public key is on the server and appliances so my scripts can login.

Then I setup my ~/.ssh/config file so that my local machine can access each appliance via a LocalForward:

Host 192.168.1.1
   LocalForward 2220 APPLIANCE_01:22
   LocalForward 2221 APPLIANCE_02:22
   LocalForward 2222 APPLIANCE_03:22
   LocalForward 2223 APPLIANCE_04:22
   LocalForward 2224 APPLIANCE_05:22
   LocalForward 2225 APPLIANCE_06:22
   LocalForward 2226 APPLIANCE_07:22
   LocalForward 2227 APPLIANCE_08:22
   LocalForward 2228 APPLIANCE_09:22
   LocalForward 2229 APPLIANCE_10:22
   LocalForward 2230 APPLIANCE_11:22
   LocalForward 2231 APPLIANCE_12:22
   LocalForward 2232 APPLIANCE_13:22

Here is a link to a file containing the same information: SSH .config file.

OK, so now I have my public key out and about, I have the SSH config file setup to tunnel some ports through my management server out to my appliances. Now it's time to do the work:

#!/bin/bash
 
function GetLogs {
   ApplianceName="$1"
   AppliancePort="$2"
   echo "["`date +'%Y-%m-%d %H:%M:%S'`"] ${ApplianceName}: RSYNC Initiating over port ${AppliancePort}."
   /usr/bin/rsync -aqz \
      -e "ssh -p ${AppliancePort}" \
      support@localhost:/logs/ /home/dandavis/appliancelogs/${ApplianceName}/ 2> /dev/null
   echo "["`date +'%Y-%m-%d %H:%M:%S'`"] ${ApplianceName}: RSYNC Completed."
}
 
# Create tunnel connection
echo -n "["`date +'%Y-%m-%d %H:%M:%S'`"] Building SSH Tunnel to Management Server… "
ssh -S /home/dandavis/.tunnel.socket -M -N -f 192.168.1.1
echo "Done."
 
# kick off the rsyncs into background
echo "["`date +'%Y-%m-%d %H:%M:%S'`"] Initiating RSYNCs."
GetLogs APPLIANCE_01 2220 &
GetLogs APPLIANCE_02 2221 &
GetLogs APPLIANCE_03 2222 &
GetLogs APPLIANCE_04 2223 &
GetLogs APPLIANCE_05 2224 &
GetLogs APPLIANCE_06 2225 &
GetLogs APPLIANCE_07 2226 &
GetLogs APPLIANCE_08 2227 &
GetLogs APPLIANCE_09 2228 &
GetLogs APPLIANCE_10 2229 &
GetLogs APPLIANCE_11 2230 &
GetLogs APPLIANCE_12 2231 &
GetLogs APPLIANCE_13 2232 &
 
# wait for rsyncs to finish
while [[ `ps -deaf | grep -v grep | grep rsync | grep APPLIANCE` ]]; do sleep 5; done
 
# Close tunnel connection
echo -n "["`date +'%Y-%m-%d %H:%M:%S'`"] Closing SSH Tunnel to Management Server… "
ssh -q -S /home/dandavis/.tunnel.socket -O exit 192.168.1.1 2> /dev/null
echo "Done."

And, just in case Wordpress… um… improved upon my formatting, here's a direct link to the script: mainsshtunnel.sh.

WTf?!?

Starting at the top and working down…

The function GetLogs has the steps we follow for each appliance. It prints a message to the console indicating that the rsync is about to begin. Then we do the actual rsync utilizing ssh over a specific port (${AppliancePort}). When it's done, it prints another message to the console.

The first real commands in the script print out a message to the console (I love messages to the console… they're so… informative). Then it creates the SSH tunnel to the management server. The options are:

  • -M Puts the client into "master" mode… makes it easier to kill off later on.
  • -S Related to the -M option, this sets the control path that we'll use to communicate with the master client later on.
  • -N Tells the client not to execute a command on the remote host. Essentially to just connect and then chill out.
  • -f Throws the client into the background so we can get on with our business.

Now that the tunnel is up, we can start our rsyncs running. With my network setup, it's no problem running a dozen or two simultaneous rsyncs. In a future post, I'll rewrite this script a bit to allow the user to control the number of concurrent rsyncs running. To start an rsync, we just call the GetLogs function with the appliance name (for directory structure only cause the rsync-ssh actually connects to localhost), the local port on which the ssh client is listening for that particular appliance, and & to throw the whole thing into the background.

After all the rsyncs are started up, we get into a while loop waiting for them to finish up (or die off, whatev). You might need to tweak the ps and grep commands a bit to get them just right for your setup.

Once all the rsyncs are done and the while loop exits, we send a control command to the master ssh client telling it to exit.

That's it. We've got our logs downloaded.

Backup Wordpress.com Blogs

Posted on June 12th, 2008 by dandavis
Tags: ,

OK, first off, I'll admit that there might be a better way to do this automatically. I don't use Wordpress.com, so I don't know. I know with my own copy of Wordpress, I have plugin options for backing up my database.

A friend of mine asked if I knew a way to backup his Wordpress.com blog. He knew how to download the XML dump, but he wanted an automated way to do it.

I hacked this out in a few minutes… and it seems to work. I haven't tested it extensively, but my friend seems happy with it.

#!/bin/bash

# Edit these to match your blog.
USERNAME="<WORDPRESS.COM USERNAME>"
PASSWORD="<WORDPRESS.COM PASSWORD"
URL="http://<BLOG URL>.wordpress.com"
   
DATE=`date +'%Y%m%d'`
   
if [[ $1 == "" ]]; then
   # If not specified on the command line, the default directory is…
   BACKUP="."
else
   # Otherwise we'll use the one that the user wants.
   BACKUP=$1
   # if BACKUP doesn't exist, make it.
   [[ ! -d ${BACKUP} ]] && mkdir -p ${BACKUP}
fi
BACKUP="${BACKUP}/backup.${DATE}.xml"
   
# Set some default file names…
COOKIES="/tmp/cookies.txt.${DATE}.$$"
OUTPUT="/tmp/output.html.${DATE}.$$"
   
# This is the command we'll use to connect to wordpress.com…
WGET="wget --load-cookies=${COOKIES} --save-cookies=${COOKIES} --keep-session-cookies -q -O"
   
# First, we'll login and get the cookies…
POSTDATA="log=${USERNAME}&pwd=${PASSWORD}"
POSTDATA="${POSTDATA}&rememberme=forever&wp-submit=Log%20In"
POSTDATA="${POSTDATA}&redirect_to=wp-admin/&testcookie=1"
${WGET} ${OUTPUT} --post-data="${POSTDATA}" ${URL}/wp-login.php
   
# Then, using those ever so tasty cookies, we'll download an XML back from wordpress.com…
${WGET} ${BACKUP} "${URL}/wp-admin/export.php?author=all&download=true"
   
# Remove our temporary files…
rm -f ${OUTPUT} ${COOKIES}

I called it wpbackup.sh.

To use it, you can just run it at the command-line with no options and it'll pop out an XML backup of your blog. Or, you can set it up in cron to save a backup periodically depending on how much your content changes. Run from cron, I would suggest specifying a command-line option for the directory into which to save the backups:

wpbackup.sh /home/me/wpbackups

Enjoy. And if you find any bugs, post a comment. If you improve on it in other ways, post it somewhere and take credit… just post a comment here letting me know… maybe you'll have an idea I can steal and use in my own scripts. :)

Simplify your URLs

Posted on June 12th, 2008 by dandavis
Tags: ,

I hate long URLs. Hell, I even hate extensions on my pages.

For some sites I've done, I did not want to have a bunch of individual pages:

  • /index.php
  • /help.php
  • /about.php

I wanted to use Smarty, a template engine for PHP, but without having to create individual PHP files and without long URLs (/index.php?page=about).

So, in my index.php file:

<?php
$smarty = new Smarty();
list ($page,$query) = explode("?",$HTTP_SERVER_VARS["REQUEST_URI"]);
$page = basename($page, ".php");
$smarty->assign('page', $page);
$smarty->display('index.tpl');
?>

(I stripped a bunch out, of course. For example, you never want to take what a user tells you at face value! My index.php file cleans up $page and compares it against a list of valid pages before doing anything else.)

Then, in index.tpl, I have a basic structure in place and I use Smarty's {include} function to include 'page' in the correct location:

<html>
<head>
<title>Common Title - {$page}</title>
</head>
<body>
Some common content, perhaps.
{include file="$page.tpl"}
</body>
</html>

And, then, to get rid of index.php… so that /about loads the about.tpl content, etc, in .htaccess I have:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.mydomain\.com$ [NC]
RewriteRule ^(.*)$ http://mydomain.com/$1 [R=301,L]
 
RewriteCond %{SCRIPT_FILENAME} ! -f
RewriteCond %{SCRIPT_FILENAME} ! -d
RewriteRule ^(.+)$ /index.php?$1 [PT,L,QSA]
</IfModule>

That first part, where I redirect www.mydomain.com to mydomain.com, is because 'www.' is redundant and its use has been deprecated!

The second part has the bits that are relevant to this post…

RewriteCond %{SCRIPT_FILENAME} ! -f
RewriteCond %{SCRIPT_FILENAME} ! -d

If the user is requesting an actual file or directory, then we won't try to rewrite the URL of the request to meet our own perverted neatness requirements.

RewriteRule ^(.+)$ /index.php?$1 [PT,L,QSA]

The URL that the user requested, not being an actual file or directory, is rewritten to be a query string to index.php.

So, for example, if the user requested http://mydomain.com/about, this rewrite would cause Apache to serve up http://mydomain.com/index.php?about (without rewriting the address in the browser). index.php would parse the string, set $page = 'about' and load up the index.tpl Smarty template. Smarty would parse the template and include about.tpl.

There! That was overly complex and convoluted, but at least my URLs remain short and I can add new pages (or update common bits of code) without a bunch of copying, pasting, and editing. And that makes me happy.

Hiding referral links

Posted on June 12th, 2008 by dandavis
Tags:

When you run across a referral link to a product (at Amazon.com, for example), are you the kind of user that copies the link and replaces the referral code with your own or a friends?

Yeah, me too! I hate users like us!

There might be packages or code snippets out there for this already, but I wrote my own 'cause that's what I do.

First, I wrote a file (externallinks.php) that has a list of referral links… this could be done in a database, but that was overkill for me.

<?php
$url['amazon-product-1'] = 'http://www.amazon.com/exec/obidos/ASIN/B0015AR7AK/dandaviscom-20';
$url['amazon-product-2'] = 'http://www.amazon.com/exec/obidos/ASIN/1591862027/dandaviscom-20';
# Not sure if this next one works like I think it does…
# but it's a whole lot shorter than the one that I *know* works.
$url['default'] = 'http://www.amazon.com/?tag=dandaviscom-20'];
?>

Once you have your list of external links, you would setup your external.php (or whatever you want to call it)…

<?php
require_once('externallinks.php');
if (isset($_REQUEST['link']) && !empty($_REQUEST['link'])) {
   $link = $_REQUEST['link'];
   if (isset($url[$link]) && !empty($url[$link])) {
      Header('Location: '.$url[$link]); exit;
   }
}
echo 'Give the user some error about there not being a valid link. You know… to be helpful and all…';
exit;
?>

Now, in your pages, instead of putting in the direct links, you can link to this page.

For example, instead of:

http://www.amazon.com/exec/obidos/ASIN/B0015AR7AK/dandaviscom-20

You would link to:

http://yourdoamin.com/external.php?link=amazon-product-1

Now, once the user gets to Amazon (or wherever), then they could change the referral code… unless that site uses some sort of redirector. Amazon.com has one: http://www.amazon.com/gp/redirect.html.

Perpetual Copyright

Posted on June 12th, 2008 by dandavis
Tags:

Seen this a few times while stumbling. I've been doing it myself for quite a while now, but…

Put this code in the footer of your pages:
<?php
$copyright = '2005'; $year = date('Y');
if ($year > $copyright) { $copyright .= '-'.$year; }
echo 'Copyright &copy; ',$copyright,' Me';
?>

Produces:

Copyright © 2005-2008 Me

And, as other sites are keen on pointing out, on January 1st of the new year, your copyright text will automatically update… So, January 1st, 2009, the code about will print out:

Copyright © 2005-2009 Me

Etc, etc.

Heading in a new direction

Posted on June 12th, 2008 by dandavis
Tags:

I've decided to change things up. I mostly just have dandavis.com for the email. I've always had a hard time figuring out what to put on the web side of things. I think I'm going to start putting code snippets that I find extremely useful and other nonsense like that. If anyone actually sees these posts, perhaps they will find something of use.

office ultimate 2007 for students for only $59.95!!!

Posted on March 31st, 2008 by dandavis
Tags:

I saw this linked to from my school's web site. I have been needing a copy of 2007, but I couldn't really afford (justify) the cost to upgrade and I was hesitant to use other avenues to procure a copy.

Next Page »