gnunet-handbook

The GNUnet Handbook
Log | Files | Refs

gns.rst (17427B)


      1 .. index::
      2    double: GNU Name System; subsystem
      3    see: GNS; GNU Name System
      4 
      5 .. _GNU-Name-System-Dev:
      6 
      7 GNS
      8 ===
      9 
     10 The GNS API itself is extremely simple. Clients first connect to the GNS
     11 service using ``GNUNET_GNS_connect``. They can then perform lookups
     12 using ``GNUNET_GNS_lookup`` or cancel pending lookups using
     13 ``GNUNET_GNS_lookup_cancel``. Once finished, clients disconnect using
     14 ``GNUNET_GNS_disconnect``.
     15 
     16 .. _Looking-up-records:
     17 
     18 Looking up records
     19 ^^^^^^^^^^^^^^^^^^
     20 
     21 ``GNUNET_GNS_lookup`` takes a number of arguments:
     22 
     23 handle This is simply the GNS connection handle from
     24    ``GNUNET_GNS_connect``.
     25 
     26 name The client needs to specify the name to
     27    be resolved. This can be any valid DNS or GNS hostname.
     28 
     29 zone The client
     30    needs to specify the public key of the GNS zone against which the
     31    resolution should be done. Note that a key must be provided, the
     32    client should look up plausible values using its configuration, the
     33    identity service and by attempting to interpret the TLD as a
     34    base32-encoded public key.
     35 
     36 type This is the desired GNS or DNS record type
     37    to look for. While all records for the given name will be returned,
     38    this can be important if the client wants to resolve record types
     39    that themselves delegate resolution, such as CNAME, PKEY or GNS2DNS.
     40    Resolving a record of any of these types will only work if the
     41    respective record type is specified in the request, as the GNS
     42    resolver will otherwise follow the delegation and return the records
     43    from the respective destination, instead of the delegating record.
     44 
     45 only_cached This argument should typically be set to
     46    ``GNUNET_NO``. Setting it to ``GNUNET_YES`` disables resolution via
     47    the overlay network.
     48 
     49 shorten_zone_key If GNS encounters new names during resolution,
     50    their respective zones can automatically be learned and added to the
     51    \"shorten zone\". If this is desired, clients must pass the private
     52    key of the shorten zone. If NULL is passed, shortening is disabled.
     53 
     54 proc This argument identifies
     55    the function to call with the result. It is given proc_cls, the
     56    number of records found (possibly zero) and the array of the records
     57    as arguments. proc will only be called once. After proc,> has been
     58    called, the lookup must no longer be canceled.
     59 
     60 proc_cls The closure for proc.
     61 
     62 .. _Accessing-the-records:
     63 
     64 Accessing the records
     65 ^^^^^^^^^^^^^^^^^^^^^
     66 
     67 The ``libgnunetgnsrecord`` library provides an API to manipulate the GNS
     68 record array that is given to proc. In particular, it offers functions
     69 such as converting record values to human-readable strings (and back).
     70 However, most ``libgnunetgnsrecord`` functions are not interesting to
     71 GNS client applications.
     72 
     73 For DNS records, the ``libgnunetdnsparser`` library provides functions
     74 for parsing (and serializing) common types of DNS records.
     75 
     76 .. _Creating-records:
     77 
     78 Creating records
     79 ^^^^^^^^^^^^^^^^
     80 
     81 Creating GNS records is typically done by building the respective record
     82 information (possibly with the help of ``libgnunetgnsrecord`` and
     83 ``libgnunetdnsparser``) and then using the ``libgnunetnamestore`` to
     84 publish the information. The GNS API is not involved in this operation.
     85 
     86 .. _Future-work:
     87 
     88 Future work
     89 ^^^^^^^^^^^
     90 
     91 In the future, we want to expand ``libgnunetgns`` to allow applications
     92 to observe shortening operations performed during GNS resolution, for
     93 example so that users can receive visual feedback when this happens.
     94 
     95 libgnunetgnsrecord
     96 ~~~~~~~~~~~~~~~~~~
     97 
     98 The ``libgnunetgnsrecord`` library is used to manipulate GNS records (in
     99 plaintext or in their encrypted format). Applications mostly interact
    100 with ``libgnunetgnsrecord`` by using the functions to convert GNS record
    101 values to strings or vice-versa, or to lookup a GNS record type number
    102 by name (or vice-versa). The library also provides various other
    103 functions that are mostly used internally within GNS, such as converting
    104 keys to names, checking for expiration, encrypting GNS records to GNS
    105 blocks, verifying GNS block signatures and decrypting GNS records from
    106 GNS blocks.
    107 
    108 We will now discuss the four commonly used functions of the
    109 API. ``libgnunetgnsrecord`` does not perform these operations itself,
    110 but instead uses plugins to perform the operation. GNUnet includes
    111 plugins to support common DNS record types as well as standard GNS
    112 record types.
    113 
    114 .. _Value-handling:
    115 
    116 Value handling
    117 ^^^^^^^^^^^^^^
    118 
    119 ``GNUNET_GNSRECORD_value_to_string`` can be used to convert the (binary)
    120 representation of a GNS record value to a human readable, 0-terminated
    121 UTF-8 string. NULL is returned if the specified record type is not
    122 supported by any available plugin.
    123 
    124 ``GNUNET_GNSRECORD_string_to_value`` can be used to try to convert a
    125 human readable string to the respective (binary) representation of a GNS
    126 record value.
    127 
    128 .. _Type-handling:
    129 
    130 Type handling
    131 ^^^^^^^^^^^^^
    132 
    133 ``GNUNET_GNSRECORD_typename_to_number`` can be used to obtain the
    134 numeric value associated with a given typename. For example, given the
    135 typename \"A\" (for DNS A reocrds), the function will return the number
    136 1. A list of common DNS record types is
    137 `here <http://en.wikipedia.org/wiki/List_of_DNS_record_types>`__. Note
    138 that not all DNS record types are supported by GNUnet GNSRECORD plugins
    139 at this time.
    140 
    141 ``GNUNET_GNSRECORD_number_to_typename`` can be used to obtain the
    142 typename associated with a given numeric value. For example, given the
    143 type number 1, the function will return the typename \"A\".
    144 
    145 .. _GNS-plugins:
    146 
    147 GNS plugins
    148 ~~~~~~~~~~~
    149 
    150 Adding a new GNS record type typically involves writing (or extending) a
    151 GNSRECORD plugin. The plugin needs to implement the
    152 ``gnunet_gnsrecord_plugin.h`` API which provides basic functions that
    153 are needed by GNSRECORD to convert typenames and values of the
    154 respective record type to strings (and back). These gnsrecord plugins
    155 are typically implemented within their respective subsystems. Examples
    156 for such plugins can be found in the GNSRECORD, GNS and CONVERSATION
    157 subsystems.
    158 
    159 The ``libgnunetgnsrecord`` library is then used to locate, load and
    160 query the appropriate gnsrecord plugin. Which plugin is appropriate is
    161 determined by the record type (which is just a 32-bit integer). The
    162 ``libgnunetgnsrecord`` library loads all block plugins that are
    163 installed at the local peer and forwards the application request to the
    164 plugins. If the record type is not supported by the plugin, it should
    165 simply return an error code.
    166 
    167 The central functions of the block APIs (plugin and main library) are
    168 the same four functions for converting between values and strings, and
    169 typenames and numbers documented in the previous subsection.
    170 
    171 .. _The-GNS-Client_002dService-Protocol:
    172 
    173 The GNS Client-Service Protocol
    174 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    175 
    176 The GNS client-service protocol consists of two simple messages, the
    177 ``LOOKUP`` message and the ``LOOKUP_RESULT``. Each ``LOOKUP`` message
    178 contains a unique 32-bit identifier, which will be included in the
    179 corresponding response. Thus, clients can send many lookup requests in
    180 parallel and receive responses out-of-order. A ``LOOKUP`` request also
    181 includes the public key of the GNS zone, the desired record type and
    182 fields specifying whether shortening is enabled or networking is
    183 disabled. Finally, the ``LOOKUP`` message includes the name to be
    184 resolved.
    185 
    186 The response includes the number of records and the records themselves
    187 in the format created by ``GNUNET_GNSRECORD_records_serialize``. They
    188 can thus be deserialized using ``GNUNET_GNSRECORD_records_deserialize``.
    189 
    190 .. _Hijacking-the-DNS_002dTraffic-using-gnunet_002dservice_002ddns:
    191 
    192 Hijacking the DNS-Traffic using gnunet-service-dns
    193 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    194 
    195 This section documents how the gnunet-service-dns (and the
    196 gnunet-helper-dns) intercepts DNS queries from the local system. This is
    197 merely one method for how we can obtain GNS queries. It is also possible
    198 to change ``resolv.conf`` to point to a machine running
    199 ``gnunet-dns2gns`` or to modify libc's name system switch (NSS)
    200 configuration to include a GNS resolution plugin. The method described
    201 in this chapter is more of a last-ditch catch-all approach.
    202 
    203 ``gnunet-service-dns`` enables intercepting DNS traffic using policy
    204 based routing. We MARK every outgoing DNS-packet if it was not sent by
    205 our application. Using a second routing table in the Linux kernel these
    206 marked packets are then routed through our virtual network interface and
    207 can thus be captured unchanged.
    208 
    209 Our application then reads the query and decides how to handle it. If
    210 the query can be addressed via GNS, it is passed to
    211 ``gnunet-service-gns`` and resolved internally using GNS. In the future,
    212 a reverse query for an address of the configured virtual network could
    213 be answered with records kept about previous forward queries. Queries
    214 that are not hijacked by some application using the DNS service will be
    215 sent to the original recipient. The answer to the query will always be
    216 sent back through the virtual interface with the original nameserver as
    217 source address.
    218 
    219 .. _Network-Setup-Details:
    220 
    221 Network Setup Details
    222 ^^^^^^^^^^^^^^^^^^^^^
    223 
    224 The DNS interceptor adds the following rules to the Linux kernel:
    225 
    226 ::
    227 
    228    iptables -t mangle -I OUTPUT 1 -p udp --sport $LOCALPORT --dport 53 \
    229    -j ACCEPT iptables -t mangle -I OUTPUT 2 -p udp --dport 53 -j MARK \
    230    --set-mark 3 ip rule add fwmark 3 table2 ip route add default via \
    231    $VIRTUALDNS table2
    232 
    233 .. todo:: 
    234    FIXME: Rewrite to reflect display which is no longer content 
    235    by line due to the < 74 characters limit.
    236 
    237 Line 1 makes sure that all packets coming from a port our application
    238 opened beforehand (``$LOCALPORT``) will be routed normally. Line 2 marks
    239 every other packet to a DNS-Server with mark 3 (chosen arbitrarily). The
    240 third line adds a routing policy based on this mark 3 via the routing
    241 table.
    242 
    243 .. _Importing-DNS-Zones-into-GNS:
    244 
    245 Importing DNS Zones into GNS
    246 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    247 
    248 This section discusses the challenges and problems faced when writing
    249 the Ascension tool. It also takes a look at possible improvements in the
    250 future.
    251 
    252 Consider the following diagram that shows the workflow of Ascension:
    253 
    254 |ascension|
    255 
    256 Further the interaction between components of GNUnet are shown in the
    257 diagram below:
    258 
    259 DNS Conversion
    260 .. _Conversions-between-DNS-and-GNS:
    261 
    262 Conversions between DNS and GNS
    263 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    264 
    265 The differences between the two name systems lies in the details and is
    266 not always transparent. For instance an SRV record is converted to a BOX
    267 record which is unique to GNS.
    268 
    269 This is done by converting to a BOX record from an existing SRV record:
    270 
    271 ::
    272 
    273    # SRV
    274    # _service._proto.name. TTL class SRV priority weight port target
    275    _sip._tcp.example.com. 14000 IN SRV     0 0 5060 www.example.com.
    276    # BOX
    277    # TTL BOX flags port protocol recordtype priority weight port target
    278    14000 BOX n 5060 6 33 0 0 5060 www.example.com
    279 
    280 Other records that need to undergo such transformation is the MX record
    281 type, as well as the SOA record type.
    282 
    283 Transformation of a SOA record into GNS works as described in the
    284 following example. Very important to note are the rname and mname keys.
    285 
    286 ::
    287 
    288    # BIND syntax for a clean SOA record
    289       IN SOA master.example.com. hostmaster.example.com. (
    290        2017030300 ; serial
    291        3600       ; refresh
    292        1800       ; retry
    293        604800     ; expire
    294        600 )      ; ttl
    295    # Recordline for adding the record
    296    $ gnunet-namestore -z example.com -a -n  -t SOA -V \
    297        rname=master.example.com mname=hostmaster.example.com  \
    298        2017030300,3600,1800,604800,600 -e 7200s
    299 
    300 The transformation of MX records is done in a simple way.
    301 
    302 ::
    303 
    304    # mail.example.com. 3600 IN MX 10 mail.example.com.
    305    $ gnunet-namestore -z example.com -n mail -R 3600 MX n 10,mail
    306 
    307 Finally, one of the biggest struggling points were the NS records that
    308 are found in top level domain zones. The intended behaviour for those is
    309 to add GNS2DNS records for those so that gnunet-gns can resolve records
    310 for those domains on its own. Those require the values from DNS GLUE
    311 records, provided they are within the same zone.
    312 
    313 The following two examples show one record with a GLUE record and the
    314 other one does not have a GLUE record. This takes place in the 'com'
    315 TLD.
    316 
    317 .. code-block:: shell
    318 
    319    # ns1.example.com 86400 IN A 127.0.0.1
    320    # example.com 86400 IN NS ns1.example.com.
    321    $ gnunet-namestore -z com -n example -R 86400 GNS2DNS n \
    322        example.com@127.0.0.1
    323 
    324    # example.com 86400 IN NS ns1.example.org.
    325    $ gnunet-namestore -z com -n example -R 86400 GNS2DNS n \
    326        example.com@ns1.example.org
    327 
    328 As you can see, one of the GNS2DNS records has an IP address listed and
    329 the other one a DNS name. For the first one there is a GLUE record to do
    330 the translation directly and the second one will issue another DNS query
    331 to figure out the IP of ns1.example.org.
    332 
    333 A solution was found by creating a hierarchical zone structure in GNS
    334 and linking the zones using PKEY records to one another. This allows the
    335 resolution of the name servers to work within GNS while not taking
    336 control over unwanted zones.
    337 
    338 Currently the following record types are supported:
    339 
    340 -  A
    341 
    342 -  AAAA
    343 
    344 -  CNAME
    345 
    346 -  MX
    347 
    348 -  NS
    349 
    350 -  SRV
    351 
    352 -  TXT
    353 
    354 This is not due to technical limitations but rather a practical ones.
    355 The problem occurs with DNSSEC enabled DNS zones. As records within
    356 those zones are signed periodically, and every new signature is an
    357 update to the zone, there are many revisions of zones. This results in a
    358 problem with bigger zones as there are lots of records that have been
    359 signed again but no major changes. Also trying to add records that are
    360 unknown that require a different format take time as they cause a CLI
    361 call of the namestore. Furthermore certain record types need
    362 transformation into a GNS compatible format which, depending on the
    363 record type, takes more time.
    364 
    365 Further a blacklist was added to drop for instance DNSSEC related
    366 records. Also if a record type is neither in the white list nor the
    367 blacklist it is considered as a loss of data and a message is shown to
    368 the user. This helps with transparency and also with contributing, as
    369 the not supported record types can then be added accordingly.
    370 
    371 .. _DNS-Zone-Size:
    372 
    373 DNS Zone Size
    374 ^^^^^^^^^^^^^
    375 
    376 Another very big problem exists with very large zones. When migrating a
    377 small zone the delay between adding of records and their expiry is
    378 negligible. However when working with big zones that easily have more
    379 than a few million records this delay becomes a problem.
    380 
    381 Records will start to expire well before the zone has finished
    382 migrating. This is usually not a problem but can cause a high CPU load
    383 when a peer is restarted and the records have expired.
    384 
    385 A good solution has not been found yet. One of the idea that floated
    386 around was that the records should be added with the s (shadow) flag to
    387 keep the records resolvable even if they expired. However this would
    388 introduce the problem of how to detect if a record has been removed from
    389 the zone and would require deletion of said record(s).
    390 
    391 Another problem that still persists is how to refresh records. Expired
    392 records are still displayed when calling gnunet-namestore but do not
    393 resolve with gnunet-gns. Zonemaster will sign the expired records again
    394 and make sure that the records are still valid. With a recent change
    395 this was fixed as gnunet-gns to improve the suffix lookup which allows
    396 for a fast lookup even with thousands of local egos.
    397 
    398 Currently the pace of adding records in general is around 10 records per
    399 second. Crypto is the upper limit for adding of records. The performance
    400 of your machine can be tested with the perf_crypto\_\* tools. There is
    401 still a big discrepancy between the pace of Ascension and the
    402 theoretical limit.
    403 
    404 A performance metric for measuring improvements has not yet been
    405 implemented in Ascension.
    406 
    407 .. _Performance:
    408 
    409 Performance
    410 ^^^^^^^^^^^
    411 
    412 The performance when migrating a zone using the Ascension tool is
    413 limited by a handful of factors. First of all ascension is written in
    414 Python3 and calls the CLI tools of GNUnet. This is comparable to a fork
    415 and exec call which costs a few CPU cycles. Furthermore all the records
    416 that are added to the same label are signed using the zones private key.
    417 This signing operation is very resource heavy and was optimized during
    418 development by adding the '-R' (Recordline) option to gnunet-namestore
    419 which allows to specify multiple records using the CLI tool. Assuming
    420 that in a TLD zone every domain has at least two name servers this
    421 halves the amount of signatures needed.
    422 
    423 Another improvement that could be made is with the addition of multiple
    424 threads or using asynchronous subprocesses when opening the GNUnet CLI
    425 tools. This could be implemented by simply creating more workers in the
    426 program but performance improvements were not tested.
    427 
    428 Ascension was tested using different hardware and database backends.
    429 Performance differences between SQLite and postgresql are marginal and
    430 almost non existent. What did make a huge impact on record adding
    431 performance was the storage medium. On a traditional mechanical hard
    432 drive adding of records were slow compared to a solid state disk.
    433 
    434 In conclusion there are many bottlenecks still around in the program,
    435 namely the single threaded implementation and inefficient, sequential
    436 calls of gnunet-namestore. In the future a solution that uses the C API
    437 would be cleaner and better.
    438 
    439 .. |ascension| image:: /images/ascension_ssd.png