1 /* 2 * dbcreate.c -- routines to create an nsd(8) name database 3 * 4 * Copyright (c) 2001-2011, NLnet Labs. All rights reserved. 5 * 6 * See LICENSE for the license. 7 * 8 */ 9 10 #include <config.h> 11 12 #include <sys/types.h> 13 #include <errno.h> 14 #include <fcntl.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <unistd.h> 18 19 #include "namedb.h" 20 21 static int write_db (namedb_type *db); 22 static int write_number(struct namedb *db, uint32_t number); 23 24 struct namedb * 25 namedb_new (const char *filename) 26 { 27 namedb_type *db; 28 /* Make a new structure... */ 29 if ((db = namedb_create()) == NULL) { 30 log_msg(LOG_ERR, 31 "insufficient memory to create database"); 32 return NULL; 33 } 34 db->filename = region_strdup(db->region, filename); 35 db->crc = 0xffffffff; 36 db->diff_skip = 0; 37 db->fd = NULL; 38 39 if (gettimeofday(&(db->diff_timestamp), NULL) != 0) { 40 log_msg(LOG_ERR, "unable to load %s: cannot initialize " 41 "timestamp", db->filename); 42 namedb_destroy(db); 43 return NULL; 44 } 45 46 /* 47 * Unlink the old database, if it exists. This is useful to 48 * ensure that NSD doesn't see the changes until a reload is done. 49 */ 50 if (unlink(db->filename) == -1 && errno != ENOENT) { 51 namedb_destroy(db); 52 return NULL; 53 } 54 55 /* Create the database */ 56 if ((db->fd = fopen(db->filename, "w")) == NULL) { 57 namedb_destroy(db); 58 return NULL; 59 } 60 61 if (!write_data_crc(db->fd, NAMEDB_MAGIC, NAMEDB_MAGIC_SIZE, &db->crc)) { 62 fclose(db->fd); 63 namedb_discard(db); 64 return NULL; 65 } 66 67 return db; 68 } 69 70 71 int 72 namedb_save (struct namedb *db) 73 { 74 if (write_db(db) != 0) { 75 return -1; 76 } 77 78 /* Finish up and write the crc */ 79 if (!write_number(db, ~db->crc)) { 80 fclose(db->fd); 81 return -1; 82 } 83 84 /* Write the magic... */ 85 if (!write_data_crc(db->fd, NAMEDB_MAGIC, NAMEDB_MAGIC_SIZE, &db->crc)) { 86 fclose(db->fd); 87 return -1; 88 } 89 90 /* Close the database */ 91 fclose(db->fd); 92 namedb_destroy(db); 93 return 0; 94 } 95 96 97 void 98 namedb_discard (struct namedb *db) 99 { 100 unlink(db->filename); 101 namedb_destroy(db); 102 } 103 104 static int 105 write_dname(struct namedb *db, domain_type *domain) 106 { 107 const dname_type *dname = domain_dname(domain); 108 109 if (!write_data_crc(db->fd, &dname->name_size, sizeof(dname->name_size), &db->crc)) 110 return -1; 111 112 if (!write_data_crc(db->fd, dname_name(dname), dname->name_size, &db->crc)) 113 return -1; 114 115 return 0; 116 } 117 118 static int 119 write_number(struct namedb *db, uint32_t number) 120 { 121 number = htonl(number); 122 return write_data_crc(db->fd, &number, sizeof(number), &db->crc); 123 } 124 125 static int 126 write_rrset(struct namedb *db, domain_type *domain, rrset_type *rrset) 127 { 128 uint16_t rr_count; 129 int i, j; 130 uint16_t type; 131 uint16_t klass; 132 133 assert(db); 134 assert(domain); 135 assert(rrset); 136 137 rr_count = htons(rrset->rr_count); 138 139 if (!write_number(db, domain->number)) 140 return 1; 141 142 if (!write_number(db, rrset->zone->number)) 143 return 1; 144 145 type = htons(rrset_rrtype(rrset)); 146 if (!write_data_crc(db->fd, &type, sizeof(type), &db->crc)) 147 return 1; 148 149 klass = htons(rrset_rrclass(rrset)); 150 if (!write_data_crc(db->fd, &klass, sizeof(klass), &db->crc)) 151 return 1; 152 153 if (!write_data_crc(db->fd, &rr_count, sizeof(rr_count), &db->crc)) 154 return 1; 155 156 for (i = 0; i < rrset->rr_count; ++i) { 157 rr_type *rr = &rrset->rrs[i]; 158 uint32_t ttl; 159 uint16_t rdata_count; 160 161 rdata_count = htons(rr->rdata_count); 162 if (!write_data_crc(db->fd, &rdata_count, sizeof(rdata_count), &db->crc)) 163 return 1; 164 165 ttl = htonl(rr->ttl); 166 if (!write_data_crc(db->fd, &ttl, sizeof(ttl), &db->crc)) 167 return 1; 168 169 for (j = 0; j < rr->rdata_count; ++j) { 170 rdata_atom_type atom = rr->rdatas[j]; 171 if (rdata_atom_is_domain(rr->type, j)) { 172 if (!write_number(db, rdata_atom_domain(atom)->number)) 173 return 1; 174 175 } else { 176 uint16_t size = htons(rdata_atom_size(atom)); 177 if (!write_data_crc(db->fd, &size, sizeof(size), &db->crc)) 178 return 1; 179 180 if (!write_data_crc(db->fd, 181 rdata_atom_data(atom), 182 rdata_atom_size(atom), &db->crc)) 183 return 1; 184 185 } 186 } 187 } 188 189 return 0; 190 } 191 192 static int 193 number_dnames_iterator(domain_type *node, void *user_data) 194 { 195 uint32_t *current_number = (uint32_t *) user_data; 196 197 node->number = *current_number; 198 ++*current_number; 199 200 return 0; 201 } 202 203 static int 204 write_dname_iterator(domain_type *node, void *user_data) 205 { 206 namedb_type *db = (namedb_type *) user_data; 207 208 return write_dname(db, node); 209 } 210 211 static int 212 write_domain_iterator(domain_type *node, void *user_data) 213 { 214 namedb_type *db = (namedb_type *) user_data; 215 rrset_type *rrset; 216 int error = 0; 217 218 for (rrset = node->rrsets; rrset; rrset = rrset->next) { 219 error += write_rrset(db, node, rrset); 220 } 221 222 return error; 223 } 224 225 /* 226 * Writes databse data into open database *db 227 * 228 * Returns zero if success. 229 */ 230 static int 231 write_db(namedb_type *db) 232 { 233 zone_type *zone; 234 uint32_t terminator = 0; 235 uint32_t dname_count = 1; 236 uint32_t zone_count = 1; 237 int errors = 0; 238 239 for (zone = db->zones; zone; zone = zone->next) { 240 zone->number = zone_count; 241 ++zone_count; 242 243 if (!zone->soa_rrset) { 244 fprintf(stderr, "SOA record not present in %s\n", 245 dname_to_string(domain_dname(zone->apex), 246 NULL)); 247 ++errors; 248 } 249 } 250 251 if (errors > 0) 252 return -1; 253 254 --zone_count; 255 if (!write_number(db, zone_count)) 256 return -1; 257 for (zone = db->zones; zone; zone = zone->next) { 258 if (write_dname(db, zone->apex)) 259 return -1; 260 } 261 262 if (domain_table_iterate(db->domains, number_dnames_iterator, &dname_count)) 263 return -1; 264 265 --dname_count; 266 if (!write_number(db, dname_count)) 267 return -1; 268 269 DEBUG(DEBUG_ZONEC, 1, 270 (LOG_INFO, "Storing %lu domain names\n", (unsigned long) dname_count)); 271 272 if (domain_table_iterate(db->domains, write_dname_iterator, db)) 273 return -1; 274 275 if (domain_table_iterate(db->domains, write_domain_iterator, db)) 276 return -1; 277 278 if (!write_data_crc(db->fd, &terminator, sizeof(terminator), &db->crc)) 279 return -1; 280 281 return 0; 282 } 283