Using pdnsd on Mac OS X

Posted by Brian on August 16, 2008

One day I discovered that my Internet Service Provider’s Domain Name System (DNS) servers were not working as expected. I did not see the usual “can’t find the server” message when I made a typo in Safari. Instead, a search page appeared offering to help me find what I was looking for.

I realized that this sort of DNS response was undesirable as it presents security and privacy issues, so I immediately installed the pdnsd proxy DNS server and configured it to query the root servers directly. Since then the ISP has removed that unwanted “feature”, but I continued to use pdnsd for peace of mind.

I initially documented how to use this on Mac OS X 10.4 Tiger, but have now updated this blog entry for Mac OS X 10.5 Leopard.

Warning: You should not query the root DNS servers directly unless you have a really good reason for doing so. Reports show that 98% of the queries to the root servers are unnecessary, so please avoid adding to the already excessive load on these servers. Also keep in mind that responses from the root servers are considerably slower than that from your ISP’s DNS servers.

Installing pdnsd

I used version 1.2.6-par of pdnsd, which you can fetch from Paul Rombouts’ website.

http://members.home.nl/p.a.rombouts/pdnsd/

Download and decompress the archive on your desktop, then build and install with these commands in the Terminal (/Applications/Utilities). Please note that you must be logged in with an administrator account and you will be prompted for your account password.

cd Desktop/pdnsd-1.2.6
./configure --sysconfdir=/etc --with-target=BSD --with-random-device=/dev/urandom 
make
sudo make install

Afterwards, you may remove the pdnsd files from your desktop. You may wish to retain the downloaded archive in a safe location for future reference or a possible reinstall.

Configuring pdnsd

There are many ways to configure pdnsd, each of which depends on what your needs are. The example configurations that follow are for users of dial-up ISPs. If you have a different situation, please take a look at the pdnsd documentation for guidance.

http://members.home.nl/p.a.rombouts/pdnsd/doc.html

Enter this command in the Terminal. You may be prompted for your account password.

sudo nano /etc/pdnsd.conf

In the nano editor, paste the text below of the pdnsd configuration that best fits your situation. It would be good to review the pdnsd documentation to see how the configuration may need to be adjusted for your system.

After pasting the text and making any needed adjustments, press Control-O and then Return to save the file. Then exit nano by pressing Control-X.

Option 1: Query ISP’s DNS Servers with “Delegation-only” Zone

The use of a “delegation-only” zone may undo the undesired effects of DNS “wildcards”, such as a search page appearing when you mistype a web address. However, it also may cause problems when trying to access some servers.

global {
perm_cache = 2048;
cache_dir = "/var/cache/pdnsd";
server_ip = 127.0.0.1;
paranoid = on;
min_ttl = 15m;
max_ttl = 1w;
timeout = 10;
status_ctl = on;
run_as = nobody;
delegation_only = "com","net";
}

server {
label = "dialup-with-isp-servers";
uptest = none;
timeout = 5;
purge_cache = off;
preset = off;
proxy_only = on;
policy = included;
exclude = .local;
}

rr {
name=localhost;
reverse=on;
a=127.0.0.1;
owner=localhost;
soa=localhost,root.localhost,42,86400,900,86400,86400;
}

source {
owner=localhost;
file="/etc/hosts";
}

Option 2: Query ISP’s DNS Servers For Almost Everything

Because of security concerns, some may wish to query the root DNS servers for important domains (such as online banks), while querying their ISP’s DNS servers for everything else.

After pasting the text, replace “mybank.com” with the domain you want to have resolved with the root servers. Additional sets of include and exclude statements may be added for additional domains. See the pdnsd documentation for assistance.

global {
perm_cache = 2048;
cache_dir = "/var/cache/pdnsd";
server_ip = 127.0.0.1;
paranoid = on;
min_ttl = 15m;
max_ttl = 1w;
timeout = 10;
status_ctl = on;
run_as = nobody;
}

server {
label = "dialup-with-isp-servers";
uptest = none;
timeout = 5;
purge_cache = off;
preset = off;
proxy_only = on;
policy = included;
exclude = .local;
exclude = ".mybank.com";
}

server {
label = "dialup-with-root-servers";
ip =198.41.0.4
,192.228.79.201
,192.33.4.12
,128.8.10.90
,192.203.230.10
,192.5.5.241
,192.112.36.4
,128.63.2.53
,192.36.148.17
,192.58.128.30
,193.0.14.129
,199.7.83.42
,202.12.27.33
;
uptest = none;
timeout = 5;
purge_cache = off;
preset = off;
root_server = on;
randomize_servers = on;
policy = excluded;
include = ".mybank.com";
}

rr {
name=localhost;
reverse=on;
a=127.0.0.1;
owner=localhost;
soa=localhost,root.localhost,42,86400,900,86400,86400;
}

source {
owner=localhost;
file="/etc/hosts";
}

Only for the extremely paranoid, this configuration completely bypasses your ISP’s DNS servers and only queries the root DNS servers. Please note the warning at the beginning of this blog entry before even considering this option.

global {
perm_cache = 2048;
cache_dir = "/var/cache/pdnsd";
server_ip = 127.0.0.1;
paranoid = on;
min_ttl = 15m;
max_ttl = 1w;
timeout = 10;
query_method = tcp_udp;
status_ctl = on;
run_as = nobody;
}

server {
label = "dialup-with-root-servers";
ip =198.41.0.4
,192.228.79.201
,192.33.4.12
,128.8.10.90
,192.203.230.10
,192.5.5.241
,192.112.36.4
,128.63.2.53
,192.36.148.17
,192.58.128.30
,193.0.14.129
,199.7.83.42
,202.12.27.33
;
uptest = none;
timeout = 5;
purge_cache = off;
preset = off;
root_server = on;
randomize_servers = on;
policy = included;
exclude = .local;
}

rr {
name=localhost;
reverse=on;
a=127.0.0.1;
owner=localhost;
soa=localhost,root.localhost,42,86400,900,86400,86400;
}

source {
owner=localhost;
file="/etc/hosts";
}

Option 4: Query European Open Root Server Network

Instead of querying the usual root DNS servers, this configuration queries the European Open Root Server Network (http://www.orsn.org). This network consists of root servers primarily located in Europe and offers public DNS servers for workstations to query.

global {
perm_cache = 2048;
cache_dir = "/var/cache/pdnsd";
server_ip = 127.0.0.1;
paranoid = on;
min_ttl = 15m;
max_ttl = 1w;
timeout = 10;
query_method = tcp_udp;
status_ctl = on;
run_as = nobody;
}

server {
label = "dialup-with-root-servers";
ip =217.146.139.5,62.157.101.211;
uptest = none;
timeout = 5;
purge_cache = off;
preset = off;
root_server = on;
policy = included;
exclude = .local;
}

rr {
name=localhost;
reverse=on;
a=127.0.0.1;
owner=localhost;
soa=localhost,root.localhost,42,86400,900,86400,86400;
}

source {
owner=localhost;
file="/etc/hosts";
}

Activating pdnsd When Connected

A script is used to notify pdnsd when the dial-up connection has been established and the root DNS servers are thus available.

Enter this command in the Terminal, then paste the text below in the pico editor.

sudo nano /etc/ppp/ip-up
#!/bin/sh

# tell pdnsd that the servers are available

/usr/local/sbin/pdnsd-ctl server dialup-with-isp-servers up $DNS1,$DNS2
/usr/local/sbin/pdnsd-ctl server dialup-with-root-servers up

# tell configd to use pdnsd instead of ISP's DNS servers

ppp_services=`/bin/echo "list State:/Network/Service/[^/]+/PPP" | /usr/sbin/scutil | /usr/bin/awk '{split($4, a, "/"); print a[4];}'`

for service in $ppp_services
do
        ppp_interface=`/bin/echo "show State:/Network/Service/$service/PPP" | /usr/sbin/scutil | /usr/bin/awk '/InterfaceName/ { print $3;}'`
        if [ "$ppp_interface" == "$IFNAME" ]
        then
/usr/sbin/scutil <<EOM
get State:/Network/Service/$service/DNS
d.add ServerAddresses * 127.0.0.1
set State:/Network/Service/$service/DNS
EOM
        fi
done

# message to log file

/usr/bin/syslog -s -l Notice "pdnsd told that DNS servers are UP"

Press Control-O and then Return to save the file. Then exit nano by pressing Control-X.

A second script is needed to notify pdnsd when the dial-up connection has been disconnected.

Enter this command in the Terminal, then paste the text below in the nano editor.

sudo nano /etc/ppp/ip-down
#!/bin/sh

# tell pdnsd that the servers are down

/usr/local/sbin/pdnsd-ctl server dialup-with-isp-servers down ""
/usr/local/sbin/pdnsd-ctl server dialup-with-root-servers down

# message to log file

/usr/bin/syslog -s -l Notice "pdnsd told that DNS servers are DOWN"

Press Control-O and then Return to save the file. Then exit nano by pressing Control-X.

Enable the scripts by entering this command in the Terminal.

sudo chmod +x /etc/ppp/ip-up /etc/ppp/ip-down

Launching pdnsd on System Startup

Mac OS X needs to be configured to launch pdnsd on system startup. The technique presented here is specific to Mac OS X v10.4 or later.

Enter this command in the Terminal, then paste the text below in the nano editor.

sudo nano /Library/LaunchDaemons/pdnsd.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>pdnsd</string>
<key>OnDemand</key>
<false/>
<key>Program</key>
<string>/usr/local/sbin/pdnsd</string>
<key>ServiceDescription</key>
<string>pdnsd - a proxy DNS server with permanent caching</string>
</dict>
</plist>

Press Control-O and then Return to save the file. Then exit nano by pressing Control-X.

To launch pdnsd, either reboot your system or enter this command in the Terminal.

sudo launchctl load /Library/LaunchDaemons/pdnsd.plist

Verifying Operation of pdnsd

To verify that pdnsd is being instead of your ISP’s DNS servers, connect using your dial-up ISP. Then enter the following command in the Terminal. The resullts should indicate that 127.0.0.1 is the responding server.

dig www.macosxhints.com

Disabling pdnsd

If you need to resume use of your ISP’s DNS servers or would otherwise like to disable use of pdnsd, enter the following commands in the Terminal.

sudo launchctl unload -w /Library/LaunchDaemons/pdnsd.plist
sudo rm /etc/ppp/ip-up /etc/ppp/ip-down

Thanks

Thanks to Paul Rombouts for maintaining pdnsd and improving support for Mac OS X.