Solved pf.conf causing slow ssh connections

Code:
root@Jefferson:~/firewall.d # uname -a
FreeBSD Jefferson.libertyroof.biz 10.1-RELEASE FreeBSD 10.1-RELEASE #0 r274401: Tue Nov 11 21:02:49 UTC 2014     root@releng1.nyi.freebsd.org:/usr/obj/usr/src/sys/GENERIC  amd64

Code:
root@Jefferson:~/firewall.d # cat pf.conf
############ Global Options #######################

int_if="fxp0"
ext_if="bge0"
set block-policy return
set loginterface $ext_if
set skip on lo

tcp_svc="22"
icmp_types="echoreq"
localnet="192.168.1.0/24"

table <us.blocks> persist file  "/root/firewall.d/us.blocks"
table <aliens> persist file "/root/firewall.d/aliens.blocks"
table <bruteforce> persist

################ End Global Options ################

########### Traffic Normalization ##################

scrub in on $ext_if all fragment reassemble
scrub out on $ext_if all fragment reassemble

####################################################


####### NAT RULE GOES BEFORE ALL FILTERS ! ! #######

nat on $ext_if from $localnet to any -> ($ext_if)

####################################################


################## Filters #########################

block in all
block drop quick on $ext_if from $localnet to <aliens>
pass out quick on $ext_if from $localnet to any keep state
block in quick on $ext_if from <aliens> to $localnet
block drop in quick on $ext_if from ! <us.blocks> to $localnet
pass in log quick on $ext_if proto tcp from <us.blocks> to { self } port 22 \
        flags S/SA keep state \
        (max-src-conn 5, max-src-conn-rate 3/9, \
        overload <bruteforce> flush global)
pass out quick on $int_if from $localnet to any keep state
pass in quick on $int_if from $localnet to any keep state

####################################################
################### <END OF FILE> ##################
####################################################

The way I had it before the initial 'block in all' was commented out because the pass to port 22 line wasn't working properly. I finally got that to work (shout out to this forum), so I dropped the comment off the first rule and everything was working fine until I tried to ssh from this machine to any of the other machines behind it.

Before I made the change, ssh went through immediately. Now the ssh process hangs for about 6 seconds before finally presenting me with a login prompt.

I'm at a loss. Can anyone else see what the problem is?
 
Looking at the rules they should work although I would write them a bit differently. Your internal interface is an fxp(4) interface. Try playing around with the hardware offload options, TXCSUM, RXCSUM and the like with ifconfig(8), fxp(4) is notorious for having many hardware bugs that require driver workarounds and many of them are still broken after fifteen or so years the driver has been around.
 
Ok, I'll try it tonight when the office clears out.
Let me be clear though. This is only when trying to login. Once the password is passed, it runs like normal.
Does that make any sense?
 
No es bueno.
Code:
ifconfig_fxp0="inet 192.168.1.1 netmask 255.255.255.0 -tso -txcsum -rxcsum"
Same thing.
I'm pining over my pf.conf thinking it's there considering it didn't start until I made the changes mentioned above. But, I really can't see how.
I did locate some other small errors while doing so that I will definitely fix. But this is the expanded ruleset I'm using.

root@Jefferson:/usr/home/tim.falardeau # pfctl -sr
Code:
No ALTQ support in kernel
ALTQ related functions disabled
scrub in on bge0 all fragment reassemble
scrub out on bge0 all fragment reassemble
block return in all
block drop quick from <bruteforce> to any
block drop quick on bge0 inet from 192.168.1.0/24 to <aliens>
pass out quick on bge0 inet from 192.168.1.0/24 to any flags S/SA keep state
block return in quick on bge0 inet from <aliens> to 192.168.1.0/24 <---- Needs to be my external IP
block drop in quick on bge0 inet from ! <us.blocks> to 70.166.151.80
pass in log quick on bge0 inet proto tcp from <us.blocks> to 192.168.1.1 port = ssh flags S/SA keep state (source-track rule, max-src-conn 5, max-src-conn-rate 3/9, overload <bruteforce> flush global, src.track 9)
pass in log quick on bge0 inet proto tcp from <us.blocks> to 70.166.151.80 port = ssh flags S/SA keep state (source-track rule, max-src-conn 5, max-src-conn-rate 3/9, overload <bruteforce> flush global, src.track 9)
pass in log quick on bge0 inet6 proto tcp from <us.blocks> to ::1 port = ssh flags S/SA keep state (source-track rule, max-src-conn 5, max-src-conn-rate 3/9, overload <bruteforce> flush global, src.track 9)
pass in log quick on bge0 inet proto tcp from <us.blocks> to 127.0.0.1 port = ssh flags S/SA keep state (source-track rule, max-src-conn 5, max-src-conn-rate 3/9, overload <bruteforce> flush global, src.track 9)
pass out quick on fxp0 inet from 192.168.1.0/24 to any flags S/SA keep state
pass in quick on fxp0 inet from 192.168.1.0/24 to any flags S/SA keep state

What am I not seeing here?
 
OK, all done with the moderating for the evening. If that fixed the issue, I was going to explain what I believe is happening.

1. You don't have a rule for outbound DNS
Code:
pass out on $ext_if from ($ext_if:0) to any port 53

2. You SSH in and sshd(8) does a DNS lookup for the hostname of what is connecting in.

3. The DNS request goes out but never makes a state match since you don't have a PF rule like in [1].

4. Since there is no state match, the DNS reply hits the block rule.

PF is a stateful firewall so if you either add a rule like in [1] or loosen the restrictions of your current rule (remove the "from $localnet") it should allow for the state match on outbound DNS requests. Alternately you can just turn off SSH doing DNS lookups as previously stated and run your firewall rules very strictly.
 
Going to try that now. But, the machine receiving the ssh request is behind this NAT'd firewall. Shouldn't the line:
Code:
pass out quick on $ext_if from $localnet to any keep state
keep the state of the dns request as it is NAT'd to be sent out?
 
Tell me if I am thinking right now.
Code:
pass out quick on $ext_if from $localnet to any keep state
That line doesn't cover the traffic out from the machines behind it because their IP's are translated on the way out and therefore the state created has their internal address and not the translated one and thus will not match on the way back in?
So I took out from $localnet and now the translated ip, which is now that of the external interface, creates a state on the way out and is allowed back into the firewall when it matches...
 
You can drop keep state from your rules, PF defaults to stateful tracking anyways. You're probably not aware that address rewrites (nat and rdr) are peformed before the traffic hits the packet filter. This means your rule above is never matched if the traffic gets NAT'ed by the nat rule:

Code:
pass out quick on $ext_if from $localnet to any keep state
 
Sorry for not dropping back by sooner as I've been rather busy.

Shouldn't the line:
Code:
pass out quick on $ext_if from $localnet to any keep state
keep the state of the dns request as it is NAT'd to be sent out?
I'm going to answer this backwards. Yes. This would ensure state get created for DNS requests leaving your LAN to the WAN. This would not create states from the router to the WAN. As kpa said above the 'keep state' keywords are superfluous and the default.

Going to try that now. But, the machine receiving the ssh request is behind this NAT'd firewall.
I don't see any rules with rdr keywords to indicate that the machine receiving an ssh request is behind the NAT. Am I missing something?
 
I will. Next time I'm sitting at my PC.
Can't say enough how awesome the FreeBSD community is.
The community is what makes me run FreeBSD as opposed to Linux.
 
Back
Top