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
로 저장 확인