In China, the so-called GFW often contaminates DNS results like

$ dig @ archive.org 

;archive.org.           IN  A

archive.org.        2662    IN  A

Here is a fake IP. We have to use the TCP mode for DNS query:

$ dig @ +tcp archive.org

;archive.org.           IN  A

archive.org.        237 IN  A

Now we get the real IP

In System Preferences -> Network, the Advanced... button can open a tab for setting DNS. However, I can only add the IP addresses of DNS servers but cannot do anything else. So my question is: how can I force the default DNS query working in the TCP mode?

PS: I don't want to modify the /etc/hosts file to circumvent this problem as it's inconvenient. If there's any elegant method that can solve this problem, it will save me much time :) Thanks.


AFAIK it's not possible to force the mDNSResponder to use TCP instead of UDP.

I've found a workaround though. The method outlined below uses a local DNS-proxy (dnschef) forced to use TCP for outgoing DNS-requests.

  • Download and unzip dnschef-0.3.
  • Download and unzip dnslib
  • Download and unarchive IPy-0.76

  • cd to the dnslib folder:

    cd ~/Downloads/paulc-dnslib-04713cc4a9df 
  • install dnslib:

    sudo python ./setup.py install
  • cd to the IPy folder:

    cd ~/Downloads/IPy-0.76 
  • install IPy:

    sudo python ./setup.py install
  • Open System Preferences -> Network, replace your current DNS-server(s) (e.g. by a local one with the IP and apply the changes.

  • cd to the dnschef folder and start it:

    cd ~/Downloads/dnschef-0.3 
    sudo ./dnschef.py --nameservers

If the last command is too troublesome or ugly (well, it is ugly because you have to open Terminal.app and start the DNS-proxy), you can move the dnschef.py and .ini to another path and create a launch daemon to start the DNS-proxy while booting.


  • sudo mkdir /usr/local/python
  • sudo cp ~/Downloads/dnschef-0.3/dns* /usr/local/python/
  • sudo rm /usr/local/python/dnschef.exe
  • sudo touch /Library/LaunchDaemon/local.dnschef.plist
  • copy and paste the following content into the newly created file with an appropriate editor
    (e.g sudo nano /Library/LaunchDaemon/local.dnschef.plist):

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
    <plist version="1.0">
  • Load the file with sudo launchctl load -w /Library/LaunchDaemons/local.dnschef.plist

    All files and folders created must be owned by root:wheel.

| improve this answer | |
  • I haven't tested this, but I'm pretty sure you'll need quotes around (in the interactive start version; the .plist file looks fine as it is). – Gordon Davisson Dec 16 '15 at 21:33
  • @GordonDavisson I've tested it and quotes (i.e "") break the launch daemon. The sudo ./dnschef.py --nameservers command works. – klanomath Dec 16 '15 at 21:35
  • Right. Quotes are needed interactively to keep the shell from interpreting # as a comment marker; launchd doesn't use a shell so quotes are not needed there (and will, as you say, break it because there's no shell to remove them). – Gordon Davisson Dec 16 '15 at 21:37
  • Thank you for the detailed answer. Haven't tried it yet but I completely believe it works :D – Stan Dec 17 '15 at 6:03
  • Updated link for dnschef: github.com/iphelix/dnschef – lawrence Jul 17 at 20:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .