mng_ips 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. #!/bin/bash
  2. #set -x
  3. clear
  4. ###
  5. #
  6. # Author: Stéphane HUC
  7. # mail: devs@stephane-huc.net
  8. #
  9. # License: BSD Simplified
  10. #
  11. # Github: https://git.framasoft.org/hucste/tools
  12. #
  13. # Date: 2016/03/12
  14. #
  15. ###
  16. ###
  17. #
  18. # Purpose: Watch log server web to block bad ip
  19. #
  20. # Edit your crontab:
  21. # 59 23 * * * /folder/manage_ips release
  22. # * * * * * /folder/manage_ips block
  23. #
  24. # or, launch-it, manually! ;-)
  25. #
  26. # -----------------------------------------------
  27. #
  28. # TODO: You need to create a file 'auth_ips' (one ip by line) 4 authorized ip
  29. #
  30. ###
  31. action="DROP" # action /sbin/iptables ; par défaut : DROP
  32. chain="INPUT" # chain /sbin/iptables ; par défaut : INPUT
  33. days=7 # nb de jours à calculer
  34. RACINE="$(dirname "$(readlink -f -- "$0")")"
  35. file="${RACINE}/block_ips"; echo "BlockIP file: ${file}"
  36. hoy="$(date +"%Y-%m-%d")"; echo "Today: ${hoy}"
  37. seconds="$(bc <<< "${days} * 24 * 60 * 60")" # nb de secondes == x jours
  38. declare -a auth_ips
  39. declare -a errors=("301" "303" "308" "310")
  40. errors=("${errors[@]}" "400" "401" "404" "405" "406" "408" "409" "410" "411" "412" "413" "414" "415" "416" "417" "422" "424" "429" "431" "444" "456" "494" "495" "496" "497")
  41. errors=("${errors[@]}" "501" "504" "505" "506" "507" "508" "509" "510")
  42. declare -a ips ips_info
  43. declare -a logs=()
  44. logs[0]="/var/log/nginx/access.log" # en premier, mettre le log serveur : IMPERATIF !!!
  45. #logs[1]=""
  46. function block() {
  47. echo "########## Attempt to blocks Bad IPs ##########"
  48. if [[ ! -f "${file}" ]]; then touch "${file}"; fi
  49. export LC_ALL=C
  50. day_log="$(date +"%d/%b/%Y")"; echo "today: ${day_log}"
  51. build_auth_ips
  52. for log in "${logs[@]}"; do
  53. echo "log: ${log}"
  54. if [[ -f "${log}" ]]; then
  55. log_today="$(grep "${day_log}" "${log}")"
  56. if [[ $? -eq 0 ]]; then
  57. for error in "${errors[@]}"; do
  58. error_file="$TEMP_DIR/block_${error}_ips.$$.$RANDOM"
  59. if awk '/ "${error}" / {print $1}' <<< "${log_today}"; then
  60. grep " ${error} " <<< "${log_today}" | awk -F ' ' '{print $1}' > "${error_file}"
  61. let i=0
  62. while IFS=$'\n' read -r line; do
  63. adr_ip="$(tr -s ' ' <<< "${line}")"
  64. if ! in_array "${adr_ip}" "${auth_ips[@]}"; then
  65. if [[ "${error}" == "301" ]]; then
  66. # cherche le nb de fois où adr_ip est dans file
  67. #nb="$(grep -o "${adr_ip}" "${error_file}" | wc -l)"
  68. # shellcheck disable=SC2094
  69. nb="$(echo "${adr_ip}" | grep -c "${error_file}")"
  70. if [[ $nb -gt 1 ]]; then
  71. if ! in_array "${adr_ip}" "${ips[@]}"; then
  72. ips[i]="${adr_ip}"
  73. ips_info[i]="${adr_ip}|${error}"
  74. fi
  75. fi
  76. else
  77. if ! in_array "${adr_ip}" "${ips[@]}"; then
  78. ips[i]="${adr_ip}"
  79. ips_info[i]="${adr_ip}|${error}"
  80. fi
  81. fi
  82. fi
  83. unset adr_ip
  84. let i=i+1
  85. # shellcheck disable=2094
  86. done < "${error_file}"
  87. rm -f "${error_file}"
  88. fi
  89. unset error_file
  90. done
  91. if [[ ${#ips_info[@]} -ge 1 ]]; then
  92. for info in "${ips_info[@]}"; do
  93. if [[ -n "${info}" ]]; then
  94. ip="$(awk -F '|' '{print $1}' <<< "${info}")"
  95. error="$(awk -F '|' '{print $2}' <<< "${info}")"
  96. echo "ip: ${ip}"
  97. search="$(grep "${ip}" "${file}")"; echo "search: ${search}"
  98. if [[ -n "${search}" ]]; then
  99. date="$(awk -F '|' '{print $2}' <<< "${search}")"
  100. if [[ "${date}" != "${hoy}" ]]; then
  101. manage_iptables "modify" "${ip}" "${date}" "${error}"
  102. else
  103. echo "Same date - no modifying IP informations : ${ip}::'${date}'='${hoy}'"
  104. fi
  105. unset date
  106. else
  107. manage_iptables "add" "${ip}" "${hoy}" "${error}"
  108. fi
  109. unset ip error search
  110. fi
  111. done
  112. fi
  113. unset ips
  114. fi
  115. unset log_today
  116. fi
  117. done
  118. if [[ -n "${ips_info[@]}" ]]; then
  119. sleep 1
  120. echo "########## Attempt to display chain /sbin/iptables ##########"
  121. file_tmp="$TEMP_DIR/iptables_${chain}.$$.$RANDOM"
  122. manage_iptables "file"
  123. echo "$(<"${file_tmp}")"
  124. rm -f "${file_tmp}"
  125. fi
  126. unset day_log ips_info
  127. }
  128. function build_auth_ips() {
  129. i=0
  130. if [ -f "$RACINE/auth_ips" ]; then
  131. if owner "$RACINE/auth_ips"; then
  132. while read line; do
  133. if [ "$(echo "${line}" | grep -v "^#")" ]; then
  134. adr_ip="$(awk -F '|' '{ print $1}' <<< "${line}")"
  135. auth_ips[i]=${adr_ip}
  136. unset adr_ip
  137. let i++
  138. fi
  139. unset line
  140. done < "$RACINE/auth_ips"
  141. fi
  142. fi
  143. }
  144. function detect_link() {
  145. echo "########## Detecting devices informations ##########"
  146. while read -r info; do
  147. echo "iface: ${info}"
  148. link="$(awk -F '/' '{print $5}' <<< "${info}")"
  149. echo "link: ${link}"
  150. if [ -n "${link}" ]; then
  151. if [[ "$(<"${info}"/carrier)" == "1" && "$(<"${info}"/operstate)" == "up" ]]; then
  152. echo -e "\t => Checking ${link} ...\n"
  153. show=$(ip -f inet addr show "${link}" | awk '/inet/ {print $2}')
  154. if [ -n "$show" ]; then
  155. address=${show%/*} ; echo "ip: ${address}"
  156. fi
  157. fi
  158. fi
  159. done <<EOF
  160. $(find /sys/class/net/ | grep -v "^/sys/class/net/$" | grep -v "lo")
  161. EOF
  162. unset i
  163. sleep 1
  164. }
  165. function in_array() {
  166. # equivalent to PHP in_array
  167. # call: in_array needle array
  168. local i=0 needle="$1" IFS=" "; shift; read -a array <<< "$@"
  169. while [ $i -le ${#array[@]} ]; do
  170. if [[ "${array[$i]}" == "${needle}" ]]; then return 0; fi # true
  171. let i=i+1
  172. done
  173. return 1
  174. unset i needle IFS array
  175. }
  176. function manage_iptables() {
  177. local choice="$1" ip="$2" date="$3" error="$4" follow=0
  178. case "${choice}" in
  179. "add")
  180. echo "IP to add: ${ip}"
  181. echo "${ip}|${date}|${error}" >> "${file}"
  182. follow=1
  183. ;;
  184. "delete")
  185. echo "IP to delete: ${ip}; dated: ${date}; error: ${error}"
  186. sed -i -e "s#${ip}|${date}\(|*\)${error}##g" "${file}"
  187. line="$(manage_iptables "view" | grep "${ip}" | cut -d ' ' -f1)"
  188. /sbin/iptables -D ${chain} "${line}"
  189. unset line
  190. ;;
  191. "file")
  192. manage_iptables "view" > "${file_tmp}"
  193. ;;
  194. "modify")
  195. echo "IP to modify: ${ip}"
  196. sed -i -e "s#${ip}|\(.*\)#${ip}|${date}|${error}#g" "${file}"
  197. cmd="$(manage_iptables "view" | grep "${ip}")"
  198. grep "${date}" <<< "${cmd}"
  199. if [[ $? -ne 0 ]]; then
  200. manage_iptables "delete" "${ip}"
  201. follow=1
  202. fi
  203. ;;
  204. "renew")
  205. follow=1
  206. ;;
  207. "view")
  208. /sbin/iptables -L ${chain} -nv --line-numbers
  209. ;;
  210. esac
  211. if [[ "${follow}" -eq 1 ]]; then
  212. if [[ "${chain}" == "INPUT" ]]; then
  213. if [[ "${action}" != "DROP" ]]; then
  214. line="$(manage_iptables "view" | grep "${action}" | cut -d ' ' -f1 | tail -n1)"
  215. line="$(bc <<< "${line} + 1")"
  216. /sbin/iptables -I ${chain} "${line}" -i "${link}" -s "${ip}" -d "${address}" -j ${action} -m comment --comment "${date}: error ${error}"
  217. unset line
  218. else
  219. /sbin/iptables -I ${chain} -i "${link}" -s "${ip}" -d "${address}" -j ${action} -m comment --comment "${date}: error ${error}"
  220. fi
  221. else
  222. /sbin/iptables -A ${chain} -i "${link}" -s "${ip}" -d "${address}" -j ${action} -m comment --comment "${date}: error ${error}"
  223. fi
  224. fi
  225. unset choice ip date error follow
  226. }
  227. function owner() {
  228. local file="$1"
  229. if test -e "${file}"; then
  230. # shellcheck disable=SC2012
  231. if [ "$(stat -c '%U' "${file}")" = "$(ls -l "${file}" | awk '{ print $3 }')" ]; then
  232. return 0
  233. else
  234. return 1
  235. fi
  236. fi
  237. unset file
  238. }
  239. function release() {
  240. echo "########## Attempt to release IPs ##########"
  241. if [[ -f "${file}" ]]; then
  242. readarray -t infos < "${file}"
  243. for info in "${infos[@]}"; do
  244. ip="$(awk -F '|' '{print $1}' <<< "${info}")"
  245. date="$(awk -F '|' '{print $2}' <<< "${info}")"
  246. error="$(awk -F '|' '{print $3}' <<< "${info}")"
  247. if [[ "${date}" != "no" ]]; then
  248. date_seconds="$(date -d "${date}" +%s)"
  249. today="$(date -d "${hoy}" +%s)"
  250. let nb="$(bc <<< "${today} - ${date_seconds}")"
  251. if [[ ${nb} -gt ${seconds} ]]; then
  252. manage_iptables "delete" "${ip}" "${date}" "${error}"
  253. fi
  254. fi
  255. unset date ip
  256. done
  257. # suppression des lignes vides
  258. sed -i '/^$/d' "${file}"
  259. fi
  260. }
  261. function renew_chain() {
  262. echo "########## Attempt to chain ${chain} into iptables ##########"
  263. if [ -n "${chain}" ]; then
  264. /sbin/iptables -F "${chain}"
  265. sleep 1
  266. manage_iptables "view"
  267. sleep 1
  268. fi
  269. build_auth_ips
  270. if [[ -f "${file}" ]]; then
  271. readarray -t infos < "${file}"
  272. for info in "${infos[@]}"; do
  273. ip="$(awk -F '|' '{print $1}' <<< "${info}")"
  274. date="$(awk -F '|' '{print $2}' <<< "${info}")"
  275. error="$(awk -F '|' '{print $3}' <<< "${info}")"
  276. if ! in_array "${ip}" "${auth_ips[@]}"; then
  277. manage_iptables "renew" "${ip}" "${date}" "${error}"
  278. fi
  279. unset date ip
  280. done
  281. fi
  282. manage_iptables "view"
  283. }
  284. function verify_need_variables() {
  285. if [ -z "$action" ]; then
  286. printf "[ \\33[1;31m%s\\33[0;39m ] %s $0\n" "ERROR" "Necessary to set variable action ! Edit the script:"
  287. exit 1;
  288. fi
  289. if [ -z "$chain" ]; then
  290. printf "[ \\33[1;31m%s\\33[0;39m ] %s $0\n" "ERROR" "Necessary to set variable chain ! Edit the script:"
  291. exit 1;
  292. fi
  293. if [ -z "${logs[0]}" ]; then
  294. printf "[ \\33[1;31m%s\\33[0;39m ] %s $0\n" "ERROR" "Necessary to set variable logs[0] ! Edit the script:"
  295. exit 1;
  296. fi
  297. if [ -z "$TEMP" ]; then
  298. TEMP_DIR="/tmp"
  299. else
  300. TEMP_DIR="${TEMP}"
  301. fi
  302. }
  303. verify_uid() {
  304. if [[ $(id -u) -ne 0 ]]; then
  305. printf "[ \\33[1;31m %s \\33[0;39m ] %s \n" "KO" "Need to get rights admins!"
  306. exit 1
  307. fi
  308. }
  309. verify_uid
  310. verify_need_variables
  311. detect_link
  312. case "$1" in
  313. -b|block) block ;;
  314. -r|release) release ;;
  315. -rc) renew_chain ;;
  316. -t|test) detect_link ;;
  317. *)
  318. clear
  319. echo "Usage: ${0##*/} {block|release|test}" >&2
  320. exit 1
  321. ;;
  322. esac