<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>

<channel>
	<title>Inode Ltd</title>
	<atom:link href="http://inode.co.nz/feed/" rel="self" type="application/rss+xml" />
	<link>http://inode.co.nz</link>
	<description>Internet, Linux, Security Consultancy &#38; Services</description>
	<pubDate>Tue, 03 Apr 2012 02:53:23 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5.1</generator>
	<language>en</language>
			<item>
		<title>Configuring an Android with MITMproxy</title>
		<link>http://inode.co.nz/configuring-an-android-with-mitmproxy</link>
		<comments>http://inode.co.nz/configuring-an-android-with-mitmproxy#comments</comments>
		<pubDate>Mon, 02 Apr 2012 23:36:16 +0000</pubDate>
		<dc:creator>jim</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<category><![CDATA[mitmproxy]]></category>

		<guid isPermaLink="false">http://inode.co.nz/?p=85</guid>
		<description><![CDATA[In this post, I&#8217;ll describe how to set up an Android machine (in this case, an Asus Transformer Prime TF201 with Android 4.0.3) to proxy HTTP/HTTPS requests via a MITMproxy instance on a separate machine.
Android doesn&#8217;t provide a facility to use a proxy server at the OS level;
individual applications may support a proxy if they [...]]]></description>
			<content:encoded><![CDATA[<p>In this post, I&#8217;ll describe how to set up an Android machine (in this case, an Asus Transformer Prime TF201 with Android 4.0.3) to proxy HTTP/HTTPS requests via a <a href="http://mitmproxy.org/">MITMproxy</a> instance on a separate machine.</p>
<p>Android doesn&#8217;t provide a facility to use a proxy server at the OS level;<br />
individual applications may support a proxy if they choose, but I haven&#8217;t<br />
seen one so far that does. This is a long-standing flaw in the OS and has<br />
been effectively ignored since 2008.<br />
<a href="http://code.google.com/p/android/issues/detail?id=1273">http://code.google.com/p/android/issues/detail?id=1273</a></p>
<p>The only currently viable solution is to use the kernel firewall to<br />
implement a transparent proxy, and there are plenty of apps around to sort<br />
out the details. Of course, you need to Root your Android first. Go and do<br />
that now &#8230;</p>
<p>In order to set up the transparent proxying, ProxyDroid is available from the Google Play store, and is just fine for our purpose. Grab it from<br />
<a href="https://play.google.com/store/apps/details?id=org.proxydroid">https://play.google.com/store/apps/details?id=org.proxydroid</a><br />
<a href='http://inode.co.nz/wp-uploads/proxydroidinstall.png'><img src="http://inode.co.nz/wp-uploads/proxydroidinstall-300x187.png" alt="Installing ProxyDroid from the Google Play store" title="ProxyDroid - install" width="300" height="187" class="alignnone size-medium wp-image-86" /></a></p>
<p>As you start ProxyDroid, you should get a Superuser access request. You<br />
will need to Allow the access in order to proceed meaningfully.<br />
<a href='http://inode.co.nz/wp-uploads/proxydroidsuperuser.png'><img src="http://inode.co.nz/wp-uploads/proxydroidsuperuser-300x187.png" alt="Grant Superuser access to the ProxyDroid application" title="ProxyDroid - superuser access" width="300" height="187" class="alignnone size-medium wp-image-87" /></a></p>
<p>Have a look through the settings: the ones we are concerned with are in<br />
the &#8220;Proxy Settings&#8221; section, &#8220;Host&#8221; and &#8220;Port&#8221;. The Proxy Type is HTTP.<br />
Set up the location of your mitmproxy instance in the Host and Port<br />
fields.<br />
<a href='http://inode.co.nz/wp-uploads/proxydroidsettingsdefault.png'><img src="http://inode.co.nz/wp-uploads/proxydroidsettingsdefault-300x187.png" alt="Default settings on the ProxyDroid app" title="ProxyDroid - default settings" width="300" height="187" class="alignnone size-medium wp-image-88" /></a><br />
<a href='http://inode.co.nz/wp-uploads/proxydroidsettings.png'><img src="http://inode.co.nz/wp-uploads/proxydroidsettings-300x187.png" alt="Settings for MITMproxy - specify the Host and Port" title="ProxyDroid - Settings for MITMproxy" width="300" height="187" class="alignnone size-medium wp-image-89" /></a></p>
<p>Before we enable the proxy, take the opportunity to look at your iptables<br />
firewall settings. I&#8217;d expect them to be basically empty.<br />
<a href='http://inode.co.nz/wp-uploads/shelldefaultiptables.png'><img src="http://inode.co.nz/wp-uploads/shelldefaultiptables-300x187.png" alt="Default Android iptables settings" title="Shell - default iptables" width="300" height="187" class="alignnone size-medium wp-image-90" /></a></p>
<p>After enabling the proxy, you should see some redirects in the NAT OUTPUT<br />
table, and netstat will confirm that there is a process listening on ports<br />
8123 and 8124. Sadly the version of lsof that came with my<br />
busybox/terminal emulator isn&#8217;t up to the job of proving that it is<br />
ProxyDroid on there, but practical experimentation seems to confirm it.<br />
<a href='http://inode.co.nz/wp-uploads/proxydroidenabled.png'><img src="http://inode.co.nz/wp-uploads/proxydroidenabled-300x187.png" alt="ProxyDroid is now enabled ..." title="ProxyDroid - enabled" width="300" height="187" class="alignnone size-medium wp-image-91" /></a><br />
<a href='http://inode.co.nz/wp-uploads/shelliptablesnetstatpd.png'><img src="http://inode.co.nz/wp-uploads/shelliptablesnetstatpd-300x187.png" alt="ProxyDroid visible via iptables and netstat" title="Shell - iptables and netstat showing ProxyDroid" width="300" height="187" class="alignnone size-medium wp-image-92" /></a></p>
<p>Now we can start up mitmproxy. As we need transparent proxy support, make<br />
sure you are on v0.8 (currently available via git only, will be released fully soon) and using the <code>--upstream-cert</code> flag.</p>
<p>A short test with wget confirms that web requests still work (note the<br />
cloud icon in the notification bar that indicated ProxyDroid is active)<br />
and at the mitmproxy end we see the matching transaction.<br />
<a href='http://inode.co.nz/wp-uploads/shellwgethttpgoogle.png'><img src="http://inode.co.nz/wp-uploads/shellwgethttpgoogle-300x187.png" alt="Standard HTTP wget works with ProxyDroid/mitmproxy" title="Shell - wget http://google.com/" width="300" height="187" class="alignnone size-medium wp-image-93" /></a></p>
<pre>
&gt;&gt; GET http://google.com/
 ← 301 text/html 219B
   GET http://www.google.com/
 ← 302 text/html 221B
   GET http://www.google.co.nz/
 ← 200 text/html 11.16kB
</pre>
<p>Again, Android disappoints with standard tool support because the busybox<br />
wget I have doesn&#8217;t do HTTPS. Time to move up to a browser.</p>
<p>Trying to grab https://google.com/ results in an error &#8212; &#8220;There are problems<br />
with the security certificate for this site.&#8221; That&#8217;s great; the Android has no<br />
idea about the CA Certificate that mitmproxy should be using.<br />
<a href='http://inode.co.nz/wp-uploads/googleviaproxydroidmitmnocawarning.png'><img src="http://inode.co.nz/wp-uploads/googleviaproxydroidmitmnocawarning-300x187.png" alt="By default, the mitmproxy CA is unknown" title="MITM - warning of unknown CA" width="300" height="187" class="alignnone size-medium wp-image-94" /></a><br />
<a href='http://inode.co.nz/wp-uploads/googleviaproxydroidmitmnocauntrusted.png'><img src="http://inode.co.nz/wp-uploads/googleviaproxydroidmitmnocauntrusted-300x187.png" alt="Details of the untrusted site certificate" title="MITM - untrusted certificate details" width="300" height="187" class="alignnone size-medium wp-image-95" /></a></p>
<p>Time to transfer the current mitmproxy CA Certificate over to the Android.<br />
You probably should switch off the ProxyDroid during this!<br />
I&#8217;ll share mine using the short script &#8216;woof&#8217;<br />
(<a href="http://www.home.unix-ag.org/simon/woof.html">http://www.home.unix-ag.org/simon/woof.html</a>, packed for Debian) and grab it with the web browser.<br />
Although the file is suffixed &#8220;.pem&#8221; in mitmproxy, it will need to be a<br />
&#8220;.cer&#8221; on the Android.</p>
<pre>
$ cd ~/.mitmproxy
$ woof -p 8000 mitmproxy-ca-cert.pem
---
android$ wget http://maru.otago.ac.nz:8000/mitmptoxy-ca.cer
</pre>
<p><a href='http://inode.co.nz/wp-uploads/shellwgetmitmproxyca.png'><img src="http://inode.co.nz/wp-uploads/shellwgetmitmproxyca-300x187.png" alt="Download the mitmproxy CA cert" title="Shell - wget the mitmproxy CA cert" width="300" height="187" class="alignnone size-medium wp-image-96" /></a></p>
<p>Now we have the cert on local disk, we need to import it to the list of<br />
trusted CAs. I go to Settings/Security/Credential Storage, and select<br />
&#8220;Install from storage&#8221;. The certificate in /sdcard/Downloads is<br />
automatically located and offered for installation. Installing the cert will delete the download file from the local disk.<br />
<a href='http://inode.co.nz/wp-uploads/settingssecuritymenu.png'><img src="http://inode.co.nz/wp-uploads/settingssecuritymenu-300x187.png" alt="Menu from the Settings / Security tab" title="Settings / Security - menu" width="300" height="187" class="alignnone size-medium wp-image-97" /></a><br />
<a href='http://inode.co.nz/wp-uploads/settingssecurityinstallca.png'><img src="http://inode.co.nz/wp-uploads/settingssecurityinstallca-300x187.png" alt="Settings / Security / Install from Storage" title="Settings / Security / Install from Storage" width="300" height="187" class="alignnone size-medium wp-image-98" /></a><br />
<a href='http://inode.co.nz/wp-uploads/settingssecurityuserinstalledca.png'><img src="http://inode.co.nz/wp-uploads/settingssecurityuserinstalledca-300x187.png" alt="Settings / Security / Trusted credentials / Security certificate" title="Settings / Security / Trusted credentials / Security certificate" width="300" height="187" class="alignnone size-medium wp-image-100" /></a><br />
<a href='http://inode.co.nz/wp-uploads/settingssecurityviewca.png'><img src="http://inode.co.nz/wp-uploads/settingssecurityviewca-300x187.png" alt="Settings / Security / Trusted credentials" title="Settings / Security / Trusted credentials" width="300" height="187" class="alignnone size-medium wp-image-99" /></a></p>
<p>At this point, Android 4.0.3 made the odd decision to enforce a screen<br />
lock on me, for &#8220;security&#8221;. Never mind.</p>
<p>Now, back to our browser &#8230; mitmproxy is still running, so let&#8217;s re-try<br />
re-enabling ProxyDroid and resubmit the browser request for<br />
https://google.com/ &#8230;<br />
<a href='http://inode.co.nz/wp-uploads/googleviaproxydroidmitm.png'><img src="http://inode.co.nz/wp-uploads/googleviaproxydroidmitm-300x187.png" alt="MITMproxy working" title="MITMproxy working" width="300" height="187" class="alignnone size-medium wp-image-101" /></a></p>
<p>This time, things work, and viewing the certificate via the Options/Page info shows that mitmproxy&#8217;s CA is now fully trusted.<br />
<a href='http://inode.co.nz/wp-uploads/googleviaproxydroidmitmmenu.png'><img src="http://inode.co.nz/wp-uploads/googleviaproxydroidmitmmenu-300x187.png" alt="Browser - PageInfo menu" title="Browser - PageInfo menu" width="300" height="187" class="alignnone size-medium wp-image-102" /></a><br />
<a href='http://inode.co.nz/wp-uploads/googleviaproxydroidmitmpageinfo.png'><img src="http://inode.co.nz/wp-uploads/googleviaproxydroidmitmpageinfo-300x187.png" alt="Browser - PageInfo" title="Browser - PageInfo" width="300" height="187" class="alignnone size-medium wp-image-103" /></a><br />
<a href='http://inode.co.nz/wp-uploads/googleviaproxydroidmitmmitmcavalid.png'><img src="http://inode.co.nz/wp-uploads/googleviaproxydroidmitmmitmcavalid-300x187.png" alt="Browser - trusted MITMproxy certificate" title="Browser - trusted MITMproxy certificate" width="300" height="187" class="alignnone size-medium wp-image-104" /></a></p>
<pre>
&gt;&gt; GET https://www.google.com/
 ← 302 text/html 222B
   GET https://www.google.co.nz/
 ← 200 text/html 16.72kB
</pre>
<p>Now you are ready to collect arbitrary HTTP/HTTPS traffic from the Android into your MITMproxy instance. Be responsible with your research and please take care about how you publish any findings that may affect a large number of users.</p>
]]></content:encoded>
			<wfw:commentRss>http://inode.co.nz/configuring-an-android-with-mitmproxy/feed</wfw:commentRss>
		</item>
		<item>
		<title>Review: Motorola NYXboard media-centre remote control</title>
		<link>http://inode.co.nz/review-motorola-nyxboard-media-centre-remote-control</link>
		<comments>http://inode.co.nz/review-motorola-nyxboard-media-centre-remote-control#comments</comments>
		<pubDate>Mon, 02 Apr 2012 00:07:43 +0000</pubDate>
		<dc:creator>jim</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://inode.co.nz/?p=82</guid>
		<description><![CDATA[Hads at Nicegear has just sent me the Motorola NYXboard Hybrid remote control, because I run an XBMC media centre. It feels a little retro, quite rectangular &#38; chunky when compared to my old Windows Media Centre remote &#8230; but when you flip it over there&#8217;s a QWERTY keyboard &#38; even a mouse pointer! The [...]]]></description>
			<content:encoded><![CDATA[<div>Hads at <a href="http://nicegear.co.nz/">Nicegear</a> has just sent me the <a href="https://nicegear.co.nz/htpc/motorola-htpc-remote/">Motorola NYXboard Hybrid remote control</a>, because I run an XBMC media centre. It feels a little retro, quite rectangular &amp; chunky when compared to my old Windows Media Centre remote &#8230; but when you flip it over there&#8217;s a QWERTY keyboard &amp; even a mouse pointer! The primary communication method is over RF, so there is a small USB dongle to plug in to the XBMC machine and job done. Just to prove the RF point, I&#8217;ve popped the USB dongle around the back of the PC, and it&#8217;s working just fine from my normal distance (about 4 metres).</div>
<div>
<ul>
<li><a href="http://inode.co.nz/wp-uploads/nyxrce.jpg"><img class="alignnone size-medium wp-image-83" title="nyxrcu" src="http://inode.co.nz/wp-uploads/nyxrce-300x252.jpg" alt="The NYXboard " width="300" height="252" /></a></li>
<li> <a href="http://inode.co.nz/wp-uploads/nyxqwerty.jpg"><img class="alignnone size-medium wp-image-84" title="nyxqwerty" src="http://inode.co.nz/wp-uploads/nyxqwerty-300x215.jpg" alt="NYXboard qwerty" width="300" height="215" /></a></li>
</ul>
</div>
<div>
<p>The controls are neat and straightforward, although I still don&#8217;t actually have a use for the 4 colour buttons &amp; the EPG &#8212; I&#8217;m getting TV via a MythTV backend that doesn&#8217;t co-operate fully with my XBMC anyway. Soft buttons combined with a clear tactile &amp; audible &#8216;click&#8217; when activated makes it obvious when you have pressed a key. It also has an IR transmitter and I have taught it how to control the hifi/dvd and TV systems, by carefully mix &amp; matching buttons because there is only one profile to play with (you can only reprogram the RCU keys, not the QWERTY side ones)</p>
<p>The real win is the QWERTY keyboard on the back. I don&#8217;t often encounter user input requests while browsing TV, but searching other video sources (YouTube, TED &amp; Khan Academy usually) is a bit of a chore with the on-screen keyboard provided by XBMC. With the NYXboard remote, it&#8217;s simplicity itself to just flip it over and start typing (when you flip, the buttons on the &#8220;other&#8221; side are disabled automatically). This really makes it easy to get more out of other parts of XBMC that I normally ignore, like the music smart playlists.</p>
<p>If you need to use the mouse pointer, the NYXboard has that covered &#8212; just use the circle keypad with the Fn key, and the mouse pointer shows up &amp; starts to move. It can be easier to select buttons by direct navigation this way, rather than by tabbing through the interface. If you have to move the mouse a long way, look out for the acceleration in speed. Both left and right clicking work fine.</p>
<p>Things aren&#8217;t perfect, however; although the normal use-cases work just fine, there are a few omissions. A minor one to start &#8212; there&#8217;s Sterling and Euro symbols theoretically available on the keyboard, but they do not work &#8212; Sterling is ignored, and Euro comes through as a lower-case &#8216;e&#8217;. Perhaps I told my XBMC that it had a US keyboard attached which makes that an OS issue; in any case it isn&#8217;t a worrying omission.</p>
<p>Slightly more concerning is the lack of an Escape key. I occasionally run external programs like Skype on the TV, and haven&#8217;t bothered to set up a window manager for them. If you get the chat window up on Skype you can only exit it with the Escape key, or a window manager control. Even the handy &#8220;Menu&#8221; function on the keyboard that pulls up the active menu does not help here &#8230; I have to get up and tap a key on the big keyboard plugged in to the machine, or ssh in and kill processes, neither of which are especially good. There is also no Control, Alt or Super/Windows key, so although this device works just fine when plugged in to a desktop PC (after all, it is a standard USB-connected keyboard) you&#8217;re limited in what you can do.</p>
<p>However, we shouldn&#8217;t lose sight of the fact that this isn&#8217;t supposed to be a full PC keyboard solution, like the ProMini featured on Thinkgeek, or the Logitech range. It&#8217;s a media centre remote control, with a QWERTY keyboard on the back for the more advanced options of the media centre itself &#8212; and a mouse cursor just in case it&#8217;s needed!</p>
<p>I rate this device very highly. I didn&#8217;t think that there was anything wrong with my old Windows MC controller until I started using the Motorola NYXboard!</p>
<p>Disclaimer: Hads sent me the remote free of charge, with no obligation other than to write an honest review. I hope I&#8217;ve done that.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://inode.co.nz/review-motorola-nyxboard-media-centre-remote-control/feed</wfw:commentRss>
		</item>
		<item>
		<title>pfSense 2.0 Cookbook</title>
		<link>http://inode.co.nz/pfsense-20-cookbook</link>
		<comments>http://inode.co.nz/pfsense-20-cookbook#comments</comments>
		<pubDate>Tue, 05 Apr 2011 04:19:30 +0000</pubDate>
		<dc:creator>jim</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<category><![CDATA[pfSense]]></category>

		<guid isPermaLink="false">http://inode.co.nz/?p=79</guid>
		<description><![CDATA[Nice to see a copy of the pfSense 2.0 Cookbook land on my desk today. Packt Publishing asked me to do a pass of technical review for this a while ago, which was good fun. Matt Williamson has done a good job of creating a useful set of enumerated examples that should help anyone wanting [...]]]></description>
			<content:encoded><![CDATA[<p>Nice to see a copy of the <a href="http://www.packtpub.com/pfsense-2-cookbook/book">pfSense 2.0 Cookbook</a> land on my desk today. Packt Publishing asked me to do a pass of technical review for this a while ago, which was good fun. <a href="http://www.bunkerhollow.com/">Matt Williamson</a> has done a good job of creating a useful set of enumerated examples that should help anyone wanting to roll out 2.0, which has recently achieved <a href="http://blog.pfsense.org/?p=585">Release Candidate 1</a> status.</p>
]]></content:encoded>
			<wfw:commentRss>http://inode.co.nz/pfsense-20-cookbook/feed</wfw:commentRss>
		</item>
		<item>
		<title>Faking single-factor authentication — ssh keys for HTTP Auth?</title>
		<link>http://inode.co.nz/faking-single-factor-authentication-%e2%80%94-ssh-keys-for-http-auth</link>
		<comments>http://inode.co.nz/faking-single-factor-authentication-%e2%80%94-ssh-keys-for-http-auth#comments</comments>
		<pubDate>Tue, 29 Mar 2011 05:23:08 +0000</pubDate>
		<dc:creator>jim</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<category><![CDATA[authentication]]></category>

		<category><![CDATA[perl]]></category>

		<guid isPermaLink="false">http://inode.co.nz/?p=78</guid>
		<description><![CDATA[For customers of one of my services I provide ssh keys, that allow restricted access to the server environment. Now I want to run a web service in there as well, that will give them various status reports on the server; but I don&#8217;t want to manage another username/password pair for them. So the intention [...]]]></description>
			<content:encoded><![CDATA[<p>For customers of one of my services I provide ssh keys, that allow restricted access to the server environment. Now I want to run a web service in there as well, that will give them various status reports on the server; but I don&#8217;t want to manage another username/password pair for them. So the intention was to try to re-use the current ssh keys for authentication on the web service.</p>
<p>This was more difficult than I initially expected. Although both ssh and SSL have a similar key structure internally, there are a lot of differences in the implementation. It turns out to be possible to reverse the problem &#8212; I could create SSL keys and then patch OpenSSH to use them instead (see <a href="http://roumenpetrov.info/openssh/">http://roumenpetrov.info/openssh/</a> for details), but I&#8217;d have to patch the client OpenSSH instances as well as the server, and that&#8217;s just painful.</p>
<p>Eventually I hit on an alternative scheme, to fake things. I will be running the web service on a localhost port, so only valid customers could access the app via ssh tunneling. The app doesn&#8217;t really need to do authentication, as the customer has already proved who they are by being able to use ssh. But identification is required &#8212; I don&#8217;t want the app to leak data between customers, of course. It turns out to be quite difficult to work out who a user is by looking backwards from a web app, when all you have is a port number that they connected from. And by &#8216;difficult&#8217; I mean &#8216;not easily supported in most web app frameworks&#8217;.</p>
<p>So I wrote a small forward proxy that the customer will run and tunnel into. Because the customer is running it, I have access to their username and environment. I use these to create a fake HTTP Auth request. The real back-end web app just allows any basic auth request to succeed, and runs from there. Remember, the back end service doesn&#8217;t need to enforce authentication because I&#8217;ve done that via ssh already.</p>
<p>Here&#8217;s the Fake Auth Forward Proxy code &#8212; a short job for perl, HTTP::Daemon and LWP::UserAgent. I did try writing this with python&#8217;s Twisted first, but to be honest the CPAN documentation was so much better when it came to working out details &#8230; I spent ages trying to figure out Twisted, asking questions on IRC &#8230; as opposed to just reading CPAN cross-references and understanding things more quickly.</p>
<pre>
#!/usr/bin/env perl

# Fake Auth Forward Proxy
#
# This HTTP proxy listens to client requests, and gets the answer from
# another HTTP server. Before making the forward request, we construct
# a new HTTP Authentication header, based on the OS username running
# this program, and the SSH_CONNECTION environment variable, if available.
#
# Usage: fafp [listenport] [server URL]
# Defaults: fafp 8080 http://127.0.0.1:3000
#
# http://inode.co.nz/
# Copyright © Jim Cheetham <jim@inode.co.nz> 2011
# Version 1.0

use strict;
use HTTP::Daemon;
use LWP::UserAgent;

my $listenport = $ARGV[0] || 8080;
# Set the forward server, and the authentication that will be used
my $fserver = $ARGV[1] || &#8220;http://127.0.0.1:3000&#8243;;
my $fauser = getlogin || getpwuid($<) || "Kilroy";
my $fapass = $ENV{'SSH_CONNECTION'} || "localconnection";
# Set up the user agent that will be making onward requests
my $ua = LWP::UserAgent->new;
$ua->timeout(10);

# Set Reuse => 1 to avoid a long TIME_WAIT state on the socket when we finish
my $d = new HTTP::Daemon ( LocalPort => $listenport, Reuse => 1) or die &#8220;Failed to start HTTP Daemon: $@\n&#8221;;
print STDERR &#8220;Fake Auth Forward Proxy listening on &#8220;, $d->url, &#8220;\nSending queries to $fserver, auth=&#8217;$fauser:$fapass&#8217;\n&#8221;;

# Loop, accepting client communication
while (my $clientconn = $d->accept) {
            # Extract the HTTP::Request object
            while (my $req = $clientconn->get_request) {
                        # Alter the request target, and add fake authentication
                        $req->authorization_basic($fauser,$fapass);
                        $req->url($fserver.$req->url);
                        # Make the forward request (via $ua) and return it to our client.
                        $clientconn->send_response($ua->request($req));
                }
        $clientconn->close;
        undef($clientconn);
}
</pre>
<p>The end user sshs into the server to contact the web applications :-</p>
<pre>
$ ssh server -L 8080:localhost:8080 /usr/local/bin/fafp
</pre>
<p>and then just contacts http://localhost:8080 to get access to the app. Job done, with only a single authentication token, the ssh key.</p>
]]></content:encoded>
			<wfw:commentRss>http://inode.co.nz/faking-single-factor-authentication-%e2%80%94-ssh-keys-for-http-auth/feed</wfw:commentRss>
		</item>
		<item>
		<title>Dropping connections to a postgresql db</title>
		<link>http://inode.co.nz/dropping-connections-to-a-postgresql-db</link>
		<comments>http://inode.co.nz/dropping-connections-to-a-postgresql-db#comments</comments>
		<pubDate>Mon, 28 Mar 2011 23:39:37 +0000</pubDate>
		<dc:creator>jim</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<category><![CDATA[postgresql]]></category>

		<category><![CDATA[sudo]]></category>

		<guid isPermaLink="false">http://inode.co.nz/?p=77</guid>
		<description><![CDATA[Sometimes, especially in development environments, you want to drop a whole database &#38; then re-establish it. Unfortunately, if there are any current connections to the postgresql db, you can&#8217;t. Postgresql doesn&#8217;t give you a way to selectively drop client connections &#8212; you can stop the whole db server, but that will affect every database in [...]]]></description>
			<content:encoded><![CDATA[<p>Sometimes, especially in development environments, you want to drop a whole database &amp; then re-establish it. Unfortunately, if there are any current connections to the postgresql db, you can&#8217;t. Postgresql doesn&#8217;t give you a way to selectively drop client connections &#8212; you can stop the whole db server, but that will affect every database in there, not just the one you are working on.</p>
<p>Luckily, postgres will report on who has current connections, through the <code>pg_stat_activity</code> table. Our task is to use this table effectively to grab the process IDs of connections, and then to ask the OS to kill those connections for us. And to do this without granting too much power on the way; this will not &#8220;run as root with no password&#8221; via sudo, for example.</p>
<p>For those impatient people out there, here&#8217;s the script that does the job, the sudoers line needed to grant a reasonable minimum privilege, and how to use it. Then I can get on with explaining it &#8230;</p>
<h2>Step 0 - The Finished Product</h2>
<p>Put this script somewhere useful, like <code>/usr/local/bin/kill-db-connections</code> or <code>$HOME/bin/kill-db-connections</code> :-</p>
<pre>#!/bin/sh
psql -U $1 -t -c "select procpid from pg_stat_activity \
  where datname='$2' and current_query not like \
  'select procpid from pg_stat_activity%';" \
| sudo -u postgres xargs kill</pre>
<p>Now decide which user will be executing this - in a development box I have nearby, this is the user <code>jenkins</code>, related to the Jenkins Continuous Integration system (previously called Hudson). So in <code>sudoers</code> I add the following restricted ability :-</p>
<pre>jenkins ALL=(postgres) NOPASSWD: /usr/bin/xargs kill</pre>
<p>Finally, we invoke this command with the username and database name as command arguments, and any user password as an environment variable &#8230;</p>
<pre>PGPASSWORD="userpw" kill-db-connection testuser testdb</pre>
<p>And that&#8217;s all we need. Now read on for the detail of each step &#8230;</p>
<h2>Step 1 - Identify the connections</h2>
<p>The <code>pg_stat_activity</code> table in postgresql stores a lot of detail about the connections to the database and what they are doing. When we look at this table we are interested in the datname column, which shows the database a client is connected to (we are assuming that a busy system has multiple databases under postgresql, which is why we are not just shutting down the whole server to get rid of unwanted connections), the procpid column which gives us the OS process ID of the connection, and the current_query column, which I&#8217;ll explain in a moment.</p>
<p>Lets just query those three and see what we get (my database name is &#8216;dev&#8217; in this example) :-</p>
<pre>dev=&gt; select datname,procpid,current_query
dev-&gt; from pg_stat_activity;
 datname  | procpid |                        current_query
----------+---------+-------------------------------------------------------------
 dev |    4865 | select datname,procpid,current_query from pg_stat_activity;
 dev |    2200 |
 dev |    4538 |
 dev |    2257 |
 dev |    2270 |
 dev |    3926 |
 dev |    5394 |
prod |    4528 |
(8 rows)</pre>
<p>Ok, so we can see 8 connections &#8212; and one of those is actually our current query! More worryingly, one of them is a connection to a different database, and we should leave this one alone. We need to refine our query a little &#8212; select only the &#8216;dev&#8217; database, and exclude our own query.</p>
<pre>dev=&gt; select datname,procpid,current_query
dev-&gt; from pg_stat_activity where datname = 'dev'
dev-&gt; and current_query not like 'select datname,procpid,current_query from pg_stat_activity%';
 datname  | procpid | current_query
----------+---------+---------------
 dev |    2200 |
 dev |    4538 |
 dev |    2257 |
 dev |    2270 |
 dev |    3926 |
 dev |    5394 |
(6 rows)</pre>
<p>That&#8217;s better! I excluded our own query by specifying enough of our own actual query using LIKE to avoid any normal db user. I couldn&#8217;t specify the whole query, because that would end up including the LIKE clause itself &#8230; and that way lies recursive madness.</p>
<p>So now we have the list of connections that we are interested in. We can now forget about the datname and current_query colums on output, because we have confidence in our main query. When we drop these from the main query we need to also modify the LIKE clause to match &#8230;</p>
<pre>dev=&gt; select procpid from pg_stat_activity
dev-&gt; where datname = 'dev'
dev-&gt; and current_query not like 'select procpid from pg_stat_activity%';
 procpid
---------
    2200
    4538
    2257
    2270
    3926
    5394
(6 rows)</pre>
<h2>Step 2 - Just the bare minimum data please</h2>
<p>We need to step outside the postgresql prompt now, in order to process this output from the shell. The first step is to work out what this needs to look like to be a &#8217;single command&#8217; rather than an interactive session.</p>
<p>We can call the psql program with the option &#8216;-c SQL_COMMAND&#8217;, but we also need to specify which user to log in as with &#8216;-U username&#8217;. Lets try this &#8230;</p>
<pre>$ psql -U devuser \
&gt; -c "select procpid from pg_stat_activity where datname='dev' \
&gt; and current_query not like 'select procpid from pg_stat_activity%';"
Password for user devuser:</pre>
<p>Oh, that&#8217;s not very helpful. Automating this won&#8217;t work if I have to type in a password every time it gets used. We have two approaches &#8212; allow this user to log in to postgresql without providing a password, or store the actual password in the script.</p>
<p>The <em>correct</em> approach is to set up a user that is allowed to run this query, and only this query, and to do so without a password. After all, we can get most of this data from the OS as any user anyway. But I&#8217;m guessing that if you knew how to do that properly you wouldn&#8217;t need to read this page! And I don&#8217;t want to start describing how to modify postgresl authentication to allow this, we have enough to cover anyway. So providing the password from the script is the way we&#8217;re going. Just make sure that the script file is stored securely, with restricted permissions to stop just anyone from reading it.</p>
<p>So, we can provide the password by populating the PGPASSWORD environment variable when we call the psql command :-</p>
<pre>$ PGPASSWORD="userpw" psql -U devuser \
&gt; -c "select procpid from pg_stat_activity where datname='dev' \
&gt; and current_query not like 'select procpid from pg_stat_activity%';"
 procpid
---------
    2200
    4538
    2257
    2270
    3926
    5394
(6 rows)</pre>
<p>That&#8217;s good. Now we need to ask psql to stop printing the column name at the top and the number of matching rows at the bottom, using the &#8216;-t&#8217; option.</p>
<pre>$ PGPASSWORD="userpw" psql -U devuser -t \
&gt; -c "select procpid from pg_stat_activity where datname='dev' \
&gt; and current_query not like 'select procpid from pg_stat_activity%';"
    2200
    4538
    2257
    2270
    3926
    5394</pre>
<p>So now we have a simple and clean list of the connections that we want to terminate. Time to move on.</p>
<h2>Step 3 - Terminate the connections</h2>
<p>Lets have a look at one of those process IDs, and see what we can see.</p>
<pre>$ ps -fp 2200
UID        PID  PPID  C STIME TTY          TIME CMD
postgres  2200 17444  0 09:22 ?        00:00:00 postgres: dev dev 203.97.121.211(44619) idle</pre>
<p>It is owned by the system user &#8216;postgres&#8217;. If we want to kill that process, we need to either have the same user ID, or to be root. Being root is not good, it is too easy to make mistakes and do bad things on a system. We want to be the user &#8216;postgres&#8217; when we are killing the connections. But at the beginning of all this, we mentioned running this under the Jenkins CI system, and that means that we are probably running as the user &#8216;jenkins&#8217;. We will need to use the <code>sudo</code> command to allow us to switch users for this. And we have already exposed one password to our script, can we avoid doing this again?</p>
<p>Yes, we can. <code>sudo</code> will allow us to run a specified command, as another user, without asking for a password. This is a potential security hole, but if you manage things well it becomes a powerful automation tool.</p>
<p>So, to allow &#8216;jenkins&#8217; to run the command &#8216;kill&#8217; as the user &#8216;postgres&#8217;, we add the following line to the sudoers configuration using <code>visudo</code> :-</p>
<pre>jenkins ALL=(postgres) NOPASSWD: /usr/bin/kill</pre>
<p>So we can now issue kill commands to these process IDs. We can also kill the whole postgresql server too, if we are not careful. How careful are you when writing new Jenkins tasks for your development server? How careful do you need to be?</p>
<p>I&#8217;m not going to answer those questions for you. What I am going to do it help you work your way through the list of process IDs from the <code>pg_stat_activity</code> table and get rid of them all quickly!</p>
<p>We could ask the shell to step through each line of the output, and send the kill signal to each one. That would look like this :-</p>
<pre>$ for pid in $(PGPASSWORD="userpw" psql -U devuser ... blah blah)
&gt; do
&gt; sudo -u postgres kill $pid
&gt; done</pre>
<p>Yes, I really did say &#8220;blah blah&#8221; in there, there was too much to type and it all looks so very messy. That&#8217;s one reason to not use this approach &#8212; the code ends up messy, and messy code is bad code.</p>
<p>The other way is to use the <code>xargs</code> command, which is written specifically to make this kind of thing easy. <code>xargs</code> basically handles the whole &#8216;for;do;done&#8217; loop for you in one go.</p>
<p>Lets test xargs with a simple printf call :-</p>
<pre>$ PGPASSWORD="userpw" psql -U devuser -t \
&gt; -c "select procpid from pg_stat_activity where datname='dev' \
&gt; and current_query not like 'select procpid from pg_stat_activity%';" \
&gt; | xargs printf 'pid=%s\n'
pid=2200
pid=4538
pid=2257
pid=2270
pid=3926
pid=5394</pre>
<p>We can use xargs to call the kill command for us, too. Now we face another choice, to do with the use of the &#8217;sudo -u postgres&#8217; that we need &#8212; do we do this <em>inside</em> the xargs loop, or outside it? Both will work &#8230;</p>
<p>I&#8217;ve chosen to invoke the sudo <em>first</em>, and to run the xargs command as the postgres user. It is a little arbitrary, but in my way the jenkins user can no longer simply call &#8217;sudo -u postgres kill &#8230;&#8217;. This might stop an accidental kill of the postgres server perhaps. It isn&#8217;t going to be difficult to work around, but it isn&#8217;t obvious. I&#8217;m not trying to utterly prevent the jenkins user from abusing their rights to kill postgres processes, but I am trying to avoid user mistakes.</p>
<p>So I will call <code>sudo -u postgres xargs kill</code> at the end of our long command line (and of course I have to change the sudoers config we used earlier).</p>
<pre>$ PGPASSWORD="userpw" psql -U devuser -t \
&gt; -c "select procpid from pg_stat_activity where datname='dev' \
&gt; and current_query not like 'select procpid from pg_stat_activity%';" \
&gt; | sudo -u postgres xargs kill</pre>
<p>sudoers:</p>
<pre>jenkins ALL=(postgres) NOPASSWD: /usr/bin/xargs kill</pre>
<h2>Step 4 - Generalising the solution</h2>
<p>So now we need to take our huge command line, and pop it into a script for later use. While we&#8217;re doing that, we can clean up some of the fixed names we have used and make the solution more flexible.</p>
<p>First off, we will leave out the users password; this will be needed in scripts called directly by Jenkins, but our single-purpose &#8216;kill-db-connections&#8217; script doesn&#8217;t need to handle it &#8212; after all, perhaps you set up postgresql acces permissions to allow a user to run this query with no password (tell me how you did it, please!)</p>
<p>Secondly, we won&#8217;t make a fixed assumption about the name of the database itself, or the username to connect as. We&#8217;ll grab these from the command-line when you run the script.</p>
<p>Thirdly, we won&#8217;t put in error checking and stuff like that. You won&#8217;t be using this script from the command-line, you will be integrating it into other scripts that, once tested, won&#8217;t be changed. So we can save time and effort here &#8212; and that&#8217;s another tradeoff between doing things &#8216;right&#8217; and doing them &#8216;now&#8217;.</p>
<p>So, our script becomes :-</p>
<pre>#!/bin/sh
psql -U $1 -t -c "select procpid from pg_stat_activity \
  where datname='$2' and current_query not like \
  'select procpid from pg_stat_activity%';" \
| sudo -u postgres xargs kill</pre>
<p>In order for the sudo to work, we need &#8217;sudoers&#8217; to contain :-</p>
<pre>jenkins ALL=(postgres) NOPASSWD: /usr/bin/xargs kill</pre>
<p>And when we call this, we need to provide the user- and database-names as command arguments, and the user password as an environment variable :-</p>
<pre>PGPASSWORD="userpw" kill-db-connection testuser testdb</pre>
<h2>Last thoughts</h2>
<p>Is there a better way for all this? Well, perhaps if the postgresql server itself supported a command like &#8216;pg_ctl kill-db-clients datname&#8217; we would be happy. Who wants to implement that, and submit the code to the postgresql project?</p>
<p>A better way to implement this specific solution, however, would be to mandate that the actual &#8216;kill-db-connection&#8217; script were run as the postgres user. That way we avoid the granting of arbitrary &#8216;kill&#8217; ability to the jenkins user, and as long as the script were protected by filesystem permissions to prevent &#8216;jenkins&#8217; from altering it (and we spent more time being very defensive about the command-line argument inputs), we could be more restrictive in sudoers, with something like &#8216;<code>jenkins ALL=(postgres) NOPASSWD: /usr/local/bin/kill-db-connections</code>&#8216;. I didn&#8217;t do that here, because I&#8217;m not <em>that</em> paranoid about the development server in question, and didn&#8217;t need to spend the extra time to make the script more defensive. However, in a larger environment you may not want to extend too much &#8216;trust&#8217; to your automation systems.</p>
<p>Another improvement would be around the handling of the user password. I&#8217;m keeping this out of the command-line arguments so that it doesn&#8217;t show up in a standard process list; however putting it in an environment variable isn&#8217;t much better as it can still be extracted by any user &#8212; it&#8217;s just a little more obscured. The psql command will read data from <code>$HOME/.pgpass</code> so we could put data in there &#8212; however when you are running from a system user account like &#8216;jenkins&#8217; it isn&#8217;t obvious just where $HOME actually is, and you may be switching between an arbitrary number of different database user accounts anyway. If you really need to exercise more care over passwords (and you should!) then you need to do a little more research. Talk to a real postgresql administrator, not me!</p>
]]></content:encoded>
			<wfw:commentRss>http://inode.co.nz/dropping-connections-to-a-postgresql-db/feed</wfw:commentRss>
		</item>
		<item>
		<title>sshfs options in fstab</title>
		<link>http://inode.co.nz/sshfs-options-in-fstab</link>
		<comments>http://inode.co.nz/sshfs-options-in-fstab#comments</comments>
		<pubDate>Tue, 15 Mar 2011 02:42:25 +0000</pubDate>
		<dc:creator>jim</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<category><![CDATA[fstab]]></category>

		<category><![CDATA[mount]]></category>

		<category><![CDATA[ssh]]></category>

		<category><![CDATA[sshfs]]></category>

		<guid isPermaLink="false">http://inode.co.nz/?p=73</guid>
		<description><![CDATA[When I configure something on a server, I like to be able to control all the options explicitly. I&#8217;m not a fan of implicit configuration, it might work fine for single-user workstations and look far prettier, but things on a server should be completely unambiguous and have no hidden dependencies.
So, I wanted to set up [...]]]></description>
			<content:encoded><![CDATA[<p>When I configure something on a server, I like to be able to control all the options explicitly. I&#8217;m not a fan of implicit configuration, it might work fine for single-user workstations and look far prettier, but things on a server should be completely unambiguous and have no hidden dependencies.</p>
<p>So, I wanted to set up an sshfs mount in <code>/etc/fstab</code>, but I needed to specify the private key to be used explicitly. Google results are full of people giving up and using scripts, or relying on <code>$HOME/.ssh/id.dsa</code>, or perhaps if they get carried away <code>$HOME/.ssh/config</code> (which is of course better).</p>
<p>Where command-line <code>sshfs</code> uses &#8216;<code>-o IdentityFile=…</code>&#8216;, you can put that option directly into the fs_mntops column in <code>/etc/fstab</code> :-</p>
<pre>
sshfs#username@server:directory  mountdir  fuse  IdentityFile=/path/to/privatekey  0 0
</pre>
<p>You probably want to add a few other options to that column, such as &#8216;user&#8217; and &#8216;noauto&#8217;. While you are at it, try adding this simple sanity check — have a file called &#8216;STOP&#8217; in your unmounted mountpoint directory, and one called &#8216;GO&#8217; in the mounted one; this makes a simple sanity check in scripts using the mount before they use up all your disk space … you may have to add the &#8216;nonempty&#8217; option to get away with this one.</p>
]]></content:encoded>
			<wfw:commentRss>http://inode.co.nz/sshfs-options-in-fstab/feed</wfw:commentRss>
		</item>
		<item>
		<title>Automating bzr over ssh without passwords</title>
		<link>http://inode.co.nz/automating-bzr-over-ssh-without-passwords</link>
		<comments>http://inode.co.nz/automating-bzr-over-ssh-without-passwords#comments</comments>
		<pubDate>Thu, 03 Mar 2011 00:37:45 +0000</pubDate>
		<dc:creator>jim</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<category><![CDATA[bzr]]></category>

		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://inode.co.nz/?p=71</guid>
		<description><![CDATA[Well this job took me far far longer than should have been necessary. I wanted to automate the job of updating a bzr branch from a remote server, and the bzr+ssh:// method involved the least change to authentication at the far end.
What I thought was a slight complication was that I need to use an [...]]]></description>
			<content:encoded><![CDATA[<p>Well this job took me far far longer than should have been necessary. I wanted to automate the job of updating a bzr branch from a remote server, and the bzr+ssh:// method involved the least change to authentication at the far end.</p>
<p>What I thought was a slight complication was that I need to use an identity file to connect, not a password; and because this is going to come from a script invoked from cron I don&#8217;t have a specific user in mind, and no $HOME.</p>
<p>Unfortunately all the examples I can find for bzr talk about changing configs in $HOME, either for bzr itself or for ssh. And only for managing passwords; for keys the only comment was to use an SSH key agent, which isn&#8217;t ideal for me. That&#8217;s odd, I thought, well I&#8217;ll just have to specify things on the command-line, like we can with rsync &#038; friends.</p>
<p>Well, no. There is no space in bzr for specifying options to the underlying ssh (which by default is paramiko). If you look hard in the documentation you might discover the BZR_SSH environment variable though … so perhaps you can set that to point to your own pre-loader script?</p>
<p>Again, no. You can only set BZR_SSH to a pre-defined set of words, and you cannot specify a specific command.</p>
<p>So the only working option that I could find was the nasty nasty method of creating a replacement command called &#8217;ssh&#8217;, and to run bzr with this script at the front of PATH. Make sure that you don&#8217;t accidentally invoke the real ssh as just &#8220;ssh&#8221; within that script &#8212; use absolute filenames to prevent a <a href="http://twitter.com/#!/yjmbo/status/42814065495654400">forkbombing of your own machine</a>.</p>
<p>This replacement ssh sets the correct username and identity file for the onward connection, and then does just whatever bzr wanted anyway. In order to invoke bzr correctly you need to specify a new PATH and the BZR_SSH setting …</p>
<p>The fake ssh script :-</p>
<pre>
#!/bin/sh
/usr/bin/ssh -l username \
    -i /full/path/to/identity_file \
    -o IdentitiesOnly=yes $*
</pre>
<p>The bzr invocation :-</p>
<pre>
PATH=/full/path/to/fake BZR_SSH=ssh \
    /usr/bin/bzr pull bzr+ssh://remote.host/repo
</pre>
]]></content:encoded>
			<wfw:commentRss>http://inode.co.nz/automating-bzr-over-ssh-without-passwords/feed</wfw:commentRss>
		</item>
		<item>
		<title>Editing OpenOffice.org documents from the commandline</title>
		<link>http://inode.co.nz/editing-openofficeorg-documents-from-the-commandline</link>
		<comments>http://inode.co.nz/editing-openofficeorg-documents-from-the-commandline#comments</comments>
		<pubDate>Thu, 20 Jan 2011 05:43:30 +0000</pubDate>
		<dc:creator>jim</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<category><![CDATA[OpenOffice.org]]></category>

		<category><![CDATA[pfSense]]></category>

		<guid isPermaLink="false">http://inode.co.nz/?p=70</guid>
		<description><![CDATA[I&#8217;ve just put together a reasonably big document with a load of content copy/pasted from a web page (in this case, a firewall configuration GUI). Everything looked fine. Then I closed the VPN to the remote firewall &#8230; and all the icon images I&#8217;d pasted broke! When they were pasted in, by default only links [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just put together a reasonably big document with a load of content copy/pasted from a web page (in this case, a firewall configuration GUI). Everything looked fine. Then I closed the VPN to the remote firewall &#8230; and all the icon images I&#8217;d pasted broke! When they were pasted in, by default only links to the graphics were added, instead of copies &#8230;</p>
<p>Luckily for me, I was using OpenOffice.org, a wordprocessor with a sensible internal file storage.</p>
<p>To fix my document all I needed to do was to unpack my <code>.odt</code> file into a temporary location, grab local copies of the icons (I populated <code>~/tmp/fwicons/</code> from a different firewall, as it happens) into the <code>Pictures/</code> directory, change all the old image URLs into filenames (just by changing their prefix from <code>http://something/...</code> to <code>Pictures/</code>), and repack the changes into the original document.</p>
<p>OpenOffice.org detected my monkeying around internally, and insisted on running a quick &#8220;repair&#8221; over the file; when that was done I had all my lovely icons back again!</p>
<p>Here&#8217;s the complete command-line session &#8230;</p>
<pre>
jim@hex:~/ORIG$ mkdir ~/tmp/fixdoc
jim@hex:~/ORIG$ cp Network\ Configuration\ 1.0.odt /home/jim/tmp/fixdoc/
jim@hex:~/ORIG$ cd /home/jim/tmp/fixdoc/
jim@hex:~/tmp/fixdoc$ ls -l
total 80
-rw-r--r-- 1 jim jim 73421 2011-01-20 18:29 Network Configuration 1.0.odt
jim@hex:~/tmp/fixdoc$ mkdir unpack
jim@hex:~/tmp/fixdoc$ cd unpack

jim@hex:~/tmp/fixdoc/unpack$ unzip ../Network\ Configuration\ 1.0.odt
Archive:  ../Network Configuration 1.0.odt
 extracting: mimetype
 extracting: Pictures/10000201000001ED000001882B8674A7.png
  inflating: content.xml
  inflating: layout-cache
  inflating: manifest.rdf
  inflating: styles.xml
 extracting: meta.xml
  inflating: Thumbnails/thumbnail.png
  inflating: Configurations2/accelerator/current.xml
   creating: Configurations2/progressbar/
   creating: Configurations2/floater/
   creating: Configurations2/popupmenu/
   creating: Configurations2/menubar/
   creating: Configurations2/toolbar/
   creating: Configurations2/images/Bitmaps/
   creating: Configurations2/statusbar/
  inflating: settings.xml
  inflating: META-INF/manifest.xml   

jim@hex:~/tmp/fixdoc/unpack$ cp ~/tmp/fwicons/*gif Pictures

jim@hex:~/tmp/fixdoc/unpack$ perl -pi -e 's|http://firewall/themes/pfsense_ng/images/icons/|Pictures/|g' content.xml

jim@hex:~/tmp/fixdoc/unpack$ zip -r ../Network\ Configuration\ 1.0.odt Pictures/*
  adding: Pictures/icon_block_d.gif (deflated 15%)
  adding: Pictures/icon_block.gif (deflated 17%)
  adding: Pictures/icon_log_d.gif (deflated 28%)
  adding: Pictures/icon_log.gif (deflated 30%)
  adding: Pictures/icon_log_s.gif (deflated 29%)
  adding: Pictures/icon_pass_d.gif (deflated 7%)
  adding: Pictures/icon_pass.gif (deflated 9%)
  adding: Pictures/icon_reject_d.gif (deflated 13%)
  adding: Pictures/icon_reject.gif (deflated 15%)
jim@hex:~/tmp/fixdoc/unpack$ zip -r ../Network\ Configuration\ 1.0.odt content.xml
updating: content.xml (deflated 93%)
</pre>
]]></content:encoded>
			<wfw:commentRss>http://inode.co.nz/editing-openofficeorg-documents-from-the-commandline/feed</wfw:commentRss>
		</item>
		<item>
		<title>The dangers of rsync into a full filesystem</title>
		<link>http://inode.co.nz/the-dangers-of-rsync-into-a-full-filesystem</link>
		<comments>http://inode.co.nz/the-dangers-of-rsync-into-a-full-filesystem#comments</comments>
		<pubDate>Fri, 10 Dec 2010 08:53:54 +0000</pubDate>
		<dc:creator>jim</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://inode.co.nz/?p=69</guid>
		<description><![CDATA[I have an overly-complex and brittle chain of storage between my MythTV server and the machine that does playback onto the TV screen; one of the steps between them is a regular rsync of files from one machine to another &#8212; unfortunately disk usage on &#8220;the other&#8221; is not well controlled.
This means that I often [...]]]></description>
			<content:encoded><![CDATA[<p>I have an overly-complex and brittle chain of storage between my MythTV server and the machine that does playback onto the TV screen; one of the steps between them is a regular rsync of files from one machine to another &#8212; unfortunately disk usage on &#8220;the other&#8221; is not well controlled.</p>
<p>This means that I often end up with a full filesystem at one end, and I&#8217;m trying to stuff more files into it. And because I&#8217;m invoking rsync from cron instead of doing it properly and invoking it from a &#8216;while true; do &#8230;; sleep; done&#8217; loop script, I end up with multiple rsync&#8217;s running.</p>
<p>I haven&#8217;t dissected the behaviour yet, but I&#8217;ve found a whole load of quite sizeable rsync temporary files (&#8221;.&lt;filename&gt;.randomsuffix&#8221;). I&#8217;m guessing that these exist because the filesystem keeps on filling during these rsync runs, and somehow rsync isn&#8217;t managing to delete the temp files when this happens.</p>
<p>I&#8217;d be happy to accept that rsync would normally try to delete temp files when things go wrong, but with potentially multiple simultaneous rsyncs banging on, over an NFS link to an embedded machine with low disk performance, I guess that there are some timeout issues; added to which occasionally I have to kill rsyncs at the top end of the chain.</p>
<p>So just a warning; if you rsync badly (i.e. over cron) into a filesystem that is prone to filling up, please remember to look out for temp files while you are cleaning up!</p>
]]></content:encoded>
			<wfw:commentRss>http://inode.co.nz/the-dangers-of-rsync-into-a-full-filesystem/feed</wfw:commentRss>
		</item>
		<item>
		<title>XMonad is fun</title>
		<link>http://inode.co.nz/xmonad-is-fun</link>
		<comments>http://inode.co.nz/xmonad-is-fun#comments</comments>
		<pubDate>Mon, 18 Oct 2010 21:49:20 +0000</pubDate>
		<dc:creator>jim</dc:creator>
		
		<category><![CDATA[Technology]]></category>

		<guid isPermaLink="false">http://inode.co.nz/?p=67</guid>
		<description><![CDATA[The longer I spend with XMonad as a window manager, the more I like it. Now I&#8217;m running on multiple screens, the time saved by not manually moving windows around between screens, maximising and un-obscuring them is very noticeable.
I do still rely on the mouse a little too much though, and now I have 4 [...]]]></description>
			<content:encoded><![CDATA[<p>The longer I spend with <a href="http://xmonad.org/">XMonad</a> as a window manager, the more I like it. Now I&#8217;m running on multiple screens, the time saved by not manually moving windows around between screens, maximising and un-obscuring them is very noticeable.</p>
<p>I do still rely on the mouse a little too much though, and now I have 4 screens in a square arrangement its easy to lose sight of the pointer &#8212; expecially when using XMonad to open/switch/rearrange windows from the keyboard. I asked Ubuntu for a larger more visible pointer which helped, but now I&#8217;ve found an XMonad action that drags the mouse in to the focused window &#8230;<br />
<a href="http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Actions-UpdatePointer.html">http://xmonad.org/xmonad-docs/xmonad-contrib/XMonad-Actions-UpdatePointer.html</a></p>
<p>xmonad.hs :-</p>
<pre>
import XMonad.Actions.UpdatePointer
...
logHook = updatePointer (Relative 0.5 0.5)
</pre>
<p>Sorted. What shall I change next? &#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://inode.co.nz/xmonad-is-fun/feed</wfw:commentRss>
		</item>
	</channel>
</rss>

