aboutsummaryrefslogtreecommitdiff
path: root/doc/documentation/chapters
diff options
context:
space:
mode:
authorng0 <ng0@infotropique.org>2017-10-23 19:14:53 +0000
committerng0 <ng0@infotropique.org>2017-10-23 19:14:53 +0000
commitfca7b695cb967d2679feec85433447edb0da4f62 (patch)
tree76f300d1beed4adb78e090809ed57298afb161e5 /doc/documentation/chapters
parent16f036356fb5221e57e8fa91de59a8e78ed46428 (diff)
downloadgnunet-fca7b695cb967d2679feec85433447edb0da4f62.tar.gz
gnunet-fca7b695cb967d2679feec85433447edb0da4f62.zip
developer +
Diffstat (limited to 'doc/documentation/chapters')
-rw-r--r--doc/documentation/chapters/developer.texi921
1 files changed, 523 insertions, 398 deletions
diff --git a/doc/documentation/chapters/developer.texi b/doc/documentation/chapters/developer.texi
index f92257292..45e12146b 100644
--- a/doc/documentation/chapters/developer.texi
+++ b/doc/documentation/chapters/developer.texi
@@ -712,6 +712,7 @@ libgnunet_plugin_transport_tcp)
712int i; int j; 712int i; int j;
713@end example 713@end example
714 714
715@noindent
715instead of 716instead of
716 717
717@example 718@example
@@ -723,34 +724,44 @@ the type of every variable. Note that @code{char *} is different from
723@code{const char*} and @code{int} is different from @code{unsigned int} 724@code{const char*} and @code{int} is different from @code{unsigned int}
724or @code{uint32_t}. Each variable type should be chosen with care. 725or @code{uint32_t}. Each variable type should be chosen with care.
725 726
726@item While @code{goto} should generally be avoided, having a @code{goto} 727@item While @code{goto} should generally be avoided, having a
727to the end of a function to a block of clean up statements (free, close, 728@code{goto} to the end of a function to a block of clean up
728etc.) can be acceptable. 729statements (free, close, etc.) can be acceptable.
729 730
730@item Conditions should be written with constants on the left (to avoid 731@item Conditions should be written with constants on the left (to avoid
731accidental assignment) and with the 'true' target being either the 732accidental assignment) and with the 'true' target being either the
732'error' case or the significantly simpler continuation. For example: 733'error' case or the significantly simpler continuation. For example:
733 734
734@example 735@example
735if (0 != stat ("filename," &sbuf)) @{ error(); @} else @{ 736if (0 != stat ("filename," &sbuf)) @{
736 /* handle normal case here */ 737 error();
737@} 738 @}
739 else @{
740 /* handle normal case here */
741 @}
738@end example 742@end example
739 743
744@noindent
740instead of 745instead of
741 746
742@example 747@example
743if (stat ("filename," &sbuf) == 0) @{ 748if (stat ("filename," &sbuf) == 0) @{
744 /* handle normal case here */ 749 /* handle normal case here */
745@} else @{ error(); @} 750 @} else @{
751 error();
752 @}
746@end example 753@end example
747 754
755@noindent
748If possible, the error clause should be terminated with a 'return' (or 756If possible, the error clause should be terminated with a 'return' (or
749'goto' to some cleanup routine) and in this case, the 'else' clause 757'goto' to some cleanup routine) and in this case, the 'else' clause
750should be omitted: 758should be omitted:
751 759
752@example 760@example
753if (0 != stat ("filename," &sbuf)) @{ error(); return; @} 761if (0 != stat ("filename," &sbuf)) @{
762 error();
763 return;
764 @}
754/* handle normal case here */ 765/* handle normal case here */
755@end example 766@end example
756 767
@@ -763,10 +774,12 @@ NULL, and enums). With the two above rules (constants on left, errors in
763code clarity. For example, one can write: 774code clarity. For example, one can write:
764 775
765@example 776@example
766if (NULL == (value = lookup_function())) @{ error(); return; @} 777if (NULL == (value = lookup_function())) @{
778 error();
779 return;
780 @}
767@end example 781@end example
768 782
769
770@item Use @code{break} and @code{continue} wherever possible to avoid 783@item Use @code{break} and @code{continue} wherever possible to avoid
771deep(er) nesting. Thus, we would write: 784deep(er) nesting. Thus, we would write:
772 785
@@ -788,7 +801,6 @@ next = head; while (NULL != (pos = next)) @{
788 GNUNET_free (pos); @} @} 801 GNUNET_free (pos); @} @}
789@end example 802@end example
790 803
791
792@item We primarily use @code{for} and @code{while} loops. 804@item We primarily use @code{for} and @code{while} loops.
793A @code{while} loop is used if the method for advancing in the loop is 805A @code{while} loop is used if the method for advancing in the loop is
794not a straightforward increment operation. In particular, we use: 806not a straightforward increment operation. In particular, we use:
@@ -848,6 +860,7 @@ if ( (1 == foo) || ((0 == bar) && (x != y)) )
848 860
849 861
850However, this is not: 862However, this is not:
863
851@example 864@example
852if (1 == foo) 865if (1 == foo)
853 return x; 866 return x;
@@ -855,7 +868,7 @@ if (0 == bar && x != y)
855 return x; 868 return x;
856@end example 869@end example
857 870
858 871@noindent
859Note that splitting the @code{if} statement above is debateable as the 872Note that splitting the @code{if} statement above is debateable as the
860@code{return x} is a very trivial statement. However, once the logic after 873@code{return x} is a very trivial statement. However, once the logic after
861the branch becomes more complicated (and is still identical), the "or" 874the branch becomes more complicated (and is still identical), the "or"
@@ -2266,15 +2279,16 @@ First of all, you should define the new message type in
2266 2279
2267After the type definition, the specified message structure should also be 2280After the type definition, the specified message structure should also be
2268described in the header file, e.g. transport.h in our case. 2281described in the header file, e.g. transport.h in our case.
2282
2269@example 2283@example
2270GNUNET_NETWORK_STRUCT_BEGIN 2284struct AddressLookupMessage @{
2271 2285 struct GNUNET_MessageHeader header;
2272struct AddressLookupMessage @{ struct GNUNET_MessageHeader header; int32_t 2286 int32_t numeric_only GNUNET_PACKED;
2273numeric_only GNUNET_PACKED; struct GNUNET_TIME_AbsoluteNBO timeout; uint32_t 2287 struct GNUNET_TIME_AbsoluteNBO timeout;
2274addrlen GNUNET_PACKED; 2288 uint32_t addrlen GNUNET_PACKED;
2275 /* followed by 'addrlen' bytes of the actual address, then 2289 /* followed by 'addrlen' bytes of the actual address, then
2276 followed by the 0-terminated name of the transport */ @}; 2290 followed by the 0-terminated name of the transport */ @};
2277 GNUNET_NETWORK_STRUCT_END 2291GNUNET_NETWORK_STRUCT_END
2278@end example 2292@end example
2279 2293
2280 2294
@@ -2295,8 +2309,8 @@ new connection to a service, in our example the transport service would be
2295connected. 2309connected.
2296 2310
2297@example 2311@example
2298struct GNUNET_CLIENT_Connection *client; client = 2312struct GNUNET_CLIENT_Connection *client;
2299GNUNET_CLIENT_connect ("transport", cfg); 2313client = GNUNET_CLIENT_connect ("transport", cfg);
2300@end example 2314@end example
2301 2315
2302@c *********************************************************************** 2316@c ***********************************************************************
@@ -2310,13 +2324,20 @@ size, type, and some extra user-defined data, such as timeout, name of
2310transport, address and name of transport. 2324transport, address and name of transport.
2311 2325
2312@example 2326@example
2313struct AddressLookupMessage *msg; size_t len = 2327struct AddressLookupMessage *msg;
2314sizeof (struct AddressLookupMessage) + addressLen + strlen (nameTrans) + 1; 2328size_t len = sizeof (struct AddressLookupMessage)
2315msg->header->size = htons (len); msg->header->type = htons 2329 + addressLen
2316(GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP); msg->timeout = 2330 + strlen (nameTrans)
2317GNUNET_TIME_absolute_hton (abs_timeout); msg->addrlen = htonl (addressLen); 2331 + 1;
2318char *addrbuf = (char *) &msg[1]; memcpy (addrbuf, address, addressLen); char 2332msg->header->size = htons (len);
2319*tbuf = &addrbuf[addressLen]; memcpy (tbuf, nameTrans, strlen (nameTrans) + 1); 2333msg->header->type = htons
2334(GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP);
2335msg->timeout = GNUNET_TIME_absolute_hton (abs_timeout);
2336msg->addrlen = htonl (addressLen);
2337char *addrbuf = (char *) &msg[1];
2338memcpy (addrbuf, address, addressLen);
2339char *tbuf = &addrbuf[addressLen];
2340memcpy (tbuf, nameTrans, strlen (nameTrans) + 1);
2320@end example 2341@end example
2321 2342
2322Note that, here the functions @code{htonl}, @code{htons} and 2343Note that, here the functions @code{htonl}, @code{htons} and
@@ -2355,9 +2376,9 @@ After receiving the request message, we run a standard GNUnet service
2355startup sequence using @code{GNUNET_SERVICE_run}, as follows, 2376startup sequence using @code{GNUNET_SERVICE_run}, as follows,
2356 2377
2357@example 2378@example
2358int main(int 2379int main(int argc, char**argv) @{
2359argc, char**argv) @{ GNUNET_SERVICE_run(argc, argv, "transport" 2380 GNUNET_SERVICE_run(argc, argv, "transport"
2360GNUNET_SERVICE_OPTION_NONE, &run, NULL)); @} 2381 GNUNET_SERVICE_OPTION_NONE, &run, NULL)); @}
2361@end example 2382@end example
2362 2383
2363@c *********************************************************************** 2384@c ***********************************************************************
@@ -2369,9 +2390,10 @@ in the function above the argument @code{run} is used to initiate
2369transport service,and defined like this: 2390transport service,and defined like this:
2370 2391
2371@example 2392@example
2372static void run (void *cls, struct 2393static void run (void *cls,
2373GNUNET_SERVER_Handle *serv, const struct GNUNET_CONFIGURATION_Handle *cfg) @{ 2394struct GNUNET_SERVER_Handle *serv,
2374GNUNET_SERVER_add_handlers (serv, handlers); @} 2395const struct GNUNET_CONFIGURATION_Handle *cfg) @{
2396 GNUNET_SERVER_add_handlers (serv, handlers); @}
2375@end example 2397@end example
2376 2398
2377 2399
@@ -2382,12 +2404,29 @@ to tell the service which function should be called when a particular
2382type of message is received, and should be defined in this way: 2404type of message is received, and should be defined in this way:
2383 2405
2384@example 2406@example
2385static struct GNUNET_SERVER_MessageHandler 2407static struct GNUNET_SERVER_MessageHandler handlers[] = @{
2386handlers[] = @{ @{&handle_start, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_START, 2408 @{&handle_start,
23870@}, @{&handle_send, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0@}, 2409 NULL,
2388@{&handle_try_connect, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT, sizeof 2410 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
2389(struct TryConnectMessage)@}, @{&handle_address_lookup, NULL, 2411 0@},
2390GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP, 0@}, @{NULL, NULL, 0, 0@} @}; 2412 @{&handle_send,
2413 NULL,
2414 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
2415 0@},
2416 @{&handle_try_connect,
2417 NULL,
2418 GNUNET_MESSAGE_TYPE_TRANSPORT_TRY_CONNECT,
2419 sizeof (struct TryConnectMessage)
2420 @},
2421 @{&handle_address_lookup,
2422 NULL,
2423 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP,
2424 0@},
2425 @{NULL,
2426 NULL,
2427 0,
2428 0@}
2429@};
2391@end example 2430@end example
2392 2431
2393 2432
@@ -2411,9 +2450,11 @@ message should be checked out, e.g., to check whether the size of message
2411is correct. 2450is correct.
2412 2451
2413@example 2452@example
2414size = ntohs (message->size); if (size < sizeof (struct 2453size = ntohs (message->size);
2415AddressLookupMessage)) @{ GNUNET_break_op (0); GNUNET_SERVER_receive_done 2454if (size < sizeof (struct AddressLookupMessage)) @{
2416(client, GNUNET_SYSERR); return; @} 2455 GNUNET_break_op (0);
2456 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
2457 return; @}
2417@end example 2458@end example
2418 2459
2419 2460
@@ -2429,12 +2470,14 @@ is a 0-terminated string, so we should also check whether the name of the
2429transport in the received message is 0-terminated: 2470transport in the received message is 0-terminated:
2430 2471
2431@example 2472@example
2432nameTransport = (const char *) 2473nameTransport = (const char *) &address[addressLen];
2433&address[addressLen]; if (nameTransport[size - sizeof (struct 2474if (nameTransport[size - sizeof
2434AddressLookupMessage) 2475 (struct AddressLookupMessage)
2435 - addressLen - 1] != '\0') @{ GNUNET_break_op 2476 - addressLen - 1] != '\0') @{
2436 (0); GNUNET_SERVER_receive_done (client, 2477 GNUNET_break_op (0);
2437 GNUNET_SYSERR); return; @} 2478 GNUNET_SERVER_receive_done (client,
2479 GNUNET_SYSERR);
2480 return; @}
2438@end example 2481@end example
2439 2482
2440Here, @code{GNUNET_SERVER_receive_done} should be called to tell the 2483Here, @code{GNUNET_SERVER_receive_done} should be called to tell the
@@ -2459,17 +2502,23 @@ client, but here the type should be
2459@code{GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY} rather than 2502@code{GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY} rather than
2460@code{GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP} in client. 2503@code{GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP} in client.
2461@example 2504@example
2462struct 2505struct AddressLookupMessage *msg;
2463AddressLookupMessage *msg; size_t len = sizeof (struct AddressLookupMessage) + 2506size_t len = sizeof (struct AddressLookupMessage)
2464addressLen + strlen (nameTrans) + 1; msg->header->size = htons (len); 2507 + addressLen
2465msg->header->type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY); 2508 + strlen (nameTrans) + 1;
2509msg->header->size = htons (len);
2510msg->header->type = htons
2511 (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2466 2512
2467// ... 2513// ...
2468 2514
2469struct GNUNET_SERVER_TransmitContext *tc; tc = 2515struct GNUNET_SERVER_TransmitContext *tc;
2470GNUNET_SERVER_transmit_context_create (client); 2516tc = GNUNET_SERVER_transmit_context_create (client);
2471GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0, 2517GNUNET_SERVER_transmit_context_append_data
2472GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY); 2518(tc,
2519 NULL,
2520 0,
2521 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_REPLY);
2473GNUNET_SERVER_transmit_context_run (tc, rtimeout); 2522GNUNET_SERVER_transmit_context_run (tc, rtimeout);
2474@end example 2523@end example
2475 2524
@@ -2493,8 +2542,10 @@ to a group of clients. An individualized notification might look like
2493this: 2542this:
2494 2543
2495@example 2544@example
2496 GNUNET_SERVER_notification_context_unicast(nc, 2545GNUNET_SERVER_notification_context_unicast(nc,
2497 client, msg, GNUNET_YES); 2546 client,
2547 msg,
2548 GNUNET_YES);
2498@end example 2549@end example
2499 2550
2500 2551
@@ -2670,7 +2721,9 @@ single number value.
2670@example 2721@example
2671struct NumberMessage @{ 2722struct NumberMessage @{
2672 /** Type: GNUNET_MESSAGE_TYPE_EXAMPLE_1 */ 2723 /** Type: GNUNET_MESSAGE_TYPE_EXAMPLE_1 */
2673 struct GNUNET_MessageHeader header; uint32_t number GNUNET_PACKED; @}; 2724 struct GNUNET_MessageHeader header;
2725 uint32_t number GNUNET_PACKED;
2726@};
2674@end example 2727@end example
2675 2728
2676An envelope containing an instance of the NumberMessage can be 2729An envelope containing an instance of the NumberMessage can be
@@ -2709,7 +2762,7 @@ A few functions in MQ allow to set additional properties on envelopes:
2709@table @asis 2762@table @asis
2710 2763
2711@item @code{GNUNET_MQ_notify_sent} Allows to specify a function that will 2764@item @code{GNUNET_MQ_notify_sent} Allows to specify a function that will
2712be called once the envelope's message@ has been sent irrevocably. 2765be called once the envelope's message has been sent irrevocably.
2713An envelope can be canceled precisely up to the@ point where the notify 2766An envelope can be canceled precisely up to the@ point where the notify
2714sent callback has been called. 2767sent callback has been called.
2715 2768
@@ -2856,11 +2909,14 @@ struct that _also_ contains the hash. Here is a simplified example:
2856 2909
2857@example 2910@example
2858struct MyValue @{ 2911struct MyValue @{
2859struct GNUNET_HashCode key; unsigned int my_data; @}; 2912struct GNUNET_HashCode key;
2913unsigned int my_data; @};
2860 2914
2861// ... 2915// ...
2862val = GNUNET_malloc (sizeof (struct MyValue)); val->key = key; val->my_data = 2916val = GNUNET_malloc (sizeof (struct MyValue));
286342; GNUNET_CONTAINER_multihashmap_put (map, &key, val, ...); 2917val->key = key;
2918val->my_data = 42;
2919GNUNET_CONTAINER_multihashmap_put (map, &key, val, ...);
2864@end example 2920@end example
2865 2921
2866This is a common pattern as later the entries might need to be removed, 2922This is a common pattern as later the entries might need to be removed,
@@ -2911,11 +2967,13 @@ For the initial example, the new code would look like this:
2911 2967
2912@example 2968@example
2913struct MyValue @{ 2969struct MyValue @{
2914struct GNUNET_HashCode key; unsigned int my_data; @}; 2970struct GNUNET_HashCode key;
2971unsigned int my_data; @};
2915 2972
2916// ... 2973// ...
2917val = GNUNET_malloc (sizeof (struct MyValue)); val->key = key; val->my_data = 2974val = GNUNET_malloc (sizeof (struct MyValue));
291842; GNUNET_CONTAINER_multihashmap_put (map, &val->key, val, ...); 2975val->key = key; val->my_data = 42;
2976GNUNET_CONTAINER_multihashmap_put (map, &val->key, val, ...);
2919@end example 2977@end example
2920 2978
2921 2979
@@ -3088,8 +3146,12 @@ it to start a service "resolver", stops the "resolver" then stops "ARM".
3088 3146
3089Configurations for ARM and services should be available in a .conf file 3147Configurations for ARM and services should be available in a .conf file
3090(As an example, see test_arm_api_data.conf). When running ARM, the 3148(As an example, see test_arm_api_data.conf). When running ARM, the
3091configuration file to use should be passed to the command:@ 3149configuration file to use should be passed to the command:
3092@code{@ $ gnunet-arm -s -c configuration_to_use.conf@ }@ 3150
3151@example
3152$ gnunet-arm -s -c configuration_to_use.conf
3153@end example
3154
3093If no configuration is passed, the default configuration file will be used 3155If no configuration is passed, the default configuration file will be used
3094(see GNUNET_PREFIX/share/gnunet/defaults.conf which is created from 3156(see GNUNET_PREFIX/share/gnunet/defaults.conf which is created from
3095contrib/defaults.conf).@ Each of the services is having a section starting 3157contrib/defaults.conf).@ Each of the services is having a section starting
@@ -3556,7 +3618,8 @@ looks like this:
3556:0: 3618:0:
3557* ^X-mailer: GNUnet 3619* ^X-mailer: GNUnet
3558/tmp/gnunet.smtp 3620/tmp/gnunet.smtp
3559# where do you want your other e-mail delivered to (default: /var/spool/mail/) 3621# where do you want your other e-mail delivered to
3622# (default: /var/spool/mail/)
3560:0: /var/spool/mail/ 3623:0: /var/spool/mail/
3561@end example 3624@end example
3562 3625
@@ -7013,12 +7076,13 @@ these messages contains all of the information about the event.
7013@c %**end of header 7076@c %**end of header
7014 7077
7015When routing GETs or PUTs, the DHT service selects a suitable subset of 7078When routing GETs or PUTs, the DHT service selects a suitable subset of
7016neighbours for forwarding. The exact number of neighbours can be zero or more 7079neighbours for forwarding. The exact number of neighbours can be zero or
7017and depends on the hop counter of the query (initially zero) in relation to the 7080more and depends on the hop counter of the query (initially zero) in
7018(log of) the network size estimate, the desired replication level and the 7081relation to the (log of) the network size estimate, the desired
7019peer's connectivity. Depending on the hop counter and our network size 7082replication level and the peer's connectivity.
7020estimate, the selection of the peers maybe randomized or by proximity to the 7083Depending on the hop counter and our network size estimate, the selection
7021key. Furthermore, requests include a set of peers that a request has already 7084of the peers maybe randomized or by proximity to the key.
7085Furthermore, requests include a set of peers that a request has already
7022traversed; those peers are also excluded from the selection. 7086traversed; those peers are also excluded from the selection.
7023 7087
7024@node PUTting data into the DHT2 7088@node PUTting data into the DHT2
@@ -7026,18 +7090,21 @@ traversed; those peers are also excluded from the selection.
7026 7090
7027@c %**end of header 7091@c %**end of header
7028 7092
7029To PUT data into the DHT, the service sends a @code{struct PeerPutMessage} of 7093To PUT data into the DHT, the service sends a @code{struct PeerPutMessage}
7030type @code{GNUNET_MESSAGE_TYPE_DHT_P2P_PUT} to the respective neighbour. In 7094of type @code{GNUNET_MESSAGE_TYPE_DHT_P2P_PUT} to the respective
7031addition to the usual information about the content (type, routing options, 7095neighbour.
7032desired replication level for the content, expiration time, key and value), the 7096In addition to the usual information about the content (type, routing
7033message contains a fixed-size Bloom filter with information about which peers 7097options, desired replication level for the content, expiration time, key
7034(may) have already seen this request. This Bloom filter is used to ensure that 7098and value), the message contains a fixed-size Bloom filter with
7035DHT messages never loop back to a peer that has already processed the request. 7099information about which peers (may) have already seen this request.
7036Additionally, the message includes the current hop counter and, depending on 7100This Bloom filter is used to ensure that DHT messages never loop back to
7037the routing options, the message may include the full path that the message has 7101a peer that has already processed the request.
7038taken so far. The Bloom filter should already contain the identity of the 7102Additionally, the message includes the current hop counter and, depending
7039previous hop; however, the path should not include the identity of the previous 7103on the routing options, the message may include the full path that the
7040hop and the receiver should append the identity of the sender to the path, not 7104message has taken so far.
7105The Bloom filter should already contain the identity of the previous hop;
7106however, the path should not include the identity of the previous hop and
7107the receiver should append the identity of the sender to the path, not
7041its own identity (this is done to reduce bandwidth). 7108its own identity (this is done to reduce bandwidth).
7042 7109
7043@node GETting data from the DHT2 7110@node GETting data from the DHT2
@@ -7046,30 +7113,35 @@ its own identity (this is done to reduce bandwidth).
7046@c %**end of header 7113@c %**end of header
7047 7114
7048A peer can search the DHT by sending @code{struct PeerGetMessage}s of type 7115A peer can search the DHT by sending @code{struct PeerGetMessage}s of type
7049@code{GNUNET_MESSAGE_TYPE_DHT_P2P_GET} to other peers. In addition to the usual 7116@code{GNUNET_MESSAGE_TYPE_DHT_P2P_GET} to other peers. In addition to the
7050information about the request (type, routing options, desired replication level 7117usual information about the request (type, routing options, desired
7051for the request, the key and the extended query), a GET request also again 7118replication level for the request, the key and the extended query), a GET
7052contains a hop counter, a Bloom filter over the peers that have processed the 7119request also again contains a hop counter, a Bloom filter over the peers
7053request already and depending on the routing options the full path traversed by 7120that have processed the request already and depending on the routing
7054the GET. Finally, a GET request includes a variable-size second Bloom filter 7121options the full path traversed by the GET.
7055and a so-called Bloom filter mutator value which together indicate which 7122Finally, a GET request includes a variable-size second Bloom filter and a
7056replies the sender has already seen. During the lookup, each block that matches 7123so-called Bloom filter mutator value which together indicate which
7057they block type, key and extended query is additionally subjected to a test 7124replies the sender has already seen. During the lookup, each block that
7058against this Bloom filter. The block plugin is expected to take the hash of the 7125matches they block type, key and extended query is additionally subjected
7059block and combine it with the mutator value and check if the result is not yet 7126to a test against this Bloom filter.
7060in the Bloom filter. The originator of the query will from time to time modify 7127The block plugin is expected to take the hash of the block and combine it
7061the mutator to (eventually) allow false-positives filtered by the Bloom filter 7128with the mutator value and check if the result is not yet in the Bloom
7129filter. The originator of the query will from time to time modify the
7130mutator to (eventually) allow false-positives filtered by the Bloom filter
7062to be returned. 7131to be returned.
7063 7132
7064Peers that receive a GET request perform a local lookup (depending on their 7133Peers that receive a GET request perform a local lookup (depending on
7065proximity to the key and the query options) and forward the request to other 7134their proximity to the key and the query options) and forward the request
7066peers. They then remember the request (including the Bloom filter for blocking 7135to other peers.
7067duplicate results) and when they obtain a matching, non-filtered response a 7136They then remember the request (including the Bloom filter for blocking
7068@code{struct PeerResultMessage} of type@ 7137duplicate results) and when they obtain a matching, non-filtered response
7069@code{GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT} is forwarded to the previous hop. 7138a @code{struct PeerResultMessage} of type
7070Whenver a result is forwarded, the block plugin is used to update the Bloom 7139@code{GNUNET_MESSAGE_TYPE_DHT_P2P_RESULT} is forwarded to the previous
7071filter accordingly, to ensure that the same result is never forwarded more than 7140hop.
7072once. The DHT service may also cache forwarded results locally if the 7141Whenver a result is forwarded, the block plugin is used to update the
7142Bloom filter accordingly, to ensure that the same result is never
7143forwarded more than once.
7144The DHT service may also cache forwarded results locally if the
7073"CACHE_RESULTS" option is set to "YES" in the configuration. 7145"CACHE_RESULTS" option is set to "YES" in the configuration.
7074 7146
7075@node The GNU Name System (GNS) 7147@node The GNU Name System (GNS)
@@ -7077,38 +7149,44 @@ once. The DHT service may also cache forwarded results locally if the
7077 7149
7078@c %**end of header 7150@c %**end of header
7079 7151
7080The GNU Name System (GNS) is a decentralized database that enables users to 7152The GNU Name System (GNS) is a decentralized database that enables users
7081securely resolve names to values. Names can be used to identify other users 7153to securely resolve names to values.
7082(for example, in social networking), or network services (for example, VPN 7154Names can be used to identify other users (for example, in social
7083services running at a peer in GNUnet, or purely IP-based services on the 7155networking), or network services (for example, VPN services running at a
7084Internet). Users interact with GNS by typing in a hostname that ends in ".gnu" 7156peer in GNUnet, or purely IP-based services on the Internet).
7157Users interact with GNS by typing in a hostname that ends in ".gnu"
7085or ".zkey". 7158or ".zkey".
7086 7159
7087Videos giving an overview of most of the GNS and the motivations behind it is 7160Videos giving an overview of most of the GNS and the motivations behind
7088available here and here. The remainder of this chapter targets developers that 7161it is available here and here.
7089are familiar with high level concepts of GNS as presented in these talks. 7162The remainder of this chapter targets developers that are familiar with
7090 7163high level concepts of GNS as presented in these talks.
7091GNS-aware applications should use the GNS resolver to obtain the respective 7164@c TODO: Add links to here and here and to these.
7092records that are stored under that name in GNS. Each record consists of a type, 7165
7093value, expiration time and flags. 7166GNS-aware applications should use the GNS resolver to obtain the
7094 7167respective records that are stored under that name in GNS.
7095The type specifies the format of the value. Types below 65536 correspond to DNS 7168Each record consists of a type, value, expiration time and flags.
7096record types, larger values are used for GNS-specific records. Applications can 7169
7097define new GNS record types by reserving a number and implementing a plugin 7170The type specifies the format of the value. Types below 65536 correspond
7098(which mostly needs to convert the binary value representation to a 7171to DNS record types, larger values are used for GNS-specific records.
7099human-readable text format and vice-versa). The expiration time specifies how 7172Applications can define new GNS record types by reserving a number and
7100long the record is to be valid. The GNS API ensures that applications are only 7173implementing a plugin (which mostly needs to convert the binary value
7101given non-expired values. The flags are typically irrelevant for applications, 7174representation to a human-readable text format and vice-versa).
7102as GNS uses them internally to control visibility and validity of records. 7175The expiration time specifies how long the record is to be valid.
7103 7176The GNS API ensures that applications are only given non-expired values.
7104Records are stored along with a signature. The signature is generated using the 7177The flags are typically irrelevant for applications, as GNS uses them
7105private key of the authoritative zone. This allows any GNS resolver to verify 7178internally to control visibility and validity of records.
7106the correctness of a name-value mapping. 7179
7107 7180Records are stored along with a signature.
7108Internally, GNS uses the NAMECACHE to cache information obtained from other 7181The signature is generated using the private key of the authoritative
7109users, the NAMESTORE to store information specific to the local users, and the 7182zone. This allows any GNS resolver to verify the correctness of a
7110DHT to exchange data between users. A plugin API is used to enable applications 7183name-value mapping.
7111to define new GNS record types. 7184
7185Internally, GNS uses the NAMECACHE to cache information obtained from
7186other users, the NAMESTORE to store information specific to the local
7187users, and the DHT to exchange data between users.
7188A plugin API is used to enable applications to define new GNS
7189record types.
7112 7190
7113@menu 7191@menu
7114* libgnunetgns:: 7192* libgnunetgns::
@@ -7124,12 +7202,11 @@ to define new GNS record types.
7124 7202
7125@c %**end of header 7203@c %**end of header
7126 7204
7127The GNS API itself is extremely simple. Clients first connec to the GNS service 7205The GNS API itself is extremely simple. Clients first connec to the
7128using @code{GNUNET_GNS_connect}. They can then perform lookups using 7206GNS service using @code{GNUNET_GNS_connect}.
7129@code{GNUNET_GNS_lookup} or cancel pending lookups using 7207They can then perform lookups using @code{GNUNET_GNS_lookup} or cancel
7130@code{GNUNET_GNS_lookup_cancel}. Once finished, clients disconnect using 7208pending lookups using @code{GNUNET_GNS_lookup_cancel}.
7131@code{GNUNET_GNS_disconnect}. 7209Once finished, clients disconnect using @code{GNUNET_GNS_disconnect}.
7132
7133 7210
7134@menu 7211@menu
7135* Looking up records:: 7212* Looking up records::
@@ -7151,28 +7228,30 @@ using @code{GNUNET_GNS_connect}. They can then perform lookups using
7151@item name The client needs to specify the name to 7228@item name The client needs to specify the name to
7152be resolved. This can be any valid DNS or GNS hostname. 7229be resolved. This can be any valid DNS or GNS hostname.
7153@item zone The client 7230@item zone The client
7154needs to specify the public key of the GNS zone against which the resolution 7231needs to specify the public key of the GNS zone against which the
7155should be done (the ".gnu" zone). Note that a key must be provided, even if the 7232resolution should be done (the ".gnu" zone).
7156name ends in ".zkey". This should typically be the public key of the 7233Note that a key must be provided, even if the name ends in ".zkey".
7157master-zone of the user. 7234This should typically be the public key of the master-zone of the user.
7158@item type This is the desired GNS or DNS record type 7235@item type This is the desired GNS or DNS record type
7159to look for. While all records for the given name will be returned, this can be 7236to look for. While all records for the given name will be returned, this
7160important if the client wants to resolve record types that themselves delegate 7237can be important if the client wants to resolve record types that
7161resolution, such as CNAME, PKEY or GNS2DNS. Resolving a record of any of these 7238themselves delegate resolution, such as CNAME, PKEY or GNS2DNS.
7162types will only work if the respective record type is specified in the request, 7239Resolving a record of any of these types will only work if the respective
7163as the GNS resolver will otherwise follow the delegation and return the records 7240record type is specified in the request, as the GNS resolver will
7164from the respective destination, instead of the delegating record. 7241otherwise follow the delegation and return the records from the
7165@item only_cached This argument should typically be set to @code{GNUNET_NO}. Setting 7242respective destination, instead of the delegating record.
7166it to @code{GNUNET_YES} disables resolution via the overlay network. 7243@item only_cached This argument should typically be set to
7167@item shorten_zone_key If GNS encounters new names during resolution, their 7244@code{GNUNET_NO}. Setting it to @code{GNUNET_YES} disables resolution via
7168respective zones can automatically be learned and added to the "shorten zone". 7245the overlay network.
7169If this is desired, clients must pass the private key of the shorten zone. If 7246@item shorten_zone_key If GNS encounters new names during resolution,
7170NULL is passed, shortening is disabled. 7247their respective zones can automatically be learned and added to the
7248"shorten zone". If this is desired, clients must pass the private key of
7249the shorten zone. If NULL is passed, shortening is disabled.
7171@item proc This argument identifies 7250@item proc This argument identifies
7172the function to call with the result. It is given proc_cls, the number of 7251the function to call with the result. It is given proc_cls, the number of
7173records found (possilby zero) and the array of the records as arguments. proc 7252records found (possilby zero) and the array of the records as arguments.
7174will only be called once. After proc,> has been called, the lookup must no 7253proc will only be called once. After proc,> has been called, the lookup
7175longer be cancelled. 7254must no longer be cancelled.
7176@item proc_cls The closure for proc. 7255@item proc_cls The closure for proc.
7177@end table 7256@end table
7178 7257
@@ -7181,14 +7260,14 @@ longer be cancelled.
7181 7260
7182@c %**end of header 7261@c %**end of header
7183 7262
7184The @code{libgnunetgnsrecord} library provides an API to manipulate the GNS 7263The @code{libgnunetgnsrecord} library provides an API to manipulate the
7185record array that is given to proc. In particular, it offers functions such as 7264GNS record array that is given to proc. In particular, it offers
7186converting record values to human-readable strings (and back). However, most 7265functions such as converting record values to human-readable
7187@code{libgnunetgnsrecord} functions are not interesting to GNS client 7266strings (and back). However, most @code{libgnunetgnsrecord} functions are
7188applications. 7267not interesting to GNS client applications.
7189 7268
7190For DNS records, the @code{libgnunetdnsparser} library provides functions for 7269For DNS records, the @code{libgnunetdnsparser} library provides
7191parsing (and serializing) common types of DNS records. 7270functions for parsing (and serializing) common types of DNS records.
7192 7271
7193@node Creating records 7272@node Creating records
7194@subsubsection Creating records 7273@subsubsection Creating records
@@ -7206,29 +7285,31 @@ operation.
7206 7285
7207@c %**end of header 7286@c %**end of header
7208 7287
7209In the future, we want to expand @code{libgnunetgns} to allow applications to 7288In the future, we want to expand @code{libgnunetgns} to allow
7210observe shortening operations performed during GNS resolution, for example so 7289applications to observe shortening operations performed during GNS
7211that users can receive visual feedback when this happens. 7290resolution, for example so that users can receive visual feedback when
7291this happens.
7212 7292
7213@node libgnunetgnsrecord 7293@node libgnunetgnsrecord
7214@subsection libgnunetgnsrecord 7294@subsection libgnunetgnsrecord
7215 7295
7216@c %**end of header 7296@c %**end of header
7217 7297
7218The @code{libgnunetgnsrecord} library is used to manipulate GNS records (in 7298The @code{libgnunetgnsrecord} library is used to manipulate GNS
7219plaintext or in their encrypted format). Applications mostly interact with 7299records (in plaintext or in their encrypted format).
7220@code{libgnunetgnsrecord} by using the functions to convert GNS record values 7300Applications mostly interact with @code{libgnunetgnsrecord} by using the
7221to strings or vice-versa, or to lookup a GNS record type number by name (or 7301functions to convert GNS record values to strings or vice-versa, or to
7222vice-versa). The library also provides various other functions that are mostly 7302lookup a GNS record type number by name (or vice-versa).
7303The library also provides various other functions that are mostly
7223used internally within GNS, such as converting keys to names, checking for 7304used internally within GNS, such as converting keys to names, checking for
7224expiration, encrypting GNS records to GNS blocks, verifying GNS block 7305expiration, encrypting GNS records to GNS blocks, verifying GNS block
7225signatures and decrypting GNS records from GNS blocks. 7306signatures and decrypting GNS records from GNS blocks.
7226 7307
7227We will now discuss the four commonly used functions of the API.@ 7308We will now discuss the four commonly used functions of the API.@
7228@code{libgnunetgnsrecord} does not perform these operations itself, but instead 7309@code{libgnunetgnsrecord} does not perform these operations itself,
7229uses plugins to perform the operation. GNUnet includes plugins to support 7310but instead uses plugins to perform the operation.
7230common DNS record types as well as standard GNS record types. 7311GNUnet includes plugins to support common DNS record types as well as
7231 7312standard GNS record types.
7232 7313
7233@menu 7314@menu
7234* Value handling:: 7315* Value handling::
@@ -7240,31 +7321,33 @@ common DNS record types as well as standard GNS record types.
7240 7321
7241@c %**end of header 7322@c %**end of header
7242 7323
7243@code{GNUNET_GNSRECORD_value_to_string} can be used to convert the (binary) 7324@code{GNUNET_GNSRECORD_value_to_string} can be used to convert
7244representation of a GNS record value to a human readable, 0-terminated UTF-8 7325the (binary) representation of a GNS record value to a human readable,
7245string. NULL is returned if the specified record type is not supported by any 73260-terminated UTF-8 string.
7327NULL is returned if the specified record type is not supported by any
7246available plugin. 7328available plugin.
7247 7329
7248@code{GNUNET_GNSRECORD_string_to_value} can be used to try to convert a human 7330@code{GNUNET_GNSRECORD_string_to_value} can be used to try to convert a
7249readable string to the respective (binary) representation of a GNS record 7331human readable string to the respective (binary) representation of
7250value. 7332a GNS record value.
7251 7333
7252@node Type handling 7334@node Type handling
7253@subsubsection Type handling 7335@subsubsection Type handling
7254 7336
7255@c %**end of header 7337@c %**end of header
7256 7338
7257@code{GNUNET_GNSRECORD_typename_to_number} can be used to obtain the numeric 7339@code{GNUNET_GNSRECORD_typename_to_number} can be used to obtain the
7258value associated with a given typename. For example, given the typename "A" 7340numeric value associated with a given typename. For example, given the
7259(for DNS A reocrds), the function will return the number 1. A list of common 7341typename "A" (for DNS A reocrds), the function will return the number 1.
7260DNS record types is 7342A list of common DNS record types is
7261@uref{http://en.wikipedia.org/wiki/List_of_DNS_record_types, here. Note that 7343@uref{http://en.wikipedia.org/wiki/List_of_DNS_record_types, here}.
7262not all DNS record types are supported by GNUnet GNSRECORD plugins at this 7344Note that not all DNS record types are supported by GNUnet GNSRECORD
7263time.} 7345plugins at this time.
7264 7346
7265@code{GNUNET_GNSRECORD_number_to_typename} can be used to obtain the typename 7347@code{GNUNET_GNSRECORD_number_to_typename} can be used to obtain the
7266associated with a given numeric value. For example, given the type number 1, 7348typename associated with a given numeric value.
7267the function will return the typename "A". 7349For example, given the type number 1, the function will return the
7350typename "A".
7268 7351
7269@node GNS plugins 7352@node GNS plugins
7270@subsection GNS plugins 7353@subsection GNS plugins
@@ -7273,67 +7356,76 @@ the function will return the typename "A".
7273 7356
7274Adding a new GNS record type typically involves writing (or extending) a 7357Adding a new GNS record type typically involves writing (or extending) a
7275GNSRECORD plugin. The plugin needs to implement the 7358GNSRECORD plugin. The plugin needs to implement the
7276@code{gnunet_gnsrecord_plugin.h} API which provides basic functions that are 7359@code{gnunet_gnsrecord_plugin.h} API which provides basic functions that
7277needed by GNSRECORD to convert typenames and values of the respective record 7360are needed by GNSRECORD to convert typenames and values of the respective
7278type to strings (and back). These gnsrecord plugins are typically implemented 7361record type to strings (and back).
7279within their respective subsystems. Examples for such plugins can be found in 7362These gnsrecord plugins are typically implemented within their respective
7280the GNSRECORD, GNS and CONVERSATION subsystems. 7363subsystems.
7281 7364Examples for such plugins can be found in the GNSRECORD, GNS and
7282The @code{libgnunetgnsrecord} library is then used to locate, load and query 7365CONVERSATION subsystems.
7283the appropriate gnsrecord plugin. Which plugin is appropriate is determined by 7366
7284the record type (which is just a 32-bit integer). The @code{libgnunetgnsrecord} 7367The @code{libgnunetgnsrecord} library is then used to locate, load and
7285library loads all block plugins that are installed at the local peer and 7368query the appropriate gnsrecord plugin.
7286forwards the application request to the plugins. If the record type is not 7369Which plugin is appropriate is determined by the record type (which is
7370just a 32-bit integer). The @code{libgnunetgnsrecord} library loads all
7371block plugins that are installed at the local peer and forwards the
7372application request to the plugins. If the record type is not
7287supported by the plugin, it should simply return an error code. 7373supported by the plugin, it should simply return an error code.
7288 7374
7289The central functions of the block APIs (plugin and main library) are the same 7375The central functions of the block APIs (plugin and main library) are the
7290four functions for converting between values and strings, and typenames and 7376same four functions for converting between values and strings, and
7291numbers documented in the previous subsection. 7377typenames and numbers documented in the previous subsection.
7292 7378
7293@node The GNS Client-Service Protocol 7379@node The GNS Client-Service Protocol
7294@subsection The GNS Client-Service Protocol 7380@subsection The GNS Client-Service Protocol
7295
7296@c %**end of header 7381@c %**end of header
7297 7382
7298The GNS client-service protocol consists of two simple messages, the 7383The GNS client-service protocol consists of two simple messages, the
7299@code{LOOKUP} message and the @code{LOOKUP_RESULT}. Each @code{LOOKUP} message 7384@code{LOOKUP} message and the @code{LOOKUP_RESULT}. Each @code{LOOKUP}
7300contains a unique 32-bit identifier, which will be included in the 7385message contains a unique 32-bit identifier, which will be included in the
7301corresponding response. Thus, clients can send many lookup requests in parallel 7386corresponding response. Thus, clients can send many lookup requests in
7302and receive responses out-of-order. A @code{LOOKUP} request also includes the 7387parallel and receive responses out-of-order.
7303public key of the GNS zone, the desired record type and fields specifying 7388A @code{LOOKUP} request also includes the public key of the GNS zone,
7304whether shortening is enabled or networking is disabled. Finally, the 7389the desired record type and fields specifying whether shortening is
7305@code{LOOKUP} message includes the name to be resolved. 7390enabled or networking is disabled. Finally, the @code{LOOKUP} message
7306 7391includes the name to be resolved.
7307The response includes the number of records and the records themselves in the 7392
7308format created by @code{GNUNET_GNSRECORD_records_serialize}. They can thus be 7393The response includes the number of records and the records themselves
7309deserialized using @code{GNUNET_GNSRECORD_records_deserialize}. 7394in the format created by @code{GNUNET_GNSRECORD_records_serialize}.
7395They can thus be deserialized using
7396@code{GNUNET_GNSRECORD_records_deserialize}.
7310 7397
7311@node Hijacking the DNS-Traffic using gnunet-service-dns 7398@node Hijacking the DNS-Traffic using gnunet-service-dns
7312@subsection Hijacking the DNS-Traffic using gnunet-service-dns 7399@subsection Hijacking the DNS-Traffic using gnunet-service-dns
7313 7400
7314@c %**end of header 7401@c %**end of header
7315 7402
7316This section documents how the gnunet-service-dns (and the gnunet-helper-dns) 7403This section documents how the gnunet-service-dns (and the
7317intercepts DNS queries from the local system.@ This is merely one method for 7404gnunet-helper-dns) intercepts DNS queries from the local system.
7318how we can obtain GNS queries. It is also possible to change @code{resolv.conf} 7405This is merely one method for how we can obtain GNS queries.
7319to point to a machine running @code{gnunet-dns2gns} or to modify libc's name 7406It is also possible to change @code{resolv.conf} to point to a machine
7320system switch (NSS) configuration to include a GNS resolution plugin. The 7407running @code{gnunet-dns2gns} or to modify libc's name system switch
7321method described in this chaper is more of a last-ditch catch-all approach. 7408(NSS) configuration to include a GNS resolution plugin.
7409The method described in this chaper is more of a last-ditch catch-all
7410approach.
7322 7411
7323@code{gnunet-service-dns} enables intercepting DNS traffic using policy based 7412@code{gnunet-service-dns} enables intercepting DNS traffic using policy
7324routing. We MARK every outgoing DNS-packet if it was not sent by our 7413based routing.
7325application. Using a second routing table in the Linux kernel these marked 7414We MARK every outgoing DNS-packet if it was not sent by our application.
7326packets are then routed through our virtual network interface and can thus be 7415Using a second routing table in the Linux kernel these marked packets are
7416then routed through our virtual network interface and can thus be
7327captured unchanged. 7417captured unchanged.
7328 7418
7329Our application then reads the query and decides how to handle it: A query to 7419Our application then reads the query and decides how to handle it: A
7330an address ending in ".gnu" or ".zkey" is hijacked by @code{gnunet-service-gns} 7420query to an address ending in ".gnu" or ".zkey" is hijacked by
7331and resolved internally using GNS. In the future, a reverse query for an 7421@code{gnunet-service-gns} and resolved internally using GNS.
7332address of the configured virtual network could be answered with records kept 7422In the future, a reverse query for an address of the configured virtual
7333about previous forward queries. Queries that are not hijacked by some 7423network could be answered with records kept about previous forward
7334application using the DNS service will be sent to the original recipient. The 7424queries.
7335answer to the query will always be sent back through the virtual interface with 7425Queries that are not hijacked by some application using the DNS service
7336the original nameserver as source address. 7426will be sent to the original recipient.
7427The answer to the query will always be sent back through the virtual
7428interface with the original nameserver as source address.
7337 7429
7338 7430
7339@menu 7431@menu
@@ -7347,59 +7439,66 @@ the original nameserver as source address.
7347 7439
7348The DNS interceptor adds the following rules to the Linux kernel: 7440The DNS interceptor adds the following rules to the Linux kernel:
7349@example 7441@example
7350iptables -t mangle -I OUTPUT 1 -p udp --sport $LOCALPORT --dport 53 -j 7442iptables -t mangle -I OUTPUT 1 -p udp --sport $LOCALPORT --dport 53 \
7351ACCEPT iptables -t mangle -I OUTPUT 2 -p udp --dport 53 -j MARK --set-mark 3 ip 7443-j ACCEPT iptables -t mangle -I OUTPUT 2 -p udp --dport 53 -j MARK \
7352rule add fwmark 3 table2 ip route add default via $VIRTUALDNS table2 7444--set-mark 3 ip rule add fwmark 3 table2 ip route add default via \
7445$VIRTUALDNS table2
7353@end example 7446@end example
7354 7447
7355Line 1 makes sure that all packets coming from a port our application opened 7448@c FIXME: Rewrite to reflect display which is no longer content by line
7356beforehand (@code{$LOCALPORT}) will be routed normally. Line 2 marks every 7449@c FIXME: due to the < 74 characters limit.
7357other packet to a DNS-Server with mark 3 (chosen arbitrarily). The third line 7450Line 1 makes sure that all packets coming from a port our application
7358adds a routing policy based on this mark 3 via the routing table. 7451opened beforehand (@code{$LOCALPORT}) will be routed normally.
7452Line 2 marks every other packet to a DNS-Server with mark 3 (chosen
7453arbitrarily). The third line adds a routing policy based on this mark
74543 via the routing table.
7359 7455
7360@node Serving DNS lookups via GNS on W32 7456@node Serving DNS lookups via GNS on W32
7361@subsection Serving DNS lookups via GNS on W32 7457@subsection Serving DNS lookups via GNS on W32
7362 7458
7363@c %**end of header 7459@c %**end of header
7364 7460
7365This section documents how the libw32nsp (and gnunet-gns-helper-service-w32) do 7461This section documents how the libw32nsp (and
7366DNS resolutions of DNS queries on the local system. This only applies to GNUnet 7462gnunet-gns-helper-service-w32) do DNS resolutions of DNS queries on the
7367running on W32. 7463local system. This only applies to GNUnet running on W32.
7368 7464
7369W32 has a concept of "Namespaces" and "Namespace providers". These are used to 7465W32 has a concept of "Namespaces" and "Namespace providers".
7370present various name systems to applications in a generic way. Namespaces 7466These are used to present various name systems to applications in a
7371include DNS, mDNS, NLA and others. For each namespace any number of providers 7467generic way.
7372could be registered, and they are queried in an order of priority (which is 7468Namespaces include DNS, mDNS, NLA and others. For each namespace any
7373adjustable). 7469number of providers could be registered, and they are queried in an order
7470of priority (which is adjustable).
7374 7471
7375Applications can resolve names by using WSALookupService*() family of 7472Applications can resolve names by using WSALookupService*() family of
7376functions. 7473functions.
7377 7474
7378However, these are WSA-only facilities. Common BSD socket functions for 7475However, these are WSA-only facilities. Common BSD socket functions for
7379namespace resolutions are gethostbyname and getaddrinfo (among others). These 7476namespace resolutions are gethostbyname and getaddrinfo (among others).
7380functions are implemented internally (by default - by mswsock, which also 7477These functions are implemented internally (by default - by mswsock,
7381implements the default DNS provider) as wrappers around WSALookupService*() 7478which also implements the default DNS provider) as wrappers around
7382functions (see "Sample Code for a Service Provider" on MSDN). 7479WSALookupService*() functions (see "Sample Code for a Service Provider"
7480on MSDN).
7383 7481
7384On W32 GNUnet builds a libw32nsp - a namespace provider, which can then be 7482On W32 GNUnet builds a libw32nsp - a namespace provider, which can then be
7385installed into the system by using w32nsp-install (and uninstalled by 7483installed into the system by using w32nsp-install (and uninstalled by
7386w32nsp-uninstall), as described in "Installation Handbook". 7484w32nsp-uninstall), as described in "Installation Handbook".
7387 7485
7388libw32nsp is very simple and has almost no dependencies. As a response to 7486libw32nsp is very simple and has almost no dependencies. As a response to
7389NSPLookupServiceBegin(), it only checks that the provider GUID passed to it by 7487NSPLookupServiceBegin(), it only checks that the provider GUID passed to
7390the caller matches GNUnet DNS Provider GUID, checks that name being resolved 7488it by the caller matches GNUnet DNS Provider GUID, checks that name being
7391ends in ".gnu" or ".zkey", then connects to gnunet-gns-helper-service-w32 at 7489resolved ends in ".gnu" or ".zkey", then connects to
7392127.0.0.1:5353 (hardcoded) and sends the name resolution request there, 7490gnunet-gns-helper-service-w32 at 127.0.0.1:5353 (hardcoded) and sends the
7393returning the connected socket to the caller. 7491name resolution request there, returning the connected socket to the
7394
7395When the caller invokes NSPLookupServiceNext(), libw32nsp reads a completely
7396formed reply from that socket, unmarshalls it, then gives it back to the
7397caller. 7492caller.
7398 7493
7399At the moment gnunet-gns-helper-service-w32 is implemented to ever give only 7494When the caller invokes NSPLookupServiceNext(), libw32nsp reads a
7400one reply, and subsequent calls to NSPLookupServiceNext() will fail with 7495completely formed reply from that socket, unmarshalls it, then gives
7401WSA_NODATA (first call to NSPLookupServiceNext() might also fail if GNS failed 7496it back to the caller.
7402to find the name, or there was an error connecting to it). 7497
7498At the moment gnunet-gns-helper-service-w32 is implemented to ever give
7499only one reply, and subsequent calls to NSPLookupServiceNext() will fail
7500with WSA_NODATA (first call to NSPLookupServiceNext() might also fail if
7501GNS failed to find the name, or there was an error connecting to it).
7403 7502
7404gnunet-gns-helper-service-w32 does most of the processing: 7503gnunet-gns-helper-service-w32 does most of the processing:
7405 7504
@@ -7407,20 +7506,22 @@ gnunet-gns-helper-service-w32 does most of the processing:
7407@item Maintains a connection to GNS. 7506@item Maintains a connection to GNS.
7408@item Reads GNS config and loads appropriate keys. 7507@item Reads GNS config and loads appropriate keys.
7409@item Checks service GUID and decides on the type of record to look up, 7508@item Checks service GUID and decides on the type of record to look up,
7410refusing to make a lookup outright when unsupported service GUID is passed. 7509refusing to make a lookup outright when unsupported service GUID is
7510passed.
7411@item Launches the lookup 7511@item Launches the lookup
7412@end itemize 7512@end itemize
7413 7513
7414When lookup result arrives, gnunet-gns-helper-service-w32 forms a complete 7514When lookup result arrives, gnunet-gns-helper-service-w32 forms a complete
7415reply (including filling a WSAQUERYSETW structure and, possibly, a binary blob 7515reply (including filling a WSAQUERYSETW structure and, possibly, a binary
7416with a hostent structure for gethostbyname() client), marshalls it, and sends 7516blob with a hostent structure for gethostbyname() client), marshalls it,
7417it back to libw32nsp. If no records were found, it sends an empty header. 7517and sends it back to libw32nsp. If no records were found, it sends an
7518empty header.
7418 7519
7419This works for most normal applications that use gethostbyname() or 7520This works for most normal applications that use gethostbyname() or
7420getaddrinfo() to resolve names, but fails to do anything with applications that 7521getaddrinfo() to resolve names, but fails to do anything with
7421use alternative means of resolving names (such as sending queries to a DNS 7522applications that use alternative means of resolving names (such as
7422server directly by themselves). This includes some of well known utilities, 7523sending queries to a DNS server directly by themselves).
7423like "ping" and "nslookup". 7524This includes some of well known utilities, like "ping" and "nslookup".
7424 7525
7425@node The GNS Namecache 7526@node The GNS Namecache
7426@section The GNS Namecache 7527@section The GNS Namecache
@@ -7428,27 +7529,32 @@ like "ping" and "nslookup".
7428@c %**end of header 7529@c %**end of header
7429 7530
7430The NAMECACHE subsystem is responsible for caching (encrypted) resolution 7531The NAMECACHE subsystem is responsible for caching (encrypted) resolution
7431results of the GNU Name System (GNS). GNS makes zone information available to 7532results of the GNU Name System (GNS). GNS makes zone information available
7432other users via the DHT. However, as accessing the DHT for every lookup is 7533to other users via the DHT. However, as accessing the DHT for every
7433expensive (and as the DHT's local cache is lost whenever the peer is 7534lookup is expensive (and as the DHT's local cache is lost whenever the
7434restarted), GNS uses the NAMECACHE as a more persistent cache for DHT lookups. 7535peer is restarted), GNS uses the NAMECACHE as a more persistent cache for
7435Thus, instead of always looking up every name in the DHT, GNS first checks if 7536DHT lookups.
7436the result is already available locally in the NAMECACHE. Only if there is no 7537Thus, instead of always looking up every name in the DHT, GNS first
7437result in the NAMECACHE, GNS queries the DHT. The NAMECACHE stores data in the 7538checks if the result is already available locally in the NAMECACHE.
7438same (encrypted) format as the DHT. It thus makes no sense to iterate over all 7539Only if there is no result in the NAMECACHE, GNS queries the DHT.
7439items in the NAMECACHE --- the NAMECACHE does not have a way to provide the 7540The NAMECACHE stores data in the same (encrypted) format as the DHT.
7440keys required to decrypt the entries. 7541It thus makes no sense to iterate over all items in the
7441 7542NAMECACHE --- the NAMECACHE does not have a way to provide the keys
7442Blocks in the NAMECACHE share the same expiration mechanism as blocks in the 7543required to decrypt the entries.
7443DHT --- the block expires wheneever any of the records in the (encrypted) block 7544
7444expires. The expiration time of the block is the only information stored in 7545Blocks in the NAMECACHE share the same expiration mechanism as blocks in
7445plaintext. The NAMECACHE service internally performs all of the required work 7546the DHT --- the block expires wheneever any of the records in
7446to expire blocks, clients do not have to worry about this. Also, given that 7547the (encrypted) block expires.
7447NAMECACHE stores only GNS blocks that local users requested, there is no 7548The expiration time of the block is the only information stored in
7448configuration option to limit the size of the NAMECACHE. It is assumed to be 7549plaintext. The NAMECACHE service internally performs all of the required
7449always small enough (a few MB) to fit on the drive. 7550work to expire blocks, clients do not have to worry about this.
7450 7551Also, given that NAMECACHE stores only GNS blocks that local users
7451The NAMECACHE supports the use of different database backends via a plugin API. 7552requested, there is no configuration option to limit the size of the
7553NAMECACHE. It is assumed to be always small enough (a few MB) to fit on
7554the drive.
7555
7556The NAMECACHE supports the use of different database backends via a
7557plugin API.
7452 7558
7453@menu 7559@menu
7454* libgnunetnamecache:: 7560* libgnunetnamecache::
@@ -7462,17 +7568,19 @@ The NAMECACHE supports the use of different database backends via a plugin API.
7462@c %**end of header 7568@c %**end of header
7463 7569
7464The NAMECACHE API consists of five simple functions. First, there is 7570The NAMECACHE API consists of five simple functions. First, there is
7465@code{GNUNET_NAMECACHE_connect} to connect to the NAMECACHE service. This 7571@code{GNUNET_NAMECACHE_connect} to connect to the NAMECACHE service.
7466returns the handle required for all other operations on the NAMECACHE. Using 7572This returns the handle required for all other operations on the
7467@code{GNUNET_NAMECACHE_block_cache} clients can insert a block into the cache. 7573NAMECACHE. Using @code{GNUNET_NAMECACHE_block_cache} clients can insert a
7468@code{GNUNET_NAMECACHE_lookup_block} can be used to lookup blocks that were 7574block into the cache.
7469stored in the NAMECACHE. Both operations can be cancelled using 7575@code{GNUNET_NAMECACHE_lookup_block} can be used to lookup blocks that
7576were stored in the NAMECACHE. Both operations can be cancelled using
7470@code{GNUNET_NAMECACHE_cancel}. Note that cancelling a 7577@code{GNUNET_NAMECACHE_cancel}. Note that cancelling a
7471@code{GNUNET_NAMECACHE_block_cache} operation can result in the block being 7578@code{GNUNET_NAMECACHE_block_cache} operation can result in the block
7472stored in the NAMECACHE --- or not. Cancellation primarily ensures that the 7579being stored in the NAMECACHE --- or not. Cancellation primarily ensures
7473continuation function with the result of the operation will no longer be 7580that the continuation function with the result of the operation will no
7474invoked. Finally, @code{GNUNET_NAMECACHE_disconnect} closes the connection to 7581longer be invoked.
7475the NAMECACHE. 7582Finally, @code{GNUNET_NAMECACHE_disconnect} closes the connection to the
7583NAMECACHE.
7476 7584
7477The maximum size of a block that can be stored in the NAMECACHE is 7585The maximum size of a block that can be stored in the NAMECACHE is
7478@code{GNUNET_NAMECACHE_MAX_VALUE_SIZE}, which is defined to be 63 kB. 7586@code{GNUNET_NAMECACHE_MAX_VALUE_SIZE}, which is defined to be 63 kB.
@@ -7482,9 +7590,10 @@ The maximum size of a block that can be stored in the NAMECACHE is
7482 7590
7483@c %**end of header 7591@c %**end of header
7484 7592
7485All messages in the NAMECACHE IPC protocol start with the @code{struct 7593All messages in the NAMECACHE IPC protocol start with the
7486GNUNET_NAMECACHE_Header} which adds a request ID (32-bit integer) to the 7594@code{struct GNUNET_NAMECACHE_Header} which adds a request
7487standard message header. The request ID is used to match requests with the 7595ID (32-bit integer) to the standard message header.
7596The request ID is used to match requests with the
7488respective responses from the NAMECACHE, as they are allowed to happen 7597respective responses from the NAMECACHE, as they are allowed to happen
7489out-of-order. 7598out-of-order.
7490 7599
@@ -7499,31 +7608,35 @@ out-of-order.
7499 7608
7500@c %**end of header 7609@c %**end of header
7501 7610
7502The @code{struct LookupBlockMessage} is used to lookup a block stored in the 7611The @code{struct LookupBlockMessage} is used to lookup a block stored in
7503cache. It contains the query hash. The NAMECACHE always responds with a 7612the cache.
7504@code{struct LookupBlockResponseMessage}. If the NAMECACHE has no response, it 7613It contains the query hash. The NAMECACHE always responds with a
7505sets the expiration time in the response to zero. Otherwise, the response is 7614@code{struct LookupBlockResponseMessage}. If the NAMECACHE has no
7506expected to contain the expiration time, the ECDSA signature, the derived key 7615response, it sets the expiration time in the response to zero.
7507and the (variable-size) encrypted data of the block. 7616Otherwise, the response is expected to contain the expiration time, the
7617ECDSA signature, the derived key and the (variable-size) encrypted data
7618of the block.
7508 7619
7509@node Store 7620@node Store
7510@subsubsection Store 7621@subsubsection Store
7511 7622
7512@c %**end of header 7623@c %**end of header
7513 7624
7514The @code{struct BlockCacheMessage} is used to cache a block in the NAMECACHE. 7625The @code{struct BlockCacheMessage} is used to cache a block in the
7515It has the same structure as the @code{struct LookupBlockResponseMessage}. The 7626NAMECACHE.
7516service responds with a @code{struct BlockCacheResponseMessage} which contains 7627It has the same structure as the @code{struct LookupBlockResponseMessage}.
7517the result of the operation (success or failure). In the future, we might want 7628The service responds with a @code{struct BlockCacheResponseMessage} which
7518to make it possible to provide an error message as well. 7629contains the result of the operation (success or failure).
7630In the future, we might want to make it possible to provide an error
7631message as well.
7519 7632
7520@node The NAMECACHE Plugin API 7633@node The NAMECACHE Plugin API
7521@subsection The NAMECACHE Plugin API 7634@subsection The NAMECACHE Plugin API
7522@c %**end of header 7635@c %**end of header
7523 7636
7524The NAMECACHE plugin API consists of two functions, @code{cache_block} to store 7637The NAMECACHE plugin API consists of two functions, @code{cache_block} to
7525a block in the database, and @code{lookup_block} to lookup a block in the 7638store a block in the database, and @code{lookup_block} to lookup a block
7526database. 7639in the database.
7527 7640
7528 7641
7529@menu 7642@menu
@@ -7536,36 +7649,39 @@ database.
7536 7649
7537@c %**end of header 7650@c %**end of header
7538 7651
7539The @code{lookup_block} function is expected to return at most one block to the 7652The @code{lookup_block} function is expected to return at most one block
7540iterator, and return @code{GNUNET_NO} if there were no non-expired results. If 7653to the iterator, and return @code{GNUNET_NO} if there were no non-expired
7541there are multiple non-expired results in the cache, the lookup is supposed to 7654results.
7542return the result with the largest expiration time. 7655If there are multiple non-expired results in the cache, the lookup is
7656supposed to return the result with the largest expiration time.
7543 7657
7544@node Store2 7658@node Store2
7545@subsubsection Store2 7659@subsubsection Store2
7546 7660
7547@c %**end of header 7661@c %**end of header
7548 7662
7549The @code{cache_block} function is expected to try to store the block in the 7663The @code{cache_block} function is expected to try to store the block in
7550database, and return @code{GNUNET_SYSERR} if this was not possible for any 7664the database, and return @code{GNUNET_SYSERR} if this was not possible
7551reason. Furthermore, @code{cache_block} is expected to implicitly perform cache 7665for any reason.
7666Furthermore, @code{cache_block} is expected to implicitly perform cache
7552maintenance and purge blocks from the cache that have expired. Note that 7667maintenance and purge blocks from the cache that have expired. Note that
7553@code{cache_block} might encounter the case where the database already has 7668@code{cache_block} might encounter the case where the database already has
7554another block stored under the same key. In this case, the plugin must ensure 7669another block stored under the same key. In this case, the plugin must
7555that the block with the larger expiration time is preserved. Obviously, this 7670ensure that the block with the larger expiration time is preserved.
7556can done either by simply adding new blocks and selecting for the most recent 7671Obviously, this can done either by simply adding new blocks and selecting
7557expiration time during lookup, or by checking which block is more recent during 7672for the most recent expiration time during lookup, or by checking which
7558the store operation. 7673block is more recent during the store operation.
7559 7674
7560@node The REVOCATION Subsystem 7675@node The REVOCATION Subsystem
7561@section The REVOCATION Subsystem 7676@section The REVOCATION Subsystem
7562@c %**end of header 7677@c %**end of header
7563 7678
7564The REVOCATION subsystem is responsible for key revocation of Egos. If a user 7679The REVOCATION subsystem is responsible for key revocation of Egos.
7565learns that his private key has been compromised or has lost it, he can use the 7680If a user learns that theis private key has been compromised or has lost
7566REVOCATION system to inform all of the other users that this private key is no 7681it, they can use the REVOCATION system to inform all of the other users
7567longer valid. The subsystem thus includes ways to query for the validity of 7682that their private key is no longer valid.
7568keys and to propagate revocation messages. 7683The subsystem thus includes ways to query for the validity of keys and to
7684propagate revocation messages.
7569 7685
7570@menu 7686@menu
7571* Dissemination:: 7687* Dissemination::
@@ -7580,38 +7696,41 @@ keys and to propagate revocation messages.
7580 7696
7581@c %**end of header 7697@c %**end of header
7582 7698
7583When a revocation is performed, the revocation is first of all disseminated by 7699When a revocation is performed, the revocation is first of all
7584flooding the overlay network. The goal is to reach every peer, so that when a 7700disseminated by flooding the overlay network.
7585peer needs to check if a key has been revoked, this will be purely a local 7701The goal is to reach every peer, so that when a peer needs to check if a
7586operation where the peer looks at his local revocation list. Flooding the 7702key has been revoked, this will be purely a local operation where the
7587network is also the most robust form of key revocation --- an adversary would 7703peer looks at his local revocation list. Flooding the network is also the
7588have to control a separator of the overlay graph to restrict the propagation of 7704most robust form of key revocation --- an adversary would have to control
7589the revocation message. Flooding is also very easy to implement --- peers that 7705a separator of the overlay graph to restrict the propagation of the
7590receive a revocation message for a key that they have never seen before simply 7706revocation message. Flooding is also very easy to implement --- peers that
7591pass the message to all of their neighbours. 7707receive a revocation message for a key that they have never seen before
7708simply pass the message to all of their neighbours.
7592 7709
7593Flooding can only distribute the revocation message to peers that are online. 7710Flooding can only distribute the revocation message to peers that are
7594In order to notify peers that join the network later, the revocation service 7711online.
7595performs efficient set reconciliation over the sets of known revocation 7712In order to notify peers that join the network later, the revocation
7596messages whenever two peers (that both support REVOCATION dissemination) 7713service performs efficient set reconciliation over the sets of known
7597connect. The SET service is used to perform this operation 7714revocation messages whenever two peers (that both support REVOCATION
7598efficiently. 7715dissemination) connect.
7716The SET service is used to perform this operation efficiently.
7599 7717
7600@node Revocation Message Design Requirements 7718@node Revocation Message Design Requirements
7601@subsection Revocation Message Design Requirements 7719@subsection Revocation Message Design Requirements
7602 7720
7603@c %**end of header 7721@c %**end of header
7604 7722
7605However, flooding is also quite costly, creating O(|E|) messages on a network 7723However, flooding is also quite costly, creating O(|E|) messages on a
7606with |E| edges. Thus, revocation messages are required to contain a 7724network with |E| edges.
7607proof-of-work, the result of an expensive computation (which, however, is cheap 7725Thus, revocation messages are required to contain a proof-of-work, the
7608to verify). Only peers that have expended the CPU time necessary to provide 7726result of an expensive computation (which, however, is cheap to verify).
7609this proof will be able to flood the network with the revocation message. This 7727Only peers that have expended the CPU time necessary to provide
7610ensures that an attacker cannot simply flood the network with millions of 7728this proof will be able to flood the network with the revocation message.
7611revocation messages. The proof-of-work required by GNUnet is set to take days 7729This ensures that an attacker cannot simply flood the network with
7612on a typical PC to compute; if the ability to quickly revoke a key is needed, 7730millions of revocation messages. The proof-of-work required by GNUnet is
7613users have the option to pre-compute revocation messages to store off-line and 7731set to take days on a typical PC to compute; if the ability to quickly
7614use instantly after their key has expired. 7732revoke a key is needed, users have the option to pre-compute revocation
7733messages to store off-line and use instantly after their key has expired.
7615 7734
7616Revocation messages must also be signed by the private key that is being 7735Revocation messages must also be signed by the private key that is being
7617revoked. Thus, they can only be created while the private key is in the 7736revoked. Thus, they can only be created while the private key is in the
@@ -7638,41 +7757,47 @@ revocations.
7638 7757
7639@c %**end of header 7758@c %**end of header
7640 7759
7641@code{GNUNET_REVOCATION_query} is used to check if a given ECDSA public key has 7760@code{GNUNET_REVOCATION_query} is used to check if a given ECDSA public
7642been revoked. The given callback will be invoked with the result of the check. 7761key has been revoked.
7643The query can be cancelled using @code{GNUNET_REVOCATION_query_cancel} on the 7762The given callback will be invoked with the result of the check.
7644return value. 7763The query can be cancelled using @code{GNUNET_REVOCATION_query_cancel} on
7764the return value.
7645 7765
7646@node Preparing revocations 7766@node Preparing revocations
7647@subsubsection Preparing revocations 7767@subsubsection Preparing revocations
7648 7768
7649@c %**end of header 7769@c %**end of header
7650 7770
7651It is often desirable to create a revocation record ahead-of-time and store it 7771It is often desirable to create a revocation record ahead-of-time and
7652in an off-line location to be used later in an emergency. This is particularly 7772store it in an off-line location to be used later in an emergency.
7653true for GNUnet revocations, where performing the revocation operation itself 7773This is particularly true for GNUnet revocations, where performing the
7654is computationally expensive and thus is likely to take some time. Thus, if 7774revocation operation itself is computationally expensive and thus is
7655users want the ability to perform revocations quickly in an emergency, they 7775likely to take some time.
7656must pre-compute the revocation message. The revocation API enables this with 7776Thus, if users want the ability to perform revocations quickly in an
7657two functions that are used to compute the revocation message, but not trigger 7777emergency, they must pre-compute the revocation message.
7658the actual revocation operation. 7778The revocation API enables this with two functions that are used to
7779compute the revocation message, but not trigger the actual revocation
7780operation.
7659 7781
7660@code{GNUNET_REVOCATION_check_pow} should be used to calculate the 7782@code{GNUNET_REVOCATION_check_pow} should be used to calculate the
7661proof-of-work required in the revocation message. This function takes the 7783proof-of-work required in the revocation message. This function takes the
7662public key, the required number of bits for the proof of work (which in GNUnet 7784public key, the required number of bits for the proof of work (which in
7663is a network-wide constant) and finally a proof-of-work number as arguments. 7785GNUnet is a network-wide constant) and finally a proof-of-work number as
7664The function then checks if the given proof-of-work number is a valid proof of 7786arguments.
7665work for the given public key. Clients preparing a revocation are expected to 7787The function then checks if the given proof-of-work number is a valid
7666call this function repeatedly (typically with a monotonically increasing 7788proof of work for the given public key. Clients preparing a revocation
7667sequence of numbers of the proof-of-work number) until a given number satisfies 7789are expected to call this function repeatedly (typically with a
7668the check. That number should then be saved for later use in the revocation 7790monotonically increasing sequence of numbers of the proof-of-work number)
7791until a given number satisfies the check.
7792That number should then be saved for later use in the revocation
7669operation. 7793operation.
7670 7794
7671@code{GNUNET_REVOCATION_sign_revocation} is used to generate the signature that 7795@code{GNUNET_REVOCATION_sign_revocation} is used to generate the
7672is required in a revocation message. It takes the private key that (possibly in 7796signature that is required in a revocation message.
7673the future) is to be revoked and returns the signature. The signature can again 7797It takes the private key that (possibly in the future) is to be revoked
7674be saved to disk for later use, which will then allow performing a revocation 7798and returns the signature.
7675even without access to the private key. 7799The signature can again be saved to disk for later use, which will then
7800allow performing a revocation even without access to the private key.
7676 7801
7677@node Issuing revocations 7802@node Issuing revocations
7678@subsubsection Issuing revocations 7803@subsubsection Issuing revocations