Sophie

Sophie

distrib > Fedora > 15 > i386 > by-pkgid > e3a718fcad37ff363f65d6a6e994e272 > files > 281

ldns-devel-1.6.12-1.fc15.i686.rpm

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><meta http-equiv="Content-Type"
content="text/html;charset=iso-8859-1">
<title>ldns documentation</title>
<link href="doxygen.css" rel="stylesheet" type="text/css">
<link href="tabs.css" rel="stylesheet" type="text/css">
</head><body>
<div class="logo">
<img src="LogoInGradientBar2-y100.png"/>
</div>
<!-- Generated by Doxygen 1.7.4 -->
  <div id="navrow1" class="tabs">
    <ul class="tablist">
      <li><a href="index.html"><span>Main&#160;Page</span></a></li>
      <li class="current"><a href="pages.html"><span>Related&#160;Pages</span></a></li>
      <li><a href="annotated.html"><span>Data&#160;Structures</span></a></li>
      <li><a href="files.html"><span>Files</span></a></li>
      <li><a href="dirs.html"><span>Directories</span></a></li>
    </ul>
  </div>
</div>
<div class="header">
  <div class="headertitle">
<div class="title">Tutorial 3: Signing a zone file </div>  </div>
</div>
<div class="contents">
<div class="textblock"><p>The full source code can be found in <a class="el" href="ldns-signzone_8c.html">examples/ldns-signzone.c</a></p>
<p>Of course, we start by the usual includes. Since we need a bit more here, we'll add those right away.</p>
<p><div class="fragment"><pre class="fragment"><span class="preprocessor">#include &quot;config.h&quot;</span>
<span class="preprocessor">#include &lt;stdlib.h&gt;</span>
<span class="preprocessor">#include &lt;unistd.h&gt;</span>

<span class="preprocessor">#include &lt;errno.h&gt;</span>

<span class="preprocessor">#include &lt;time.h&gt;</span>

<span class="preprocessor">#include &lt;<a class="code" href="ldns_8h.html" title="Including this file will include all ldns files, and define some lookup tables.">ldns/ldns.h</a>&gt;</span>
<span class="preprocessor">#include &lt;<a class="code" href="keys_8h.html" title="Addendum to dnssec.h, this module contains key and algorithm definitions and functions.">ldns/keys.h</a>&gt;</span>

<span class="preprocessor">#ifdef HAVE_SSL</span>
<span class="preprocessor"></span><span class="preprocessor">#include &lt;openssl/conf.h&gt;</span>
<span class="preprocessor">#include &lt;openssl/engine.h&gt;</span>
<span class="preprocessor">#endif </span><span class="comment">/* HAVE_SSL */</span>

<span class="preprocessor">#define MAX_FILENAME_LEN 250</span>
</pre></div></p>
<p>Let's skip the boring usage() and sanity check functions, and dive right into <a class="el" href="linktest_8c.html#a840291bc02cba5474a4cb46a9b9566fe">main()</a>.</p>
<p><div class="fragment"><pre class="fragment"><a class="code" href="linktest_8c.html#a840291bc02cba5474a4cb46a9b9566fe">main</a>(<span class="keywordtype">int</span> argc, <span class="keywordtype">char</span> *argv[])
{
</pre></div></p>
<p>We'll be reading another zone file, so let's prepare some variables for that.</p>
<p><div class="fragment"><pre class="fragment">        <span class="keyword">const</span> <span class="keywordtype">char</span> *zonefile_name;
        FILE *zonefile = NULL;
        <span class="keywordtype">int</span> line_nr = 0;
        <span class="keywordtype">int</span> c;
        <span class="keywordtype">int</span> argi;
</pre></div></p>
<p>We will create a separate zone structure for the signed zone, so let's have a clear name for the original one.</p>
<p><div class="fragment"><pre class="fragment">        <a class="code" href="structldns__struct__zone.html" title="DNS Zone.">ldns_zone</a> *orig_zone;
        <a class="code" href="structldns__struct__rr__list.html" title="List or Set of Resource Records.">ldns_rr_list</a> *orig_rrs = NULL;
        <a class="code" href="structldns__struct__rr.html" title="Resource Record.">ldns_rr</a> *orig_soa = NULL;
        <a class="code" href="structldns__struct__dnssec__zone.html" title="Structure containing a dnssec zone.">ldns_dnssec_zone</a> *signed_zone;
</pre></div></p>
<p>To sign a zone, we need keys, so we need some variables to read and store it;</p>
<p><div class="fragment"><pre class="fragment">        <span class="keywordtype">char</span> *keyfile_name_base;
        <span class="keywordtype">char</span> *keyfile_name = NULL;
        FILE *keyfile = NULL;
        <a class="code" href="structldns__struct__key.html" title="General key structure, can contain all types of keys that are used in DNSSEC.">ldns_key</a> *key = NULL;
        <a class="code" href="structldns__struct__key__list.html" title="Same as rr_list, but now for keys.">ldns_key_list</a> *keys;
        <a class="code" href="error_8h.html#aaa6d98f86f535cf87b83b89e91f488f9">ldns_status</a> s;
</pre></div></p>
<p>The <a class="el" href="keys_8h.html#a7f4a39b1b2b9a8bf834ba4a10dc06420">ldns_key</a> structure holds (private) keys. These can be of any supported algorithm type; you can put an RSA key in it, an DSA key, or an HMAC key. Public keys can simply be put in an <a class="el" href="rr_8h.html#a34d846d44506c86bc94f244445605e98">ldns_rr</a> structure with type <a class="el" href="rr_8h.html#a640100112b0009efe3d61bbf799b33daa316efb0ac15f31b6891fa6fba833eae8">LDNS_RR_TYPE_DNSKEY</a>.</p>
<p>The <a class="el" href="keys_8h.html#a9694e5e73a6f6e570f4cf79695fd90c7">ldns_key_list</a> type is much like the <a class="el" href="rr_8h.html#a99b7150f3167c5df552095a8f7144f33">ldns_rr_list</a>, only, you guessed it, for <code>ldns_key</code> entries.</p>
<p>The signed zone will be stored in a new file.</p>
<p><div class="fragment"><pre class="fragment">        <span class="keywordtype">char</span> *outputfile_name = NULL;
        FILE *outputfile;
</pre></div></p>
<p>And we have some command line options for the output zone.</p>
<p><div class="fragment"><pre class="fragment">        <span class="comment">/* tmp vars for engine keys */</span>
        <span class="keywordtype">char</span> *eng_key_l;
        <span class="keywordtype">size_t</span> eng_key_id_len;
        <span class="keywordtype">char</span> *eng_key_id;
        <span class="keywordtype">int</span> eng_key_algo;
        
        <span class="keywordtype">bool</span> use_nsec3 = <span class="keyword">false</span>;
        <span class="keywordtype">int</span> signflags = 0;

        <span class="comment">/* Add the given keys to the zone if they are not yet present */</span>
        <span class="keywordtype">bool</span> add_keys = <span class="keyword">true</span>;
        uint8_t nsec3_algorithm = 1;
        uint8_t nsec3_flags = 0;
        <span class="keywordtype">size_t</span> nsec3_iterations_cmd = 1;
        uint16_t nsec3_iterations = 1;
        uint8_t nsec3_salt_length = 0;
        uint8_t *nsec3_salt = NULL;
        
        <span class="comment">/* we need to know the origin before reading ksk&#39;s,</span>
<span class="comment">         * so keep an array of filenames until we know it</span>
<span class="comment">         */</span>
        <span class="keyword">struct </span>tm tm;
        uint32_t inception;
        uint32_t expiration;
        <a class="code" href="structldns__struct__rdf.html" title="Resource record data field.">ldns_rdf</a> *origin = NULL;
        uint32_t ttl = <a class="code" href="ldns_8h.html#a2bdd8bfa0eb61ccf7719d5ffcd1ac79e">LDNS_DEFAULT_TTL</a>;
        <a class="code" href="rr_8h.html#aa11e99c7e7c630e03373f2a2cafc4ee9">ldns_rr_class</a> <span class="keyword">class </span>= <a class="code" href="rr_8h.html#adc72070b39f210fae670577de8136600a2ad89c0befc939420e3b1157c07a8b46" title="the Internet">LDNS_RR_CLASS_IN</a>; 
</pre></div></p>
<p><code>origin</code> is a domain name, so it can be stored in an <a class="el" href="rdata_8h.html#adb9c97875196c13e6d1996ae0fd17f86">ldns_rdf</a> variable with type <a class="el" href="rdata_8h.html#aaa92376014f0abbf0110ca6efd587bb9a72cb73467bcbfbb41168e2a2b4a8283a">LDNS_RDF_TYPE_DNAME</a>.</p>
<p>The next part is option parsing, which is pretty straightforward using <code>getopt()</code>, so we'll skip this too. U can always look to the source of the file to check it out.</p>
<p>Okay that's it for the variables, let's get to work!</p>
<p>First we'll try to read in the zone that is to be signed.</p>
<p><div class="fragment"><pre class="fragment">                zonefile = fopen(zonefile_name, <span class="stringliteral">&quot;r&quot;</span>);
                
                <span class="keywordflow">if</span> (!zonefile) {
                        fprintf(stderr,
                                   <span class="stringliteral">&quot;Error: unable to read %s (%s)\n&quot;</span>,
                                   zonefile_name,
                                   strerror(errno));
                        exit(EXIT_FAILURE);
                } <span class="keywordflow">else</span> {
</pre></div></p>
<p>If the file exists and can be read, we'll let ldns mold it into a zone structure:</p>
<p><div class="fragment"><pre class="fragment">                        s = <a class="code" href="zone_8c.html#accd66901157e00acd3b4b571aa7092b8">ldns_zone_new_frm_fp_l</a>(&amp;orig_zone,
</pre></div></p>
<p>This creates a new (<code>new</code>) zone from (<code>frm</code>) a filepointer (<code>fp</code>), while remembering the current line (<code>l</code>) in the input file (for error messages).</p>
<p>A pointer to the zone structure to be filled is passed as the first argument, like in most <code>new_frm</code> functions.</p>
<p>Like a lot of ldns functions, this one returns a <code>ldns_status</code> indicating success or the type of failure, so let us check that.</p>
<p><div class="fragment"><pre class="fragment">                        <span class="keywordflow">if</span> (s != <a class="code" href="error_8h.html#a11f34802bb1624af46054952e3b853afac58492ee3fc8d23f33c79824ed08c465">LDNS_STATUS_OK</a>) {
                                fprintf(stderr, <span class="stringliteral">&quot;Zone not read, error: %s at %s line %d\n&quot;</span>, 
                                           <a class="code" href="error_8c.html#a4005bb78082a40de485f947470fa5017" title="look up a descriptive text by each error.">ldns_get_errorstr_by_id</a>(s), 
                                           zonefile_name, line_nr);
                                exit(EXIT_FAILURE);
                        } <span class="keywordflow">else</span> {
</pre></div></p>
<p>If everything is ok so far, we check if the zone has a SOA record and contains actual data.</p>
<p><div class="fragment"><pre class="fragment">                                orig_soa = <a class="code" href="zone_8c.html#aae16d59c27e1f2292f8bd87604517e0c" title="Return the soa record of a zone.">ldns_zone_soa</a>(orig_zone);
                                <span class="keywordflow">if</span> (!orig_soa) {
                                        fprintf(stderr,
                                                   <span class="stringliteral">&quot;Error reading zonefile: missing SOA record\n&quot;</span>);
                                        exit(EXIT_FAILURE);
                                }
                                orig_rrs = <a class="code" href="zone_8c.html#a5a75b7744ea0d91770d579730a84bbf9" title="Get a list of a zone&#39;s content.">ldns_zone_rrs</a>(orig_zone);
                                <span class="keywordflow">if</span> (!orig_rrs) {
                                        fprintf(stderr,
                                                   <span class="stringliteral">&quot;Error reading zonefile: no resource records\n&quot;</span>);
                                        exit(EXIT_FAILURE);
                                }
                        }
</pre></div></p>
<p>Now that we have the complete zone in our memory, we won't be needing the file anymore.</p>
<p><div class="fragment"><pre class="fragment">                        fclose(zonefile);
                }
</pre></div></p>
<p>If there was no origin given, we'll use the one derived from the original zone file.</p>
<p><div class="fragment"><pre class="fragment">        <span class="keywordflow">if</span> (!origin) {
                origin = <a class="code" href="rr_8c.html#a1d254bd0deb5d18e34d84ebc10496c5d" title="returns the owner name of an rr structure.">ldns_rr_owner</a>(orig_soa);
        }
</pre></div></p>
<p>No signing party can be complete without keys to sign with, let's fetch those.</p>
<p>Multiple key files can be specified on the command line, by using the base names of the .key/.private file pairs.</p>
<p><div class="fragment"><pre class="fragment">                keyfile_name_base = argv[argi];
                keyfile_name = <a class="code" href="util_8h.html#aaad6949daea3c6cefd01d19300f6e21a">LDNS_XMALLOC</a>(<span class="keywordtype">char</span>, strlen(keyfile_name_base) + 9);
                <a class="code" href="config_8h.html#acc2509f3dc1aeb186437c3fd8412e69a">snprintf</a>(keyfile_name,
                            strlen(keyfile_name_base) + 9,
                            <span class="stringliteral">&quot;%s.private&quot;</span>,
                            keyfile_name_base);
                keyfile = fopen(keyfile_name, <span class="stringliteral">&quot;r&quot;</span>);
</pre></div></p>
<p>As you can see, we append ".private" to the name, which should result in the complete file name of the private key. Later we'll also form the ".key" file name, which will be directly included in the signed zone.</p>
<p>If the file exists, we'll read it and create a <code>ldns_key</code> from its contents, much like the way we read the zone earlier.</p>
<p><div class="fragment"><pre class="fragment">                line_nr = 0;
                <span class="keywordflow">if</span> (!keyfile) {
                        fprintf(stderr,
                                   <span class="stringliteral">&quot;Error: unable to read %s: %s\n&quot;</span>,
                                   keyfile_name,
                                   strerror(errno));
                } <span class="keywordflow">else</span> {
                        s = <a class="code" href="keys_8c.html#a0197f9dd65bae3a3cb408c19683d3db8" title="Creates a new private key based on the contents of the file pointed by fp.">ldns_key_new_frm_fp_l</a>(&amp;key, keyfile, &amp;line_nr);
                        fclose(keyfile);
                        <span class="keywordflow">if</span> (s == <a class="code" href="error_8h.html#a11f34802bb1624af46054952e3b853afac58492ee3fc8d23f33c79824ed08c465">LDNS_STATUS_OK</a>) {
</pre></div></p>
<p>If this went ok, we need to set the inception and expiration times, which are set in the keys, but will eventually end up in the RRSIGs generated by those keys.</p>
<p><div class="fragment"><pre class="fragment">                                <span class="keywordflow">if</span> (expiration != 0) {
                                        <a class="code" href="keys_8c.html#a25f9483844dbd83abca56d725923c591" title="Set the key&#39;s expiration date (seconds after epoch)">ldns_key_set_expiration</a>(key, expiration);
                                }
                                <span class="keywordflow">if</span> (inception != 0) {
                                        <a class="code" href="keys_8c.html#af1521b6b3c0e84a629d09bf237f40308" title="Set the key&#39;s inception date (seconds after epoch)">ldns_key_set_inception</a>(key, inception);
                                }
</pre></div></p>
<p>And now that we have read the private keys, we read the public keys and add them to the zone.</p>
<p>Reading them from the files works roughly the same as reading private keys, but public keys are normal Resource Records, and they can be stored in general <code>ldns_rr</code> structures.</p>
<p><div class="fragment"><pre class="fragment">                                <a class="code" href="util_8h.html#a5e13054aa9b3843e97514228a0bbe909">LDNS_FREE</a>(keyfile_name);
                                
                                <a class="code" href="keys_8c.html#a221251701900a1de52cfe2613a9e6e9d" title="pushes a key to a keylist">ldns_key_list_push_key</a>(keys, key);
                        } <span class="keywordflow">else</span> {
                                fprintf(stderr, <span class="stringliteral">&quot;Error reading key from %s at line %d: %s\n&quot;</span>, argv[argi], line_nr, <a class="code" href="error_8c.html#a4005bb78082a40de485f947470fa5017" title="look up a descriptive text by each error.">ldns_get_errorstr_by_id</a>(s));
                        }
</pre></div></p>
<p>With <code>push()</code> we add them to our key list and our zone. This function clones the data, so we can safely free it after that.</p>
<p><div class="fragment"><pre class="fragment"></pre></div></p>
<p>And if we're done, we free the allocated memory for the file name.</p>
<p><div class="fragment"><pre class="fragment"></pre></div></p>
<p>If the reading did not work, we print an error. Finally, we move on to the next key in the argument list.</p>
<p><div class="fragment"><pre class="fragment"></pre></div></p>
<p>Just to be sure, we add a little check to see if we actually have any keys now.</p>
<p><div class="fragment"><pre class="fragment"></pre></div></p>
<p>So, we have our zone, we have our keys, let's do some signing!</p>
<p><div class="fragment"><pre class="fragment"></pre></div></p>
<p>Yes. That's it. We now have a completely signed zone, <code>ldns_zone_sign</code> checks the keys, and uses the zone signing keys to sign the data resource records. NSEC and RRSIG resource records are generated and added to the new zone.</p>
<p>So now that we have a signed zone, all that is left is to store it somewhere.</p>
<p>If no explicit output file name was given, we'll just append ".signed" to the original zone file name.</p>
<p><div class="fragment"><pre class="fragment"></pre></div></p>
<p><code>ldns_zone_sign</code> returns NULL if the signing did not work, so we must check that.</p>
<p><div class="fragment"><pre class="fragment"></pre></div></p>
<p>Writing to a file is no different than normal printing, so we'll print to the file and close it.</p>
<p><div class="fragment"><pre class="fragment"></pre></div></p>
<p>And of course, give an error if the signing failed.</p>
<p><div class="fragment"><pre class="fragment"></pre></div></p>
<p>Just to be nice, let's free the rest of the data we allocated, and exit with the right return value.</p>
<p><div class="fragment"><pre class="fragment"></pre></div> </p>
</div></div>
<hr class="footer"/><address class="footer"><small>Generated on Wed Jan 11 2012 for ldns by&#160;
<a href="http://www.doxygen.org/index.html">
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.7.4 </small></address>
</body>
</html>