dlz_postgres_driver.c
来自「非常好的dns解析软件」· C语言 代码 · 共 1,343 行 · 第 1/3 页
C
1,343 行
dbi->client = NULL; } /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d did client", dlz_thread_num); /* * what type of query are we going to run? * this time we build the actual query to run. */ switch(query) { case ALLNODES: querystring = build_querystring(ns_g_mctx, dbi->allnodes_q); break; case ALLOWXFR: querystring = build_querystring(ns_g_mctx, dbi->allowxfr_q); break; case AUTHORITY: querystring = build_querystring(ns_g_mctx, dbi->authority_q); break; case FINDZONE: querystring = build_querystring(ns_g_mctx, dbi->findzone_q); break; case LOOKUP: querystring = build_querystring(ns_g_mctx, dbi->lookup_q); break; default: /* * this should never happen. If it does, the code is * screwed up! */ UNEXPECTED_ERROR(__FILE__, __LINE__, "Incorrect query flag passed to " "postgres_get_resultset"); result = ISC_R_UNEXPECTED; goto cleanup; } /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d built query", dlz_thread_num); /* if the querystring is null, Bummer, outta RAM. UPGRADE TIME!!! */ if (querystring == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d query is '%s'", dlz_thread_num, querystring); /* * output the full query string during debug so we can see * what lame error the query has. */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(1), "\nQuery String: %s\n", querystring); /* attempt query up to 3 times. */ for (j=0; j < 3; j++) { /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d executing query for %d time", dlz_thread_num, j); /* try to get result set */ *rs = PQexec((PGconn *)dbi->dbconn, querystring ); result = ISC_R_SUCCESS; /* * if result set is null, reset DB connection, max 3 * attempts. */ for (i=0; *rs == NULL && i < 3; i++) { /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d resetting connection", dlz_thread_num); result = ISC_R_FAILURE; PQreset((PGconn *) dbi->dbconn); /* connection ok, break inner loop */ if (PQstatus((PGconn *) dbi->dbconn) == CONNECTION_OK) break; } /* result set ok, break outter loop */ if (PQresultStatus(*rs) == PGRES_TUPLES_OK) { /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d rs ok", dlz_thread_num); break; } else { /* we got a result set object, but it's not right. */ /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d clearing rs", dlz_thread_num); PQclear(*rs); /* get rid of it */ /* in case this was the last attempt */ result = ISC_R_FAILURE; } } cleanup: /* it's always good to cleanup after yourself */ /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d cleaning up", dlz_thread_num); /* if we couldn't even allocate DBI, just return NULL */ if (dbi == NULL) return ISC_R_FAILURE; /* free dbi->zone string */ if (dbi->zone != NULL) isc_mem_free(ns_g_mctx, dbi->zone); /* free dbi->record string */ if (dbi->record != NULL) isc_mem_free(ns_g_mctx, dbi->record); /* free dbi->client string */ if (dbi->client != NULL) isc_mem_free(ns_g_mctx, dbi->client);#ifdef ISC_PLATFORM_USETHREADS /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d unlocking mutex", dlz_thread_num); /* release the lock so another thread can use this dbi */ isc_mutex_unlock(&dbi->instance_lock);#endif /* ISC_PLATFORM_USETHREADS */ /* release query string */ if (querystring != NULL) isc_mem_free(ns_g_mctx, querystring ); /* temporary logging message */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "%d returning", dlz_thread_num); /* return result */ return result;}/*% * The processing of result sets for lookup and authority are * exactly the same. So that functionality has been moved * into this function to minimize code. */static isc_result_tpostgres_process_rs(dns_sdlzlookup_t *lookup, PGresult *rs){ isc_result_t result; unsigned int i; unsigned int rows; unsigned int fields; unsigned int j; unsigned int len; char *tmpString; char *endp; int ttl; rows = PQntuples(rs); /* how many rows in result set */ fields = PQnfields(rs); /* how many columns in result set */ for (i=0; i < rows; i++) { switch(fields) { case 1: /* * one column in rs, it's the data field. use * default type of A record, and default TTL * of 86400 */ result = dns_sdlz_putrr(lookup, "a", 86400, PQgetvalue(rs, i, 0)); break; case 2: /* two columns, data field, and data type. * use default TTL of 86400. */ result = dns_sdlz_putrr(lookup, PQgetvalue(rs, i, 0), 86400, PQgetvalue(rs, i, 1)); break; case 3: /* three columns, all data no defaults. * convert text to int, make sure it worked * right. */ ttl = strtol(PQgetvalue(rs, i, 0), &endp, 10); if (*endp != '\0' || ttl < 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver ttl must be " "a positive number"); } result = dns_sdlz_putrr(lookup, PQgetvalue(rs, i, 1), ttl, PQgetvalue(rs, i, 2)); break; default: /* * more than 3 fields, concatenate the last * ones together. figure out how long to make * string */ for (j=2, len=0; j < fields; j++) { len += strlen(PQgetvalue(rs, i, j)) + 1; } /* * allocate string memory, allow for NULL to * term string */ tmpString = isc_mem_allocate(ns_g_mctx, len + 1); if (tmpString == NULL) { /* major bummer, need more ram */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver unable to " "allocate memory for " "temporary string"); PQclear(rs); return (ISC_R_FAILURE); /* Yeah, I'd say! */ } /* copy field to tmpString */ strcpy(tmpString, PQgetvalue(rs, i, 2)); /* * concat the rest of fields together, space * between each one. */ for (j=3; j < fields; j++) { strcat(tmpString, " "); strcat(tmpString, PQgetvalue(rs, i, j)); } /* convert text to int, make sure it worked right */ ttl = strtol(PQgetvalue(rs, i, 0), &endp, 10); if (*endp != '\0' || ttl < 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver ttl must be " "a postive number"); } /* ok, now tell Bind about it. */ result = dns_sdlz_putrr(lookup, PQgetvalue(rs, i, 1), ttl, tmpString); /* done, get rid of this thing. */ isc_mem_free(ns_g_mctx, tmpString); } /* I sure hope we were successful */ if (result != ISC_R_SUCCESS) { /* nope, get rid of the Result set, and log a msg */ PQclear(rs); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "dns_sdlz_putrr returned error. " "Error code was: %s", isc_result_totext(result)); return (ISC_R_FAILURE); } } /* free result set memory */ PQclear(rs); /* if we did return results, we are successful */ if (rows > 0) return (ISC_R_SUCCESS); /* empty result set, no data found */ return (ISC_R_NOTFOUND);}/* * SDLZ interface methods *//*% determine if the zone is supported by (in) the database */static isc_result_tpostgres_findzone(void *driverarg, void *dbdata, const char *name){ isc_result_t result; PGresult *rs = NULL; unsigned int rows; UNUSED(driverarg); /* run the query and get the result set from the database. */ result = postgres_get_resultset(name, NULL, NULL, FINDZONE, dbdata, &rs); /* if we didn't get a result set, log an err msg. */ if (result != ISC_R_SUCCESS) { if (rs != NULL) PQclear(rs); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver unable to return " "result set for findzone query"); return (ISC_R_FAILURE); } /* count how many rows in result set */ rows = PQntuples(rs); /* get rid of result set, we are done with it. */ PQclear(rs); /* if we returned any rows, zone is supported. */ if (rows > 0) return (ISC_R_SUCCESS); /* no rows returned, zone is not supported. */ return (ISC_R_NOTFOUND);}/*% Determine if the client is allowed to perform a zone transfer */static isc_result_tpostgres_allowzonexfr(void *driverarg, void *dbdata, const char *name, const char *client){ isc_result_t result; PGresult *rs = NULL; unsigned int rows; UNUSED(driverarg); /* first check if the zone is supported by the database. */ result = postgres_findzone(driverarg, dbdata, name); if (result != ISC_R_SUCCESS) return (ISC_R_NOTFOUND); /* * if we get to this point we know the zone is supported by * the database the only questions now are is the zone * transfer is allowed for this client and did the config file * have an allow zone xfr query. * * Run our query, and get a result set from the database. */ result = postgres_get_resultset(name, NULL, client, ALLOWXFR, dbdata, &rs); /* if we get "not implemented", send it along. */ if (result == ISC_R_NOTIMPLEMENTED) return result; /* if we didn't get a result set, log an err msg. */ if (result != ISC_R_SUCCESS) { if (rs != NULL) PQclear(rs); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver unable to return " "result set for allow xfr query"); return (ISC_R_FAILURE); } /* count how many rows in result set */ rows = PQntuples(rs); /* get rid of result set, we are done with it. */ PQclear(rs); /* if we returned any rows, zone xfr is allowed. */ if (rows > 0) return (ISC_R_SUCCESS); /* no rows returned, zone xfr not allowed */ return (ISC_R_NOPERM);}/*% * If the client is allowed to perform a zone transfer, the next order of * business is to get all the nodes in the zone, so bind can respond to the * query. */static isc_result_tpostgres_allnodes(const char *zone, void *driverarg, void *dbdata, dns_sdlzallnodes_t *allnodes){ isc_result_t result; PGresult *rs = NULL; unsigned int i; unsigned int rows; unsigned int fields; unsigned int j; unsigned int len; char *tmpString; char *endp; int ttl; UNUSED(driverarg); /* run the query and get the result set from the database. */ result = postgres_get_resultset(zone, NULL, NULL, ALLNODES, dbdata, &rs); /* if we get "not implemented", send it along */ if (result == ISC_R_NOTIMPLEMENTED) return result; /* if we didn't get a result set, log an err msg. */ if (result != ISC_R_SUCCESS) { if (rs != NULL) PQclear(rs); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver unable to return " "result set for all nodes query"); return (ISC_R_FAILURE); } rows = PQntuples(rs); /* how many rows in result set */ fields = PQnfields(rs); /* how many columns in result set */ for (i=0; i < rows; i++) { if (fields < 4) { /* gotta have at least 4 columns */ isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver too few fields " "returned by all nodes query"); } /* convert text to int, make sure it worked right */ ttl = strtol(PQgetvalue(rs, i, 0), &endp, 10); if (*endp != '\0' || ttl < 0) { isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_DLZ, ISC_LOG_ERROR, "Postgres driver ttl must be " "a postive number"); } if (fields == 4) { /* tell Bind about it. */ result = dns_sdlz_putnamedrr(allnodes, PQgetvalue(rs, i, 2), PQgetvalue(rs, i, 1), ttl, PQgetvalue(rs, i, 3)); } else { /* * more than 4 fields, concatonat the last * ones together. figure out how long to make * string */ for (j=3, len=0; j < fields; j++) {
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?