postfix 와 ssh 로 거의 수초간격으로 엉터리 비번으로 계속 접속시도하는데
fail2ban 으로 막는것도 한계가 있고
내 메일서버로 무슨 구멍인지 스팸메일 보내기까지 성공한다.
아래는 모든 IP, 포트를 차단한후 허용된 국내IP, 허용된 포트만 오픈하는 방식이다.
해외 IP는 http, https를 제외한 모든 서비스 다 차단하고나니 auth.log와 mail.log가 조용하다.
진작 할 걸..
1. GeoLite2 Free Downloadable Databases
https://dev.maxmind.com/geoip/geoip2/geolite2/
위 사이트에서 GeoLite2 City csv 포맷 다운로드
mkdir /root/geoip cd /root/geoip wget https://geolite.maxmind.com/download/geoip/database/GeoLite2-City-CSV.zip unzip GeoLite2-City-CSV.zip ln -s GeoLite2-City-CSV_20190611 GeoLite2-City-CSV_current
2. mysql 에 넣기
vi db-setup.sql
USE geoip; DROP TABLE IF EXISTS ip_blocks; CREATE TABLE `ip_blocks` ( `ip_from` int unsigned NOT NULL, `ip_to` int unsigned NOT NULL, `network` varchar(32) NOT NULL, `geoname_id` int unsigned NOT NULL, `registered_country_geoname_id` int unsigned NOT NULL, `represented_country_geoname_id` int unsigned NOT NULL, `is_anonymous_proxy` tinyint(1) NOT NULL, `is_satellite_provider` tinyint(1) NOT NULL, `postal_code` varchar(32) NOT NULL, `latitude` float(8,4) NOT NULL, `longitude` float(8,4) NOT NULL, `accuracy_radius` smallint unsigned NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8; ALTER TABLE `ip_blocks` ADD PRIMARY KEY `ip_to` (`ip_to`); DROP TABLE IF EXISTS ip_locations; CREATE TABLE `ip_locations` ( `geoname_id` int unsigned NOT NULL, `locale_code` varchar(32) NOT NULL, `continent_code` char(2) NOT NULL, `continent_name` varchar(32) NOT NULL, `country_iso_code` char(2) NOT NULL, `country_name` varchar(64) NOT NULL, `subdivision_1_iso_code` varchar(3) NOT NULL, `subdivision_1_name` varchar(128) COLLATE 'utf8_unicode_ci' NOT NULL, `subdivision_2_iso_code` varchar(3) NOT NULL, `subdivision_2_name` varchar(128) COLLATE 'utf8_unicode_ci' NOT NULL, `city_name` varchar(128) COLLATE 'utf8_unicode_ci' NOT NULL, `metro_code` smallint unsigned NOT NULL, `time_zone` varchar(64) NOT NULL, `is_in_european_union` tinyint(1) NOT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8; ALTER TABLE `ip_locations` ADD PRIMARY KEY `geoname_id` (`geoname_id`); LOAD DATA LOCAL INFILE '/root/geoip/GeoLite2-City-CSV_current/GeoLite2-City-Blocks-IPv4.csv' INTO TABLE ip_blocks COLUMNS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' IGNORE 1 LINES ( network, geoname_id, registered_country_geoname_id, represented_country_geoname_id, is_anonymous_proxy, is_satellite_provider, postal_code, latitude, longitude, accuracy_radius) SET ip_from = INET_ATON(SUBSTRING(network, 1, LOCATE('/', network) - 1)), ip_to = (INET_ATON(SUBSTRING(network, 1, LOCATE('/', network) - 1)) + (pow(2, (32-CONVERT(SUBSTRING(network, LOCATE('/', network) + 1), UNSIGNED INTEGER)))-1)); LOAD DATA LOCAL INFILE '/root/geoip/GeoLite2-City-CSV_current/GeoLite2-City-Locations-en.csv' INTO TABLE ip_locations CHARACTER SET UTF8 COLUMNS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' IGNORE 1 LINES ( geoname_id, locale_code, continent_code, continent_name, country_iso_code, country_name, subdivision_1_iso_code, subdivision_1_name, subdivision_2_iso_code, subdivision_2_name, city_name, metro_code, time_zone, is_in_european_union);
mysql에 import하기
mysql -u사용자 -p < db-setup.sql
3. iptables 에 룰 한번에 추가하는 php 쉘스크립트
iptables_setup.php
#!/usr/bin/php <?php iptables_init(); iptables_add_google_spf(); iptables_add_spf("steampowered.com"); iptables_add_spf("certbot.com"); iptables_add_country(); function iptables_init() { shell_exec("iptables -P INPUT ACCEPT"); shell_exec("iptables -F"); shell_exec("iptables -Z"); shell_exec("iptables -A INPUT -i lo -j ACCEPT"); shell_exec("iptables -A INPUT -s 192.168.0.0/24 -j ACCEPT"); shell_exec("iptables -A INPUT -s 192.168.0.0/24 -m state --state NEW -j ACCEPT"); shell_exec("iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT"); shell_exec("iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT"); shell_exec("iptables -P INPUT DROP"); shell_exec("iptables -P FORWARD DROP"); } function iptables_add_spf($domain) { $output = shell_exec("dig $domain txt"); preg_match_all('/ip4:([^ ]+)/', $output, $matches_ips); foreach ($matches_ips[1] as $ip) { shell_exec("iptables -A INPUT -p tcp -s $ip -d 192.168.0.0/24 --dport 25 -j ACCEPT"); } } function iptables_add_google_spf() { $output = shell_exec("dig _spf.google.com txt"); preg_match_all('/include:([^ ]+)/', $output, $matches); foreach ($matches[1] as $spf) { $output = shell_exec("dig $spf txt"); preg_match_all('/ip4:([^ ]+)/', $output, $matches_ips); foreach ($matches_ips[1] as $ip) { shell_exec("iptables -A INPUT -p tcp -s $ip -d 192.168.0.0/24 --dport 25 -j ACCEPT"); } } } function iptables_add_country($country_iso_code = "KR", $jump = "ACCEPT") { $mysqli = new mysqli("localhost", "ddart", "black", "geoip"); if ($mysqli->connect_errno) { echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error; } $query = "select ip_from, ip_to from ip_blocks join ip_locations on ip_blocks.geoname_id = ip_locations.geoname_id" . " where ip_locations.country_iso_code = '" . $country_iso_code . "' order by ip_blocks.ip_to"; $ip_from = 0; $ip_to = 0; $result = $mysqli->query($query); if (!$result) { echo $mysqli->error; } else { while($row = $result->fetch_assoc()) { if ($row['ip_from'] <= $ip_to + 256) { $ip_to = $row['ip_to']; } else { if ($ip_from) { //$cmd = "iptables -A INPUT -m iprange --src-range " . long2ip($ip_from) . "-" . long2ip($ip_to) . " -j " . $jump; $cmd = "iptables -A INPUT -p tcp -m iprange --src-range " . long2ip($ip_from) . "-" . long2ip($ip_to) . " -d 192.168.0.0/24 --dport 25 -j " . $jump; //echo $cmd . "\n"; shell_exec($cmd); } $ip_from = $row['ip_from']; $ip_to = $row['ip_to']; } } } }
* 관리자별 IP주소대역 추가
https://한국인터넷정보센터.한국/jsp/business/management/isCurrentIpv4.jsp
엑셀다운로드 후 엑셀을 열어 '다른이름으로 저장하기'에서 csv 포맷으로 변환후
'/root/geoip/providers/KR_IPv4_(2019.06.21).csv' 에 저장.
vi provider.sql
USE geoip; DROP TABLE IF EXISTS ip_providers; CREATE TABLE `ip_providers` ( `idx` INT UNSIGNED NOT NULL AUTO_INCREMENT , `provider_name` VARCHAR(40) NOT NULL , `provider_english_name` VARCHAR(20) NOT NULL , `ip_from` INT UNSIGNED NOT NULL , `ip_to` INT UNSIGNED NOT NULL , `assigned_date` VARCHAR(8) NOT NULL , PRIMARY KEY (`idx`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; LOAD DATA LOCAL INFILE '/root/geoip/providers/KR_IPv4_(2019.06.21).csv' INTO TABLE ip_providers CHARACTER SET UTF8 COLUMNS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' IGNORE 3 LINES ( provider_name, provider_english_name, @ip_from, @ip_to, @num, assigned_date) SET ip_from = INET_ATON(@ip_from), ip_to = INET_ATON(@ip_to);
관리자별 iptables 추가 함수
function iptables_add_provider($provider = "에스케이브로드밴드주식회사", $jump = "ACCEPT") { $mysqli = new mysqli("localhost", "사용자", "비밀번호", "geoip"); if ($mysqli->connect_errno) { echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error; } $query = "select ip_from, ip_to from ip_providers " . " where provider_name = '" . $provider . "' order by ip_to"; $ip_from = 0; $ip_to = 0; $result = $mysqli->query($query); if (!$result) { echo $mysqli->error; } else { while($row = $result->fetch_assoc()) { if ($row['ip_from'] <= $ip_to + 256) { $ip_to = $row['ip_to']; } else { if ($ip_from) { $cmd = "iptables -A INPUT -m iprange --src-range " . long2ip($ip_from) . "-" . long2ip($ip_to) . " -j " . $jump; //echo $cmd . "\n"; shell_exec($cmd); } $ip_from = $row['ip_from']; $ip_to = $row['ip_to']; } } } }
재부팅후에도 적용되게 저장
apt-get install iptables-persistent netfilter-persistent netfilter-persistent save
vi /etc/iptables/rules.v4
vi /etc/iptables/rules.v6
로 저장 확인