【学習メモ】SPFが正しく設定されるかSMTPコマンドを実行して見分ける

## 0.要約
SPFは以下3つの登場人物の組み合わせによるもの。

1. メールの送信者（正規の送信者、Amazon SESなど代理の送信者、スパムメール業者など）
2. ドメインの持ち主（メール送信元とされる）
3. メールの受信者

それぞれが実際にやること。

1. 送信元を主張してメールを送る → HELO, MAIL FROM(Return-Path/エンペローブID)に含まれるドメイン
2. 送信元と騙られないようにSPFレコード（送信元として承認しているホスト）を設定する 
3. 受信者（MTA）が1.と2.の情報を組み合わせてSPFを確認する
 

メールヘッダは情報が多く、そこからSPFの仕組みを理解するのは難しいので、
SMTPコマンドでメールを送る際に利用される情報を整理してから、
メールヘッダを読み解いてSPFを理解していきます。



参考資料
[telnetでメール送信(ash.jp)](http://ash.jp/net/telnet_smtp.htm)
## 1.SMTPコマンドでメールを送る
### SMTPコマンドのおさらい
SMTPコマンドでは、以下の順にデータを入力してメールを送信します。

|SMTPコマンド|メールヘッダに書かれる情報|内容|詐称|
|:--|:--|:--|:--|
|HELO|Received|送信者が送り元のドメインを知らせる|できる|
|Mail From: *1|Return-Path|送信者が送り元のメールアドレスを知らせる|できる|
|RCPT TO:|Delivered-To|送信先のアドレス|?|
|DATA|(本文として記載)|From, Subjectなどを含めた本文全体|-|

*1 Return-Path, エンベロープFromなどの呼び方があります。


virtualboxなどの仮想マシンのMTAに対しローカルからSMTPコマンドを試してみます。(CentOS8 stream)
### 下準備
CentOS8StreamをベースにMTAを準備します。
（VirtualBoxの場合、Adapter1をNAT、Adapter2をHost-only AdapterにしてAdapter2からSSHでつなぎます）
ここでは仮想マシンのIPを```192.168.56.101```とします。

```
% ssh root@192.168.56.101
```
Postfixを入れます

```
# dnf install -y postfix telnet
```
Postfixが受け付けるインターフェース、mydomain、mydestinationを修正します。

```
# cp -vp /etc/postfix/main.cf /etc/postfix/main.cf.orig
# sed -i s/^#inet_interfaces\ =\ all/inet_interfaces\ =\ all/g /etc/postfix/main.cf
# sed -i s/^inet_interfaces\ =\ localhost/#inet_interfaces\ =\ localhost/g /etc/postfix/main.cf
# sed -i s/^#mydomain\ =\ domain.tld/mydomain\ =\ smtp-test.local/g /etc/postfix/main.cf
# sed -i s/^mydestination\ =\ \$myhostname,\ localhost.\$mydomain,\ localhost/#mydestination\ =\ \$myhostname,\ localhost.\$mydomain,\ localhost/g /etc/postfix/main.cf
# sed -i s/^#mydestination\ =\ \$myhostname,\ localhost.\$mydomain,\ localhost,\ \$mydomain$/mydestination\ =\ \$myhostname,\ localhost.\$mydomain,\ localhost,\ \$mydomain/g /etc/postfix/main.cf
```
Firewallに穴を開けます。

```
# firewall-cmd --add-port=25/tcp --permanent
# firewall-cmd --reload
```
```
# systemctl start postfix
```
### Virtualbox内のSMTPに接続して接続先サーバーのユーザーに送信
ローカルから接続してみます。
以下3つのデータでセットします。
HELO: example.com
MAIL FROM: user@example.com
RCPT TO: root@smtp-test.local

```
% telnet 192.168.56.101 25
Trying 192.168.56.101...
Connected to 192.168.56.101.
Escape character is '^]'.
220 localhost.localdomain ESMTP Postfix
```
```
HELO example.com
250 localhost.localdomain
```
```
MAIL FROM: user@example.com
250 2.1.0 Ok
```
```
RCPT TO: root@smtp-test.local
250 2.1.5 Ok
```
```
DATA
354 End data with <CR><LF>.<CR><LF>
```
```
From: test@example.com
Subject: test
Body test
.
250 2.0.0 Ok: queued as D73CF18808FB
```
```
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
```
送られた側を見てみます。

```
# cat /var/spool/mail/root
From user@example.com  Thu Nov 18 16:53:31 2021
Return-Path: <user@example.com>
X-Original-To: root@smtp-test.local
Delivered-To: root@smtp-test.local
Received: from example.com (unknown [192.168.56.1])
        by localhost.localdomain (Postfix) with SMTP id D73CF18808FB
        for <root@smtp-test.local>; Thu, 18 Nov 2021 16:52:59 +0900 (JST)
From: test@example.com
Subject: test

Body test
```
届いていることがわかります。

### 下準備2
gmail.comのメールをリレーするようにします。

```
# sed -i s/^#relay_domains\ =\ \$mydestination/relay_domains\ =\ \$mydestination,\ gmail.com/g /etc/postfix/main.cf
```
```
systemctl restart postfix
```

### Virtualbox内のSMTPに接続してGmailのアドレスに送信
さきほどの3つを変えてみます。MAIL FROMは.jp、Fromはorgにしてみます。
ここでSPFがどのように判断されているか確認します。

HELO exmpale.com
MAIL FROM: user@example.jp
From: test@example.org


```
% telnet 192.168.56.101 25
Trying 192.168.56.101...
Connected to 192.168.56.101.
Escape character is '^]'.
220 localhost.localdomain ESMTP Postfix
```
```
HELO exmpale.com
250 localhost.localdomain
```
```
MAIL FROM: user@example.jp
250 2.1.0 Ok
```
```
RCPT TO: (yourname)@gmail.com
250 2.1.5 Ok
```
```
DATA
354 End data with <CR><LF>.<CR><LF>
```
```
From: test@example.org
Subject: test
Body test
.
250 2.0.0 Ok: queued as 61DD418808F8
```
```
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
```
gmailを見てみます。（迷惑メールに分類されていました）
注目は```Received-SPF```の部分です。

```
Delivered-To: (yourname)@gmail.com
Received: by 2002:(略) with SMTP id fh36csp194206ysb;
        Thu, 18 Nov 2021 00:45:25 -0800 (PST)
X-Google-Smtp-Source: (略)
X-Received: by 2002:(略) with SMTP id v6-(略)mr64030887plz.15.1637225125151;
        Thu, 18 Nov 2021 00:45:25 -0800 (PST)
ARC-Seal: i=1; a=rsa-sha256; t=1637225125; cv=none;
        d=google.com; s=arc-20160816;
        b=(略)==
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816;
        h=subject:from:message-id:date;
        bh=(略)=;
        b=(略)==
ARC-Authentication-Results: i=1; mx.google.com;
       spf=neutral (google.com: xxx.xxx.xxx.xxx is neither permitted nor denied by best guess record for domain of user@example.jp) smtp.mailfrom=user@example.jp
Return-Path: <user@example.jp>
Received: from localhost.localdomain ([xxx.xxx.xxx.xxx ])
        by mx.google.com with ESMTPS id j64si4519585pge.37.2021.11.18.00.45.24
        for <(yourname)@gmail.com>
        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
        Thu, 18 Nov 2021 00:45:24 -0800 (PST)
Received-SPF: neutral (google.com: xxx.xxx.xxx.xxx is neither permitted nor denied by best guess record for domain of user@example.jp) client-ip=xxx.xxx.xxx.xxx;
Authentication-Results: mx.google.com;
       spf=neutral (google.com: xxx.xxx.xxx.xxx is neither permitted nor denied by best guess record for domain of user@example.jp) smtp.mailfrom=user@example.jp
Date: Thu, 18 Nov 2021 00:45:24 -0800 (PST)
Message-ID: <619612a4.1c69fb81.daa42.e0fdSMTPIN_ADDED_MISSING@mx.google.com>
Received: from exmpale.com (unknown [192.168.56.1]) by localhost.localdomain (Postfix) with SMTP id 61DD418808F8 for <(yourname)@gmail.com>; Thu, 18 Nov 2021 17:44:32 +0900 (JST)
From: test@example.org
Subject: test

bodytest
```
SPFの判定結果はneutralとなっています。

```
Received-SPF: neutral (google.com: xxx.xxx.xxx.xxx is neither permitted nor denied by best guess record for domain of user@example.jp) client-ip=xxx.xxx.xxx.xxx;
```
どこのドメインを見ているか、というと「user@example.jp」となっていますので、HELOでもFromでもなく、MAIL FROMを見ていることがわかります。
Received: from exmpale.comとあり、HELOの値はここで使われていることがわかります。
example.jpのTXTレコードはグローバルに引けず、SPFの情報がないので、Neutralになってしまいます。(RFC上はSPFレコードが抽出できない場合は2.6.1のnoneに該当するはずですがなぜか2.6.2のNeutralになっています)

MAIL FROMをexample.comにした場合は、グローバルで引けるTXTレコードに ```"v=spf1 -all"```とありますので、SPFはFAILになります。

```
Received-SPF: fail (google.com: domain of user@example.com does not designate xxx.xxx.xxx.xxx as permitted sender) client-ip=xxx.xxx.xxx.xxx;
```

## 2.RFCをあわせてSPFの判定を見る
### 1.送信元を主張してメールを送る
HELO, MAIL FROMによって入力することができます。
RFC7208では、SPFにHELOとMAIL FROMのどちらかを使う、と書かれています。(利用する対象としては両方考えられる)
```using a given "HELO" or "MAIL FROM" identity during a mail transaction.```
2章-3のHELOの部分では、HELOのチェックはマストではなく、推奨と書いてあり、MAIL FROMが正しいだけでも良さそうです。

### 2. 送信元と騙られないようにSPFレコード（送信元として承認しているホスト）を設定する   
自分のドメインを騙ってメールが送信されないように設定する値です。
送信元として許可するIPやMXレコードを指定し、最後に```-all```を使って指定外の値からメールは送らない、とするのが一般的です。
場合によっては```~all```として、Softfailとすることもあります。

### 3.受信者（MTA）が1.と2.の情報を組み合わせてSPFを確認する
Gmailの場合、SPFの判定に送信主が主張（入力）するMAIL FROMが使われることがわかりました。
1.のようにHELOも見るとRFCにはありますので、他の条件ではそちらも見る可能性があります。

よく言われるReverse DNSを設定する（メールサーバーのIPにMXと同じFQDNを逆引き設定しておく）ですが、こちらについてはRFC7208に記載が見当たらなく、このSPFの要請ではないようです。
ですが、送信元IPの逆引きができるものに関しては一般的にはReverse DNSが実行されメールヘッダに結果が出てきます。


参考資料
[telnetでメール送信(ash.jp)](http://ash.jp/net/telnet_smtp.htm)


2021年11月18日現在
[Email Authentication for Internationalized Mail](https://datatracker.ietf.org/doc/html/rfc8616)
SPF [ [RFC7208] ](https://datatracker.ietf.org/doc/html/rfc7208)
DKIM [ [RFC6376] ](https://datatracker.ietf.org/doc/html/rfc6376)
DMARC [ [RFC7489] ](https://datatracker.ietf.org/doc/html/rfc7489)