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