static void ns_interface_destroy(ns_interface_t *ifp) { isc_mem_t *mctx = ifp->mgr->mctx; int disp; REQUIRE(NS_INTERFACE_VALID(ifp)); ns_interface_shutdown(ifp); for (disp = 0; disp < ifp->nudpdispatch; disp++) if (ifp->udpdispatch[disp] != NULL) { dns_dispatch_changeattributes(ifp->udpdispatch[disp], 0, DNS_DISPATCHATTR_NOLISTEN); dns_dispatch_detach(&(ifp->udpdispatch[disp])); } if (ifp->tcpsocket != NULL) isc_socket_detach(&ifp->tcpsocket); DESTROYLOCK(&ifp->lock); ns_interfacemgr_detach(&ifp->mgr); ifp->magic = 0; isc_mem_put(mctx, ifp, sizeof(*ifp)); }
isc_result_t ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr, dns_dispatchmgr_t *dispatchmgr, isc_task_t *task, ns_interfacemgr_t **mgrp) { isc_result_t result; ns_interfacemgr_t *mgr; #ifndef USE_ROUTE_SOCKET UNUSED(task); #endif REQUIRE(mctx != NULL); REQUIRE(mgrp != NULL); REQUIRE(*mgrp == NULL); mgr = isc_mem_get(mctx, sizeof(*mgr)); if (mgr == NULL) return (ISC_R_NOMEMORY); mgr->mctx = NULL; isc_mem_attach(mctx, &mgr->mctx); result = isc_mutex_init(&mgr->lock); if (result != ISC_R_SUCCESS) goto cleanup_mem; mgr->taskmgr = taskmgr; mgr->socketmgr = socketmgr; mgr->dispatchmgr = dispatchmgr; mgr->generation = 1; mgr->listenon4 = NULL; mgr->listenon6 = NULL; ISC_LIST_INIT(mgr->interfaces); ISC_LIST_INIT(mgr->listenon); /* * The listen-on lists are initially empty. */ result = ns_listenlist_create(mctx, &mgr->listenon4); if (result != ISC_R_SUCCESS) goto cleanup_mem; ns_listenlist_attach(mgr->listenon4, &mgr->listenon6); result = dns_aclenv_init(mctx, &mgr->aclenv); if (result != ISC_R_SUCCESS) goto cleanup_listenon; #ifdef HAVE_GEOIP mgr->aclenv.geoip = ns_g_geoip; #endif #ifdef USE_ROUTE_SOCKET mgr->route = NULL; result = isc_socket_create(mgr->socketmgr, ROUTE_SOCKET_PROTOCOL, isc_sockettype_raw, &mgr->route); switch (result) { case ISC_R_NOPERM: case ISC_R_SUCCESS: case ISC_R_NOTIMPLEMENTED: case ISC_R_FAMILYNOSUPPORT: break; default: goto cleanup_aclenv; } mgr->task = NULL; if (mgr->route != NULL) isc_task_attach(task, &mgr->task); mgr->references = (mgr->route != NULL) ? 2 : 1; #else mgr->references = 1; #endif mgr->magic = IFMGR_MAGIC; *mgrp = mgr; #ifdef USE_ROUTE_SOCKET if (mgr->route != NULL) { isc_region_t r = { mgr->buf, sizeof(mgr->buf) }; result = isc_socket_recv(mgr->route, &r, 1, mgr->task, route_event, mgr); if (result != ISC_R_SUCCESS) { isc_task_detach(&mgr->task); isc_socket_detach(&mgr->route); ns_interfacemgr_detach(&mgr); } } #endif return (ISC_R_SUCCESS); #ifdef USE_ROUTE_SOCKET cleanup_aclenv: dns_aclenv_destroy(&mgr->aclenv); #endif cleanup_listenon: ns_listenlist_detach(&mgr->listenon4); ns_listenlist_detach(&mgr->listenon6); cleanup_mem: isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr)); return (result); }
static void route_event(isc_task_t *task, isc_event_t *event) { isc_socketevent_t *sevent = NULL; ns_interfacemgr_t *mgr = NULL; isc_region_t r; isc_result_t result; struct MSGHDR *rtm; isc_boolean_t done = ISC_TRUE; UNUSED(task); REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE); mgr = event->ev_arg; sevent = (isc_socketevent_t *)event; if (sevent->result != ISC_R_SUCCESS) { if (sevent->result != ISC_R_CANCELED) isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "automatic interface scanning " "terminated: %s", isc_result_totext(sevent->result)); ns_interfacemgr_detach(&mgr); isc_event_free(&event); return; } rtm = (struct MSGHDR *)mgr->buf; #ifdef RTM_VERSION if (rtm->rtm_version != RTM_VERSION) { isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, "automatic interface rescanning disabled: " "rtm->rtm_version mismatch (%u != %u) " "recompile required", rtm->rtm_version, RTM_VERSION); ns_interfacemgr_detach(&mgr); isc_event_free(&event); return; } #endif switch (rtm->MSGTYPE) { case RTM_NEWADDR: case RTM_DELADDR: if (mgr->route != NULL && ns_g_server->interface_auto) ns_server_scan_interfaces(ns_g_server); break; default: break; } LOCK(&mgr->lock); if (mgr->route != NULL) { /* * Look for next route event. */ r.base = mgr->buf; r.length = sizeof(mgr->buf); result = isc_socket_recv(mgr->route, &r, 1, mgr->task, route_event, mgr); if (result == ISC_R_SUCCESS) done = ISC_FALSE; } UNLOCK(&mgr->lock); if (done) ns_interfacemgr_detach(&mgr); isc_event_free(&event); return; }