<?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>The Daily Build &#187; linux</title>
	<atom:link href="http://blog.bstpierre.org/tag/linux/feed" rel="self" type="application/rss+xml" />
	<link>http://blog.bstpierre.org</link>
	<description>Software Development, version 3.0</description>
	<lastBuildDate>Fri, 03 Feb 2012 02:59:01 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.4</generator>
		<item>
		<title>Tightening UFW Firewall Rules to Limit SSH Access</title>
		<link>http://blog.bstpierre.org/ufw-firewall-limit-ssh</link>
		<comments>http://blog.bstpierre.org/ufw-firewall-limit-ssh#comments</comments>
		<pubDate>Thu, 08 Dec 2011 23:54:21 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[firewall]]></category>
		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=371</guid>
		<description><![CDATA[The auth.log on one of my servers (really, on all of the servers I have access to) is full of stuff like this: Dec 8 03:19:33 localhost sshd[4718]: User root from 10.1.2.3 not allowed [...] Dec 8 03:19:35 localhost sshd[4721]: Invalid user db2inst1 from 10.1.2.3 Dec 8 03:19:38 localhost sshd[4723]: User root from 10.1.2.3 not [...]]]></description>
			<content:encoded><![CDATA[<p>The auth.log on one of my servers (really, on <em>all</em> of the servers I have access to) is full of stuff like this:</p>
<pre><code>Dec  8 03:19:33 localhost sshd[4718]: User root from 10.1.2.3 not allowed [...]
Dec  8 03:19:35 localhost sshd[4721]: Invalid user db2inst1 from 10.1.2.3
Dec  8 03:19:38 localhost sshd[4723]: User root from 10.1.2.3 not allowed [...]</code>
</pre>
<p>fail2ban is configured to (temporarily) block these after a certain number of attempts, but they keep coming back. One particular IP address was hitting ssh constantly (except for the ban periods) for several days, so I added a rule to drop everything from that address &#8212; but this strategy isn&#8217;t scalable.</p>
<p>The simple, obvious solution is to only allow access from known hosts. It would be very rare that I need to access this server from anywhere except a small number of addresses. I started with a ufw (Ubuntu&#8217;s &#8220;uncomplicated firewall&#8221;) ruleset like this:</p>
<pre><code>% sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
Anywhere                   DENY        10.1.2.3
Anywhere                   DENY        172.16.99.88
22                         ALLOW       Anywhere</code>
</pre>
<p>To avoid getting locked out, I added (temporarily) a crontab entry for root:</p>
<pre><code>*/15 * * * * /usr/sbin/ufw allow ssh</code></pre>
<p>This will allow access to ssh from any un-banned IP address (the current policy) every 15 minutes. Then I inserted a rule that allows access to ssh from my home ISPs netblock. (You can figure out the netblock by doing a whois lookup on your external IP address; you may need to add multiple netblocks if your ISP has several allocated. Be careful: it&#8217;s no fun to get locked out!) This action is safe because I have not yet removed global ssh access. Note that I&#8217;m using &#8220;insert 3&#8243; to add this rule at a specific position in the list.</p>
<pre><code>sudo ufw insert 3 allow proto tcp from 10.9.8.0/18 to any port 22</code></pre>
<p>And I added a rule to permit access from another server with a fixed IP I have access to (for the rare case where I need to access this server when I&#8217;m not at home):</p>
<p><code>sudo ufw insert 3 allow proto tcp from 172.17.101.102 to any port 22</code></p>
<p>Now my ruleset looks like:</p>
<pre><code>Status: active

To                         Action      From
--                         ------      ----
Anywhere                   DENY        10.1.2.3
Anywhere                   DENY        172.16.99.88
22/tcp                     ALLOW       172.17.101.102
22/tcp                     ALLOW       10.9.8.0/18
22                         ALLOW       Anywhere
</code></pre>
<p>So far, so good, but ssh access is still permitted from anywhere &#8212; because of that last rule. This is the dangerous part&#8230; you could get locked out if you haven&#8217;t set the rules correctly. (You set up that crontab entry, right?)</p>
<pre><code>sudo ufw delete allow ssh</code></pre>
<p>Wait for the prompt&#8230; hooray, I&#8217;m still connected! After checking that I can access ssh from home and the other server, I know it&#8217;s safe to remove the crontab job. (If the cron job has already fired, you&#8217;ll need to rerun the <code>ufw delete allow ssh</code> command.)</p>
<p>At this point I can delete the first two rules that ban specific IPs, since they&#8217;re outside my netblock and won&#8217;t be allowed anyway.</p>
<p>Now I can enjoy quieter logs without all those access attempts from China and Croatia!</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/ufw-firewall-limit-ssh/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Using SSH for IPv6-enabled HTTP Proxying</title>
		<link>http://blog.bstpierre.org/using-ssh-for-ipv6-enabled-http-proxying</link>
		<comments>http://blog.bstpierre.org/using-ssh-for-ipv6-enabled-http-proxying#comments</comments>
		<pubDate>Fri, 11 Nov 2011 16:50:26 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[ipv6]]></category>
		<category><![CDATA[ssh]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=358</guid>
		<description><![CDATA[My ISP has apparently made no progress whatsoever with IPv6, but I&#8217;ve got an IPv6 enabled VPS. SSH makes it trivial to use that VPS as a SOCKS5 proxy. Just do: ssh -D 8080 myvps.example.com Then set your browser&#8217;s SOCKS proxy to localhost:8080. In Firefox on Linux, this is Edit &#62; Preferences &#62; Advanced &#62; [...]]]></description>
			<content:encoded><![CDATA[<p>My ISP has apparently made no progress whatsoever with IPv6, but I&#8217;ve got an IPv6 enabled VPS.</p>
<p>SSH makes it trivial to use that VPS as a SOCKS5 proxy. Just do:</p>
<p><code>ssh -D 8080 myvps.example.com</code></p>
<p>Then set your browser&#8217;s SOCKS proxy to localhost:8080. In Firefox on Linux, this is Edit &gt; Preferences &gt; Advanced &gt; Network tab &gt; (Connection) Settings &gt; Manual Proxy Configuration. Leave <em>all fields blank</em> except for SOCKS Host and Port &#8212; localhost and 8080, respectively. Choose SOCKS5. Then browse to about:config and change <code>change network.proxy.socks_remote_dns</code> to true. This tells Firefox to ask the proxy to resolve names instead of trying to resolve them using your ISP. Chrome worked for me without hassle.</p>
<p>Go to <a href="http://test-ipv6.com/">test-ipv6.com</a> to test that it works. If your results from test-ipv6.com indicate that IPv6 name lookups are failing, make sure you&#8217;ve got that about:config setting mentioned above changed.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/using-ssh-for-ipv6-enabled-http-proxying/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Use Linux to build win32 installers for Python apps</title>
		<link>http://blog.bstpierre.org/linux-win32-python-installer</link>
		<comments>http://blog.bstpierre.org/linux-win32-python-installer#comments</comments>
		<pubDate>Wed, 20 Jul 2011 15:00:36 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[howto]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=319</guid>
		<description><![CDATA[A python-based project I&#8217;m working on has a win32 user that I need to support. Until yesterday I&#8217;ve been moving to a win32 laptop in order to run python setup.py bdist_wininst so I can produce a self-installing executable. Then I discovered how trivial it is to use wine to do the job: Install wine. (sudo [...]]]></description>
			<content:encoded><![CDATA[<p>A python-based project I&#8217;m working on has a win32 user that I need to support. Until yesterday I&#8217;ve been moving to a win32 laptop in order to run <code>python setup.py bdist_wininst</code> so I can produce a self-installing executable. Then I discovered how trivial it is to use wine to do the job:</p>
<ol>
<li>Install wine. (<code>sudo aptitude install wine</code>)</li>
<li>Install python into the wine environment. (Download an msi from python.org and run <code>msiexec /i python-x.x.x.msi</code>.)</li>
<li>Install whatever prerequisite packages you need (e.g. wxPython) using <code>wine</code> or <code>msiexec</code>.</li>
<li>When you&#8217;ve got everything ready to build, just do <code>wine c:/Python27/python.exe setup.py bdist_wininst</code> and look in ./dist/ for your exe!</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/linux-win32-python-installer/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An Interesting pid File Race</title>
		<link>http://blog.bstpierre.org/pid-file-race</link>
		<comments>http://blog.bstpierre.org/pid-file-race#comments</comments>
		<pubDate>Wed, 26 May 2010 16:08:50 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[linux]]></category>
		<category><![CDATA[software-engineering]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=305</guid>
		<description><![CDATA[ISC&#8217;s dhcpd uses this code to check for an already-running daemon: /* Read previous pid file. */ if ((i = open (path_dhcpd_pid, O_RDONLY)) &#62;= 0) { status = read (i, pbuf, (sizeof pbuf) - 1); close (i); if (status &#62; 0) { pbuf [status] = 0; pid = atoi (pbuf); /* If the previous server [...]]]></description>
			<content:encoded><![CDATA[<p>ISC&#8217;s dhcpd uses <a href="http://google.com/codesearch/p?hl=en#5KTrgOW2hXs/pub/nslu2/sources/dhcp-3.0.4.tar.gz|9nqObdv7Xcs/dhcp-3.0.4/server/dhcpd.c&amp;q=_PATH_DHCPD_CONF&amp;d=3&amp;l=539">this code</a> to check for an already-running daemon:</p>
<pre>/* Read previous pid file. */
if ((i = open (path_dhcpd_pid, O_RDONLY)) &gt;= 0) {
    status = read (i, pbuf, (sizeof pbuf) - 1);
    close (i);
    if (status &gt; 0) {
        pbuf [status] = 0;
        pid = atoi (pbuf);

        /* If the previous server process is not still running,
           write a new pid file immediately. */
        if (pid &amp;&amp; (pid == getpid() || kill (pid, 0) &lt; 0)) {
            unlink (path_dhcpd_pid);
            if ((i = open (path_dhcpd_pid,
                           O_WRONLY | O_CREAT, 0644)) &gt;= 0) {
                sprintf (pbuf, "%d\n", (int)getpid ());
                write (i, pbuf, strlen (pbuf));
                close (i);
                pidfilewritten = 1;
            }
        } else
            log_fatal ("There's already a DHCP server running.");
    }
}
</pre>
<p>The problem with this strategy is that, if the box dies, there&#8217;s a stale pid file left in /var/run/dhcpd.pid. This wouldn&#8217;t be so bad &#8212; the code above checks [using <code>kill(pid, 0)</code>] to see if there&#8217;s a process running with that pid. But when the box is restarting, there will be a bunch of processes all starting in similar sequence each time. So on one boot, you might see dhcpd with a pid of 1001 and ntpd with a pid of 1002. If the box dies violently (e.g. power cut), the dhcpd pid file will contain 1001. On the second boot, assume ntpd starts first and gets a pid of 1001 and dhcpd is 1002. Now, the <code>kill(pid, 0)</code> will succeed, making it appear that dhcpd is already running, and dhcpd will exit.</p>
<p>How to fix this?</p>
<ol>
<li>Explicitly put the pid file under /tmp. Getting this right is fussy &#8212; make sure you avoid the race conditions associated with creating temp files. Use dhcpd&#8217;s &#8220;-pf&#8221; flag to tell it where to use the pid file. This avoids spurious &#8220;already running&#8221; messages, because dhcpd will never read a pid from an existing pid file. [You could also just remove the /var/run/dhcpd.pid file, but I'd rather explicitly provide the path in my startup script in case some dim bulb decides to change the compiled-in default.]</li>
<li>Be careful in your restart code to kill any existing dhcpd (assuming you really want a new dhcpd), or avoid trying to start a new one (assuming you want to use an already running dhcpd). <code>pgrep(1)</code> and <code>pkill(1)</code> will be useful here.</li>
</ol>
<p>In researching this, I saw this <a href="http://openbsd.monkey.org/misc/200601/msg00735.html">bit of wisdom from Henning Brauer</a>: &#8220;pid files are useless.&#8221;.</p>
<p>I heartily agree&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/pid-file-race/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hassle Free Way to Kill Sudo&#8217;d Jobs</title>
		<link>http://blog.bstpierre.org/hassle-free-way-to-kill-sudod-jobs</link>
		<comments>http://blog.bstpierre.org/hassle-free-way-to-kill-sudod-jobs#comments</comments>
		<pubDate>Thu, 13 Aug 2009 00:45:28 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[news]]></category>
		<category><![CDATA[tools]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[script]]></category>
		<category><![CDATA[tip]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=189</guid>
		<description><![CDATA[Every now and then I have to run a foreground job under sudo that doesn&#8217;t want to die when I hit ^C. Then it&#8217;s a hassle to ^Z, get the pid of the sudo job, and sudo kill that pid. So I wrote a little script (or a template for scripts) that runs the sudo [...]]]></description>
			<content:encoded><![CDATA[<p>Every now and then I have to run a foreground job under sudo that doesn&#8217;t want to die when I hit ^C. Then it&#8217;s a hassle to ^Z, get the pid of the sudo job, and sudo kill that pid.</p>
<p>So I wrote a little script (or a template for scripts) that runs the sudo job in the background (but preserves stdout/stderr) and relies on bash to clean up the job when you ^C the script. Only gotcha with this is that you may have to retype your sudo password when you ^C if your authentication has timed out by the time you get around to killing it.</p>
<pre>#!/bin/bash

function cleanup()
{
    sudo kill $job_pid
    wait $job_pid
    exit 0
}

trap cleanup SIGTERM
trap cleanup SIGINT

sudo long_running_foreground_process &amp;
job_pid=$!
wait</pre>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/hassle-free-way-to-kill-sudod-jobs/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Using Python&#8217;s ctypes to Call Into C Libraries</title>
		<link>http://blog.bstpierre.org/using-pythons-ctypes-to-make-system-calls</link>
		<comments>http://blog.bstpierre.org/using-pythons-ctypes-to-make-system-calls#comments</comments>
		<pubDate>Wed, 05 Aug 2009 10:35:55 +0000</pubDate>
		<dc:creator>Brian St. Pierre</dc:creator>
				<category><![CDATA[python]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[linux]]></category>
		<category><![CDATA[tutorial]]></category>

		<guid isPermaLink="false">http://blog.bstpierre.org/?p=185</guid>
		<description><![CDATA[The ctypes module makes loading and calling into a dynamic library incredibly easy.]]></description>
			<content:encoded><![CDATA[<p>The ctypes module makes loading and calling into a dynamic library incredibly easy:</p>
<pre>&gt;&gt;&gt; from ctypes import CDLL
&gt;&gt;&gt; libc = CDLL('libc.so.6')
&gt;&gt;&gt; print libc.strlen('abcde')
5</pre>
<p>As with everything else in python, it gets even better when you scratch the surface. In the example above, CDLL returns an object that represents the dynamic library. You can access the functions in that library by attribute access (&#8220;libc.strlen&#8221;) or item access (&#8220;libc['strlen']&#8220;). Both access mechanisms return a callable object.</p>
<p>This callable object has an &#8220;errcheck&#8221; attribute that can be assigned a callable. We can use this for error-checking our calls into the library. Let&#8217;s write a simple version of the &#8220;kill&#8221; command that uses the kill(2) system call.</p>
<pre>import sys
from ctypes import *

# Load the library.
libc = CDLL('libc.so.6')

# Our error checking function. This will receive the
# return value of the library function, the function that
# was called, and the arguments passed to the function as a
# tuple.
def kill_errcheck(retval, func, funcargs):
    '''Check for error -- retval == -1.'''
    if retval &lt; 0:
        raise Exception('kill%s failed' % (funcargs, ))
    return True

# Get the kill function from the standard library.
kill = libc.kill

# Set the error checker for kill().
kill.errcheck = kill_errcheck

# Pass the command line argument as a pid to kill, with
# SIGSEGV (11).
pid = int(sys.argv[1])
kill(pid, 11)</pre>
<p>Save this as kill.py. Then, in your shell, try something like this:</p>
<pre># Notice that the 3401 is the pid of the process
# we're putting into the background. Yours will
# be different.
bash$ sleep 120&amp;
[1] 3401
bash$ python kill.py 3401
[1]+ Segmentation Fault         sleep 120
bash$ python kill.py 3401
Traceback (most recent call last):
  File "kill.py", line 17, in
    kill(pid, 11)
  File "kill.py", line 10, in kill_errcheck
    raise Exception('kill%s failed' % (funcargs, ))
Exception: kill(3401, 11) failed</pre>
<p>At line 4 of the output we run sleep in the background. At line 5 we learn the pid of this process. At line 6 we run our kill program, giving it the pid we just spawned, and we see the notification from bash that the process was killed (with signal 11, segmentation fault). At line 8 we run our kill program again on pid 3401, but it doesn&#8217;t exist, the kill system call returns -1, and our error checker raises an exception when it detects the system call failure.</p>
<p>But wait, there&#8217;s more&#8230; I&#8217;m working on a follow up post that combines ctypes.Structure with calls into a linux system call.</p>
]]></content:encoded>
			<wfw:commentRss>http://blog.bstpierre.org/using-pythons-ctypes-to-make-system-calls/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

