Search this blog ...

Monday, March 21, 2011

Malware exploiting Java Plug-In 1.6.0_22

I learned a nasty lesson yesterday about the dangers of not having the very latest versions of browser plug-ins installed.  The irony is that I work for the company that developed the Plug-in. I had installed the Sun (Oracle) JDK / JRE Standard Edition 6 Update 22 which was released only back in October 2010. This includes a Java Plug-In that will allow applets to be invoked from the browser.

Running the current latest version of Firefox (3.6.15) on Windows XP, I opened the top few sites returned from a Google search for UFC 128 title fight video in separate tabs. I was immediately called away to tend to my son, and returned to find my wife in front of the laptop with a multitude of Internet Explorer windows popped-up. I proceeded to chastise her and give her the ‘WTF are you doing’ / ‘What have you done’ spiel – only to be told she hasn’t pressed a key/or button.

Bugger!

Malware.

I immediately ripped the network cable from the back of the computer, and proceeded to start Task Manager along with a program called TaskInfo (by Iarsn) – and kill any and all processes that didn’t look right. Unfortunately I had recently got a bit lazy/blaze about what runs on my laptop and hadn’t taken too much notice regarding any new drivers/services that were installed (i.e. HP Universal Print Driver / Canon Scanner / OpenVPN network adapter etc).  So I was struggling to work out what was legit and what was not.

In the few short minutes I was gone from the computer, the Malware well and truly set its hooks in installing crap such as Offerbox and various browser plug-ins/extensions. My AVG Anti-Virus Free Edition version 2011 unfortunately caught very little of this malware that was being installed.

Fortunately I also had installed on my machine two additional free programs.  The first being CCleaner http://www.piriform.com/ccleaner, and the second, a very old version of Unlocker developed by Cedrick Collomb.  Unlocker is an extremely useful tool that is capable of releasing various locks on files that are being held by system and application processes. Using CCleaner, I was able to see *some* of the additional startup programs that had been added. Using Unlocker, I was able to delete a lot of malware running, and also delete the “C:\Program Files\Java” directory as well. After removing some of the malware, I ran CCleaner’s Registry Cleaner tool which provided me some locations in the registry that were invalid (pointing to missing shared DLLS/applications paths broken etc).  Those entries identified by CCLeaner which corresponded to Malware, gave me a starting point for my manual registry “cleaning”.

I also stumbled in to the Windows “Prefetch” directory that gave me a basic timeline of the crap that got installed on my machine when I was away, and also some other programs to try and identify and delete.

IMG_thumb[2]

I cleaned and deleted as much as I could, and performed my first reboot (keeping the network cable disconnected).  Firing up TaskInfo after the machine started, I could see some rundll32.exe processes that had spawned that were pointing to some weird DLL files in existing legitimate directories.  I could see a file named “lusrmgrk.dll” that was both being invoked from the “C:\Windows” and “C:\Program Files\Pidgin” directory. I opened those directories  and set the Folder View Model to detailed and enabled display of both “Date Modified” and “Date Created” columns.  Sure enough, those files had been created/modified at exactly the time of this malware travesty. I deleted these files using Unlocker’s assitance.  There were other strange files in the Windows directory with similar date/times that were listed in the Prefetch folder at around the time of the Malware installation;  So those got deleted as well.  I initially set about running some MD5 checksums on the files to see if anyone had a similar virus and reported the checksum, but didn’t get any hits.  For example, the MD5 of “Lfeboa.exe”, which was 137216 bytes, was “014303FB5CF4F2F8A2EADD5EDD82427B”.

Up until this stage, I had not reconnected the network cable on the infected laptop.  The Apple iPad was getting used to search google for md5 checksums and read various malware removal articles.  It was at this point, I really hated Apple and what it stood for. Steve Jobs and/or the marketing geniuses at Apple decided the iPad would not need any external storage support (micro SD etc). I can only speculate this is purely self-motivated so that they can get the Apple fanboys to continually upgrade to a newer device with more capacity. What this meant though, is that I had no way of getting a file from the iPad to my infected computer without establishing a network connection (or jail-breaking the device and buying a camera kit). Thankyou Apple.

So the network connection on the PC had to be turned on (very very briefly).  I downloaded two apps:

TDSSKiller (an anti-rootkit utility from Kaspersky Lab: http://support.kaspersky.com/faq/?qid=208283363)

and

Malwarebytes Anti-Malware (http://www.malwarebytes.org/mbam-download.php )

Malwarebytes needed to be briefly connected to the internet so that it could update its database, but there is a workaround in future for this:  See issue #4: http://forums.malwarebytes.org/index.php?showtopic=10138

Having downloaded and installed these, the network connection was yanked and I let the programs do their jobs. Both apps found remaining malware on disk and were able to remove most* traces. I initially did the quick scan with Malwarebytes, but eventually did the full scan which detected an additional malware file.

Upon reboot, I fired up the taskinfo application, but could still see two rundll32.exe processes.  However the processes were attempting to load DLLs that were not present on disk.  I decided to run the Windows Malicious Software removal tool, but it did not detect anything.

My concern was that there was still some malware on disk that was causing the processes to be initiated.

Taskinfo also provides an option to view the parent process ID of a task.  The parent process IDs  for the rundll32 processes were pointing to a svchost process.  And in particular, “C:\WINDOWS\System32\svchost.exe -k netsvcs”.

See the following article for a description of svchost: http://support.microsoft.com/kb/314056

Basically, Svchost is responsible for starting services at startup. If you were to view task manager, you would see there are a number of svchost processes, each of which is starting services from a particular service group.  The “netsvcs” group encompasses some 20 or so services:

snap1028

snap1027

One of the services in the group was ultimately triggering the rundll32 processes.  I just wasn’t sure how.  It could be that a malware service had been added; or maybe an existing legitimate service had been compromised; or maybe an existing service had a dependency on some other service that was compromised etc.

Unfortunately I could not find an easy way to work out which service was triggering the rundll32 processes.  So I decided to basically stop them in blocks and restart the computer and try and isolate which service was somehow responsible.

Bingo; Task Scheduler was somehow a part of this! I had read up about Malware creating and scheduling tasks to spawn their evil crap.   I had looked in the C:\Windows\Tasks directory, but it was empty. This was from Windows Explorer with all options set to show hidden files.  So I was concerned that the Task Scheduler process itself maybe compromised, or a dependant service (Remote Procedure Call).

I decided to do one final check from command prompt supplying the “/ah” option to the “dir” command. Wow; there were some .job files in the directory.

tasks

Using the “Xcacls.vbs” tool, http://support.microsoft.com/kb/825751/en-us I was able to give my local administrator user “full control” on the two .job files. Having done this, I was able to change the file permissions so they were no longer hidden etc.

At this point, the tasks became visible from Windows Explorer, and they could be deleted:

snap1025b

snap1025

snap1026

A quick reboot, and the processes were no more. 

I’ll never know If I’ve removed all the Malware; But one thing is for sure, I’m going to be much more anal when it comes to Browser plug-ins.

And … if you are currently running JDK 1.6.0_23 or older, make sure you upgrade!!!!!!

http://www.oracle.com/technetwork/topics/security/javacpufeb2011-304611.html

Wednesday, March 16, 2011

Tomato – Adding Custom Packages - NVRAM vs JFFS vs USB Stick

I made the mistake last night of visiting the Tomato forum using my new (but actually second-hand) generation 1 iPad. It was late, and I desperately needed the sleep, but what the hell. Unfortunately I came across a forum thread titled My utilities web site revived.  Some two and a bit hours later (and well into the next day), I put the iPad down having read the thread from start to finish.  I gleaned so much useful and interesting bits of information from that that thread that I felt compelled to write a blogpost. This was mostly for my own future reference, but also to share the knowledge.

All I can say is that ‘rhester72’ is a porting/compilation stud and by the looks of it one generous and smart dude.  Tomato community are very lucky to have him. 

Me personally – well I’m one of the 4 billion java developer drones. I haven’t actively coded in C/C++ for a number of years. I miss these languages; mostly I miss  the forgotten skills to properly harness and control these languages – compiler directives / linking /make files / best practices etc.   My foray into iPad application development will at least see me leveraging C once more.

Anyway, returning to blog topic …

rhester72 has gone to the trouble/effort of compiling a number of very useful packages/applications for the Tomato environment (MIPS processor series / running 2.6 Linux kernel/and to a lesser extent 2.4 kernel). These packages add some nice bells and whistles that may come in very handy. For example,  the torrent client (transmission) means you can potentially turn off your power-sucking gaming box and leave it to your ~10 watt ASUS RT-N16 :)

The binaries come in two styles:

  1. static linked
  2. dynamic linked

Static linked binaries are generally much bigger in size, as the dependent libraries are linked/packaged directly in the resulting binary. It is not however always possible to produce a static binary for certain types of packages due to their architecture.

Dynamic linked binaries on the other hard should be smaller, as they are linked at runtime to dependent shared libraries.  The issue with these style of binaries is actually finding the the shared libraries themself at runtime:

  • the shared library may actually be missing from the machine, or not available in the shared library search path (meaning the binary cannot be run)
  • an incompatible version of the shared library may be located in the shared library search path (causing some type of conflict resulting in the binary not behaving correctly)

Dynamic linked binaries can however reduce memory footprint and save valuable space should multiple packages that you plan on running leverage same versions of specific shared libraries.

Space and memory permitting, it is often simpler to take the static binary.

Check out rhester72’s list of packages at the following URL:

http://www.multics.minidns.net/tomato/

Be sure to view the descriptions, notes, and most importantly the readme.

When using dynamically linked binaries, it is not always obvious what the required shared library dependences are. Fortunately, the “ldd” command can be used to help out.

root@asus:/tmp# wget http://www.multics.minidns.net/tomato/PRECOMPILED/atop
root@asus:/tmp# chmod u+x atop
root@asus:/tmp# ldd atop
        libncurses.so.5 => not found
        libm.so.0 => /lib/libm.so.0 (0x2aabf000)
        libz.so.1 => not found
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x2aadd000)
        libc.so.0 => /lib/libc.so.0 (0x2aafc000)
        ld-uClibc.so.0 => /lib/ld-uClibc.so.0 (0x2aaa8000)
root@asus:/tmp#

 

Above, you can see that libncurses.so.5 and libz.so.1 are missing.  Lets rectify this …

 

root@asus:/tmp# wget http://www.multics.minidns.net/tomato/PRECOMPILED/lib/libncurses.so.5

root@asus:/tmp# wget http://www.multics.minidns.net/tomato/PRECOMPILED/lib/libz.so.1

root@asus:/tmp# ldd atop
        libncurses.so.5 => not found
        libm.so.0 => /lib/libm.so.0 (0x2aabf000)
        libz.so.1 => not found
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x2aadd000)
        libc.so.0 => /lib/libc.so.0 (0x2aafc000)
        ld-uClibc.so.0 => /lib/ld-uClibc.so.0 (0x2aaa8000)

This still did not work; Why?

The answer is the shared library search path.

In Linux, Shared Libraries are searched (in order) from the following locations until a match is located:

  1. LD_LIBRARY_PATH environment variable (if set)
  2. A specific rpath location encoded in to the dynamically linked ELF binary (or shared library) at compilation time (if set)
  3. System default paths defined in /etc/ld.so.conf

On my specific stock tomato instance, LD_LIBRARY_PATH is not set. 

Using the readelf command on the atop binary, I can see the Library rpath is set to /opt/lib:/opt/usr/lib.

rpath

The contents of ld.so.conf on my instance are:

root@asus:/tmp# cat /etc/ld.so.conf
/opt/lib
/opt/usr/lib
/lib
/usr/lib

 

Thus, I need to modify the instance so that the  libncurses.so.5 and libz.so.1 libraries can be found.  For the time being, I’m going to manually set LD_LIBRARY_PATH to the /tmp directory which is where I downloaded the files in the first place:

root@asus:/tmp# export LD_LIBRARY_PATH=/tmp

root@asus:/tmp# ldd atop
        libncurses.so.5 => /tmp/libncurses.so.5 (0x2aabf000)
        libm.so.0 => /lib/libm.so.0 (0x2ab12000)
        libz.so.1 => /tmp/libz.so.1 (0x2ab30000)
        libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x2ab53000)
        libc.so.0 => /lib/libc.so.0 (0x2ab72000)
        ld-uClibc.so.0 => /lib/ld-uClibc.so.0 (0x2aaa8000)

As you can see above, the dependent libraries are now found, and we can at least attempt to invoke the atop binary!

Now that you know how to add the packages, the question is where to install them:

  • Recall that the /tmp directory on the Tomato router is volatile; It is essentially a ramdisk created in available RAM of the router, and is blown away upon reboot.
  • Non-volatile available/free flash memory on the router, if sufficient, can potentially be leveraged with important caveats.
  • Another recommended choice (if available with your router) it to leverage an external USB stick/drive
  • Possibly you may be able to even utilize network attached storage.

Flash memory is obviously very convenient, but it comes in a variety of sizes. The Linksys WRT54G series came in 2MB, 4MB and 8MB varieties. It is hard enough getting a distribution like Tomato on a router with such little flash memory, let alone using it for custom packages and the like.

The ASUS RT-N16 on the other hand has 32 MB of flash. Even with the full-blown VPN 2.6 Tomato bundle installed, there is still some 25MB available for potential JFFS2 use. There is also a special area in the flash memory known as the NVRAM segment. This is essentially the very last segment in the flash memory and is at minimum one “erase block” in size. Although the erase block size is typically 64KB (or 128KB as is the case with the RT-N16), the actual NVRAM is programmatically restricted to 32KB.

Tomato does support a special “nvram setfile2nvram” command that will allow you to store a very small file in any remaining NVRAM space (such that, within the 32KB not the full erase block segment size i.e. 128KB on the RT-N16).  However, this option should be leveraged as one of the last resorts. If you have free flash memory available, then JFFS2 is a better option.  Even better again is to leverage a USB stick if your router supports it. 

The reasons for this is best explained by OpenWRT developer/CoFounder MBM’s post at the following location: https://forum.openwrt.org/viewtopic.php?id=10083

To quote him directly:

“The flash chip is broken up into sections called erase blocks. On a 4M chip it's usually 64k and on an 8M chip it's 128k. Each erase block is rated at about 100,000-1,000,000 erase/write cycles depending on vendor.

This just means that on a 4M chip you have to have to erase 64k and rewrite it even if you only want to change one byte of the 64k. After that 64k block has been erased 100,000 times you risk failure where it won't store the data properly.

The problem with the NVRAM implementation is that it's exactly one erase block at the very end of the flash. When you boot, the NVRAM data is copied to a buffer in ram; with the exception of "nvram commit", all the nvram commands are using the copy in ram. When you do an "nvram commit" it writes the contents of ram to the flash. So, when you have a chip rated for 100,000 cycles, you'll probably have a failure around the 100,000th "nvram commit".
”

Although leveraging JFFS2 will still result in wear due to erase cycles, this file system is specifically designed with flash devices in mind.  It is engineered is such a way to make “wear-levelling more even and prevent erasures from being too concentrated”.

Once again though MBM  makes an important point:

“ Suppose we have a jffs2 filesystem with two types of files, files that never change and files that change frequently. Common sense says that the erase blocks containing the files that never change or contain free space will only be written once and will remain untouched while the blocks containing the other files will change frequently; wear leveling means that all of the blocks within the jffs2 filesystem will be used equally, so all of the blocks in the above example would be written to equally even if it means moving data that hasn't changed“

Thus, if you anticipate files being updated /writes occurring on the JFFS2 partition at a considerable rate, you are eventually going to ruin your flash chip.  In such scenarios you must absolutely use something like USB.  You must also be very careful that any custom packages you install are not repeatedly writing (e.g. log messages) to a location that is stored in the JFFS2 partition.

tomato jffs2

Here is an ugly script I wrote designed for Tomato 1.28 to get details of flash memory allocation/distribution; Note that I have enabled JFFS2 support on my router from the Tomato UI (Administration > JFFS page):

cat > /tmp/flashinfo.sh <<EOF
#!/bin/sh

# Tomato 1.28 Flash Info Script by Matt Shannon

echo "Router model: " \`nvram get t_model_name\`
uname -a
echo ""

dmesg | grep nvram
dmesg | grep jffs2
echo ""

cat /proc/mtd
echo ""

ERASEBLOCKSIZE=0x\`cat /proc/mtd | grep nvram | cut -f3 -d " "\`
echo "Erase Block size is" \`awk 'BEGIN{printf("%d", '\$ERASEBLOCKSIZE' / 1024)}\` kilobytes
echo ""

NVRAMSEGMENT=0x\`cat /proc/mtd | grep nvram | cut -f2 -d " "\`
echo "NVRAM Full Segment size is" \`awk 'BEGIN{printf("%d", '\$NVRAMSEGMENT' / 1024)}\` kilobytes

NVRAMSUMMARY=\`nvram show | tail -1\`
NVRAMUSED=\`echo \$NVRAMSUMMARY | cut -d "," -f2 | cut -d " " -f2\`
NVRAMFREE=\`echo \$NVRAMSUMMARY | cut -d "," -f3 | cut -d " " -f2\`
echo "NVRAM Actual Size Available to firmware is" \`awk 'BEGIN{printf("%d", ('\$NVRAMUSED' + '\$NVRAMFREE') / 1024)}\` kilobytes
echo "NVRAM Summary: \$NVRAMSUMMARY"
echo ""

JFFSSIZE=0x\`cat /proc/mtd | grep jffs2 | cut -f2 -d " "\`
echo "JFFS2 size is" \`awk 'BEGIN{printf("%d", '\$JFFSSIZE' / 1048576)}\` megabytes
echo ""
EOF

chmod 744 /tmp/flashinfo.sh

/tmp/flashinfo.sh

sample output:

Router model:  Asus RT-N16
Linux asus 2.6.22.19 #8 Tue Nov 30 14:58:27 EST 2010 mips GNU/Linux

0x01fe0000-0x02000000 : "nvram"
0x006e0000-0x01fe0000 : "jffs2"

dev:    size   erasesize  name
mtd0: 00040000 00020000 "pmon"
mtd1: 01fa0000 00020000 "linux"
mtd2: 005aec00 00020000 "rootfs"
mtd3: 01900000 00020000 "jffs2"
mtd4: 00020000 00020000 "nvram"

Erase Block size is 128 kilobytes

NVRAM Full Segment size is 128 kilobytes
NVRAM Actual Size Available to firmware is 32 kilobytes
NVRAM Summary: 852 entries, 21155 bytes used, 11613 bytes free.

JFFS2 size is 25 megabytes

 

Recall from above that rhester72’s dynamically linked binary atop hardcodes an rpath to /opt/lib:/opt/usr/lib. If you were to SSH in to your router however, you will likely find that the /opt directory is empty.  Rhester72 leverages an init script (Tomato UI > Administration > Scripts > Init)  to attempt to automatically bind the /opt location to a directory “opt” found in the /jffs mount location. (Note, when enabling JFFS2 in Tomato, the JFFS partition is automatically mounted at startup under the /jffs directory). Here is his script which will try for 30 seconds to bind the opt directory:

t=0
while [[ ! -d /jffs/opt && $t -lt 30 ]];do
sleep 1
t=$(($t+1))
done

if [ -d /jffs/opt ];then
mount -o bind /jffs/opt /opt
else
logger -t /jffs -p err did not mount within $t seconds
fi

If the bind fails, a message will be written to /var/log/messages.  To utilize such an approach you will need to do the following:

  1. enable JFFS2
  2. once the jffs partition is mounted, mkdir /jffs/opt
  3. make appropriate subdirectories mkdir -p /jffs/opt/bin /jffs/opt/lib /jffs/opt/sbin /jffs/opt/usr/bin /jffs/opt/usr/lib /jffs/opt/usr/sbin /jffs/opt/usr/share

Refer to his readme.

Leveraging the above directory structure to store binaries and shared libraries should give you good results (remember /opt will be bound to /jffs/opt):

root@asus:/tmp/home/root# echo $PATH | tr ":" "\n"
/bin
/usr/bin
/sbin
/usr/sbin
/home/root
/mmc/sbin
/mmc/bin
/mmc/usr/sbin
/mmc/usr/bin
/opt/sbin
/opt/bin
/opt/usr/sbin
/opt/usr/bin

root@asus:/tmp/home/root# cat /etc/ld.so.conf | grep /opt
/opt/lib
/opt/usr/lib

As a final note, be careful with setting LD_LIBRARY_PATH in any profile.  Also it is worth inspecting the /etc/profile script, you will see that it attempts to source both /jffs/etc/profile and /opt/etc/profile (if they exist).

profile

Thanks again to rhester72;

Monday, March 14, 2011

Quick & simple VPN setup guide: using OpenVPN on a ‘Tomato’ router

Before the advent of custom firmware on consumer-priced/graded routers (Linksys/Netgear etc), obtaining secure remote access to a network resource using stock firmware was somewhat an art.  Circa 2002, I remember geeking it up in front of my work colleagues by remotely accessing my home machine’s desktop to download mp3 over Napster. Back then, I was using a combination of port-forwarding, VNC, and SSH; amazingly this setup was able to be tunnelled through work’s HTTP proxy server.

Even today, many people still leverage such approaches.  The following links give a bit of a history and overview:

http://members.shaw.ca/nicholas.fong/vnc/

http://nodivisions.com/tech/vnc/

Modern custom router firmwares (DD-WRT / Tomato / etc) make it even simpler by bundling some of the required software.  Here is a link that describes an updated approach to the above:

http://blog.dreamdevil.com/index.php/2008/09/06/remote-desktop-through-ssh-with-putty-and-tomato-firmware/

Anyway…

A friend whom runs a small business on a tight technology budget recently asked me what I would suggest that would allow his employees remote access to the office “files”.  He and his colleagues are regularly travelling for days at a time and require access both at customer sites, and also from hotels.  Most of the sites he visits do allow him to connect his laptop to the customer network; but not all. Thus, we needed a solution that would wherever possible allow him to leverage the customer’s office internet connection. For those sites that prevent such access, he would leverage a 3G solution using either a USB dongle, or 3G Wi-Fi Hotspot.

Immediately, OpenVPN sprung to mind as a possible solution – mostly cause it was free, and also had client support on Windows, Mac, and Linux. The icing on the cake however was the fact that the DD-WRT and Tomato router firmwares happened to provide special VPN builds that bundled the OpenVPN server application.  Thus, assuming we could locate a router with sufficient grunt that could run such a firmware, there would be no need to have a dedicated separate OpenVPN server machine.

Basically, three main routers sprung to mind:

Asus RT-N16

Linksys (Cisco) E3000

Netgear WNDR3700

The first two routers (Asus & Linksys) are supported by Tomato.  All three routers are supported by DD-WRT.

I’ve had great success with Tomato in the past, so I suggested to my friend to purchase the Linksys E3000. This can be purchased here in Australia for about $170.

It just so happened that I had an Asus RT-N16 at home, hence I was able to test out the VPN configuration on my home environment, before messing with my friends office network. I liked it so much (having a VPN), that I decided to keep it and refine it!

The main decisions when leveraging OpenVPN are:

1) Does your router have a static WAN IP address?

If you router does not have a static IP address, then you are at the mercy of your internet provider whom may or may not reissue you the same IP address upon lease expiration/reboot etc. It is best to play it safe and configure your router to use a Dynamic DNS. Sign up for a free account at an appropriate provider (e.g. http://www.dyndns.com), and then configure your router with the appropriate DDNS account details.  Your router will subsequently register your dynamic IP address with the provider whenever your WAN connection comes up/changes. This way, you can configure your OpenVPN client configuration with a static hostname (e.g. todayguesswhat.dyndns.org)

2) Do I TUN (network TUNnel) or TAP (network tap)?

TAP > runs at layer 2 (OSI model)  - bridge mode ; effectively the VPN client will appear to be on the same network subnet as the destination. Packets broadcast on destination network will be received by client.

TUN > runs at layer 3 (OSI model) – router mode; effectively the VPN client is on a different network to the destination; routing rules are used to allow the client to access the destination network.  Packets broadcast on destination network won’t be received by VPN client.

3) What protocol: TCP or UDP?

SgtPepper (Tomato guru) over at the LinksysInfo forum clarified/corrected my understanding of what this option means. Initially I assumed incorrectly that the choice between TCP and UDP came down to what application layer network protocols you planned on using over the VPN.  Such that, if you wanted FTP/Telnet/SSH HTTP/HTTPS/SMTP/IMAP/SMB-over-TCP/NFS-over-TCP/ you chose TCP, whereas VoIP and Network Games, then UDP.  WRONG!

To Quote SgtPepper directly “Choosing TCP vs UDP should have nothing to do with the application type you're using. OpenVPN tunnels TCP and UDP traffic over whichever protocol you choose. Tunneling TCP over TCP is extremely inefficient, so TCP should only be chosen if you absolutely have to. That should only be if you have to go through an HTTP proxy, trick a firewall, or have a very flaky connection and have problems with UDP. If you have the option, you should absolutely 100% use UDP.”

4) What port for the server to listen on?

The default port is 1194. But if 443 is available, I would suggest using this. The use of port 443 is particularly pertinent to TCP-based OpenVPN configurations whereby client access to the VPN may require tunnelling through a proxy server. Proxy servers are much more likely to accept traffic destined for port 443 versus something like 1194. Port 443 is the default port used by secure HTTP (aka HTTPS), and as such most proxy servers should allow it unimpeded.

5) What LAN subnet/segment should the router be leveraging?

Most routers ship with a default IP address of 192.168.1.1, and subnet mask 255.255.255.0. Chances are, one of the destinations you visit will also be leveraging such a topology. The problem occurs when the destination network is the same as the actual client network you are connecting from. For example, if my network at home is 192.168.1.x, and I’m at a client site that is using 192.168.1.x, and I attempt to make VPN connection to home, the routing tables get completely messed up. There are probably some crazy network mask and routing rule/metric options you can leverage to work around such a situation, but my advice is to avoid it in the first place.

 

 

For my home VPN, I decided to leverage TAP (interface type), TCP (protocol), 443 (port), and 192.168.192.1/24 (CIDR Notation).

The reason I chose TAP is to theoretically support broadcast traffic, but mostly so as to appear on the same network as my destination. If your client has no business to receive the broadcast traffic, and you are expecting large amounts of broadcast traffic on the destination network subnet, then it is best to switch to TUN.

The reason I chose TCP is that OpenVPN natively supports tunnelling of the TCP traffic over a HTTP proxy. This means that if we are stuck behind a HTTP proxy without direct internet access, we can still hopefully access the VPN by tunnelling through the proxy server. Refer to SgtPepper’s quote from above however regarding efficiency and only choose this option if you have to!

I chose port 443 likewise to increase my odds of a proxy server connection working, and also so that it looks legitimate from an auditing perspective.

I chose 192.168.192.x/255.255.255.0 network for my LAN, as this network has less chance of being leveraged on a client site (unlike for example 192.168.1.x).

One interesting point to make is that Tomato natively supports two OpenVPN server processes running at the same time.  Thus there is nothing stopping you running TCP and TAP for one instance, and UDP with TUN/TAP on the other instance.

 

Now… on to the VPN setup:

If you are running a Linksys E3000, I suggest obtaining and installing the following firmware (or newer):

tomato-E3000USB-1.28.9054MIPSR2-beta-vpn3.6.bin

the above firmware can be installed directly over the top of the factory firmware.

 

If you are running an Asus RT-N16, I suggest obtaining and installing the following firmware (or newer):

tomato-K26USB-1.28.9054MIPSR2-beta-vpn3.6.trx

Note: With the RT-N16, to upgrade from a stock firmware you must first flash the router with the following:

http://www.dd-wrt.com/routerdb/de/download/Asus/RT-N16/-/dd-wrt.v24-14896_NEWD-2_K2.6_mini_RT-N16.trx/3763

 

Next, you must download and install the OpenVPN software specific for your OS (client)

For Windows, this is currently: http://swupdate.openvpn.net/community/releases/openvpn-2.1.4-install.exe

As we only need the client components and RSA certificate management scripts, be sure to DESELECT “OpenVPN Service”.

openvpn

 

Next, we will generate the various keypairs…


CD /D "%ProgramFiles%\OpenVPN\easy-rsa"

##   create vars.bat and openssl.cnf from templates
init-config.bat

##   Update the values in vars.bat as appropriate, specifically:
##   KEY_COUNTRY, KEY_PROVINCE, KEY_CITY, KEY_ORG, KEY_EMAIL
##   If requiring stronger keys, change KEY_SIZE from 1024 to 2048
##   Use WordPad to edit the file, as it leverages UNIX line breaks
"%ProgramFiles%\Windows NT\Accessories\wordpad.exe" "%ProgramFiles%\OpenVPN\easy-rsa\vars.bat"

vars


##   Invoke vars.bat to set environment
vars


##   CAUTION - deletes any existing keys / reset SERIAL and INDEX.TXT
clean-all


##   Construct Certificate Authority keypair, set commonName to be CA
build-ca

ca


##   Construct server keypair, set commonName to VPNServer
build-key-server server

server


##   Construct client keypair for user 'matt', set commonName as appropriate (e.g. matt)
build-key client_matt

client 

...

##   Construct client keypair for user 'louise', set commonName as appropriate (e.g. louise)
## build-key client_louise

##   NOTE - if you have specified a challenge password in your certificate when you created it,
##   you will be required to provide that password should you ever want to request to revoke the certificate


##   The keys directory will contain private keys / certificates / index file stating
##   issued certificates / serial file containing next serial number to leverage etc.
##   !!! KEEP THEM IN A SAFE PLACE. !!!!

keys


##   Generate Diffie Hellman parameters
##   This will generate dh1024.pem in keys folder (or dh2048.pem files, depending on KEY-SIZE variable)
build-dh

dh

 

Next, we will configure Tomato…

From the Tomato Administration UI, choose “VPN Tunnelling” > "Server”

Refer to screenshots for detailed settings.

Basic Settings:
Start with WAN: <checked>
Interface Type: TAP
Protocol: TCP
Port: 443
Firewall: Automatic
Authorization Mode: TLS
Extra HMAC authorization (tls-auth): Disabled
Client address pool: DHCP <checked>

tomato1

Advanced Settings:
Poll Interval: 0
Direct clients to redirect internet traffic: <NOT checked>
Respond to DNS: <NOT checked>
Encryption cipher: Use Default
Compression: Adaptive
TLS Renegotiation Time: -1
Manage Client-Specific Options: <checked>
Allow Client<->Client: <checked>
Allow Only These Clients: <NOT checked>

Custom Configuration**:
script-security 3
auth-user-pass-verify /etc/verify.sh via-env

tomato2 

Keys
Certificate Authority: <paste contents of ca.crt>
Server Certificate: <paste contents of server.crt from -----BEGIN CERTIFICATE----- through-----END CERTIFICATE----- inclusive>
Server Key: <paste contents of server.key>
Diffie Hellman parameters: <paste contents of dh1024.pem>

tomato3

All the above OpenVPN configuration options ultimately get stored in NVRAM. Tomato will dynamically generate the appropriate configuration file and keys/certificates in the “/tmp/etc/openvpn”  area based on these NVRAM values.

If you were to SSH/Telnet in to the router, and issue an “nvram show | grep vpn_server1” command, you should see the various configuration values stored in NVRAM from above.

The dynamically constructed files are as follows:

/tmp/etc/openvpn/server1/ [ca.crt | config.ovpn | dh.pem | server.crt | server.key]
/tmp/etc/openvpn/fw/server1-fw.sh

The server1-fw.sh file contains the iptables entries.

tomato generated vpn files

** You will notice the “Advanced” tab > “Custom Configuration” option for the Server VPN Tunnelling is populated with a script-security and auth-user-pass-verify entry.  These options are adding an additional level of security by requiring the VPN client not only hold a valid keypair, but also present a valid username/password.  The client supplied username/password is provided to a custom script (that we must create) named verify.sh.  This script must return exit status 0 in order for the VPN client connection to be successful (assuming they had a valid keypair in the first place).

Unfortunately the /tmp folder is erased and recreated every time the router is rebooted. (/etc is a symbolic link to /tmp/etc).  We need a mechanism to ensure shell scripts for custom authentication survive reboot. There are three options:

1) enable the JFFS feature and essentially leverage the unused portion of the router's NVRAM and turn it in to a mountable and writable space http://tomatousb.org/doc:jffs 

2) leverage init scripts in the tomato UI to recreate the various shell scripts required in the /tmp directory at boot time.

3) use the "nvram setfile2nvram <filename>" command to save small files in nvram.  The files will be automatically restored on start-up.

We will leverage the latter option (#3) for our custom authentication script; SSH/telnet in to the router as root and issue the following:


cd /etc

cat > /etc/generate.sh <<EOF
#!/bin/sh

HASHPASS=\`echo -n "\$1\$2" | md5sum | sed s'/\  -//'\`
i=0
while [ \$i -lt 10 ]; do
  HASHPASS=\`echo -n \$HASHPASS\$HASHPASS | md5sum | sed s'/\  -//'\`
  i=\`expr \$i + 1\`
done
echo \$1:\$HASHPASS
exit 1
EOF

chmod 755 /etc/generate.sh

nvram setfile2nvram /etc/generate.sh

cat > /etc/verify.sh <<EOF
#!/bin/sh
# echo "\${username}"
hash=\`/etc/generate.sh "\${username}" "\${password}"\`

USERS=\`cat /etc/vpnusers\`
for u in \$USERS; do
  test "\${hash}" == "\${u}" && exit 0
done
exit 1
EOF

chmod 755 /etc/verify.sh

nvram setfile2nvram /etc/verify.sh

To generate password hashes for the users (first argument is username, second argument is password):

/etc/generate.sh matt test1234 >> /etc/vpnusers

Persist the vpnusers file:

nvram setfile2nvram /etc/vpnusers

tomato4

To test the verify script:

export username=matt
export password=test1234
/etc/verify.sh
echo $?

If the output is 0 from the above command, the matt/test1234 credential was found in the vpnusers file.  If the output is 1, something is broken!

The hard part is now done. Reboot the router!

 

The final task is creation of the client configuration file and adding the client keypair and CA:

1) Make a directory "config" under "%ProgramFiles%\OpenVPN" if not already present.

2) Within the "config" directory, make a subdirectory, e.g "homevpn"

3) Copy to the "homevpn" directory ca.crt, and the appropriate client keypair (e.g. client_matt.key / client_matt.crt).

4) Within the "config" directory, create an openvpn client config file, e.g. "homevpn.ovpn"; The contents of "homevpn.ovpn" based on the above server configuration above are as follows:


# The hostname/IP and port of the server. You can have multiple remote entries to load balance between the servers.
remote todayguesswhat.dyndns.org 443

# Specify that we are a client and that we will be pulling certain config file directives from the server.
client

ns-cert-type server

# On most systems, the VPN will not function unless you partially or fully disable the firewall for the TUN/TAP interface.
dev tap21

# Are we connecting to a TCP or UDP server?
proto tcp

# Keep trying indefinitely to resolve the host name of the OpenVPN server.  Useful for machines which are not permanently connected to the internet such as laptops.
resolv-retry infinite

# Most clients don't need to bind to a specific local port number.
nobind

# Try to preserve some state across restarts.
persist-key
persist-tun

# --float tells OpenVPN to accept authenticated packets from any address, not only the address which was specified in the --remote option.
# Useful if you're using round-robin DNS.  Also useful if your server has a dynamic IP address which the ISP could change.
# I use float so I can connect from inside AND outside my router.
float

# If the pushed routes appear not to be added on windows hosts, add the following:
# route-delay 30

# SSL/TLS parms.
ca "C:\\Program Files\\OpenVPN\\config\\homevpn\\ca.crt"
cert "C:\\Program Files\\OpenVPN\\config\\homevpn\\client_matt.crt"
key "C:\\Program Files\\OpenVPN\\config\\homevpn\\client_matt.key"

# Enable compression on the VPN link.
# Don't enable this unless it is also
# enabled in the server config file.
comp-lzo

# Set log file verbosity.
verb 3

# Silence repeating messages
mute 20

# prompt for username and password
auth-user-pass

You should hopefully now be able to establish a VPN connection!  Good luck.

Thursday, February 10, 2011

javac – file not found – wildcards and spaces in directory names

Calling the javac command from Windows XP with the source files argument containing a wildcard in quotes – e.g. javac "*.java" will result in the error:

javac: file not found:

Whereas with no quotes – e.g.  javac *.java , no error is produced.

Consider a source files argument containing both a path and wildcard combined  – e.g. javac C:\temp\*.java , this is perfectly fine and no error is produced.

The following however will fail –e.g. javac "C:\my documents\*.java" , due to the wildcard in quotes issue above.

Some may argue that this is perfectly reasonable, given that java does not allow spaces in package names.  But what if the java files above in the “my documents” folder are top-level classes without  package qualification – such as the file below:

e.g.

class Test
{
  public static void main(String[] args)
  {
    System.out.println("Hello World!");
  }
}

Consider a simple java kit that you deliver to folks with the following structure:-

MyApplication\

  bin\compile.bat
  lib\utilities.jar
  lib\resources.jar
  src\com\acme\myapp\Main.java
  src\com\acme\myapp\utils\Utils.java

If the kit above is extracted to some folder/directory without spaces, it should be pretty easy to compile from the command-line. Whereas if it were extracted to the standard Windows desktop location as shown below, more care must be taken:

C:\Documents and Settings\Administrator\Desktop\MyApplication\

  bin\compile.bat
  lib\utilities.jar
  lib\resources.jar
  src\com\acme\myapp\Main.java
  src\com\acme\myapp\utils\Utils.java

One will not be able to run javac "C:\Documents and Settings\Administrator\Desktop\MyApplication\src\com\acme\myapp\*.java" .  They must instead change directory to an appropriate location whereby the javac source files argument can be supplied without including quotes.  For example:

cd /D "C:\Documents and Settings\Administrator\Desktop\MyApplication"
javac src\com\acme\myapp\*.java

Below is a sample windows java compile batch script that I’ve created that should work with the application structure above regardless of what destination directory the kit is extracted to:-

compile.bat

@ECHO off

REM Changes made to an Environment Variable after SETLOCAL has been issued are local to the batch file.
REM Issuing an ENDLOCAL command will restore the previous environment variables.
SETLOCAL

REM Commands
SET JAVACMPCMD=%JAVA_HOME%\bin\javac.exe
SET JARCMD=%JAVA_HOME%\bin\jar.exe

REM library files and source location
SET PROJECT_LIB=%~dp0..\lib
SET PROJECT_SRC=%~dp0..\src
REM source base package path
SET BASE_PKG_PATH=%PROJECT_SRC%\com\acme\myapp

REM classes directory
SET PROJECT_CLASSES=%~dp0..\classes

REM generated library destination path and file
SET DEST_JAR_FILE=%~dp0..\myapp.jar

REM classpath for compilation
SET CP=%PROJECT_LIB%\utilities.jar;%PROJECT_LIB%\resources.jar

REM ************
REM MAIN PROGRAM
REM ************

REM Verify whether required variables are set
IF "%JAVA_HOME%x"=="x" GOTO errjava

REM Preparation ...
IF EXIST "%DEST_JAR_FILE%" DEL /q "%DEST_JAR_FILE%"
IF EXIST "%PROJECT_CLASSES%" RMDIR /s /q "%PROJECT_CLASSES%"
MKDIR "%PROJECT_CLASSES%"

ECHO.
ECHO Compiling code ...

PUSHD "%BASE_PKG_PATH%"
"%JAVACMPCMD%" -target 1.6 -classpath "%CP%" -d "%PROJECT_CLASSES%" *.java utils\*.java
SET ERR=%ERRORLEVEL%
POPD
IF NOT "%ERR%"=="0" GOTO errcomp

ECHO.
ECHO Creating jar file ...

"%JARCMD%" cfM "%DEST_JAR_FILE%" -C "%PROJECT_CLASSES%/" .
IF NOT "%ERRORLEVEL%"=="0" GOTO errjar

REM Cleanup ...
RMDIR /s /q "%PROJECT_CLASSES%"
GOTO end

REM JAVA_HOME is not set
:errjava
ECHO.
ECHO Set the following environment variables:
ECHO.
ECHO JAVA_HOME          (Absolute path to jdk directory)
GOTO end

:errcomp
ECHO.
ECHO Compilation did not succeed.
ECHO Note: If receiving read errors, ensure folder path does not contain whitespace.
GOTO end

:errjar
ECHO.
ECHO Jar creation did not succeed.
GOTO end

:end
ECHO.

 

Saturday, January 8, 2011

vi – range replace – indent block of lines

example 1:

from line 10 through 50, insert two spaces at the start of the line

<esc>:10,50s/^/  /

example 2:

from line 10 through 50, replace the two spaces at the start of the line with empty

<esc>:10,50s/^  //

Wednesday, December 29, 2010

Additional Batch PDFill AutoIt Scripts

Merge all JPG image files in the source directory to a single PDF file in the output directory:

; Script by Matt Shannon - Dec 2010

$srcDirectory = 'C:\Documents and Settings\Administrator\Desktop\source'
$destDirectory = 'C:\Documents and Settings\Administrator\Desktop\output'

; change current directory to src directory
FileChangeDir($srcDirectory)
$search = FileFindFirstFile("*.jpg") 

If $search = -1 Then
  MsgBox(0, "Error", "No files/directories matched the search pattern")
  Exit
EndIf

RunPDFill()

$dest = ''

While 1
  $file = FileFindNextFile($search)
  If @error Then ExitLoop
  ; MsgBox(4096, "File:", $file)

  $dest = StringReplace($file, ".jpg", -1, 0) & ".pdf"

  AddImg($srcDirectory, $file)
 
WEnd

; Close the search handle
FileClose($search)

SaveToPDF($destDirectory, $dest)


Func RunPDFill()

  Run('C:\Program Files\PlotSoft\PDFill\PDFill_PDF_Tools.exe', "", @SW_MAXIMIZE)
  WinWaitActive("[REGEXPTITLE:PDFill PDF Tools 7.0.*]")

  ControlClick("[REGEXPTITLE:PDFill PDF Tools 7.0.*]", "", "[CLASS:Button; TEXT: 9. Convert Images to PDF]")
  WinWaitActive("[TITLE:Free PDF Tools: Convert images to PDF]")

  ; set paper size output to A4
  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:ComboBox; INSTANCE:1]")
  Send("A{ENTER}")

  ; set margins to 0
  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:Edit; INSTANCE:3]")
  Send("{HOME}{SHIFTDOWN}{END}{SHIFTUP}{DEL}0")

  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:Edit; INSTANCE:4]")
  Send("{HOME}{SHIFTDOWN}{END}{SHIFTUP}{DEL}0")

  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:Edit; INSTANCE:5]")
  Send("{HOME}{SHIFTDOWN}{END}{SHIFTUP}{DEL}0")

  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:Edit; INSTANCE:6]")
  Send("{HOME}{SHIFTDOWN}{END}{SHIFTUP}{DEL}0")

EndFunc


Func AddImg($srcdir, $srcfile)

  ; add an image
  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:Button; TEXT:Add an Image]")
  WinWaitActive("[TITLE:Select Image files to add into PDF]")

  ; send image location followed by enter
  ControlClick("[TITLE:Select Image files to add into PDF]", "", "[CLASS:Edit; INSTANCE:1]")
  Send($srcdir & "\" & $srcfile & "{ENTER}")

  ; wait for window to return
  WinWaitActive("[TITLE:Free PDF Tools: Convert images to PDF]")

EndFunc

Func SaveToPDF($destdir, $destfile)

  ; click save-as
  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:Button; TEXT:Save As ...]")
  WinWaitActive("[TITLE:Save all the images as ... ]")

  ; send pdf output location followed by enter
  ControlClick("[TITLE:Save all the images as ... ]", "", "[CLASS:Edit; INSTANCE:1]")
  Send($destdir & "\" & $destfile & "{ENTER}")

  ; wait for adobe to open - and then close it down
  WinWaitActive("[TITLE:" & $destfile & " - Adobe Reader]")
  WinClose("[TITLE:" & $destfile & " - Adobe Reader]")

  ; wait for pdf image tools to return - and then close it down
  WinWaitActive("[TITLE:Free PDF Tools: Convert images to PDF]")
  WinClose("[TITLE:Free PDF Tools: Convert images to PDF]")

  ; wait for main pdf tools to return - and then close it down
  WinWaitActive("[REGEXPTITLE:PDFill PDF Tools 7.0.*]")
  WinClose("[REGEXPTITLE:PDFill PDF Tools 7.0.*]")

EndFunc

 

Merge all PDF files in the source directory to a single PDF file in the output directory:

; Script by Matt Shannon - Dec 2010

$srcDirectory = 'C:\Documents and Settings\Administrator\Desktop\source'
$destDirectory = 'C:\Documents and Settings\Administrator\Desktop\output'

; change current directory to src directory
FileChangeDir($srcDirectory)
$search = FileFindFirstFile("*.pdf") 

If $search = -1 Then
  MsgBox(0, "Error", "No files/directories matched the search pattern")
  Exit
EndIf

RunPDFill()

$dest = ''

While 1
  $file = FileFindNextFile($search)
  If @error Then ExitLoop
  ; MsgBox(4096, "File:", $file)

  $dest = StringReplace($file, ".pdf", -1, 0) & "_merged.pdf"

  AddPdf($srcDirectory, $file)
 
WEnd

; Close the search handle
FileClose($search)

SaveToPDF($destDirectory, $dest)


Func RunPDFill()

  Run('C:\Program Files\PlotSoft\PDFill\PDFill_PDF_Tools.exe', "", @SW_MAXIMIZE)
  WinWaitActive("[REGEXPTITLE:PDFill PDF Tools 7.0.*]")

  ControlClick("[REGEXPTITLE:PDFill PDF Tools 7.0.*]", "", "[CLASS:Button; TEXT: 1. Merge PDF Files]")
  WinWaitActive("[TITLE:Free PDF Tools: Merge PDF Files]")

EndFunc


Func AddPdf($srcdir, $srcfile)

  ; Add a PDF File
  ControlClick("[TITLE:Free PDF Tools: Merge PDF Files]", "", "[CLASS:Button; TEXT:Add a PDF File]")
  WinWaitActive("[TITLE:Add PDF files to be Concated]")

  ; send image location followed by enter
  ControlClick("[TITLE:Add PDF files to be Concated]", "", "[CLASS:Edit; INSTANCE:1]")
  Send($srcdir & "\" & $srcfile & "{ENTER}")

  ; wait for window to return
  WinWaitActive("[TITLE:Free PDF Tools: Merge PDF Files]")

EndFunc

Func SaveToPDF($destdir, $destfile)

  ; click save-as
  ControlClick("[TITLE:Free PDF Tools: Merge PDF Files]", "", "[CLASS:Button; TEXT:Save As ...]")
  WinWaitActive("[TITLE:Save the concated file as ... ]")

  ; send pdf output location followed by enter
  ControlClick("[TITLE:Save the concated file as ... ]", "", "[CLASS:Edit; INSTANCE:1]")
  Send($destdir & "\" & $destfile & "{ENTER}")

  ; wait for adobe to open - and then close it down
  WinWaitActive("[TITLE:" & $destfile & " - Adobe Reader]")
  WinClose("[TITLE:" & $destfile & " - Adobe Reader]")

  ; wait for pdf image tools to return - and then close it down
  WinWaitActive("[TITLE:Free PDF Tools: Merge PDF Files]")
  WinClose("[TITLE:Free PDF Tools: Merge PDF Files]")

  ; wait for main pdf tools to return - and then close it down
  WinWaitActive("[REGEXPTITLE:PDFill PDF Tools 7.0.*]")
  WinClose("[REGEXPTITLE:PDFill PDF Tools 7.0.*]")

EndFunc

Friday, December 24, 2010

Batch Convert Images to PDF using PDFill and AutoIt

I’m in the processing of completely digitalizing my filing cabinet and shredding all but the most important paper-based records. I recently purchased a Canon PIXMA MX870 Multifunction printer/scanner unit purely for its Auto Document Feeder with duplex scanning support. It turns out, the ADF duplex support isn’t all I had hoped with it regularly complaining about paper jams.  This really irritates me Canon! I’m furious actually.

Anyway back to the digital filing cabinet …

I’m leveraging three really cool pieces of software:

  1. FileCenter by Lucion http://lucion.com/filecenter-overview.html
  2. PDFill PDF tools (FREE) by PlotSoft  http://www.pdfill.com/pdf_tools_free.html
  3. AutoIt  http://www.autoitscript.com/autoit3

FileCenter is providing the interface to my new digital filing cabinet providing file management capabilities along with scanning and OCR (optical character recognition) features. It has a number of really useful bells and whistles including smart file (re)naming capabilities that really help with the overall organization of the filing cabinet. The standard edition which I initially purchased (on special now for $50) seems to do its job quite well.  The only downside is the supplied OCR engine is sometimes not up to the task. The FileCenter Pro Plus edition (on special now for $199) ships with an Advanced OCR engine that seems to have a much better job at extracting text from the various scans/images I supply it. I may persist with Standard Edition for a little longer as money is tight – but if Lucion want to give me a free upgrade please contact me :). Lucion provides a 30 day trial of FileCenter Pro Plus with no limitations whatsoever – so check it out. It’s a great piece of software.

PDFill PDF tools are FREE and are without doubt some of the most useful and powerful tools I have ever come across. I use these tools regularly to do things like:

  • Merging PDF files together
  • Reordering pages of PDF files
  • Converting images to PDF
  • Rotating PDF pages

Whilst FileCenter appears to provide many of these capabilities, the level of customization and tweaking that the PDFill PDF tools provide is unmatched. The only downside to these tools is they are all GUI based requiring lots of clicks and user input and don’t appear to provide any command-line based control for doing tasks like batch conversion/processing.

This is where the final piece of software “AutoIt v3” comes in to its own. The guys that wrote this are studs to release it for free.  This tool/scripting language allows one to construct little batch file/shell script like programs that can automatically control and interact with Windows applications without any end-user input required. Thus, I can write a little program for example that simulates mouse clicks and keyboard input from a user.

I have a number a JPG image files that are essentially scans of various paper-based documents that I want to convert to PDF. PDFill provides a tool "Convert Images to PDF" that allows me to manually navigate to the appropriate source image, and then specify the output PDF file along with the PDF output page size / margins / image layout etc etc. This is quite a laborious repetitive task that I decided to automate by using an AutoIT v3 script.

The script essentially searches for JPG files in a particular source directory, then iterates through each image file returned supplying it automatically to the PDFill tool. Appropriate output options / output file etc get set using a combination of automated mouse gestures and keyboard input. Upon conversion completion, the script detects Adobe Reader automatically launching to preview the output and closes it down.

Without further adieu – I give you the automated batched PDFill conversion script :-

; Script by Matt Shannon - Dec 2010

$srcDirectory = 'C:\Documents and Settings\Administrator\Desktop\scans'
$destDirectory = 'C:\Documents and Settings\Administrator\Desktop\output'

; change current directory to src directory
FileChangeDir($srcDirectory)
$search = FileFindFirstFile("*.jpg") 

If $search = -1 Then
  MsgBox(0, "Error", "No files/directories matched the search pattern")
  Exit
EndIf

While 1
  $file = FileFindNextFile($search)
  If @error Then ExitLoop
  ; MsgBox(4096, "File:", $file)

  $dest = StringReplace($file, ".jpg", -1, 0) & ".pdf"

  ConvertToPDF($srcDirectory, $file, $destDirectory, $dest)
 
WEnd

; Close the search handle
FileClose($search)

Func ConvertToPDF($srcdir, $srcfile, $destdir, $destfile)

  Run('C:\Program Files\PlotSoft\PDFill\PDFill_PDF_Tools.exe', "", @SW_MAXIMIZE)
  WinWaitActive("[REGEXPTITLE:PDFill PDF Tools 7.0.*]")

  ControlClick("[REGEXPTITLE:PDFill PDF Tools 7.0.*]", "", "[CLASS:Button; TEXT: 9. Convert Images to PDF]")
  WinWaitActive("[TITLE:Free PDF Tools: Convert images to PDF]")

  ; set paper size output to A4
  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:ComboBox; INSTANCE:1]")
  Send("A{ENTER}")

  ; set margins to 0
  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:Edit; INSTANCE:3]")
  Send("{HOME}{SHIFTDOWN}{END}{SHIFTUP}{DEL}0")

  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:Edit; INSTANCE:4]")
  Send("{HOME}{SHIFTDOWN}{END}{SHIFTUP}{DEL}0")

  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:Edit; INSTANCE:5]")
  Send("{HOME}{SHIFTDOWN}{END}{SHIFTUP}{DEL}0")

  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:Edit; INSTANCE:6]")
  Send("{HOME}{SHIFTDOWN}{END}{SHIFTUP}{DEL}0")

  ; add an image
  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:Button; TEXT:Add an Image]")
  WinWaitActive("[TITLE:Select Image files to add into PDF]")

  ; send image location followed by enter
  ControlClick("[TITLE:Select Image files to add into PDF]", "", "[CLASS:Edit; INSTANCE:1]")
  Send($srcdir & "\" & $srcfile & "{ENTER}")

  ; wait for window to return
  WinWaitActive("[TITLE:Free PDF Tools: Convert images to PDF]")

  ; click save-as
  ControlClick("[TITLE:Free PDF Tools: Convert images to PDF]", "", "[CLASS:Button; TEXT:Save As ...]")
  WinWaitActive("[TITLE:Save all the images as ... ]")

  ; send pdf output location followed by enter
  ControlClick("[TITLE:Save all the images as ... ]", "", "[CLASS:Edit; INSTANCE:1]")
  Send($destdir & "\" & $destfile & "{ENTER}")

  ; wait for adobe to open - and then close it down
  WinWaitActive("[TITLE:" & $destfile & " - Adobe Reader]")
  WinClose("[TITLE:" & $destfile & " - Adobe Reader]")

  ; wait for pdf image tools to return - and then close it down
  WinWaitActive("[TITLE:Free PDF Tools: Convert images to PDF]")
  WinClose("[TITLE:Free PDF Tools: Convert images to PDF]")

  ; wait for main pdf tools to return - and then close it down
  WinWaitActive("[REGEXPTITLE:PDFill PDF Tools 7.0.*]")
  WinClose("[REGEXPTITLE:PDFill PDF Tools 7.0.*]")

EndFunc

Friday, November 26, 2010

I repaired my Lelit Combi PL042QE coffee machine

Today I finally got some free time to look at the Lelit coffee machine. It had stopped working a few weeks back with a complete loss of power. At the time, I remember thinking the machine was extremely hot and suspected the worse.  None of the lights on the front (power etc) would subsequently activate and I was expecting some costly repairs. I sent an email to Alan Frew from coffeeco where the machine was originally purchased (I’m the second owner).  Alan quickly responded with a useful link to his website for steps on troubleshooting:

http://www.coffeeco.com.au/articles/repair.html

Unfortunately, according to Alan’s flow chart “When I turn it on nothing happens” indicates “Your problem is serious. Return your machine for expert service”. 

Anyway, I decided to pull the machine apart (which ultimately takes the removal of just 2 screws), to see if I could spot something visually that could indicate the cause.

Nothing!

Next, I did a search on google for multimeter and Lelit coffee machine to see if someone much smarter than I had done similar troubleshooting in the past.

Nothing!

I finally stumbled on an excellent guide for troubleshooting Rancilio Silvia machines http://www.coffeegeek.com/forums/espresso/machines/312139 which gave me a basis to get started.

BEFORE CONTINUING – ENSURE THE MACHINE IS COMPLETELY DISCONNECTED FROM THE POWER SOURCE

The Lelit that I’m in possession of is fitted with three thermostats:

  1. 95°C thermostat for coffee
  2. 125°C thermostat for steam
  3. 165°C thermostat for safety over-temperature cut-off (red push button)

I first set my cheap $20 DickSmith multimeter to test for continuity. I set test leads on each side of the thermostat (having removed the active (brown)/netural (blue) cables). The buzzer sounded on each thermostat (which for my multimeter indicates the resistance is less than 70Ω). Pulling the little red push button upwards on the 165°C thermostat causes the buzzer to stop indicating an open circuit (which is expected).

Just to be doubly sure that the thermostats appeared to be good (and not measuring more than a few ohms), I set the multimeter to measure resistance.  There is a note in the manual of my multimeter stating to short-circuit the test leads/input terminals before taking measurements where low-resistance precise measurement is required and record the resulting value. The value should then be subtracted from the measurement obtained when testing the particular object in question. Taking the above adjustment in to account, the resistance readings for the 95, 125, and 165 thermostats were 0.1, 0.1, and 1.x ohms respectively – all well within the “few” ohms range. The fact that the 165 thermostat was reading slightly higher had me wondering whether it was possibly bad??

IMG_0163

Next, the Silvia troubleshooting article states to test the heating coil (element) by obtaining a resistance reading across the heater terminals. Once again we remove the connecting cables and perform our test against the bare terminals. The resistance reading across the heater terminals on my machine was 50Ω . Fantastic!!! It thus looks like I hadn’t burned my element out!

At this stage, I decided to give Alan a call suspecting that maybe it was the 165 thermostat that could be the issue.  I provided him the resistance readings from the thermostat and heater, and Alan seemed to think they were fine. He mentioned a few additional troubleshooting steps that I could perform, and also told me a story of how a customer the day before had brought in to the shop a $2000  coffee machine for servicing that had just stopped working. The machine that had died turned out just to have a faulty main power switch.  A faulty power switch I thought – surely that couldn’t be my issue - switches don’t just break. 

Anyway I persisted with my charge that it must be the thermostat and decided to find out if there was a simple way to bypass it to see if the machine would momentarily turn on (to prove the thermostat was the issue!).  It turns out it is as simple as (carefully) just shorting the thermostat’s two terminals with a wire to keep the circuit closed.

I gingerly shorted the two terminals of the thermostat and carefully plugged the machine in to the power source and pushed the main switch.  NOTE – my place is fitted with a residual current device (RDC) – also known as a safety switch.  I would not have attempted this without such a backup.

Nothing!  No lights.  Still broken.

BEFORE CONTINUING – ENSURE THE MACHINE IS COMPLETELY DISCONNECTED FROM THE POWER SOURCE

At this point with nothing to lose and facing the thought of packaging my machine up and getting it serviced by the professionals, I decided to test if the main switch could be the fault.  The switch fitted to the machine is a DPST (double pole, single throw) – meaning two separate circuits are controlled by the switch, and the switch can either be closed (on), or open (off).

I set the multimeter back to continuity and inserted each lead in to the terminals controlling the active circuit (brown wires). The buzzer sounded as I flicked the switch from off to on. So this particular circuit was intact. I next inserted the leads in to the terminals controlling the neutral circuit(blue wires). This time, the buzzer would NOT sound as I repeatedly flicked the switch from on to off (and vice-versa).  Wow – the switch was broken!  Who would have thought?  Maybe Alan had intentionally mentioned this switch thing for a reason (in fact I bet he did!!!).

I decided to set the switch to the on position and remove the neutral connecting leads and manually short them together carefully using a wire. I once again plugged the machine in to the power source. 

LIGHTS – ACTION.

The boiler light came on and a bit of excess water spat out the tubes. It worked!  I quickly disconnected the power source.

BEFORE CONTINUING – ENSURE THE MACHINE IS COMPLETELY DISCONNECTED FROM THE POWER SOURCE

OK – so the broken switch was the reason the machine would not power up. But what had caused the switch to break in the first place? The switch is easily removed by pushing the spring-like clips on the top/bottom of the switch whilst at the same time pushing from the rear so that it pops out the front of the machine. On inspection of the switch terminals, I could see the lower terminal that accepts the incoming neutral (blue) cable from the power source was slightly melted. Why this was, I do not know. The machine had been left on for quite a considerable time (90 minutes or so) without any use. I’ll have to wait and see if the issue reproduces – and if so, get the experts involved.

The rocker switch itself is rated for 16A/250V AC and T120/55 (ambient temperature). Tracking down a replacement DPST switch in Australia with similar specs was proving reasonably tricky.

I found the following rocker switch SCHURTER 1301.9224  (red illumination) that matched the specs perfectly. The green illumination model is 1301.9215.  Farnell (aka element14) sell both switches for about $5 each – but there is a minimum credit card order of $10 required and a 5 day wait. http://au.element14.com

Jaycar also sells a similar switch – although it is a DPDT! http://jaycar.com.au/productView.asp?ID=SK0982

Eager to get my coffee machine back in order, I decided to buy switches from both places.I picked the switch up from Jaycar and installed it, and everything appears to work perfectly. I have also ordered the Schurter 1301.9224 from element14, and if motivated will probably switch the Jaycar out and replace it.

Below is a pic of before and after:

beforeafter

A big thankyou to both Alan Frew from coffeeco, and also Jim Galt (author of troubleshooting Rancilio Silvia post).

Tuesday, November 16, 2010

Example cost of running a Tivo

Tivo apparently draws 24W continuously.

Origin energy here in QLD have a standard tariff of 21.351 cents/kWH

365 days per year * 24 hours per day * .024 KW * .21351 $/kWH (Origin Energy) = $44.88 per year to run.