Consider the following rules running on my router on 192.168.1.1
(yes, they're unconventional):
iptables -t filter -I INPUT 1 -p tcp --source 192.168.0.0/16 --destination-port "$PORT" --jump ACCEPT
iptables -t nat -I INPUT 1 -p tcp --source 192.168.0.0/16 --destination-port "$PORT" --jump SNAT --to-source 192.168.2.1
iptables -t nat -I PREROUTING 1 -p tcp --source 192.168.0.0/16 --destination-port "$PORT" --jump DNAT --to-destination 192.168.1.1
When $PORT
is not 445
(say, when it's 444
), these rules work fine.
When $PORT
is 445
(SMB), though, these rules do not work.
Note that I do not have Samba (or anything else caring about port 445) running on the router, though you should be able to infer this from the fact that socat
has no listening conflict below.
(And no, I do not have any other iptables
rules regarding port 445
.)
For example, I observe the following on my router
$ socat -d -d tcp-listen:444 - # this is on the router
socat[29117] N listening on AF=2 0.0.0.0:444
socat[29117] N accepting connection from AF=2 192.168.2.1:42339 on AF=2 192.168.1.1:444
socat[29117] N reading from and writing to stdio
socat[29117] N starting data transfer loop with FDs [6,6] and [0,1]
socat[29117] N socket 1 (fd 6) is at EOF
socat[29117] N exiting with status 0
when I run the following on a local machine:
netcat -w 1 -t -n -z "$(dig +short myip.opendns.com @resolver1.opendns.com)" 444 <<<"" && echo Success || echo Failed
However, if I do exactly the same things above with port 445
rather than 444
, socat
stays forever listening on AF=2 0.0.0.0:445
and netcat
prints Failed
after a short pause.
Therefore, I suspect something in the router's kernel is filtering out public traffic to port 445
, probably for security reasons (yes, I'm well aware of the security issues).
However, that is obviously just a guess, and I have no idea how to check/disable what is going on.
How might this be happening and how can I verify this?
Here's some more info that might help. Let's say I enable logging
iptables -v -t nat -I INPUT -d "$MACHINE_IP" -j LOG
iptables -v -t nat -I OUTPUT -d "$MACHINE_IP" -j LOG
iptables -v -t nat -I PREROUTING -d "$MACHINE_IP" -j LOG
iptables -v -t nat -I POSTROUTING -d "$MACHINE_IP" -j LOG
iptables -v -t nat -I INPUT -s "$MACHINE_IP" -j LOG
iptables -v -t nat -I OUTPUT -s "$MACHINE_IP" -j LOG
iptables -v -t nat -I PREROUTING -s "$MACHINE_IP" -j LOG
iptables -v -t nat -I POSTROUTING -s "$MACHINE_IP" -j LOG
where $MACHINE_IP
is just the IP of my local machine. Now if I run
netcat -w 1 -t -n -z "$PUBLIC_IP" 444 <<<"Test" && echo Success || echo Failed
I get back the following (where I've formatted & redacted as appropriate):
kernel: IN=br0 OUT= MAC="$MAC" SRC="$MACHINE_IP" DST="$PUBLIC_IP" LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=51334 DF PROTO=TCP SPT=42366 DPT=444 WINDOW=29200 RES=0x00 SYN URGP=0
kernel: ACCEPT IN=br0 OUT= MAC="$MAC" SRC="$MACHINE_IP" DST=192.168.1.1 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=51334 DF PROTO=TCP SPT=42366 DPT=444 SEQ=496897934 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (<redacted>)
kernel: IN=br0 OUT= MAC="$MAC" SRC="$MACHINE_IP" DST=192.168.1.1 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=51334 DF PROTO=TCP SPT=42366 DPT=444 WINDOW=29200 RES=0x00 SYN URGP=0
kernel: ACCEPT IN=br0 OUT= MAC="$MAC" SRC="$MACHINE_IP" DST=192.168.1.1 LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=51335 DF PROTO=TCP SPT=42366 DPT=444 SEQ=496897934 ACK=0 WINDOW=29200 RES=0x00 SYN URGP=0 OPT (<redacted>)
But, if I run
netcat -w 1 -t -n -z "$PUBLIC_IP" 445 <<<"Test" && echo Success || echo Failed
then I only get back:
kernel: IN=br0 OUT= MAC="$MAC" SRC="$MACHINE_IP" DST="$PUBLIC_IP" LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=40192 DF PROTO=TCP SPT=39617 DPT=445 WINDOW=29200 RES=0x00 SYN URGP=0
kernel: IN=br0 OUT= MAC="$MAC" SRC="$MACHINE_IP" DST="$PUBLIC_IP" LEN=60 TOS=0x00 PREC=0x00 TTL=64 ID=40193 DF PROTO=TCP SPT=39617 DPT=445 WINDOW=29200 RES=0x00 SYN URGP=0
It's weird that $PUBLIC_IP
doesn't get translated at all in the second one. Why would that happen? etc.
iptables [...] -j TRACE
).