How to do local port forwarding with iptables - iptables

I have an application (server) listening on port 8080. I want to be able to forward port 80 to it, such that hitting http://localhost resolves my application (on localhost:8080).
This should be generalized for any port mapping (e.g. 80:8080 => P_src:P_target), and use best practices for modern *nix machines (e.g. Ubuntu).
N.B. This is all done locally, so there is no need to accept connections from anyone but localhost.

So after much searching around, I found the answer uses iptables, setting up a NAT, and using the built-ins PREROUTING and OUTPUT.
First, you must have port forwarding enabled:
echo "1" > /proc/sys/net/ipv4/ip_forward
Then you have to add the following rules to your iptables NAT table, using your own values for ${P_src} and ${P_target}:
iptables -t nat -A PREROUTING -s 127.0.0.1 -p tcp --dport ${P_src} -j REDIRECT --to ${P_target}`
iptables -t nat -A OUTPUT -s 127.0.0.1 -p tcp --dport ${P_src} -j REDIRECT --to ${P_target}`
If you want to remove the rules, you simply need to use the -D switch instead of -A for each rule.
I build a nice little script for this that does adding and removing of mappings.
#!/bin/bash
#
# API: ./forwardPorts.sh add|rm p1:p1' p2:p2' ...
#
# Results in the appending (-A) or deleting (-D) of iptable rule pairs that
# would otherwise facilitate port forwarding.
#
# E.g
# sudo iptables -t nat -A PREROUTING -s 127.0.0.1 -p tcp --dport 80 -j REDIRECT --to 8080
# sudo iptables -t nat -A OUTPUT -s 127.0.0.1 -p tcp --dport 80 -j REDIRECT --to 8080
#
if [[ $# -lt 2 ]]; then
echo "forwardPorts takes a state (i.e. add or rm) and any number port mappings (e.g. 80:8080)";
exit 1;
fi
case $1 in
add )
append_or_delete=A;;
rm )
append_or_delete=D;;
* )
echo "forwardPorts requires a state (i.e. add or rm) as it's first argument";
exit 1; ;;
esac
shift 1;
# Do a quick check to make sure all mappings are integers
# Many thanks to S.O. for clever string splitting:
# http://stackoverflow.com/questions/918886/how-do-i-split-a-string-on-a-delimiter-in-bash
for map in "$#"
do
IFS=: read -a from_to_array <<< "$map"
if [[ ! ${from_to_array[0]} =~ ^-?[0-9]+$ ]] || [[ ! ${from_to_array[1]} =~ ^-?[0-9]+$ ]]; then
echo "forwardPorts port maps must go from an integer, to an integer (e.g. 443:4443)";
exit 1;
fi
mappings[${#mappings[#]}]=${map}
done
# We're shooting for transactional consistency. Only manipulate iptables if all
# the rules have a chance to succeed.
for map in "${mappings[#]}"
do
IFS=: read -a from_to_array <<< "$map"
from=${from_to_array[0]}
to=${from_to_array[1]}
sudo iptables -t nat -$append_or_delete PREROUTING -s 127.0.0.1 -p tcp --dport $from -j REDIRECT --to $to
sudo iptables -t nat -$append_or_delete OUTPUT -s 127.0.0.1 -p tcp --dport $from -j REDIRECT --to $to
done
exit 0;

Related

Proxmox-VE 6 / PFSense, Problems with the iptables

I have been trying for some time to configure my Proxmox with a PFSense VM filtering internet traffic to my other VMs.
So far I have managed to install PFSense and configure the Proxmox interfaces. I have also managed to go to the PFSense web interface. However, my VMs do not always have access to the internet, so I try to modify my iptables to manage to redirect all the traffic on PFSense.
Here are my interfaces:
interfaces
On the shell I did this operation :
cat > /root/pfsense-route.sh << EOF
#!/bin/sh
## IP forwarding activation echo 1 > /proc/sys/net/ipv4/ip_forward
## Rediriger les paquets destinés au LAN pour l'interface WAN de la PFSense ip route change 192.168.9.0/24 via 10.0.0.2 dev vmbr1 EOF
And I modified the file /etc/hosts :
[...]
auto vmbr2
iface vmbr2 inet static
address 192.168.9.1/24
bridge-ports none
bridge-stp off
bridge-fd 0
post-up /root/pfsense-route.sh
#LAN
And now the heart of the problem, the iptables. Here is my current file :
#!/bin/sh
# ---------
# VARIABLES
# ---------
## Proxmox bridge holding Public IP
PrxPubVBR="vmbr0"
## Proxmox bridge on VmWanNET (PFSense WAN side)
PrxVmWanVBR="vmbr1"
## Proxmox bridge on PrivNET (PFSense LAN side)
PrxVmPrivVBR="vmbr2"
## Network/Mask of VmWanNET
VmWanNET="10.0.0.0/30"
## Network/Mmask of PrivNET
PrivNET="192.168.9.0/24"
## Network/Mmask of VpnNET
VpnNET="10.2.2.0/24"
## Public IP => Your own public IP address
PublicIP="91.121.134.145"
## Proxmox IP on the same network than PFSense WAN (VmWanNET)
ProxVmWanIP="10.0.0.1"
## Proxmox IP on the same network than VMs
ProxVmPrivIP="192.168.9.1"
## PFSense IP used by the firewall (inside VM)
PfsVmWanIP="10.0.0.2"
# ---------------------
# CLEAN ALL & DROP IPV6
# ---------------------
### Delete all existing rules.
iptables -F
iptables -t nat -F
iptables -t mangle -F
iptables -X
### This policy does not handle IPv6 traffic except to drop it.
ip6tables -P INPUT DROP
ip6tables -P OUTPUT DROP
ip6tables -P FORWARD DROP
# --------------
# DEFAULT POLICY
# --------------
### Block ALL !
iptables -P OUTPUT DROP
iptables -P INPUT DROP
iptables -P FORWARD DROP
# ------
# CHAINS
# ------
### Creating chains
iptables -N TCP
iptables -N UDP
# UDP = ACCEPT / SEND TO THIS CHAIN
iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP
# TCP = ACCEPT / SEND TO THIS CHAIN
iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP
# ------------
# GLOBAL RULES
# ------------
# Allow localhost
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# Don't break the current/active connections
iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# Allow Ping - Comment this to return timeout to ping request
iptables -A INPUT -p icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
# --------------------
# RULES FOR PrxPubVBR
# --------------------
### INPUT RULES
# ---------------
# Allow SSH server
iptables -A TCP -i \$PrxPubVBR -d \$PublicIP -p tcp --dport 22 -j ACCEPT
# Allow Proxmox WebUI
iptables -A TCP -i \$PrxPubVBR -d \$PublicIP -p tcp --dport 8006 -j ACCEPT
### OUTPUT RULES
# ---------------
# Allow ping out
iptables -A OUTPUT -p icmp -j ACCEPT
### Proxmox Host as CLIENT
# Allow HTTP/HTTPS
iptables -A OUTPUT -o \$PrxPubVBR -s \$PublicIP -p tcp --dport 80 -j ACCEPT
iptables -A OUTPUT -o \$PrxPubVBR -s \$PublicIP -p tcp --dport 443 -j ACCEPT
# Allow DNS
iptables -A OUTPUT -o \$PrxPubVBR -s \$PublicIP -p udp --dport 53 -j ACCEPT
### Proxmox Host as SERVER
# Allow SSH
iptables -A OUTPUT -o \$PrxPubVBR -s \$PublicIP -p tcp --sport 22 -j ACCEPT
# Allow PROXMOX WebUI
iptables -A OUTPUT -o \$PrxPubVBR -s \$PublicIP -p tcp --sport 8006 -j ACCEPT
### FORWARD RULES
# ----------------
### Redirect (NAT) traffic from internet
# All tcp to PFSense WAN except 22, 8006
iptables -A PREROUTING -t nat -i \$PrxPubVBR -p tcp --match multiport ! --dports 22,8006 -j DNAT --to \$PfsVmWanIP
# All udp to PFSense WAN
iptables -A PREROUTING -t nat -i \$PrxPubVBR -p udp -j DNAT --to \$PfsVmWanIP
# Allow request forwarding to PFSense WAN interface
iptables -A FORWARD -i \$PrxPubVBR -d \$PfsVmWanIP -o \$PrxVmWanVBR -p tcp -j ACCEPT
iptables -A FORWARD -i \$PrxPubVBR -d \$PfsVmWanIP -o \$PrxVmWanVBR -p udp -j ACCEPT
# Allow request forwarding from LAN
iptables -A FORWARD -i \$PrxVmWanVBR -s \$VmWanNET -j ACCEPT
### MASQUERADE MANDATORY
# Allow WAN network (PFSense) to use vmbr0 public adress to go out
iptables -t nat -A POSTROUTING -s \$VmWanNET -o \$PrxPubVBR -j MASQUERADE
# --------------------
# RULES FOR PrxVmWanVBR
# --------------------
### Allow being a client for the VMs
iptables -A OUTPUT -o \$PrxVmWanVBR -s \$ProxVmWanIP -p tcp -j ACCEPT
For now with this I still manage to go on my VMs in proxmox, but I’m not internet access on it. Moreover, the shell of my server is no longer accessible on proxmox and SSH connections are no longer accessible.
Some details:
I use port 22 as ssh port
My server ip is 91.121.134.145
My version of linux is Debian 10 (Buster)
Honestly I don’t know where the problem comes from, I’m a beginner and I find the majority of this configuration on the internet. If you see what is wrong I would be very happy to have the answer! In the meantime I thank you in advance for your reading and your answers!
Edit :
I tried to pass the iptables in legacy mode using these commands :
update-alternatives --set iptables /usr/sbin/iptables-legacy
update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy
update-alternatives --set ebtables /usr/sbin/ebtables-legacy
Only this command to refuse to work :
update-alternatives --set arptables /usr/sbin/arptables-legacy
Moreover I don’t know why but my VMs have good access to the internet, the problem is therefore centered on the SSH port that no longer works (I can no longer go on the shell since proxmox)

Squid SSL transparent proxy

It just doesn't work, does it?
Firefox OK after installing the .pem file, but other applications not working.
Converted the .pem file to a .crt using
# openssl x509 -outform der -in myCA.pem -out myCA.crt
and installed it as a Trusted Root Certification Autnorities in certlm but still lots of things not working: Outlook, Teams, GoogleDrive,...
It seems to be very unreliable.
This is the configuration (from https://elatov.github.io/2019/01/using-squid-to-proxy-ssl-sites/) that's got Squid working. I have no idea why -- I just got lucky.
acl step1 at_step SslBump1
ssl_bump peek step1
ssl_bump bump all
ssl_bump splice all
with
the .pem in the browser as an Authority, and
the .crt in Windows as a Trusted Root Certification Authorities.
For the exceptions the best approach is to not send them to Squid in the first place. Using the -d flag with a domain name in the iptables command simply resolves it to an IP address at the time the command therefore it's better to maintain an ipset that iptables can reference.
Here is my script for maintaining my ipset with the domains in a text file.
The idea is that this can be run as a cron job to pick up new domains and update the map to IP addresses.
#!/bin/sh
## Bypass Squid
ipset -L no-proxy >/dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Creating ipset: no-proxy."
ipset create no-proxy hash:ip
fi
ipset flush no-proxy
if [ -f "/etc/squid/no-proxy-iptables.txt" ]; then
for domain in $(cat /etc/squid/no-proxy-iptables.txt); do
for address in $( dig a $domain +short | grep -P -e '^(\d{1,3}\.){3}\d{1,3}$' ); do
echo $domain " -> " $address
ipset add no-proxy $address
done
done
else
echo "File doess not exist: /etc/squid/no-proxy-iptables.txt"
fi
And here is my firewall script:
#!/bin/sh
iptables -t nat -F
iptables -t mangle -F
iptables -F # Does NOT flush everything! Hence the other three commands.
iptables -X
# Squid: exceptions
ipset -L no-proxy >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "Using ipset: no-proxy."
iptables -t nat -A PREROUTING -i br0 -m set --match-set no-proxy dst -j ACCEPT
fi
# Squid: HTTP
iptables -t nat -A PREROUTING -i br0 -p tcp --dport 80 -j DNAT --to 192.168.1.31:3128
iptables -t nat -A PREROUTING -i br0 -p tcp --dport 80 -j REDIRECT --to-port 3128
# Squid: HTTPS
iptables -t nat -A PREROUTING -i br0 -p tcp --dport 443 -j DNAT --to 192.168.1.31:3129
iptables -t nat -A PREROUTING -i br0 -p tcp --dport 443 -j REDIRECT --to-port 3129
# IP masquerade
iptables -A FORWARD -o wlan0 -i br0 -s 192.168.1.0/24 -m conntrack --ctstate NEW -j ACCEPT
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -t nat -F POSTROUTING
iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
iptables -t nat -A POSTROUTING -o enp0s6f1u2 -j MASQUERADE
# echo 1 > /proc/sys/net/ipv4/ip_forward
iptables-save > /etc/iptables/rules.v4
You seem to be able to get a good guess at what domains to bypass by keeping an eye on the network tab in the browser dev tools.

Can iptables be used to prevent internal connection?

I can set iptables rules to prevent external connection. But can we use iptables to prevent internal connection? For example, I have set iptables to prevent port 5555 port on my machine, but my local APP can still connect with 5555 when running on my machine.
Yes you can block it using iptables.
iptables -A INPUT -d 127.0.0.1 -p tcp --dport 5555 -j DROP
With this command you'll not be able to connect from your own host to your own service. Then you can remove the rule using the opposite to -A append which is -D delete:
iptables -D INPUT -d 127.0.0.1 -p tcp --dport 5555 -j DROP
Hope it helps.
Depends upon how you are blocking the port 5555, if you have a specific INPUT rule with interface and source and/or destination addresses it would match only those. In your case, you could modify your rule to just match tcp destination port 5555 and it will block all packets to tcp destination port 5555. for eg:
iptables -t filter -I INPUT -p tcp --dport 5555 -j DROP
If you just want to block your internal apps and not touch your existing iptables rule then use the incoming interface as lo for eg:
iptables -t filter -I INPUT -i lo -p tcp --dport 5555 -j DROP
Note: If you are using destination ip then use the entire loopback address range rather than just 127.0.0.1 for eg:
iptables -t filter -I INPUT -d 127.0.0.0/8 -p tcp --dport 5555 -j DROP
Before you do any changes you can instead of -j DROP action use -j LOG action to log and confirm the tcp connections this rule will match. You could also skip the action part without specifying the -j option and check how many packets would match your rule with iptables -t filter -L -n -v without causing any harm.

Iptables rules - white list ips

My centos server has an iptables rule.
iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 50 -j REJECT --reject-with tcp-reset
this code is doing the work like firewall but I don't want to block of my server ips.
my server ips:
"127.0.0.1", "my server ip1", "my server ip2", etc.
How do I get them out of this ip tables rule?
Thank you very much!
Just use :
# Loopback
iptables -I INPUT -s 127.0.0.1 -i lo -j ACCEPT
# Repeat for each SERVER_IP
iptables -I INPUT -s SERVER_IP -j ACCEPT
Note that this will open everything for SERVER_IPs. YMMV depending on want you want to allow.
For instance, if you just want to open HTTP port for those IPs :
# Loopback
iptables -I INPUT -s 127.0.0.1 -i lo -j ACCEPT
# Repeat for each SERVER_IP
iptables -I INPUT -s SERVER_IP -p tcp --dport 80 -j ACCEPT

Can't Access Plesk Admin Because Of DOS Attack, Block IP Address Through SSH?

I can't access Plesk Amdin because of DOS attack; can I block a hostname or IP address through SSH? If so, how would I be able to do this?
Thank you!
If you have iptables you can block it using simple rule:
iptables -I INPUT --source 1.2.3.4 -j DROP
This rule drops packets coming from IP 1.2.3.4.
Probably the easiest is to SSH to your box use vim to and add the following to the top of your .htaccess file in the root of your domain (/var/www/vhosts/yourdomain.com/httpdocs/.htaccess):
deny from 12.345.67.89
Obviously replace the IP address with the one you want to block. Repeat this for any sites you think are being attacked.
iptables -I INPUT -p tcp -s 1.2.3.4 -m statistic --probability 0.5 -j DROP
iptables -I INPUT n -p tcp -s 1.2.3.4 -m rpfilter --loose -j ACCEPT # n would be an numeric index into the INPUT CHAIN -- default is append to INPUT chain
iptables -I INPUT -p tcp -m hashlimit --hashlimit-mode srcip -s 1.2.3.4 --hashlimit-srcmask --hashlimit-above 9/second -j DROP
iptables -I INPUT -p tcp -s 1.2.3.4 -m limit --sport 80 --limit 100/second -j ACCEPT
There are countless others for your circumstances.
Sincerely,
ArrowInTree