- 1. 概要
- 2. 考察
- 3. 接続許可
- 4. 受信接続拒否
- 5. 送信接続許可
- 6. プログラム
- 7. 効果
1. 概要
「FreeBSD」のマシンをメールサーバとして使用する際。
「smtp」で接続してくる相手は、変な国からの接続は拒否したいし。
「pop/imap」で接続を許可するのは、ユーザとして接続してくる可能性のあるもののみ許可したい。
2. 考察
そのあたり、メールサーバの設定で、もちろんできるのではありますが。
メールサーバのログに、わらわらと残る可能性があります。
かといって、設定すべきネットワークの量が多すぎて、ルータのファイアウォールに設定するには、面倒くさい。
そこで、「IP Firewall」を使うのはどうかな?と思った次第です。
3. 接続許可
まず、「LAN」、自ドメイン内等の許可すべきアドレスからの接続は、すべて許可します。
下記のような定義ですな。
add 10002 allow tcp from 192.168.0.0/16 to me any
4. 受信接続拒否
前項以外の「ip」は、受信接続を拒否します。
add 20001 deny tcp from any to me pop3,imap
5. 送信接続許可
当初、日本以外の「ip」アドレスを列挙して、送信接続を拒否しようかと思ったのですが、ネットワークの数が多すぎて、設定ファイルに書くには、長すぎるし、「ipfw」自体が重くなりすぎそうです。
なので、日本国内の「ip」アドレスを送信接続許可したのちに、それ以外のアドレスを、送信接続拒否するように定義します。
日本国内の「ip」アドレスは、「無料の IP ジオロケーションデータベース」から、「.csv」ファイルをいただいて、国名の箇所が「JP」になっているものを抜き出します。
add 30001 allow tcp from 1.0.16.0/20 to me smtp
add 30002 allow tcp from 1.0.64.0/18 to me smtp
add 30003 allow tcp from 1.1.64.0/18 to me smtp
・・・ 略 ・・・
add 39054 allow tcp from 223.223.224.0/19 to me smtp
add 39055 allow tcp from 223.252.64.0/19 to me smtp
add 39056 allow tcp from 223.252.112.0/20 to me smtp
add 39057 deny log tcp from any to me smtp
てな感じになります。
6. プログラム
以上のものを、「python」でプログラム化してみました。
下記のソースになります。
import csv
import ipaddress
import os
allow = [ 'JP' ]
deny = [ 'AL', 'AM', 'AT', 'AU', 'AZ', 'BA', 'BD', 'BG', 'BR', 'BS', 'BY', 'CA', 'CN', 'CO', 'CS', 'CZ',
'DE', 'DK', 'DO', 'ES', 'EU', 'FO', 'FR', 'GB', 'GR', 'HK', 'HR', 'HU', 'ID', 'IE', 'IN', 'IQ',
'IR', 'JO', 'KG', 'KH', 'KR', 'KW', 'KZ', 'LA', 'LB', 'MA', 'MD', 'ME', 'MH', 'MN', 'MO', 'MT',
'MU', 'MY', 'NL', 'NP', 'NZ', 'PF', 'PG', 'PH', 'PK', 'PL', 'PR', 'RO', 'RS', 'RU', 'SA', 'SC',
'SE', 'SG', 'SK', 'TH', 'TM', 'TR', 'UA', 'UY', 'VN', 'ZZ' ]
os.chdir(os.path.dirname(__file__))
allowFile = 'allow_ipfw.txt'
denyFile = 'deny_ipfw.txt'
listFile = 'IP2LOCATION-LITE-DB1.CSV'
outputFile = 'ipfw-all.txt'
myList = []
with open(listFile) as file:
reader = csv.reader(file, quotechar='"')
for row in reader:
if row[2] == '-':
continue
start = str(ipaddress.IPv4Address(int(row[0])))
end = str(ipaddress.IPv4Address(int(row[1])))
try:
start_ip = ipaddress.ip_address(start)
end_ip = ipaddress.ip_address(end)
networks = list(ipaddress.summarize_address_range(start_ip, end_ip))
if len(networks) <= 0:
print("The specified IP address range is invalid")
continue
except ValueError as e:
print(f"An invalid IP address was specified - {e}")
continue
for network in networks:
dic = { 'country': row[2], 'start': start, 'end': end, 'range': network }
myList.append(dic)
# ここから出力にはいる
with open(outputFile, 'w') as file:
# LAN ドメインネットワークの接続はすべて許可する
filter_number = 10001
with open(allowFile, 'r') as rfile:
readall = rfile.read()
lines = readall.split('\n')
for line in lines:
file.write('add '+ str(filter_number) +' allow tcp from '+ line +' to me any\n')
filter_number += 1
# ここまでの アドレス以外は pop/imap を拒否という定義を作成
filter_number = 20001
file.write('add '+ str(filter_number) +' deny log tcp from any to me pop3,imap\n')
# smtp で 拒否するアドレスを定義
filter_number = 30001
for one in myList:
if one['country'] in allow:
file.write('add '+ str(filter_number) +' allow tcp from '+ str(one['range']) +' to me smtp\n')
filter_number += 1
file.write('add '+ str(filter_number) +' deny log tcp from any to me smtp\n')
主な個所を説明しておきます。
16行目まで、許可する国の識別コード、拒否したい国の識別コード(これは、現在のところ使用していません)。
「allowFile」で定義しているファイル内に、「LAN」アドレス、ドメインのネットワーク等、ほぼ無条件で許可する「IP」アドレスを定義しています。
「denyFile」は、現在使用していませんが、悪質なアドレスを列挙して、何も接続させないようにしようと考えています。
「listFile」は、国別の「IP」アドレスを定義した、「.csv」ファイルです。
「outputFile」が、最終的に許可・拒否の定義を出力するファイルになります。
20~46行で、国別「IP」アドレスの「.csv」ファイルを「国識別コード」「開始アドレス」「終了アドレス」「203.0.113.0/24 形式のネットワークアドレス」の辞書型へ変換しています。
50~77行で、許可・拒否の定義を出力しています。
55~58行で、許可アドレスを、下記の形式で許可定義しています。
add 10001 allow tcp from 127.0.0.1 to me any
65~67行で、下記の形式で、前項で許可した「IP」アドレス以外からの「pop3」「imap」への接続を拒否しています。
add 20001 deny log tcp from any to me pop3,imap
72~75行で、国識別コード「JP」のアドレスからの「smtp」への接続を許可しています。
add 30001 allow tcp from 1.0.16.0/20 to me smtp
77行で、上のアドレス以外からの「smtp」への接続を拒否しています。
(ここのルール番号は、上記の連番になります)
add 39057 deny log tcp from any to me smtp
7. 効果
さて、この設定の効果なのですが。
実は、抜群。
毎日、恐ろしいほど届いていた、スパムメールが激減しました。
/var/log/security
と見てみると、毎分、「smtp」への接続を試みるものを拒否しているのが出力されています。
ログを出力するのは、やめておこうかと思えるほどです。
あれこれやってみた結果、メールサーバに対しては、これが一番効果がありました。
|