/************************************************************************************************** $Id: import.c,v 1.27 2005/04/20 17:22:25 bboy Exp $ import.c: Import DNS data. Copyright (C) 2002-2005 Don Moore This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at Your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA **************************************************************************************************/ #include "util.h" #define DEBUG_SQL 0 int opt_output = 0; /* Output instead of insert */ int opt_notrim = 0; /* Don't remove trailing origin */ int opt_replace = 0; /* Replace current zone */ extern void import_axfr(char *hostport, char *import_zone); #ifdef TINYDNS_IMPORT extern void import_tinydns(char *datafile, char *import_zone); #endif enum _input_format { /* Import format types */ INPUT_UNKNOWN, INPUT_AXFR, #ifdef TINYDNS_IMPORT INPUT_TINYDNS #endif } input_format = INPUT_UNKNOWN; char *axfr_host = NULL; /* Host to import via AXFR */ #ifdef TINYDNS_IMPORT char *tinydns_datafile = NULL; /* Name of tinydns-data format file */ #endif uint32_t import_zone_id = 0; /* ID of current zone */ static int soa_imported, rr_imported, ptr_imported; /* Number of records imported */ /************************************************************************************************** USAGE Display program usage information. **************************************************************************************************/ static void usage(int status) { if (status != EXIT_SUCCESS) { fprintf(stderr, _("Try `%s --help' for more information."), progname); fputs("\n", stderr); } else { printf(_("Usage: %s [OPTION]... [ZONE]..."), progname); puts(""); puts(_("Import DNS data.")); puts(""); /* puts("----------------------------------------------------------------------------78"); */ puts(_(" -a, --axfr=HOST import zones from HOST via AXFR")); #ifdef TINYDNS_IMPORT puts(_(" -t, --tinydns=FILE import zones from tinydns-data format FILE")); #endif puts(""); puts(_(" -D, --database=DB database name to use")); puts(_(" -h, --host=HOST connect to SQL server at HOST")); puts(_(" -p, --password=PASS password for SQL server (or prompt from tty)")); puts(_(" -u, --user=USER username for SQL server if not current user")); puts(""); puts(_(" -o, --output output data instead of inserting records")); puts(_(" -r, --replace if ZONE already exists, replace it")); puts(_(" --notrim do not remove trailing origin from names")); puts(""); #if DEBUG_ENABLED puts(_(" -d, --debug enable debug output")); #endif puts(_(" -v, --verbose be more verbose while running")); puts(_(" --help display this help and exit")); puts(_(" --version output version information and exit")); puts(""); puts(_("If no ZONE is specified, all zones found will be imported. If AXFR")); puts(_("is being used as the import method, the zone names must be specified.")); puts(""); printf(_("Report bugs to .\n"), PACKAGE_BUGREPORT); } exit(status); } /*--- usage() -----------------------------------------------------------------------------------*/ /************************************************************************************************** CMDLINE Process command line options. **************************************************************************************************/ static void cmdline(int argc, char **argv) { char *optstr; int optc, optindex; struct option const longopts[] = { {"axfr", required_argument, NULL, 'a'}, #ifdef TINYDNS_IMPORT {"tinydns", required_argument, NULL, 't'}, #endif {"database", required_argument, NULL, 'D'}, {"host", required_argument, NULL, 'h'}, {"password", optional_argument, NULL, 'p'}, {"user", required_argument, NULL, 'u'}, {"output", no_argument, NULL, 'o'}, {"replace", no_argument, NULL, 'r'}, {"notrim", no_argument, NULL, 0}, {"debug", no_argument, NULL, 'd'}, {"verbose", no_argument, NULL, 'v'}, {"help", no_argument, NULL, 0}, {"version", no_argument, NULL, 0}, {NULL, 0, NULL, 0} }; err_file = stdout; error_init(argv[0], LOG_USER); /* Init output routines */ optstr = getoptstr(longopts); while ((optc = getopt_long(argc, argv, optstr, longopts, &optindex)) != -1) { switch (optc) { case 0: { const char *opt = longopts[optindex].name; if (!strcmp(opt, "version")) /* --version */ { printf("%s ("PACKAGE_NAME") "PACKAGE_VERSION" ("SQL_VERSION_STR")\n", progname); puts("\n" PACKAGE_COPYRIGHT); puts(_("This is free software; see the source for copying conditions. There is NO")); puts(_("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.")); exit(EXIT_SUCCESS); } else if (!strcmp(opt, "help")) /* --help */ usage(EXIT_SUCCESS); else if (!strcmp(opt, "notrim")) /* --help */ opt_notrim = 1; } break; case 'a': /* -a, --axfr */ axfr_host = optarg; input_format = INPUT_AXFR; break; #ifdef TINYDNS_IMPORT case 't': /* -t, --tinydns */ tinydns_datafile = optarg; input_format = INPUT_TINYDNS; break; #endif case 'd': /* -d, --debug */ #if DEBUG_ENABLED err_verbose = err_debug = 1; #endif break; case 'D': /* -D, --database=DB */ conf_set(&Conf, "database", optarg, 0); break; case 'h': /* -h, --host=HOST */ conf_set(&Conf, "db-host", optarg, 0); break; case 'p': /* -p, --password=PASS */ if (optarg) { conf_set(&Conf, "db-password", optarg, 0); memset(optarg, 'X', strlen(optarg)); } else conf_set(&Conf, "db-password", passinput(_("Enter password")), 0); break; case 'u': /* -u, --user=USER */ conf_set(&Conf, "db-user", optarg, 0); break; case 'o': /* -o, --output */ opt_output = 1; break; case 'r': /* -r, --replace */ opt_replace = 1; break; case 'v': /* -v, --verbose */ err_verbose = 1; break; default: usage(EXIT_FAILURE); } } } /*--- cmdline() ---------------------------------------------------------------------------------*/ /************************************************************************************************** IMPORT_SOA Update, replace, or output SOA. Returns the zone ID or 1 if not working with database. **************************************************************************************************/ uint32_t import_soa(const char *import_origin, const char *ns, const char *mbox, unsigned serial, unsigned refresh, unsigned retry, unsigned expire, unsigned minimum, unsigned ttl) { char esc_origin[DNS_MAXESC+1], esc_ns[DNS_MAXESC+1], esc_mbox[DNS_MAXESC+1]; soa_imported++; import_zone_id = 0; Verbose("import soa \"%s\"", import_origin); if (opt_output) /* Not updating database */ { printf( "soa\t%s\t%s\t%s\t%u\t%u\t%u\t%u\t%u\t%u\n", import_origin, ns, mbox, serial, refresh, retry, expire, minimum, ttl ); return (1); } /* SQL-escape the strings */ sql_escstr(sql, esc_origin, (char *)import_origin, strlen(import_origin)); sql_escstr(sql, esc_ns, (char *)ns, strlen(ns)); sql_escstr(sql, esc_mbox, (char *)mbox, strlen(mbox)); /* If this zone already exists, update the "soa" record and delete all "rr" record(s) */ import_zone_id = sql_count(sql, "SELECT id FROM %s WHERE origin='%s'", mydns_soa_table_name, esc_origin); if (import_zone_id > 0) { if (!opt_replace) { Warnx("%s: %s", import_origin, _("zone already exists")); Errx(_("use -r (--replace) to overwrite existing zone")); } /* Delete from "rr" table */ #if DEBUG_SQL Debug("DELETE FROM %s WHERE zone=%u;", mydns_rr_table_name, import_zone_id); #endif sql_queryf(sql, "DELETE FROM %s WHERE zone=%u;", mydns_rr_table_name, import_zone_id); /* Update "soa" table */ #if DEBUG_SQL Debug( "UPDATE %s SET origin='%s',ns='%s',mbox='%s',serial=%u,refresh=%u,retry=%u," "expire=%u,minimum=%u,ttl=%u WHERE id=%u;", mydns_soa_table_name, esc_origin, esc_ns, esc_mbox, serial, refresh, retry, expire, minimum, ttl, import_zone_id); #endif sql_queryf(sql, "UPDATE %s SET origin='%s',ns='%s',mbox='%s',serial=%u,refresh=%u,retry=%u," "expire=%u,minimum=%u,ttl=%u WHERE id=%u;", mydns_soa_table_name, esc_origin, esc_ns, esc_mbox, serial, refresh, retry, expire, minimum, ttl, import_zone_id); } /* Otherwise, just create the new zone */ else { Verbose("origin: [%s]", esc_origin); Verbose("ns: [%s]", esc_ns); Verbose("mbox: [%s]", esc_mbox); #if DEBUG_SQL Debug( "INSERT INTO %s (origin,ns,mbox,serial,refresh,retry,expire,minimum,ttl)" " VALUES ('%s','%s','%s',%u,%u,%u,%u,%u,%u);", mydns_soa_table_name, esc_origin, esc_ns, esc_mbox, serial, refresh, retry, expire, minimum, ttl); #endif sql_queryf(sql, "INSERT INTO %s (origin,ns,mbox,serial,refresh,retry,expire,minimum,ttl)" " VALUES ('%s','%s','%s',%u,%u,%u,%u,%u,%u);", mydns_soa_table_name, esc_origin, esc_ns, esc_mbox, serial, refresh, retry, expire, minimum, ttl); /* Store SOA for new record in `got_soa' */ if ((import_zone_id = sql_count(sql, "SELECT id FROM %s WHERE origin='%s'", mydns_soa_table_name, esc_origin)) < 1) Errx(_("error getting id for new soa record")); } return (import_zone_id); } /*--- import_soa() ------------------------------------------------------------------------------*/ /************************************************************************************************** IMPORT_RR Update/output results for an RR record. **************************************************************************************************/ void import_rr(char *name, char *type, char *data, unsigned aux, unsigned ttl) { char esc_name[255 + 255 + 1], esc_data[255 + 255 + 1]; rr_imported++; Verbose("import rr \"%s\" %s \"%s\"", name, type, data); if (opt_output) { printf("rr\t%s\t%s\t%s\t%u\t%u\n", name, type, data, aux, ttl); return; } if (import_zone_id < 1) Errx(_("got rr record without soa")); /* s = shortname(name); */ sql_escstr(sql, esc_name, name, strlen(name)); sql_escstr(sql, esc_data, data, strlen(data)); #if DEBUG_SQL Debug( "INSERT INTO %s (zone,name,type,data,aux,ttl)" " VALUES (%u,'%s','%s','%s',%u,%u);", mydns_rr_table_name, import_zone_id, esc_name, type, esc_data, aux, ttl); #endif sql_queryf(sql, "INSERT INTO %s (zone,name,type,data,aux,ttl)" " VALUES (%u,'%s','%s','%s',%u,%u);", mydns_rr_table_name, import_zone_id, esc_name, type, esc_data, aux, ttl); } /*--- import_rr() -------------------------------------------------------------------------------*/ /************************************************************************************************** MAIN **************************************************************************************************/ int main(int argc, char **argv) { setlocale(LC_ALL, ""); /* Internationalization */ bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); cmdline(argc, argv); load_config(); rr_imported = ptr_imported = 0; if (input_format == INPUT_UNKNOWN) /* No input format specified */ { Warnx(_("no input format specified")); usage(EXIT_FAILURE); } /* If we're inserting directly into the database, connect to the database */ if (!opt_output) db_connect(); if (optind >= argc) /* No arguments - try to import all zones */ { switch (input_format) { case INPUT_AXFR: Warnx(_("using AXFR method; no zones specified")); usage(EXIT_FAILURE); break; #ifdef TINYDNS_IMPORT case INPUT_TINYDNS: import_tinydns(tinydns_datafile, NULL); break; #endif case INPUT_UNKNOWN: break; } } while (optind < argc) { switch (input_format) { case INPUT_AXFR: import_axfr(axfr_host, (char *)argv[optind]); if (import_zone_id) Verbose("%s: zone %u (%u soa / %u rr / %u ptr)", axfr_host, import_zone_id, soa_imported, rr_imported, ptr_imported); break; #ifdef TINYDNS_IMPORT case INPUT_TINYDNS: import_tinydns(tinydns_datafile, (char *)argv[optind]); break; #endif case INPUT_UNKNOWN: break; } optind++; } return (0); } /*--- main() ------------------------------------------------------------------------------------*/ /* vi:set ts=3: */ /* NEED_PO */