<?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>Too Far Afield</title>
	<atom:link href="http://blog.nachtarbeiter.net/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.nachtarbeiter.net</link>
	<description></description>
	<lastBuildDate>Tue, 16 Feb 2010 07:02:12 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Monitoring PowerDNS via the internal web server</title>
		<link>http://blog.nachtarbeiter.net/2010/02/16/monitoring-powerdns-via-the-internal-web-server/</link>
		<comments>http://blog.nachtarbeiter.net/2010/02/16/monitoring-powerdns-via-the-internal-web-server/#comments</comments>
		<pubDate>Tue, 16 Feb 2010 07:02:12 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[apache]]></category>
		<category><![CDATA[base64]]></category>
		<category><![CDATA[dns]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[pdns]]></category>
		<category><![CDATA[powerdns]]></category>

		<guid isPermaLink="false">http://stage.nachtarbeiter.net/?p=585</guid>
		<description><![CDATA[If you want to stay informed about the current status of your PowerDNS server, there is no need to scan the logs or use third party tools like logcheckd. Actually, you might want to do this anyway, but PowerDNS provides an internal web server, which summarizes all the status information (including log messages) in a [...]]]></description>
			<content:encoded><![CDATA[<p>If you want to stay informed about the current status of your <cite>PowerDNS</cite> server, there is no need to scan the logs or use third party tools like <code>logcheckd</code>. Actually, you might want to do this anyway, but <cite>PowerDNS</cite> provides an internal web server, which summarizes all the status information (including log messages) in a very nice and compact way for you to view.</p>
<p>By default, the web server will listen on port <code>8081</code> on <code>localhost</code>. That means, that you can&#8217;t view the status information from the outside network. To view the page, you could use a command line browser like <code>lynx</code>. You could change the interface of the web server to a public IP address, but this is <strong>very insecure</strong> and not recommended. The <cite>PowerDNS</cite> web server provides some sensitive information about your DNS server and you should not expose this information to the public. Also, the <cite>PowerDNS</cite> web server is probably not as thoroughly tested and hardened as <abbr title="for example">e.g.</abbr> <cite>Apache</cite> or <cite>nginx</cite>.  Another problem is, that you can only specify a single password and that you are limited to basic authentication, which is not very secure.</p>
<p>There is a secure way to retrieve the information provided by <cite>PowerDNS</cite> from outside your DNS server host. You could use <cite>Apache</cite>, <cite>nginx</cite> or any other web server you like as a proxy server. That way you can use more advanced authentication methods built into that web server to secure your status page. I will now show you how to do this using Apache 2 on Debian. We&#8217;ll need <code>mod_proxy</code>, <code>mod_proxy_http</code> and <code>mod_headers</code> enabled on the Apache 2 server. If you do not want to run an instance of Apache 2 on your DNS server, you could use an SSL tunnel or a secure back channel link to a remote Apache server to retrieve the status page. But this is beyond the scope of this post.</p>
<p>First, enable the internal <cite>PowerDNS</cite> web server by editing the configuration file.</p>
<ol class="code">
<li><code>webserver=yes</code></li>
<li><code>webserver-address=127.0.0.1</code></li>
<li><code>webserver-port=8081</code></li>
<li><code>webserver-password=PowerDNS</code></li>
</ol>
<p>This tells <cite>PowerDNS</cite> to run the internal web server on port <code>8081</code> of the <code>localhost</code> interface. The user name will be <code>admin</code> and the password will be <code>PowerDNS</code>. Of course you should change the password to something more secure, it&#8217;s just an example. After a restart of <cite>PowerDNS</cite> you can connect to your server from your DNS server host. The password is optional, but it&#8217;s safer that way, especially in an environment where you&#8217;ve got other users on your DNS server box.</p>
<p>Now install and enable the required modules of Apache 2 by executing the following commands.</p>
<ol class="code">
<li><code>apt-get install libapache2-mod-proxy-html</code></li>
<li><code>a2enmod proxy</code></li>
<li><code>a2enmod proxy_http</code></li>
<li><code>a2enmod headers</code></li>
</ol>
<p>The last module is only needed, if you set a password for your internal web server as recommended above. I assume that you&#8217;ve got some kind of virtual host configuration for your Apache server. You&#8217;ll want to add a new virtual host for the DNS status information. If you use a subdirectory, navigation might be a bit odd. Let&#8217;s add a new site to the available sites.</p>
<ol class="code">
<li><code>vi /etc/apache2/sites-available/status.dns.example.net</code></li>
<li><code>&lt;VirtualHost 192.168.0.1:80&gt;</code></li>
<li><code>        ServerName status.dns.example.net</code></li>
<li><code>        DocumentRoot /var/www/</code></li>
<li><code></code></li>
<li><code>        ProxyRequests Off</code></li>
<li><code>        &lt;proxy *&gt;</code></li>
<li><code>               Order deny,allow</code></li>
<li><code>               Allow from all</code></li>
<li><code>                ForceType 'text/html; charset=UTF-8'</code></li>
<li><code>        &lt;/proxy&gt;</code></li>
<li><code>        ProxyPass / http://localhost:8081</code></li>
<li><code>        ProxyPassReverse / http://localhost:8081</code></li>
<li><code></code></li>
<li><code>&lt;/VirtualHost&gt;</code></li>
</ol>
<p>Alright, so what are we doing here? Basically, we&#8217;re adding a new virtual host <code>status.dns.example.net</code> on our main interface of <code>dns.example.net</code>. We&#8217;re using a reverse proxy to to send all requests coming from the outside to our internal <cite>PowerDNS</cite> web server on port <code>8081</code>. Also, we&#8217;re forcing a <code>text/html</code> content type in the proxy request filter, because otherwise we would just get <code>text/plain</code> and we would simply see the source code, which is probably not what you want. Let&#8217;s enable the site for a test:</p>
<ol class="code">
<li><code>a2ensite status.dns.example.net</code></li>
<li><code>/etc/init.d/apache2 reload</code></li>
</ol>
<p>If you point your web browser to <code>status.dns.example.net</code> you should now see the internal status page of <cite>PowerDNS</cite>. If you set a password above, you will see a password dialogue. This is the password dialogue sent by the <cite>PowerDNS</cite> web server. The user name is <code>admin</code> and the password is your password. Try it out now, because we&#8217;ll get rid of this in a minute.</p>
<p>For security reasons, you probably want to use Apache 2 for authentication. E.g. you might want use a SSL connection and authenticate your co-workers using the internal LDAP server of your company intranet. You might even stay with the insecure basic authentication method, but use other user names. This is entirely up to you and beyond the scope of this post. Consult the Apache 2 documentation on how to do this. What you probably don&#8217;t want to do, however, is to authenticate twice (first your secure authentication method and then <cite>PowerDNS</cite> basic authentication. Luckily, we can configure the Apache 2 proxy to do the authentication for us. This is a bit tricky, though.<br />
To authenticate at the <cite>PowerDNS</cite> server, Apache 2 needs to send an additional <code>Authorization</code> header line to the <cite>PowerDNS</cite> server with every request it handles. We use the <code>RequestHeader</code> directive to override any existing <code>Authorization</code> header with our own authentication data. Add the following lines just before the end of the virtual host container.</p>
<ol class="code">
<li><code>        &lt;Location /&gt;</code></li>
<li><code>                RequestHeader Set Authorization "Basic YWRtaW46UG93ZXJETlM="</code></li>
<li><code>        &lt;/Location&gt;</code></li>
</ol>
<p>The above example works only for our example password, which is <code>PowerDNS</code>. Try it for a test. This is, because part of the header value is encrypted using the <code>base64</code> algorithm. You need to change the encrypted part <code>YWRtaW46UG93ZXJETlM=</code>. In plain text the encrypted string would read <code>admin:PowerDNS</code>, where <code>admin</code> is the user name and <code>PowerDNS</code> is the password. To use your own password, you need to encrypt the string <code>admin:yourownpassword</code> using the <code>base64</code> algorithm and replace our example string. Be sure to keep the <code>Basic</code> and the space. It is crucial for success, that you&#8217;ve got the right encrypted string. There are a number of <a href="http://www.motobit.com/util/base64-decoder-encoder.asp">online tools</a>, to encode and decode these strings. To ensure, that you&#8217;ve got the correct encryption method, encode the example string and compare it to the string above for a reference. If you&#8217;ve got the wrong string, it will not work.</p>
<p>Restart the Apache 2 server. To clear your password cache, restart your browser. Now surf to the site again. You will see, that the password dialogue is gone. Now, don&#8217;t forget to secure the page again using Apache 2. Under any circumstances, do <em>not</em> use <code>Directory</code> containers in the configuration. These will not apply to the proxy, because the proxy is not a physical directory on your server. Use <code>Location</code> containers like we did above for setting the <code>RequestHeader</code> directive. Also, you could still use insecure basic authentication to secure the page, if you wanted. It would work regardless of the <code>RequestHeader</code> magic.</p>
<h3>A light-weight alternative</h3>
<p>For those of you, who think that <cite>Apache</cite> is too heavy, here is an example for the <cite>nginx</cite> web server:</p>
<ol class="code">
<li><code>vi /etc/nginx/sites-available/status.dns.example.net</code></li>
<li><code>server {</code></li>
<li><code>   listen 192.168.0.1:80;</code></li>
<li><code>   server_name status.dns.example.net;</code></li>
<li><code>   root /var/www/nginx-default;</code></li>
<li><code>   location / {</code></li>
<li><code>      index index.html</code></li>
<li><code>      proxy_pass http://localhost:8081;</code></li>
<li><code>      proxy_redirect off;</code></li>
<li><code>      proxy_set_header Authorization "Basic YWRtaW46UG93ZXJETlM=";</code></li>
<li><code>   }</code></li>
<li><code>}</code></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://blog.nachtarbeiter.net/2010/02/16/monitoring-powerdns-via-the-internal-web-server/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Display MySQL query output on the command line</title>
		<link>http://blog.nachtarbeiter.net/2010/01/19/display-mysql-query-output-on-the-command-line/</link>
		<comments>http://blog.nachtarbeiter.net/2010/01/19/display-mysql-query-output-on-the-command-line/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 05:40:07 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[mysql]]></category>

		<guid isPermaLink="false">http://blog.nachtarbeiter.net/?p=887</guid>
		<description><![CDATA[If you are using the MySQL command line client regularly, the following scenario might be familiar to you: You run a select on a table, which contains a lot of fields. The output will not fit on one line, which means that it will be unreadable. Consider the following example:

mysql&#62; SELECT * FROM posts LIMIT [...]]]></description>
			<content:encoded><![CDATA[<p>If you are using the MySQL command line client regularly, the following scenario might be familiar to you: You run a select on a table, which contains a lot of fields. The output will not fit on one line, which means that it will be unreadable. Consider the following example:</p>
<ol class="code">
<li><code>mysql&gt; SELECT * FROM posts LIMIT 1;</code></li>
<li><code>+----+-------------+---------------------+---------------------+--------------------------------+--------------+-----------</code></li>
<li><code>----+--------------+----------+----------+-------------+----------------+-------------+---------------+-------------+----</code></li>
<li><code>-----+--------+---------------------+---------------------+-----------------------+-------------+-------+------------+----</code></li>
<li><code>-------+----------------+---------------+</code></li>
<li><code>| ID | post_author | post_date           | post_date_gmt       | post_content                   | post_title   | </code></li>
<li><code>post_category | post_excerpt | post_lat | post_lon | post_status | comment_status | ping_status | </code></li>
<li><code>post_password | post_name   | to_ping | pinged | post_modified       | post_modified_gmt   | </code></li>
<li><code>post_content_filtered | post_parent | guid  | menu_order | post_type | post_mime_type | </code></li>
<li><code>comment_count |</code></li>
<li><code><br />
</code></li>
<li><code>+----+-------------+---------------------+---------------------+--------------------------------+--------------+-----------</code></li>
<li><code>----+--------------+----------+----------+-------------+----------------+-------------+---------------+-------------+----</code></li>
<li><code>-----+--------+---------------------+---------------------+-----------------------+-------------+-------+------------+----</code></li>
<li><code>-------+----------------+---------------+</code></li>
<li><code><br />
|  1 |           1 | 2004-01-17 18:17:37 | 2004-01-17 16:17:37 | We'll see what time brings ... | Hello world! |             1 </code></li>
<li><code>|              |     NULL |     NULL | publish     | closed         | closed      |               | hello-world </code></li>
<li><code>|         |        | 2004-01-17 18:17:37 | 2004-01-17 16:17:37 |                       |           0 | /?p=1 </code></li>
<li><code>|          0 | post      |                |             0 |</code></li>
<li><code><br />
</code></li>
<li><code>+----+-------------+---------------------+---------------------+--------------------------------+--------------+-----------</code></li>
<li><code>----+--------------+----------+----------+-------------+----------------+-------------+---------------+-------------+----</code></li>
<li><code>-----+--------+---------------------+---------------------+-----------------------+-------------+-------+------------+----</code></li>
<li><code>-------+----------------+---------------+</code></li>
<li><code>1 row in set (0.00 sec)</code></li>
</ol>
<p>There is actually a nice solution for this. By default, the command line client uses horizontal mode to display the results of MySQL queries. If you use <code>\G</code> instead of <code>;</code> or <code>\g</code> at the end of the line, your query result will be displayed in vertical mode, which will look a lot better:</p>
<ol class="code">
<li><code>mysql&gt; SELECT * FROM posts LIMIT 1\G</code></li>
<li><code>*************************** 1. row ***************************</code></li>
<li><code>                   ID: 1</code></li>
<li><code>          post_author: 1</code></li>
<li><code>            post_date: 2004-01-17 18:17:37</code></li>
<li><code>        post_date_gmt: 2004-01-17 16:17:37</code></li>
<li><code>         post_content: We'll see what time brings ...</code></li>
<li><code>           post_title: Hello world!</code></li>
<li><code>        post_category: 1</code></li>
<li><code>         post_excerpt: </code></li>
<li><code>             post_lat: NULL</code></li>
<li><code>             post_lon: NULL</code></li>
<li><code>          post_status: publish</code></li>
<li><code>       comment_status: closed</code></li>
<li><code>          ping_status: closed</code></li>
<li><code>        post_password: </code></li>
<li><code>            post_name: hello-world</code></li>
<li><code>              to_ping: </code></li>
<li><code>               pinged: </code></li>
<li><code>        post_modified: 2004-01-17 18:17:37</code></li>
<li><code>    post_modified_gmt: 2004-01-17 16:17:37</code></li>
<li><code>post_content_filtered: </code></li>
<li><code>          post_parent: 0</code></li>
<li><code>                 guid: /?p=1</code></li>
<li><code>           menu_order: 0</code></li>
<li><code>            post_type: post</code></li>
<li><code>       post_mime_type: </code></li>
<li><code>        comment_count: 0</code></li>
<li><code>1 row in set (0.00 sec)</code></li>
</ol>
<p>While vertical output uses a lot more vertical space than the horizontal output, the vertical output is a lot more readable. Now you can probably see what I used as example query. It is actually the first post from this blog. Yes, this blog just got 6 years old <code>;)</code>.</p>
<p>If you want your command line client to use vertical mode by default, you can add <code>vertical</code> to the client section (<code>[client]</code>) of your <code>.my.cnf</code> file. This would look something like this:</p>
<ol class="code">
<li><code>[client]</code></li>
<li><code>vertical</code></li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://blog.nachtarbeiter.net/2010/01/19/display-mysql-query-output-on-the-command-line/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Introducing TwoZero</title>
		<link>http://blog.nachtarbeiter.net/2009/12/10/introducing-twozero/</link>
		<comments>http://blog.nachtarbeiter.net/2009/12/10/introducing-twozero/#comments</comments>
		<pubDate>Thu, 10 Dec 2009 17:17:11 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[25C3]]></category>
		<category><![CDATA[26C3]]></category>
		<category><![CDATA[CCC]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Pentabarf]]></category>
		<category><![CDATA[Python]]></category>
		<category><![CDATA[TwoZero]]></category>

		<guid isPermaLink="false">http://blog.nachtarbeiter.net/?p=884</guid>
		<description><![CDATA[Some of you might have already seen TwoZero running on my laptop last year at the 25th Chaos Communication Congress. It&#8217;s a very basic web application written utilizing the Django web development framework. It&#8217;s task is to provide meyou with a personal conference schedule. It imports a schedule XML file from Pentabarf, which is used [...]]]></description>
			<content:encoded><![CDATA[<p>Some of you might have already seen <cite>TwoZero</cite> running on my laptop last year at the <a href="https://events.ccc.de/congress/2008/">25th Chaos Communication Congress</a>. It&#8217;s a very basic web application written utilizing the <a href="http://www.djangoproject.com/">Django web development framework</a>. It&#8217;s task is to provide <strike>me</strike>you with a personal conference schedule. It imports a schedule XML file from <a href="http://pentabarf.org/">Pentabarf</a>, which is used to manage the conferences organized by the <a href="http://ccc.de/">Chaos Computer Club</a>. You can then select talks you&#8217;d like to attend. These talks will be presented to you in a separate personal schedule.</p>
<p>As the <a href="https://events.ccc.de/congress/2009/">26th Chaos Communication Congress</a> is just around the corner, I&#8217;ve set up a <a href="http://twozero.nachtarbeiter.net/">public instance of <cite>TwoZero</cite></a>. Try it out and tell me what you think. You can also download the source code (see the <cite>About</cite> section) and hopefully send in your excellent patches.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nachtarbeiter.net/2009/12/10/introducing-twozero/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Type Hinting in PHP</title>
		<link>http://blog.nachtarbeiter.net/2009/09/05/type-hinting-in-php/</link>
		<comments>http://blog.nachtarbeiter.net/2009/09/05/type-hinting-in-php/#comments</comments>
		<pubDate>Sat, 05 Sep 2009 03:26:21 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[fail]]></category>
		<category><![CDATA[oop]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[rant]]></category>
		<category><![CDATA[web development]]></category>

		<guid isPermaLink="false">http://blog.nachtarbeiter.net/?p=874</guid>
		<description><![CDATA[PHP 5 introduces Type Hinting. But it does so in the usual PHP way: It&#8217;s neither fish nor fowl. You&#8217;ll be exited at first when you discover the new feature. And then you&#8217;ll be disappointed. Because things do not work like you&#8217;d expect. Suppose you do something like this:

&#60;?php
&#160;
function foo ( string $bar) {
  [...]]]></description>
			<content:encoded><![CDATA[<p>PHP 5 introduces Type Hinting. But it does so in the usual PHP way: It&#8217;s neither fish nor fowl. You&#8217;ll be exited at first when you discover the new feature. And then you&#8217;ll be disappointed. Because things do not work like you&#8217;d expect. Suppose you do something like this:</p>
<ol class="code">
<li><code>&lt;?php</code></li>
<li><code>&nbsp;</code></li>
<li><code>function foo ( string $bar) {</code></li>
<li><code>   echo $bar;</code></li>
<li>}</li>
<li><code>foo ('Hello World!');</code></li>
<li><code>&nbsp;</code></li>
<li><code>?&gt;</code></li>
</ol>
<p>What happens, when you execute the above code? You will get a rather cryptic error message:</p>
<ol class="code">
<li><code>Catchable fatal error: Argument 1 passed to foo() must be an instance of string, string given.</code></li>
</ol>
<p>So the method expected a string as the first parameter and you passed a string to it, but PHP chose to throw up regardless. Great, isn&#8217;t it? Of course, the reason for this is right at the very bottom of the <a href="http://de.php.net/manual/en/language.oop5.typehinting.php">PHP documentation on Type Hinting</a>. All the way down the page below a number of examples:</p>
<p><cite>Type Hints can only be of the object and array  (since PHP 5.1) type. Traditional type hinting with int and string isn&#8217;t supported.</cite></p>
<p>Doh!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nachtarbeiter.net/2009/09/05/type-hinting-in-php/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Amazing Australian broadcasters</title>
		<link>http://blog.nachtarbeiter.net/2009/09/01/amazing-australian-broadcasters/</link>
		<comments>http://blog.nachtarbeiter.net/2009/09/01/amazing-australian-broadcasters/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 21:25:31 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[amazing]]></category>
		<category><![CDATA[Australia]]></category>
		<category><![CDATA[internet]]></category>
		<category><![CDATA[life]]></category>
		<category><![CDATA[radio]]></category>

		<guid isPermaLink="false">http://blog.nachtarbeiter.net/?p=870</guid>
		<description><![CDATA[Totally unrelated to anything, but it just came to my mind: Australian radio service is great. They&#8217;ve got great radio shows all through the night on a weekday presented by hosts with very strange Australian accents. I can get the whole Australian radio experience on a any European evening. In my bathroom. Or anywhere else. [...]]]></description>
			<content:encoded><![CDATA[<p>Totally unrelated to anything, but it just came to my mind: Australian radio service is great. They&#8217;ve got great radio shows all through the night on a weekday presented by hosts with very strange Australian accents. I can get the whole Australian radio experience on a any European evening. In my bathroom. Or anywhere else. <a href="http://triplej.net.au/">Australian radio</a>: Amazing! <a href="http://www.youtube.com/watch?v=_y36fG2Oba0">The internet</a>: Amazing! Australian radio and the internet combined: You guess what!</p>
<p>PS: I know that it&#8217;s early morning in Sydney right now. Never mind.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nachtarbeiter.net/2009/09/01/amazing-australian-broadcasters/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Printer-less printing</title>
		<link>http://blog.nachtarbeiter.net/2009/09/01/printer-less-printing/</link>
		<comments>http://blog.nachtarbeiter.net/2009/09/01/printer-less-printing/#comments</comments>
		<pubDate>Tue, 01 Sep 2009 21:09:43 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[environment]]></category>
		<category><![CDATA[life]]></category>
		<category><![CDATA[printing]]></category>

		<guid isPermaLink="false">http://blog.nachtarbeiter.net/?p=868</guid>
		<description><![CDATA[Sometime in February I got rid of my ink-jet printer. Ever since I&#8217;ve spent a total of 3,15 EUR on printing the occasional file, form or letter at a nearby copy-shop. Way cheaper than the ink cartridges I had to buy regularly (while I didn&#8217;t print that much, the printer used a lot of ink [...]]]></description>
			<content:encoded><![CDATA[<p>Sometime in February I got rid of my ink-jet printer. Ever since I&#8217;ve spent a total of 3,15 EUR on printing the occasional file, form or letter at a nearby copy-shop. Way cheaper than the ink cartridges I had to buy regularly (while I didn&#8217;t print that much, the printer used a lot of ink during self-cleaning operations). And a lot friendlier to the environment. Yay!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nachtarbeiter.net/2009/09/01/printer-less-printing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Checking mail quota during SMTP transaction in Exim</title>
		<link>http://blog.nachtarbeiter.net/2009/08/31/checking-mail-quota-during-smtp-transaction-in-exim/</link>
		<comments>http://blog.nachtarbeiter.net/2009/08/31/checking-mail-quota-during-smtp-transaction-in-exim/#comments</comments>
		<pubDate>Mon, 31 Aug 2009 15:15:21 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[Exim]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[mail]]></category>
		<category><![CDATA[quota]]></category>

		<guid isPermaLink="false">http://blog.nachtarbeiter.net/?p=667</guid>
		<description><![CDATA[Introduction
The Exim mail server comes with out of the box quota support. All you need to do is to set the quota, quota_warn_threshold and quota_warn_message options on your transport and you will be fine (see Chapter 26 of the Exim Specification). Combine this with a few custom database lookups and you&#8217;ve got a great way [...]]]></description>
			<content:encoded><![CDATA[<h3>Introduction</h3>
<p>The <a href="http://exim.org/"><cite>Exim</cite></a> mail server comes with out of the box quota support. All you need to do is to set the <code>quota</code>, <code>quota_warn_threshold</code> and <code>quota_warn_message</code> options on your <cite>transport</cite> and you will be fine (see <a href="http://www.exim.org/exim-html-current/doc/html/spec_html/ch26.html"><cite>Chapter 26</cite> of the <cite>Exim Specification</cite></a>). Combine this with a few custom database lookups and you&#8217;ve got a great way to handle your user&#8217;s mailbox quota. By utilizing some additional options and the power of <a href="http://www.regular-expressions.info/">regular expressions</a> you could even define different quotas for each folder of your user&#8217;s <cite><abbr title="Internet Message Access Protocol">IMAP</abbr></cite> mailboxes. </p>
<h3>The problem</h3>
<p>Using <cite>Exim</cite>&#8217;s quota management has a major drawback, though: Quota checking takes place <em>after</em> the message has been accepted for delivery. What does that mean in practise?</p>
<p>If the quota limit of a mailbox is exceeded, messages for this mailbox are still accepted for delivery, but deferred temporarily. At each queue run, <cite>Exim</cite> checks, if the quota limit is still exceeded. If the user has deleted mails from her mailbox since the last queue run, the mail will be delivered. If not, the mail will be deferred again. At some point, <cite>Exim</cite> will give up and finally bounce the mail back to the sender. How long <cite>Exim</cite> will try to deliver the message depends on your <cite>retry rules</cite>. While this is good for your user, because she has some more time to clear up her mailbox before she effectively looses mail, it is bad in a number of ways:</p>
<ul>
<li>The deferred mails add up to the queue and clutter it up.</li>
<li>If the user does not delete messages from her mailbox (e.g. she is no longer using it actively), messages will sit in your queue for a long time, before they are finally bounced back to the sender. During this time, the sender does not know about the status of the mail. You need to provide disk space for these mails. If you set up quota limits to better manage the disk space at your disposal, this may hit you hard.</li>
<li>If your user gets a lot of spam from faked sender addresses, you may generate a lot of <a href="http://en.wikipedia.org/wiki/Backscatter_%28e-mail%29">collateral spam</a> by bouncing her messages back to the faked sender addresses.</li>
</ul>
<h3>A possible solution</h3>
<p><cite>Exim</cite> were not <cite>Exim</cite>, if there wasn&#8217;t some way to get around this limitation and check quota right at <code>RCPT</code> time during the <cite><abbr title="Simple Mail Transfer Protocol">SMTP</abbr></cite> transaction. Actually, there are a number of ways to implement this. And all have pros and cons. I&#8217;d like to show you a way that is relatively easy to implement, but does have some minor issues.</p>
<p>Basically, the idea is to set up a database of those users that are over quota. You&#8217;d use an external script to periodically check, if a user exceeded her quota limit, and manage the database accordingly. You could use a flat file to store mailbox names of these users or &#8211; if you&#8217;re already using a relational database (e.g. <cite>MySQL</cite>, <cite>PostgreSQL</cite>) or an <cite><abbr title="Lightweight Directory Access Protocol">LDAP</abbr></cite> directory for mailbox management &#8211; add an additional property (e.g. <code>isOverQuota</code>) to your mailbox object.<br />
Additionally, you need to configure <cite>Exim</cite> to check our file or database during the <cite><abbr title="Simple Mail Transfer Protocol">SMTP</abbr></cite> transaction and reject an incoming message, if it is for a mailbox that is over quota. How to do this depends a bit on your current configuration. Chances are, you&#8217;re already verifying the recipient of a message before you accept it (check your <cite><abbr title="Access Control List">ACL</abbr></cite>s for <code>require verify recipient</code>). In this case, the fastest way to implement this in <cite>Exim</cite> is to add an additional <cite>router</cite> somewhere before (probably <em>immediately</em> before) the <cite>router</cite> that handles routing of messages to your user&#8217;s mailboxes (the router with the <code>quota</code> option). If you used a <cite>MySQL</cite> database it might look something like this:</p>
<ol class="code">
<li><code>virtual_mailbox_overquota:</code></li>
<li><code>   driver = redirect</code></li>
<li><code>   domains = +local_domains</code></li>
<li><code>   condition = ${if eqi{$local_part} {${lookup mysql {SELECT username FROM exim.mailbox WHERE username='$local_part' AND domainname='$domain' AND enabled='1' AND overquota='1' LIMIT 1}}}{yes}{no}}</code></li>
<li><code>   data = :fail: Mailbox is full, quota limit exceeded</code></li>
<li><code>   allow_fail</code></li>
</ol>
<p>Note: You&#8217;ll probably want to change the <code>domains</code> and <code>condition</code> options before you use this router in your configuration. But you get the idea, don&#8217;t you?</p>
<p>By default <cite>Exim</cite> calculates quota by adding the size of the new message to the size of the mailbox and comparing this to the quota limit of the mailbox (inclusive checking). This means that a user can&#8217;t go over quota. The mailbox will always remain below the quota limit. This is great, but it doesn&#8217;t work for us. Our script depends on users <em>going</em> over quota, because otherwise it would not detect the mailboxes that <em>are</em> over quota. Again, there are a number of possible solutions to this problem. You could increase the quota limit of every mailbox by 1% and check for mailboxes at 99%. Alternatively, you could disable inclusive quota checking. To do so, add the following option to the <cite>router</cite>, which handles routing of messages to your user&#8217;s mailboxes (the router with the <code>quota</code> option):</p>
<ol class="code">
<li><code>quota_is_inclusive = false</code></li>
</ol>
<h3>Testing the new configuration</h3>
<p>To test, if the new configuration works, you might use <cite>Exim</cite>&#8217;s basic address deliverability checking.</p>
<ol class="code">
<li><code>$<strong>exim -C exim.new.conf -f sender@example.org -bt not.over.quota@example.org</strong></code></li>
<li><code>not.over.quota@example.org</code><code></code></li>
<li><code>    router = virtual_mailbox, transport = appendfile</code></li>
<li><code>$<strong>exim -C exim.new.conf -f sender@example.org -bt exceeded.quota@example.org</strong></code></li>
<li><code>exceeded.quota@example.org is undeliverable: Mailbox is full, mailbox quota exceeded</code></li>
</ol>
<p>If you get anything close to the above, you&#8217;re probably okay. Of course you need to have a mailbox that exceeded its quota limit for this test to work.</p>
<h3>Some issues</h3>
<p>There are two minor problems with this solution. Depending on your situation, these might be acceptable or not. </p>
<p>First, there is the checking interval. If a user exceeded her quota limit, mail to her mailbox wouldn&#8217;t be blocked at <cite><abbr title="Simple Mail Transfer Protocol">SMTP</abbr></cite> time until the checking script&#8217;s next run.  This is not such a big problem, because the message won&#8217;t be delivered anyway. Instead it would be deferred and bounced back later (see above). Unfortunately, it&#8217;s the same the other way around. If a user deleted messages from her mailbox, this would not be recognized by <cite>Exim</cite> before the checking script&#8217;s next run. Mail would be rejected at <cite><abbr title="Simple Mail Transfer Protocol">SMTP</abbr></cite> time, although there might actually be enough space in the mailbox. This is a much bigger problem. Generally spoken, the interval between the runs of your checking script should be as low as at all possible. But don&#8217;t burn your mail server on the way <code>;)</code>. </p>
<p>Second there is the exclusive quota checking. Because we depend on the mailbox actually going over quota, we need to disable inclusive checking or &#8211; alternatively &#8211; increase quota limits and flag mailboxes as over quota at 99% or less.<br />
If we do the latter, there is always the possibility, that the quota of a mailbox isn&#8217;t above the checking threshold <em>and</em> there are new messages coming in, which are too large for the mailbox. These messages would be queued. Consider an example: A user get&#8217;s 30 messages of 1 GB, but his mailbox is only 500 MB. He gets no small messages in between, so our checking script will not flag the mailbox in subsequent runs and the size of the queue will rise a lot. This is especially a problem, because this probably affects mostly messages that are quite large. Also, if you can&#8217;t check fast enough and get a lot of small messages, there might be a lot of mailboxes that go way above the checking threshold before you can flag them. If you have a very large user base, this might be a problem. A run of the script probably takes longer, if you have a lot of mailboxes, so this adds to the problem.<br />
If we disable inclusive checking, the last message that brings a mailbox over quota will always be delivered. Depending on the message this might be okay (in case of small messages) or really bad (in case of very large messages). But: The mailbox will be flagged at the next run of our checking script, so the queue will remain relatively clear compared to our scenario above.<br />
If you do not have a lot of users and your resources are limited, you might not like this option. If you&#8217;ve got a large user base, exclusive checking is probably better.</p>
<p>Of course, there are other solutions, that do not have these issues. But they are a lot harder to implement and to maintain.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nachtarbeiter.net/2009/08/31/checking-mail-quota-during-smtp-transaction-in-exim/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>New Mozilla.org</title>
		<link>http://blog.nachtarbeiter.net/2009/08/26/new-mozilla-org/</link>
		<comments>http://blog.nachtarbeiter.net/2009/08/26/new-mozilla-org/#comments</comments>
		<pubDate>Wed, 26 Aug 2009 12:51:06 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[life]]></category>
		<category><![CDATA[Mozilla]]></category>

		<guid isPermaLink="false">http://blog.nachtarbeiter.net/?p=858</guid>
		<description><![CDATA[Yesterday the new Mozilla.org site went live. I contributed to the redesign project by helping with the feed parser, that aggregates the Latest news from Mozilla and Community Ticker sections on the front page.
]]></description>
			<content:encoded><![CDATA[<p>Yesterday the new <a href="http://mozilla.org/">Mozilla.org</a> site went live. I contributed to the redesign project by helping with the <a href="http://viewvc.svn.mozilla.org/vc/projects/mozilla.org/trunk/includes/MozillaOrg/FeedParser.php?view=markup">feed parser</a>, that aggregates the <cite>Latest news from Mozilla</cite> and <cite>Community Ticker</cite> sections on the front page.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nachtarbeiter.net/2009/08/26/new-mozilla-org/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Greetings from Sylt</title>
		<link>http://blog.nachtarbeiter.net/2009/08/23/greetings-from-sylt/</link>
		<comments>http://blog.nachtarbeiter.net/2009/08/23/greetings-from-sylt/#comments</comments>
		<pubDate>Sun, 23 Aug 2009 17:18:46 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[life]]></category>
		<category><![CDATA[sylt]]></category>

		<guid isPermaLink="false">http://blog.nachtarbeiter.net/?p=856</guid>
		<description><![CDATA[
]]></description>
			<content:encoded><![CDATA[<p><img src="/wp-content/uploads/2009/08/sylt-blog.jpg" width="500" height="375" alt="Sylt Ellenbogen (Denmark in the back)" /></p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nachtarbeiter.net/2009/08/23/greetings-from-sylt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A Thunderstorm&#8230;</title>
		<link>http://blog.nachtarbeiter.net/2009/08/21/a-thunderstorm/</link>
		<comments>http://blog.nachtarbeiter.net/2009/08/21/a-thunderstorm/#comments</comments>
		<pubDate>Fri, 21 Aug 2009 05:30:45 +0000</pubDate>
		<dc:creator>Patrick</dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[life]]></category>

		<guid isPermaLink="false">http://blog.nachtarbeiter.net/?p=842</guid>
		<description><![CDATA[&#8230; at 7 a.m. in the morning. Something different for a change. Good morning everyone!
]]></description>
			<content:encoded><![CDATA[<p>&#8230; at 7 a.m. in the morning. Something different for a change. Good morning everyone!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.nachtarbeiter.net/2009/08/21/a-thunderstorm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
