7c38d4781fd4c5b146503b0dad7f0a2d58bfd00bTinderbox User * Copyright (C) 2011-2017 Internet Systems Consortium, Inc. ("ISC")
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * This Source Code Form is subject to the terms of the Mozilla Public
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * License, v. 2.0. If a copy of the MPL was not distributed with this
0c27b3fe77ac1d5094ba3521e8142d9e7973133fMark Andrews * file, You can obtain one at http://mozilla.org/MPL/2.0/.
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * This provides a very simple example of an external loadable DLZ
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * driver, with update support.
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt/* For this simple example, use fixed sized strings */
50f64cf0e58073f61bea3e1e4a9ad258bca80961Francis Duponttypedef void log_t(int level, const char *fmt, ...);
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt /* An example driver doesn't need good memory management :-) */
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt /* Helper functions from the dlz_dlopen driver */
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt for (i = 0; single[i]; i++) {
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * Add a record to a list
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Huntadd_name(struct dlz_example_data *state, struct record *list,
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt const char *name, const char *type, dns_ttl_t ttl, const char *data)
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt for (i = 0; i < MAX_RECORDS; i++) {
50f64cf0e58073f61bea3e1e4a9ad258bca80961Francis Dupont if (first_empty == -1 && strlen(list[i].name) == 0U) {
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt if (!single && strcasecmp(list[i].data, data) != 0)
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews "dlz_example: out of record space");
e7d8a617835d93425b30c4fe1d35660ccd62e1d3Mark Andrews strncpy(list[i].name, name, sizeof(list[i].name));
e7d8a617835d93425b30c4fe1d35660ccd62e1d3Mark Andrews strncpy(list[i].type, type, sizeof(list[i].type));
47c5b8af920a93763c97d9a93ea1fd766961a5b3Evan Hunt strncpy(list[i].data, data, sizeof(list[i].data));
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * Delete a record from a list
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Huntdel_name(struct dlz_example_data *state, struct record *list,
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt const char *name, const char *type, dns_ttl_t ttl,
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt const char *data)
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt for (i = 0; i < MAX_RECORDS; i++) {
793814f80703afdd69b59ade91e63efa81ae4178Evan Huntfmt_address(isc_sockaddr_t *addr, char *buffer, size_t size) {
793814f80703afdd69b59ade91e63efa81ae4178Evan Hunt ret = inet_ntop(AF_INET, &addr->type.sin.sin_addr, addr_buf,
793814f80703afdd69b59ade91e63efa81ae4178Evan Hunt ret = inet_ntop(AF_INET6, &addr->type.sin6.sin6_addr, addr_buf,
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * Return the version of the API
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * Remember a helper function from the bind9 dlz_dlopen driver
50f64cf0e58073f61bea3e1e4a9ad258bca80961Francis Dupont state->putnamedrr = (dns_sdlz_putnamedrr_t *)ptr;
50f64cf0e58073f61bea3e1e4a9ad258bca80961Francis Dupont state->writeable_zone = (dns_dlz_writeablezone_t *)ptr;
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * Called to initialize the driver
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Huntdlz_create(const char *dlzname, unsigned int argc, char *argv[],
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt void **dbdata, ...)
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt state = calloc(1, sizeof(struct dlz_example_data));
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt /* Fill in the helper functions */
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt while ((helper_name = va_arg(ap, const char *)) != NULL) {
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews b9_add_helper(state, helper_name, va_arg(ap, void *));
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews "dlz_example: please specify a zone name");
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt /* Ensure zone name is absolute */
2b8bed6681d1541474f022586cbe728dfce36880Evan Hunt n = sprintf(soa_data, "%s hostmaster%s%s 123 900 600 86400 3600",
e7d8a617835d93425b30c4fe1d35660ccd62e1d3Mark Andrews if ((unsigned)n >= sizeof(soa_data))
2b8bed6681d1541474f022586cbe728dfce36880Evan Hunt add_name(state, &state->current[0], state->zone_name,
2b8bed6681d1541474f022586cbe728dfce36880Evan Hunt add_name(state, &state->current[0], state->zone_name,
2b8bed6681d1541474f022586cbe728dfce36880Evan Hunt add_name(state, &state->current[0], state->zone_name,
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews state->log(ISC_LOG_INFO, "dlz_example: started for zone %s",
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * Shut down the backend
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews "dlz_example: shutting down zone %s",
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * See if we handle a given zone
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
b3d116c299722ed7b27550744fff789a61ad3d2bEvan Hunt methods->version - methods->age <= DNS_CLIENTINFOMETHODS_VERSION &&
b3d116c299722ed7b27550744fff789a61ad3d2bEvan Hunt DNS_CLIENTINFOMETHODS_VERSION <= methods->version)
abff0f462a758383d012887d3a97da4dac0c5a94Evan Hunt "dlz_example: dlz_findzonedb called with name '%s' "
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt "in zone DB '%s' from %s",
177be355d4ccf0ce6308e3e6c0f5404eaf13e9a0Evan Hunt * Returning ISC_R_NOTFOUND will cause the query logic to
177be355d4ccf0ce6308e3e6c0f5404eaf13e9a0Evan Hunt * check the database for parent names, looking for zone cuts.
177be355d4ccf0ce6308e3e6c0f5404eaf13e9a0Evan Hunt * Returning ISC_R_NOMORE prevents the query logic from doing
177be355d4ccf0ce6308e3e6c0f5404eaf13e9a0Evan Hunt * this; it will move onto the next database after a single query.
abff0f462a758383d012887d3a97da4dac0c5a94Evan Hunt * For example.net, only return ISC_R_NOMORE when queried
abff0f462a758383d012887d3a97da4dac0c5a94Evan Hunt * from 10.53.0.1.
21a7fde6ba34c62f4859a4c19de4f49ec1bab474Evan Hunt * For bigcname.domain, return success so it appears to be
21a7fde6ba34c62f4859a4c19de4f49ec1bab474Evan Hunt * the zone origin; this regression tests a bug in which
21a7fde6ba34c62f4859a4c19de4f49ec1bab474Evan Hunt * zone origin nodes could fail to return SERVFAIL to the client.
21a7fde6ba34c62f4859a4c19de4f49ec1bab474Evan Hunt * Return success if we have an exact match between the
21a7fde6ba34c62f4859a4c19de4f49ec1bab474Evan Hunt * zone name and the qname
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt snprintf(absolute, sizeof(absolute), "%s.", name);
abff0f462a758383d012887d3a97da4dac0c5a94Evan Hunt * Look up one record in the sample database.
cbd1fa092ea66bfa9990c5e515725646295396c5Evan Hunt * If the queryname is "source-addr", send back a TXT record containing
abff0f462a758383d012887d3a97da4dac0c5a94Evan Hunt * the address of the client, to test the use of 'methods' and 'clientinfo'
cbd1fa092ea66bfa9990c5e515725646295396c5Evan Hunt * If the queryname is "too-long", send back a TXT record that's too long
cbd1fa092ea66bfa9990c5e515725646295396c5Evan Hunt * to process; this should result in a SERVFAIL when queried.
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Huntdlz_lookup(const char *zone, const char *name, void *dbdata,
793814f80703afdd69b59ade91e63efa81ae4178Evan Hunt dns_sdlzlookup_t *lookup, dns_clientinfomethods_t *methods,
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
47c5b8af920a93763c97d9a93ea1fd766961a5b3Evan Hunt snprintf(full_name, 255, "%s.%s", name, state->zone_name);
8d8f9f7f86a33a155dd74b9b2c1317afca555d54Evan Hunt * For test purposes, log all calls to dlz_lookup()
8d8f9f7f86a33a155dd74b9b2c1317afca555d54Evan Hunt state->log(ISC_LOG_INFO, "lookup #%d for %s", count, full_name);
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt * If we need to know the database version (as set in
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt * the 'newversion' dlz function) we can pick it up from the
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt * clientinfo.
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt * This allows a lookup to query the correct version of the DNS
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt * data, if the DLZ can differentiate between versions.
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt * For example, if a new database transaction is created by
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt * 'newversion', the lookup should query within the same
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt * transaction scope if it can.
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt * If the DLZ only operates on 'live' data, then version
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt * wouldn't necessarily be needed.
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt if (dbversion != NULL && *(isc_boolean_t *)dbversion)
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt "dlz_example: lookup against live "
8d8f9f7f86a33a155dd74b9b2c1317afca555d54Evan Hunt "transaction");
b3d116c299722ed7b27550744fff789a61ad3d2bEvan Hunt DNS_CLIENTINFOMETHODS_VERSION <= methods->version)
cbd1fa092ea66bfa9990c5e515725646295396c5Evan Hunt for (i = 0; i < 511; i++)
8d8f9f7f86a33a155dd74b9b2c1317afca555d54Evan Hunt /* Tests for DLZ redirection zones */
8d8f9f7f86a33a155dd74b9b2c1317afca555d54Evan Hunt if (strcmp(name, "*") == 0 && strcmp(zone, ".") == 0) {
8d8f9f7f86a33a155dd74b9b2c1317afca555d54Evan Hunt result = state->putrr(lookup, "A", 0, "100.100.100.2");
8d8f9f7f86a33a155dd74b9b2c1317afca555d54Evan Hunt if (strcmp(name, "long.name.is.not.there") == 0 &&
8d8f9f7f86a33a155dd74b9b2c1317afca555d54Evan Hunt result = state->putrr(lookup, "A", 0, "100.100.100.3");
8d8f9f7f86a33a155dd74b9b2c1317afca555d54Evan Hunt /* Answer from current records */
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt for (i = 0; i < MAX_RECORDS; i++) {
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt if (strcasecmp(state->current[i].name, full_name) == 0) {
cf786a52ce85fd069c764a7de3d036b63a741153Automatic Updater result = state->putrr(lookup, state->current[i].type,
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * See if a zone transfer is allowed
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Huntdlz_allowzonexfr(void *dbdata, const char *name, const char *client) {
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt /* Just say yes for all our zones */
abff0f462a758383d012887d3a97da4dac0c5a94Evan Hunt return (dlz_findzonedb(dbdata, name, NULL, NULL));
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * Perform a zone transfer
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Huntdlz_allnodes(const char *zone, void *dbdata, dns_sdlzallnodes_t *allnodes) {
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt for (i = 0; i < MAX_RECORDS; i++) {
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt result = state->putnamedrr(allnodes, state->current[i].name,
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * Start a transaction
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Huntdlz_newversion(const char *zone, void *dbdata, void **versionp) {
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews "dlz_example: transaction already "
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * End a transaction
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Huntdlz_closeversion(const char *zone, isc_boolean_t commit,
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews state->log(ISC_LOG_INFO, "dlz_example: transaction not "
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews state->log(ISC_LOG_INFO, "dlz_example: committing "
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt for (i = 0; i < MAX_RECORDS; i++) {
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt for (i = 0; i < MAX_RECORDS; i++) {
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews state->log(ISC_LOG_INFO, "dlz_example: cancelling "
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt memset(state->deletes, 0, sizeof(state->deletes));
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * Configure a writeable zone
2b8bed6681d1541474f022586cbe728dfce36880Evan Huntdlz_configure(dns_view_t *view, dns_dlzdb_t *dlzdb, void *dbdata) {
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews state->log(ISC_LOG_INFO, "dlz_example: starting configure");
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews "writeable_zone method available");
2b8bed6681d1541474f022586cbe728dfce36880Evan Hunt result = state->writeable_zone(view, dlzdb, state->zone_name);
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews state->log(ISC_LOG_ERROR, "dlz_example: failed to "
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews state->log(ISC_LOG_INFO, "dlz_example: configured writeable "
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * Authorize a zone update
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Huntdlz_ssumatch(const char *signer, const char *name, const char *tcpaddr,
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt const char *type, const char *key, isc_uint32_t keydatalen,
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews state->log(ISC_LOG_INFO, "dlz_example: denying update "
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews state->log(ISC_LOG_INFO, "dlz_example: allowing update of "
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Huntmodrdataset(struct dlz_example_data *state, const char *name,
411d2914ade28174f3789d4a8e43636fc68eb310Mark Andrews char *full_name, *dclass, *type, *data, *ttlstr, *buf;
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * The format is:
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * FULLNAME\tTTL\tDCLASS\tTYPE\tDATA
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * The DATA field is space separated, and is in the data format
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt * for the type used by dig
aefb3e308ba01ad47a3d3aaadf77a5edd4261cb9Evan Hunt snprintf(absolute, sizeof(absolute), "%s.", name);
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Huntdlz_addrdataset(const char *name, const char *rdatastr,
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt if (version != (void *) &state->transaction_started)
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews state->log(ISC_LOG_INFO, "dlz_example: adding rdataset %s '%s'",
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt return (modrdataset(state, name, rdatastr, &state->adds[0]));
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Huntdlz_subrdataset(const char *name, const char *rdatastr,
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt if (version != (void *) &state->transaction_started)
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews state->log(ISC_LOG_INFO, "dlz_example: subtracting rdataset "
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt return (modrdataset(state, name, rdatastr, &state->deletes[0]));
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Huntdlz_delrdataset(const char *name, const char *type,
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt struct dlz_example_data *state = (struct dlz_example_data *)dbdata;
422009fe5b15e31e7f5d09212bd1480121a1464eEvan Hunt if (version != (void *) &state->transaction_started)
611dc8876869036ab5e981e53ae7a446145d9354Mark Andrews state->log(ISC_LOG_INFO, "dlz_example: deleting rdataset %s "