port-forward.sh 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. #!/bin/bash
  2. # Port forward script
  3. # acetone at mail.i2p
  4. # 2022
  5. # CONSTANTS
  6. INPUT_INTERFACE="changeme"
  7. OUTPUT_INTERFACE="changeme"
  8. SETTINGS_STORAGE="/srv/portforward.txt"
  9. ######################
  10. ######################
  11. # LOGIC
  12. RULES=() # inport,dest_addr,dest_port
  13. usage() {
  14. echo "PORT FORWARD SCRIPT (v0.0.1) USAGE ◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤"
  15. echo "--command--arguments------------------description----------"
  16. echo ""
  17. echo "* add <inport> <address> <port> Add rule to forward"
  18. echo " ﹂example:"
  19. echo " add 80 192.168.1.3 8080"
  20. echo " ^ ^ ^ destination port"
  21. echo " | └ destination address"
  22. echo " └ inport"
  23. echo ""
  24. echo "* del <address> <port> Delete existed rule"
  25. echo " ﹂example:"
  26. echo " del 80 192.168.1.3 8080"
  27. echo " ^ ^ ^ destination port"
  28. echo " | └ destination address"
  29. echo " └ inport"
  30. echo ""
  31. echo "* list Display existed rules"
  32. echo ""
  33. echo "* init Apply rules at start"
  34. echo ""
  35. echo "* install Install at first time"
  36. echo ""
  37. echo "◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤◢◤"
  38. }
  39. message_about_interfaces() {
  40. echo "Please edit first lines of script to define interfaces correctly"
  41. echo "Script path: nano /usr/sbin/port-forward.sh"
  42. }
  43. check_interface() {
  44. if [[ $(ip a | grep $INPUT_INTERFACE) == "" ]]; then
  45. echo "Input interface $INPUT_INTERFACE not exists"
  46. message_about_interfaces
  47. exit
  48. fi
  49. if [[ $(ip a | grep $OUTPUT_INTERFACE) == "" ]]; then
  50. echo "Output interface $OUTPUT_INTERFACE not exists"
  51. message_about_interfaces
  52. exit
  53. fi
  54. }
  55. check_to_root() {
  56. if [ "$EUID" -ne 0 ]; then
  57. echo "Please run as root"
  58. exit 1
  59. fi
  60. }
  61. in_port() {
  62. echo $1 | cut -f1 -d,
  63. }
  64. dest_address() {
  65. echo $1 | cut -f2 -d,
  66. }
  67. dest_port() {
  68. echo $1 | cut -f3 -d,
  69. }
  70. enable_forwarding() {
  71. check_to_root
  72. sed -i 's/\#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/' /etc/sysctl.conf
  73. sysctl net.ipv4.ip_forward=1
  74. sysctl -p
  75. systemctl stop nftables
  76. systemctl disable nftables
  77. apt update
  78. apt install iptables -y
  79. }
  80. add() {
  81. INPORT=$1
  82. DEST_ADDRESS=$2
  83. DEST_PORT=$3
  84. if [[ $(iptables -t nat -L -n | grep "dpt:$INPORT ") != "" ]]; then
  85. echo "Inport $INPORT already in use. Request rejected."
  86. echo "Try command 'list' to see existed rules and 'del' to remove some one."
  87. exit 1
  88. fi
  89. iptables -A PREROUTING -t nat -i $INPUT_INTERFACE -p tcp --dport $INPORT -j DNAT --to $DEST_ADDRESS:$DEST_PORT
  90. if [[ $? != 0 ]]; then
  91. echo "Incorrect input data"
  92. exit 1
  93. fi
  94. iptables -A PREROUTING -t nat -i $INPUT_INTERFACE -p udp --dport $INPORT -j DNAT --to $DEST_ADDRESS:$DEST_PORT
  95. echo "$INPORT,$DEST_ADDRESS,$DEST_PORT" >> $SETTINGS_STORAGE
  96. if [[ $(iptables -t nat -L -v | grep -e "^.*MASQUERADE.*$OUTPUT_INTERFACE.*$") == "" ]]; then
  97. iptables -t nat -A POSTROUTING -o $OUTPUT_INTERFACE -j MASQUERADE
  98. fi
  99. }
  100. del() {
  101. INPORT=$1
  102. DEST_ADDRESS=$2
  103. DEST_PORT=$3
  104. exists=false
  105. for rule in "${RULES[@]}"
  106. do
  107. if [[ $INPORT == $(in_port $rule) ]]; then
  108. if [[ $DEST_ADDRESS == $(dest_address $rule) ]]; then
  109. if [[ $DEST_PORT == $(dest_port $rule) ]]; then
  110. exists=true
  111. break
  112. fi
  113. fi
  114. fi
  115. done
  116. if [[ $exists != true ]]; then
  117. echo "Rule not exists"
  118. exit 1
  119. fi
  120. iptables -D PREROUTING -t nat -i $INPUT_INTERFACE -p tcp --dport $INPORT -j DNAT --to $DEST_ADDRESS:$DEST_PORT
  121. iptables -D PREROUTING -t nat -i $INPUT_INTERFACE -p udp --dport $INPORT -j DNAT --to $DEST_ADDRESS:$DEST_PORT
  122. sed -i "/^${INPORT},${DEST_ADDRESS},${DEST_PORT}$/d" $SETTINGS_STORAGE
  123. }
  124. init() {
  125. if [ -f "$SETTINGS_STORAGE" ]; then
  126. while read -r line; do
  127. if [[ $(in_port $line) == "" ]]; then
  128. continue
  129. fi
  130. if [[ $(dest_address $line) == "" ]]; then
  131. continue
  132. fi
  133. if [[ $(dest_port $line) == "" ]]; then
  134. continue
  135. fi
  136. RULES+=("$line")
  137. done < $SETTINGS_STORAGE
  138. for rule in "${RULES[@]}"
  139. do
  140. if [[ $(iptables -t nat -L -n | grep "dpt:$(in_port $rule) to:$(dest_address $rule):$(dest_port $rule)") == "" ]]; then
  141. echo $(in_port $rule) $(dest_address $rule) $(dest_port $rule) > /dev/null
  142. fi
  143. done
  144. fi
  145. check_interface
  146. }
  147. install() {
  148. if [[ $(crontab -l | grep "@reboot /usr/sbin/port-forward.sh init") != "" ]]; then
  149. if [[ $2 != "forced" ]]; then
  150. echo "Seems like already installed!"
  151. echo "To force the installation run this script as 'install forced'"
  152. exit 1
  153. fi
  154. fi
  155. systemctl enable cron
  156. cp $1 /usr/sbin/port-forward.sh
  157. if [[ $? != 0 ]]; then
  158. echo "Copy script to /usr/sbin/port-forward.sh failed"
  159. exit 1
  160. fi
  161. echo -e "@reboot /usr/sbin/port-forward.sh init" > /tmp/cronrule.tmp
  162. crontab /tmp/cronrule.tmp
  163. rm /tmp/cronrule.tmp
  164. enable_forwarding
  165. rm $1
  166. clear
  167. echo "Installed"
  168. echo "Using via 'port-forward.sh'"
  169. echo "Edit via 'nano /usr/sbin/port-forward.sh'"
  170. }
  171. if [[ $1 == "init" ]]; then
  172. check_to_root
  173. init
  174. exit 0
  175. fi
  176. if [[ $1 == "install" ]]; then
  177. check_to_root
  178. install $0 $2
  179. exit 0
  180. fi
  181. if [[ $1 == "add" ]]; then
  182. if [[ $2 == "" ]]; then
  183. echo "Expected inport after 'add' command"
  184. exit 1
  185. fi
  186. if [[ $3 == "" ]]; then
  187. echo "Expected destination address after 'add <inport>' command"
  188. exit 1
  189. fi
  190. if [[ $4 == "" ]]; then
  191. echo "Expected destination port after 'add <inport> <address>' command"
  192. exit 1
  193. fi
  194. check_to_root
  195. init
  196. add $2 $3 $4
  197. exit 0
  198. fi
  199. if [[ $1 == "del" ]]; then
  200. if [[ $2 == "" ]]; then
  201. echo "Expected inport after 'del' command"
  202. exit 1
  203. fi
  204. if [[ $3 == "" ]]; then
  205. echo "Expected destination address after 'del <inport>' command"
  206. exit 1
  207. fi
  208. if [[ $4 == "" ]]; then
  209. echo "Expected destination port after 'del <inport> <address>' command"
  210. exit 1
  211. fi
  212. check_to_root
  213. init
  214. del $2 $3 $4
  215. exit 0
  216. fi
  217. if [[ $1 == "list" ]]; then
  218. check_to_root
  219. init
  220. echo "Input interface: $INPUT_INTERFACE"
  221. echo "Output interface: $OUTPUT_INTERFACE"
  222. echo ""
  223. for rule in "${RULES[@]}"
  224. do
  225. echo -e "[$(in_port $rule)] -> $(dest_address $rule):$(dest_port $rule)"
  226. echo -e "Remove command: del $(in_port $rule) $(dest_address $rule) $(dest_port $rule)"
  227. echo ""
  228. done
  229. exit 0
  230. fi
  231. usage