static isc_result_t newconnection(controllistener_t *listener, isc_socket_t *sock) { controlconnection_t *conn; isc_interval_t interval; isc_result_t result; conn = isc_mem_get(listener->mctx, sizeof(*conn)); if (conn == NULL) return (ISC_R_NOMEMORY); conn->sock = sock; isccc_ccmsg_init(listener->mctx, sock, &conn->ccmsg); conn->ccmsg_valid = ISC_TRUE; conn->sending = ISC_FALSE; conn->buffer = NULL; conn->timer = NULL; isc_interval_set(&interval, 60, 0); result = isc_timer_create(ns_g_timermgr, isc_timertype_once, NULL, &interval, listener->task, control_timeout, conn, &conn->timer); if (result != ISC_R_SUCCESS) goto cleanup; conn->listener = listener; conn->nonce = 0; ISC_LINK_INIT(conn, link); result = isccc_ccmsg_readmessage(&conn->ccmsg, listener->task, control_recvmessage, conn); if (result != ISC_R_SUCCESS) goto cleanup; ISC_LIST_APPEND(listener->connections, conn, link); return (ISC_R_SUCCESS); cleanup: if (conn->buffer != NULL) isc_buffer_free(&conn->buffer); isccc_ccmsg_invalidate(&conn->ccmsg); if (conn->timer != NULL) isc_timer_detach(&conn->timer); isc_mem_put(listener->mctx, conn, sizeof(*conn)); return (result); }
int main(int argc, char **argv) { isc_boolean_t show_final_mem = ISC_FALSE; isc_result_t result = ISC_R_SUCCESS; isc_taskmgr_t *taskmgr = NULL; isc_task_t *task = NULL; isc_log_t *log = NULL; isc_logconfig_t *logconfig = NULL; isc_logdestination_t logdest; cfg_parser_t *pctx = NULL; cfg_obj_t *config = NULL; const char *keyname = NULL; char *p; size_t argslen; int ch; int i; result = isc_file_progname(*argv, program, sizeof(program)); if (result != ISC_R_SUCCESS) memcpy(program, "rndc", 5); progname = program; admin_conffile = RNDC_CONFFILE; admin_keyfile = RNDC_KEYFILE; result = isc_app_start(); if (result != ISC_R_SUCCESS) fatal("isc_app_start() failed: %s", isc_result_totext(result)); while ((ch = isc_commandline_parse(argc, argv, "c:k:Mmp:s:Vy:")) != -1) { switch (ch) { case 'c': admin_conffile = isc_commandline_argument; break; case 'k': admin_keyfile = isc_commandline_argument; break; case 'M': isc_mem_debugging = ISC_MEM_DEBUGTRACE; break; case 'm': show_final_mem = ISC_TRUE; break; case 'p': remoteport = atoi(isc_commandline_argument); if (remoteport > 65535 || remoteport == 0) fatal("port '%s' out of range", isc_commandline_argument); break; case 's': servername = isc_commandline_argument; break; case 'V': verbose = ISC_TRUE; break; case 'y': keyname = isc_commandline_argument; break; case '?': usage(0); break; default: fatal("unexpected error parsing command arguments: " "got %c\n", ch); break; } } argc -= isc_commandline_index; argv += isc_commandline_index; if (argc < 1) usage(1); isc_random_get(&serial); DO("create memory context", isc_mem_create(0, 0, &mctx)); DO("create socket manager", isc_socketmgr_create(mctx, &socketmgr)); DO("create task manager", isc_taskmgr_create(mctx, 1, 0, &taskmgr)); DO("create task", isc_task_create(taskmgr, 0, &task)); DO("create logging context", isc_log_create(mctx, &log, &logconfig)); isc_log_setcontext(log); DO("setting log tag", isc_log_settag(logconfig, progname)); logdest.file.stream = stderr; logdest.file.name = NULL; logdest.file.versions = ISC_LOG_ROLLNEVER; logdest.file.maximum_size = 0; DO("creating log channel", isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC, ISC_LOG_INFO, &logdest, ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL)); DO("enabling log channel", isc_log_usechannel(logconfig, "stderr", NULL, NULL)); parse_config(mctx, log, keyname, &pctx, &config); isccc_result_register(); command = *argv; /* * Convert argc/argv into a space-delimited command string * similar to what the user might enter in interactive mode * (if that were implemented). */ argslen = 0; for (i = 0; i < argc; i++) argslen += strlen(argv[i]) + 1; args = isc_mem_get(mctx, argslen); if (args == NULL) DO("isc_mem_get", ISC_R_NOMEMORY); p = args; for (i = 0; i < argc; i++) { size_t len = strlen(argv[i]); memcpy(p, argv[i], len); p += len; *p++ = ' '; } p--; *p++ = '\0'; INSIST(p == args + argslen); notify("%s", command); if (strcmp(command, "restart") == 0) fatal("'%s' is not implemented", command); DO("post event", isc_app_onrun(mctx, task, rndc_start, NULL)); result = isc_app_run(); if (result != ISC_R_SUCCESS) fatal("isc_app_run() failed: %s", isc_result_totext(result)); if (connects > 0 || sends > 0 || recvs > 0) isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL); isc_task_detach(&task); isc_taskmgr_destroy(&taskmgr); isc_socketmgr_destroy(&socketmgr); isc_log_destroy(&log); isc_log_setcontext(NULL); cfg_obj_destroy(pctx, &config); cfg_parser_destroy(&pctx); isc_mem_put(mctx, args, argslen); isccc_ccmsg_invalidate(&ccmsg); if (show_final_mem) isc_mem_stats(mctx, stderr); isc_mem_destroy(&mctx); if (failed) return (1); return (0); }
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); }
int main(int argc, char **argv) { isc_result_t result = ISC_R_SUCCESS; isc_boolean_t show_final_mem = ISC_FALSE; isc_taskmgr_t *taskmgr = NULL; isc_task_t *task = NULL; isc_log_t *log = NULL; isc_logconfig_t *logconfig = NULL; isc_logdestination_t logdest; cfg_parser_t *pctx = NULL; cfg_obj_t *config = NULL; const char *keyname = NULL; struct in_addr in; struct in6_addr in6; char *p; size_t argslen; int ch; int i; result = isc_file_progname(*argv, program, sizeof(program)); if (result != ISC_R_SUCCESS) memmove(program, "rndc", 5); progname = program; admin_conffile = RNDC_CONFFILE; admin_keyfile = RNDC_KEYFILE; isc_sockaddr_any(&local4); isc_sockaddr_any6(&local6); result = isc_app_start(); if (result != ISC_R_SUCCESS) fatal("isc_app_start() failed: %s", isc_result_totext(result)); isc_commandline_errprint = ISC_FALSE; while ((ch = isc_commandline_parse(argc, argv, "b:c:hk:Mmp:qrs:Vy:")) != -1) { switch (ch) { case 'b': if (inet_pton(AF_INET, isc_commandline_argument, &in) == 1) { isc_sockaddr_fromin(&local4, &in, 0); local4set = ISC_TRUE; } else if (inet_pton(AF_INET6, isc_commandline_argument, &in6) == 1) { isc_sockaddr_fromin6(&local6, &in6, 0); local6set = ISC_TRUE; } break; case 'c': admin_conffile = isc_commandline_argument; c_flag = ISC_TRUE; break; case 'k': admin_keyfile = isc_commandline_argument; break; case 'M': isc_mem_debugging = ISC_MEM_DEBUGTRACE; break; case 'm': show_final_mem = ISC_TRUE; break; case 'p': remoteport = atoi(isc_commandline_argument); if (remoteport > 65535 || remoteport == 0) fatal("port '%s' out of range", isc_commandline_argument); break; case 'q': quiet = ISC_TRUE; break; case 'r': showresult = ISC_TRUE; break; case 's': servername = isc_commandline_argument; break; case 'V': verbose = ISC_TRUE; break; case 'y': keyname = isc_commandline_argument; break; case '?': if (isc_commandline_option != '?') { fprintf(stderr, "%s: invalid argument -%c\n", program, isc_commandline_option); usage(1); } /* FALLTHROUGH */ case 'h': usage(0); break; default: fprintf(stderr, "%s: unhandled option -%c\n", program, isc_commandline_option); exit(1); } } argc -= isc_commandline_index; argv += isc_commandline_index; if (argc < 1) usage(1); isc_random_get(&serial); DO("create memory context", isc_mem_create(0, 0, &rndc_mctx)); DO("create socket manager", isc_socketmgr_create(rndc_mctx, &socketmgr)); DO("create task manager", isc_taskmgr_create(rndc_mctx, 1, 0, &taskmgr)); DO("create task", isc_task_create(taskmgr, 0, &task)); DO("create logging context", isc_log_create(rndc_mctx, &log, &logconfig)); isc_log_setcontext(log); DO("setting log tag", isc_log_settag(logconfig, progname)); logdest.file.stream = stderr; logdest.file.name = NULL; logdest.file.versions = ISC_LOG_ROLLNEVER; logdest.file.maximum_size = 0; DO("creating log channel", isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC, ISC_LOG_INFO, &logdest, ISC_LOG_PRINTTAG|ISC_LOG_PRINTLEVEL)); DO("enabling log channel", isc_log_usechannel(logconfig, "stderr", NULL, NULL)); parse_config(rndc_mctx, log, keyname, &pctx, &config); isccc_result_register(); command = *argv; DO("allocate data buffer", isc_buffer_allocate(rndc_mctx, &databuf, 2048)); /* * Convert argc/argv into a space-delimited command string * similar to what the user might enter in interactive mode * (if that were implemented). */ argslen = 0; for (i = 0; i < argc; i++) argslen += strlen(argv[i]) + 1; args = isc_mem_get(rndc_mctx, argslen); if (args == NULL) DO("isc_mem_get", ISC_R_NOMEMORY); p = args; for (i = 0; i < argc; i++) { size_t len = strlen(argv[i]); memmove(p, argv[i], len); p += len; *p++ = ' '; } p--; *p++ = '\0'; INSIST(p == args + argslen); notify("%s", command); if (strcmp(command, "restart") == 0) fatal("'%s' is not implemented", command); if (nserveraddrs == 0) get_addresses(servername, (in_port_t) remoteport); DO("post event", isc_app_onrun(rndc_mctx, task, rndc_start, NULL)); result = isc_app_run(); if (result != ISC_R_SUCCESS) fatal("isc_app_run() failed: %s", isc_result_totext(result)); if (connects > 0 || sends > 0 || recvs > 0) isc_socket_cancel(sock, task, ISC_SOCKCANCEL_ALL); isc_task_detach(&task); isc_taskmgr_destroy(&taskmgr); isc_socketmgr_destroy(&socketmgr); isc_log_destroy(&log); isc_log_setcontext(NULL); cfg_obj_destroy(pctx, &config); cfg_parser_destroy(&pctx); isc_mem_put(rndc_mctx, args, argslen); isccc_ccmsg_invalidate(&ccmsg); dns_name_destroy(); isc_buffer_free(&databuf); if (show_final_mem) isc_mem_stats(rndc_mctx, stderr); isc_mem_destroy(&rndc_mctx); if (failed) return (1); return (0); }