2015-01-27 25 views
14

Mam aplikację (serwer) nasłuchującą na porcie 8080. Chcę móc przesłać do niej port 80, tak, aby trafienie http://localhost rozwiązało moją aplikację (na localhost:8080).Jak wykonać transfer lokalnego portu za pomocą iptables

Powinno to zostać uogólnione dla dowolnego odwzorowania portu (na przykład 80:8080 =>P_src:P_target) i użyć sprawdzonych metod dla nowoczesnych maszyn * nix (np. Ubuntu).

N.B. Wszystko to odbywa się lokalnie, więc nie ma potrzeby akceptowania połączeń od kogokolwiek oprócz lokalnego hosta.

+2

Ludzie nie lubią tego pytania ... Jeśli zagłosujesz na dół, wyjaśnij dlaczego. –

+0

Szczerze wygląda dla mnie naprawdę dobrze. Jasne pytanie, prawie pełne wyjaśnienie. – erikbwork

+1

Nie pytanie dotyczące programowania. Prolly powinien zostać przeniesiony do unix lub serverfault. – Bacon

Odpowiedz

14

Po wielu poszukiwaniach znalazłem, że odpowiedź używa iptables, ustawia NAT i używa wbudowanych funkcji PREROUTING i OUTPUT.

Po pierwsze, musi mieć port forwarding enabled:

echo "1" > /proc/sys/net/ipv4/ip_forward

Następnie trzeba dodać następujące zasady do iptables tabeli NAT, z wykorzystaniem własnych wartości ${P_src} i ${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}` 

Jeśli chcesz usunąć reguły, po prostu musisz użyć przełącznika -D zamiast -A dla każdej reguły.

Buduję ładny mały skrypt do tego, który dodaje i usuwa mapowania.

#!/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 "[email protected]" 
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;