From: Christian Grothoff Date: Tue, 3 Jan 2012 20:30:07 +0000 (+0000) Subject: -more DNS service hacking X-Git-Tag: initial-import-from-subversion-38251~15446 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=5b9de1c328efb28856b9239301be1821ecf21bc0;p=oweals%2Fgnunet.git -more DNS service hacking --- diff --git a/src/dns/dns_api_new.c b/src/dns/dns_api_new.c index a61676a47..b578c3a9d 100644 --- a/src/dns/dns_api_new.c +++ b/src/dns/dns_api_new.c @@ -125,6 +125,11 @@ struct GNUNET_DNS_Handle * Re-connect counter, to make sure we did not reconnect in the meantime. */ uint32_t generation; + + /** + * Flags for events we care about. + */ + enum GNUNET_DNS_Flags flags; /** * Did we start the receive loop yet? @@ -162,7 +167,7 @@ reconnect (void *cls, { struct GNUNET_DNS_Handle *dh = cls; struct ReplyQueueEntry *qe; - struct GNUNET_MessageHeader *msg; + struct GNUNET_DNS_Register *msg; dh->reconnect_task = GNUNET_SCHEDULER_NO_TASK; dh->dns_connection = GNUNET_CLIENT_connect ("dns", dh->cfg); @@ -170,11 +175,12 @@ reconnect (void *cls, return; dh->generation++; qe = GNUNET_malloc (sizeof (struct ReplyQueueEntry) + - sizeof (struct GNUNET_MessageHeader)); - msg = (struct GNUNET_MessageHeader*) &qe[1]; - qe->msg = msg; - msg->size = htons (sizeof (struct GNUNET_MessageHeader)); - msg->type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT); + sizeof (struct GNUNET_DNS_Register)); + msg = (struct GNUNET_DNS_Register*) &qe[1]; + qe->msg = &msg->header; + msg->header.size = htons (sizeof (struct GNUNET_DNS_Register)); + msg->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT); + msg->flags = htonl (dh->flags); queue_reply (dh, qe); } @@ -471,12 +477,14 @@ GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh, * Connect to the service-dns * * @param cfg configuration to use + * @param flags when to call rh * @param rh function to call with DNS requests * @param rh_cls closure to pass to rh * @return DNS handle */ struct GNUNET_DNS_Handle * GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + enum GNUNET_DNS_Flags flags, GNUNET_DNS_RequestHandler rh, void *rh_cls) { @@ -484,6 +492,7 @@ GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, dh = GNUNET_malloc (sizeof (struct GNUNET_DNS_Handle)); dh->cfg = cfg; + dh->flags = flags; dh->rh = rh; dh->rh_cls = rh_cls; dh->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, dh); diff --git a/src/dns/dns_new.h b/src/dns/dns_new.h index 7cf3a316a..29a9f937b 100644 --- a/src/dns/dns_new.h +++ b/src/dns/dns_new.h @@ -28,6 +28,24 @@ GNUNET_NETWORK_STRUCT_BEGIN + +/** + * Message from client to DNS service to register itself. + */ +struct GNUNET_DNS_Register +{ + /** + * Header of type GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT + */ + struct GNUNET_MessageHeader header; + + /** + * NBO encoding of 'enum GNUNET_DNS_Flags' for the client. + */ + uint32_t flags; +}; + + /** * Message from DNS service to client: please handle a request. */ diff --git a/src/dns/gnunet-service-dns_new.c b/src/dns/gnunet-service-dns_new.c index ae57d9088..041b2d12b 100644 --- a/src/dns/gnunet-service-dns_new.c +++ b/src/dns/gnunet-service-dns_new.c @@ -22,27 +22,13 @@ * @file dns/gnunet-service-dns_new.c * @author Christian Grothoff */ -// current thoughts: -// - for full compatibility to DNS and to avoid going insane here parsing/generating DNS packets, -// how about literally attaching the "original" DNS packet (request/response) to the IPC traffic? -// that way, clients can literally do arbitrary modifications and we are done with that issue here. -// All we'd do in here is add the IP/UDP headers and be DONE with it. -// => minor modifications to API and IPC protocol -// => minor modifications to our data structures -// => major gains in terms of simplicity here and what can (at least theoretically) be done with the service -// => can test much more quickly -// => but: need to really write a good libgnunetdnsparse to avoid making MANY clients really complicated -// (not the worst of worlds either, other than deferring this mess some...) -// -> also positive: can be tested independently of the rest of the mess - - #include "platform.h" #include "gnunet_util_lib.h" #include "gnunet_constants.h" #include "gnunet_protocols.h" -//#include "gnunet_dnsparser_lib.h" #include "gnunet_signatures.h" #include "dns_new.h" +#include "gnunet_dns_service-new.h" GNUNET_NETWORK_STRUCT_BEGIN struct ip4_hdr @@ -86,45 +72,58 @@ struct udp_pkt uint16_t crc GNUNET_PACKED; }; -struct dns_pkt + +struct dns_hdr { uint16_t id GNUNET_PACKED; - - unsigned rd:1 GNUNET_PACKED; // recursion desired (client -> server) - unsigned tc:1 GNUNET_PACKED; // message is truncated - unsigned aa:1 GNUNET_PACKED; // authoritative answer - unsigned op:4 GNUNET_PACKED; // query:0, inverse q.:1, status: 2 - unsigned qr:1 GNUNET_PACKED; // query:0, response:1 - - unsigned rcode:4 GNUNET_PACKED; // 0 No error - // 1 Format error - // 2 Server failure - // 3 Name Error - // 4 Not Implemented - // 5 Refused - unsigned z:3 GNUNET_PACKED; // reserved - unsigned ra:1 GNUNET_PACKED; // recursion available (server -> client) - - uint16_t qdcount GNUNET_PACKED; // number of questions - uint16_t ancount GNUNET_PACKED; // number of answers - uint16_t nscount GNUNET_PACKED; // number of authority-records - uint16_t arcount GNUNET_PACKED; // number of additional records + uint16_t flags GNUNET_PACKED; + uint16_t qdcount GNUNET_PACKED; + uint16_t ancount GNUNET_PACKED; + uint16_t nscount GNUNET_PACKED; + uint16_t arcount GNUNET_PACKED; }; +GNUNET_NETWORK_STRUCT_END -struct dns_query_line -{ - uint16_t type; - uint16_t class; -}; -struct dns_record_line +/** + * Phases each request goes through. + */ +enum RequestPhase { - uint16_t type; - uint16_t class; - uint32_t ttl; - uint16_t data_len; + /** + * Request has just been received. + */ + RP_INIT, + + /** + * Showing the request to all monitor clients. If + * client list is empty, will enter QUERY phase. + */ + RP_MONITOR, + + /** + * Showing the request to PRE-RESOLUTION clients to find an answer. + * If client list is empty, will trigger global DNS request. + */ + RP_QUERY, + + /** + * Global Internet query is now pending. + */ + RP_INTERNET_DNS, + + /** + * Client (or global DNS request) has resulted in a response. + * Forward to all POST-RESOLUTION clients. If client list is empty, + * give the result to the hijacker (and be done). + */ + RP_MODIFY, + + /** + * Some client has told us to drop the request. + */ + RP_DROP }; -GNUNET_NETWORK_STRUCT_END /** @@ -147,6 +146,11 @@ struct ClientRecord */ struct GNUNET_SERVER_Client *client; + /** + * Flags for the client. + */ + enum GNUNET_DNS_Flags flags; + }; @@ -156,16 +160,6 @@ struct ClientRecord struct RequestRecord { - /** - * Name for the request. - */ - char *name; - - /** - * Response data, or NULL if not known. - */ - char *rdata; - /** * List of clients that still need to see this request (each entry * is set to NULL when the client is done). @@ -173,9 +167,10 @@ struct RequestRecord struct ClientRecord **client_wait_list; /** - * Length of the client wait list. + * Payload of the UDP packet (the UDP payload), can be either query + * or already the response. */ - unsigned int client_wait_list_length; + char *payload; /** * Source address of the original request (for sending response). @@ -195,34 +190,19 @@ struct RequestRecord uint64_t request_id; /** - * TTL if we know it, or 0. - */ - uint32_t dns_ttl; - - /** - * Number of bytes in rdata. + * Number of bytes in payload. */ - uint16_t rdata_length; + size_t payload_length; /** - * Length of the 'name' string, including 0-terminator. - */ - uint16_t name_length; - - /** - * The DNS type (i.e. 1 == 'A'). - */ - uint16_t dns_type; - - /** - * The DNS class (i.e. 1 == Internet) + * Length of the client wait list. */ - uint16_t dns_class; + unsigned int client_wait_list_length; /** - * Original DNS Id we got from the client. + * In which phase this this request? */ - uint16_t original_dns_id; + enum RequestPhase phase; }; @@ -280,6 +260,11 @@ static struct ClientRecord *clients_head; */ static struct ClientRecord *clients_tail; +/** + * Our notification context. + */ +static struct GNUNET_SERVER_NotificationContext *nc; + /** * Array of all open requests. */ @@ -291,6 +276,23 @@ static struct RequestRecord requests[UINT16_MAX]; static uint64_t request_id_gen; +/** + * We're done processing a DNS request, free associated memory. + * + * @param rr request to clean up + */ +static void +cleanup_rr (struct RequestRecord *rr) +{ + GNUNET_free (rr->payload); + rr->payload = NULL; + rr->payload_length = 0; + GNUNET_array_grow (rr->client_wait_list, + rr->client_wait_list_length, + 0); +} + + /** * Task run during shutdown. * @@ -302,7 +304,6 @@ cleanup_task (void *cls GNUNET_UNUSED, const struct GNUNET_SCHEDULER_TaskContext *tc) { unsigned int i; - struct RequestRecord *rr; GNUNET_HELPER_stop (hijacker); hijacker = NULL; @@ -329,19 +330,16 @@ cleanup_task (void *cls GNUNET_UNUSED, read6_task = GNUNET_SCHEDULER_NO_TASK; } for (i=0;i<65536;i++) - { - rr = &requests[i]; - GNUNET_free (rr->name); - GNUNET_free_non_null (rr->rdata); - GNUNET_array_grow (rr->client_wait_list, - rr->client_wait_list_length, - 0); - } + cleanup_rr (&requests[i]); + GNUNET_SERVER_notification_context_destroy (nc); + nc = NULL; } /** * We're done with some request, finish processing. + * + * @param rr request send to the network or just clean up. */ static void request_done (struct RequestRecord *rr) @@ -354,11 +352,10 @@ request_done (struct RequestRecord *rr) GNUNET_array_grow (rr->client_wait_list, rr->client_wait_list_length, 0); - if (NULL == rr->rdata) + if (RP_MODIFY != rr->phase) { /* no response, drop */ - GNUNET_free (rr->name); - rr->name = NULL; + cleanup_rr (rr); return; } @@ -374,21 +371,16 @@ request_done (struct RequestRecord *rr) break; default: GNUNET_break (0); - GNUNET_free (rr->name); - rr->name = NULL; + cleanup_rr (rr); return; } reply_len += sizeof (struct udp_pkt); - reply_len += sizeof (struct dns_pkt); - reply_len += rr->name_length; - reply_len += sizeof (struct dns_record_line); - reply_len += rr->rdata_length; + reply_len += rr->payload_length; if (reply_len >= GNUNET_SERVER_MAX_MESSAGE_SIZE) { /* response too big, drop */ GNUNET_break (0); /* how can this be? */ - GNUNET_free (rr->name); - rr->name = NULL; + cleanup_rr(rr); return; } { @@ -433,6 +425,7 @@ request_done (struct RequestRecord *rr) default: GNUNET_assert (0); } + /* now UDP header */ { struct udp_pkt udp; @@ -444,51 +437,10 @@ request_done (struct RequestRecord *rr) memcpy (&buf[off], &udp, sizeof (udp)); off += sizeof (udp); } - - /* now DNS header */ - { - struct dns_pkt dns; - - dns.id = rr->original_dns_id; - dns.rd = 1; /* recursion desired / supported */ - dns.tc = 0; /* not truncated */ - dns.aa = 1; /* are we authoritative!? I say yes. */ - dns.op = 0; /* standard query */ - dns.qr = 1; /* this is a response */ - dns.rcode = 0; /* no error */ - dns.z = 0; /* reserved */ - dns.ra = 1; /* recursion available */ - dns.qdcount = htons (0); /* no queries */ - dns.ancount = htons (1); /* one answer */ - dns.nscount = htons (0); /* no authorities yet (fixme) */ - dns.arcount = htons (0); /* no additinal records yet (fixme) */ - memcpy (&buf[off], &dns, sizeof (dns)); - off += sizeof (dns); - } - - /* now DNS name */ - { - // FIXME: fill in DNS name! - off += rr->name_length; - } - - - /* now DNS record line */ - { - struct dns_record_line drl; - - drl.type = htons (rr->dns_type); - drl.class = htons (rr->dns_class); - drl.ttl = htonl (rr->dns_ttl); - drl.data_len = htons (rr->rdata_length); - memcpy (&buf[off], &drl, sizeof (drl)); - off += sizeof (drl); - } - - /* now DNS rdata */ + /* now DNS header */ { - memcpy (&buf[off], rr->rdata, rr->rdata_length); - off += rr->rdata_length; + memcpy (&buf[off], rr->payload, rr->payload_length); + off += rr->payload_length; } /* final checks & sending */ @@ -499,8 +451,147 @@ request_done (struct RequestRecord *rr) NULL, NULL); } /* clean up, we're done */ - GNUNET_free (rr->name); - rr->name = NULL; + cleanup_rr (rr); +} + + +/** + * Show the payload of the given request record to the client + * (and wait for a response). + * + * @param rr request to send to client + * @param client client to send the response to + */ +static void +send_request_to_client (struct RequestRecord *rr, + struct GNUNET_SERVER_Client *client) +{ + char buf[sizeof (struct GNUNET_DNS_Request) + rr->payload_length]; + struct GNUNET_DNS_Request *req; + + if (sizeof (buf) >= GNUNET_SERVER_MAX_MESSAGE_SIZE) + { + GNUNET_break (0); + cleanup_rr (rr); + return; + } + req = (struct GNUNET_DNS_Request*) buf; + req->header.type = htons (GNUNET_MESSAGE_TYPE_DNS_CLIENT_REQUEST); + req->header.size = htons (sizeof (buf)); + req->reserved = htonl (0); + req->request_id = rr->request_id; + memcpy (&req[1], rr->payload, rr->payload_length); + GNUNET_SERVER_notification_context_unicast (nc, + client, + &req->header, + GNUNET_NO); +} + + +/** + * A client has completed its processing for this + * request. Move on. + * + * @param rr request to process further + */ +static void +next_phase (struct RequestRecord *rr) +{ + struct ClientRecord *cr; + int nz; + unsigned int j; + struct GNUNET_NETWORK_Handle *dnsout; + socklen_t salen; + + if (rr->phase == RP_DROP) + { + cleanup_rr (rr); + return; + } + nz = -1; + for (j=0;jclient_wait_list_length;j++) + { + if (NULL != rr->client_wait_list[j]) + { + nz = (int) j; + break; + } + } + if (-1 != nz) + { + send_request_to_client (rr, rr->client_wait_list[nz]->client); + return; + } + /* done with current phase, advance! */ + switch (rr->phase) + { + case RP_INIT: + rr->phase = RP_MONITOR; + for (cr = clients_head; NULL != cr; cr = cr->next) + { + if (0 != (cr->flags & GNUNET_DNS_FLAG_REQUEST_MONITOR)) + GNUNET_array_append (rr->client_wait_list, + rr->client_wait_list_length, + cr); + } + next_phase (rr); + return; + case RP_MONITOR: + rr->phase = RP_QUERY; + for (cr = clients_head; NULL != cr; cr = cr->next) + { + if (0 != (cr->flags & GNUNET_DNS_FLAG_PRE_RESOLUTION)) + GNUNET_array_append (rr->client_wait_list, + rr->client_wait_list_length, + cr); + } + next_phase (rr); + return; + case RP_QUERY: + rr->phase = RP_INTERNET_DNS; + switch (rr->dst_addr.ss_family) + { + case AF_INET: + dnsout = dnsout4; + salen = sizeof (struct ip4_hdr); + break; + case AF_INET6: + dnsout = dnsout6; + salen = sizeof (struct ip6_hdr); + break; + default: + GNUNET_break (0); + cleanup_rr (rr); + return; + } + GNUNET_NETWORK_socket_sendto (dnsout, + rr->payload, + rr->payload_length, + (struct sockaddr*) &rr->dst_addr, + salen); + return; + case RP_INTERNET_DNS: + rr->phase = RP_MODIFY; + for (cr = clients_head; NULL != cr; cr = cr->next) + { + if (0 != (cr->flags & GNUNET_DNS_FLAG_POST_RESOLUTION)) + GNUNET_array_append (rr->client_wait_list, + rr->client_wait_list_length, + cr); + } + next_phase (rr); + return; + case RP_MODIFY: + request_done (rr); + break; + case RP_DROP: + cleanup_rr (rr); + break; + default: + GNUNET_break (0); + cleanup_rr (rr); + break; + } } @@ -517,7 +608,6 @@ client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) struct RequestRecord *rr; unsigned int i; unsigned int j; - int az; for (cr = clients_head; NULL != cr; cr = cr->next) { @@ -532,16 +622,14 @@ client_disconnect (void *cls, struct GNUNET_SERVER_Client *client) rr = &requests[i]; if (0 == rr->client_wait_list_length) continue; /* not in use */ - az = 1; for (j=0;jclient_wait_list_length;j++) { if (rr->client_wait_list[j] == cr) + { rr->client_wait_list[j] = NULL; - if (rr->client_wait_list[j] != NULL) - az = 0; + next_phase (rr); + } } - if (1 == az) - request_done (rr); /* this was the last client... */ } GNUNET_free (cr); return; @@ -564,7 +652,9 @@ read_response (void *cls, struct sockaddr_in addr4; struct sockaddr_in6 addr6; struct sockaddr *addr; + struct dns_hdr *dns; socklen_t addrlen; + struct RequestRecord *rr; ssize_t r; int len; @@ -612,9 +702,26 @@ read_response (void *cls, GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recvfrom"); return; } - // NOTE: struct dns_pkt *dns = (struct dns_pkt *) buf; - // FIXME: handle_response (buf, r, addr, addrlen); - } + if (sizeof (struct dns_hdr) > r) + { + GNUNET_log (GNUNET_ERROR_TYPE_ERROR, + _("Received DNS response that is too small (%u bytes)"), + r); + return; + } + dns = (struct dns_hdr *) buf; + rr = &requests[dns->id]; + if (rr->phase != RP_INTERNET_DNS) + { + /* FIXME: case for statistics */ + /* unexpected / bogus reply */ + return; + } + GNUNET_free_non_null (rr->payload); + rr->payload = GNUNET_malloc (len); + memcpy (rr->payload, buf, len); + next_phase (rr); + } } @@ -744,16 +851,19 @@ open_port6 () static void handle_client_init (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message GNUNET_UNUSED) + const struct GNUNET_MessageHeader *message) { struct ClientRecord *cr; + const struct GNUNET_DNS_Register *reg = (const struct GNUNET_DNS_Register*) message; cr = GNUNET_malloc (sizeof (struct ClientRecord)); cr->client = client; + cr->flags = (enum GNUNET_DNS_Flags) ntohl (reg->flags); GNUNET_SERVER_client_keep (client); GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, cr); + GNUNET_SERVER_notification_context_add (nc, client); GNUNET_SERVER_receive_done (client, GNUNET_OK); } @@ -768,10 +878,73 @@ handle_client_init (void *cls GNUNET_UNUSED, static void handle_client_response (void *cls GNUNET_UNUSED, struct GNUNET_SERVER_Client *client, - const struct GNUNET_MessageHeader *message GNUNET_UNUSED) + const struct GNUNET_MessageHeader *message) { - // FIXME: validate and parse response, process response - GNUNET_SERVER_receive_done (client, GNUNET_OK); + const struct GNUNET_DNS_Response *resp; + struct RequestRecord *rr; + unsigned int i; + uint16_t msize; + uint16_t off; + + msize = ntohs (message->size); + if (msize < sizeof (struct GNUNET_DNS_Response)) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + return; + } + resp = (const struct GNUNET_DNS_Response*) message; + off = (uint16_t) resp->request_id; + rr = &requests[off]; + if (rr->request_id != resp->request_id) + { + // FIXME: this is a case for calling statistics... + // (client is answering a request that we've lost + // track of -- more than 64k requests ago or so...) + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + for (i=0;iclient_wait_list_length;i++) + { + if (rr->client_wait_list[i]->client != client) + continue; + rr->client_wait_list[i] = NULL; + switch (ntohl (resp->drop_flag)) + { + case 0: /* drop */ + rr->phase = RP_DROP; + break; + case 1: /* no change */ + break; + case 2: /* update */ + msize -= sizeof (struct GNUNET_DNS_Response); + if ( (sizeof (struct dns_hdr) > msize) || + (RP_MONITOR == rr->phase) ) + { + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); + next_phase (rr); + return; + } + GNUNET_free_non_null (rr->payload); + rr->payload = GNUNET_malloc (msize); + memcpy (rr->payload, &resp[1], msize); + if (rr->phase == RP_QUERY) + { + /* clear wait list, we're moving to MODIFY phase next */ + GNUNET_array_grow (rr->client_wait_list, + rr->client_wait_list_length, + 0); + } + next_phase (rr); + GNUNET_SERVER_receive_done (client, GNUNET_OK); + return; + } + } + /* odd, client was not on our list for the request, that ought + to be an error */ + GNUNET_break (0); + GNUNET_SERVER_receive_done (client, GNUNET_SYSERR); } @@ -784,12 +957,14 @@ handle_client_response (void *cls GNUNET_UNUSED, * @param message the actual message, a DNS request we should handle */ static void -process_helper_messages (void *cls, void *client, +process_helper_messages (void *cls GNUNET_UNUSED, void *client, const struct GNUNET_MessageHeader *message) { + struct RequestRecord *rr = NULL; /* FIXME: parse message, create record, start processing! */ /* FIXME: put request into queue for clients / system DNS */ request_id_gen++; + next_phase (rr); } @@ -804,7 +979,8 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, { static const struct GNUNET_SERVER_MessageHandler handlers[] = { /* callback, cls, type, size */ - {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, sizeof (struct GNUNET_MessageHeader)}, + {&handle_client_init, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_INIT, + sizeof (struct GNUNET_DNS_Register)}, {&handle_client_response, NULL, GNUNET_MESSAGE_TYPE_DNS_CLIENT_RESPONSE, 0}, {NULL, NULL, 0, 0} }; @@ -816,6 +992,7 @@ run (void *cls, struct GNUNET_SERVER_Handle *server, char *ipv6prefix; cfg = cfg_; + nc = GNUNET_SERVER_notification_context_create (server, 1); GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &cleanup_task, cls); if (GNUNET_YES == diff --git a/src/include/gnunet_dns_service-new.h b/src/include/gnunet_dns_service-new.h index 06b9a87a1..bab8a2485 100644 --- a/src/include/gnunet_dns_service-new.h +++ b/src/include/gnunet_dns_service-new.h @@ -40,6 +40,49 @@ struct GNUNET_DNS_Handle; */ struct GNUNET_DNS_RequestHandle; +/** + * Flags that specify when to call the client's handler. + */ +enum GNUNET_DNS_Flags +{ + + /** + * Useless option: never call the client. + */ + GNUNET_DNS_FLAG_NEVER = 0, + + /** + * Set this flag to see all requests first prior to resolution + * (for monitoring). Clients that set this flag must then + * call "GNUNET_DNS_request_forward" when they process a request + * for the first time. Caling "GNUNET_DNS_request_answer" is + * not allowed for MONITOR peers. + */ + GNUNET_DNS_FLAG_REQUEST_MONITOR = 1, + + /** + * This client should be called on requests that have not + * yet been resolved as this client provides a resolution + * service. Note that this does not guarantee that the + * client will see all requests as another client might be + * called first and that client might have already done the + * resolution, in which case other pre-resolution clients + * won't see the request anymore. + */ + GNUNET_DNS_FLAG_PRE_RESOLUTION = 2, + + /** + * This client wants to be called on the results of a DNS resolution + * (either resolved by PRE-RESOLUTION clients or the global DNS). + * The client then has a chance to modify the answer (or cause it to + * be dropped). There is no guarantee that other POST-RESOLUTION + * client's won't modify (or drop) the answer afterwards. + */ + GNUNET_DNS_FLAG_POST_RESOLUTION = 4 + +}; + + /** * Signature of a function that is called whenever the DNS service @@ -71,12 +114,9 @@ typedef void (*GNUNET_DNS_RequestHandler)(void *cls, /** - * If a GNUNET_DNS_RequestHandler calls this function, the request is - * given to other clients or the global DNS for resolution. Once a - * global response has been obtained, the request handler is AGAIN - * called to give it a chance to observe and modify the response after - * the "normal" resolution. It is not legal for the request handler - * to call this function if a response is already present. + * If a GNUNET_DNS_RequestHandler calls this function, the client + * has no desire to interfer with the request and it should + * continue to be processed normally. * * @param rh request that should now be forwarded */ @@ -97,7 +137,8 @@ GNUNET_DNS_request_drop (struct GNUNET_DNS_RequestHandle *rh); /** * If a GNUNET_DNS_RequestHandler calls this function, the request is * supposed to be answered with the data provided to this call (with - * the modifications the function might have made). + * the modifications the function might have made). The reply given + * must always be a valid DNS reply and not a mutated DNS request. * * @param rh request that should now be answered * @param reply_length size of reply (uint16_t to force sane size) @@ -113,12 +154,14 @@ GNUNET_DNS_request_answer (struct GNUNET_DNS_RequestHandle *rh, * Connect to the service-dns * * @param cfg configuration to use + * @param flags when to call rh * @param rh function to call with DNS requests * @param rh_cls closure to pass to rh * @return DNS handle */ struct GNUNET_DNS_Handle * GNUNET_DNS_connect (const struct GNUNET_CONFIGURATION_Handle *cfg, + enum GNUNET_DNS_Flags flags, GNUNET_DNS_RequestHandler rh, void *rh_cls);