hypertorify.sh 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. #!/usr/bin/env bash
  2. ################################################################################
  3. # #
  4. # hypertorify.sh #
  5. # #
  6. # version: alpha #
  7. # #
  8. # Hyperbola v0.4 - Transparent proxy through Tor #
  9. # #
  10. # Copyright (C) 2021 Sagar Acharya #
  11. # #
  12. # #
  13. # GNU GENERAL PUBLIC LICENSE #
  14. # #
  15. # This program is free software: you can redistribute it and/or modify #
  16. # it under the terms of the GNU General Public License as published by #
  17. # the Free Software Foundation, either version 3 of the License. #
  18. # #
  19. # This program is distributed in the hope that it will be useful, #
  20. # but WITHOUT ANY WARRANTY; without even the implied warranty of #
  21. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
  22. # GNU General Public License for more details. #
  23. # #
  24. # You should have received a copy of the GNU General Public License #
  25. # along with this program. If not, see <http://www.gnu.org/licenses/>. #
  26. ################################################################################
  27. ## General
  28. #
  29. # program information
  30. readonly prog_name="hypertorify"
  31. readonly version="alpha"
  32. readonly signature="Copyright (C) 2021 Sagar Acharya"
  33. readonly git_url="https://notabug.org/sagaracharya/hypertorify"
  34. # set colors for stdout
  35. export red="$(tput setaf 1)"
  36. export green="$(tput setaf 2)"
  37. export yellow="$(tput setaf 3)"
  38. export blue="$(tput setaf 4)"
  39. export magenta="$(tput setaf 5)"
  40. export cyan="$(tput setaf 6)"
  41. export white="$(tput setaf 7)"
  42. export b="$(tput bold)"
  43. export reset="$(tput sgr0)"
  44. ## Directories
  45. #
  46. readonly app_dir="/usr/share/hypertorify"
  47. ## Show program banner
  48. banner() {
  49. printf "${b}${cyan}
  50. _ _ __ __ _____ _______ ______ _______ _____ ______ _____ _______ __ __
  51. |_____| \_/ |_____] |______ |_____/ | | | |_____/ | |______ \_/
  52. | | | | |______ | \_ | |_____| | \_ __|__ | |
  53. v${version}
  54. =[ Transparent proxy through Tor
  55. ${reset}\\n\\n"
  56. }
  57. ## Print a message and exit with (1) when an error occurs
  58. die() {
  59. printf "${red}%s${reset}\\n" "[ERROR] ${@}" >&2
  60. exit 1
  61. }
  62. ## Print information
  63. info() {
  64. printf "${b}${cyan}%s${reset} ${b}%s${reset}\\n" "::" "${@}"
  65. }
  66. ## Print `OK` messages
  67. msg() {
  68. printf "${b}${green}%s${reset} %s\\n\\n" "[OK]" "${@}"
  69. }
  70. ## Check if the program run as a root
  71. check_root() {
  72. if [[ "${UID}" -ne 0 ]]; then
  73. die "Please run this program as a root!"
  74. fi
  75. }
  76. ## Display program version
  77. print_version() {
  78. printf "%s\\n" "${prog_name} ${version}"
  79. printf "%s\\n" "${signature}"
  80. printf "%s\\n" "License GPLv3+: GNU GPL version 3 or later <https://gnu.org/licenses/gpl.html>"
  81. printf "%s\\n" "This is free software: you are free to change and redistribute it."
  82. printf "%s\\n" "There is NO WARRANTY, to the extent permitted by law."
  83. exit 0
  84. }
  85. ## Check program settings
  86. #
  87. # - tor package
  88. # - tor configuration file: /etc/tor/torrc
  89. # - directory permissions: /var/lib/tor
  90. check_settings() {
  91. info "Check program settings"
  92. if ! hash tor 2>/dev/null; then
  93. die "tor isn't installed, exit"
  94. fi
  95. if [[ ! -d "${app_dir}/backups" ]]; then
  96. die "directory '${app_dir}/backups' not exist, run makefile first!"
  97. fi
  98. # check /var/lib/tor permissions
  99. #
  100. # required:
  101. # -rwx------ tor tor
  102. # (700)
  103. if [[ "$(stat -c '%U' /var/lib/tor)" != "tor" ]] &&
  104. [[ "$(stat -c '%a' /var/lib/tor)" != "700" ]]; then
  105. printf "%s\\n" "Set permissions of /var/lib/tor directory"
  106. chown -R tor:tor /var/lib/tor
  107. chmod -R 700 /var/lib/tor
  108. fi
  109. if [[ ! -f /etc/init.d/tor-hardened ]]; then
  110. die "Failed to find /etc/init.d/tor-hardened. Please install package tor-hardened-preferences."
  111. fi
  112. # check /etc/tor/torrc
  113. if [[ ! -f /etc/tor/torrc ]]; then
  114. die "/etc/tor/torrc file not exist, check Tor configuration"
  115. fi
  116. }
  117. ## nftables settings
  118. #
  119. # This function is used with args in start() & stop() for set/restore
  120. # nftables.
  121. #
  122. # Args:
  123. # tor_proxy -> set rules for Tor transparent proxy
  124. # default -> restore default nftables
  125. setup_nftables() {
  126. case "$1" in
  127. tor_proxy)
  128. printf "%s\\n" "Set nftables rules"
  129. ## flush current nftables rules
  130. #nft create table inet nat
  131. #nft create table inet filter
  132. #nft create chain inet filter input
  133. #nft add rule inet filter input accept
  134. #nft create chain inet filter forward
  135. #nft add rule inet filter forward accept
  136. #nft create chain inet filter output
  137. #nft add rule inet filter output accept
  138. # copy file /usr/share/hypertorify/data/nftables.rules in the
  139. # /etc/ directory
  140. if ! mv -f /etc/nftables.rules "${app_dir}/backups/nftables.rules.backup" 2>/dev/null; then
  141. die "can't backup file /etc/nftables.rules to hypertorify backup directory"
  142. fi
  143. if ! cp -f "${app_dir}/ruleset.nft" /etc/nftables.rules 2>/dev/null; then
  144. die "can't copy file /etc/nftables.rules"
  145. fi
  146. # set new nftables rules
  147. if nft -f < /etc/nftables.rules 2>/dev/null; then
  148. die "can't set nftables rules"
  149. fi
  150. # start nftables service
  151. if ! rc-service nftables start 2>/dev/null; then
  152. die "openrc error, exit!"
  153. fi
  154. ;;
  155. # restore default
  156. default)
  157. printf "%s\\n" "Restore default nftables"
  158. # flush nftables rules
  159. nft flush ruleset
  160. nft create table inet nat
  161. nft create table inet filter
  162. nft create chain inet filter input
  163. nft add rule inet filter input accept
  164. nft create chain inet filter forward
  165. nft add rule inet filter forward accept
  166. nft create chain inet filter output
  167. nft add rule inet filter output accept
  168. # rewrite default /etc/nftables.rules file
  169. if ! mv -f "${app_dir}/backups/nftables.rules.backup" /etc/nftables.rules 2>/dev/null; then
  170. die "can't restore backup nftables.rules.backup file from hypertorify backup directory"
  171. fi
  172. ;;
  173. esac
  174. }
  175. ## Check public IP address
  176. #
  177. # Make an HTTP request to the URL in the list, if the first request fails, try
  178. # with the next, then print the IP address.
  179. #
  180. # Thanks to "NotMilitaryAI" for this function
  181. check_ip() {
  182. info "Check public IP Address"
  183. local url_list=(
  184. 'https://ipleak.net/json/'
  185. 'https://api.myip.com/'
  186. )
  187. for url in "${url_list[@]}"; do
  188. local request="$(curl -s "$url")"
  189. local response="$?"
  190. if [[ "$response" -ne 0 ]]; then
  191. continue
  192. fi
  193. printf "%s\\n" "${request}"
  194. break
  195. done
  196. }
  197. ## Check status of program and services
  198. #
  199. # - tor-hardened
  200. # - tor settings (check if Tor works correctly)
  201. # - public IP address
  202. check_status() {
  203. info "Check current status of Tor service"
  204. if rc-service tor-hardened status | grep started >/dev/null 2>&1; then
  205. msg "Tor service is active"
  206. else
  207. die "Tor service is not running! exit"
  208. fi
  209. # make HTTP request with curl at: https://check.torproject.org/
  210. # and grep the necessary strings from the html page to test connection
  211. # with tor
  212. info "Check Tor network settings"
  213. # curl option details:
  214. # --socks5 <host[:port]> SOCKS5 proxy on given host + port
  215. # --socks5-hostname <host[:port]> SOCKS5 proxy, pass host name to proxy
  216. #
  217. # `-L` and `tac` for avoid error: "(23) Failed writing body"
  218. # https://github.com/kubernetes/helm/issues/2802
  219. # https://stackoverflow.com/questions/16703647/why-curl-return-and-error-23-failed-writing-body
  220. if curl -s -m 5 --socks5 "localhost:9050" --socks5-hostname "localhost:9050" -L "https://check.torproject.org/" \
  221. | cat | tac | grep -q 'Congratulations'; then
  222. printf "${b}${green}%s${reset} %s\\n\\n" \
  223. "[OK]" "Your system is configured to use Tor"
  224. else
  225. printf "${red}%s${reset}\\n\\n" "[!] Your system is not using Tor"
  226. printf "%s\\n" "try another Tor circuit with '${prog_name} --restart'"
  227. exit 1
  228. fi
  229. check_ip
  230. }
  231. ## Start transparent proxy through Tor
  232. start() {
  233. check_root
  234. # Exit if tor is already active
  235. if rc-service tor status | grep started >/dev/null 2>&1; then
  236. die "Tor service is already active, stop it first"
  237. fi
  238. banner
  239. sleep 2
  240. check_settings
  241. printf "\\n"
  242. info "Starting Transparent Proxy"
  243. # DNS settings: /etc/resolv.conf:
  244. #
  245. # write nameserver 127.0.0.1 to etc/resolv.conf file
  246. # i.e. use Tor DNSPort (see: /etc/tor/torrc)
  247. printf "%s\\n" "Configure DNS to use Tor's DNSPort"
  248. # backup current resolv.conf
  249. if ! cp /etc/resolv.conf "${app_dir}/backups/resolv.conf.backup"; then
  250. die "can't backup /etc/resolv.conf"
  251. fi
  252. # write new nameserver
  253. printf "%s\\n" "nameserver 127.0.0.1" > /etc/resolv.conf
  254. # restart tor-hardened
  255. printf "%s\\n" "Starting tor-hardened"
  256. if ! rc-service tor-hardened status | grep started >/dev/null 2>&1; then
  257. if ! rc-service tor-hardened start 2>/dev/null; then
  258. die "can't start tor-hardened, exit!"
  259. else
  260. echo "started tor-hardened"
  261. fi
  262. fi
  263. # nftables settings
  264. setup_nftables tor_proxy
  265. # check program status
  266. printf "\\n"
  267. check_status
  268. printf "\\n${b}${green}%s${reset} %s\\n" \
  269. "[OK]" "Transparent Proxy activated, your system is under Tor"
  270. }
  271. ## Stop transparent proxy
  272. #
  273. # stop connection with Tor Network and return to clearnet navigation
  274. stop() {
  275. check_root
  276. # don't run function if tor-hardened is NOT running!
  277. if rc-service tor-hardened status | grep started >/dev/null 2>&1; then
  278. info "Stopping Transparent Proxy"
  279. # restore default nftables and stop tor-hardened and nftables services
  280. setup_nftables default
  281. printf "%s\\n" "Stop Tor service"
  282. rc-service tor-hardened stop
  283. rc-service nftables stop
  284. # restore /etc/resolv.conf:
  285. #
  286. # restore file with resolvconf program if exists, otherwise copy the
  287. # original file from backup directory
  288. printf "%s\\n" "Restore default DNS"
  289. if hash resolvconf 2>/dev/null; then
  290. resolvconf -u
  291. else
  292. cp "${app_dir}/backups/resolv.conf.backup" /etc/resolv.conf
  293. fi
  294. # restore default /etc/tor/torrc
  295. printf "%s\\n" "Restore default /etc/tor/torrc"
  296. cp "${app_dir}/backups/torrc.backup" /etc/tor/torrc
  297. printf "\\n${b}${green}%s${reset} %s\\n" \
  298. "[-]" "Transparent Proxy stopped"
  299. exit 0
  300. else
  301. die "Tor-hardened service is not running! exit"
  302. fi
  303. }
  304. ## Restart
  305. #
  306. # restart tor-hardened (i.e. get new Tor exit node)
  307. # and change public IP address
  308. restart() {
  309. check_root
  310. if rc-service tor-hardened status | grep started >/dev/null 2>&1; then
  311. info "Change IP address"
  312. rc-service tor-hardened restart
  313. rc-service nftables restart
  314. sleep 1
  315. msg "IP address changed"
  316. check_ip
  317. exit 0
  318. else
  319. die "Tor service is not running! exit"
  320. fi
  321. }
  322. ## Show help menù
  323. usage() {
  324. printf "%s\\n" "${prog_name} ${version}"
  325. printf "%s\\n" "Hyperbola OS - Transparent proxy through Tor"
  326. printf "%s\\n\\n" "${signature}"
  327. printf "%s\\n\\n" "Usage: ${prog_name} [option]"
  328. printf "%s\\n\\n" "Options:"
  329. printf "%s\\n" "-h, --help show this help message and exit"
  330. printf "%s\\n" "-t, --tor start transparent proxy through tor"
  331. printf "%s\\n" "-c, --clearnet reset nftables and return to clearnet navigation"
  332. printf "%s\\n" "-s, --status check status of program and services"
  333. printf "%s\\n" "-i, --ipinfo show public IP address"
  334. printf "%s\\n" "-r, --restart restart tor service and change IP address"
  335. printf "%s\\n\\n" "-v, --version display program version and exit"
  336. printf "%s\\n" "Project URL: ${git_url}"
  337. printf "%s\\n" "Report bugs: ${git_url}/issues"
  338. exit 0
  339. }
  340. ## Main function
  341. #
  342. # parse command line arguments and start program
  343. main() {
  344. if [[ "$#" -eq 0 ]]; then
  345. printf "%s\\n" "${prog_name}: Argument required"
  346. printf "%s\\n" "Try '${prog_name} --help' for more information."
  347. exit 1
  348. fi
  349. while [[ "$#" -gt 0 ]]; do
  350. case "$1" in
  351. -t | --tor)
  352. start
  353. ;;
  354. -c | --clearnet)
  355. stop
  356. ;;
  357. -r | --restart)
  358. restart
  359. ;;
  360. -s | --status)
  361. check_status
  362. ;;
  363. -i | --ipinfo)
  364. check_ip
  365. ;;
  366. -v | --version)
  367. print_version
  368. ;;
  369. -h | --help)
  370. usage
  371. exit 0
  372. ;;
  373. -- | -* | *)
  374. printf "%s\\n" "${prog_name}: Invalid option '$1'"
  375. printf "%s\\n" "Try '${prog_name} --help' for more information."
  376. exit 1
  377. ;;
  378. esac
  379. exit 0
  380. done
  381. }
  382. # Call main
  383. main "${@}"