elmore
January 20th, 2003, 16:43
Ok for this quick mini how-to, we're going to be setting up an internal DNS server. This is actually not as hard as it may seem. Particularly since we'll be using a tool that will pretty much set DNS up for us.
What you need:
An OpenBSD box
h2n Which can be downloaded from
ftp://ftp.iij.ad.jp/pub/published/oreilly/nutshell/dnsbind/dns.2ed.tar.Z
A valid /etc/hosts file
Your brain
Download h2n from the link above or, I've provided one that's already been hacked up, to remove unecessary things and is already setup to work in OBSD's chrooted DNS environment. Here it is. Since this is a mini how-to I won't be proividing intimate details of the main config file. Perhaps later if I have some time I'll go back and explain these changes. For the most part the changes are self explanatory.
[code:1:50011dc771]
#!/usr/bin/perl
# HACKED: by bmw to eliminate the default MX record for host to the host.
davidbyrne# cat h2n.new
#!/usr/bin/perl
# HACKED: by bmw to eliminate the default MX record for host to the host.
# (look for DefMxWeight)
#NAME
#
# h2n - Translate host table to name server file format
# $Date: 93/02/04 17:43:05 $ $Revision: 1.16 $
#
#SYNOPSIS
#
# h2n -d DOMAIN -n NET [options]
# Various defaults
$Host = `hostname`;
chop($Host);
$Host =~ s/\..*//;
$doaliases = 1;
$domx = 1;
$dowks = 0;
$dotxt = 0;
$dontdodomains = 0;
$Bootfile = "./named.boot";
$Hostfile = "/etc/hosts";
$Commentfile = "";
$Commentfileread = 0;
$User = "root";
# $Pwd = `pwd`;
$Pwd = "/"; # bmw: for chroot'ed environ
$RespHost = "";
$RespUser = "";
$DefSerial = 1;
$DefRefresh = 10800;
$DefRetry = 3600;
$DefExpire = 604800;
$DefTtl = 86400;
$DefMxWeight = 10;
$Defsubnetmask = "";
$ForceSerial = -1;
push(@bootmsgs, "primary\t0.0.127.IN-ADDR.ARPA db.127.0.0\n");
&PARSEARGS(@ARGV);
&FIXUP;
open(HOSTS, $Hostfile) || die "can not open $Hostfile";
LINE: while(<HOSTS>){
next if /^#/; # skip comment lines
next if /^$/; # skip empty lines
chop; # remove the trailing newline
tr/A-Z/a-z/; # translate to lower case
($data,$comment) = split('#', $_, 2);
($addr, $names) = split(' ', $data, 2);
if ($names =~ /^[ \t]*$/) {
print STDERR "Bad line in hosts file ignored '$_'\n";
next LINE;
}
# Match -e args
foreach $netpat (@elimpats){
next LINE if (/[.\s]$netpat/);
}
# Process -c args
foreach $netpat (@cpats){
if (/\.$netpat/) {
($canonical, $aliases) = split(' ', $names, 2);
$canonical =~ s/\.$netpat//;
if($Cnames{$canonical} != 1){
printf DOMAIN "%-20s IN CNAME %s.%s.\n",
$canonical, $canonical, $cpatrel{$netpat};
$Cnames{$canonical} = 1;
}
next LINE;
}
}
# Check that the address is in the address list.
$match = 'none';
foreach $netpat (@Netpatterns){
$match = $netpat, last if ($addr =~ /^$netpat\./);
}
next if ($match eq 'none');
($canonical, $aliases) = split(' ', $names, 2); # separate out aliases
next if ($dontdodomains && $canonical =~ /\./); # skip domain names
$canonical =~ s/$Domainpattern//; # strip off domain if there is one
$Hosts{$canonical} .= $addr . " "; # index addresses by canonical name
$Aliases{$addr} .= $aliases . " "; # index aliases by address
$Comments{"$canonical-$addr"} = $comment;
# Print PTR records
$file = $Netfiles{$match};
printf $file "%-30s\tIN PTR %s.%s.\n",
&REVERSE($addr), $canonical, $Domain;
}
#
# Go through the list of canonical names.
# If there is more than 1 address associated with the
# name, it is a multi-homed host. For each address
# look up the aliases since the aliases are associated
# with the address, not the canonical name.
#
foreach $canonical (keys %Hosts){
@addrs = split(' ', $Hosts{$canonical});
$numaddrs = $#addrs + 1;
foreach $addr (@addrs) {
#
# Print address record for canonical name.
#
if($Cnames{$canonical} != 1){
printf DOMAIN "%-20s IN A %s\n", $canonical, $addr;
} else {
print STDERR "$canonical - can't create A record because CNAME exists for name.\n";
}
#
# Print cname or address records for each alias.
# If this is a multi-homed host, print an address
# record for each alias. If this is a single address
# host, print a cname record.
#
if ($doaliases) {
@aliases = split(' ', $Aliases{$addr});
foreach $alias (@aliases){
#
# Skip over the alias if the alias and canonical
# name only differ in that one of them has the
# domain appended to it.
#
next if ($dontdodomains && $alias =~ /\./); # skip domain names
$alias =~ s/$Domainpattern//;
if($alias eq $canonical){
next;
}
if($numaddrs > 1){
printf DOMAIN "%-20s IN A %s\n", $alias, $addr;
} else {
#
# Flag aliases that have already been used
# in CNAME records or have A records.
#
if(($Cnames{$alias} != 1) && (!$Hosts{$alias})){
printf DOMAIN "%-20s IN CNAME %s.%s.\n",
$alias, $canonical, $Domain;
$Cnames{$alias} = 1;
} else {
print STDERR "$alias - CNAME or A exists already; alias ignored\n";
}
}
}
}
}
if ($domx) {
&MX($canonical, @addrs);
}
if ($dotxt) {
&TXT($canonical, @addrs);
}
if ($Commentfile ne "") {
&DO_COMMENTS($canonical, @addrs);
}
}
# Deal with spcl's
if (-r "spcl.$Domainfile") {
print DOMAIN "\$INCLUDE spcl.$Domainfile\n";
}
foreach $n (@Networks) {
if (-r "spcl.$n") {
$file = "DB.$n";
print $file "\$INCLUDE spcl.$n\n";
}
}
# generate boot.* files
&GEN_BOOT;
exit;
#
# Generate resource record data for
# strings from the commment field that
# are found in the comment file (-C).
#
sub DO_COMMENTS {
local($canonical, @addrs) = @_;
local(*F, @c, $c, $a, $comments);
if (!$Commentfileread) {
open(F, $Commentfile) || die "Unable to open file $Commentfile: $!";
$Commentfileread++;
while (<F>) {
chop;
($key, $c) = split(':', $_, 2);
$CommentRRs{$key} = $c;
}
close(F);
}
foreach $a (@addrs) {
$key = "$canonical-$a";
$comments .= " $Comments{$key}";
}
@c = split(' ', $comments);
foreach $c (@c) {
if($CommentRRs{$c}){
printf DOMAIN "%-20s %s\n", $canonical, $CommentRRs{$c};
}
}
}
#
# Generate MX record data
#
sub MX {
local($canonical, @addrs) = @_;
local($first, $a, $key, $comments);
if($Cnames{$canonical}){
print STDERR "$canonical - can't create MX record because CNAME exists for name.\n";
return;
}
$first = 1;
foreach $a (@addrs) {
$key = "$canonical-$a";
$comments .= " $Comments{$key}";
}
if ($comments !~ /\[no smtp\]/) {
# Add WKS if requested
if ($dowks) {
foreach $a (@addrs) {
printf DOMAIN "%-20s IN WKS %s TCP SMTP\n", $canonical, $a;
}
}
#printf DOMAIN "%-20s IN MX %s %s.%s.\n", $canonical, $DefMxWeight,
# $canonical, $Domain;
#$first = 0;
}
if ($#Mx >= 0) {
if ($comments !~ /\[no mx\]/) {
foreach $a (@Mx) {
if ($first) {
printf DOMAIN "%-20s IN MX %s\n", $canonical, $a;
$first = 0;
} else {
printf DOMAIN "%-20s IN MX %s\n", "", $a;
}
}
}
}
}
#
# Generate TXT record data
#
sub TXT {
local($canonical, @addrs) = @_;
local($a, $key, $comments);
foreach $a (@addrs) {
$key = "$canonical-$a";
$comments .= " $Comments{$key}";
}
$comments =~ s/\[no smtp\]//g;
$comments =~ s/^\s*//;
$comments =~ s/\s*$//;
if ($comments ne "") {
printf DOMAIN "%s IN TXT \"%s\"\n", $canonical, $comments;
}
}
#
# Create the SOA record at the beginning of the file
#
sub MAKE_SOA {
local($fname, $file) = @_;
local($s);
if ( -s $fname) {
open($file, "$fname") || die "Unable to open $fname: $!";
$_ = <$file>;
chop;
if (/\($/) {
if (! $soa_warned) {
print STDERR "Converting SOA format to new style.\n";
$soa_warned++;
}
if ($ForceSerial > 0) {
$Serial = $ForceSerial;
} else {
($Serial, $junk) = split(' ', <$file>, 2);
$Serial++;
}
if (!defined($Refresh)) {
($Refresh, $junk) = split(' ', <$file>, 2);
($Retry, $junk) = split(' ', <$file>, 2);
($Expire, $junk) = split(' ', <$file>, 2);
($Ttl, $junk) = split(' ', <$file>, 2);
}
} else {
split(' ');
if ($#_ == 11) {
if ($ForceSerial > 0) {
$Serial = $ForceSerial;
} else {
$Serial = ++@_[6];
}
if (!defined($Refresh)) {
$Refresh = @_[7];
$Retry = @_[8];
$Expire = @_[9];
$Ttl = @_[10];
}
} else {
print STDERR "Improper format SOA in $fname.\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
}
close($file);
} else {
if ($ForceSerial > 0) {
$Serial = $ForceSerial;
} else {
$Serial = $DefSerial;
}
if (!defined($Refresh)) {
$Refresh = $DefRefresh;
$Retry = $DefRetry;
$Expire = $DefExpire;
$Ttl = $DefTtl;
}
close($file);
}
open($file, "> $fname") || die "Unable to open $fname: $!";
print $file "\@ IN SOA $RespHost $RespUser ";
print $file "( $Serial $Refresh $Retry $Expire $Ttl )\n";
foreach $s (@Servers) {
print $file " IN NS $s\n";
}
print $file "\n";
}
#
# Reverse the octets of an IP address and append
# in-addr.arpa.
#
sub REVERSE {
join('.', reverse(split('\.', $_[0]))) . '.IN-ADDR.ARPA.';
}
#
# Establish what we will be using for SOA records
#
sub FIXUP {
local($s);
if ($Host =~ /\./) {
$RespHost = "$Host.";
} else {
$RespHost = "$Host.$Domain.";
}
$RespHost =~ s/\.\././g;
if ($User =~ /@/) { # -u user@...
if ($User =~ /\./) {
$RespUser = "$User."; # -u user@terminator.movie.edu
} else {
$RespUser = "$User.$Domain."; # -u user@terminator
}
$RespUser =~ s/@/./;
} elsif ($User =~ /\./) {
$RespUser = "$User."; # -u user.terminator.movie.edu
} else {
$RespUser = "$User.$RespHost"; # -u user
}
$RespUser =~ s/\.\././g; # Strip any ".."'s to "."
# Clean up nameservers
if (!defined(@Servers)) {
push(@Servers, "$Host.$Domain.");
} else {
foreach $s (@Servers) {
if ($s !~ /\./) {
$s .= ".$Domain";
}
if ($s !~ /\.$/) {
$s .= ".";
}
}
}
# Clean up MX hosts
foreach $s (@Mx) {
$s =~ s/:/ /;
if ($s !~ /\./) {
$s .= ".$Domain";
}
if ($s !~ /\.$/) {
$s .= ".";
}
}
# Now open boot file and print saved data
open(BOOT, "> $Bootfile") || die "can not open $Bootfile";
print BOOT "\ndirectory $Pwd\n";
foreach $line (@bootmsgs) {
print BOOT $line;
}
print BOOT "cache\t. db.cache\n";
# Go ahead and start creating files and making SOA's
foreach $i (@makesoa) {
($x1, $x2) = split(' ', $i);
&MAKE_SOA($x1, $x2);
}
printf DOMAIN "%-20s IN A 127.0.0.1\n", "localhost";
$file = "DB.127.0.0.1";
&MAKE_SOA("db.127.0.0", $file);
printf $file "%-30s\tIN PTR localhost.\n", &REVERSE("127.0.0.1");
close($file);
}
sub PARSEARGS {
local(@args) = @_;
local($i, $net, $subnetmask, $option, $tmp1);
local(*F, $file, @newargs, @targs);
$i = 0;
while ($i <= $#args){
$option = $args[$i];
if($option eq "-d"){
$Domain = $args[++$i];
$Domainpattern = "." . $Domain;
$Domainpattern =~ s/\./\\./g; # for stripping off domain
# Add entry to the boot file.
$Domainfile = $Domain;
$Domainfile =~ s/\..*//;
push(@makesoa, "db.$Domainfile DOMAIN");
push(@bootmsgs, "primary\t$Domain db.$Domainfile\n");
} elsif ($option eq "-f"){
$file = $args[++$i];
open(F, $file) || die "Unable to open args file $file: $!";
while (<F>) {
next if (/^#/);
next if (/^$/);
chop;
@targs = split(' ');
push(@newargs, @targs);
}
close(F);
&PARSEARGS(@newargs);
} elsif ($option eq "-z"){
$Bootsecsaveaddr = $args[++$i];
if (!defined($Bootsecaddr)) {
$Bootsecaddr = $Bootsecsaveaddr;
}
} elsif ($option eq "-Z"){
$Bootsecaddr = $args[++$i];
if (!defined($Bootsecsaveaddr)) {
$Bootsecsaveaddr = $Bootsecaddr;
}
} elsif ($option eq "-b"){
$Bootfile = $args[++$i];
} elsif ($option eq "-A"){
$doaliases = 0;
} elsif ($option eq "-M"){
$domx = 0;
} elsif ($option eq "-w"){
$dowks = 1;
} elsif ($option eq "-D"){
$dontdodomains = 1;
} elsif ($option eq "-t"){
$dotxt = 1;
} elsif ($option eq "-u"){
$User = $args[++$i];
} elsif ($option eq "-s"){
while ($args[++$i] !~ /^-/ && $i <= $#args) {
push(@Servers, $args[$i]);
}
$i--;
} elsif ($option eq "-m"){
if ($args[++$i] !~ /:/) {
print STDERR "Improper format for -m option ignored ($args[$i]).\n";
}
push(@Mx, $args[$i]);
} elsif ($option eq "-c"){
$tmp1 = $args[++$i];
if ($tmp1 !~ /\./) {
$tmp1 .= ".$Domain";
}
$tmp2 = $tmp1;
$tmp2 =~ s/\./\\./g;
$cpatrel{$tmp2} = $tmp1;
push(@cpats, $tmp2);
} elsif ($option eq "-e"){
$tmp1 = $args[++$i];
if ($tmp1 !~ /\./) {
$tmp1 .= ".$Domain";
}
$tmp1 =~ s/\./\\./g;
push(@elimpats, $tmp1);
} elsif ($option eq "-h"){
$Host = $args[++$i];
} elsif ($option eq "-o"){
if ( $args[++$i] !~ /^[:\d]*$/
|| split(':', $args[$i]) != 4) {
print STDERR "Improper format for -o ($args[$i]).\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
($DefRefresh, $DefRetry, $DefExpire, $DefTtl) = split(':', $args[$i]);
} elsif ($option eq "-i"){
$ForceSerial = $args[++$i];
} elsif ($option eq "-H"){
$Hostfile = $args[++$i];
if (! -r $Hostfile || -z $Hostfile) {
print STDERR "Invalid file specified for -H ($Hostfile).\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
} elsif ($option eq "-C"){
$Commentfile = $args[++$i];
if (! -r $Commentfile || -z $Commentfile) {
print STDERR "Invalid file specified for -C ($Commentfile).\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
} elsif ($option eq "-N"){
$Defsubnetmask = $args[++$i];
if ( $Defsubnetmask !~ /^[.\d]*$/
|| split('\.', $Defsubnetmask) != 4) {
print STDERR "Improper subnet mask ($Defsubnetmask).\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
if ($#Networks >= 0) {
print STDERR "Hmm, -N option should probably be specified before any -n options.\n";
}
} elsif ($option eq "-n"){
($net, $subnetmask) = split(':',$args[++$i]);
if ($subnetmask eq "") {
foreach $tmp1 (&SUBNETS($net, $Defsubnetmask)) {
&BUILDNET($tmp1);
}
} else {
if ( $subnetmask !~ /^[.\d]*$/
|| split('\.', $subnetmask) != 4) {
print STDERR "Improper subnet mask ($subnetmask).\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
foreach $tmp1 (&SUBNETS($net, $subnetmask)) {
&BUILDNET($tmp1);
}
}
} elsif ($option eq "-1"){
print STDERR "Option -1 is obsolete ... ignored.\n";
} elsif ($option eq "-F"){
print STDERR "Option -F is now the default (and only) way ... ignored.\n";
} else {
if($option =~ /^-.*/){
print STDERR "Unknown option: $option ... ignored.\n";
}
}
$i++;
}
if (!defined(@Networks) || $Domain eq "") {
print STDERR "Must specify at least -d and one -n.\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
}
sub BUILDNET {
local($net) = @_;
push(@Networks, $net);
#
# Create pattern to match against.
# The dots must be changed to \. so they
# aren't used as wildcards.
#
$netpat = $net;
$netpat =~ s/\./\\./g;
push(@Netpatterns, $netpat);
#
# Create db files for PTR records.
# Save the file names in an array for future use.
#
$netfile = "DB.$net";
$Netfiles{$netpat} = $netfile;
push(@makesoa, "db.$net $netfile");
# Add entry to the boot file.
$revaddr = &REVERSE($net);
chop($revaddr); # remove trailing dot
push(@bootmsgs, "primary $revaddr db.$net\n");
}
#
# Calculate all the subnets from a network number and mask.
# This was originally written for awk, not perl.
#
sub SUBNETS {
local($network, $mask) = @_;
local(@ans, @net, @mask, $buf, $number, $i, $j, $howmany);
@net = split(/\./, $network);
@mask = split(/\./, $mask);
$number = '';
#
# Only expand bytes 1, 2, or 3
# for DNS purposes
#
for ($i = 0; $i < 3; $i++) {
if ($mask[$i] == 255) {
$number = $number . $net[$i] . '.';
} elsif (($mask[$i] == 0) || $mask[$i] eq '') {
push(@ans, $network);
last;
} else {
#
# This should be done as a bit-wise or
# but awk does not have an or symbol
#
$howmany = 255 - $mask[$i];
for ($j = 0; $j <= $howmany; $j++) {
if ($net[$i] + $j <= 255) {
$buf = sprintf("%s%d", $number, $net[$i] + $j);
push(@ans, $buf);
}
}
last;
}
}
if ($#ans == -1) {
push(@ans, $network);
}
@ans;
}
sub GEN_BOOT {
local(*F, $revaddr, $n);
if (! -e "boot.cacheonly") {
open(F, ">boot.cacheonly") || die "Unable to open boot.cacheonly: $!";
print F "directory\t$Pwd\n";
print F "primary\t\t0.0.127.IN-ADDR.ARPA db.127.0.0\n";
print F "cache\t\t. db.cache\n";
close(F);
}
if (defined($Bootsecaddr)) {
open(F, ">boot.sec") || die "Unable to open boot.sec: $!";
print F "directory\t$Pwd\n";
print F "primary\t\t0.0.127.IN-ADDR.ARPA db.127.0.0\n";
printf F "secondary\t%-23s $Bootsecaddr\n", $Domain;
foreach $n (@Networks) {
$revaddr = &REVERSE($n);
chop($revaddr);
printf F "secondary\t%-23s $Bootsecaddr\n", $revaddr;
}
print F "cache\t\t. db.cache\n";
close(F);
open(F, ">boot.sec.save") || die "Unable to open boot.sec.save: $!";
print F "directory\t$Pwd\n";
print F "primary\t\t0.0.127.IN-ADDR.ARPA db.127.0.0\n";
printf F "secondary\t%-23s $Bootsecsaveaddr db.%s\n",
$Domain, $Domainfile;
foreach $n (@Networks) {
$revaddr = &REVERSE($n);
chop($revaddr);
printf F "secondary\t%-23s $Bootsecsaveaddr db.%s\n",
$revaddr, $n;
}
print F "cache\t\t. db.cache\n";
close(F);
}
}
[/code:1:50011dc771]
Ok now you've got h2n file, what you need to do next is to write script that calls specific options, There's actually a couplel more files that we need to make in order to get DNS talking properly.
1. make a file called mkdns, this is the file that will pass all the options to the h2n perl script.
[code:1:50011dc771]
#!/bin/sh
#
# Create a named db from the hosts file.
# All relevant hosts needed in DNS should exist in /etc/hosts
#
# The current -n options listed below are all current Visible Genetics
# subnets. The -n options will not need changed unless a new subnet is
# add, such as a 172.xxx.xxx.xxx subnet
#
# Only options below that should be changed are as follows:
# -m if your subnet contains it's own mail host for smtp and pop
# -u for whomever the Systems Administrator is at the locale
# -z should be set to the DNS master server which will typically be this host
#
cd /var/named || { echo "no /var/named"; exit 1; }
mv boot.sec.save boot.sec.save.old
/var/named/h2n \
-H /etc/hosts \
-d screamingelectron.org \
-n 216.248.179.99:255.255.255.254 \
-n 10.26.1:255.255.255.0 \
-n 10.20.20:255.255.255.0 \
-n 10.1:255.255.0.0 \
-t \
-m 30:crosseyedandpainless.screamingelectron.org \
-u elmore@screamingelectron.org \
-o 3600:900:1209600:86400 \
-z 10.26.1.3
# -H /var/named/hosts.tmp \
# add extra info to gen'ed boot file
cat - <<! >> named.boot
;
; The forwarder IP addresses should be the DNS server(s) supplied by the
; ISP you are using for your Internet connection
forwarders 216.27.175.2
slave
!
cat - <<! >> boot.sec.save
;
; See forwarder note above
;
forwarders 142.77.1.1
slave
!
diff -q boot.sec.save.old boot.sec.save || {
echo "Don't forget to edit and copy the /var/named/boot.sec.save file"
echo "over to any secondary DNS servers"
}
/bin/kill -HUP `head -1 /var/named/named.pid` || {
# seems to not be running; start a new one...
/usr/sbin/named -t /var/named -u named
}
cat - <<EOM
Note: secondaries DNS servers may not sync
for up to 1 hour.
EOM
[/code:1:50011dc771]
Things to change:
-d is your home domain name, in my case screamingelectron.org
-n are your internal subnets and external subnets if you have any public boxes.
-m is the mx record you're using for your internal SMTP server.
-u is the admin e-mail address to use for all records.
-z Creates a boot file for you to copy over to secondaries.
IP forwarders are your public upstream DNS servers from your ISP.
2. The next file that needs to made is your spcl.domainname file. This file is particularly important if you have an outside webserver. Without this file you won't be able to connect to your outside boxes.
In my case spcl.screamingelectron
[code:1:50011dc771]
;-----------------------------------------------------------------------
; special records for the domain
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; "hidden" hosts -- outside the firewall in the DMZ
;-----------------------------------------------------------------------
screamingelectron.org. IN A 216.154.201.126
www.screamingelectron.org. IN A 216.154.201.126
;-----------------------------------------------------------------------
; *** special mail routing ***
;
; cf: /etc/sendmail.cf
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; aliases and hacks
; - move services away from old proxies
; - solves old WWW pointer problems
; - old servers must be listed in no-proxies field in client
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; forward all outgoing mail to mailhost for routing.
;-----------------------------------------------------------------------
; wildcard MX: this is not only buggy, but superfluous too!
;
;* IN MX 10 mailhost.scredamingelectron.org.
;*.com. IN MX 15 mailhost.screamingelectron.org.
;*.ca. IN MX 15 mailhost.screamingelectron.org.
[/code:1:50011dc771]
3. OK make sure you have all of your outside hosts listed in this file in the same manner I have mine. If you don;t you won;t be able to access them. The next thing is to make sure all your internal hosts are in your /etc/hosts file.
4. The last things to do edit /etc/rc.conf and change the following line.
[code:1:50011dc771]
named_flags=NO # for normal use: ""
to
named_flags="" # for normal use: ""
[/code:1:50011dc771]
5. Now cd to /var/named and execute your mkdns file. chenage your /etc/resolv.conf don't forget to add your search domain, and you're good to go. Do a couple of local nslookups to test.
What you need:
An OpenBSD box
h2n Which can be downloaded from
ftp://ftp.iij.ad.jp/pub/published/oreilly/nutshell/dnsbind/dns.2ed.tar.Z
A valid /etc/hosts file
Your brain
Download h2n from the link above or, I've provided one that's already been hacked up, to remove unecessary things and is already setup to work in OBSD's chrooted DNS environment. Here it is. Since this is a mini how-to I won't be proividing intimate details of the main config file. Perhaps later if I have some time I'll go back and explain these changes. For the most part the changes are self explanatory.
[code:1:50011dc771]
#!/usr/bin/perl
# HACKED: by bmw to eliminate the default MX record for host to the host.
davidbyrne# cat h2n.new
#!/usr/bin/perl
# HACKED: by bmw to eliminate the default MX record for host to the host.
# (look for DefMxWeight)
#NAME
#
# h2n - Translate host table to name server file format
# $Date: 93/02/04 17:43:05 $ $Revision: 1.16 $
#
#SYNOPSIS
#
# h2n -d DOMAIN -n NET [options]
# Various defaults
$Host = `hostname`;
chop($Host);
$Host =~ s/\..*//;
$doaliases = 1;
$domx = 1;
$dowks = 0;
$dotxt = 0;
$dontdodomains = 0;
$Bootfile = "./named.boot";
$Hostfile = "/etc/hosts";
$Commentfile = "";
$Commentfileread = 0;
$User = "root";
# $Pwd = `pwd`;
$Pwd = "/"; # bmw: for chroot'ed environ
$RespHost = "";
$RespUser = "";
$DefSerial = 1;
$DefRefresh = 10800;
$DefRetry = 3600;
$DefExpire = 604800;
$DefTtl = 86400;
$DefMxWeight = 10;
$Defsubnetmask = "";
$ForceSerial = -1;
push(@bootmsgs, "primary\t0.0.127.IN-ADDR.ARPA db.127.0.0\n");
&PARSEARGS(@ARGV);
&FIXUP;
open(HOSTS, $Hostfile) || die "can not open $Hostfile";
LINE: while(<HOSTS>){
next if /^#/; # skip comment lines
next if /^$/; # skip empty lines
chop; # remove the trailing newline
tr/A-Z/a-z/; # translate to lower case
($data,$comment) = split('#', $_, 2);
($addr, $names) = split(' ', $data, 2);
if ($names =~ /^[ \t]*$/) {
print STDERR "Bad line in hosts file ignored '$_'\n";
next LINE;
}
# Match -e args
foreach $netpat (@elimpats){
next LINE if (/[.\s]$netpat/);
}
# Process -c args
foreach $netpat (@cpats){
if (/\.$netpat/) {
($canonical, $aliases) = split(' ', $names, 2);
$canonical =~ s/\.$netpat//;
if($Cnames{$canonical} != 1){
printf DOMAIN "%-20s IN CNAME %s.%s.\n",
$canonical, $canonical, $cpatrel{$netpat};
$Cnames{$canonical} = 1;
}
next LINE;
}
}
# Check that the address is in the address list.
$match = 'none';
foreach $netpat (@Netpatterns){
$match = $netpat, last if ($addr =~ /^$netpat\./);
}
next if ($match eq 'none');
($canonical, $aliases) = split(' ', $names, 2); # separate out aliases
next if ($dontdodomains && $canonical =~ /\./); # skip domain names
$canonical =~ s/$Domainpattern//; # strip off domain if there is one
$Hosts{$canonical} .= $addr . " "; # index addresses by canonical name
$Aliases{$addr} .= $aliases . " "; # index aliases by address
$Comments{"$canonical-$addr"} = $comment;
# Print PTR records
$file = $Netfiles{$match};
printf $file "%-30s\tIN PTR %s.%s.\n",
&REVERSE($addr), $canonical, $Domain;
}
#
# Go through the list of canonical names.
# If there is more than 1 address associated with the
# name, it is a multi-homed host. For each address
# look up the aliases since the aliases are associated
# with the address, not the canonical name.
#
foreach $canonical (keys %Hosts){
@addrs = split(' ', $Hosts{$canonical});
$numaddrs = $#addrs + 1;
foreach $addr (@addrs) {
#
# Print address record for canonical name.
#
if($Cnames{$canonical} != 1){
printf DOMAIN "%-20s IN A %s\n", $canonical, $addr;
} else {
print STDERR "$canonical - can't create A record because CNAME exists for name.\n";
}
#
# Print cname or address records for each alias.
# If this is a multi-homed host, print an address
# record for each alias. If this is a single address
# host, print a cname record.
#
if ($doaliases) {
@aliases = split(' ', $Aliases{$addr});
foreach $alias (@aliases){
#
# Skip over the alias if the alias and canonical
# name only differ in that one of them has the
# domain appended to it.
#
next if ($dontdodomains && $alias =~ /\./); # skip domain names
$alias =~ s/$Domainpattern//;
if($alias eq $canonical){
next;
}
if($numaddrs > 1){
printf DOMAIN "%-20s IN A %s\n", $alias, $addr;
} else {
#
# Flag aliases that have already been used
# in CNAME records or have A records.
#
if(($Cnames{$alias} != 1) && (!$Hosts{$alias})){
printf DOMAIN "%-20s IN CNAME %s.%s.\n",
$alias, $canonical, $Domain;
$Cnames{$alias} = 1;
} else {
print STDERR "$alias - CNAME or A exists already; alias ignored\n";
}
}
}
}
}
if ($domx) {
&MX($canonical, @addrs);
}
if ($dotxt) {
&TXT($canonical, @addrs);
}
if ($Commentfile ne "") {
&DO_COMMENTS($canonical, @addrs);
}
}
# Deal with spcl's
if (-r "spcl.$Domainfile") {
print DOMAIN "\$INCLUDE spcl.$Domainfile\n";
}
foreach $n (@Networks) {
if (-r "spcl.$n") {
$file = "DB.$n";
print $file "\$INCLUDE spcl.$n\n";
}
}
# generate boot.* files
&GEN_BOOT;
exit;
#
# Generate resource record data for
# strings from the commment field that
# are found in the comment file (-C).
#
sub DO_COMMENTS {
local($canonical, @addrs) = @_;
local(*F, @c, $c, $a, $comments);
if (!$Commentfileread) {
open(F, $Commentfile) || die "Unable to open file $Commentfile: $!";
$Commentfileread++;
while (<F>) {
chop;
($key, $c) = split(':', $_, 2);
$CommentRRs{$key} = $c;
}
close(F);
}
foreach $a (@addrs) {
$key = "$canonical-$a";
$comments .= " $Comments{$key}";
}
@c = split(' ', $comments);
foreach $c (@c) {
if($CommentRRs{$c}){
printf DOMAIN "%-20s %s\n", $canonical, $CommentRRs{$c};
}
}
}
#
# Generate MX record data
#
sub MX {
local($canonical, @addrs) = @_;
local($first, $a, $key, $comments);
if($Cnames{$canonical}){
print STDERR "$canonical - can't create MX record because CNAME exists for name.\n";
return;
}
$first = 1;
foreach $a (@addrs) {
$key = "$canonical-$a";
$comments .= " $Comments{$key}";
}
if ($comments !~ /\[no smtp\]/) {
# Add WKS if requested
if ($dowks) {
foreach $a (@addrs) {
printf DOMAIN "%-20s IN WKS %s TCP SMTP\n", $canonical, $a;
}
}
#printf DOMAIN "%-20s IN MX %s %s.%s.\n", $canonical, $DefMxWeight,
# $canonical, $Domain;
#$first = 0;
}
if ($#Mx >= 0) {
if ($comments !~ /\[no mx\]/) {
foreach $a (@Mx) {
if ($first) {
printf DOMAIN "%-20s IN MX %s\n", $canonical, $a;
$first = 0;
} else {
printf DOMAIN "%-20s IN MX %s\n", "", $a;
}
}
}
}
}
#
# Generate TXT record data
#
sub TXT {
local($canonical, @addrs) = @_;
local($a, $key, $comments);
foreach $a (@addrs) {
$key = "$canonical-$a";
$comments .= " $Comments{$key}";
}
$comments =~ s/\[no smtp\]//g;
$comments =~ s/^\s*//;
$comments =~ s/\s*$//;
if ($comments ne "") {
printf DOMAIN "%s IN TXT \"%s\"\n", $canonical, $comments;
}
}
#
# Create the SOA record at the beginning of the file
#
sub MAKE_SOA {
local($fname, $file) = @_;
local($s);
if ( -s $fname) {
open($file, "$fname") || die "Unable to open $fname: $!";
$_ = <$file>;
chop;
if (/\($/) {
if (! $soa_warned) {
print STDERR "Converting SOA format to new style.\n";
$soa_warned++;
}
if ($ForceSerial > 0) {
$Serial = $ForceSerial;
} else {
($Serial, $junk) = split(' ', <$file>, 2);
$Serial++;
}
if (!defined($Refresh)) {
($Refresh, $junk) = split(' ', <$file>, 2);
($Retry, $junk) = split(' ', <$file>, 2);
($Expire, $junk) = split(' ', <$file>, 2);
($Ttl, $junk) = split(' ', <$file>, 2);
}
} else {
split(' ');
if ($#_ == 11) {
if ($ForceSerial > 0) {
$Serial = $ForceSerial;
} else {
$Serial = ++@_[6];
}
if (!defined($Refresh)) {
$Refresh = @_[7];
$Retry = @_[8];
$Expire = @_[9];
$Ttl = @_[10];
}
} else {
print STDERR "Improper format SOA in $fname.\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
}
close($file);
} else {
if ($ForceSerial > 0) {
$Serial = $ForceSerial;
} else {
$Serial = $DefSerial;
}
if (!defined($Refresh)) {
$Refresh = $DefRefresh;
$Retry = $DefRetry;
$Expire = $DefExpire;
$Ttl = $DefTtl;
}
close($file);
}
open($file, "> $fname") || die "Unable to open $fname: $!";
print $file "\@ IN SOA $RespHost $RespUser ";
print $file "( $Serial $Refresh $Retry $Expire $Ttl )\n";
foreach $s (@Servers) {
print $file " IN NS $s\n";
}
print $file "\n";
}
#
# Reverse the octets of an IP address and append
# in-addr.arpa.
#
sub REVERSE {
join('.', reverse(split('\.', $_[0]))) . '.IN-ADDR.ARPA.';
}
#
# Establish what we will be using for SOA records
#
sub FIXUP {
local($s);
if ($Host =~ /\./) {
$RespHost = "$Host.";
} else {
$RespHost = "$Host.$Domain.";
}
$RespHost =~ s/\.\././g;
if ($User =~ /@/) { # -u user@...
if ($User =~ /\./) {
$RespUser = "$User."; # -u user@terminator.movie.edu
} else {
$RespUser = "$User.$Domain."; # -u user@terminator
}
$RespUser =~ s/@/./;
} elsif ($User =~ /\./) {
$RespUser = "$User."; # -u user.terminator.movie.edu
} else {
$RespUser = "$User.$RespHost"; # -u user
}
$RespUser =~ s/\.\././g; # Strip any ".."'s to "."
# Clean up nameservers
if (!defined(@Servers)) {
push(@Servers, "$Host.$Domain.");
} else {
foreach $s (@Servers) {
if ($s !~ /\./) {
$s .= ".$Domain";
}
if ($s !~ /\.$/) {
$s .= ".";
}
}
}
# Clean up MX hosts
foreach $s (@Mx) {
$s =~ s/:/ /;
if ($s !~ /\./) {
$s .= ".$Domain";
}
if ($s !~ /\.$/) {
$s .= ".";
}
}
# Now open boot file and print saved data
open(BOOT, "> $Bootfile") || die "can not open $Bootfile";
print BOOT "\ndirectory $Pwd\n";
foreach $line (@bootmsgs) {
print BOOT $line;
}
print BOOT "cache\t. db.cache\n";
# Go ahead and start creating files and making SOA's
foreach $i (@makesoa) {
($x1, $x2) = split(' ', $i);
&MAKE_SOA($x1, $x2);
}
printf DOMAIN "%-20s IN A 127.0.0.1\n", "localhost";
$file = "DB.127.0.0.1";
&MAKE_SOA("db.127.0.0", $file);
printf $file "%-30s\tIN PTR localhost.\n", &REVERSE("127.0.0.1");
close($file);
}
sub PARSEARGS {
local(@args) = @_;
local($i, $net, $subnetmask, $option, $tmp1);
local(*F, $file, @newargs, @targs);
$i = 0;
while ($i <= $#args){
$option = $args[$i];
if($option eq "-d"){
$Domain = $args[++$i];
$Domainpattern = "." . $Domain;
$Domainpattern =~ s/\./\\./g; # for stripping off domain
# Add entry to the boot file.
$Domainfile = $Domain;
$Domainfile =~ s/\..*//;
push(@makesoa, "db.$Domainfile DOMAIN");
push(@bootmsgs, "primary\t$Domain db.$Domainfile\n");
} elsif ($option eq "-f"){
$file = $args[++$i];
open(F, $file) || die "Unable to open args file $file: $!";
while (<F>) {
next if (/^#/);
next if (/^$/);
chop;
@targs = split(' ');
push(@newargs, @targs);
}
close(F);
&PARSEARGS(@newargs);
} elsif ($option eq "-z"){
$Bootsecsaveaddr = $args[++$i];
if (!defined($Bootsecaddr)) {
$Bootsecaddr = $Bootsecsaveaddr;
}
} elsif ($option eq "-Z"){
$Bootsecaddr = $args[++$i];
if (!defined($Bootsecsaveaddr)) {
$Bootsecsaveaddr = $Bootsecaddr;
}
} elsif ($option eq "-b"){
$Bootfile = $args[++$i];
} elsif ($option eq "-A"){
$doaliases = 0;
} elsif ($option eq "-M"){
$domx = 0;
} elsif ($option eq "-w"){
$dowks = 1;
} elsif ($option eq "-D"){
$dontdodomains = 1;
} elsif ($option eq "-t"){
$dotxt = 1;
} elsif ($option eq "-u"){
$User = $args[++$i];
} elsif ($option eq "-s"){
while ($args[++$i] !~ /^-/ && $i <= $#args) {
push(@Servers, $args[$i]);
}
$i--;
} elsif ($option eq "-m"){
if ($args[++$i] !~ /:/) {
print STDERR "Improper format for -m option ignored ($args[$i]).\n";
}
push(@Mx, $args[$i]);
} elsif ($option eq "-c"){
$tmp1 = $args[++$i];
if ($tmp1 !~ /\./) {
$tmp1 .= ".$Domain";
}
$tmp2 = $tmp1;
$tmp2 =~ s/\./\\./g;
$cpatrel{$tmp2} = $tmp1;
push(@cpats, $tmp2);
} elsif ($option eq "-e"){
$tmp1 = $args[++$i];
if ($tmp1 !~ /\./) {
$tmp1 .= ".$Domain";
}
$tmp1 =~ s/\./\\./g;
push(@elimpats, $tmp1);
} elsif ($option eq "-h"){
$Host = $args[++$i];
} elsif ($option eq "-o"){
if ( $args[++$i] !~ /^[:\d]*$/
|| split(':', $args[$i]) != 4) {
print STDERR "Improper format for -o ($args[$i]).\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
($DefRefresh, $DefRetry, $DefExpire, $DefTtl) = split(':', $args[$i]);
} elsif ($option eq "-i"){
$ForceSerial = $args[++$i];
} elsif ($option eq "-H"){
$Hostfile = $args[++$i];
if (! -r $Hostfile || -z $Hostfile) {
print STDERR "Invalid file specified for -H ($Hostfile).\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
} elsif ($option eq "-C"){
$Commentfile = $args[++$i];
if (! -r $Commentfile || -z $Commentfile) {
print STDERR "Invalid file specified for -C ($Commentfile).\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
} elsif ($option eq "-N"){
$Defsubnetmask = $args[++$i];
if ( $Defsubnetmask !~ /^[.\d]*$/
|| split('\.', $Defsubnetmask) != 4) {
print STDERR "Improper subnet mask ($Defsubnetmask).\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
if ($#Networks >= 0) {
print STDERR "Hmm, -N option should probably be specified before any -n options.\n";
}
} elsif ($option eq "-n"){
($net, $subnetmask) = split(':',$args[++$i]);
if ($subnetmask eq "") {
foreach $tmp1 (&SUBNETS($net, $Defsubnetmask)) {
&BUILDNET($tmp1);
}
} else {
if ( $subnetmask !~ /^[.\d]*$/
|| split('\.', $subnetmask) != 4) {
print STDERR "Improper subnet mask ($subnetmask).\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
foreach $tmp1 (&SUBNETS($net, $subnetmask)) {
&BUILDNET($tmp1);
}
}
} elsif ($option eq "-1"){
print STDERR "Option -1 is obsolete ... ignored.\n";
} elsif ($option eq "-F"){
print STDERR "Option -F is now the default (and only) way ... ignored.\n";
} else {
if($option =~ /^-.*/){
print STDERR "Unknown option: $option ... ignored.\n";
}
}
$i++;
}
if (!defined(@Networks) || $Domain eq "") {
print STDERR "Must specify at least -d and one -n.\n";
print STDERR "I give up ... sorry.\n";
exit(1);
}
}
sub BUILDNET {
local($net) = @_;
push(@Networks, $net);
#
# Create pattern to match against.
# The dots must be changed to \. so they
# aren't used as wildcards.
#
$netpat = $net;
$netpat =~ s/\./\\./g;
push(@Netpatterns, $netpat);
#
# Create db files for PTR records.
# Save the file names in an array for future use.
#
$netfile = "DB.$net";
$Netfiles{$netpat} = $netfile;
push(@makesoa, "db.$net $netfile");
# Add entry to the boot file.
$revaddr = &REVERSE($net);
chop($revaddr); # remove trailing dot
push(@bootmsgs, "primary $revaddr db.$net\n");
}
#
# Calculate all the subnets from a network number and mask.
# This was originally written for awk, not perl.
#
sub SUBNETS {
local($network, $mask) = @_;
local(@ans, @net, @mask, $buf, $number, $i, $j, $howmany);
@net = split(/\./, $network);
@mask = split(/\./, $mask);
$number = '';
#
# Only expand bytes 1, 2, or 3
# for DNS purposes
#
for ($i = 0; $i < 3; $i++) {
if ($mask[$i] == 255) {
$number = $number . $net[$i] . '.';
} elsif (($mask[$i] == 0) || $mask[$i] eq '') {
push(@ans, $network);
last;
} else {
#
# This should be done as a bit-wise or
# but awk does not have an or symbol
#
$howmany = 255 - $mask[$i];
for ($j = 0; $j <= $howmany; $j++) {
if ($net[$i] + $j <= 255) {
$buf = sprintf("%s%d", $number, $net[$i] + $j);
push(@ans, $buf);
}
}
last;
}
}
if ($#ans == -1) {
push(@ans, $network);
}
@ans;
}
sub GEN_BOOT {
local(*F, $revaddr, $n);
if (! -e "boot.cacheonly") {
open(F, ">boot.cacheonly") || die "Unable to open boot.cacheonly: $!";
print F "directory\t$Pwd\n";
print F "primary\t\t0.0.127.IN-ADDR.ARPA db.127.0.0\n";
print F "cache\t\t. db.cache\n";
close(F);
}
if (defined($Bootsecaddr)) {
open(F, ">boot.sec") || die "Unable to open boot.sec: $!";
print F "directory\t$Pwd\n";
print F "primary\t\t0.0.127.IN-ADDR.ARPA db.127.0.0\n";
printf F "secondary\t%-23s $Bootsecaddr\n", $Domain;
foreach $n (@Networks) {
$revaddr = &REVERSE($n);
chop($revaddr);
printf F "secondary\t%-23s $Bootsecaddr\n", $revaddr;
}
print F "cache\t\t. db.cache\n";
close(F);
open(F, ">boot.sec.save") || die "Unable to open boot.sec.save: $!";
print F "directory\t$Pwd\n";
print F "primary\t\t0.0.127.IN-ADDR.ARPA db.127.0.0\n";
printf F "secondary\t%-23s $Bootsecsaveaddr db.%s\n",
$Domain, $Domainfile;
foreach $n (@Networks) {
$revaddr = &REVERSE($n);
chop($revaddr);
printf F "secondary\t%-23s $Bootsecsaveaddr db.%s\n",
$revaddr, $n;
}
print F "cache\t\t. db.cache\n";
close(F);
}
}
[/code:1:50011dc771]
Ok now you've got h2n file, what you need to do next is to write script that calls specific options, There's actually a couplel more files that we need to make in order to get DNS talking properly.
1. make a file called mkdns, this is the file that will pass all the options to the h2n perl script.
[code:1:50011dc771]
#!/bin/sh
#
# Create a named db from the hosts file.
# All relevant hosts needed in DNS should exist in /etc/hosts
#
# The current -n options listed below are all current Visible Genetics
# subnets. The -n options will not need changed unless a new subnet is
# add, such as a 172.xxx.xxx.xxx subnet
#
# Only options below that should be changed are as follows:
# -m if your subnet contains it's own mail host for smtp and pop
# -u for whomever the Systems Administrator is at the locale
# -z should be set to the DNS master server which will typically be this host
#
cd /var/named || { echo "no /var/named"; exit 1; }
mv boot.sec.save boot.sec.save.old
/var/named/h2n \
-H /etc/hosts \
-d screamingelectron.org \
-n 216.248.179.99:255.255.255.254 \
-n 10.26.1:255.255.255.0 \
-n 10.20.20:255.255.255.0 \
-n 10.1:255.255.0.0 \
-t \
-m 30:crosseyedandpainless.screamingelectron.org \
-u elmore@screamingelectron.org \
-o 3600:900:1209600:86400 \
-z 10.26.1.3
# -H /var/named/hosts.tmp \
# add extra info to gen'ed boot file
cat - <<! >> named.boot
;
; The forwarder IP addresses should be the DNS server(s) supplied by the
; ISP you are using for your Internet connection
forwarders 216.27.175.2
slave
!
cat - <<! >> boot.sec.save
;
; See forwarder note above
;
forwarders 142.77.1.1
slave
!
diff -q boot.sec.save.old boot.sec.save || {
echo "Don't forget to edit and copy the /var/named/boot.sec.save file"
echo "over to any secondary DNS servers"
}
/bin/kill -HUP `head -1 /var/named/named.pid` || {
# seems to not be running; start a new one...
/usr/sbin/named -t /var/named -u named
}
cat - <<EOM
Note: secondaries DNS servers may not sync
for up to 1 hour.
EOM
[/code:1:50011dc771]
Things to change:
-d is your home domain name, in my case screamingelectron.org
-n are your internal subnets and external subnets if you have any public boxes.
-m is the mx record you're using for your internal SMTP server.
-u is the admin e-mail address to use for all records.
-z Creates a boot file for you to copy over to secondaries.
IP forwarders are your public upstream DNS servers from your ISP.
2. The next file that needs to made is your spcl.domainname file. This file is particularly important if you have an outside webserver. Without this file you won't be able to connect to your outside boxes.
In my case spcl.screamingelectron
[code:1:50011dc771]
;-----------------------------------------------------------------------
; special records for the domain
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; "hidden" hosts -- outside the firewall in the DMZ
;-----------------------------------------------------------------------
screamingelectron.org. IN A 216.154.201.126
www.screamingelectron.org. IN A 216.154.201.126
;-----------------------------------------------------------------------
; *** special mail routing ***
;
; cf: /etc/sendmail.cf
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; aliases and hacks
; - move services away from old proxies
; - solves old WWW pointer problems
; - old servers must be listed in no-proxies field in client
;-----------------------------------------------------------------------
;-----------------------------------------------------------------------
; forward all outgoing mail to mailhost for routing.
;-----------------------------------------------------------------------
; wildcard MX: this is not only buggy, but superfluous too!
;
;* IN MX 10 mailhost.scredamingelectron.org.
;*.com. IN MX 15 mailhost.screamingelectron.org.
;*.ca. IN MX 15 mailhost.screamingelectron.org.
[/code:1:50011dc771]
3. OK make sure you have all of your outside hosts listed in this file in the same manner I have mine. If you don;t you won;t be able to access them. The next thing is to make sure all your internal hosts are in your /etc/hosts file.
4. The last things to do edit /etc/rc.conf and change the following line.
[code:1:50011dc771]
named_flags=NO # for normal use: ""
to
named_flags="" # for normal use: ""
[/code:1:50011dc771]
5. Now cd to /var/named and execute your mkdns file. chenage your /etc/resolv.conf don't forget to add your search domain, and you're good to go. Do a couple of local nslookups to test.