static void my_connect(isc_task_t *task, isc_event_t *event) { isc_socket_t *sock; isc_socket_connev_t *dev; isc_region_t region; char buf[1024]; sock = event->ev_sender; dev = (isc_socket_connev_t *)event; printf("%s: Connection result: %d\n", (char *)(event->ev_arg), dev->result); if (dev->result != ISC_R_SUCCESS) { isc_socket_detach(&sock); isc_event_free(&event); isc_task_shutdown(task); return; } /* * Send a GET string, and set up to receive (and just display) * the result. */ strcpy(buf, "GET / HTTP/1.1\r\nHost: www.flame.org\r\n" "Connection: Close\r\n\r\n"); region.base = isc_mem_get(mctx, strlen(buf) + 1); region.length = strlen(buf) + 1; strcpy((char *)region.base, buf); /* This strcpy is safe. */ isc_socket_send(sock, ®ion, task, my_http_get, event->ev_arg); isc_event_free(&event); }
static void rndc_connected(isc_task_t *task, isc_event_t *event) { char socktext[ISC_SOCKADDR_FORMATSIZE]; isc_socketevent_t *sevent = (isc_socketevent_t *)event; isccc_sexpr_t *request = NULL; isccc_sexpr_t *data; isccc_time_t now; isccc_region_t message; isc_region_t r; isc_uint32_t len; isc_buffer_t b; isc_result_t result; connects--; if (sevent->result != ISC_R_SUCCESS) { isc_sockaddr_format(&serveraddrs[currentaddr], socktext, sizeof(socktext)); if (sevent->result != ISC_R_CANCELED && ++currentaddr < nserveraddrs) { notify("connection failed: %s: %s", socktext, isc_result_totext(sevent->result)); isc_socket_detach(&sock); isc_event_free(&event); rndc_startconnect(&serveraddrs[currentaddr], task); return; } else fatal("connect failed: %s: %s", socktext, isc_result_totext(sevent->result)); } isc_stdtime_get(&now); DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial, now, now + 60, &request)); data = isccc_alist_lookup(request, "_data"); if (data == NULL) fatal("_data section missing"); if (isccc_cc_definestring(data, "type", "null") == NULL) fatal("out of memory"); message.rstart = databuf + 4; message.rend = databuf + sizeof(databuf); DO("render message", isccc_cc_towire(request, &message, &secret)); len = sizeof(databuf) - REGION_SIZE(message); isc_buffer_init(&b, databuf, 4); isc_buffer_putuint32(&b, len - 4); r.length = len; r.base = databuf; isccc_ccmsg_init(mctx, sock, &ccmsg); isccc_ccmsg_setmaxsize(&ccmsg, 1024 * 1024); DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task, rndc_recvnonce, NULL)); recvs++; DO("send message", isc_socket_send(sock, &r, task, rndc_senddone, NULL)); sends++; isc_event_free(&event); }
static void my_recv(isc_task_t *task, isc_event_t *event) { isc_socket_t *sock; isc_socketevent_t *dev; isc_region_t region; char buf[1024]; char host[256]; sock = event->ev_sender; dev = (isc_socketevent_t *)event; printf("Socket %s (sock %p, base %p, length %d, n %d, result %d)\n", (char *)(event->ev_arg), sock, dev->region.base, dev->region.length, dev->n, dev->result); if (dev->address.type.sa.sa_family == AF_INET6) { inet_ntop(AF_INET6, &dev->address.type.sin6.sin6_addr, host, sizeof(host)); printf("\tFrom: %s port %d\n", host, ntohs(dev->address.type.sin6.sin6_port)); } else { inet_ntop(AF_INET, &dev->address.type.sin.sin_addr, host, sizeof(host)); printf("\tFrom: %s port %d\n", host, ntohs(dev->address.type.sin.sin_port)); } if (dev->result != ISC_R_SUCCESS) { isc_socket_detach(&sock); isc_mem_put(mctx, dev->region.base, dev->region.length); isc_event_free(&event); isc_task_shutdown(task); return; } /* * Echo the data back. */ if (strcmp(event->ev_arg, "so2") != 0) { region = dev->region; sprintf(buf, "\r\nReceived: %.*s\r\n\r\n", (int)dev->n, (char *)region.base); region.base = isc_mem_get(mctx, strlen(buf) + 1); region.length = strlen(buf) + 1; strcpy((char *)region.base, buf); /* strcpy is safe */ isc_socket_send(sock, ®ion, task, my_send, event->ev_arg); } else { region = dev->region; printf("\r\nReceived: %.*s\r\n\r\n", (int)dev->n, (char *)region.base); } isc_socket_recv(sock, &dev->region, 1, task, my_recv, event->ev_arg); isc_event_free(&event); }
/* * Arrange to send as much as we can of "stream" without blocking. * * Requires: * The stream iterator is initialized and points at an RR, * or possibly at the end of the stream (that is, the * _first method of the iterator has been called). */ static void sendstream(xfrout_ctx_t *xfr) { dns_message_t *tcpmsg = NULL; dns_message_t *msg = NULL; /* Client message if UDP, tcpmsg if TCP */ isc_result_t result; isc_region_t used; isc_region_t region; dns_rdataset_t *qrdataset; dns_name_t *msgname = NULL; dns_rdata_t *msgrdata = NULL; dns_rdatalist_t *msgrdl = NULL; dns_rdataset_t *msgrds = NULL; dns_compress_t cctx; isc_boolean_t cleanup_cctx = ISC_FALSE; isc_boolean_t is_tcp; int n_rrs; isc_buffer_clear(&xfr->buf); isc_buffer_clear(&xfr->txlenbuf); isc_buffer_clear(&xfr->txbuf); is_tcp = ISC_TF((xfr->client->attributes & NS_CLIENTATTR_TCP) != 0); if (!is_tcp) { /* * In the UDP case, we put the response data directly into * the client message. */ msg = xfr->client->message; CHECK(dns_message_reply(msg, ISC_TRUE)); } else { /* * TCP. Build a response dns_message_t, temporarily storing * the raw, uncompressed owner names and RR data contiguously * in xfr->buf. We know that if the uncompressed data fits * in xfr->buf, the compressed data will surely fit in a TCP * message. */ CHECK(dns_message_create(xfr->mctx, DNS_MESSAGE_INTENTRENDER, &tcpmsg)); msg = tcpmsg; msg->id = xfr->id; msg->rcode = dns_rcode_noerror; msg->flags = DNS_MESSAGEFLAG_QR | DNS_MESSAGEFLAG_AA; if ((xfr->client->attributes & NS_CLIENTATTR_RA) != 0) msg->flags |= DNS_MESSAGEFLAG_RA; CHECK(dns_message_settsigkey(msg, xfr->tsigkey)); CHECK(dns_message_setquerytsig(msg, xfr->lasttsig)); if (xfr->lasttsig != NULL) isc_buffer_free(&xfr->lasttsig); /* * Add a EDNS option to the message? */ if ((xfr->client->attributes & NS_CLIENTATTR_WANTOPT) != 0) { dns_rdataset_t *opt = NULL; CHECK(ns_client_addopt(xfr->client, msg, &opt)); CHECK(dns_message_setopt(msg, opt)); /* * Add to first message only. */ xfr->client->attributes &= ~NS_CLIENTATTR_WANTNSID; xfr->client->attributes &= ~NS_CLIENTATTR_HAVEEXPIRE; } /* * Account for reserved space. */ if (xfr->tsigkey != NULL) INSIST(msg->reserved != 0U); isc_buffer_add(&xfr->buf, msg->reserved); /* * Include a question section in the first message only. * BIND 8.2.1 will not recognize an IXFR if it does not * have a question section. */ if (xfr->nmsg == 0) { dns_name_t *qname = NULL; isc_region_t r; /* * Reserve space for the 12-byte message header * and 4 bytes of question. */ isc_buffer_add(&xfr->buf, 12 + 4); qrdataset = NULL; result = dns_message_gettemprdataset(msg, &qrdataset); if (result != ISC_R_SUCCESS) goto failure; dns_rdataset_makequestion(qrdataset, xfr->client->message->rdclass, xfr->qtype); result = dns_message_gettempname(msg, &qname); if (result != ISC_R_SUCCESS) goto failure; dns_name_init(qname, NULL); isc_buffer_availableregion(&xfr->buf, &r); INSIST(r.length >= xfr->qname->length); r.length = xfr->qname->length; isc_buffer_putmem(&xfr->buf, xfr->qname->ndata, xfr->qname->length); dns_name_fromregion(qname, &r); ISC_LIST_INIT(qname->list); ISC_LIST_APPEND(qname->list, qrdataset, link); dns_message_addname(msg, qname, DNS_SECTION_QUESTION); } else { /* * Reserve space for the 12-byte message header */ isc_buffer_add(&xfr->buf, 12); msg->tcp_continuation = 1; } } /* * Try to fit in as many RRs as possible, unless "one-answer" * format has been requested. */ for (n_rrs = 0; ; n_rrs++) { dns_name_t *name = NULL; isc_uint32_t ttl; dns_rdata_t *rdata = NULL; unsigned int size; isc_region_t r; msgname = NULL; msgrdata = NULL; msgrdl = NULL; msgrds = NULL; xfr->stream->methods->current(xfr->stream, &name, &ttl, &rdata); size = name->length + 10 + rdata->length; isc_buffer_availableregion(&xfr->buf, &r); if (size >= r.length) { /* * RR would not fit. If there are other RRs in the * buffer, send them now and leave this RR to the * next message. If this RR overflows the buffer * all by itself, fail. * * In theory some RRs might fit in a TCP message * when compressed even if they do not fit when * uncompressed, but surely we don't want * to send such monstrosities to an unsuspecting * slave. */ if (n_rrs == 0) { xfrout_log(xfr, ISC_LOG_WARNING, "RR too large for zone transfer " "(%d bytes)", size); /* XXX DNS_R_RRTOOLARGE? */ result = ISC_R_NOSPACE; goto failure; } break; } if (isc_log_wouldlog(ns_g_lctx, XFROUT_RR_LOGLEVEL)) log_rr(name, rdata, ttl); /* XXX */ result = dns_message_gettempname(msg, &msgname); if (result != ISC_R_SUCCESS) goto failure; dns_name_init(msgname, NULL); isc_buffer_availableregion(&xfr->buf, &r); INSIST(r.length >= name->length); r.length = name->length; isc_buffer_putmem(&xfr->buf, name->ndata, name->length); dns_name_fromregion(msgname, &r); /* Reserve space for RR header. */ isc_buffer_add(&xfr->buf, 10); result = dns_message_gettemprdata(msg, &msgrdata); if (result != ISC_R_SUCCESS) goto failure; isc_buffer_availableregion(&xfr->buf, &r); r.length = rdata->length; isc_buffer_putmem(&xfr->buf, rdata->data, rdata->length); dns_rdata_init(msgrdata); dns_rdata_fromregion(msgrdata, rdata->rdclass, rdata->type, &r); result = dns_message_gettemprdatalist(msg, &msgrdl); if (result != ISC_R_SUCCESS) goto failure; msgrdl->type = rdata->type; msgrdl->rdclass = rdata->rdclass; msgrdl->ttl = ttl; if (rdata->type == dns_rdatatype_sig || rdata->type == dns_rdatatype_rrsig) msgrdl->covers = dns_rdata_covers(rdata); else msgrdl->covers = dns_rdatatype_none; ISC_LIST_APPEND(msgrdl->rdata, msgrdata, link); result = dns_message_gettemprdataset(msg, &msgrds); if (result != ISC_R_SUCCESS) goto failure; result = dns_rdatalist_tordataset(msgrdl, msgrds); INSIST(result == ISC_R_SUCCESS); ISC_LIST_APPEND(msgname->list, msgrds, link); dns_message_addname(msg, msgname, DNS_SECTION_ANSWER); msgname = NULL; result = xfr->stream->methods->next(xfr->stream); if (result == ISC_R_NOMORE) { xfr->end_of_stream = ISC_TRUE; break; } CHECK(result); if (! xfr->many_answers) break; /* * At this stage, at least 1 RR has been rendered into * the message. Check if we want to clamp this message * here (TCP only). 20480 was set as an upper limit to * improve message compression. */ if ((isc_buffer_usedlength(&xfr->buf) >= 20480) && is_tcp) break; } if (is_tcp) { CHECK(dns_compress_init(&cctx, -1, xfr->mctx)); dns_compress_setsensitive(&cctx, ISC_TRUE); cleanup_cctx = ISC_TRUE; CHECK(dns_message_renderbegin(msg, &cctx, &xfr->txbuf)); CHECK(dns_message_rendersection(msg, DNS_SECTION_QUESTION, 0)); CHECK(dns_message_rendersection(msg, DNS_SECTION_ANSWER, 0)); CHECK(dns_message_renderend(msg)); dns_compress_invalidate(&cctx); cleanup_cctx = ISC_FALSE; isc_buffer_usedregion(&xfr->txbuf, &used); isc_buffer_putuint16(&xfr->txlenbuf, (isc_uint16_t)used.length); region.base = xfr->txlenbuf.base; region.length = 2 + used.length; xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending TCP message of %d bytes", used.length); CHECK(isc_socket_send(xfr->client->tcpsocket, /* XXX */ ®ion, xfr->client->task, xfrout_senddone, xfr)); xfr->sends++; } else { xfrout_log(xfr, ISC_LOG_DEBUG(8), "sending IXFR UDP response"); ns_client_send(xfr->client); xfr->stream->methods->pause(xfr->stream); xfrout_ctx_destroy(&xfr); return; } /* Advance lasttsig to be the last TSIG generated */ CHECK(dns_message_getquerytsig(msg, xfr->mctx, &xfr->lasttsig)); xfr->nmsg++; failure: if (msgname != NULL) { if (msgrds != NULL) { if (dns_rdataset_isassociated(msgrds)) dns_rdataset_disassociate(msgrds); dns_message_puttemprdataset(msg, &msgrds); } if (msgrdl != NULL) { ISC_LIST_UNLINK(msgrdl->rdata, msgrdata, link); dns_message_puttemprdatalist(msg, &msgrdl); } if (msgrdata != NULL) dns_message_puttemprdata(msg, &msgrdata); dns_message_puttempname(msg, &msgname); } if (tcpmsg != NULL) dns_message_destroy(&tcpmsg); if (cleanup_cctx) dns_compress_invalidate(&cctx); /* * Make sure to release any locks held by database * iterators before returning from the event handler. */ xfr->stream->methods->pause(xfr->stream); if (result == ISC_R_SUCCESS) return; xfrout_fail(xfr, result, "sending zone data"); }
static void control_recvmessage(isc_task_t *task, isc_event_t *event) { controlconnection_t *conn; controllistener_t *listener; controlkey_t *key; isccc_sexpr_t *request = NULL; isccc_sexpr_t *response = NULL; isc_uint32_t algorithm; isccc_region_t secret; isc_stdtime_t now; isc_buffer_t b; isc_region_t r; isc_buffer_t *text; isc_result_t result; isc_result_t eresult; isccc_sexpr_t *_ctrl; isccc_time_t sent; isccc_time_t exp; isc_uint32_t nonce; isccc_sexpr_t *data; REQUIRE(event->ev_type == ISCCC_EVENT_CCMSG); conn = event->ev_arg; listener = conn->listener; algorithm = DST_ALG_UNKNOWN; secret.rstart = NULL; text = NULL; /* Is the server shutting down? */ if (listener->controls->shuttingdown) goto cleanup; if (conn->ccmsg.result != ISC_R_SUCCESS) { if (conn->ccmsg.result != ISC_R_CANCELED && conn->ccmsg.result != ISC_R_EOF) log_invalid(&conn->ccmsg, conn->ccmsg.result); goto cleanup; } request = NULL; for (key = ISC_LIST_HEAD(listener->keys); key != NULL; key = ISC_LIST_NEXT(key, link)) { isccc_region_t ccregion; ccregion.rstart = isc_buffer_base(&conn->ccmsg.buffer); ccregion.rend = isc_buffer_used(&conn->ccmsg.buffer); secret.rstart = isc_mem_get(listener->mctx, key->secret.length); if (secret.rstart == NULL) goto cleanup; memmove(secret.rstart, key->secret.base, key->secret.length); secret.rend = secret.rstart + key->secret.length; algorithm = key->algorithm; result = isccc_cc_fromwire(&ccregion, &request, algorithm, &secret); if (result == ISC_R_SUCCESS) break; isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); if (result != ISCCC_R_BADAUTH) { log_invalid(&conn->ccmsg, result); goto cleanup; } } if (key == NULL) { log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH); goto cleanup; } /* We shouldn't be getting a reply. */ if (isccc_cc_isreply(request)) { log_invalid(&conn->ccmsg, ISC_R_FAILURE); goto cleanup_request; } isc_stdtime_get(&now); /* * Limit exposure to replay attacks. */ _ctrl = isccc_alist_lookup(request, "_ctrl"); if (_ctrl == NULL) { log_invalid(&conn->ccmsg, ISC_R_FAILURE); goto cleanup_request; } if (isccc_cc_lookupuint32(_ctrl, "_tim", &sent) == ISC_R_SUCCESS) { if ((sent + CLOCKSKEW) < now || (sent - CLOCKSKEW) > now) { log_invalid(&conn->ccmsg, ISCCC_R_CLOCKSKEW); goto cleanup_request; } } else { log_invalid(&conn->ccmsg, ISC_R_FAILURE); goto cleanup_request; } /* * Expire messages that are too old. */ if (isccc_cc_lookupuint32(_ctrl, "_exp", &exp) == ISC_R_SUCCESS && now > exp) { log_invalid(&conn->ccmsg, ISCCC_R_EXPIRED); goto cleanup_request; } /* * Duplicate suppression (required for UDP). */ isccc_cc_cleansymtab(listener->controls->symtab, now); result = isccc_cc_checkdup(listener->controls->symtab, request, now); if (result != ISC_R_SUCCESS) { if (result == ISC_R_EXISTS) result = ISCCC_R_DUPLICATE; log_invalid(&conn->ccmsg, result); goto cleanup_request; } if (conn->nonce != 0 && (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS || conn->nonce != nonce)) { log_invalid(&conn->ccmsg, ISCCC_R_BADAUTH); goto cleanup_request; } result = isc_buffer_allocate(listener->mctx, &text, 2 * 2048); if (result != ISC_R_SUCCESS) goto cleanup_request; /* * Establish nonce. */ if (conn->nonce == 0) { while (conn->nonce == 0) isc_random_get(&conn->nonce); eresult = ISC_R_SUCCESS; } else eresult = ns_control_docommand(request, &text); result = isccc_cc_createresponse(request, now, now + 60, &response); if (result != ISC_R_SUCCESS) goto cleanup_request; data = isccc_alist_lookup(response, "_data"); if (data != NULL) { if (isccc_cc_defineuint32(data, "result", eresult) == NULL) goto cleanup_response; } if (eresult != ISC_R_SUCCESS) { if (data != NULL) { const char *estr = isc_result_totext(eresult); if (isccc_cc_definestring(data, "err", estr) == NULL) goto cleanup_response; } } if (isc_buffer_usedlength(text) > 0) { if (data != NULL) { char *str = (char *)isc_buffer_base(text); if (isccc_cc_definestring(data, "text", str) == NULL) goto cleanup_response; } } _ctrl = isccc_alist_lookup(response, "_ctrl"); if (_ctrl == NULL || isccc_cc_defineuint32(_ctrl, "_nonce", conn->nonce) == NULL) goto cleanup_response; if (conn->buffer == NULL) { result = isc_buffer_allocate(listener->mctx, &conn->buffer, 2 * 2048); if (result != ISC_R_SUCCESS) goto cleanup_response; } isc_buffer_clear(conn->buffer); /* Skip the length field (4 bytes) */ isc_buffer_add(conn->buffer, 4); result = isccc_cc_towire(response, &conn->buffer, algorithm, &secret); if (result != ISC_R_SUCCESS) goto cleanup_response; isc_buffer_init(&b, conn->buffer->base, 4); isc_buffer_putuint32(&b, conn->buffer->used - 4); r.base = conn->buffer->base; r.length = conn->buffer->used; result = isc_socket_send(conn->sock, &r, task, control_senddone, conn); if (result != ISC_R_SUCCESS) goto cleanup_response; conn->sending = ISC_TRUE; isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); isccc_sexpr_free(&request); isccc_sexpr_free(&response); isc_buffer_free(&text); return; cleanup_response: isccc_sexpr_free(&response); cleanup_request: isccc_sexpr_free(&request); isc_mem_put(listener->mctx, secret.rstart, REGION_SIZE(secret)); if (text != NULL) isc_buffer_free(&text); cleanup: isc_socket_detach(&conn->sock); isccc_ccmsg_invalidate(&conn->ccmsg); conn->ccmsg_valid = ISC_FALSE; maybe_free_connection(conn); maybe_free_listener(listener); }
static void rndc_recvnonce(isc_task_t *task, isc_event_t *event) { isccc_sexpr_t *response = NULL; isccc_sexpr_t *_ctrl; isccc_region_t source; isc_result_t result; isc_uint32_t nonce; isccc_sexpr_t *request = NULL; isccc_time_t now; isc_region_t r; isccc_sexpr_t *data; isccc_region_t message; isc_uint32_t len; isc_buffer_t b; recvs--; if (ccmsg.result == ISC_R_EOF) fatal("connection to remote host closed\n" "This may indicate that the remote server is using " "an older version of \n" "the command protocol, this host is not authorized " "to connect,\nor the key is invalid."); if (ccmsg.result != ISC_R_SUCCESS) fatal("recv failed: %s", isc_result_totext(ccmsg.result)); source.rstart = isc_buffer_base(&ccmsg.buffer); source.rend = isc_buffer_used(&ccmsg.buffer); DO("parse message", isccc_cc_fromwire(&source, &response, &secret)); _ctrl = isccc_alist_lookup(response, "_ctrl"); if (_ctrl == NULL) fatal("_ctrl section missing"); nonce = 0; if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS) nonce = 0; isc_stdtime_get(&now); DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial, now, now + 60, &request)); data = isccc_alist_lookup(request, "_data"); if (data == NULL) fatal("_data section missing"); if (isccc_cc_definestring(data, "type", args) == NULL) fatal("out of memory"); if (nonce != 0) { _ctrl = isccc_alist_lookup(request, "_ctrl"); if (_ctrl == NULL) fatal("_ctrl section missing"); if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL) fatal("out of memory"); } message.rstart = databuf + 4; message.rend = databuf + sizeof(databuf); DO("render message", isccc_cc_towire(request, &message, &secret)); len = sizeof(databuf) - REGION_SIZE(message); isc_buffer_init(&b, databuf, 4); isc_buffer_putuint32(&b, len - 4); r.length = len; r.base = databuf; isccc_ccmsg_cancelread(&ccmsg); DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task, rndc_recvdone, NULL)); recvs++; DO("send message", isc_socket_send(sock, &r, task, rndc_senddone, NULL)); sends++; isc_event_free(&event); isccc_sexpr_free(&response); return; }
static void rndc_recvnonce(isc_task_t *task, isc_event_t *event) { isccc_sexpr_t *response = NULL; isccc_sexpr_t *_ctrl; isccc_region_t source; isc_result_t result; isc_uint32_t nonce; isccc_sexpr_t *request = NULL; isccc_time_t now; isc_region_t r; isccc_sexpr_t *data; isc_buffer_t b; recvs--; if (ccmsg.result == ISC_R_EOF) fatal("connection to remote host closed\n" "This may indicate that\n" "* the remote server is using an older version of" " the command protocol,\n" "* this host is not authorized to connect,\n" "* the clocks are not synchronized,\n" "* the key signing algorithm is incorrect, or\n" "* the key is invalid."); if (ccmsg.result != ISC_R_SUCCESS) fatal("recv failed: %s", isc_result_totext(ccmsg.result)); source.rstart = isc_buffer_base(&ccmsg.buffer); source.rend = isc_buffer_used(&ccmsg.buffer); DO("parse message", isccc_cc_fromwire(&source, &response, algorithm, &secret)); _ctrl = isccc_alist_lookup(response, "_ctrl"); if (!isccc_alist_alistp(_ctrl)) fatal("bad or missing ctrl section in response"); nonce = 0; if (isccc_cc_lookupuint32(_ctrl, "_nonce", &nonce) != ISC_R_SUCCESS) nonce = 0; isc_stdtime_get(&now); DO("create message", isccc_cc_createmessage(1, NULL, NULL, ++serial, now, now + 60, &request)); data = isccc_alist_lookup(request, "_data"); if (data == NULL) fatal("_data section missing"); if (isccc_cc_definestring(data, "type", args) == NULL) fatal("out of memory"); if (nonce != 0) { _ctrl = isccc_alist_lookup(request, "_ctrl"); if (_ctrl == NULL) fatal("_ctrl section missing"); if (isccc_cc_defineuint32(_ctrl, "_nonce", nonce) == NULL) fatal("out of memory"); } isc_buffer_clear(databuf); /* Skip the length field (4 bytes) */ isc_buffer_add(databuf, 4); DO("render message", isccc_cc_towire(request, &databuf, algorithm, &secret)); isc_buffer_init(&b, databuf->base, 4); isc_buffer_putuint32(&b, databuf->used - 4); r.base = databuf->base; r.length = databuf->used; isccc_ccmsg_cancelread(&ccmsg); DO("schedule recv", isccc_ccmsg_readmessage(&ccmsg, task, rndc_recvdone, NULL)); recvs++; DO("send message", isc_socket_send(sock, &r, task, rndc_senddone, NULL)); sends++; isc_event_free(&event); isccc_sexpr_free(&response); return; }