How do I drop outgoing packets to specific host/port?

I want to test something locally. For that, I'd like to be able to drop outgoing packets sent to a specific host/port. I tried messing around with pf rules using Murus (the non-free version), but have been unsuccessful.

I am comfortable in the terminal, but am unsure where to make any changes and how to apply them. I am familiar with iptables on linux.

Can I get some direction on how to achieve this?


Solution 1:

To permanently block outgoing traffic to specific domains and/or ports you should create a new anchor file and add it to pf.conf.

  1. Create an anchor file org.user.block.out in /private/etc/pf.anchors

    sudo touch /private/etc/pf.anchors/org.user.block.out
    

    with the following content and a trailing empty line

    mybadtcphosts = "{ www.domain.com, domain.com, 135.0.9.17, 10.0.0.17 }"
    mybadtcpports = "{ 443, 80 }"
    mybadudphosts = "{ www.domain3.com, domain3.com, 27.134.89.124, 192.168.5.37 }"
    mybadudpports = "{ 53, 5353 }"
    
    block drop out proto tcp from any to $mybadtcphosts port $mybadtcpports
    block drop out proto udp from any to $mybadudphosts port $mybadudpports
    

    The additional domain names/IP addresses in mybad*hosts are just an example how to add additional domains. The same goes for the ports 80/5353 in mybad*ports.

    A simple but less flexible solution is:

    block drop out proto tcp from any to domain.com port 80
    
  2. Modify the file /private/etc/pf.conf but keep a trailing empty line

    original file:

    scrub-anchor "com.apple/*"
    nat-anchor "com.apple/*"
    rdr-anchor "com.apple/*"
    dummynet-anchor "com.apple/*"
    anchor "com.apple/*"
    load anchor "com.apple" from "/etc/pf.anchors/com.apple"
    

    to

    scrub-anchor "com.apple/*"
    nat-anchor "com.apple/*"
    rdr-anchor "com.apple/*"
    dummynet-anchor "com.apple/*"
    anchor "com.apple/*"
    anchor "org.user.block.out"
    load anchor "com.apple" from "/etc/pf.anchors/com.apple"
    load anchor "org.user.block.out" from "/etc/pf.anchors/org.user.block.out"
    
  3. Parse and test your anchor file to make sure there are no errors:

    sudo pfctl -vnf /etc/pf.anchors/org.user.block.out
    
  4. Now modify /System/Library/LaunchDaemons/com.apple.pfctl.plist from

    <array>
        <string>pfctl</string>
        <string>-f</string>
        <string>/etc/pf.conf</string>
    </array>
    

    to

    <array>
        <string>pfctl</string>
        <string>-e</string>
        <string>-f</string>
        <string>/etc/pf.conf</string>
    </array>
    

    You have to disable System Integrity Protection if El Capitan is installed to accomplish this. After editing the file reenable SIP. After rebooting your Mac pf will be enabled (that's the -e option).

    Alternatively you may create your own launch daemon similar to the answer here: Using Server 5.0.15 to share internet WITHOUT internet sharing.

After a system update or upgrade some of the original files above may have been replaced and you have to reapply all changes.


Murus:

Open Murus. Click the gear in the configuration panel to create a custom rule:

Murus Config

Enter all necessary details:

custom rule

Hit the blue button     Add Custom PF rule     and start PF in the upper right corner with the rightwards arrowhead (or "play" button).

Solution 2:

You could use the PF firewall:

Add this line to /etc/pf.conf to drop all packets to the given ip:port

block drop out quick proto tcp  to 192.168.1.103 port 80

After changing pf.conf you should reload it with

sudo pfctl -f /etc/pf.conf

Eventually you will have to enable it with

sudo pfctl -e