dndx-phantun/docker/phantun.sh
Sing Yu Chan d7913c1407
chore(docker): add Docker image build. Thanks @pexcn for the contributions!
Co-authored-by: Datong Sun <dndx@idndx.com>
2023-02-13 23:29:59 +08:00

210 lines
6.4 KiB
Bash
Executable File
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
# alias settings must be global, and must be defined before the function being called with the alias
if [ "$USE_IPTABLES_NFT_BACKEND" = 1 ]; then
alias iptables=iptables-nft
alias iptables-save=iptables-nft-save
alias ip6tables=ip6tables-nft
alias ip6tables-save=ip6tables-nft-save
fi
info() {
local green='\e[0;32m'
local clear='\e[0m'
local time=$(date '+%Y-%m-%d %T')
printf "${green}[${time}] [INFO]: ${clear}%s\n" "$*"
}
warn() {
local yellow='\e[1;33m'
local clear='\e[0m'
local time=$(date '+%Y-%m-%d %T')
printf "${yellow}[${time}] [WARN]: ${clear}%s\n" "$*" >&2
}
error() {
local red='\e[0;31m'
local clear='\e[0m'
local time=$(date '+%Y-%m-%d %T')
printf "${red}[${time}] [ERROR]: ${clear}%s\n" "$*" >&2
}
_get_default_iface() {
ip -4 route show default | awk -F 'dev' '{print $2}' | awk '{print $1}'
}
_get_default6_iface() {
ip -6 route show default | awk -F 'dev' '{print $2}' | awk '{print $1}'
}
_get_addr_by_iface() {
ip -4 addr show dev "$1" | grep -w "inet" | awk '{print $2}' | awk -F '/' '{print $1}' | head -1
}
_get_addr6_by_iface() {
ip -6 addr show dev "$1" | grep -w "inet6" | awk '{print $2}' | awk -F '/' '{print $1}' | head -1
}
_check_rule_by_comment() {
iptables-save | grep -q "$1"
}
_check_rule6_by_comment() {
ip6tables-save | grep -q "$1"
}
_is_server_mode() {
[ "$1" = "phantun-server" ]
}
_is_ipv4_only() {
case "$@" in
*-4*|*--ipv4-only*)
return 0
;;
*\ -4*|*\ --ipv4-only*)
return 0
;;
esac
return 1
}
_get_tun_from_args() {
local tun=$(echo "$@" | awk -F '--tun' '{print $2}' | awk '{print $1}')
echo ${tun:=tun0}
}
_get_peer_from_args() {
local peer=$(echo "$@" | awk -F '--tun-peer' '{print $2}' | awk '{print $1}')
_is_server_mode "$1" && echo ${peer:=192.168.201.2} || echo ${peer:=192.168.200.2}
}
_get_peer6_from_args() {
local peer=$(echo "$@" | awk -F '--tun-peer6' '{print $2}' | awk '{print $1}')
_is_server_mode "$1" && echo ${peer:=fcc9::2} || echo ${peer:=fcc8::2}
}
_get_port_from_args() {
local value=$(echo "$@" | awk -F '-l|--local' '{print $2}' | awk '{print $1}')
_is_server_mode "$1" && echo $value || echo $value | awk -F ':' '{print $2}'
}
_iptables() {
iptables -w 10 "$@"
}
_ip6tables() {
ip6tables -w 10 "$@"
}
apply_sysctl() {
info "apply sysctl: $(sysctl -w net.ipv4.ip_forward=1)"
! _is_ipv4_only "$@" || return
info "apply sysctl: $(sysctl -w net.ipv6.conf.all.forwarding=1)"
}
apply_iptables() {
local interface=$(_get_default_iface)
local address=$(_get_addr_by_iface "${interface}")
local tun=$(_get_tun_from_args "$@")
local peer=$(_get_peer_from_args "$@")
local port=$(_get_port_from_args "$@")
local comment="phantun_${tun}_${port}"
if _check_rule_by_comment "${comment}"; then
warn "iptables rules already exist, maybe needs to check."
else
_iptables -A FORWARD -i $tun -j ACCEPT -m comment --comment "${comment}" || error "iptables filter rule add failed."
_iptables -A FORWARD -o $tun -j ACCEPT -m comment --comment "${comment}" || error "iptables filter rule add failed."
if _is_server_mode "$1"; then
info "iptables DNAT rule added: [${comment}]: ${interface} -> ${tun}, ${address} -> ${peer}"
_iptables -t nat -A PREROUTING -p tcp -i $interface --dport $port -j DNAT --to-destination $peer \
-m comment --comment "${comment}" || error "iptables DNAT rule add failed."
else
info "iptables SNAT rule added: [${comment}]: ${tun} -> ${interface}, ${peer} -> ${address}"
_iptables -t nat -A POSTROUTING -s $peer -o $interface -j SNAT --to-source $address \
-m comment --comment "${comment}" || error "iptables SNAT rule add failed."
fi
fi
}
apply_ip6tables() {
! _is_ipv4_only "$@" || return
local interface=$(_get_default6_iface)
local address=$(_get_addr6_by_iface "${interface}")
local tun=$(_get_tun_from_args "$@")
local peer=$(_get_peer6_from_args "$@")
local port=$(_get_port_from_args "$@")
local comment="phantun_${tun}_${port}"
if _check_rule6_by_comment "${comment}"; then
warn "ip6tables rules already exist, maybe needs to check."
else
_ip6tables -A FORWARD -i $tun -j ACCEPT -m comment --comment "${comment}" || error "ip6tables filter rule add failed."
_ip6tables -A FORWARD -o $tun -j ACCEPT -m comment --comment "${comment}" || error "ip6tables filter rule add failed."
if _is_server_mode "$1"; then
info "ip6tables DNAT rule added: [${comment}]: ${interface} -> ${tun}, ${address} -> ${peer}"
_ip6tables -t nat -A PREROUTING -p tcp -i $interface --dport $port -j DNAT --to-destination $peer \
-m comment --comment "${comment}" || error "ip6tables DNAT rule add failed."
else
info "ip6tables SNAT rule added: [${comment}]: ${tun} -> ${interface}, ${peer} -> ${address}"
_ip6tables -t nat -A POSTROUTING -s $peer -o $interface -j SNAT --to-source $address \
-m comment --comment "${comment}" || error "ip6tables SNAT rule add failed."
fi
fi
}
stop_process() {
kill $(pidof phantun-server phantun-client)
info "terminate phantun process."
}
revoke_iptables() {
local tun=$(_get_tun_from_args "$@")
local port=$(_get_port_from_args "$@")
local comment="phantun_${tun}_${port}"
iptables-save -t filter | grep "${comment}" | while read rule; do
_iptables -t filter ${rule/-A/-D} || error "iptables filter rule remove failed."
done
iptables-save -t nat | grep "${comment}" | while read rule; do
_iptables -t nat ${rule/-A/-D} || error "iptables nat rule remove failed."
done
info "iptables rule: [${comment}] removed."
}
revoke_ip6tables() {
! _is_ipv4_only "$@" || return
local tun=$(_get_tun_from_args "$@")
local port=$(_get_port_from_args "$@")
local comment="phantun_${tun}_${port}"
ip6tables-save -t filter | grep "${comment}" | while read rule; do
_ip6tables -t filter ${rule/-A/-D} || error "ip6tables filter rule remove failed."
done
ip6tables-save -t nat | grep "${comment}" | while read rule; do
_ip6tables -t nat ${rule/-A/-D} || error "ip6tables nat rule remove failed."
done
info "ip6tables rule: [${comment}] removed."
}
graceful_stop() {
warn "caught SIGTERM or SIGINT signal, graceful stopping..."
stop_process
revoke_iptables "$@"
revoke_ip6tables "$@"
}
start_phantun() {
trap 'graceful_stop "$@"' SIGTERM SIGINT
apply_sysctl "$@"
apply_iptables "$@"
apply_ip6tables "$@"
"$@" &
wait
}
start_phantun "$@"