2 * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC")
3 * Copyright (C) 2000-2002 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
18 /* $Id: zonetodb.c,v 1.23 2009/09/02 23:48:01 tbox Exp $ */
23 #include <isc/buffer.h>
24 #include <isc/entropy.h>
27 #include <isc/print.h>
28 #include <isc/result.h>
31 #include <dns/dbiterator.h>
32 #include <dns/fixedname.h>
34 #include <dns/rdata.h>
35 #include <dns/rdataset.h>
36 #include <dns/rdatasetiter.h>
37 #include <dns/rdatatype.h>
38 #include <dns/result.h>
40 #include <pgsql/libpq-fe.h>
43 * Generate a PostgreSQL table from a zone.
45 * This is compiled this with something like the following (assuming bind9 has
48 * gcc -g `isc-config.sh --cflags isc dns` -c zonetodb.c
49 * gcc -g -o zonetodb zonetodb.o `isc-config.sh --libs isc dns` -lpq
53 char *dbname, *dbtable;
57 closeandexit(int status) {
64 check_result(isc_result_t result, const char *message) {
65 if (result != ISC_R_SUCCESS) {
66 fprintf(stderr, "%s: %s\n", message,
67 isc_result_totext(result));
73 * Canonicalize a string before writing it to the database.
74 * "dest" must be an array of at least size 2*strlen(source) + 1.
77 quotestring(const char *source, char *dest) {
78 while (*source != 0) {
81 else if (*source == '\\')
89 addrdata(dns_name_t *name, dns_ttl_t ttl, dns_rdata_t *rdata) {
90 unsigned char namearray[DNS_NAME_MAXTEXT + 1];
91 unsigned char canonnamearray[2 * DNS_NAME_MAXTEXT + 1];
92 unsigned char typearray[20];
93 unsigned char canontypearray[40];
94 unsigned char dataarray[2048];
95 unsigned char canondataarray[4096];
100 isc_buffer_init(&b, namearray, sizeof(namearray) - 1);
101 result = dns_name_totext(name, ISC_TRUE, &b);
102 check_result(result, "dns_name_totext");
103 namearray[isc_buffer_usedlength(&b)] = 0;
104 quotestring(namearray, canonnamearray);
106 isc_buffer_init(&b, typearray, sizeof(typearray) - 1);
107 result = dns_rdatatype_totext(rdata->type, &b);
108 check_result(result, "dns_rdatatype_totext");
109 typearray[isc_buffer_usedlength(&b)] = 0;
110 quotestring(typearray, canontypearray);
112 isc_buffer_init(&b, dataarray, sizeof(dataarray) - 1);
113 result = dns_rdata_totext(rdata, NULL, &b);
114 check_result(result, "dns_rdata_totext");
115 dataarray[isc_buffer_usedlength(&b)] = 0;
116 quotestring(dataarray, canondataarray);
118 snprintf(str, sizeof(str),
119 "INSERT INTO %s (NAME, TTL, RDTYPE, RDATA)"
120 " VALUES ('%s', %d, '%s', '%s')",
121 dbtable, canonnamearray, ttl, canontypearray, canondataarray);
123 res = PQexec(conn, str);
124 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
125 fprintf(stderr, "INSERT INTO command failed: %s\n",
126 PQresultErrorMessage(res));
134 main(int argc, char **argv) {
135 char *porigin, *zonefile;
136 dns_fixedname_t forigin, fname;
137 dns_name_t *origin, *name;
139 dns_dbiterator_t *dbiter;
141 dns_rdatasetiter_t *rdsiter;
142 dns_rdataset_t rdataset;
143 dns_rdata_t rdata = DNS_RDATA_INIT;
144 isc_mem_t *mctx = NULL;
145 isc_entropy_t *ectx = NULL;
151 printf("usage: %s origin file dbname dbtable\n", argv[0]);
152 printf("Note that dbname must be an existing database.\n");
161 dns_result_register();
164 result = isc_mem_create(0, 0, &mctx);
165 check_result(result, "isc_mem_create");
167 result = isc_entropy_create(mctx, &ectx);
168 check_result(result, "isc_entropy_create");
170 result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE);
171 check_result(result, "isc_hash_create");
173 isc_buffer_init(&b, porigin, strlen(porigin));
174 isc_buffer_add(&b, strlen(porigin));
175 dns_fixedname_init(&forigin);
176 origin = dns_fixedname_name(&forigin);
177 result = dns_name_fromtext(origin, &b, dns_rootname, 0, NULL);
178 check_result(result, "dns_name_fromtext");
181 result = dns_db_create(mctx, "rbt", origin, dns_dbtype_zone,
182 dns_rdataclass_in, 0, NULL, &db);
183 check_result(result, "dns_db_create");
185 result = dns_db_load(db, zonefile);
186 if (result == DNS_R_SEENINCLUDE)
187 result = ISC_R_SUCCESS;
188 check_result(result, "dns_db_load");
190 printf("Connecting to '%s'\n", dbname);
191 conn = PQsetdb(NULL, NULL, NULL, NULL, dbname);
192 if (PQstatus(conn) == CONNECTION_BAD) {
193 fprintf(stderr, "Connection to database '%s' failed: %s\n",
194 dbname, PQerrorMessage(conn));
198 snprintf(str, sizeof(str),
199 "DROP TABLE %s", dbtable);
201 res = PQexec(conn, str);
202 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK)
203 fprintf(stderr, "DROP TABLE command failed: %s\n",
204 PQresultErrorMessage(res));
207 snprintf(str, sizeof(str), "BEGIN");
209 res = PQexec(conn, str);
210 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
211 fprintf(stderr, "BEGIN command failed: %s\n",
212 PQresultErrorMessage(res));
218 snprintf(str, sizeof(str),
220 "(NAME TEXT, TTL INTEGER, RDTYPE TEXT, RDATA TEXT)",
223 res = PQexec(conn, str);
224 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
225 fprintf(stderr, "CREATE TABLE command failed: %s\n",
226 PQresultErrorMessage(res));
233 result = dns_db_createiterator(db, 0, &dbiter);
234 check_result(result, "dns_db_createiterator()");
236 result = dns_dbiterator_first(dbiter);
237 check_result(result, "dns_dbiterator_first");
239 dns_fixedname_init(&fname);
240 name = dns_fixedname_name(&fname);
241 dns_rdataset_init(&rdataset);
242 dns_rdata_init(&rdata);
244 while (result == ISC_R_SUCCESS) {
246 result = dns_dbiterator_current(dbiter, &node, name);
247 if (result == ISC_R_NOMORE)
249 check_result(result, "dns_dbiterator_current");
252 result = dns_db_allrdatasets(db, node, NULL, 0, &rdsiter);
253 check_result(result, "dns_db_allrdatasets");
255 result = dns_rdatasetiter_first(rdsiter);
257 while (result == ISC_R_SUCCESS) {
258 dns_rdatasetiter_current(rdsiter, &rdataset);
259 result = dns_rdataset_first(&rdataset);
260 check_result(result, "dns_rdataset_first");
261 while (result == ISC_R_SUCCESS) {
262 dns_rdataset_current(&rdataset, &rdata);
263 addrdata(name, rdataset.ttl, &rdata);
264 dns_rdata_reset(&rdata);
265 result = dns_rdataset_next(&rdataset);
267 dns_rdataset_disassociate(&rdataset);
268 result = dns_rdatasetiter_next(rdsiter);
270 dns_rdatasetiter_destroy(&rdsiter);
271 dns_db_detachnode(db, &node);
272 result = dns_dbiterator_next(dbiter);
275 snprintf(str, sizeof(str), "COMMIT TRANSACTION");
277 res = PQexec(conn, str);
278 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) {
279 fprintf(stderr, "COMMIT command failed: %s\n",
280 PQresultErrorMessage(res));
285 dns_dbiterator_destroy(&dbiter);
288 isc_entropy_detach(&ectx);
289 isc_mem_destroy(&mctx);