logo

한국어

iptables firewall script

관리자 2018.04.24 00:59 조회 수 : 16

다운로드: firewall_hasu0707.sh

#!/bin/bash

######################################################################
#
# iptables firewall script
#
# Date:   2018.04.26
# Author: 이존석 (hasu0707@gmail.com)
#
# systemd 서비스 등록: firewall_hasu0707.sh regi
#
######################################################################
PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
SCRIPT_NAME=firewall_hasu0707
IPTABLES=iptables
IPSET=ipset
ANY=0/0
NAT_RULE=1
IS_DEBUG=0
GEOIP_FILE1=/etc/geoip_kr.zone
OPENVPN_PROTO=udp
OPENVPN_PORT=1194
WAN_IF1=ens33
LAN_IF1=ens38
WAN_NET1=10.10.10.36/32
LAN_NET1=192.168.100.0/24

# ex) 192.168.0.100,10.10.10.45,172.16.9.54 (공백없이 붙여서)
#DEFAULT_WHITELIST=172.16.21.0/24,192.168.8.0/24,10.10.10.106/32
DEFAULT_WHITELIST=192.168.0.0/24,10.10.10.0/24

######################################################################
#
# systemd 서비스에 등록
#
######################################################################
register_systemd() {
  # systemd 설정파일 작성
  echo "[Unit]" > /lib/systemd/system/${SCRIPT_NAME}.service
  echo "Description=Firewall Script by hasu0707" >> /lib/systemd/system/${SCRIPT_NAME}.service
  echo "DefaultDependencies=no" >> /lib/systemd/system/${SCRIPT_NAME}.service
  echo "Before=network.target" >> /lib/systemd/system/${SCRIPT_NAME}.service
  echo "" >> /lib/systemd/system/${SCRIPT_NAME}.service
  echo "[Service]" >> /lib/systemd/system/${SCRIPT_NAME}.service
  echo "Type=oneshot" >> /lib/systemd/system/${SCRIPT_NAME}.service
  echo "ExecStart=/usr/sbin/${SCRIPT_NAME}.sh start" >> /lib/systemd/system/${SCRIPT_NAME}.service
  echo "ExecStop=/usr/sbin/${SCRIPT_NAME}.sh stop" >> /lib/systemd/system/${SCRIPT_NAME}.service
  echo "RemainAfterExit=yes" >> /lib/systemd/system/${SCRIPT_NAME}.service
  echo "" >> /lib/systemd/system/${SCRIPT_NAME}.service
  echo "[Install]" >> /lib/systemd/system/${SCRIPT_NAME}.service
  echo "WantedBy=multi-user.target" >> /lib/systemd/system/${SCRIPT_NAME}.service

  # 심볼릭 링크 걸어주기
  ln -sf /lib/systemd/system/${SCRIPT_NAME}.service /etc/systemd/system/multi-user.target.wants/${SCRIPT_NAME}.service

  # 데몬 리로드 (효과가 즉시 나타나지 않는다)
  systemctl daemon-reload

  # 스크립트를 /usr/sbin에 복사한다.
  cp -f $0 /usr/sbin/${SCRIPT_NAME}.sh
  chown root:root /usr/sbin/${SCRIPT_NAME}.sh
  chmod 755 /usr/sbin/${SCRIPT_NAME}.sh

  # firewall stop
  systemctl stop ${SCRIPT_NAME}.service
  systemctl disable ${SCRIPT_NAME}.service
  journalctl -u ${SCRIPT_NAME}.service

  # systemd 등록 후 선택 조치사항 출력
  echo "#############################################################"
  echo "systemctl enable ${SCRIPT_NAME}.service"
  echo "systemctl start ${SCRIPT_NAME}.service"
  echo "#############################################################"
}

######################################################################
#
# iptables 초기화
#
######################################################################
clear_iptables() {
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:clear_iptables"
  fi

  ${IPTABLES} -F
  ${IPTABLES} --delete-chain
  ${IPTABLES} -t nat -F
  ${IPTABLES} -t nat --delete-chain

  ${IPTABLES} -P INPUT ACCEPT
  ${IPTABLES} -P OUTPUT ACCEPT
  ${IPTABLES} -P FORWARD DROP
  ${IPTABLES} -t nat -P PREROUTING ACCEPT
  ${IPTABLES} -t nat -P POSTROUTING ACCEPT
  ${IPTABLES} -t nat -P OUTPUT ACCEPT

  ${IPSET} destroy GEOIP_IPSET 2> /dev/null
  ${IPSET} destroy WHITELIST_IPSET 2> /dev/null

  if [ -e /proc/sys/net/ipv4/ip_forward ]; then echo 0 > /proc/sys/net/ipv4/ip_forward; fi
}

######################################################################
#
# /proc 셋팅
#
######################################################################
set_proc() {
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:set_proc"
  fi

  if [ -e /proc/sys/net/ipv4/tcp_syncookies ]; then echo 1 > /proc/sys/net/ipv4/tcp_syncookies; fi
  if [ -e /proc/sys/net/ipv4/conf/all/rp_filter ]; then echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter; fi

  if [ ${NAT_RULE} -eq 1 ]
  then
    if [ -e /proc/sys/net/ipv4/ip_forward ]; then echo 1 > /proc/sys/net/ipv4/ip_forward; fi
  else
    if [ -e /proc/sys/net/ipv4/ip_forward ]; then echo 0 > /proc/sys/net/ipv4/ip_forward; fi
  fi
}

######################################################################
#
# 기본 정책 셋팅
#
######################################################################
set_default_rules() {
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:set_default_rules"
  fi

  ${IPTABLES} -F
  ${IPTABLES} -P INPUT DROP
  ${IPTABLES} -P OUTPUT DROP
  ${IPTABLES} -P FORWARD DROP
}

######################################################################
#
# 위험요소 차단
#
######################################################################
block_threat_rules() {
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:block_threat_rules"
  fi

  # 포트스캔 차단
  #----- NMAP FIN/URG/PSH -----
  ${IPTABLES} -A INPUT -p tcp --tcp-flags ALL FIN,URG,PSH -j DROP
  #----- SYN/RST/ACK/FIN/URG -----
  ${IPTABLES} -A INPUT -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
  #----- ALL/ALL Scan -----
  ${IPTABLES} -A INPUT -p tcp --tcp-flags ALL ALL -j DROP
  #----- NMAP FIN Stealth -----
  ${IPTABLES} -A INPUT -p tcp --tcp-flags ALL FIN -j DROP
  #----- SYN/RST -----
  ${IPTABLES} -A INPUT -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
  #----- SYN/FIN - Scan(probably) -----
  ${IPTABLES} -A INPUT -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
  #----- NMAP Null Scan -----
  ${IPTABLES} -A INPUT -p tcp --tcp-flags ALL NONE -j DROP

  # 잘못된 TCP 패킷 차단
  ${IPTABLES} -A INPUT -p tcp --tcp-option 64 -j DROP
  ${IPTABLES} -A INPUT -p tcp --tcp-option 128 -j DROP
}

######################################################################
#
# ICMP 패킷 정책
#
######################################################################
set_icmp_rules() {
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:set_icmp_rules"
  fi

  ${IPTABLES} -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
  ${IPTABLES} -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
  ${IPTABLES} -A INPUT -p icmp --icmp-type echo-request -i ${WAN_IF1} -j DROP
  ${IPTABLES} -I INPUT -p icmp --icmp-type redirect -j DROP
  ${IPTABLES} -I INPUT -p icmp --icmp-type router-advertisement -j DROP
  ${IPTABLES} -I INPUT -p icmp --icmp-type router-solicitation -j DROP
  ${IPTABLES} -I INPUT -p icmp --icmp-type address-mask-request -j DROP
  ${IPTABLES} -I INPUT -p icmp --icmp-type address-mask-reply -j DROP
}

######################################################################
#
# 화이트 리스트 정책 적용
#
######################################################################
accept_whitelist_rules() {
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:accept_whitelist_rules"
  fi

  ${IPSET} destroy WHITELIST_IPSET 2> /dev/null
  ${IPSET} create WHITELIST_IPSET hash:net

  for ITEM in $(echo ${DEFAULT_WHITELIST} | tr "," "\n"); do
    ${IPSET} -A WHITELIST_IPSET ${ITEM} 2> /dev/null
  done

  ${IPTABLES} -A INPUT -i ${WAN_IF1} -m state --state NEW -m set --match-set WHITELIST_IPSET src -j ACCEPT
}

######################################################################
#
# OpenVPN 정책
#
######################################################################
accept_openvpn_rules() {
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:accept_openvpn_rules"
  fi

  ${IPTABLES} -A INPUT -i tun+ -j ACCEPT
  ${IPTABLES} -A FORWARD -i tun+ -j ACCEPT
  ${IPTABLES} -A FORWARD -i tun+ -o ${WAN_IF1} -m state --state RELATED,ESTABLISHED -j ACCEPT
  ${IPTABLES} -A FORWARD -i ${WAN_IF1} -o tun+ -m state --state RELATED,ESTABLISHED -j ACCEPT
  ${IPTABLES} -A OUTPUT -o tun+ -j ACCEPT
  ${IPTABLES} -A INPUT -i ${WAN_IF1} -m state --state NEW -p ${OPENVPN_PROTO} --dport ${OPENVPN_PORT} -j ACCEPT
}

######################################################################
#
# NAT 정책
#
######################################################################
nat_rules() {
  if [ ${NAT_RULE} -eq 1 ]
  then
    if [ ${IS_DEBUG} -eq 1 ]
    then
      echo "DEBUG:nat_rules"
    fi
    ${IPTABLES} -F -t nat
    ${IPTABLES} -A FORWARD -i ${LAN_IF1} -o ${WAN_IF1} -j ACCEPT
    ${IPTABLES} -t nat -A POSTROUTING -s ${LAN_NET1} -o ${WAN_IF1} -j MASQUERADE
    ${IPTABLES} -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
  fi
}

######################################################################
#
# loopback 정책
#
######################################################################
accept_loopback_if_rules() {
  # allow all packets on the loopback interface
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:accept_loopback_if_rules"
  fi
  ${IPTABLES} -A INPUT -i lo -j ACCEPT
  ${IPTABLES} -A OUTPUT -o lo -j ACCEPT
}

######################################################################
#
# 연결된 패킷 허용
#
######################################################################
accept_est_packet_rules() {
  # allow established and related packets back in
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:accept_est_packet_rules"
  fi
  ${IPTABLES} -A OUTPUT -o ${WAN_IF1} -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT
  ${IPTABLES} -A INPUT -i ${WAN_IF1} -m state --state ESTABLISHED,RELATED -j ACCEPT
}

######################################################################
#
# 대한민국의 IP주소를 GEOIP_IPSET로 등록한다.
#
######################################################################
load_geoip() {
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:load_geoip"
  fi

  ${IPSET} destroy GEOIP_IPSET 2> /dev/null
  ${IPSET} create GEOIP_IPSET hash:net

  if [ ! -f ${GEOIP_FILE1} ]
  then
    wget -Nq http://www.ipdeny.com/ipblocks/data/countries/kr.zone -O ${GEOIP_FILE1}
  fi

  if [ -f ${GEOIP_FILE1} ]
  then
    for IPVAL in $(cat ${GEOIP_FILE1}); do
      ${IPSET} add GEOIP_IPSET ${IPVAL} 2> /dev/null
    done
  fi
}

######################################################################
#
# GeoIP 정책을 처리한다. (대한민국 외 모두 차단)
#
######################################################################
set_geoip_rules() {
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:set_geoip_rules"
  fi

  ${IPTABLES} -A INPUT -i ${WAN_IF1} -m set ! --match-set GEOIP_IPSET src -j DROP
}

######################################################################
#
# 외부에서 내부주소로 들어오는 패킷을 차단한다.
#
######################################################################
block_internet_to_lannet_rules() {
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:block_internet_to_lannet_rules"
  fi

  ${IPTABLES} -I INPUT -i ${WAN_IF1} -s ${LAN_NET1} -j DROP
  ${IPTABLES} -I FORWARD -i ${WAN_IF1} -s ${LAN_NET1} -j DROP
}

######################################################################
#
# 포트포워딩 룰 (LAN)
# (내부 네트워크(192.168.1.x 등)에 대한 포워딩)
# 인수: <출발지 주소> <출발지 포트> <목적지 주소> <목적지 포트> <프로토콜>
#
######################################################################
local_func_port_forward_lan() {
  PF_SRC_NET=$1
  PF_SRC_PORT=$2
  PF_DST_IP=$3
  PF_DST_PORT=$4
  PF_PROTO=$5

  ${IPTABLES} -A FORWARD -i ${WAN_IF1} -s ${PF_SRC_NET} -d ${PF_DST_IP} -p ${PF_PROTO} --dport ${PF_DST_PORT} -j ACCEPT
  ${IPTABLES} -A PREROUTING -t nat -i ${WAN_IF1} -p ${PF_PROTO} --dport ${PF_SRC_PORT} -j DNAT --to ${PF_DST_IP}:${PF_DST_PORT}
}

######################################################################
#
# 포트포워딩 룰 (DMZ)
# (DMZ는 서버 전용 내부네트워크(192.168.1.x가 아닌)에 대한 포워딩)
# 인수: <출발지 주소> <출발지 포트> <목적지 주소> <목적지 포트> <프로토콜>
#
######################################################################
local_func_port_forward_dmz() {
  PF_SRC_NET=$1
  PF_SRC_PORT=$2
  PF_DST_IP=$3
  PF_DST_PORT=$4
  PF_PROTO=$5

  ${IPTABLES} -A FORWARD -i ${WAN_IF1} -s ${PF_SRC_NET} -d ${PF_DST_IP} -p ${PF_PROTO} --dport ${PF_DST_PORT} -j ACCEPT
  ${IPTABLES} -A PREROUTING -t nat -i ${WAN_IF1} -s ${PF_SRC_NET} -p ${PF_PROTO} --dport ${PF_SRC_PORT} -j DNAT --to-destination ${PF_DST_IP}:${PF_DST_PORT}
}

######################################################################
#
# 이 장비에 대한 서비스 포트 오픈
#
# 인수: <출발지 주소> <열어줄 포트> <프로토콜>
#
######################################################################
local_func_accept_wan_service_port() {
  AS_SRC_NET=$1
  AS_SERVICE_PORT=$2
  AS_PROTO=$3

  ${IPTABLES} -A INPUT -i ${WAN_IF1} -s ${AS_SRC_NET} -d ${WAN_NET1} -p ${AS_PROTO} --destination-port ${AS_SERVICE_PORT} -j ACCEPT
}

######################################################################
#
# 포트포워딩 정책
#
######################################################################
port_forward_rules() {
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:port_forward_rules"
  fi

#  local_func_port_forward_lan ${DEFAULT_WHITELIST} 9989 192.168.100.5 22 tcp
#  local_func_port_forward_dmz ${ANY} 3389 172.16.10.50 3389 tcp
}

######################################################################
#
# 서비스 포트 열어주기
#
######################################################################
accept_wan_service_port_rules() {
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:accept_wan_service_port_rules"
  fi

#  local_func_accept_wan_service_port ${ANY} http tcp
#  local_func_accept_wan_service_port ${ANY} smtp tcp
#  local_func_accept_wan_service_port ${ANY} smtp udp
#  local_func_accept_wan_service_port ${ANY} domain tcp
#  local_func_accept_wan_service_port ${ANY} domain udp

   # SSH는 WHITELIST에 대해서만 오픈
  local_func_accept_wan_service_port ${DEFAULT_WHITELIST} ssh tcp
}

######################################################################
#
# 외부에서 들어오는 모든 패킷 차단
#
######################################################################
block_input_all_rules() {
  if [ ${IS_DEBUG} -eq 1 ]
  then
    echo "DEBUG:block_input_all_rules"
  fi

  ${IPTABLES} -A INPUT -i ${WAN_IF1} -p tcp --dport 0:65535 -j DROP
  ${IPTABLES} -A INPUT -i ${WAN_IF1} -p udp --dport 0:65535 -j DROP
}

case "$1" in
    start)
        clear_iptables
        set_default_rules
        set_proc
        accept_loopback_if_rules
        block_threat_rules
        set_icmp_rules
        accept_whitelist_rules
        accept_openvpn_rules
        nat_rules
        accept_est_packet_rules
        load_geoip
        block_internet_to_lannet_rules
        set_geoip_rules
        port_forward_rules
        accept_wan_service_port_rules
        block_input_all_rules
        ;;
    stop)
        clear_iptables
        ${IPSET} -X
        ;;

    force-reload|restart)
        $0 stop
        $0 start
        ;;

    status)
        ${IPTABLES} -t nat -L
        ${IPTABLES} -L
        ${IPSET} -L
        ;;

    regi)
        register_systemd
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|force-reload|status|regi}"
        exit 1
        ;;
esac