Hi all

I have a strange behaviour in pf on 5.9-stable:

A system (asterisk) behind the gateway is receiving and replying to udp
streams (RTP). The connection parameters (src/dst ip/port) are set up
before (STUN and SIP), so both systems "know" where to send to.

The gateway does NAT (rdr-to in, nat-to out) for the system. But while
incoming packets are forwarded with source and destination port
unchanged, the source port on the outgoing packets is changed (to
something in the >50000 range). This breaks the connection, as the
external system (resp. the firewall it is behind) expects the packets to
have the original dst port as src port.

The same happens when the system starts a udp stream on its own - the
source port gets rewritten. Also the UDP checksum appears to be wrong
after the NAT.


Short question:
How do I prevent pf from changing the source port of outgoing natted udp
packets?


Long question:

tcpdump:

$int_if:
18:40:21.392468 $int_server_ip.10442 > $external_system.5012: [udp sum
ok] udp 32 (DF) (ttl 64, id 64912, len 60)
18:40:21.396091 $external_system.5012 > $int_server_ip.10442: [bad udp
cksum a9e7! -> 316d] udp 32 (ttl 115, id 9052, len 60)
18:40:21.413332 $int_server_ip.10442 > $external_system.5012: [udp sum
ok] udp 32 (DF) (ttl 64, id 64916, len 60)
18:40:21.415143 $external_system.5012 > $int_server_ip.10442: [bad udp
cksum a9e7! -> 7036] udp 32 (ttl 115, id 9053, len 60)
...

$ext_if:
18:40:21.392510 $sext_server_ip.51049 > $external_system.5012: [bad udp
cksum 528b! -> e3da] udp 32 (ttl 63, id 16487, len 60)
18:40:21.395975 $external_system.5012 > $sext_server_ip.10442: [udp sum
ok] udp 32 (ttl 116, id 9052, len 60) <--This is a "new" incoming stream

18:40:21.413377 $sext_server_ip.51049 > $external_system.5012: [bad udp
cksum 528b! -> 53d8] udp 32 (ttl 63, id 30449, len 60)
18:40:21.415089 $external_system.5012 > $sext_server_ip.10442: [udp sum
ok] udp 32 (ttl 116, id 9053, len 60)
...

The problem seems to be that the internal system tells the external one
about the source port (10442) it should connect to (via SIP), and as
last step sends a packet from that port (plus in-protocol info, I
assume). But pf changes that source port on that outgoing packet (to
51049), and keeps doing so for all following packets, while the external
system sticks to the protocol and sends its traffic to 10442.

So it looks like pf can't distinguish between what it sees as "follow
up" packets to the first outgoing packet (18:40:21.392468) and the reply
packets to the "incoming" stream.

The connection breaks because the firewall the $external_system is
behind expects replies to the packets send to 10442 to come back from
that port.

All of this wouldn't happen if the source port hadn't been changed to 51049.

So: is there any way of preventing this behaviour? I didn't find
anything in pf.conf(5) or elsewhere ...

Thx for any insight, folks

/markus

PS:
These are the rules in question:

match in from any to $ext_server_ip rdr-to $int_server_ip

match out from $int_server_ip to any nat-to $ext_server_ip

pass  log  quick on { $ext_if, $int_if } inet proto udp  from any  to
$int_server_ip port { 9999 >< 11001 }  label "RTP IN -- ACCEPT "

pass  log  quick on { $ext_if, $int_if } inet proto udp  from
$int_server_ip  to any port { >= 1024 }  label "UDP HIGH OUT -- ACCEPT "

Reply via email to