<?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"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>zomo tech &#187; sw</title>
	<atom:link href="http://www.zomo.co.uk/category/sw/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.zomo.co.uk</link>
	<description>Is it done yet?</description>
	<lastBuildDate>Wed, 14 Sep 2011 07:56:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>pf on OS X 10.7</title>
		<link>http://www.zomo.co.uk/2011/09/pf-on-os-x-10-7/</link>
		<comments>http://www.zomo.co.uk/2011/09/pf-on-os-x-10-7/#comments</comments>
		<pubDate>Wed, 14 Sep 2011 07:54:18 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>
		<category><![CDATA[10.6]]></category>
		<category><![CDATA[10.7]]></category>
		<category><![CDATA[ipfw]]></category>
		<category><![CDATA[lion]]></category>
		<category><![CDATA[osx]]></category>
		<category><![CDATA[pf]]></category>
		<category><![CDATA[snow leopard]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=423</guid>
		<description><![CDATA[Today&#8217;s the first day that my new laptop, which runs OS X 10.7 (Lion), will sit on an untrusted network so I figured it was time to port my firewall rules across from the old one, that ran OS X 10.6 (Snow Leopard). I cut my UNIX teeth at a cryptoanarchist shop whose culture of [...]]]></description>
			<content:encoded><![CDATA[<p>Today&#8217;s the first day that my new laptop, which runs OS X 10.7 (Lion), will sit on an untrusted network so I figured it was time to port my firewall rules across from the old one, that ran OS X 10.6 (Snow Leopard).</p>
<p>I cut my UNIX teeth at a cryptoanarchist shop whose culture of paranoia makes me wary of Apple&#8217;s own firewall with its emphasis on letting all the hot shinyness Just Work rather than being overly fussy about inbound connections. Furthermore, with IPv6 tunnels like <a href="http://www.sixxs.net/tools/aiccu/">aiccu</a>, you aren&#8217;t behind the warm fuzzy comfort of NAT, you&#8217;re just there on the net with all the fun that entails. So, worth having some extra protection I reckon.</p>
<p>10.6 (and earlier) came with <a href="http://www.freebsd.org/cgi/man.cgi?ipfw"><code>ipfw</code></a>, a packet filter that&#8217;s knocked around the BSD world for some time. It works but isn&#8217;t overly featuresome (for example, it doesn&#8217;t support NAT in-kernel, so you monkey about passing packets to <a href="http://www.freebsd.org/cgi/man.cgi?natd">an external daemon</a>). But it was Good Enough for an end system so I supplemented the system&#8217;s &#8220;Application Firewall&#8221; with an additional <code>ipfw</code> ruleset to give an approximation of safety when out and about, and way more permissive when on networks I trust.</p>
<p>On 10.6 I used <a href="http://www.hanynet.com/waterroof/">WaterRoof</a> to sort-of manage the <code>ipfw</code> rules: in that I only really used its <a href="http://en.wikipedia.org/wiki/Launchd">launchd</a> loader and would hack on the rules by hand. In the spirit of decrufting I figured I&#8217;d sort that myself and went to remind myself how to load <code>ipfw</code> rules enmasse. I noticed at the top of man page:<br />
<code><br />
NAME<br />
     ipfw -- IP firewall and traffic shaper control program (DEPRECATED)<br />
...<br />
DESCRIPTION<br />
     Note that use of this utility is DEPRECATED. Please use pfctl(8) instead<br />
</code></p>
<p>Deprecated? Use <code>pfctl</code> instead? <a href="http://www.zomo.co.uk/wp-content/uploads/2011/09/good-news.jpg">Good news everyone</a> &#8211; OS X 10.7 now comes with <code>pf</code>, another BSD packet filter that I&#8217;ve chosen of <code>ipfw</code> on BSD hosts for years off the back of its featureset (native NAT, state syncing between failover firewall pairs, traffic queing&#8230;).</p>
<p>Anyway, the point of this post is to point out a few things I noticed which are intriguing. Firstly, <code>pf</code> is not enabled by default. Further, Apple have added some moving parts around how it <em>is</em> enabled. From <code>/etc/pf.conf</code>:<br />
<code><br />
# This file contains the main ruleset, which gets automatically loaded<br />
# at startup.  PF will not be automatically enabled, however.  Instead,<br />
# each component which utilizes PF is responsible for enabling and disabling<br />
# PF via -E and -X as documented in pfctl(8).  That will ensure that PF<br />
# is disabled only when the last enable reference is released.<br />
</code><br />
These two flags, <code>-E</code> and <code>-X</code>, are absent from <code>pf</code> on BSD. Here&#8217;s how they&#8217;re documented on OS X:<br />
<code><br />
     -E      Enable the packet filter and increment the pf enable reference count.<br />
     -X token<br />
             Release the pf enable reference represented by the token passed.<br />
</code><br />
This suggests that different system components might choose to enable and disable <code>pf</code>, and this is the mechanism to coordinate that. There&#8217;s a clue about which components in <code>/etc/pf.anchors/com.apple</code>, which is loaded by the main <code>/etc/pf.conf</code>. It defines additional rule anchors:<br />
<code><br />
anchor "100.InternetSharing/*"<br />
anchor "200.AirDrop/*"<br />
anchor "250.ApplicationFirewall/*"<br />
</code></p>
<p>Interestingly, this host&#8217;s ApplicationFirewall has a bunch of entries in when viewed in the Preferences GUI, yet the <code>pf</code> anchor of the same name is empty (and <code>pf</code> was disabled when I started out):<br />
<code><br />
$ sudo pfctl -a com.apple/250.ApplicationFirewall -s rules<br />
Password:<br />
No ALTQ support in kernel<br />
ALTQ related functions disabled<br />
</code><br />
so I&#8217;m unsure what the status of this mechanism is. I&#8217;ve not had occasion to use AirDrop or connection sharing, but would be curious to see if either use these anchors and enable <code>pf</code> temporarily.</p>
<p>Finally, what&#8217;s the token that&#8217;s passed to <code>-X</code>? You can ask <code>pfctl</code> for the current tokens:<br />
<code><br />
$ sudo pfctl -s References<br />
No ALTQ support in kernel<br />
ALTQ related functions disabled<br />
TOKENS:<br />
PID      Process Name                 TOKEN                    TIMESTAMP<br />
17013    pfctl                        18446743524308110600     0 days 01:05:50<br />
</code><br />
I enabled <code>pf</code> with <code>pfctl</code>, so that makes sense. When I did so it didn&#8217;t inform me of the token, but I suppose an enabling process would spelunk the token shortly after enabling <code>pf</code> by merit of its name and <code>PID</code> and pass it back when it&#8217;s finished with <code>pf</code>.</p>
<p>Now, on with the actual job of ruleset writing and puzzling out the <code>launchd</code> voodoo required to enable it at boot.</p>
<p>Minor whinge: Apple could do with updating <code>/etc/protocols</code>:<br />
<code><br />
# $FreeBSD: src/etc/protocols,v 1.14 2000/09/24 11:20:27 asmodai Exp $<br />
</code><br />
Why whinge? It doesn&#8217;t know <code>icmp6</code> is a valid alias for <code>ipv6-icmp</code>. Yep, minor.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2011/09/pf-on-os-x-10-7/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Cyrus saslauthd and passwords containing quote marks</title>
		<link>http://www.zomo.co.uk/2011/06/cyrus-saslauthd-and-passwords-containing-quote-marks/</link>
		<comments>http://www.zomo.co.uk/2011/06/cyrus-saslauthd-and-passwords-containing-quote-marks/#comments</comments>
		<pubDate>Sat, 11 Jun 2011 15:33:06 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=404</guid>
		<description><![CDATA[n the back of reading how affordable and powerful GPUs make for insanely fast brute-force software (eg: whitepixel2) I recently did a round of password strengthening, even for accounts that aren&#8217;t immediately vulnerable to 30 billion MD5s a second (yes!) attacks. I then found then whenever I sent mail using authenticated SMTP my mail server [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://jhische.com/dailydropcap/O-10-cap.png" title="Daily Drop Cap by Jessica Hische" align="left" alt="O"/>n the back of reading how affordable and powerful GPUs make for insanely fast brute-force software (eg: <a href="http://blog.zorinaq.com/?e=43">whitepixel2</a>) I recently did a round of password strengthening, even for accounts that aren&#8217;t immediately vulnerable to 30 billion MD5s a second (yes!) attacks.</p>
<p>I then found then whenever I sent mail using authenticated SMTP my mail server would lock up with <code>saslauthd</code> chewing the CPU. This authentication daemon is the glue between the MTA (<a href="http://www.exim.org/">Exim</a>) and the IMAP server (<a href="http://www.courier-mta.org/imap/">Courier</a>) &#8211; it logs into the IMAP service to test the SMTP user&#8217;s credentials. This little kink of indirection comes about because the IMAP daemon is downstream from the Exim host, in a <a href="http://en.wikipedia.org/wiki/FreeBSD_jail">BSD jail</a> host, so its own authentication mechanisms aren&#8217;t visible to the MTA.</p>
<p>My new mail password contained a double-quote mark, which made me wonder if the password wasn&#8217;t being quoted properly. Testing a bit with <code>openssl</code>:<br />
<code><br />
$ openssl s_client -starttls smtp -connect localhost:25<br />
CONNECTED(00000003)<br />
---<br />
250 HELP<br />
EHLO localhost<br />
250-svc9.zomo.co.uk Hello localhost [127.0.0.1]<br />
250-SIZE 52428800<br />
250-PIPELINING<br />
250-AUTH PLAIN LOGIN<br />
250 HELP<br />
AUTH PLAIN AGZvbwAi < -- this is Base64 for username foo, password "</p>
<p>[ hang ]</p>
<p></code><br />
Compiling a </code><code>-g</code> debug variant of the daemon and aiming <code>gdb</code> at it:<br />
<code><br />
$ sudo gdb /usr/local/sbin/saslauthd-debug 97103<br />
GNU gdb 6.1.1 [FreeBSD]<br />
Copyright 2004 Free Software Foundation, Inc.<br />
...<br />
(gdb) bt<br />
#0  0x284250d1 in strchr () from /lib/libc.so.7<br />
#1  0x0804a823 in qstring ()<br />
#2  0x0804ac45 in auth_rimap ()<br />
#3  0x0804f8e3 in do_auth ()<br />
#4  0x0804e1f4 in do_request ()<br />
#5  0x0804e53b in ipc_loop ()<br />
#6  0x0805018d in main ()<br />
</code></p>
<p>What&#8217;s <code>qstring()</code>? It&#8217;s a function for escaping the quote marks in strings passed to the IMAP daemon. Turns out count-the-quotemark logic wasn&#8217;t properly advancing along the string, so it would sit there spinning forever.<br />
<script src="https://gist.github.com/1020643.js"> </script><br />
Trivial patch<sup><a href="http://www.zomo.co.uk/2011/06/cyrus-saslauthd-and-passwords-containing-quote-marks/#footnote_0_404" id="identifier_0_404" class="footnote-link footnote-identifier-link" title="Gist if it&amp;#8217;s not inlined above">1</a></sup> fixes:<br />
<code><br />
$ openssl s_client -starttls smtp -connect localhost:25<br />
CONNECTED(00000003)<br />
---<br />
250 HELP<br />
EHLO localhost<br />
250-svc9.zomo.co.uk Hello localhost [127.0.0.1]<br />
250-SIZE 52428800<br />
250-PIPELINING<br />
250-AUTH PLAIN LOGIN<br />
250 HELP<br />
AUTH PLAIN AGZvbwAi<br />
535 Incorrect authentication data<br />
</code></p>
<p>Better :)</p>
<ol class="footnotes"><li id="footnote_0_404" class="footnote"><a href="https://gist.github.com/1020643">Gist</a> if it&#8217;s not inlined above</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2011/06/cyrus-saslauthd-and-passwords-containing-quote-marks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Competing webserver workloads</title>
		<link>http://www.zomo.co.uk/2011/02/competing-webserver-workloads/</link>
		<comments>http://www.zomo.co.uk/2011/02/competing-webserver-workloads/#comments</comments>
		<pubDate>Thu, 17 Feb 2011 21:57:30 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=363</guid>
		<description><![CDATA[Recently a client was receiving complaints that their busy server hosting both their WordPress sites and their OpenX1 banner delivery was underperforming. Specifically, sites including their banners were seeing page loads hang on them. If you&#8217;re in the business of selling banners this is bad news. There were reports of the WordPress sites being slow [...]]]></description>
			<content:encoded><![CDATA[<style type="text/css"><!--
th,td { font-size: 10px; align: center;}
li { margin-top: 0.25em; margin-right: 2em;}
.hr {margin-top: 0.25em; border-color: black; border-bottom-style: solid;}
.titre	{background: #20D0D0;color: #000000; font-weight: bold;}
.total	{background: #20D0D0;color: #ffff80;}
.frontend	{background: #e8e8d0;}
.backend	{background: #e8e8d0;}
.active0	{background: #ff9090;}
.active1	{background: #ffd020;}
.active2	{background: #ffffa0;}
.active3	{background: #c0ffc0;}
.active4	{background: #ffffa0;}
.active5	{background: #a0e0a0;}
.active6	{background: #e0e0e0;}
.backup0	{background: #ff9090;}
.backup1	{background: #ff80ff;}
.backup2	{background: #c060ff;}
.backup3	{background: #b0d0ff;}
.backup4	{background: #c060ff;}
.backup5	{background: #90b0e0;}
.backup6	{background: #e0e0e0;}
.rls      {letter-spacing: 0.2em; margin-right: 1px;}
table.tbl { border-collapse: collapse; border-style: none;}
table.tbl td { border-width: 1px 1px 1px 1px; border-style: solid solid solid solid; padding: 2px 3px; border-color: gray;}
table.tbl th { border-width: 1px; border-style: solid solid solid solid; border-color: gray;}
table.tbl th.pxname {background: #b00040; color: #ffff40; font-weight: bold; border-style: solid solid none solid; padding: 2px 3px; white-space: nowrap;}
table.tbl th.empty { border-style: none; empty-cells: hide; background: white;}
table.tbl th.desc { background: white; border-style: solid solid none solid; text-align: left; padding: 2px 3px;}
table.lgd { border-collapse: collapse; border-width: 1px; border-style: none none none solid; border-color: black;}
table.lgd td { border-width: 1px; border-style: solid solid solid solid; border-color: gray; padding: 2px;}
table.lgd td.noborder { border-style: none; padding: 2px; white-space: nowrap;}
-->
</style>
<p>Recently a client was receiving complaints that their busy server hosting both their <a href="http://wordpress.org/">WordPress</a> sites and their <a href="http://www.openx.org/">OpenX</a><sup><a href="http://www.zomo.co.uk/2011/02/competing-webserver-workloads/#footnote_0_363" id="identifier_0_363" class="footnote-link footnote-identifier-link" title=" advertising is a necessary evil, right? ">1</a></sup>  banner delivery was underperforming. Specifically, sites including their banners were seeing page loads hang on them. If you&#8217;re in the business of selling banners this is bad news. There were reports of the WordPress sites being slow too, but mostly from administrators<sup><a href="http://www.zomo.co.uk/2011/02/competing-webserver-workloads/#footnote_1_363" id="identifier_1_363" class="footnote-link footnote-identifier-link" title=" and that turned out to be a pagination issue ">2</a></sup> rather than site visitors.</p>
<p>I sorted out a bunch of <a href="http://www.zomo.co.uk/2011/01/timeouts-and-failing-fast/">request amplification issues</a> but still things still weren&#8217;t right, so I added a second server to help out. Instead of just chucking the combined traffic at both servers I used <a href="http://haproxy.1wt.eu/">HAProxy</a> to separate out the traffic to each, with a view to adding more OpenX servers as necessary.</p>
<p>Here&#8217;s what HAProxy&#8217;s stats had to say after some time running the sites split:</p>
<table class="tbl" width="100%">
<tbody>
<tr class="titre" align="center">
<th class="pxname" width="10%">wordpress</th>
</tr>
<tr class="titre" align="center">
<th rowspan="2"></th>
<th colspan="3">Queue</th>
<th colspan="3">Session rate</th>
<th colspan="5">Sessions</th>
<th colspan="2">Bytes</th>
</tr>
<tr class="titre" align="center">
<th>Cur</th>
<th>Max</th>
<th>Limit</th>
<th>Cur</th>
<th>Max</th>
<th>Limit</th>
<th>Cur</th>
<th>Max</th>
<th>Limit</th>
<th>Total</th>
<th>LbTot</th>
<th>In</th>
<th>Out</th>
</tr>
<tr class="active3" align="center">
<td>app01</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">-</td>
<td align="right">1</td>
<td align="right">367</td>
<td align="right"></td>
<td align="right">2</td>
<td align="right">454</td>
<td align="right">-</td>
<td align="right"><span class="rls">1</span>75<span class="rls">8</span>026</td>
<td align="right"><span class="rls">1</span>75<span class="rls">8</span>026</td>
<td align="right"><span class="rls">1</span>33<span class="rls">6</span>54<span class="rls">1</span>933</td>
<td align="right">3<span class="rls">0</span>06<span class="rls">2</span>77<span class="rls">7</span>594</td>
</tr>
</tbody>
</table>
<table class="tbl" width="100%">
<tbody>
<tr class="titre" align="center">
<th class="pxname" width="10%">openx</th>
</tr>
<tr class="titre" align="center">
<th rowspan="2"></th>
<th colspan="3">Queue</th>
<th colspan="3">Session rate</th>
<th colspan="5">Sessions</th>
<th colspan="2">Bytes</th>
</tr>
<tr class="titre" align="center">
<th>Cur</th>
<th>Max</th>
<th>Limit</th>
<th>Cur</th>
<th>Max</th>
<th>Limit</th>
<th>Cur</th>
<th>Max</th>
<th>Limit</th>
<th>Total</th>
<th>LbTot</th>
<th>In</th>
<th>Out</th>
</tr>
<tr class="active3" align="center">
<td>app02</td>
<td align="right">0</td>
<td align="right">0</td>
<td align="right">-</td>
<td align="right">19</td>
<td align="right">45</td>
<td align="right"></td>
<td align="right">3</td>
<td align="right">75</td>
<td align="right">-</td>
<td align="right"><span class="rls">5</span>58<span class="rls">8</span>327</td>
<td align="right"><span class="rls">5</span>58<span class="rls">8</span>293</td>
<td align="right"><span class="rls">4</span>21<span class="rls">6</span>68<span class="rls">7</span>748</td>
<td align="right">1<span class="rls">1</span>87<span class="rls">8</span>95<span class="rls">1</span>168</td>
</tr>
</tbody>
</table>
<p>Some of these I found unsurprising &#8211; WordPress serves a higher volume of data, it is content heavy compared to banner delivery and related click handling. Conversely the inbound data volume for OpenX is up because it&#8217;s loaded with click information.</p>
<p>What&#8217;s interesting is that the WordPress sites have a higher maximum concurrent session count, yet the total sessions is far higher for the OpenX banners. This illustrates the benefit of separating out different server loads: one server is churning away pushing out fat content and even when heavily cached this burns enough resource that requests get queued and gum up, whilst another is fielding quick-in quick-out requests. When it&#8217;s not contending with its laggard sibling it can get on with its business unhindered.</p>
<p>Ultimately the visibility HAProxy affords beats an Apache <a href="http://httpd.apache.org/docs/2.2/mod/mod_status.html">scoreboard</a> when that Apache is fielding two differently focused workloads.</p>
<ol class="footnotes"><li id="footnote_0_363" class="footnote"> advertising is a necessary evil, right? </li><li id="footnote_1_363" class="footnote"> and that turned out to be a <a href="http://twitter.com/zomoco/status/32487132966686720">pagination</a> issue </li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2011/02/competing-webserver-workloads/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Timeouts and failing fast</title>
		<link>http://www.zomo.co.uk/2011/01/timeouts-and-failing-fast/</link>
		<comments>http://www.zomo.co.uk/2011/01/timeouts-and-failing-fast/#comments</comments>
		<pubDate>Sun, 23 Jan 2011 20:57:24 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=301</guid>
		<description><![CDATA[&#8220;Integration points are the number-one killer of systems&#8221; &#8211; Release It!, Michael Nygard Last week I had two different web systems fail in a similar way. One was a single box running two busy WordPress sites, another was a largish multi-tier publishing cluster. Both dropped off air because they didn&#8217;t handle the failure of a [...]]]></description>
			<content:encoded><![CDATA[<blockquote><p>&#8220;Integration points are the number-one killer of systems&#8221; &#8211; <a href="http://pragprog.com/titles/mnee/release-it">Release It!</a>, Michael Nygard</p></blockquote>
<p>Last week I had two different web systems fail in a similar way. One was a single box running two busy <a href="http://wordpress.org/">WordPress</a> sites, another was a largish multi-tier publishing cluster. Both dropped off air because they didn&#8217;t handle the failure of a remote system very well. In particular, both had the webserver waiting on a HTTP request to a foreign site to complete before returning a page to the client.</p>
<p>The architecture issues with this kind of request amplification are reasonably clear, and can sometimes be avoided. Data ingest from other systems can often execute asynchronously in another process. The cluster mentioned has a set of machines dedicated to just this, distributing the data they retrieve from remote systems via database and shared filesystem ready for the webservers to use when building pages.</p>
<p>However, in the situations where it is necessary for a webserver to dial out to another system at request time then it&#8217;s worth being really paranoid about how that outbound request works and untrusting of the reply. The particular problem here was lack of timeouts.</p>
<p>Here, both systems were running <a href="http://httpd.apache.org/docs/2.2/mod/prefork.html">mpm_prefork</a> <a href="http://httpd.apache.org">Apache</a>. Both were serving a request that made a HTTP call somewhere else before returning the page to the client<sup><a href="http://www.zomo.co.uk/2011/01/timeouts-and-failing-fast/#footnote_0_301" id="identifier_0_301" class="footnote-link footnote-identifier-link" title="One of the WordPress sites was doing this in every page&amp;#8217;s footer. And not caching the result. Better still, it was contacting the other WordPress site on the same server. This almost guarantees the request won&amp;#8217;t return when the shared webserver gets busy since there may be no spare server slots to accept the second request. Ouch.">1</a></sup>. Last week the remote sites that both these systems contact had outages, leaving Apache waiting for the reply up until the request timed out.</p>
<p>However, with no timeout configured that wait is effectively infinite. Long enough for these hanging Apache processes to consume all the available slots of the webserver, resulting an interesting set of observations:</p>
<ul>
<li>New TCP connections to the server just hang.</li>
<li>Server load is low, because the load measures runnable processes (and, on Linux, uninterruptible sleeping processes), and these hanging processes are just sleeping, waiting on <code>poll(2)</code> or <code>select(2)</code>.</li>
<li>No errors are logged by Apache or the application code because they haven&#8217;t failed yet.<sup><a href="http://www.zomo.co.uk/2011/01/timeouts-and-failing-fast/#footnote_1_301" id="identifier_1_301" class="footnote-link footnote-identifier-link" title="If you don&amp;#8217;t run Apache hot, then you&amp;#8217;d see a &amp;#8220;I&amp;#8217;ve reached MaxClients&amp;#8221; message in the error log, but not much else.">2</a></sup> </li>
</ul>
<p>Here&#8217;s some <code>vmstat</code> during such a wedge:<br />
<code><br />
procs -----------memory---------- ---swap-- -----io---- -system-- ----cpu----<br />
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa<br />
 0  0 140580  56528  58168 516184    0    0     0     0 1026   78  0  0 100  0  0<br />
 0  0 140580  56528  58168 516184    0    0     0     0 1032   80  0  0 100  0  0<br />
 0  0 140580  56528  58168 516184    0    0     0     0 1031   78  0  0 100  0  0<br />
</code><br />
&#8220;It was quiet. <strong>Too</strong> quiet&#8221;. Hook up <code>gdb</code> and you can see what&#8217;s going on:<br />
<code><br />
(gdb) bt<br />
#0  0x00002aafffb7d14f in poll () from /lib64/libc.so.6<br />
#1  0x00002ab0090b3930 in Curl_select () from /usr/lib64/libcurl.so.3<br />
#2  0x00002ab0090ac4bc in Curl_perform () from /usr/lib64/libcurl.so.3<br />
#3  0x00002ab00850591b in zif_curl_exec () from /etc/httpd/modules/libphp5.so<br />
#4  0x00002ab0086663b2 in ?? () from /etc/httpd/modules/libphp5.so<br />
#5  0x00002ab00865651c in execute () from /etc/httpd/modules/libphp5.so<br />
#6  0x00002ab00865dc09 in ?? () from /etc/httpd/modules/libphp5.so<br />
#7  0x00002ab00865651c in execute () from /etc/httpd/modules/libphp5.so<br />
#8  0x00002ab008688750 in ?? () from /etc/httpd/modules/libphp5.so<br />
#9  0x00002ab00865651c in execute () from /etc/httpd/modules/libphp5.so<br />
#10 0x00002ab00865dc09 in ?? () from /etc/httpd/modules/libphp5.so<br />
#11 0x00002ab00865651c in execute () from /etc/httpd/modules/libphp5.so<br />
#12 0x00002ab00865c11e in ?? () from /etc/httpd/modules/libphp5.so<br />
#13 0x00002ab00865651c in execute () from /etc/httpd/modules/libphp5.so<br />
#14 0x00002ab0086395de in zend_execute_scripts () from /etc/httpd/modules/libphp5.so<br />
#15 0x00002ab0085fe697 in php_execute_script () from /etc/httpd/modules/libphp5.so<br />
#16 0x00002ab0086b6ad6 in ?? () from /etc/httpd/modules/libphp5.so<br />
#17 0x00002aaffdbb7a4a in ap_run_handler ()<br />
#18 0x00002aaffdbbaed8 in ap_invoke_handler ()<br />
#19 0x00002aaffdbc578a in ap_internal_redirect ()<br />
#20 0x00002ab0069ffbc0 in ap_make_dirstr_parent () from /etc/httpd/modules/mod_rewrite.so<br />
#21 0x00002aaffdbb7a4a in ap_run_handler ()<br />
#22 0x00002aaffdbbaed8 in ap_invoke_handler ()<br />
#23 0x00002aaffdbc5938 in ap_process_request ()<br />
#24 0x00002aaffdbc2b70 in ?? ()<br />
#25 0x00002aaffdbbecd2 in ap_run_process_connection ()<br />
#26 0x00002aaffdbc9789 in ?? ()<br />
#27 0x00002aaffdbc9a1a in ?? ()<br />
#28 0x00002aaffdbc9ad0 in ?? ()<br />
#29 0x00002aaffdbca7bb in ap_mpm_run ()<br />
#30 0x00002aaffdba4e48 in main ()<br />
</code></p>
<p>Another kink is that a <a href="http://httpd.apache.org/docs/2.2/stopping.html#graceful">graceful</a> restart of Apache, via <code>SIGUSR1</code>, doesn&#8217;t work since a graceful restart waits for a request to finish &#8211; and these ones aren&#8217;t finishing. <code>apachectl</code> or <code>service(8)</code> scripts will exit but the hung processes remain. These long running wedged processes are also visible in <code>ps</code>:<br />
<code><br />
apache     580  0.0  0.3  30332  5492 ?        S    Jan02   0:00<br />
/usr/sbin/httpd<br />
</code><br />
and can be matched up with the hung connections via <code>netstat -anp</code><br />
<code><br />
tcp        0      0 172.18.74.113:50129         192.0.32.10:80<br />
    ESTABLISHED 580/httpd<br />
</code></p>
<p>This is a mostly a long winded way of pointing out the importance of timeouts on code that executes during a request, particularly when doing something non-local. Fail fast!</p>
<p>To keep the WordPress sites running I ran through the code adding <code>CURLOPT_CONNECTTIMEOUT</code>, <code>CURLOPT_TIMEOUT</code> settings to all the cURL calls I could find, and the development team took care of the code running on the cluster. Both have been stable since.</p>
<p>There are plenty of other pitfalls in these integration points between systems. Michael Nygard&#8217;s book, linked at top, makes a good survey of them alongside other stability antipatterns in complex systems. It&#8217;s a recommended read.</p>
<ol class="footnotes"><li id="footnote_0_301" class="footnote">One of the WordPress sites was doing this in every page&#8217;s footer. And not caching the result. Better still, it was contacting the other WordPress site on the same server. This almost guarantees the request won&#8217;t return when the shared webserver gets busy since there may be no spare server slots to accept the second request. Ouch.</li><li id="footnote_1_301" class="footnote">If you don&#8217;t run Apache hot, then you&#8217;d see a &#8220;I&#8217;ve reached <code>MaxClients</code>&#8221; message in the error log, but not much else.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2011/01/timeouts-and-failing-fast/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FreeBSD, gettext, libintl and bash</title>
		<link>http://www.zomo.co.uk/2010/10/freebsd-gettext-libintl-and-bash/</link>
		<comments>http://www.zomo.co.uk/2010/10/freebsd-gettext-libintl-and-bash/#comments</comments>
		<pubDate>Mon, 25 Oct 2010 07:06:31 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=265</guid>
		<description><![CDATA[Login surprise! Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994 The Regents of the University of California. All rights reserved. FreeBSD 8.0-RELEASE-p4 (GENERIC) #0: Mon Jul 12 20:22:27 UTC 2010 /libexec/ld-elf.so.1: Shared object "libintl.so.8" not found, required by "bash" $ What&#8217;s happened here is that gettext (which provides libintl.so) has been upgraded without [...]]]></description>
			<content:encoded><![CDATA[<p>Login surprise!</p>
<pre>Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
        The Regents of the University of California.  All rights reserved.

FreeBSD 8.0-RELEASE-p4 (GENERIC) #0: Mon Jul 12 20:22:27 UTC 2010

/libexec/ld-elf.so.1: Shared object "libintl.so.8" not found, required by "bash"
$
</pre>
<p>What&#8217;s happened here is that <a href="http://www.gnu.org/software/gettext/"><code>gettext</code></a> (which provides <code>libintl.so</code>) has been upgraded without its dependencies noticing (read: I messed up some package maintenance). These dependencies are linked against a specific version of this library that&#8217;s now gone. One of these dependencies is <a href="http://www.gnu.org/software/bash/"><code>bash</code></a>, my preferred shell.</p>
<p>Having your shell asplode like that is ungood. If <code>bash</code> has been set as my default shell then I wouldn&#8217;t be able to log in at all! This is a risk of relying on software that isn&#8217;t part of FreeBSD&#8217;s core to absolutely always work across system maintenance. <code>bash</code> is a third-party <a href="http://www.freebsd.org/ports/index.html">port</a>, and it&#8217;s prudent to anticipate package management fail<sup><a href="http://www.zomo.co.uk/2010/10/freebsd-gettext-libintl-and-bash/#footnote_0_265" id="identifier_0_265" class="footnote-link footnote-identifier-link" title="because all package management sucks at some point, yes?">1</a></sup>. </p>
<p>To side-step this risk I tend to set my shell to something that <i>is</i> native to a FreeBSD release (plain ole&#8217; <code>/bin/sh</code>) and adding the following in my <code>.profile</code>, to test if <code>bash</code> is indeed working before running it:</p>
<p><code>/usr/local/bin/bash -c true &#038;&#038; exec /usr/local/bin/bash</code></p>
<p>And to fix all the other ports that are now broken:</p>
<p><code> $ sudo portmaster -r -R devel/gettext</code></p>
<ol class="footnotes"><li id="footnote_0_265" class="footnote">because all package management sucks at some point, yes?</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2010/10/freebsd-gettext-libintl-and-bash/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>cron</title>
		<link>http://www.zomo.co.uk/2010/02/cron/</link>
		<comments>http://www.zomo.co.uk/2010/02/cron/#comments</comments>
		<pubDate>Wed, 24 Feb 2010 09:18:37 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=217</guid>
		<description><![CDATA[Obviously cron jobs are abundantly useful for so many things, all the way from basic housekeeping up to big application functionality. They&#8217;re also the source of plenty of flail. What do I mean? They are neither code nor data, so often get overlooked, or shonkily installed, by application deployment tools They run with a minimal [...]]]></description>
			<content:encoded><![CDATA[<p>Obviously cron jobs are abundantly useful for so many things, all the way from basic housekeeping up to big application functionality.</p>
<p>They&#8217;re also the source of plenty of flail. What do I mean?</p>
<ul>
<li>They are neither code nor data, so often get overlooked, or shonkily installed, by application deployment tools</li>
<li>They run with a minimal environment that can catch out the unwary: scripts that work in interactive shell sometimes don&#8217;t from cron</li>
<li>The default behaviour of mailing output to the cronjob owner generates large amounts of mail that gets ignored, filtered or bounced</li>
<li>Jobs can fail silently and no-one notices until, say, you need to restore that backup that hasn&#8217;t run for last six months</li>
<li>Jobs that helpfully append their output to a log commonly don&#8217;t rotate that log</li>
<li>It&#8217;s easy to have jobs overlapping if they get stuck or take longer than expected to complete. This is a splendid way of wedging a machine.</li>
</ul>
<p>The mail aspect is a particular peeve. In some jobs my mailbox has enjoyed several thousand cron generated mails a day, and there&#8217;s no way I&#8217;m able to accurately look at each one and react to it. Mostly they contain expected output from successful job execution, so they&#8217;re easy to skip. But I don&#8217;t trust my eyes to get that right all the time.</p>
<p>One approach to this is to arrange for jobs to only send mail on error. This is an improvement, but can lead into thinking that a job is happily succeeding when in fact it&#8217;s either not running or the only-on-error logic is bust. Since cron jobs often cover essential system tasks like backing up, syncing data around and reporting it&#8217;s vital that they don&#8217;t fail silently.</p>
<p> I&#8217;ve worked somewhere that tackled this by collating cron-generated mails from diverse systems into a system mailbox and pattern matching them for failure signs. This seems slightly dubious &#8212; it&#8217;s fragile and labour intensive  &#8212; but at least the system also flagged if expected jobs failed to arrive and got our inboxes tamed. </p>
<p>To tackle these problems I find myself writing wrappers for cronjobs. I&#8217;ve written several variants to meet different situation&#8217;s needs. Unhelpfully I call them all <code>cronwrap</code>.  These wrappers sets out to</p>
<ul>
<li>Engage the amazingly useful <a href="http://unixwiz.net/tools/lockrun.html"><code>lockrun</code></a> utility to guard against multiple execution of stuck crons</li>
<li>Place cron output into timestamped logs that can be both aged out and made available to interested parties</li>
<li>Hook into local monitoring systems:
<ol>
<li>On execution, update a run counter (SNMP data or some simple text file)</li>
<li>On failure, send a SNMP trap or leave some bait for Nagios. Also, update a fail counter</li>
<li>If <code>lockrun</code> has prevented a job running owing to overlap, send a SNMP trap or similarly bait Nagios</li>
</ol>
</li>
<li>If required, send output by mail somewhere (sometimes this is necessary, even with the concerns listed above)</li>
</ul>
<p>So, nothing surprising there. Using such wrappers helps keep cron jobs tamed and reliable, and it&#8217;s monitoring them near to where the action occurs, rather than mediating via SMTP.</p>
<p>This is hardly invention either, there&#8217;s <a href="http://www.google.com/codesearch?q=cronwrap&#038;hl=en&#038;btnG=Search+Code">plenty</a> of prior art with different nuances in behaviour to meet the needs of different environments. Perhaps I&#8217;ll merge the variants of my efforts and publish too.</p>
<p>What&#8217;s curious is that this functionality isn&#8217;t available inside the cron daemon<sup><a href="http://www.zomo.co.uk/2010/02/cron/#footnote_0_217" id="identifier_0_217" class="footnote-link footnote-identifier-link" title=" To be clear, I&amp;#8217;m talking about the BSD cron written by Paul Vixie. None of the variants I&amp;#8217;ve seen address these concerns either. I&amp;#8217;d love to know if there&amp;#8217;s any I&amp;#8217;ve missed.">1</a></sup> itself. It is perfectly placed to catch exit status, divert output and know if a job has overrun; and would remove the need for all this additional monkeying to make jobs reliable and well behaved. If my C wasn&#8217;t just read-only I&#8217;d have a crack at it!</p>
<p>There, I&#8217;ve finally condensed all my cron rant into one sustained piece.</p>
<p><strong>Update:</strong> I posted a cron wrapper at <a href="https://github.com/zomo/cronwrap">https://github.com/zomo/cronwrap</a>.</p>
<ol class="footnotes"><li id="footnote_0_217" class="footnote"> To be clear, I&#8217;m talking about the BSD cron written by Paul Vixie. None of the variants I&#8217;ve seen address these concerns either. I&#8217;d love to know if there&#8217;s any I&#8217;ve missed.</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2010/02/cron/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>SOAP in unexpected &#8220;actually, quite easy&#8221; incident.</title>
		<link>http://www.zomo.co.uk/2009/09/soap-in-unexpected-actually-quite-easy-incident/</link>
		<comments>http://www.zomo.co.uk/2009/09/soap-in-unexpected-actually-quite-easy-incident/#comments</comments>
		<pubDate>Wed, 30 Sep 2009 21:02:18 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>
		<category><![CDATA[web]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=203</guid>
		<description><![CDATA[In web service access shuffle, today&#8217;s mission is introducing large N number of new backend pools, traffic rules and virtual servers to Zeus ZXTM balancers. No time for monkeying around in the web UI, better check out their well documented API. It uses SOAP, which I&#8217;ve never got busy with before &#8211; slightly apprehensive. The [...]]]></description>
			<content:encoded><![CDATA[<p>In web service access shuffle, today&#8217;s mission is introducing large N number of new backend pools, traffic rules and virtual servers to Zeus <a href="http://www.zeus.com/products/zxtm/">ZXTM</a> balancers. No time for monkeying around in the web UI, better check out their <a href="http://knowledgehub.zeus.com/media/5.1/ZXTM_5.1_Control_API.pdf">well documented</a> API. It uses <a href="http://en.wikipedia.org/wiki/SOAP">SOAP</a>, which I&#8217;ve never got busy with before &#8211; slightly apprehensive.</p>
<p>The reference documentation has examples in Perl and PHP which got me so far, but I&#8217;m most comfortable in Ruby now, and was happy to find <a href="http://knowledgehub.zeus.com/code/2009/04/09/ruby_and_soap_example_2"><sup><a href="http://www.zomo.co.uk/2009/09/soap-in-unexpected-actually-quite-easy-incident/#footnote_0_203" id="identifier_0_203" class="footnote-link footnote-identifier-link" title="I was going to paste example code, but this&amp;#8217;ll do">1</a></sup> this</a> pointer to using the <a href="http://dev.ctor.org/soap4r">soap4r</a> library.</p>
<p>Chief bonus here is the <code>wsdl2ruby.rb</code> tool that&#8217;ll transform the <a href="http://www.w3.org/TR/wsdl">WSDL</a> data into Ruby objects with heirarchy, attribute accessors and everything else to make operating the API really comfortable. If your WSDL is a moving target during development it&#8217;ll even do this on the fly.</p>
<p>This meant getting the scripting done to configure the ZXTMs was pretty straightforward, without any faffing with the underlying access mech. Refreshing!</p>
<ol class="footnotes"><li id="footnote_0_203" class="footnote">I was going to paste example code, but this&#8217;ll do</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2009/09/soap-in-unexpected-actually-quite-easy-incident/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ipmitool for OSX</title>
		<link>http://www.zomo.co.uk/2009/09/ipmitool-for-osx/</link>
		<comments>http://www.zomo.co.uk/2009/09/ipmitool-for-osx/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 08:51:49 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=196</guid>
		<description><![CDATA[Nothing searchable in MacPorts, but found this. Update: Turns out this build is missing isol mode serial-on-LAN for IPMI 1.5 hosts1, and building the ipmitool distribution wasn&#8217;t so hard after all. Packaging systems have made me lazy! Dell R200 uses IPMI 1.5, Dell R410 uses 2.0. Both do SOL and remote power management well enough]]></description>
			<content:encoded><![CDATA[<p>Nothing searchable in <a href="http://www.macports.org/">MacPorts</a>, but found <a href="http://freebsdgirl.com/2008/07/ipmitool-for-osx.html">this</a>.</p>
<p>Update: Turns out this build is missing <code>isol</code> mode serial-on-LAN for IPMI 1.5 hosts<sup><a href="http://www.zomo.co.uk/2009/09/ipmitool-for-osx/#footnote_0_196" id="identifier_0_196" class="footnote-link footnote-identifier-link" title="Dell R200 uses IPMI 1.5, Dell R410 uses 2.0. Both do SOL and remote power management well enough">1</a></sup>, and building the <a href="http://ipmitool.sourceforge.net/">ipmitool</a> distribution wasn&#8217;t so hard after all. Packaging systems have made me lazy!</p>
<ol class="footnotes"><li id="footnote_0_196" class="footnote">Dell R200 uses IPMI 1.5, Dell R410 uses 2.0. Both do SOL and remote power management well enough</li></ol>]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2009/09/ipmitool-for-osx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>vxargs &#8211; visual parallel xargs</title>
		<link>http://www.zomo.co.uk/2009/09/vxargs-visual-parallel-xargs/</link>
		<comments>http://www.zomo.co.uk/2009/09/vxargs-visual-parallel-xargs/#comments</comments>
		<pubDate>Fri, 18 Sep 2009 07:34:36 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=182</guid>
		<description><![CDATA[Flag for vxargs, an xargs-a-like that runs its multiple command invocations in parallel and provides a (ncurses) histogram of the progress. Its companion program pattern provides an easy way to generate IP / hostnames based on a logical sequence. Together the make a reasonble way to run a command on a bunch of hosts and [...]]]></description>
			<content:encoded><![CDATA[<p>Flag for <a href="http://vxargs.sourceforge.net/">vxargs</a>, an xargs-a-like that runs its multiple command invocations in parallel and provides a (ncurses) histogram of the progress. Its companion program <a href="http://code.activestate.com/recipes/355531/">pattern</a> provides an easy way to generate IP / hostnames based on a logical sequence. Together the make a reasonble way to run a command on a bunch of hosts and collate the stdout, stderr and exit status of each.</p>
<p>As a same-same-but-different alternative to</p>
<ul>
<li><a href="http://www.theether.org/pssh/">pssh</a></li>
<li>That xterm multiplexer I can never remember the name of</li>
<li><a href="http://www.gnu.org/software/screen/">screen(1)</a> and <a href="http://en.wikipedia.org/wiki/Apple_Terminal">Terminal.app</a>&#8216;s send-to-many option</li>
<li>Quick and dirty shell scripts iterating over a host list</li>
<li><a href="http://www.capify.org/index.php/">Capistrano</a>&#8216;s shell (even on hosts that don&#8217;t run any other Ruby!)</li>
</ul>
<p>&#8230; it&#8217;s proving pretty solid.</p>
<p>Example:<br />
<code><br />
[admin@manage3 tmp]$ pattern.py foo[1-8] | vxargs -y -o ~/tmp ssh {} varnishadm -Tlocalhost:6082 ping<br />
</code></p>
<p>Terminal clears, and shows progress:<br />
<code><br />
8/8:ssh -l root foo8 varnishadm -Tlocalhost:6082 ping<br />
Done<br />
Done<br />
Done<br />
Done<br />
Done<br />
( 10s)  6: foo7<br />
Done<br />
</code><br />
and exits<br />
<code><br />
exit code 0: 7 job(s)<br />
exit code 1: 1 job(s)<br />
total number of jobs: 8<br />
</code><br />
Now you can inspect the output from each host, exit status and an overall failure list<br />
<code><br />
[admin@manage3 tmp]$ cat ~/tmp/abnormal_list<br />
foo5<br />
[admin@manage3 tmp]$ cat ~/tmp/foo5.err<br />
Warning: Permanently added 'foo5,10.221.11.0' (RSA) to the list of known hosts.<br />
connect(): Connection refused<br />
An error occured in receiving status.<br />
</code></p>
<p>Via <a href="http://chneukirchen.org/trivium/2009-09-13">Trivium</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2009/09/vxargs-visual-parallel-xargs/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>irssi client certificate patch</title>
		<link>http://www.zomo.co.uk/2009/09/irssi-client-certificate-patch/</link>
		<comments>http://www.zomo.co.uk/2009/09/irssi-client-certificate-patch/#comments</comments>
		<pubDate>Thu, 17 Sep 2009 07:18:21 +0000</pubDate>
		<dc:creator>lemon</dc:creator>
				<category><![CDATA[sw]]></category>

		<guid isPermaLink="false">http://www.zomo.co.uk/?p=169</guid>
		<description><![CDATA[Patch for irssi so it can prompt for your X509 client certificate correctly.]]></description>
			<content:encoded><![CDATA[<p><a href="http://bugs.irssi.org/index.php?do=details&#038;task_id=305">Patch</a> for <a href="http://www.irss.org">irssi</a> so it can prompt for your X509 client certificate correctly.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zomo.co.uk/2009/09/irssi-client-certificate-patch/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

