/*- * Copyright (c) 1996 * David Parsons. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by David Parsons * (orc@pell.chi.il.us) * 4. My name may not be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY DAVID PARSONS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL DAVID PARSONS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ static char rcsid[] = "$Header: /home/orc/src/CVS/dns/dns.c,v 1.10 1996/05/06 08:22:27 orc Exp $"; /* * build DNS maps from the contents of /etc/hosts */ #include #include #include #include #include #include #include #include enum CLASS { NOTHING=0, CLASS_A, CLASS_B, CLASS_C }; /* macros for getting expiration durations */ #define MINUTE 60 #define HOUR (MINUTE*60) #define DAY (HOUR*24) #define WEEK (DAY * 7) struct SOA { char origin[80]; /* Origin of this domain */ char site[80]; /* Site owning this domain */ char contact[80]; /* contact person for the domain */ enum CLASS class; /* number of bytes in network, for IN_ADDR */ int netlen; /* # of bytes in network address */ unsigned char network[6]; /* network address, 4 (for now) chars long */ char in_addr[20]; /* network address, reversed and asciified * for IN_ADDR.ARPA domain */ }; struct NS { char name[80]; /* nameserver or MX */ int precedence; /* for MX, precedence */ struct NS *next; /* next nameserver in chain */ } ; struct ALIAS { char name[40]; /* machine alias */ struct ALIAS *next; /* next alias in chain */ } ; struct HOST { char name[80]; /* machine name */ unsigned char addr[10]; /* IP address */ int addr_valid; /* Is this IP valid for a reverse zone? */ struct ALIAS *aliases; struct HOST *next; /* next machine in chain */ } ; struct SECONDARY { char domain[80]; /* domain we secondary for */ char mapname[80]; /* might be different from the domain if * it's an IN_ADDR.ARPA domain */ struct ALIAS *addr; /* the IP addresses of the nameservers for it */ struct SECONDARY *next; } ; /* * flags */ int write_boot = 0; /* write a named.boot file */ int write_for_real = 0; /* write into /etc and dnsdb */ int restart_named = 0; /* HUP named after we've written files */ enum {toA,toPTR,toCNAME} alias_to = toPTR; int private_mail = 1; /* don't mx each host in the domain */ char *hosts_file = "/etc/hosts"; /* where we get hostnames from */ /* * global nameserving variables. */ static struct SOA soa; /* the SOA record for the domain */ static struct NS *nameservers = 0; /* nameservers for this domain */ static struct NS *mxes = 0; /* mail exchangers for this domain */ static struct HOST *hosts = 0; /* the contents of /etc/hosts */ static struct ALIAS *domain_aliases = 0; /* other domains we are */ char dnsdb[200]; /* where the named files go */ char roothost[200]; /* map the domain onto a machine */ static struct SECONDARY *secondaries = 0; /* what domains do we */ /* secondary for? */ /* * functions to set various things */ /* SET THE AUTHORITIVE SITE */ int setsite(struct SOA *soa, char *text) { if (*text == '.') ++text; strcpy(soa->site, text); return 0; } /* setsite */ /* SET A NAMESERVER */ int setnameserver(struct NS **nameservers, char *text) { struct NS *tmp; if (tmp = (struct NS *)malloc(sizeof *tmp)) { tmp->next = *nameservers; strcpy(tmp->name, text); *nameservers = tmp; return 0; } else return EOF; } /* setnameserver */ /* SET A MX */ int setmailexchanger(struct NS **mx, char *text) { char *tmp; if (setnameserver(mx, text) == 0) { (*mx)->precedence = atoi(text); if (tmp = strtok(NULL, "\t ")) { strcpy((*mx)->name, tmp); return 0; } errno = EINVAL; } return EOF; } /* setmailexchanger */ /* SET A DOMAIN ALIAS */ int setdomainalias(struct ALIAS **aliases, char *text) { struct ALIAS *tal; if (tal = malloc(sizeof *tal)) { strcpy(tal->name, text); tal->next = *aliases; *aliases = tal; return 0; } return EOF; } /* setdomainalias */ /* SET A SECONDARY */ int setsecondary(struct SECONDARY **secondary, char *text) { struct SECONDARY *tsec; char *p; unsigned int a0, a1, a2, a3; if (tsec = malloc(sizeof *tsec)) { strcpy(tsec->domain, text); strcpy(tsec->mapname, text); tsec->next = *secondary; *secondary = tsec; while (p=strtok(NULL, "\t ")) if (setdomainalias(&(tsec->addr), p) != 0) return EOF; /* check if the domain is actually a network number; if it is, we're * secondarying an IN_ADDR.ARPA map */ for (p=tsec->domain; *p; p++) if (*p != '.' && !isdigit(*p)) return 0; if (sscanf(tsec->domain, "%u.%u.%u", &a0, &a1, &a2) == 3) sprintf(tsec->domain, "%u.%u.%u.IN-ADDR.ARPA", a2, a1, a0); else if (sscanf(tsec->domain, "%u.%u", &a0, &a1) == 2) sprintf(tsec->domain, "%u.%u.IN-ADDR.ARPA", a1, a0); else if (sscanf(tsec->domain, "%u", &a0) == 1) sprintf(tsec->domain, "%u.IN-ADDR.ARPA", a0); return 0; } return EOF; } /* setsecondary */ /* SET THE PRIVATE-MAIL FLAG */ int setprivate(int *flag, char *text) { if (strcasecmp(text, "yes") == 0) *flag = 1; else if (strcasecmp(text, "no") == 0) *flag = 0; else return EOF; return 0; } /* setprivate */ /* SET SOME STRING */ int setstring(char *dest, char *text) { strcpy(dest, text); return 0; } /* setstring */ /* SET THE NETWORK ADDRESS */ int setnetwork(struct SOA *soa, char *text) { char *p; soa->netlen = 0; for (p=strtok(text, "."); p; p=strtok(NULL, ".")) { soa->network[soa->netlen++] = atoi(p); } if (soa->netlen < 4) { /* short network name; make a a guess about * the network from the length. */ switch (soa->netlen) { case 1: soa->class = CLASS_A; break; case 2: soa->class = CLASS_B; break; case 3: soa->class = CLASS_C; break; } while (soa->netlen < 4) soa->network[soa->netlen++] = 0; } else if (soa->class == NOTHING) { /* deduce network class from trailing zeros */ if (soa->network[3] == 0) { soa->class = CLASS_C; if (soa->network[2] == 0) { soa->class = CLASS_B; if (soa->network[1] == 0) soa->class = CLASS_A; } } } return 0; } /* setnetwork */ /* SET THE NETWORK CLASS */ int setclass(struct SOA *soa, char *text) { switch (*text) { case 'A': case 'a': soa->class = CLASS_A; break; case 'B': case 'b': soa->class = CLASS_B; break; case 'C': case 'c': soa->class = CLASS_C; break; default: errno = EINVAL; return EOF; } return 0; } /* setclass */ /* * timestamp() and datestamp() give back the date in a couple of forms. * timestamp() returns YYJJJMMM, adjusting for beginning of the epoch. * (JJJ is julian date, MMM is minutes since midnight / 2.) In 2070, * this function will wrap and nameservers that expect to find * monotonically increasing serial numbers will promptly become * very confused. * datestamp() returns the date in an ascii string, courtesy of ctime(), * so we can put it into headers */ static int stamped=0; /* have we gotten the date? */ static time_t now; /* the date */ /* * get the date in serial number form */ char * timestamp() { static char bfr[20]; struct tm *p; if (!stamped) { time(&now); p = gmtime(&now); sprintf(bfr, "%02u%03u%03u", (p->tm_year % 100) - 70, p->tm_yday, ((p->tm_hour * MINUTE) + p->tm_min) / 2); stamped++; } return bfr; } /* * get the date in human-readable form */ char * datestamp() { if (!stamped) { timestamp(); } return ctime(&now); } /* * gethostlist() reads /etc/hosts; if you've specified a NETWORK, * it ignores all machines not in that network. */ gethostlist() { char line[200]; struct HOST *thost; struct ALIAS *talias; char *p; char *ip, *fqdn, *alias; FILE *hfile; unsigned int a0, a1, a2, a3; int lineno=0; int invalid; int namelen; int zonelen = strlen(soa.origin); if (hfile = fopen(hosts_file, "r")) { top: while (fgets(line, sizeof line, hfile)) { lineno++; invalid = 0; strtok(line, "#\n"); if ((ip = strtok(line, " \t")) == NULL) continue; if ((fqdn = strtok(NULL, " \t")) == NULL) continue; if (sscanf(ip, "%d.%d.%d.%d ", &a0, &a1, &a2, &a3) != 4) continue; if (soa.network[0]) { switch (soa.class) { case CLASS_C: if (a2 != soa.network[2]) invalid++; case CLASS_B: if (a1 != soa.network[1]) invalid++; case CLASS_A: if (a0 != soa.network[0]) invalid++; } } namelen = strlen(fqdn); if (namelen < zonelen) continue; if (strcasecmp(fqdn+namelen-zonelen, soa.origin) != 0) continue; thost = malloc(sizeof *thost); thost->addr_valid = !invalid; thost->addr[0] = a0; thost->addr[1] = a1; thost->addr[2] = a2; thost->addr[3] = a3; strncpy(thost->name, fqdn, namelen-zonelen); thost->name[namelen-zonelen-1] = 0; thost->aliases = NULL; thost->next = hosts; hosts = thost; while (alias=strtok(NULL, "\t ")) { if (strcasecmp(alias, thost->name) != 0) { talias = malloc(sizeof *talias); strcpy(talias->name, alias); talias->next = thost->aliases; thost->aliases = talias; } } } fclose(hfile); } else { perror(hosts_file); exit(1); } } /* gethostlist */ /* * make sure a relative name is actually in our hostlist */ void validate(char *what, char *name) { struct HOST *thost; struct ALIAS *talias; for (thost=hosts; thost; thost = thost->next) { if (strcasecmp(name, thost->name) == 0) return; for (talias = thost->aliases; talias; talias = talias->next) if (strcasecmp(name, talias->name) == 0) return; } fprintf(stderr, "%s `%s' is not listed in /etc/hosts; cannot generate\n" "DNS maps!\n" , what, name); exit(1); } /* validate */ /* * generate a path for a dns file. */ char * dnsPath(char *prefix, char *fmt, ...) { static char bfr[1024]; va_list ptr; if (write_for_real) { /* we're generating actual DNS files, so write them into the * directory they belong in */ if (*prefix != '/') sprintf(bfr, "/%s", prefix); else strcpy(bfr, prefix); /* Make the directory, in case it doesn't exist */ if (mkdir(prefix, 0755) != 0) { if (errno != EEXIST) { perror(prefix); exit(2); } } if (prefix[strlen(prefix)-1] != '/') strcat(bfr, "/"); } else bfr[0] = 0; va_start(ptr, fmt); vsprintf(bfr+strlen(bfr), fmt, ptr); va_end(ptr); return bfr; } /* dnsPath */ /* * restart named, if it is running */ restart_server() { pid_t named_pid; FILE *pidfile; /* you may need to change this for your machine */ #define NAMED_PID "/var/run/named.pid" if (pidfile = fopen(NAMED_PID, "r")) { fscanf(pidfile, "%d", &named_pid); fclose(pidfile); if (named_pid > 0) { printf("restarting named [pid %d]\n", named_pid); kill(named_pid, SIGHUP); } } } /* restart_server */ /* * Duration() prints out a time in some human-readable form */ char * Duration(int secs) { static char bfr[80]; int units; int weeks, days, hours, minutes; char comma=0; bfr[0] = 0; minutes = (secs / MINUTE) % 60; hours = (secs / HOUR ) % 24; days = (secs / DAY ) % 7; weeks = (secs / WEEK ); #define PLURAL(x) ((x) != 1) ? "s": "" if (weeks > 0) { sprintf(bfr, "%d week%s", weeks, PLURAL(weeks)); comma++; } if (days > 0) { if (comma > 2) return bfr; sprintf(bfr+strlen(bfr), "%s%d day%s", comma?",":"", days, PLURAL(days)); comma++; } if (hours > 0) { if (comma > 2) return bfr; sprintf(bfr+strlen(bfr), "%s%d hour%s", comma?",":"", hours, PLURAL(hours)); comma++; } if (minutes > 0) { if (comma > 2) return bfr; sprintf(bfr+strlen(bfr), "%s%d minute%s", comma?",":"", minutes, PLURAL(minutes)); comma++; } return bfr; } /* Duration */ /* * write the start of authority header to some zonefile */ print_soa(FILE *dest, char *description, char *domain, int refresh, int retry, int expire, int minimum) { if (description) { fprintf(dest, ";\n" "; data file for %s\n" "; generated by dns on %s" ";\n", description, datestamp()); } else { fprintf(dest, ";\n" "; data file for the %s domain\n" "; generated by dns on %s" ";\n", domain, datestamp()); } fprintf(dest, "$ORIGIN %s.\n" "@ IN SOA %s. %s. (\n" " %-16s; serial number\n", domain, soa.site, soa.contact, timestamp()); fprintf(dest, " %-12d ; refresh (%s)\n", refresh, Duration(refresh)); fprintf(dest, " %-12d ; retry (%s)\n", retry, Duration(retry)); fprintf(dest, " %-12d ; expire (%s)\n", expire, Duration(expire)); fprintf(dest, " %-12d) ; minimum ttl (%s)\n" "\n", minimum, Duration(minimum)); } /* print_soa */ /* * write a root host alias to some zonefile */ void print_roothost(FILE *dest, char *domain) { struct HOST *thost; struct ALIAS *talias; if (roothost[0] == 0) return; fprintf(dest, ";\n" "; default host\n" ";\n"); for (thost = hosts; thost; thost = thost->next) { if (strcasecmp(thost->name, roothost) == 0) { writeit:fprintf(dest, "%-15s IN A %d.%d.%d.%d\n", "", thost->addr[0], thost->addr[1], thost->addr[2], thost->addr[3]); return; } for (talias = thost->aliases; talias; talias = talias->next) if (strcasecmp(talias->name, roothost) == 0) goto writeit; } /* hosts loop */ } /* print_roothost */ /* * write all the mail exchangers for this domain to some zone file */ void printmxes(FILE *dest, char *domain, int display_header) { struct NS *tmx; if (!mxes) return; if (display_header) fprintf(dest, ";\n" "; mail exchangers\n" ";\n"); for (tmx=mxes; tmx; tmx=tmx->next) fprintf(dest, "%-15s IN MX %d %s.\n", "", tmx->precedence, tmx->name); } /* printmxes */ /* * write all the nameservers for this domain to a zonefile */ void print_nameservers(FILE *dest, char *domain) { struct NS *tns; if (!nameservers) return; fprintf(dest, ";\n" "; the nameservers\n" ";\n"); for (tns=nameservers; tns; tns=tns->next) fprintf(dest, "%-15s IN NS %s.\n", "", tns->name); } /* print_nameservers */ /* * write the zone file for the domain name */ printzone(char *filename) { FILE *zone; struct NS *tns; struct HOST *thost; struct ALIAS *talias; int aliascount=0; if ((zone = fopen(filename, "w")) == NULL) { perror(filename); exit(1); } printf("Writing zone information to %s\n", filename); print_soa(zone, NULL, soa.origin, 12*HOUR, HOUR, 4*WEEK, 4*WEEK); print_roothost(zone, soa.origin); printmxes(zone, soa.origin, 1); print_nameservers(zone, soa.origin); fprintf(zone, ";\n" "; the systems\n" ";\n"); fprintf(zone, "%-15s IN A 127.0.0.1\n", "localhost"); for (thost=hosts; thost; thost = thost->next) { fprintf(zone, "%-15s IN A %d.%d.%d.%d\n", thost->name, thost->addr[0], thost->addr[1], thost->addr[2], thost->addr[3]); if (!private_mail) printmxes(zone, soa.origin, 0); if (thost->aliases) aliascount++; } if (aliascount) { fprintf(zone, ";\n" "; aliases\n" ";\n"); for (thost=hosts; thost; thost = thost->next) for (talias = thost->aliases; talias; talias = talias->next) switch (alias_to) { case toA: fprintf(zone, "%-15s IN A %d.%d.%d.%d\t; %s\n", talias->name, thost->addr[0], thost->addr[1], thost->addr[2], thost->addr[3], thost->name); break; case toPTR: fprintf(zone, "%-15s IN PTR %s.%s.\n", talias->name, thost->name, soa.origin); break; case toCNAME: fprintf(zone, "%-15s IN CNAME %s.%s.\n", talias->name, thost->name, soa.origin); break; } } fclose(zone); } /* printzone */ /* * write the zone file for the IN-ADDR.ARPA reverse domain */ printrev(char *filename) { FILE *rev; struct NS *tns; struct HOST *thost; struct ALIAS *talias; char addr[100]; if ((rev = fopen(filename, "w")) == NULL) { perror(filename); exit(1); } printf("Writing IN-ADDR zone to %s\n", filename); sprintf(addr, "%s.IN-ADDR.ARPA", soa.in_addr); print_soa(rev, NULL, addr, 12*HOUR, HOUR, 4*WEEK, 4*WEEK); print_nameservers(rev, addr); fprintf(rev, ";\n" "; the systems\n" ";\n"); for (thost=hosts; thost; thost = thost->next) { int ipx = 3; if (!thost->addr_valid) continue; addr[0] = 0; switch (soa.class) { case CLASS_A: sprintf(addr+strlen(addr), "%d.", thost->addr[ipx--]); case CLASS_B: sprintf(addr+strlen(addr), "%d.", thost->addr[ipx--]); case CLASS_C: sprintf(addr+strlen(addr), "%d", thost->addr[ipx--]); } fprintf(rev, "%-15s IN PTR %s.%s.\n", addr, thost->name, soa.origin); } fclose(rev); } /* printrev */ /* * write the zone file for the localhost domain */ printlocal(char *filename) { FILE *local; struct NS *tns; if ((local = fopen(filename, "w")) == NULL) { perror(filename); exit(1); } printf("Writing localhost zone to %s\n", filename); print_soa(local, "the local loopback interface", "0.0.127.IN-ADDR.ARPA", 10*MINUTE, 5*MINUTE, WEEK, HOUR); fprintf(local, "%-15s IN PTR localhost.\n", "1"); fclose(local); } /* printlocal */ /* * write an alias domain */ printalias(char *filename, char *domain_to_alias) { FILE *alias; char bfr[80]; if ((alias = fopen(filename, "w")) == NULL) { perror(filename); exit(1); } printf("Writing zone for domain alias %s to %s\n", domain_to_alias, filename); sprintf(bfr, "aliased domain %s", domain_to_alias); print_soa(alias, bfr, domain_to_alias, 12*HOUR, HOUR, 2*WEEK, 2*WEEK); fprintf(alias, "%-15s IN PTR %s.\n", "", soa.origin); print_roothost(alias, domain_to_alias); printmxes(alias, domain_to_alias, 1); print_nameservers(alias, domain_to_alias); fclose(alias); } /* printalias */ /* * write a named boot record */ printboot(char *filename) { FILE *boot; struct ALIAS *tal; struct SECONDARY *tsec; if ((boot = fopen(filename, "w")) == NULL) { perror(filename); exit(1); } printf("Writing named boot file to %s\n", filename); fprintf(boot, "; domain %s\n", soa.origin); fprintf(boot, "; data file to boot a name server\n" "; generated by dns on %s" ";\n", datestamp()); fprintf(boot, "directory %s\n", dnsdb); fprintf(boot, ";\n" "; type domain/zone host/file local-file\n" ";\n"); fprintf(boot, "cache . named.cache\n" "\n" "primary 0.0.127.IN-ADDR.ARPA localhost.zone\n"); if (soa.class != NOTHING) { fprintf(boot, "primary %s.IN-ADDR.ARPA", soa.in_addr); fprintf(boot,"%*s%s.rev\n", 33-(12+strlen(soa.in_addr)), "", soa.origin); } fprintf(boot, "primary %-34s%s.zone\n", soa.origin, soa.origin); for (tal = domain_aliases; tal; tal = tal->next) fprintf(boot, "primary %-34s%s.alias\n", tal->name, tal->name); fprintf(boot, "\n" "; domains we do secondary nameservice for\n" ";\n"); for (tsec = secondaries; tsec; tsec = tsec->next) { fprintf(boot, "secondary %-20s", tsec->domain); for (tal = tsec->addr; tal; tal = tal->next) fprintf(boot, " %s", tal->name); fprintf(boot, " %s.bak\n", tsec->mapname); } fclose(boot); } /* printboot */ /* * all the things we can set are kept in an option block, so we just do * table lookups for decoding things. using a lex grammer would be more * elegant, but this is the quick perl-inspired solution. */ enum FLAGS { NEEDSARG=0x01 }; typedef (*setfunc)(void *, char*); struct OPTIONS { char *name; enum FLAGS flag; setfunc setter; int value; int set; void *data; #define VARIABLE(name,func,ptr) { name, NEEDSARG, (setfunc)func, 0, 0, ptr } #define FLAG(name,value,ptr) { name, 0, (setfunc)0, value,0, ptr } } options[] = { VARIABLE("ORIGIN", setstring, soa.origin ), VARIABLE("DOMAIN", setstring, soa.origin ), VARIABLE("SITE", setsite, &soa ), VARIABLE("NAMESERVER", setnameserver, &nameservers), VARIABLE("CONTACT", setstring, soa.contact ), VARIABLE("NETWORK", setnetwork, &soa ), VARIABLE("CLASS", setclass, &soa ), VARIABLE("MX", setmailexchanger,&mxes), VARIABLE("POSTOFFICE", setmailexchanger,&mxes), VARIABLE("DATABASE", setstring, dnsdb ), VARIABLE("ROOTHOST", setstring, roothost ), FLAG ("ALIAS-IP", toA, &alias_to), FLAG ("ALIAS-PTR", toPTR, &alias_to), FLAG ("ALIAS-NAME", toCNAME, &alias_to), VARIABLE("ALIAS-DOMAIN", setdomainalias, &domain_aliases), VARIABLE("SECONDARY", setsecondary, &secondaries), VARIABLE("PRIVATE-MAIL", setprivate, &private_mail), } ; #define NR_OPTIONS (sizeof options / sizeof options[0]) /* * usage: dns < config-file */ main(int argc, char **argv) { extern int getopt(); extern int optind, opterr; extern char *optarg; int c; char *opt, *value; char *p; int x; struct NS *tmp; int lineno=0; int oops=0; char line[1000]; memset(&soa, 0, sizeof soa); memset(dnsdb, 0, sizeof dnsdb); memset(roothost, 0, sizeof roothost); while ((c=getopt(argc, argv, "bWrH:")) != EOF) switch (c) { case 'b': write_boot++; break; case 'r': restart_named++; break; case 'W': write_for_real++; break; case 'H': hosts_file = optarg; break; default: fprintf(stderr, "usage: dns [-bWr] [-H hosts-file] [config-file]\n"); exit(1); } if (optind <= argc) if (!freopen(argv[optind], "r", stdin)) { perror(argv[optind]); exit(1); } while (gets(line)) { lineno++; strtok(line, ";#\n"); opt = strtok(line, "= \t"); if (opt == NULL) continue; value = strtok(NULL, " \t"); for (x=0; x 0) exit(1); gethostlist(); /* pick up a list of hostnames */ /* If the authoritative sitename is relative to our origin, * tack the origin onto it now */ if (!strchr(soa.site,'.')) { validate("Authoritative site", soa.site); strcat(soa.site, "."); strcat(soa.site, soa.origin); } /* If the contact isn't defined, or if it's just a username, * make it root at the authoritative site. */ if (!soa.contact[0]) sprintf(soa.contact, "root@%s", soa.site); else if (!strchr(soa.contact, '@')) { strcat(soa.contact, "@"); strcat(soa.contact, soa.site); } /* dotify the contact name */ for (p=soa.contact; *p; p++) if (*p == '@') *p = '.'; /* add the origin to relative nameservers */ for (tmp=nameservers; tmp; tmp=tmp->next) if (!strchr(tmp->name, '.')) { validate("Nameserver", tmp->name); strcat(tmp->name, "."); strcat(tmp->name, soa.origin); } /* add the origin to relative mail exchangers */ for (tmp=mxes; tmp; tmp=tmp->next) if (!strchr(tmp->name, '.')) { validate("Mail exchanger", tmp->name); strcat(tmp->name, "."); strcat(tmp->name, soa.origin); } /* set up the default location of the dns database */ if (!dnsdb[0]) strcpy(dnsdb, "/var/named"); /* * Now print all the zone maps and boot records */ printlocal(dnsPath(dnsdb, "localhost.zone")); printzone(dnsPath(dnsdb, "%s.zone", soa.origin)); { struct ALIAS *tal; for (tal=domain_aliases; tal; tal = tal->next) printalias(dnsPath(dnsdb, "%s.alias", tal->name), tal->name); } if (soa.network[0] && soa.class != NOTHING) { switch (soa.class) { case CLASS_A: sprintf(soa.in_addr, "%d", soa.network[0]); break; case CLASS_B: sprintf(soa.in_addr, "%d.%d", soa.network[1], soa.network[0]); break; case CLASS_C: sprintf(soa.in_addr, "%d.%d.%d", soa.network[2], soa.network[1], soa.network[0]); break; } printrev(dnsPath(dnsdb, "%s.rev", soa.origin)); } if (write_boot) printboot(dnsPath("/etc", "named.boot")); if (restart_named) restart_server(); } /* main */