Programming

Use iptables to monitor network usage.

Posted in Computers, IT, Linux, Programming on February 25th, 2010 by matt – Be the first to comment

Iptables is a powerful firewall/packet filtering framework inside Linux, and obviously used for firewalls on desktop, servers, and even embedded Linux devices such as most home internet routers. I was asked to write a script that could monitor and report network usage on one of our machines at work.

I took on the challenge and after searching package repositories and Google for cool Linux console apps that will report network usage, I came came across the idea of using iptables.. seeing as I love iptables, and it is installed by default on most machines it was the perfect solution for us.

The Idea
Iptables can be thought of a bunch of tables each containing some lists of rules called “chains”. There are some default chains which packets must progress through depending on the packets origin and destination. The main and default table that most people use is the ‘filter’ table, the default chains are:

  • INPUT – Packets coming to the machine from the network.
  • OUTPUT – Packets leaving your machine,
  • FORWARD – Packets passing through your machine, if your machine routes packets.

Each of these chains have a default policy, that is what should happen if there is no rules or no rules matching the packet, this is either:

  • ACCEPT – Allow the packet into the machine.
  • DROP – Drop the packet,

Now the default chains cannot be changed, the packets will work through one of those chains, we can add any rules we want to filter these packets. Netfilter/iptables tracks the amount of data running through chains. So if you want to track all your incoming network usage you can just use the INPUT chain, but if we want to track more specific traffic, we can create a custom chain, add a rule to pass the specific packets to this new chain, and thus monitor the specific traffic! Easy huh!

Before I go into the script and specific iptables configuration I’ll show you readers some useful itptables commands:

  • To see the manual page on iptables: man iptables
  • To list the rules on the default (filter) table: iptables -L
  • To list rules on other tables: iptables -t <tablename> -L

NOTE: If you add a -v you can see packet and byte counts.

Now we move onto what I did.

Network script and setup

I mentioned some iptables commands in the last section, so now I will describe the iptables command I use in the script for reporting:
iptables -L -n -x -v --line-numbers

The options mean:

  • -L = List the rules
  • -n = Do not do a DNS lookup, just show numbers
  • -x = use exact byte values, don’t convert to M or G, this is needed to ease the maths.
  • -v = verbose output, to actually show the counts
  • –line-numbers = The script inserts rules as to not disrupt other iptables rules that it doesn’t control so we need to know the rule number.

With the reporting explained let now talk about how we setup iptables, this is just the theory, the script actually sets it up for you, but as you will have different requirements you’ll need to know

In this example we will only be only worried about monitoring things going through a proxy, which we’ll call 192.168.1.10 and traffic not coming from our local network, not via the proxy (not on 192.168.1.0/24). As the we get the required byte counts from the rule on the INPUT chain, we can use 1 custom chain for both types of traffic. So the first step is to create the custom chain and then add rules to match these packets:

iptables -N DOWNLOADED

Then we add a rule for each of the traffic conditions we want to track:

# Proxy rule
iptables -I INPUT 1 -s 192.168.1.10 -j DOWNLOADED

# Not our network rule
iptables -I INPUT 1 ! -s 192.168.1.0/24 -j DOWNLOADED

The above rules break down like:

  • -I INPUT 1 = Insert into the INPUT chain at index 1 (1 based).
  • -s <ip address or network> = Source is from <ip address>, the ‘!’ means negate (read as ‘not’)
  • -j DOWNLOADED = Jump or push this packet over to the DOWNLOADED chain.

See simple huh… ok maybe not, it is quite easy once you’ve used iptables for a while. Anyway, now that we have iptables set up I can talk about the script.

When ever the machine is rebooted or the chains flushed the counts will be zero’d out again, and as the chains only store the totals we need to keep track of the previous values so we can do a calculation. So I log the entries as three values (columns) separated by tabs:

date proxy bytes non-network bytes

The report I then generate says to usage since last check and current total, but the current total since when? In stead of having to parse the file since the last flush/reboot I simply have another file storing the last run with the following structure, similar to the log but containing the date of the last reset.

date proxy bytes non-network bytes total start date

Anyway without further adieu I’ll now present my script, it contains the reporting, and I have my own function that makes the report counts human readable:

#!/usr/bin/env python

import sys
import os
import datetime
from send_email import send_email

# Global Variables
PROXY = "192.168.1.10"
NETWORK = "192.168.1.0/24"

IPTABLES_CUSTOM_CHAIN = "DOWNLOADED"
IPTABLES_CREATE_CHAIN = "iptables -N " + IPTABLES_CUSTOM_CHAIN
IPTABLES_DELETE_CHAIN = "iptables -X " + IPTABLES_CUSTOM_CHAIN
IPTABLES_PROXY_RULE = "INPUT %s -s " + PROXY + " -j " + IPTABLES_CUSTOM_CHAIN
IPTABLES_NOT_NETWORK_RULE = "INPUT %s ! -s " + NETWORK + " -j " + IPTABLES_CUSTOM_CHAIN

IPTABLES_REPORT_CMD = "iptables -L -n -x -v --line-numbers"

# Result column indexes
TIMESTAMP_IDX = 0
PROXY_IDX = 1
NOT_NETWORK_IDX = 2
TOTAL_START_IDX = 3

# Format of the folling files: date     proxy bytes     non-network bytes
# NOTE: Seperated by tabs (\t)
LAST_RESULT = "/home/dpadmin/matt/bin/netmon.last"
RESULT_LOG = "/home/dpadmin/matt/bin/netmon.log"

# Email reporting variables
EMAIL_TO = ['email@address.goes.here']
EMAIL_FROM = 'email.from@address.goes.here'
EMAIL_SUBJECT = 'Network Usage Report - %s'
EMAIL_ATTACHMENTS = []
EMAIL_SERVER = 'localhost'
EMAIL_MSG = """Network usage between: %s and %s

Proxy Traffic:
  Usage: %s
  Current Total: %s

Non Network Traffic:
  Usage: %s
  Current Total: %s

Total since: %s
"""

def human_readable(bytes):
        if bytes < 1024:
                return str(bytes)
        for x in 'K', 'M','G':
                bytes /= 1024.0
                if bytes < 1024:
                        return "%.2f%s" % (bytes, x)
        if bytes > 1024:
                return "%.2f%s" % (bytes, 'G')

def make_human_readable(results):
        return (results[0], human_readable(results[1]), human_readable(results[2]))

def get_totals():
        timestamp = generate_timestamp()
        result = os.popen(IPTABLES_REPORT_CMD)
        proxy_bytes = 0
        network_bytes = 0

        # Parse the output.
        # 1. Find "Chain INPUT" that way we know we have the right chain.
        # 2. Look for 1 and 2 in the first column, as they are our rules.
        # 3. Find out which one is the proxy one.
        # 4. return totals.
        start = False
        for line in result:
                if line.startswith("Chain INPUT"):
                        start = True
                elif line.startswith("Chain"):
                        start = False
                elif start:
                        cols = line.split()
                        if len(cols) != 0:
                                if cols[0] == '1' or cols[0] == '2':
                                        # Found our rules
                                        if cols[8] == PROXY:
                                                proxy_bytes = int(cols[2])
                                        else:
                                                network_bytes = int(cols[2])

        return (timestamp, proxy_bytes, network_bytes)

def generate_timestamp():
        d = datetime.datetime.now()
        datestr = "%d/%.2d/%.2d-%.2d:%.2d:%.2d" % (d.year, d.month, d.day, d.hour, d.minute, d.second)
        return datestr

def get_last():
        if os.path.exists(LAST_RESULT):
                lstFile = file(LAST_RESULT).readlines()
                result = lstFile[0].strip().split()
                result[PROXY_IDX] = int(result[PROXY_IDX])
                result[NOT_NETWORK_IDX] = int(result[NOT_NETWORK_IDX])
                return tuple(result)
        else:
                timestamp = generate_timestamp()
                return (timestamp, 0, 0, timestamp)

def _cleanup_iptables():
        os.system("iptables -D %s" % (IPTABLES_PROXY_RULE % ("")))
        os.system("iptables -D %s" % (IPTABLES_NOT_NETWORK_RULE % ("")))
        os.system(IPTABLES_DELETE_CHAIN)

def start():
        # Incase the rules alread exist lets remove them
        _cleanup_iptables()

        # Now we can add them
        os.system(IPTABLES_CREATE_CHAIN)
        os.system("iptables -I %s" % (IPTABLES_PROXY_RULE % ("1")))
        os.system("iptables -I %s" % (IPTABLES_NOT_NETWORK_RULE % ("1")))

def stop():
        # Delete the rules TOTAL_START_IDX
        _cleanup_iptables()

def report():
        last = get_last()

        # Now we need to get the byte totals from iptables.
        new_totals = get_totals()

        reset_detected = False
        proxy_usage = 0
        not_network_usage = 0
        total_start = last[TOTAL_START_IDX]
        if last[PROXY_IDX] > new_totals[PROXY_IDX]:
                # Counters must have been reset.
                reset_detected = True
                proxy_usage = new_totals[PROXT_IDX]
                not_network_usage = new_totals[NOT_NETWORK_IDX]
                total_start = new_totals[TIMESTAMP_IDX]
        else:
                # Do the calc
                proxy_usage = new_totals[PROXY_IDX] - last[PROXY_IDX]
                not_network_usage = new_totals[NOT_NETWORK_IDX] - last[NOT_NETWORK_IDX]

        result = (new_totals[TIMESTAMP_IDX],proxy_usage, not_network_usage)
        result_str = "Timestamp: %s Proxied: %s Off Network: %s"

        # Write out the new last totals to the log and last.
        last_file = file(LAST_RESULT, 'w')
        tmp_list = []
        tmp_list.extend(new_totals)
        tmp_list.append(total_start)
        last_file.write("%s\t%d\t%d\t%s\n" % tuple(tmp_list))
        last_file.close()

        log = file(RESULT_LOG, 'a')
        log.write("%s\t%d\t%d\n" % new_totals)
        log.close()

        last = make_human_readable(last)
        new_totals = make_human_readable(new_totals)
        result = make_human_readable(result)

        print "Last Total - " + result_str % last
        print "New Total - " + result_str % new_totals
        print "New Usage - " + result_str % result

        if reset_detected:
                msg = " == RESET DETECTED! == \n"
        else:
                msg = ""

        # Send the email report
        msg += EMAIL_MSG % (last[TIMESTAMP_IDX],result[TIMESTAMP_IDX], result[PROXY_IDX], new_totals[PROXY_IDX], result[NOT_NETWORK_IDX], new_totals[NOT_NETWORK_IDX], total_start)
        send_email(EMAIL_FROM, EMAIL_TO, EMAIL_SUBJECT % (result[TIMESTAMP_IDX]), msg, EMAIL_ATTACHMENTS, EMAIL_SERVER)

def main(args):
        if len(args) == 0:
                # Run report
                report()
        elif str(args[0]).upper() == "CLEAR":
                stop()
        elif str(args[0]).upper() == "FLUSH":
                stop()
        elif str(args[0]).upper() == "STOP":
                stop()
        elif str(args[0]).upper() == "INITIATE":
                start()
        elif str(args[0]).upper() == "START":
                start()
        elif str(args[0]).upper() == "INITIALISE":
                start()
        elif str(args[0]).upper() == "REPORT":
                report()

if __name__ == "__main__":
        main(sys.argv[1:])

The send email code looks like:

import smtplib
import os
from email.MIMEMultipart import MIMEMultipart
from email.MIMEBase import MIMEBase
from email.MIMEText import MIMEText
from email.Utils import COMMASPACE, formatdate
from email import Encoders

def send_email(send_from, send_to, subject, text, files=[], server="localhost"):
  assert type(send_to)==list
  assert type(files)==list

  msg = MIMEMultipart()
  msg['From'] = send_from
  msg['To'] = COMMASPACE.join(send_to)
  msg['Date'] = formatdate(localtime=True)
  msg['Subject'] = subject

  msg.attach( MIMEText(text) )

  for f in files:
    part = MIMEBase('application', "octet-stream")
    part.set_payload( open(f,"rb").read() )
    Encoders.encode_base64(part)
    part.add_header('Content-Disposition', 'attachment; filename="%s"' % os.path.basename(f))
    msg.attach(part)

  smtp = smtplib.SMTP(server)
  smtp.sendmail(send_from, send_to, msg.as_string())
  smtp.close()

The script will setup the iptables setup by:

network_monitor.py start
network_monitor.py initiate
network_monitor.py initialise

To clean up iptables:

network_monitor.py clear
network_monitor.py flush
network_monitor.py stop

and finally to report:

network_monitor.py report
network_monitor.py

If you wish to graph the log then using higher and higher totals might not be what you want, so here is another script which parses the totals log and turns each entry into the daily usage, in MB, rather then totals:

#!/usr/bin/env python

import sys
import os

OUT_FILE = "netmon_graph.dat"

def main(netmon_log):
        if not os.path.exists(netmon_log):
                print "Error %s doesn't exist!" % (netmon_log)
                sys.exit(1)

        inFile = file(netmon_log)
        outFile = file(OUT_FILE, 'w')

        outFile.write("%s\t%s\t%s\n" % ("Date", "Proxy", "Non-Network"))

        line = inFile.readline()
        lastProxyValue = 0
        lastNetValue = 0
        while len(line) > 0:
                #process
                cols = line.strip().split()
                if len(cols) == 3:
                        date = cols[0]
                        proxy = long(cols[1])
                        net = long(cols[2])

                        if proxy < lastProxyValue or net < lastNetValue:
                                lastProxyValue = 0
                                lastNetValue = 0

                        # Calc
                        newProxy = proxy - lastProxyValue
                        newNet = net - lastNetValue

                        lastProxyValue = proxy
                        lastNetValue = net

                        # Convert to MBs
                        newProxy = float(newProxy) / 1024.0 / 1024.0
                        newNet = float(newNet) / 1024.0 / 1024.0

                        outFile.write("%s\t%.2f\t%.2f\n" % (date, newProxy, newNet))

                line = inFile.readline()

        inFile.close()
        outFile.close()

if __name__ == "__main__":
        main(sys.argv[1])

Happy network monitoring!

Backup your iphone SMS’s as a conversation transcript.

Posted in Computers, IT, Programming on February 4th, 2010 by matt – 1 Comment

At the point in writing there aren’t many ways of backing up your SMS’s from your iPhone, but you do a system backup when you sync with itunes but what if you want your SMS conversions backed up as a simple non proprietary format? Well the answer is here!

Shea recently upgraded to an iPhone, and was having trouble with bluetoothing the data across from her old phone. She told me she had saved the most important SMS’s but was a shame to loose the record of our entire SMS communication history.
And she’s right, in today’s world where everything is digital a lot of important relationship related stuff was discussed and it would be a shame to loose it all. So I started googling, at first I thought it would be a feature of itunes.. i was wrong.. which is a shame. But it turns out people have done it before, and some applications where written to do just that, unfortunately though all report that they only work for the iphone OS version 2.0. Sure it would be alot easier if the phone was jail broken, but there must be an easier way.. and there is!

Step 1 – Extract the SMS database from one of your iPhone backups:

I came across this OSX app, I’m not sure if there is a windows equivalent but seeing as I sync my iPhone under OSX I don’t really care.
Anyway this app allows you to access one of your iPhone backups and extract parts of it. For this post we are only interested in the SMS’s so once you have chosen a backup from the list scroll to the bottom and extract “System Files” or “Other Files” (can’t remember the name will check when I get home).

You’ll be prompted for a location to extract to, I suggest you extract the contents to an empty folder.
Once the files have been extracted you should find a sms.db file under:

<extracted folder>/System Files/Library/SMS/sms.db

This sms.db turns out to be a sqlite file.. and for those in the know, know that this is good news! With a few lines of python we can access and extract what we need from the file, but first we need to find the structure, which leads us to step 2.

Step 2 – Determine the sms.db table internal table structure.

There are many sqlite applications, but I’ll point you to 2 of them. A OSX app and a Linux app.
For OSX there is  sqlitebrowser and for Linux I simply used sqliteman which to install is as simple as:
For Debian/Ubuntu:

apt-get install sqliteman

For Fedora:

yum install sqliteman

Now inside the sms.db file there turns out to be 5 tables:

_sqlitedatabaseproperties
group_member
message
msg_group
msg_peices

All actual SMS text are stored in the ‘message’ table, and as the conversion I needed to backup was a simple 1 on 1 conversation all I needed was to query this one table.
While we are here what’s the structure of the ‘message’ table, well there are 17 columns but the only ones that I required where address, date, text and flags.

  • address – Is the number of the person you were having the SMS communication with.
  • date – Date of the text in epoch format.
  • text – The text itself.
  • flags – numerical flags attached to the message, but just looking at the table I realised that if the flag field contained a 2 then the text was from the recipient, a 3 indicated it was send from you.

With all that information I was ready to write my simple script, which leads to step 3.

Step 3 – The basic script

This python script does need some work, I only wrote it as a once off, so adding more exception handling and passing in the main parameters into the script rather then using variables would be useful, but outside the scope.

It is also worth a mention that I am using python 2.6 and it does also require the sqlite module, under fedora it is as simple as:

yum install python-sqlite2

Note: Yes its the 2nd version of the python sqlite module, but is actually supports sqlite version 3, so inside python you ‘import sqlite3′ so it actually is the sqlite3 module.

Now for the script, don’t forget to change the <data place holders> with the data you require:

#!/usr/bin/env python                                                                                                                                        

import sqlite3
import time
import sys
import os
import codecs 

DEBUG = True
names = {'2' : "<Recipient>", '3': "<your self>"}
key = "<number>"               

SQL = "select flags, address, date, text from message where address = '%s'"

output = """%s - %s
        %s         

"""

def getDate(epoch):
        return time.strftime("%a, %d %b %Y %H:%M:%S",time.localtime(epoch))

def main(dbfile, outputfile):
        outFile = codecs.open(outputfile, encoding='utf-8', mode='w')

        conn = sqlite3.connect(dbfile)
        c = conn.cursor()
        c.execute(SQL % (key))

        count = 0
        firstDate = ""
        lastDate = ""

        for row in c:
                flags = str(row[0])
                for name in names.keys():
                        if name in flags:
                                user = names[name]
                date = getDate(row[2])
                text = unicode(row[3])

                outStr = output % (user, date, text)

                if DEBUG:
                        print outStr

                outFile.write(outStr)

                # Store the first Date
                if count == 0:
                        firstDate = date
                lastDate = date
                count += 1
        outStr = "Date Range: %s - %s" % (firstDate, lastDate)
        if DEBUG:
                print outStr

        outFile.write(outStr)
        outFile.close()

if __name__ == "__main__":
        if len(sys.argv) < 3:
                print "%s  " % (sys.argv[0])
                sys.exit(1)

        dbfile = sys.argv[1]
        outFile = sys.argv[2]

        if not os.path.exists(dbfile):
                print "%s doesn't exist" % (dbfile)
                sys.exit(1)

        main(dbfile, outFile)

This creates a transcript like:

Matt - Mon, 04 Feb 2010 08:01:38
This is a text message

Other Person - Mon, 04 Feb 2010 08:02:38
This is the response.

Anyway happy backing up!
Needless to say I believe Shea was happy :)

MySQL Datetime precision… I think not!

Posted in Computers, IT, Programming on December 24th, 2009 by matt – Be the first to comment

We use Hibernate at work, and I’ve been working on getting all our JUnit tests to work on MySQL… Yes hibernate takes care of most of that, and it does, BUT some of our unit tests were failing when I pointed it at MySQL rather then PostgreSQL.

After some debugging I noticed that when we pulled one of our objects out of the database via hibernate, the Date object inside wasn’t the same as the Date inserted:
originalDate.getTime(); // = 1261613807262
retrievedDate.getTime(); // = 1261613807000

The two epoch dates are almost the same, except the last three digits are zero’d out. The keen observers might have already figured out these are microseconds.
It seems MySQL isn’t storing or retrieving the microseconds from the datetime datatype.  Even though MySQL does have the MICROSECOND() function. A quick search on Google supports my findings there is a “Feature Request” opened on the MySQL bug tracker, annoyingly though it was opened on 15 Feb 2005, yet nothing is yet implemented.

For those who want to get around this issue, and want to Assert the dates, and want them to actually work, you simply need to zero out the microseconds component of the date, here is the simple function I used:
private Date removeMicroseconds(Date date) {
return new Date(date.getTime() - (date.getTime() % 1000));
}

Installing Sun Java on Fedora 12

Posted in Computers, IT, Linux, Programming on December 8th, 2009 by matt – 3 Comments

By default Fedora 12 doesn’t install Sun’s Java, and it isn’t in the repository. This isn’t a mistake, in fact I think this is a good decision! Fedora is only dealing with free open source software. You can add other repositories to give you the extra non OSS software you want, for those who cannot live without certain software.

Fedora uses the OpenJDK, which I think is awesome.. but unfortunately as I am a Java developer at the moment, and it seems some of the software I work requires the Sun version of Java, at least to compile.

So I needed to install Sun JDK on my 64bit machine.. this is how I did it:

  1. Download the Sun Java JDK 64bit Linux bin installer.
  2. Run it to install.
  3. Even though I ran it as root it installed in the current folder. So move the folder to we it should be installed:
    sudo cp -a jdk1.6.0_16 /usr/lib/jvm/
  4. Use the alternatives command to tell Fedora to use the new Java binary, to do so we need to “install” the new binary as an option in alternatives:
    sudo /usr/sbin/alternatives --install /usr/bin/java java /usr/lib/jvm/jdk1.6.0_16/bin/java 20000
    Then use alternatives and make sure our new binary is selected:
    sudo /usr/sbin/alternatives --config java
  5. Use the following command to verify that Fedora is pointing to the right binary:
    java -version

That’s it, Sun’s Java should now be installed!

Eclipse @author

Posted in Computers, IT, Programming on October 15th, 2009 by matt – Be the first to comment

Most Java developers know eclipse is an awesome IDE, it’s customisation and auto-completeness is great.. It even auto completes annotations in the code far ya.

When added a @author annotation to some code, it’ll automatically try and add your name.. which is great, but it uses your logon name, not my real name. It’s not that big a deal, cause retyping your name is easy!

But curiosity got the better of me, I wanted to know if there was a place you can set the author name correctly.. and there is! When starting eclipse you can pass in an option:
eclipse -Duser.name=Matthew Oliver

But most people want to run eclipse from the menu, sure you can update the menu item, but there is another way. In the eclipse installation directory there is an eclipse.ini file, just append -Duser.name=<name> and that’s it.

For those of you following along at home, or those of you who are sysadmins, may realise that is a major problem.. can you figure it out?

By setting the user.name in the ini file, you forcing the user.name for everyone who uses eclipse on that machine, if there is only one person then there is no problem, but if there’s more however…

Maybe editing the menu item is better after all ;) or maybe there is an eclipse.ini file under ~/.eclipse somewhere!! Who knows.

Bash autocompletion + Java

Posted in Computers, IT, Linux, Programming on August 25th, 2009 by matt – Be the first to comment

I think the title says it all, I was just checking something at work and needed to run one of our Java apps using the command line, I did the standard:
java -cp jarfile1.jar:jarfile2.jar au.gov.

and hit tab key twice out of habit and to my surprise bash had checked the jar files inside the command I was writing and presented me with all the class options!!

Bash auto completion just continues to impress me! Thank you bash, you have just made my life SO much easier yet again.

For those of you who have no idea what bash is, its a terminal shell used by default in Linux.. so for those of you out there not yet using Linux, here is yet another reason to do so.

OSX also uses bash as the default shell for the terminal, so I’ll now have to test it on my macbook.. after a quick test the answer is no, OSX is either using an older version of bash which doesn’t support this feature, or hasn’t turned on/set up all the autocompletion features by default.

Ant vs Proxy

Posted in Computers, IT, Linux, Programming on June 23rd, 2009 by matt – Be the first to comment

I’ve been updating our ant build scripts to compile all our third party library’s from source for two reasons:

  1. So we don’t keep binary blobs under CVS, and
  2. So it is easy to distribute the source of the libraries we use.

Ant is a very powerful build system, and everything was moving along swimmingly until I was working on calling the JavaHelp build script, which is nice and smart, but it’ll seem too smart for it’s own good! It automatically downloads its dependencies for you, the only problem is at work we are stuck behind a very annoying web proxy.

But never fear ant came to the rescue! Ant allows you to put a <setproxy .. /> tag into your build script to set a proxy, yay!!

BUT…

Can anyone see a problem here? When we are working on build scripts for some open source apps we write here at work, then adding the proxy to the script is good and fine here, but it WILL break for all users out in the big wide world who use our software… if only there was an easier way.

I talked to Chris and he came solution… one that I should have thought of myself, environment variables!

Ant checks an evironment variable called ANT_OPTS for, strangely enough, ant options. To set the proxy settings:

export ANT_OPTS="-Dhttp.proxyHost=localhost -Dhttp.proxyPort=5865 -Dhttps.proxyHost=localhost -Dhttps.proxyPort=5865"

NOTE: Change localhost and the port to the port of your proxy server.

JVMs have a GPL’d implementation of the JavaMail API thanks to GNU!

Posted in Linux, Programming on June 12th, 2009 by matt – Be the first to comment

This has been around for a while, but I’ve only just stumbled across this as I have been looking at into the licensing of some 3rd party jars we use at work.

GNU have a free implementation of the Sun JavaMail API specification, which means we now have some more GPL’d jars we can use.

So lets build em!
First we need to download all the source:

wget http://ftp.gnu.org/gnu/classpathx/activation-1.1.1.tar.gz
wget http://ftp.gnu.org/gnu/classpath/inetlib-1.1.1.tar.gz
wget http://ftp.gnu.org/gnu/classpathx/mail-1.1.2.tar.gz
NOTE: The above links are on the javamail link above, so you can just download it from there!

Extract and start building.. as an example I’ll just use the ‘/tmp’ directory, remember to change this to your desired location.

tar -xvf activation-1.1.1.tar.gz
tar -xvf inetlib-1.1.1.tar.gz
tar -xvf mail-1.1.2.tar.gz

We need to build activation.jar and inetlib.jar first as they are dependancies of the GNU mail api.

First build activation.jar:

cd activation-1.1.1/
./configure
make
cd ..

Then build inetlib.jar:

cd inetlib-1.1.1/
./configure
make
cd ..

Now with those jars built we need to build the gnumail jars:

cd mail-1.1.2/
./configure --with-activation-jar=/tmp/activation-1.1.1/ --with-inetlib-jar=/tmp/inetlib-1.1.1/
make
cd ..

Lets move all the Jar files into /tmp so I can show you them all:

cp activation-1.1.1/*.jar .
cp inetlib-1.1.1/*.jar .
cp mail-1.1.2/*.jar .

ws -l *.jar
-rw-r–r– 1 matt matt 44375 2009-06-12 15:53 activation.jar
-rw-r–r– 1 matt matt 163942 2009-06-12 15:54 gnumail.jar
-rw-r–r– 1 matt matt 95250 2009-06-12 15:54 gnumail-providers.jar
-rw-r–r– 1 matt matt 182002 2009-06-12 15:53 inetlib.jar

Now just put them in your Java path and away you go!

Happy GNU Java’n