1/* 2 * Copyright (C) 2004, 2005, 2007-2009 Internet Systems Consortium, Inc. ("ISC") 3 * Copyright (C) 2000-2002 Internet Software Consortium. 4 * 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. 8 * 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. 16 */ 17 18/* $Id: zonetodb.c,v 1.23 2009/09/02 23:48:01 tbox Exp $ */ 19 20#include <stdlib.h> 21#include <string.h> 22 23#include <isc/buffer.h> 24#include <isc/entropy.h> 25#include <isc/hash.h> 26#include <isc/mem.h> 27#include <isc/print.h> 28#include <isc/result.h> 29 30#include <dns/db.h> 31#include <dns/dbiterator.h> 32#include <dns/fixedname.h> 33#include <dns/name.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> 39 40#include <pgsql/libpq-fe.h> 41 42/* 43 * Generate a PostgreSQL table from a zone. 44 * 45 * This is compiled this with something like the following (assuming bind9 has 46 * been installed): 47 * 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 50 */ 51 52PGconn *conn = NULL; 53char *dbname, *dbtable; 54char str[10240]; 55 56void 57closeandexit(int status) { 58 if (conn != NULL) 59 PQfinish(conn); 60 exit(status); 61} 62 63void 64check_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)); 68 closeandexit(1); 69 } 70} 71 72/* 73 * Canonicalize a string before writing it to the database. 74 * "dest" must be an array of at least size 2*strlen(source) + 1. 75 */ 76static void 77quotestring(const char *source, char *dest) { 78 while (*source != 0) { 79 if (*source == '\'') 80 *dest++ = '\''; 81 else if (*source == '\\') 82 *dest++ = '\\'; 83 *dest++ = *source++; 84 } 85 *dest++ = 0; 86} 87 88void 89addrdata(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]; 96 isc_buffer_t b; 97 isc_result_t result; 98 PGresult *res; 99 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); 105 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); 111 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); 117 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); 122 printf("%s\n", str); 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)); 127 PQclear(res); 128 closeandexit(1); 129 } 130 PQclear(res); 131} 132 133int 134main(int argc, char **argv) { 135 char *porigin, *zonefile; 136 dns_fixedname_t forigin, fname; 137 dns_name_t *origin, *name; 138 dns_db_t *db = NULL; 139 dns_dbiterator_t *dbiter; 140 dns_dbnode_t *node; 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; 146 isc_buffer_t b; 147 isc_result_t result; 148 PGresult *res; 149 150 if (argc != 5) { 151 printf("usage: %s origin file dbname dbtable\n", argv[0]); 152 printf("Note that dbname must be an existing database.\n"); 153 exit(1); 154 } 155 156 porigin = argv[1]; 157 zonefile = argv[2]; 158 dbname = argv[3]; 159 dbtable = argv[4]; 160 161 dns_result_register(); 162 163 mctx = NULL; 164 result = isc_mem_create(0, 0, &mctx); 165 check_result(result, "isc_mem_create"); 166 167 result = isc_entropy_create(mctx, &ectx); 168 check_result(result, "isc_entropy_create"); 169 170 result = isc_hash_create(mctx, ectx, DNS_NAME_MAXWIRE); 171 check_result(result, "isc_hash_create"); 172 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"); 179 180 db = NULL; 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"); 184 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"); 189 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)); 195 closeandexit(1); 196 } 197 198 snprintf(str, sizeof(str), 199 "DROP TABLE %s", dbtable); 200 printf("%s\n", str); 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)); 205 PQclear(res); 206 207 snprintf(str, sizeof(str), "BEGIN"); 208 printf("%s\n", str); 209 res = PQexec(conn, str); 210 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { 211 fprintf(stderr, "BEGIN command failed: %s\n", 212 PQresultErrorMessage(res)); 213 PQclear(res); 214 closeandexit(1); 215 } 216 PQclear(res); 217 218 snprintf(str, sizeof(str), 219 "CREATE TABLE %s " 220 "(NAME TEXT, TTL INTEGER, RDTYPE TEXT, RDATA TEXT)", 221 dbtable); 222 printf("%s\n", str); 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)); 227 PQclear(res); 228 closeandexit(1); 229 } 230 PQclear(res); 231 232 dbiter = NULL; 233 result = dns_db_createiterator(db, 0, &dbiter); 234 check_result(result, "dns_db_createiterator()"); 235 236 result = dns_dbiterator_first(dbiter); 237 check_result(result, "dns_dbiterator_first"); 238 239 dns_fixedname_init(&fname); 240 name = dns_fixedname_name(&fname); 241 dns_rdataset_init(&rdataset); 242 dns_rdata_init(&rdata); 243 244 while (result == ISC_R_SUCCESS) { 245 node = NULL; 246 result = dns_dbiterator_current(dbiter, &node, name); 247 if (result == ISC_R_NOMORE) 248 break; 249 check_result(result, "dns_dbiterator_current"); 250 251 rdsiter = NULL; 252 result = dns_db_allrdatasets(db, node, NULL, 0, &rdsiter); 253 check_result(result, "dns_db_allrdatasets"); 254 255 result = dns_rdatasetiter_first(rdsiter); 256 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); 266 } 267 dns_rdataset_disassociate(&rdataset); 268 result = dns_rdatasetiter_next(rdsiter); 269 } 270 dns_rdatasetiter_destroy(&rdsiter); 271 dns_db_detachnode(db, &node); 272 result = dns_dbiterator_next(dbiter); 273 } 274 275 snprintf(str, sizeof(str), "COMMIT TRANSACTION"); 276 printf("%s\n", str); 277 res = PQexec(conn, str); 278 if (!res || PQresultStatus(res) != PGRES_COMMAND_OK) { 279 fprintf(stderr, "COMMIT command failed: %s\n", 280 PQresultErrorMessage(res)); 281 PQclear(res); 282 closeandexit(1); 283 } 284 PQclear(res); 285 dns_dbiterator_destroy(&dbiter); 286 dns_db_detach(&db); 287 isc_hash_destroy(); 288 isc_entropy_detach(&ectx); 289 isc_mem_destroy(&mctx); 290 closeandexit(0); 291 exit(0); 292} 293