Solved ipfw & transmission-daemon

Hello good folks of FreeBSD

These past ~6 months I've been running FreeBSD 11.2-RELEASE as a router, firewall, mailserver and so on, including services like net-p2p/transmission-daemon, on my private network. The last issue I can't seem to get around, is IPFW blocking some of the traffic from transmission-daemon. I say some, because transmission-daemon do work, though it's pretty slow.

The setup is pretty standard, I think, and looks like this:

/etc/rc.conf
Code:
...
ifconfig_igb0="inet 192.168.40.2 netmask 255.255.255.0"
ifconfig_igb1=""
ifconfig_igb2="inet 192.168.20.1 netmask 255.255.255.0"
ifconfig_igb3=""
defaultrouter="192.168.40.1"


firewall_enable="YES"
firewall_script="/etc/ipfw.rules"
firewall_logging="YES"
gateway_enable="YES"
natd_enable="YES"
natd_interface="igb0"
natd_flags="-dynamic -m"
transmission_enable="YES"
...

/etc/ipfw.rules
Code:
#!/bin/sh
tcp_out="25,53,80,123,443,587,993"
udp_out="53,123"
trs_out="51000"
mail_in="25,587,993"
http_in="80,443"
trs_in="51000"
blocked="111"
wan="igb0"
lan="igb2"
fw_add="/sbin/ipfw -q add"
state="keep-state"
limit="limit src-addr"
skip="skipto 2000"

# Flush out the list before we begin and allow internal traffic and localhost
/sbin/ipfw -q flush
$fw_add 10 allow all from any to any via $lan
$fw_add 15 allow all from any to any via lo0

# Divert incomming packets to natd
$fw_add 100 divert natd ip from any to any in via $wan

# Check the dynamic rules table
$fw_add 105 check-state

# Allow outgoing packets to accepted ports
$fw_add 200 $skip tcp from any to any $tcp_out out via $wan setup $state
$fw_add 205 $skip udp from any to any $udp_out out via $wan $state
$fw_add 210 $skip icmp from any to any out via $wan $state

# Allow outgoing Transmission packets
$fw_add 250 $skip tcp from my to any $trs_out out via $wan setup $state
$fw_add 255 $skip udp from me to any $trs_out out via $wan $state

# Deny and log all other outbound packets
$fw_add 300 deny log all from any to any out via $wan

# Deny packets to known scammer ports without logging
$fw_add 400 deny all from any to any $blocked in via $wan

# Deny noise from web browsers
$fw_add 405 deny all from any 80,443 to any 1024-65535 in via $wan

# Deny public inbound pings
$fw_add 600 deny icmp from any to any in via $wan

# Allow SMTP, IMAP and Submission to the local server - Max 3 connections per IP
$fw_add 700 allow tcp from any to me $mail_in in via $wan setup $limit 3

# Allow HTTP and HTTPS to the local server - Max 12 connections per IP
$fw_add 705 allow tcp from any to me $http_in in via $wan setup $limit 12

# Allow incoming Transmission packets to the local server
$fw_add 710 allow tcp from any to me $trs_in in via $wan $setup
$fw_add 715 allow udp from any to me $trs_in in via $wan

# Reject and log all other incoming connections
$fw_add 1000 deny log all from any to any in via $wan

# Everything else not caught yet is denied and logged
$fw_add 1005 deny log all from any to any

# skipto location to allow outgoing natd traffic
$fw_add 2000 divert natd ip from any to any out via $wan
$fw_add 2005 allow ip from any to any

# Implicit deny is placed here by ipfw
The file is being read by IPFW, since it both shows the rules after a restart, and all other rules works as expected.

/usr/local/etc/transmission/home/settings.json
Code:
...
"bind-address-ipv4": "0.0.0.0",
"bind-address-ipv6": "::",
...
"peer-port": 51000,
"peer-port-random-high": 51500,
"peer-port-random-low": 51001,
"peer-port-random-on-start": false,
...
And sockstat confirms that transmission-daemon do indeed listen on 51000
sockstat | grep transmission
Code:
transmission transmissi29198 9 udp4 *:56289               *:*
transmission transmissi29198 10 udp4 *:39474              *:*
transmission transmissi29198 11 tcp4 192.168.20.1:1342    *:*
transmission transmissi29198 12 tcp4 *:51000              *:*
transmission transmissi29198 13 tcp6 *:51000              *:*
transmission transmissi29198 14 udp4 *:51000              *:*
transmission transmissi29198 15 udp4 192.168.40.2:23784   192.168.40.1:5351
transmission transmissi29198 16 tcp4 192.168.20.1:1342    XXX:60882
transmission transmissi29198 17 dgram-> /var/run/log
transmission transmissi29198 18 tcp4 192.168.40.2:63859   XXX:443
There are no errors shown by transmission-daemon in the logs, just like I can't find any errors by IPFW or any other program or the kernel. However, when looking at the log from IPFW, connections from transmission-daemon is being blocked like so:
Code:
Dec  9 12:25:56 sm kernel: ipfw: 300 Deny UDP 192.168.40.2:51000 XXX:10937 out via igb0
Dec  9 12:25:56 sm kernel: ipfw: 300 Deny UDP 192.168.40.2:51000 XXX:10937 out via igb0
Dec  9 12:25:58 sm kernel: ipfw: 300 Deny UDP 192.168.40.2:51000 XXX:10937 out via igb0
Dec  9 12:26:02 sm kernel: ipfw: 300 Deny UDP 192.168.40.2:51000 XXX:10937 out via igb0
Dec  9 12:26:02 sm kernel: ipfw: 300 Deny UDP 192.168.40.2:51000 XXX:29829 out via igb0
Dec  9 12:26:02 sm kernel: ipfw: 300 Deny UDP 192.168.40.2:51000 XXX:53369 out via igb0
And I don't understand why. A far as I can see, in the configuration and logfiles, those connections should not be blocked. The kernel is built with standard settings and IPFW is loaded as a kernel module at boot time. Please let me know if I missed some info.

Any help and hints would be greatly appreciated, as I'm slowly going nuts.

Thank you for reading this far
 
Code:
# Allow incoming Transmission packets to the local server
$fw_add 710 allow tcp from any to me $trs_in in via $wan $setup
$fw_add 715 allow udp from any to me $trs_in in via $wan

You'll need to skip these packets to after the NAT rule as transmission daemon is listening on a private address.
Code:
# Allow incoming Transmission packets to the local server
$fw_add 710 $skip tcp from any to me $trs_in in via $wan $setup
$fw_add 715 $skip udp from any to me $trs_in in via $wan

Also, might I suggest to use in kernel NAT instead of natd?
You can switch by replacing your natd divert rules with nat rules as outlined below.
Code:
$fw_add 100 divert natd ip from any to any in via $wan
Becomes
$fw_add 100 nat 1 ip4 from any to any in via $wan

$fw_add 2000 divert natd ip from any to any out via $wan
becomes
$fw_add 2000 nat 1 ip4 from any to any out via $wan

Don't forget to setup the nat 1 instance in the beginning of your script as such
Code:
# Configure nat instance 1
$fw_add nat 1 config if $wan same_ports unreg_only reset redirect_port tcp 192.168.40.2:51000 51000

At the end put firewall_nat_enable="YES" in rc.conf; this will load ipfw_nat.ko and libalias.ko at boot.
 
Thank you very much for the reply.

While I did start to adjust my rules to your suggestion, I realized it might be a good time to try PF and see if I would have a easier time configuring that instead. So after a few weeks with the man pages I shifted over and have had it working without issue since then.
 
Also, might I suggest to use in kernel NAT instead of natd?
You can switch by replacing your natd divert rules with nat rules as outlined below.
Code:
$fw_add 100 divert natd ip from any to any in via $wan
Becomes
$fw_add 100 nat 1 ip4 from any to any in via $wan

$fw_add 2000 divert natd ip from any to any out via $wan
becomes
$fw_add 2000 nat 1 ip4 from any to any out via $wan

Don't forget to setup the nat 1 instance in the beginning of your script as such
Code:
# Configure nat instance 1
$fw_add nat 1 config if $wan same_ports unreg_only reset redirect_port tcp 192.168.40.2:51000 51000

At the end put firewall_nat_enable="YES" in rc.conf; this will load ipfw_nat.ko and libalias.ko at boot.

I also use kernel NAT instead of natd. If enabled, then natd should be disabled in rc.conf:

natd_enable="NO"
 
Back
Top