<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
 <channel>
  <title>Blargh - Thomas Habets blog</title>
  <link>http://blog.habets.pp.se/</link>
  <description>Network, unix, Erlang and other fun projects</description>
  <copyright>Copyright Thomas Habets 2009</copyright>
  <lastBuildDate>Tue, 07 Feb 2012 22:57:14 GMT</lastBuildDate>
  <pubDate>Tue, 07 Feb 2012 22:57:14 GMT</pubDate>
  <docs>http://blogs.law.harvard.edu/tech/rss</docs>
  <atom:link href="http://blog.habets.pp.se/rss" rel="self"
             type="application/rss+xml" />
  <language>en-us</language>
  <item>
   <title>Be careful with hashmaps</title>
   <description><![CDATA[<p itemprop="description">
  As you remember from long ago hashes are <code>O(1)</code> best case, but can be <code>O(n)</code>
  if you get hash collisions. And if you're adding <code>n</code> new entries
  that means <code>O(n^2)</code>.
</p>
<p>
  I thought I'd take a look at the hash_set/hash_map GNU C++ extension.
</p>


In <code>/usr/include/c++/4.4.3/backward/hash_fun.h</code>:
<table class="codetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7
8</pre></div></td><td class="code"><div class="code"><pre>  <span class="kr">inline</span> <span class="kt">size_t</span>
  <span class="nf">__stl_hash_string</span><span class="p">(</span><span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">__s</span><span class="p">)</span>
  <span class="p">{</span>
    <span class="kt">unsigned</span> <span class="kt">long</span> <span class="n">__h</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
    <span class="k">for</span> <span class="p">(</span> <span class="p">;</span> <span class="o">*</span><span class="n">__s</span><span class="p">;</span> <span class="o">++</span><span class="n">__s</span><span class="p">)</span>
      <span class="n">__h</span> <span class="o">=</span> <span class="mi">5</span> <span class="o">*</span> <span class="n">__h</span> <span class="o">+</span> <span class="o">*</span><span class="n">__s</span><span class="p">;</span>
    <span class="k">return</span> <span class="kt">size_t</span><span class="p">(</span><span class="n">__h</span><span class="p">);</span>
  <span class="p">}</span>
</pre></div>
</td></tr></table>

Test program that loads some strings:
<table class="codetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33</pre></div></td><td class="code"><div class="code"><pre><span class="cp">#include&lt;time.h&gt;</span>
<span class="cp">#include&lt;iostream&gt;</span>
<span class="cp">#include&lt;hash_set&gt;</span>

<span class="kt">double</span> <span class="nf">getclock</span><span class="p">()</span>
<span class="p">{</span>
  <span class="k">struct</span> <span class="n">timespec</span> <span class="n">ts</span><span class="p">;</span>
  <span class="n">clock_gettime</span><span class="p">(</span><span class="n">CLOCK_MONOTONIC</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ts</span><span class="p">);</span>
  <span class="k">return</span> <span class="n">ts</span><span class="p">.</span><span class="n">tv_sec</span> <span class="o">+</span> <span class="n">ts</span><span class="p">.</span><span class="n">tv_nsec</span> <span class="o">/</span> <span class="mf">1e9</span><span class="p">;</span>
<span class="p">}</span>

<span class="n">_GLIBCXX_BEGIN_NAMESPACE</span><span class="p">(</span><span class="n">__gnu_cxx</span><span class="p">)</span>
<span class="n">template</span><span class="o">&lt;&gt;</span> <span class="k">struct</span> <span class="n">hash</span><span class="o">&lt;</span> <span class="o">::</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span> <span class="p">{</span>
  <span class="kt">size_t</span> <span class="n">operator</span><span class="p">()(</span><span class="k">const</span> <span class="o">::</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&amp;</span> <span class="n">x</span><span class="p">)</span> <span class="k">const</span> <span class="p">{</span>
    <span class="k">return</span> <span class="n">hash</span><span class="o">&lt;</span><span class="k">const</span> <span class="kt">char</span><span class="o">*&gt;</span><span class="p">()(</span><span class="n">x</span><span class="p">.</span><span class="n">c_str</span><span class="p">());</span>
  <span class="p">}</span>
<span class="p">};</span>
<span class="n">_GLIBCXX_END_NAMESPACE</span>

<span class="kt">int</span> <span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
  <span class="n">__gnu_cxx</span><span class="o">::</span><span class="n">hash_set</span><span class="o">&lt;</span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="o">&gt;</span> <span class="n">the_set</span><span class="p">;</span>
  <span class="kt">double</span> <span class="n">start</span> <span class="o">=</span> <span class="n">getclock</span><span class="p">();</span>

  <span class="k">while</span> <span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">cin</span><span class="p">.</span><span class="n">good</span><span class="p">())</span> <span class="p">{</span>
    <span class="n">std</span><span class="o">::</span><span class="n">string</span> <span class="n">line</span><span class="p">;</span>
    <span class="n">getline</span><span class="p">(</span><span class="n">std</span><span class="o">::</span><span class="n">cin</span><span class="p">,</span> <span class="n">line</span><span class="p">);</span>

    <span class="n">the_set</span><span class="p">.</span><span class="n">insert</span><span class="p">(</span><span class="n">line</span><span class="p">);</span>
  <span class="p">}</span>
  <span class="n">std</span><span class="o">::</span><span class="n">cout</span> <span class="o">&lt;&lt;</span> <span class="s">&quot;Size: &quot;</span> <span class="o">&lt;&lt;</span> <span class="n">the_set</span><span class="p">.</span><span class="n">size</span><span class="p">()</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span>
            <span class="o">&lt;&lt;</span> <span class="s">&quot;Time: &quot;</span> <span class="o">&lt;&lt;</span> <span class="n">getclock</span><span class="p">()</span><span class="o">-</span><span class="n">start</span> <span class="o">&lt;&lt;</span> <span class="n">std</span><span class="o">::</span><span class="n">endl</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</td></tr></table>

Running the loader with different inputs:
<blockquote><pre>
$ ./generateCollisions 5 > coll-5
$ ./generateCollisions 6 > coll-6
$ wc -l coll-5 coll-6
  13826 coll-5
 149696 coll-6
 163522 total
$ seq -f "%06.0f" 13826 > num-5
$ seq -f "%06.0f" 149696 > num-6
$ ./load < num-5
Size: 13827
Time: 0.0148379
$ ./load < num-6
Size: 149697
Time: 0.135555
$ ./load < coll-5
Size: 13827
Time: 1.44663
$ ./load < coll-6
Size: 149697
Time: 212.009</pre></blockquote>
That's going from 0.14 seconds to over 3 and a half minutes.

<h2>Collision generator</h2>
Left as an exercise to the reader. My code is too ugly to release.

<h2>Summary</h2>
Nothing new, just a friendly reminder to treat input data as untrusted. Think of all the places
where you use a hash map. How many of the keys come straight from untrusted sources? (user names,
photo tags, JSON or XML data that at some point is shoved into suitable data structures, etc...)

<h2>Links</h2>
<ul>
<li><a href="http://events.ccc.de/congress/2011/Fahrplan/events/4680.en.html">28C3:
    Effective Denial of Service attacks against web application platforms</a></li>
</ul>
]]></description>
   <link>http://blog.habets.pp.se/2012/02/Be-careful-with-hashmaps</link>
   <guid>http://blog.habets.pp.se/2012/02/Be-careful-with-hashmaps</guid>
   <pubDate>Tue, 07 Feb 2012 22:57:14 GMT</pubDate>
  </item>
  <item>
   <title>Benchmarking TPM-backed SSL</title>
   <description><![CDATA[<p>
  <img src="/static/2012-02-05_TPM_handshake_performance.png"/><br/>
</p>
<p>
  As you can plainly see from this graph, my TPM chip can do
  approximately 1.4 SSL handshakes per second. A handshake takes about 0.7 seconds of TPM time,
  so when two clients are connecting the average connect time is 1.4 seconds.
  This means probably not useful on server side, but should be good for some client side applications.
</p>

<p>
  To replicate the test, start a server:
  <blockquote><pre>openssl s_server -keyform engine -engine tpm -accept 12345 -cert foo.crt -key foo.key -tls1 -CAfile foo.crt -verify 1 -status</pre></blockquote>
  And then connect 100 times:
  <blockquote><pre>for n in $(seq 100); do time openssl s_client -tls1 -connect localhost:12345 < /dev/null >/dev/null 2>/dev/null;done 2> timelog</pre></blockquote>
  Then just look at the "real" time in the timelog. (if in doubt, use bash. zsh gave me some crap in the log) Example GNUPlot:
  <blockquote><pre>plot [1:] [0:2] '2' using (2/$1) w l title '2 clients','1' using (1/$1) w l title '1 client'</pre></blockquote>
</p>]]></description>
   <link>http://blog.habets.pp.se/2012/02/Benchmarking-TPM-backed-SSL</link>
   <guid>http://blog.habets.pp.se/2012/02/Benchmarking-TPM-backed-SSL</guid>
   <pubDate>Sun, 05 Feb 2012 13:02:16 GMT</pubDate>
  </item>
  <item>
   <title>TPM-backed SSL</title>
   <description><![CDATA[<p>
  This is a short howto on setting up TPM-backed SSL. This means that
  the secret key belonging to an SSL cert is protected by the TPM and
  cannot be copied off of the machine or otherwise inspected.
</p>

<p>
  Meaning even if you get hacked the attackers cannot impersonate you,
  if you manage to kick them off or just shut down the server. The
  secret key is safe. It has never been outside the TPM and never will be.
</p>

<p>
  This can be used for both client and server certs.
</p>



<h2>Prerequisites</h2>
<ul>
  <li>A TPM chip. Duh. May need to be turned on in the BIOS. Could be called "security chip" or something.
      If you don't have a TPM chip but still want to follow along (maybe add TPM support to some program)
      then you can install a TPM emulator. See links at the end on how to install a TPM emulator.</li>
  <li>A working CA that will sign your CSR. I will assume you're
      running your own CA, but you can send the CSR to someone else
      to sign if you want cert creating step.</li>
  <li>Installed "stuff": <blockquote><pre>$ aptitude install tpm-tools libengine-tpm-openssl</pre></blockquote></li>
</ul>

<h2>Initialize TPM</h2>
<ul>
  <li>Make sure you can communicate with the TPM chip:
<blockquote><pre>$ tpm_version
  TPM 1.2 Version Info:
  Chip Version:        1.2.4.1
  Spec Level:          2
  Errata Revision:     2
  TPM Vendor ID:       INTC
  Vendor Specific data: 00040001 0003040e
  TPM Version:         01010000
  Manufacturer Info:   494e5443
</pre></blockquote>
  </li>

  <li>Clear the chip:
<blockquote><pre>$ tpm_clear --force
$ tpm_setenable --enable --force
$ tpm_setactive --active</pre></blockquote>
These steps may require reboots. They will probably tell you if that's the case.
  </li>

  <li>Take ownership and create SRK:
  <blockquote><pre>$ tpm_takeownership -u -y
Enter SRK password: <b>&lt;just press enter&gt;</b>
Confirm password: <b>&lt;just press enter&gt;</b></pre></blockquote>
  Yes really, empty password. This password protects TPM operations, so
  worst case is that someone with shell access can put some load on your TPM chip.
  They can't use it to crack keys or anything. This is not a password that protects
  your secrets, they're already secure. You may want to supply an owner password. If so,
  leave out the <code>-y</code> option.
  </li>

</ul>

<h2>Create SSL certificate</h2>
<ul>
  <li>Use script from libengine-tpm-openssl to create key: <code>create_tpm_key foo.key</code></li>
  <li>Create CSR for key: <code>openssl req -keyform engine -engine tpm -key foo.key -new -out foo.csr</code></li>
  <li>Sign the CSR with your CA: <code>openssl x509 -req -days 365 -in foo.csr -CA ca.crt -CAkey ca.key -CAserial serial -out foo.crt</code></li>
</ul>

<h2>Test it</h2>
On the server:<blockquote><pre>$ openssl s_server -accept 12345 -cert /path/to/server.crt -key /path/to/server.key -CAfile CA/ca.crt -Verify 1</pre></blockquote>

On the client
<blockquote><pre>$ openssl s_client -keyform engine -engine tpm -connect server-name-here:12345 -cert foo.crt -key foo.key</pre></blockquote>

<h2>Use in your code</h2>
<p>
  Instead of using <code>SSL_CTX_load_verify_locations()</code>,
  use <code>ENGINE_*()</code> and <code>SSL_CTX_use_PrivateKey()</code>
</p>
<p>
Without TPM:
<table class="codetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4</pre></div></td><td class="code"><div class="code"><pre><span class="kt">void</span> <span class="nf">loadpriv</span><span class="p">(</span><span class="n">SSL_CTX</span><span class="o">*</span> <span class="n">ctx</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">file</span><span class="p">)</span>
<span class="p">{</span>
  <span class="n">SSL_CTX_use_PrivateKey_file</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">file</span><span class="p">,</span> <span class="n">SSL_FILETYPE_PEM</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</td></tr></table>
</p>
<p>
With TPM:
<table class="codetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3
4
5
6
7
8
9</pre></div></td><td class="code"><div class="code"><pre><span class="kt">void</span> <span class="nf">loadpriv</span><span class="p">(</span><span class="n">SSL_CTX</span><span class="o">*</span> <span class="n">ctx</span><span class="p">,</span> <span class="k">const</span> <span class="kt">char</span><span class="o">*</span> <span class="n">file</span><span class="p">)</span>
<span class="p">{</span>
  <span class="n">ENGINE</span><span class="o">*</span> <span class="n">engine</span> <span class="o">=</span> <span class="n">ENGINE_by_id</span><span class="p">(</span><span class="s">&quot;tpm&quot;</span><span class="p">);</span>
  <span class="n">ENGINE_init</span><span class="p">(</span><span class="n">engine</span><span class="p">);</span>

  <span class="n">UI_METHOD</span><span class="o">*</span> <span class="n">ui_method</span> <span class="o">=</span> <span class="n">UI_OpenSSL</span><span class="p">();</span>
  <span class="n">EVP_PKEY</span><span class="o">*</span> <span class="n">pkey</span> <span class="o">=</span> <span class="n">ENGINE_load_private_key</span><span class="p">(</span><span class="n">engine</span><span class="p">,</span> <span class="n">file</span><span class="p">,</span> <span class="n">ui_method</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">);</span>
  <span class="n">SSL_CTX_use_PrivateKey</span><span class="p">(</span><span class="n">ctx</span><span class="p">,</span> <span class="n">pkey</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</td></tr></table>
Error handling left as an exercise for the reader.
</p>

<h2>Use in the real world</h2>
<p>
  Huh. I haven't actually seen this implemented in any Open Source software (besides the openssl command
  line interface)
  Well, actually curl and stunnel4 <em>appear</em> that they could support it, but
  it's not clear how. <a href="http://comments.gmane.org/gmane.network.stunnel.user/3109">Here</a>
  is someone else wondering how to get stunnel to do it. It's from 2006 with no replies.
</p>
<p>
  The only thing I have that uses the TPM chip is my Chromebook. Client certs there are
  protected by it by default.
</p>
<p>
  Please leave comments if you know of any TPM support in Open Source stuff.
</p>

<h2>tlssh</h2>
I have added support for <a href="http://github.com/ThomasHabets/tlssh">tlssh</a>
to use TPM on both the server and client side. Add "-E tpm" on the
client side, and have something like this on the server side config
(or only on one side. There's no requirement that both sides use TPM):
<table class="codetable"><tr><td class="linenos"><div class="linenodiv"><pre>1
2
3</pre></div></td><td class="code"><div class="code"><pre>PrivkeyEngine tpm
TpmSrkPassword
PrivkeyPassword secretpasswordhere
</pre></div>
</td></tr></table>
That last line is just needed if the key has a password. The client can be configured
in the same way to not have to ask for the passwords.
</p>
<p>
  If <code>PrivkeyEngine tpm</code> or <code>-E tpm</code> is supplied the secret key
  will be assumed to be TPM protected and should be in the form of a "BEGIN TSS KEY BLOB"
  section instead of a PEM format "BEGIN RSA PRIVATE KEY" section.
</p>

<h2>Performance</h2>
<p>
  Oh, it's slow. Really slow. Luckily it's just used in the handshake.
  I haven't done proper benchmarks, but let's just say you won't be
  using it to power your webmail. I may do some benchmarking in a coming blog post.
</p>
<p>
  <b>Update:</b> It can do about 1.4 connections per second.
  See <a href="/2012/02/Benchmarking-TPM-backed-SSL">Benchmarking TPM backed SSL</a>
  for details.
</p>

<h2>Misc notes</h2>
<ul>
  <li>The .key file for the TPM-backed cert contains the secret key encrypted
      with something that's in the TPM. It's not usable without the exact same TPM chip.</li>
  <li>You can choose to create a key in the normal way and then "convert" it to a TPM-backed key.
      It's not as secure since you can't say the key was never stored outside the TPM chip, but
      use the <code>-w</code> switch to <code>create_tpm_key</code> if you want to do this.</li>
  <li>OpenSSL is probably the most horrible, disgusting, undocumented crap library I've ever seen.
      Some of this can be blamed on SSL, X509 and ASN.1, but far from all.</li>
  <li>Emulated TPM is not completely useless. Since the emulator runs as root and the user
      has no insight into it you can have users be able to use private keys that they
      can't read or copy to other machines. (caveat: I don't know if the emulator is
      actually secure in this mode, but it can be made to be)</li>
  <li>My TPM chip doesn't seem to like importing (<code>create_tpm_key -w foo.key</code>)
      4096 bit keys. 2048 was fine though.</li>
</ul>

<h2>Links</h2>
<ul>
  <li><a href="http://www.infond.fr/2010/03/trusted-platforms-module-tpm-openssl.html">trusted platforms
      module (TPM), openssl and ecryptfs tutorial</a>. Another
      nice use of TPM. Also installation instructions for TPM emulator</li>
  <li><a href="http://www.cs.tau.ac.il/~orkaplan/TPMWorkshop/downloads/">Resources from a TPM workshop</a></li>
  <li><a href="https://sites.google.com/site/ourcomputernotes/security/use-tpm-on-linux">Use TPM on Linux</a></li>
</ul>]]></description>
   <link>http://blog.habets.pp.se/2012/02/TPM-backed-SSL</link>
   <guid>http://blog.habets.pp.se/2012/02/TPM-backed-SSL</guid>
   <pubDate>Sat, 04 Feb 2012 15:22:29 GMT</pubDate>
  </item>
  <item>
   <title>Secure browser-to-proxy communication</title>
   <description><![CDATA[<p>
  When connecting to a possibly hostile network I want to tunnel
  all traffic from my browser to some proxy I have set up on the Internet.
</p>

<p>
  The obvious way to do this is with a proxy. The problem with that is
  that the traffic from the browser to the proxy is not encrypted. Even
  when you browse to secure SSL sites some traffic is being sent in the
  clear, such as the host name. That's not so bad, but I want to hide my
  HTTP traffic too.
</p>



<p>
  Turns out that at least
  <a href="http://www.chromium.org/developers/design-documents/secure-web-proxy">Chrome
  <em>does</em> support using SSL between the browser and the proxy</a>,
  but you can't configure it directly. You have to use Proxy Auto Configuration
  to point to an HTTPS host:port.
</p>

<p>
  Running OpenVPN is out in this case since I want it to work with everything, including Android
  and ChromeOS… and Windows (without installing "stuff"). Not that I've tried it with Windows yet,
  but it should work.
</p>

<p>
  For added fun I wanted to authenticate to the proxy using a client
  certificate, so that I don't have to worry about remembering or losing passwords.
</p>

<p>
  Before you set off to do the same thing I should warn you that either I haven't
  done it quite right or there is a bug in Chrome. If the network has a hickup
  so that the proxy or the .pac file is unavailable it will fall back to connecting
  directly. I want it to never fall back. That's kind of the point.
</p>

<p>
  But all is not in vain. I also set up IPSec with these same certificates. There
  will be a follow-up post describing how I set this up to tunnel securely with
  both Chromebook and my phone.
</p>

<p>
  This is what I did (caveat: some of this is from memory.
  If you find any errors please let me know):
<ol>
<li><h3>Copy easyrsa 2.0 from openvpn sources</h3>
  This is a set of scripts to manage a CA. We'll be using
  this directory/set of scripts both to create a server and
  client certificates. But only the client certificates will
  be signed by our own CA.
</li>

<li><h3>Edit <code>vars</code> file</h3>
  I like to change KEY_SIZE to 2048, country and other stuff.
  These will be the defaults when creating certs.
</li>

<li><h3>Init easyrsa</h3>
  <code>./clean-all</code><br/>
  This is a one-time init. Don't run this script again.
</li>

<li><h3>Build the CA for the client certs</h3>
  <code>./build-ca</code>
</li>

<li><h3>Copy CA cert to proxy server</h3>
  <code>scp keys/ca.crt proxy:/etc/proxy-ssl/proxy-ca.crt</code>
</li>

<li><h3>Build server key and signing request</h3>
  <code>./build-req proxy.foo.com</code>
</li>

<li><h3>Get signed server cert</h3>
  Send keys/proxy.foo.com.csr to your real CA (e.g. cacert.org or Verisign).
  You'll get back proxy.foo.com.crt. If you do use cacert.org then make sure that
  your browser trusts <a href="http://www.cacert.org">their root</a> by importing it.
</li>

<li><h3>Put proxy.foo.com cert and key on proxy server</h3>
 <code>scp keys/proxy.foo.com.{crt,key} proxy:/etc/proxy-ssl/</code>
</li>

<li><h3>Install squid proxy and stunnel on proxy server</h3>
  On Debian/Ubuntu: <code>apt-get install squid3 stunnel</code>
</li>

<li><h3>Configure & start stunnel</h3>
  <ol>
    <li>set ENABLE=1 in /etc/defaults/stunnel.conf</li>
    <li>In /etc/stunnel/stunnel.conf
      <code><pre>
      cert=/etc/proxy-ssl/proxy.foo.com.crt
      key=/etc/proxy-ssl/proxy.foo.com.key
      verify=2
      CAfile=/etc/proxy-ssl/proxy-ca.crt
      [proxy]
      accept  = 12346
      connect = 3128</pre></code>
    </li>
    <li>/etc/init.d/stunnel4 start</li>
  </ol>
</li>

<li><h3>Create .pac file somewhere on an https url</h3>
<blockquote><pre>
function FindProxyForURL(url, host)
{
      return "HTTPS proxy.foo.com:12346";
}
</pre></blockquote>
Make sure that the certificate of the https server is one that the browser will accept.

<li><h3>Set proxy autoconf to the url to this .pac file</h3>
  Spanner-&gt;Preferences-&gt;Under the Bonnet-&gt;Change proxy settings-&gt;Automatic Proxy Configuration<br/>
  Set the URL to where the file is, including "https://".
</li>

<li><h3>Try it now. It should fail with SSL errors</h3>
  It should fail because proxy doesn't accept your cert
  (you don't have a cert in the browser yet). Don't continue if you get some other error.
</li>

<li><h3>Create client cert signed by your own CA</h3>
  <code>./build-key my-proxy-key</code><br>
  Don't set a password.
</li>

<li><h3>Convert the client key+cert to .p12, because that's what Android and Chrome wants</h3>
  <code>openssl pkcs12 -export -in keys/my-proxy-key.crt -inkey keys/my-proxy-key.key -out my-proxy-key.p12</code><br/>
  It'll ask for a password that will only be used in the next step. No need to save it for later.
</li>

<li><h3>Import the client certificate into the browser</h3>
  On your Chrome (or chromebook) go Spanner-&gt;Preferences-&gt;Under the Bonnet-&gt;Certificate Manager-&gt;Your Certificates-&gt;Import (or "Import and Bind to Device").
</li>

<li><h3>Try to browse somewhere. Now it should work</h3>
  Make sure you're actually using the proxy. Go to <a href="http://www.whatismyip.com">www.whatismyip.com</a>
  or something and make sure that it sees the IP of the proxy.  
  It'll probably tell you that you're using a proxy. If it doesn't work then good luck. :-)
</li>
</ol>

<h2>Problems</h2>
<p>
  Like I said it seems that it falls back to connecting directly, even though
  the .pac file doesn't have a fallback mechanism configured. Stay tuned for the IPSec version.
</p>]]></description>
   <link>http://blog.habets.pp.se/2011/12/Secure-browser-to-proxy-communication</link>
   <guid>http://blog.habets.pp.se/2011/12/Secure-browser-to-proxy-communication</guid>
   <pubDate>Tue, 27 Dec 2011 01:16:10 GMT</pubDate>
  </item>
  <item>
   <title>Optimizing TCP slow start</title>
   <description><![CDATA[<p>
  The short version of the problem and solution I will describe is that while TCP gets up to speed
  fairly fast, and "fast enough" for many uses, it doesn't accelerate
  fast enough for short-lived connections such as web page requests. If I have 10Mbps connection
  and the server has 10Mbps to spare, why doesn't a 17kB web page transfer at 10Mbps from
  first to last byte? (that is, when excluding TCP handshake, HTTP request and server side
  page rendering)
</p>

<p>
  This is pretty Linux-focused, but I'll add pointers for other OSs if I see them.
</p>


<h2>Short version</h2>
<p>
  This will get a bit basic for some people, so here's the short version. Make sure you measure
  the effect of changing these settings. Don't just increase them and think "more is better".
</p>
On receiver side (requires kernel version 2.6.33 or newer (and a fairly new iproute package. iproute2-ss100519 works). Use your default route instead of "x.x.x.x"):
<blockquote><pre>
ip route change default via x.x.x.x initrwnd 20
</pre></blockquote>

On sender side:
<blockquote><pre>
ip route change default via x.x.x.x initcwnd 20
</pre></blockquote>

To tweak both send and receive:
<blockquote><pre>
ip route change default via x.x.x.x initcwnd 20 initrwnd 20
</pre></blockquote>


<h2>The path to enlightenment</h2>
<p>
  In short, the number of bytes in flight in TCP is the lowest of the senders congestion window (cwnd)
  and the receiver window size. The window size is the receiver announcing how much it's ready
  to receive, and the sender will therefore not send any more than that. The cwnd is the sender
  trying to avoid causing congestion. (since TCP is two-way both sides have both, but think of it as one-way for now)
</p>
<p>
  The window size is announced in every segment (TCP packets are called "segments") and is the receivers
  method of throttling. The cwnd is not sent across the network, but is a local sender-side throttling only.
</p>
<p>
  Both of these default to "a few" multiples of the maximum size segments (MSS).
  The MSS is announced in the SYN and SYN|ACK packets and are adjusted so that a TCP segment
  fits in the path MTU (hopefully). Typical initial window size and cwnd is on the order of 4kB.
  Linux has an initial cwnd of 10*MSS nowadays, but that doesn't help if the receiver window is smaller
  that that.
  Both window size and cwnd will change as the connection progresses. How and why is a huge topic in itself. I'm
  focusing here on a specific problem of initial size and TCP slow start.
</p>
<p>
  The problem I was having was that when I downloaded <a href="http://blog.habets.pp.se">http://blog.habets.pp.se</a>
  over a ~50ms RTT connection these values don't go up fast enough. During the ~300ms transaction (including everything)
  the sender stalls about 4-6 times waiting for the receiver to give the go-ahead. (I only have approximate numbers since
  the RTT between the servers I was testing was a bit unstable. Virtual servers and all that).
  The time between first and last byte was about 170ms. Really? ~50ms RTT and 17kB in 170ms? That's not good.
</p><p>
  Ideally there should be two round trips involved. One where the client has sent SYN and is waiting for SYN|ACK,
  and the other when the client has sent the request and is waiting for the results. If this was a long-running
  connection (with <a href="http://en.wikipedia.org/wiki/HTTP_persistent_connection">HTTP keep-alive</a> for example)
  this wouldn't be a problem, but since I'm looking at the first request in a new TCP connection it is.
</p>
<h3>Increase receiver window size</h3>
<p>
  Since I couldn't find it in <code>sysctl</code> or <code>/sys</code> I looked at the source.
  <code>net/ipv4/tcp_output.c</code> has a function called <code>tcp_select_initial_window()</code>.
  The last parameter is <code>__u32 init_rcv_win</code>. Well, that was easy. Because
  I'm lazy I just compiled the kernel hardcoding it to 10 (it's in multiples of MSS).
  I started a lab virtual machine and sure enough the initial window is now a lot bigger.
  Still not seeing a reduction in round trip waits though, and it's as slow as before.
  At least now it's not the receivers fault. The window has lots of space left but the
  sender is quiet.
</p><p>
  What is this <code>dst_metric(dst, RTAX_INITRWND)</code> that it was before I changed
  it to hardcoded 10 though? <code>include/linux/rtnetlink.h</code> which defines RTAX_INITRWND looks like mostly
  routing related stuff. Aha! Sure enough:
  <blockquote><pre>
user@hostname$ ip route help
[...]
OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ]
       [ rtt TIME ] [ rttvar TIME ] [reordering NUMBER ]
       [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]
       [ ssthresh NUMBER ] [ realms REALM ] [ src ADDRESS ]
       [ rto_min TIME ] [ hoplimit NUMBER ] [ initrwnd NUMBER ]
[...]  </pre></blockquote>
  Setting these things per route table entry? Yeah that does make sense. I set values as
  seen under "Short version" above and a HTTP request is now just two round trips (three
  if you count closing the connection, but the web page is already downloaded at that point so
  I'm not counting it), and single-digit milliseconds from first to last byte. A 96% reduction
  (26% if you include the connection setup & HTTP request). (very inexact numbers, I just ran
  the test once. It's late. For details on how cwnd affects latency see
<a href="http://code.google.com/speed/articles/tcp_initcwnd_paper.pdf">Googles paper on it</a>.
</p>

<h2>Misc</h2>
<ul>
  <li>As far as I can see window size and cwnd can not be set per-socket by <code>setsockopt()</code> or similar. If they could this would cause people to write evil applications that don't play well with the rest of the Internet.</li>
  <li>Current cwnd, window size and other data can be seen with <code>getsockopt(..., TCP_INFO, ...)</code>.</li>
  <li><a href="http://code.google.com/speed/articles/tcp_initcwnd_paper.pdf">An Argument for Increasing TCP’s Initial Congestion Window</a></li>
  <li><a href="http://blog.benstrong.com/2010/11/google-and-microsoft-cheat-on-slow.html">Google and Microsoft Cheat on Slow-Start. Should You?</a></li>
  <li><a href="http://www.amailbox.org/mailarchive/linux-netdev/2010/5/26/6278007">Linux kernel patch</a> for adding <code>setsockopt()</code> for changing cwnd. Not needed. It was rejected for a reason.</li>
</ul>

<h2>Links</h2>
<ul>
  <li>Draft to <a href="http://tools.ietf.org/html/draft-hkchu-tcpm-initcwnd-01">increase TCP's initial window</a> by default to 10 * MSS. This has been implemented in Linux.</li>
  <li><a href="http://www.andysnotebook.com/2011/11/increasing-the-tcp-initial-congestion-window-on-windows-2008-server-r2.html">Increasing the TCP Initial Congestion Window on Windows 2008 Server R2</a></li>
</ul>]]></description>
   <link>http://blog.habets.pp.se/2011/10/Optimizing-TCP-slow-start</link>
   <guid>http://blog.habets.pp.se/2011/10/Optimizing-TCP-slow-start</guid>
   <pubDate>Sat, 15 Oct 2011 23:21:49 GMT</pubDate>
  </item>
  <item>
   <title>Yubico is awesome</title>
   <description><![CDATA[<p>
  <a href="http://www.yubico.com">Yubico</a> and their products are awesome.
</p>

<p>
  That pretty much sums up this blog post but I'm going to go on anyway. If you're
  thinking of introducing two-factor authentication to your company, or you're using
  something that's fundamentally broken (like RSA SecureID) you simply must at least
  take Yubikeys into consideration.
</p>

<p>
  When I say that SecureID (and others) are fundamentally broken what I mean is that
  when (not if, as recent history has shown) RSA (the company) is broken into <b>YOUR</b>
  security is now compromised. When I first used SecureID and found out that you as
  a customer aren't in control of your own keys my first thought was "well that's just
  stupid". Why are you giving the keys to the kingdom to someone else?
</p><p>
  Enter Yubikeys. They just beat SecureID in every way (almost). Benefits:
  <ul>
    <li>Open specification.</li>
    <li>You can set your own keys (secrets) and don't have to show them to a third party who can lose them.</li>
    <li>They're cheap. 25 USD for one (yes you can buy just one if you want)
        and cheaper in bulk, of course. No server license.</li>
    <li>No server license. (this bears repeating). Yes there are products
        you can buy to get features and such, but with minimal coding you can actually get this
        up and running on your website / server logins for free!</li>
    <li>Looong OTP tokens. If you don't have some account locking feature on your servers
        you can brute-force 6 digits fairly quickly. OpenSSH by default allows 10
        unauthenticated sessions with one attempt per second. You can script that
        to log in in less than a day.</li>
  </ul>
  Cons:
  <ul>
    <li>No clock in the device. While plugged in the token it generates will
        be a function of how long it's been powered up this session, but it doesn't
        have a battery-powered clock that you can sync with the server.</li>
    <li>No display on the device. Well, you wouldn't want to key in a really long
        token anyway, but if you can't insert USB into the terminal or want to use it to log in
        somewhere with your phone then you're screwed. I bet Yubico are working on
        some <a href="http://en.wikipedia.org/wiki/Near_field_communication">NFC</a>
        to fix that though. (the RFID parts of some Yubikeys are something separate
        that I'm not including here)</li>
  </ul>
  Maybe to fix that last point someone should make a handheld device that you can
  plug your Yubikey into where all it can do is display what's typed.

<h2>So what can you do with a Yubikey?</h2>
The Yubikey has two slots, and you can do different things with the two slots.

<h3>Simple OTP generation</h3>
When you press the button it'll generate a token that is "typed" (the
Yubikey will appear to be a USB keyboard to the computer) that's a function of:
<ul>
  <li>The secret key (obviously)</li>
  <li>The time since this session started</li>
  <li>Number of tokens generated this session</li>
  <li>Number of sessions since device was programmed</li>
  <li>Key ID (user settable), so you know which secret key to use do decode the token.</li>
  <li>Some other less interesting fields. This list is intentionally not complete.</li>
</ul>
A "session" is "when it's plugged in". This means you can always tell an earlier token
from a more recent one (if you know the secret key). The data is encrypted (not HMACed) so that the
verifier (the server) can read the fields and see that it's not an old token. But this
is where the lack of a clock kicks in. You can generate a token and then wait a year before
you use it. If (and only if) no newer token has been used, that token is still valid.
</p><p>
  This waiting is not possible when using challenge-response mode (see below).
</p>

<h3>Symantec VIP</h3>
<p>
If you buy one for personal use I'd recommend buying the VIP key. It's the same price
as the normal one but it comes pre-programmed in slot 1 with something you can use to
log into your paypal account (once you associate the key with your account).
</p><p>
You can still use slot 2 for something else.
</p>

<h3>Static password</h3>
Meh. I haven't had the need for this. It's the equivalent of a long password that you've
written down, except the convenience that you don't have to type. If someone has physical
access they can copy the password just like a written-down one.

<h3>HOTP</h3>
Generate standard HOTP, in case you're already using those you can use
a Yubikey to generate them instead of whatever device you're currently using.

<h3>Challenge-response mode</h3>
If you want to make sure that the Yubikey is plugged into a computer when
the authentication is taking place then challenge-response is for you. Since
keyboards are one-way devices this means that the "the Yubikey is just a keyboard,
no software required" breaks down. I suppose the OS could flash the caps lock lamp
to send data to a keyboard without extra functions, but the point is that would
also require software that is Yubikey-aware on the client. The other modes do not
require this. They work with everything that understands USB keyboards.
</p><p>
So what you need on your client is a program that can take the challenge from
the server, send it to the Yubikey and then send the reply back to the server.
If you are an online game developer this would just be something you put into
your game. As long as the users have their Yubikey plugged into their machine
they can log in and play.
</p><p>
I've created some scripts to use this for unix authentication that I'll be releasing
in a week or two. You SSH to some server, the server says "Yubikey challenge: XXX[...]: ",
you copy that challenge (just select it) and press a key combination that starts
this script. The script takes the challenge from the clipboard, gets the reply
from the Yubikey and "types" it. Challenge-responses aren't "typed" by the Yubikey
so I'm doing that in the script. And presto, you get challenge-response Yubikey
authentication with SSH and every other application without having to code it into
your client.

<h2><a href="http://www.yubico.com/YubiHSM">YubiHSM</a></h2>
This is a different product. It's for servers, not clients. It will protect you against
your whole password database being stolen if you have a break-in. For many people
losing their users passwords is worse than losing the data. Think of sites like
<a href="http://www.twitter.com">Twitter</a>,
<a href="http://www.stackoverflow.com">stackoverflow.com</a> and other public-data
websites. Do they care if someone steals their whole database? Of course they do, but
if they at least don't lose their passwords then when the system is fixed and backdoors
removed (a whole topic in itself) they're done. If they lose everyones password then
not only do they have to ask all their users to change their password, but also that
they must stop using that password everywhere else they may have used it. You're not
supposed to reuse passwords, but the reality is that people do.
</p><p>
By the way, I don't care if you hash your passwords with unique salt for everyone. If
you lose that database then you've lost the users' passwords.
</p><p>
YubiHSM is a USB-attached device that doesn't emulate a keyboard. It has several functions
(including the ability to do the logic of a Yubikey authentication server) but to
me the most interesting is protecting the password database.
</p><p>
In short, YubiHSM can give you an interface where you can use just two operations:
<ul>
  <li>Set password. This will not store anything on the YubiHSM but will give you
      back a blob that only the YubiHSM can decrypt.</li>
  <li>Check password. You supply a password and a blob and the YubiHSM says "yes" or "no".
      It does not give you the password.</li>
</ul>
So the only way to crack the password file once stolen (short of breaking AES) is
to try password after password with the "check password" function until you hit the
right one. Since you have to send all these check commands to the YubiHSM it doesn't scale.
The attacker can't simply buy 100 Amazon EC2 machines to attack you. And when you notice
that someone broke in to your server you can just detach the YubiHSM and even that attack
vector is gone.
</p><p>
Using <a href="https://github.com/ThomasHabets/yhsmpam">yhsmpam</a> I've used this to
secure a unix machine. Think of it as moving from storing hashes in /etc/passwd to storing
them in /etc/shadow, but this time moving from /etc/shadow to YubiHSM.
</p><p>
Unfortunately YubiHSM isn't for sale yet. Oooh! I just checked
<a href="http://www.yubico.com/YubiHSM">the website</a> and it's going on sale on 18 August 2011.
At 500 USD it's more expensive than the Yubikey, but then again you only need it for your
authentication server, not for every user. 500 USD is NOT a lot for this kind of hardware. Before YubiHSM
you'd have to cough up 15k+ USD to get this. PRE-ORDER NOW! Run, do not walk, to
<a href="https://store.yubico.com/">their online store</a>.

<h2>Complaints</h2>
<ul>
  <li>No clock in the Yubikey</li>
  <li>Hard to use Yubikey with phone</li>
  <li>While all "normal" keyboard layouts work fine (including German), Dvorak will not work
      well with Yubikeys by default. Well, with my ChromeOS laptop it did work by default, but still.</li>
</ul>

<h2>Links</h2>
<ul>
 <li><a href="http://www.yubico.com">Yubico</a></li>
 <li><a href="https://github.com/ThomasHabets/pam_externalpass">pam_externalpass</a>
     - PAM module I use to do more fancy auth.</li>
 <li><a href="https://github.com/ThomasHabets/yhsmpam">YHSMPAM</a> - Backend for keeping UNIX passwords in YubiHSM</li>
 <li><a href="https://github.com/ThomasHabets/yoracle">YOracle</a> - My own yubikey validator server.</li>
 <li>[Placeholder for when I release the challenge-response code]</li>
</ul>]]></description>
   <link>http://blog.habets.pp.se/2011/07/Yubico-is-awesome</link>
   <guid>http://blog.habets.pp.se/2011/07/Yubico-is-awesome</guid>
   <pubDate>Sun, 17 Jul 2011 23:59:25 GMT</pubDate>
  </item>
  <item>
   <title>OpenSSH certificates</title>
   <description><![CDATA[The documentation for OpenSSH certificates (introduced in OpenSSH 5.4) are, shall we say, a bit lacking. So I'm writing down the essentials of what they are and how to use them.

<h2>What they are NOT</h2>
<h3>They're not SSH PubkeyAuthentication</h3>
<p>
  In other words if your .pub file doesn't end in -cert.pub
  and you haven't used ssh-keygen -s, then you aren't using certificates.
</p>



<h3>They're not SSL</h3>
  Still the same SSH protocol.

<h3>They're not PEM, x509 ASN.1 or any other insane format</h3>
  This means you cannot get your keys signed by Verisign
  or any other root CA. And you cannot use multiple levels of CA.

<h3>They're not easy to google for</h3>
  Most hits will be about normal pubkey authentication. Some
  will be about older patches to one SSH implementation or
  another that  added some form of PKI, even x509 support.
  You'll probably have the most luck googling for
  "ssh-keygen -s" (with quotes).

<h2>What they do</h2>
<h3>Sign host keys</h3>
  If an organization publishes their host-key signing CAs public
  key you can just get that and you'll never have to see the familiar:
<blockquote><pre>
The authenticity of host 'xxx' can't be established.
RSA key fingerprint is xxx.
Are you sure you want to continue connecting (yes/no)? 
</pre></blockquote>

<h3>Sign user keys</h3>
  Instead of copying your public key into thousands of
  servers ~/.ssh/authorized_keys you just have the user CA
  public key there (or system wide) and with one change it's
  ready for all future users of the system.

<h3>Either or both of the above</h3>
  User CA and host CA don't depend on each other. They don't have to have the same key.

<h3>Allow you to expire certs</h3>
  While <b>keys</b> don't expire, the <b>certs</b> can if you want.

<h2>Setting up host certificates</h2>
<ol>
  <li>On the machine that you'll be storing your CA on: Create host CA key (host_ca & host_ca.pub):
    <blockquote>ssh-keygen -f host_ca</blockquote>
  </li>
  <li>Sign existing host public key:
    <blockquote>
      ssh-keygen -s host_ca -I host_foo -h -n
      foo.bar.com -V +52w /etc/ssh/ssh_host_rsa_key.pub
    </blockquote>
    Copy /etc/ssh/ssh_host_rsa_key.pub from other servers and this command
    on those files too, and copy the resulting back to the server.
  </li>
  <li>Configure server(s) to present certificate (/etc/ssh/sshd_config):
    <blockquote>HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub</blockquote>
    and restart sshd.
  </li>
  <li>Put host CA in clients known_hosts, such as ~/.ssh/known_hosts
      or a system-wide one. The line should look something like this:
    <blockquote>@cert-authority *.bar.com ssh-rsa AAAAB3[...]== Comment</blockquote>
  </li>
  <li>Remove clients entry (including aliases such as its IP address)
      for the host itself in ~/.ssh/known_hosts (if any)</li>
  <li>Logging in to the correct name should now work and you should
      not be asked about the host key:
    <blockquote>ssh foo.bar.com</blockquote></li>
  <li>Logging in to the IP address of the machine should present
      the message: "Certificate invalid: name is not a listed principal"</li>
</ol>
<p>
  Do NOT forget the -n switch when creating host certificates.
  Otherwise anyone who cracks one machine will be able to impersonate
  any other machine in the domain to users who trust this CA. 
</p>
<p>
  You may need to add something like this to your client config (~/.ssh/config):
<blockquote><pre>
Host * 
  HostKeyAlgorithms ssh-dss-cert-v01@openssh.com,ssh-dss 
</pre></blockquote>
It worked for me without it, but some have needed it.

<h2>Setting up user certificates</h2>
<ol>
  <li>On the machine you'll be storing your CA on: Create user CA key (user_ca & user_ca.pub):
    <blockquote>ssh-keygen -f user_ca</blockquote>
  </li>
  <li>For every server that the certificates should work on:
    <ul>
      <li>Copy user_ca.pub from the CA machine to /etc/ssh/ on the server.</li>
      <li>Add user_ca.pub to servers /etc/ssh/sshd_config:
          <blockquote>TrustedUserCAKeys /etc/ssh/user_ca.pub</blockquote></li>
    </ul>
    And restart sshd.
  </li>
  <li>For each user: Sign existing user pubkey key:
    <blockquote>ssh-keygen -s user_ca -I user_thomas
    -n thomas,thomas2 -V +52w /path/to/id_rsa.pub</blockquote>
    Give the resulting *-cert.pub file back to the user.
  </li>
  <li>Log in as user thomas or thomas2 on the server, even though
      the server has never seen your key or cert before, only
      user_ca.pub.</li>
</ol>

<h2>Some notes</h2>
<ul>
  <li>Never forget -n when creating host certs.</li>
  <li>If you put your user CA in ~/.ssh/authorized_keys instead of
      configuring the server you don't need -n for user certs.
      If you're doing system-wide (as described) it's mandatory.</li>
  <li>The certificate validity time is in UTC</li>
  <li>You can revoke keys and certs with RevokeKeys</li>
  <li>-I just specifies the key ID. It doesn't have to follow the pattern I used.</ri>
  <li>Print certificate information with ssh-keygen -L:
      <blockquote><pre>$ ssh-keygen -L -f user-thomas-cert.pub
user-thomas-cert.pub:
        Type: ssh-rsa-cert-v00@openssh.com user certificate
        Public key: RSA-CERT-V00 a4:b3:6d:e2:bd:4a:39:01:31:c9:05:43:db:78:f6:c9
        Signing CA: RSA a5:e5:20:8e:ea:ea:15:7e:c3:31:60:2d:6b:93:a0:6b
        Key ID: "user_thomas"
        Valid: from 2011-07-07T15:37:00 to 2012-07-05T15:38:11
        Principals: 
                thomas
                thomas2
        Critical Options: 
                permit-agent-forwarding
                permit-port-forwarding
                permit-pty
                permit-user-rc
                permit-X11-forwarding
</pre></blockquote>
  </li>
</ul>

<h2>Links</h2>
<ul>
 <li><a href="http://www.gossamer-threads.com/lists/openssh/users/50165">Email
   thread: getting host certificates working</a></li>
 <li><a href="http://serverfault.com/questions/264515/how-to-revoke-an-ssh-certificate-not-ssh-identity-file">Serverfault: How to revoke an SSH certificate</a></li>
</ul>]]></description>
   <link>http://blog.habets.pp.se/2011/07/OpenSSH-certificates</link>
   <guid>http://blog.habets.pp.se/2011/07/OpenSSH-certificates</guid>
   <pubDate>Wed, 06 Jul 2011 19:16:54 GMT</pubDate>
  </item>
  <item>
   <title>gettimeofday() should never be used to measure time</title>
   <description><![CDATA[<p>
gettimeofday() and time() should only be used to get the current time if the current
wall-clock time is actually what you want. They should <em>never</em> be used to
measure time or schedule an event X time into the future.
</p>


<h2>What's the problem?</h2>
<p>
  gettimeofday() returns the current wall clock time and timezone. time() returns a
  subset of this info (only whole seconds, and not timezone).
</p>

<p>
  Using these functions in order to measure the passage of time (how long an operation took)
  therefore seems like a no-brainer. After all, in real life you measure by checking your watch
  before and after the operation. The differences are:
</p>

<h3>1. Nobody sneaks in and changes your wristwatch when you're not looking</h3>
<p>
  You usually aren't running NTP on your wristwatch, so it probably won't jump a second or two (or 15 minutes)
  in a random direction because it happened to sync up against a proper clock at that point.
</p>
<p>
  Good NTP implementations try to not make the time jump like this. They instead make the clock
  go faster or slower so that it will drift to the correct time. But while it's drifting you
  either have a clock that's going too fast or too slow. It's not measuring the passage of time
  properly.
</p>

<h3>2. You're not stupid, the computer is</h3>
<p>
  Doing something doesn't take less than 0 time. If you get &lt;0 when you measure time, you'll
  realize something is wrong. A program will happily print that a ping reply came back before you sent it.
  Even if you check for time<0, the program that uses gettimeofday() still can't tell the difference between
  a 2 second delay and 3 seconds plus a time adjustment.
</p>

<h3>3. You are the limiting factor</h3>
<p>
  In real life you are not expected to measure sub-second times. You can't measure the difference between
  1.08 seconds and 1.03 seconds. This problem is mostly (but far from entirely) in the small scale.
</p>

<h2>What to use instead</h2>
<p>
  The most portable way to measure time correctly seems to be clock_gettime(CLOCK_MONOTONIC, ...).
  It's not stable across reboots, but we don't care about that. We just want a timer that goes up
  by one second for each second that passes in the physical world.
</p>

<p>
  So if you want to wait 10 seconds, then check the monotonic clock, add 10 seconds and wait until that
  time has come.
<table class="codetable"><tr><td class="linenos"><div class="linenodiv"><pre> 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56</pre></div></td><td class="code"><div class="code"><pre><span class="cp">#include &lt;time.h&gt;</span>
<span class="cp">#include &lt;stdio.h&gt;</span>

<span class="cm">/**                                                                             </span>
<span class="cm"> * sleep for `sec&#39; seconds, without relying on the wall clock of time(2)        </span>
<span class="cm"> * or gettimeofday(2).                                                          </span>
<span class="cm"> *                                                                              </span>
<span class="cm"> * under ideal conditions is accurate to one microsecond. To get nanosecond     </span>
<span class="cm"> * accuracy, replace sleep()/usleep() with something with higher resolution     </span>
<span class="cm"> * like nanosleep() or ppoll().                                          </span>
<span class="cm"> */</span>
<span class="kt">void</span>
<span class="nf">true_sleep</span><span class="p">(</span><span class="kt">int</span> <span class="n">sec</span><span class="p">)</span>
<span class="p">{</span>
        <span class="k">struct</span> <span class="n">timespec</span> <span class="n">ts_start</span><span class="p">;</span>
        <span class="k">struct</span> <span class="n">timespec</span> <span class="n">ts_end</span><span class="p">;</span>

	<span class="n">clock_gettime</span><span class="p">(</span><span class="n">CLOCK_MONOTONIC</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ts_start</span><span class="p">);</span>

        <span class="n">ts_end</span> <span class="o">=</span> <span class="n">ts_start</span><span class="p">;</span>
        <span class="n">ts_end</span><span class="p">.</span><span class="n">tv_sec</span> <span class="o">+=</span> <span class="n">sec</span><span class="p">;</span>

        <span class="k">for</span><span class="p">(;;)</span> <span class="p">{</span>
                <span class="k">struct</span> <span class="n">timespec</span> <span class="n">ts_current</span><span class="p">;</span>
                <span class="k">struct</span> <span class="n">timespec</span> <span class="n">ts_remaining</span><span class="p">;</span>

                <span class="n">clock_gettime</span><span class="p">(</span><span class="n">CLOCK_MONOTONIC</span><span class="p">,</span> <span class="o">&amp;</span><span class="n">ts_current</span><span class="p">);</span>

		<span class="n">ts_remaining</span><span class="p">.</span><span class="n">tv_sec</span> <span class="o">=</span> <span class="n">ts_end</span><span class="p">.</span><span class="n">tv_sec</span> <span class="o">-</span> <span class="n">ts_current</span><span class="p">.</span><span class="n">tv_sec</span><span class="p">;</span>
                <span class="n">ts_remaining</span><span class="p">.</span><span class="n">tv_nsec</span> <span class="o">=</span> <span class="n">ts_end</span><span class="p">.</span><span class="n">tv_nsec</span> <span class="o">-</span> <span class="n">ts_current</span><span class="p">.</span><span class="n">tv_nsec</span><span class="p">;</span>
                <span class="k">while</span> <span class="p">(</span><span class="n">ts_remaining</span><span class="p">.</span><span class="n">tv_nsec</span> <span class="o">&gt;</span> <span class="mi">1000000000</span><span class="p">)</span> <span class="p">{</span>
                        <span class="n">ts_remaining</span><span class="p">.</span><span class="n">tv_sec</span><span class="o">++</span><span class="p">;</span>
                        <span class="n">ts_remaining</span><span class="p">.</span><span class="n">tv_nsec</span> <span class="o">-=</span> <span class="mi">1000000000</span><span class="p">;</span>
                <span class="p">}</span>
		<span class="k">while</span> <span class="p">(</span><span class="n">ts_remaining</span><span class="p">.</span><span class="n">tv_nsec</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
			<span class="n">ts_remaining</span><span class="p">.</span><span class="n">tv_sec</span><span class="o">--</span><span class="p">;</span>
                        <span class="n">ts_remaining</span><span class="p">.</span><span class="n">tv_nsec</span> <span class="o">+=</span> <span class="mi">1000000000</span><span class="p">;</span>
                <span class="p">}</span>

                <span class="k">if</span> <span class="p">(</span><span class="n">ts_remaining</span><span class="p">.</span><span class="n">tv_sec</span> <span class="o">&lt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                        <span class="k">break</span><span class="p">;</span>
                <span class="p">}</span>

                <span class="k">if</span> <span class="p">(</span><span class="n">ts_remaining</span><span class="p">.</span><span class="n">tv_sec</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
                        <span class="nx">sleep</span><span class="p">(</span><span class="n">ts_remaining</span><span class="p">.</span><span class="n">tv_sec</span><span class="p">);</span>
                <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
                        <span class="n">usleep</span><span class="p">(</span><span class="n">ts_remaining</span><span class="p">.</span><span class="n">tv_nsec</span> <span class="o">/</span> <span class="mi">1000</span><span class="p">);</span>
                <span class="p">}</span>
        <span class="p">}</span>
<span class="p">}</span>

<span class="kt">int</span>
<span class="nf">main</span><span class="p">()</span>
<span class="p">{</span>
        <span class="n">true_sleep</span><span class="p">(</span><span class="mi">10</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</td></tr></table>

<p>
  The same method works if you want to schedule something in the future, or see how long something took.
  I've found that I very rarely actually need the wall clock time in programs. The only exceptions I can think
  of are when it should be store on disk (valid across reboot or with NFS across server) or when the time
  (not the time delta) should be shown to the user.
</p>

<p>
  The case of "sleep" can actually be solved by clock_nanosleep(), but I wanted an example that could
  illustrate how to measure too.
</p>

<p>
  If clock_gettime(CLOCK_MONOTONIC, ...) is not available on your system, then try to find a monotonic
  clock that is. Like gethrtime() or CLOCK_HIGHRES on Solaris. I have created
  <a href="https://github.com/ThomasHabets/monotonic_clock">a portable library for getting monotonic time</a>.
</p>

<h2>The guilty ones</h2>
<h3>libpcap</h3>
<p>
  The pcap_pkthdr struct (the "received packet" struct) contains a struct timeval ts that
  ruins our ability to measure the time it takes for the reply you get for some query you sent.
  <a href="http://www.mail-archive.com/tcpdump-workers@lists.tcpdump.org/msg05261.html">They tell me</a>
  the kernel supplies the timestamp, so it's not really libpcaps fault.
</p>
<p>
  Calling clock_gettime() when libpcap gives you a packet has turned out to be useless, as the
  time difference between packet reception and the delivery to your program is too long and unstable.
  You're stuck with this wall-clock time until you fix all the kernels in the world and break binary
  compatibility with old libpcap programs.
</p>

<h3>ping</h3>
<p>
  Try running a ping and setting the time in the past. Ping will freeze waiting until it thinks it's
  time for the next packet. Tried with iputils ping for Linux. A brief survey of the source code of
  other OpenSource pings show this:
  <ul>
    <li><a href="http://www.freebsd.org/cgi/cvsweb.cgi/src/sbin/ping/ping.c?rev=1.113">FreeBSD</a>: Same as Linux</li>
    <li><a href="http://cvsweb.netbsd.org/bsdweb.cgi/src/sbin/ping/ping.c?rev=1.90&content-type=text/x-cvsweb-markup&only_with_tag=MAIN">NetBSD</a>: Much code in common with FreeBSD. This too looks the same.</li>
    <li><a href="http://www.opensource.apple.com/source/network_cmds/network_cmds-329.2/ping.tproj/ping.c">Mac OSX</a>: Same heritage, same fault</li>
    <li><a href="http://www.openbsd.org/cgi-bin/cvsweb/src/sbin/ping/ping.c?rev=1.88">OpenBSD</a>: Seems OK because they (surprise surprise) ignore the C standard and do the work in a SIGALRM handler</li>
    <li><a href="http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/ping/ping.c#sigalrm_handler">Solaris</a>: Same as OpenBSD, except they don't support fractional second intervals</li>
  </ul>
  Note that I haven't actually tested to confirm these (except Linux). I've just quickly scanned through the source code.
</p>

<p>
  It seems that the only people who got the ping send scheduler right in this regard did it at the expense of not following
  the C standard, and nobody got the RTT calculation right. Solaris actually used a monotonic clock (gethrtime())
  in other parts of the code, but not for RTT calculation.
</p>

<p>
  I have sent <a href="http://www.spinics.net/lists/netdev/msg139987.html">a patch</a> to fix this on Linux ping.
  It has not yet been applied to upstream.
</p>

<h3>Oracle database</h3>
<p>
  If time was set backwards then Oracle would <em>reboot</em> the machine. <a href="http://database.in2p3.fr/10203_buglist.htm">Really</a>. (bug ID seems to be 5015469)
</p>
<p>
  When a leap second is inserted into the official time, such as 2008-12-31 23:59:<b>60</b>, all the other clocks
  are suddenly fast, and therefore adjust themselves backwards. On newyears day 2009 many people woke up to their
  Oracle servers having rebooted. Not simply shut down the oracle process, but actually rebooted the server.
</p>

<h3>F5</h3>
<p>
  F5 BigIP load balancers seem to cut all active connections when time is set backwards. So if you use
  two NTP servers that don't have the same time, all your connections will be cut when your load
  balancer flips back and forth between the two upstream times.
</p>

<h3>Me</h3>
<p>
  At least arping and gtping didn't handle this properly and could in some cases (not always) act
  like Linux ping. I have fixed both of them and it'll be in the next version. I had put off fixing
  them because I wanted a solution that solved packet timings as well as packet scheduling, but
  at least with arping that doesn't seem possible due to the libpcap issue mentioned above.
</p>
<p>
  GTPing should now have this solved perfectly, and ARPing should only show incorrect times for
  replies when the wall clock changes or drifts, but the scheduler should still send one packet
  per interval.
</p>

<h3>Everyone else?</h3>
<p>
  I'd be surprised to see <em>any</em> program handling this correctly. Please let me know if
  you find one.
</p>

<h2>Exception</h2>
<p>
  If a wall-clock time is all you can get (such as from libpcap), then you're gonna have to use that. But
  you don't have to like it. And avoid wall time where at all possible.
</p>

<h2>Unrelated note</h2>
<p>
  When I turn on the GPS I have in my car after it's been off for too long it asks
  me where I am and what time and date it is. Why would a GPS possibly want to ask
  me those things? Telling <em>me</em> where I am and what time it is is <em>what
  it was made to do</em>.
</p>
<p>
  <em>Update</em>: As a couple of people have pointed out there is a "right" answer to this.
  It's not a problem for newer GPS units, but
  <a href="https://secure.wikimedia.org/wikipedia/en/wiki/GPS_signals#Almanac">there it is</a>.
</p>

<h2>Links</h2>
<ul>
  <li><a href="http://code-factor.blogspot.com/2009/11/monotonic-timers.html">Doug Coleman on Monotonic timers</a></li>
  <li><a href="https://github.com/ThomasHabets/monotonic_clock">Portable library for getting monotonic time</a></li>
  <li><a href="http://www.smbc-comics.com/index.php?db=comics&id=2035#comic">My feelings about GPSs</a></li>
  <li><a href="http://code.google.com/p/anacrolix/source/browse/projects/pimu/monotime.py">Monotonic time in Python</a></li>
</ul>]]></description>
   <link>http://blog.habets.pp.se/2010/09/gettimeofday-should-never-be-used-to-measure-time</link>
   <guid>http://blog.habets.pp.se/2010/09/gettimeofday-should-never-be-used-to-measure-time</guid>
   <pubDate>Sun, 05 Sep 2010 15:22:47 GMT</pubDate>
  </item>
  <item>
   <title>tlssh - a replacement for SSH</title>
   <description><![CDATA[<p>
I've started writing a replacement for SSH.
</p><p>

Why? Because SSH has some drawbacks that sometimes annoy me. I also wanted
an authentication scheme that's more similar to SSL/TLS than what SSH does.
</p><p>
With tlssh you don't specify username or password, you simply connect to the
server using a client-side certificate to log in as the user specified in the
certificate. No interaction until you reach the shell prompt on the server.
</p>

<p>
Of course you can log in using a public key with SSH, but it's only a public/private
key pair, there's none of the
<a href="https://secure.wikimedia.org/wikipedia/en/wiki/Public_key_infrastructure">PKI</a>
that SSL has.
</p><p>
Specifically, what I was missing in SSH was:
<ul>
  <li>Expiring keys, both login-keys and server certificates</li>
  <li><a href="https://secure.wikimedia.org/wikipedia/en/wiki/Certificate_revocation_list">CRL</a>s
  (Certificate Revocation Lists) - wouldn't it be nice to just revoke the
  all certificates that were on a compromised machine and they'll suddenly be unusable
  everywhere? (I will add
  <a href="https://secure.wikimedia.org/wikipedia/en/wiki/OCSP">OCSP</a> too. Same
  thing but more "online")</li>
  <li>Pureness. Not all these channels and port forwarding features that complicate
  everything (and adds bugs).</li>
  <li>TCP MD5. I doubt SSH will ever get this. (temporarily disabled in tlssh)</li>
  <li>CA-signed server certificate. Use Verisign-signed certificates (if you trust them) and
  you'll have none of that "confirm server fingerprint" stuff.</li>
  <li>Will get some client-side features that I've missed in SSH. Like "take a
  file from the local filesystem as send it as if I typed it", to avoid having
  to scp 5 times because you have to transfer a file hop-by-hop. The OpenSSH folks
  rejected my patch for this.
  </li>
</ul>
</p><p>
It's built on <a href="http://www.openssl.org">OpenSSL</a>, so as long as there aren't
any bugs in the X.509 parsing
in OpenSSL I should be fine. Unfortunately X.509 is a horrible mess of a format
so this is not impossible. Activating TCP MD5 before SSL negotiation should
lessen the risk, but still.
</p><p>
To log in to a server you create a certificate with CommonName bob.users.example.com,
and get it signed by the CA the server trusts. The server will split this
CommonName into the user part and the domain part. The domain part must match
what the server is expecting. If everything is fine (and the certificate is not
in the CRL, and the CRL is not too old), you are presented with a shell as the user
mentioned in the user part of the certificate.
</p><p>
To log in as a different user you have to create a second certificate.
</p><p>
Another reason I'm writing tlssh is to learn OpenSSL. The OpenSSL API is
horrible, as it turned out.
</p><p>
It's also fun to code system level stuff, creating terminals and such.
You learn that <a href="http://www.openbsd.org/">OpenBSD</a> doesn't seem to
care about <a href"https://secure.wikimedia.org/wikipedia/en/wiki/POSIX">POSIX</a> or other standards.
When some library call is acting funny you can often google your way to some
top OpenBSD-developer saying "who cares about POSIX? That was a stupid question"
when someone notices the non-compliance. They still don't have wordexp() for example.
</p><p>
<h2>Drawbacks</h2>
<ul>
 <li>Not as portable as <a href="http://www.openssh.org/">OpenSSH</a>. Currently
 works on Linux, OpenBSD and Solaris.</li>
 <li>Not as audited (I wholeheartedly invite more eyes, and code too)</li>
 <li>Because it needs a CA to sign certificates, it's not initially as plug-and-play as SSH.</li>
 <li>Like I said X.509 is horrible. Hopefully OpenSSL parses it perfectly, but you never know.</li>
</ul>

<h2>Resources</h2>
<ul>
 <li><a href="http://github.com/ThomasHabets/tlssh">tlssh on Github</a></li>
 <li>git clone git://github.com/ThomasHabets/tlssh.git</li>
</ul>]]></description>
   <link>http://blog.habets.pp.se/2010/08/tlssh---a-replacement-for-SSH</link>
   <guid>http://blog.habets.pp.se/2010/08/tlssh---a-replacement-for-SSH</guid>
   <pubDate>Thu, 05 Aug 2010 19:33:00 GMT</pubDate>
  </item>
  <item>
   <title>The rules of multicast</title>
   <description><![CDATA[<h2>The first rule of multicast is you <em>don't</em> talk about multicast</h2>
<p>
  Most networks don't do multicast routing, which means most network guys don't
  have much experience with it. Sure they know that it exists, and it's probably
  used on their layer 2, but they don't do multicast routing. These "rules" list
  some things that you should know when configuring or troubleshooting multicast.
</p>



<h2>The second rules of multicast is you do <em>not</em> forward packets coming
    from a non-RPF interface</h2>
<p>
  If a multicast packet is received, and it's not the multicast RPF interface,
  it's dropped. The table can be viewed with "show ip mroute", and it will clearly
  show what interface is acceptable. Here's an example of group 239.0.0.1:
  <img style="margin-left: 1em" src="http://cdn.habets.pp.se/blog.habets.pp.se/static/2010-06-xx_multicast_net.png--0" alt="Network map"/>

  <blockquote><pre>R1#show ip mroute 239.0.0.1
[...]
(*, 239.0.0.1), 00:00:08/stopped, RP 1.0.0.1, flags: S
  Incoming interface: Null, RPF nbr 0.0.0.0
  Outgoing interface list:
    FastEthernet1/0, Forward/Sparse, 00:00:08/00:03:21

(1.0.0.2, 239.0.0.1), 00:00:01/00:02:58, flags: 
  Incoming interface: FastEthernet1/1, RPF nbr 1.1.12.2
  Outgoing interface list:
    FastEthernet1/0, Forward/Sparse, 00:00:01/00:03:28</pre></blockquote>
  It clearly shows that packets that come from 1.0.0.2 are only accepted when they come
  in on interface Fa1/1. Packets with any <em>other</em> source address is accepted
  by the (*,G) route from any interface. In both cases the packets will be sent out Fa1/0.
</p>
<p>
  To just show the RPF path to an IP address while not being multicast-specific,
  use "show ip rpf".
  <blockquote><pre>R1#show ip rpf 1.0.0.2
RPF information for ? (1.0.0.2)
  RPF interface: FastEthernet1/1
  RPF neighbor: ? (1.1.12.2)
  RPF route/mask: 1.0.0.2/32
  RPF type: unicast (ospf 1)
  RPF recursion count: 0
  Doing distance-preferred lookups across tables</pre></blockquote>
</p>

<h2>Third rule: no show ip cef, no debug ip packet</h2>
<p>
  You can't go low-level as in unicast and do "show ip cef &lt;destination address&gt;".
  In order to see what path a forwarded (or locally originating) multicast packet takes,
  you have to check "show ip mroute". Multicast packets do not show up when doing
  "debug ip packet". The command to use is "debug ip mpacket", and even then
  you must run "no ip mroute-cache" on interfaces where you want to see packets.
</p>

<h2>Fourth rule: Only one RP per group</h2>
<p>
  If you use Auto-RP or PIMv2 BSR this won't be a problem. The protocol should take care
  to only create one RP per group. When you define your RPs statically (ip pim rp-address
  &lt;rp-address&gt;), however, you run the risk having two unrelated RPs. You can also
  get this if you only have one RP address IP, but you announce it from two or more routers
  in the network (anycast RP). If you have multiple RPs then they will have to talk to each other to
  make sure they all have a complete list of all senders in the network. Do this by setting
  up MSDP between them.
</p>

<h2>Rule 5: The unicast routing table is not to be trusted</h2>
<p>
  "show ip route" is not used for multicast routing. Sure, the unicast topology is a source
  of information for the multicast one. But if you're troubleshooting it just might be
  (i.e.: probably is) because the process of creating the multicast routing table is not
  working properly. Your first source of information is and always should be "show ip mroute".
  You also have "show ip mroute &lt;group-address&gt; count", which shows counters for each
  source and a bit of information as to why packets (if any) are being dropped, and how many
  are forwarded.
</p>

<h2>Rule 6: For multicast VPNs, lo0 must have PIM turned on</h2>
<p>
  The MDT speaks using the router id. Just make the router id the same for LDP, ISIS/OSPF and BGP
  and nobody will get hurt. lo0 is the simple choice for router id.
</p>


<h2>Rule 7: In order for IGMP snooping to work, you have to define the router port</h2>
<p>
  Describing the problem and possible solutions would make this post way too big. So I'll let
  <a href="http://www.cisco.com/en/US/products/hw/switches/ps708/products_tech_note09186a008059a9df.shtml">Cisco</a>
  do that.
</p>
<p>
  Short version of one of the solutions: Enable PIM on any router facing a switch, even if
  you don't expect to actually talk PIM with any other router on that interface. Also block
  PIM adjacencies from forming so that they aren't formed by mistake.
</p>
<p>
  To confirm proper IGMP snooping, run "show mac-address-table multicast" on the switch.
</p>

<h2>Rule 8: Both sender and receiver side need PIM enabled (or not)</h2>
<p>
  <a href="http://www.ciscosystems.sc/en/US/docs/ios/12_1/iproute/configuration/guide/1cdmulti.html#wp1001064">According to cisco</a>, you need to turn on PIM on an interface in order for
  the router to listen to IGMP (receiver side) and in order to "perform IP multicast routing" (which
  I read as something you need on the sender side). My testing shows that sometimes you don't need
  PIM on the sender side though. But maybe you should enable it just in case. It probably
  should be turned on anyway due to rule 7.
</p>
<p>
  But just as with rule 7, make sure that you don't accidentally set up a PIM adjacency
  with anyone unexpectedly (this can cause your multicast to fail, even if the other router
  isn't misconfigured). If you aren't using PIM to define the router port (rule 7)
  you can use "ip pim passive". Otherwise you should use "ip pim neighbor-filter".
</p>


<h2>Rule 9: MPLS TE networks need "mpls traffic-eng multicast-intact"</h2>
<p>
  I have no idea why this isn't default, but you have to wave your magic wand
  inside your IGP section. "mpls traffic-eng multicast-intact". Otherwise you
  won't have "interoperability between PIM and MPLS-TE". What that means is that
  your RPF will be toast and traffic will be dropped.
</p>
<p>
  Don't turn on PIM on your TE tunnel. It will not work. The short story is
  that a TE tunnel is unidirectional, so you won't be able to set up a PIM
  adjacency over it. But if you try you will only get your routers hopes up,
  but hoping for something that will never happen. You can see how hopeless
  it is with the command "show ip rpf &lt;sender-address&gt;".
</p>

<h2>If this is your first multicast network, you <em>have</em> to play around</h2>
<p>
  show ip mroute, show ip rpf, debug ip mpacket, no ip mroute-cache. Play with them.
  Learn them. Learn them well. You can know all the unicast you want, but it
  won't impress multicast one bit.
</p>

<h2>Links</h2>
<ul>
<li><a href="http://www.cisco.com/en/US/tech/tk828/technologies_tech_note09186a0080094821.shtml">Multicast Quick-Start Configuration Guide</a></li>
<li><a href="http://www.cisco.com/en/US/products/hw/switches/ps708/products_tech_note09186a008059a9df.shtml">Multicast Does Not Work in the Same VLAN in Catalyst Switches</a></li>
<li><a href="http://www.ciscosystems.com.ro/en/US/docs/ios/12_0s/feature/guide/mplstemi.html">mpls traffic-eng multicast-intact Command</a></li>
<li><a href="http://www.ciscosystems.sc/en/US/docs/ios/12_1/iproute/configuration/guide/1cdmulti.html#wp1001064">Enabling PIM on an Interface</a></li>
</ul>]]></description>
   <link>http://blog.habets.pp.se/2010/06/The-rules-of-multicast</link>
   <guid>http://blog.habets.pp.se/2010/06/The-rules-of-multicast</guid>
   <pubDate>Fri, 11 Jun 2010 17:06:22 GMT</pubDate>
  </item>
 </channel>
</rss>

