OpenWrtのMAP-E ルータ構築 [iptablesについて]

（前置き経緯）
自宅のネット環境がPPPoE接続で、通常利用でそれほど支障はなかったのですが、macOS更新ダウンロードで３時間以上は絶えられなくなり、IPv6接続に切り替えました。
市販のコンパクトな４千円程度の小さなWifiルータを試しましたが、ルーターの起動も遅い、動作も遅い、なにか固まるような動き、小型アンテナで電波は強くとも距離が飛びません。
Raspberry Pi 2Bで構築のルータ(PPPoE接続)＋長いアンテナのついたWifiルータ のほうが快適でした。そこで、IPv4 over IPv6環境も自前でブロードバンドルーターを構築するに至りました。

(環境)　 Raspberry Pi 2B 用　　 OpenWrt 19.07.4　をインストール構築。
イメージの場所　https://openwrt.org/toh/raspberry_pi_foundation/raspberry_pi

あちこち参考にさせていただきましたが、結果として自前でルータ構築できたことに感謝です。

OpenWrt標準では、完全ではないので、追加修正が必要です。
MAP-E技術、OpenWrtのmapeセットアップに関しては、多くの先人たちの説明に譲ります。

(参考) https://qiita.com/s_ponta/items/5652a7be49198288ae61
(参考) https://ktaka.blog.ccmp.jp/2020/05/linuxipv6-ipoe.html
(参考) https://blog.mamemaki.com/entry/2019/12/15/171104



パケットmark付けのiptablesについて自分なりに補います。



# （OpenWrt）  Firewall - Custom Rules 用
先人たちのコードを修正して、ルール用のテーブルのテキストを吐き出すように次を作成しました。
次の実行結果テキストをカスタムルールに貼り付け適用するものです。

```shell:echo-iptables.sh
#!/bin/sh

createMAPE()
{
 if [ "$1" = "OCNV" ] ; then
    divNum=64
    startPort=1024
  fi

  if [ "$1" = "V6P" ] ; then
    divNum=16
    startPort=4096
  fi
   
  rule=1
  startMark=9
  Every=`expr $divNum - 1`

  while [ $rule -lt $divNum ] ; do
    mark=`expr $rule + $startMark`
    pn=`expr $rule - 1`
    portl=`expr $rule \* $startPort + $PSID \* 16`
    portr=`expr $portl + 15`
    echo  "iptables -t nat -A prerouting_lan_rule -m statistic --mode nth --every $Every --packet $pn -j MARK --set-mark $mark"
    echo  "iptables -t nat -A OUTPUT -o map-tnl -m statistic --mode nth --every $Every --packet $pn -j MARK --set-mark $mark"    #output_wan_ruleだとバグな感じで適用されませんので、「OUTPUT -o map-tnl」とします。
  done
}

#　あなたの環境に書き換えてください。
BR='xxxx:xxx:xxxx::x'
CE='xxxx:xxxx:xxxx:xxxx:xx:xxxx:xxx:xxx'    # xで適当に隠します。
IP4='xxx.xx.xx.xx'
PSID='x'

createMAPE OCNV
#createMAPE V6P
```
BR　CE　IPV4 PSID　の求め方は「MAP-E計算」で検索かけて、１ページ目を一通りチェックします。


私の環境が、今はOCNバーチャルコネクトなので、ここでは createMAPE OCNV を走らせます。

markの番号は 10進数の10からはじめています。0以上ならよさそうです。paketは0からのようです。
paket分散は計算でキリの良い64したくなりますが、0〜62 の 63個です。間違うとロスするタイミングがときどきありそうです。常に --every 63 になるように $Every を当てています。


##OpenWrt カスタムルール用の考慮
-A PREROUTING　や　-A OUTPUT の チェイン指定でも動作はするようですが、全部インターフェースの出入りに適用されてしまいますので、いくらか動きが遅いです。次のチェインを指定します。

|| REROUTING| OUTPUT |
|:-:|:-:|:-:|
|適用先|  LAN の入り | WAN の出  |
|チェイン| prerouting_lan_rule  | output_wan_rule が適用され<BR>ないので OUTPUT -o map-tnl |

（重要）OpenWrt 19.07.4において、output_wan_ruleは、バグのようで適用されませんので、OUTPUT -o map-tnl を直接指定する必要がありました。

（参考）インターフェースの名称は lan wan tnl を使っています。これに連動してチェイン名も変わるかもしれません。

```:/etc/config/network
config interface 'lan'
~省略
config interface 'wan'
~省略
config interface 'tnl'
~省略
```

チェイン名をiptables-saveで内容確認、探してください。
たとえば、prerouting_xxxx_ruleで、xxxxがインターフェース名になっていると予想します。

```
root@OpenWrt:~# iptables-save
```


#以上を踏まえ、カスタムルールに追加するiptablesが得ました
出力されたこれらをコピーしてOpenWrtの　Network　->　Firewall ->　Custom Rules　に貼り付け適用します。

```shell
iptables -t nat -A prerouting_lan_rule -m statistic --mode nth --every 63 --packet 0 -j MARK --set-mark 10
iptables -t nat -A OUTPUT -o map-tnl -m statistic --mode nth --every 63 --packet 0 -j MARK --set-mark 10
.
.
.
iptables -t nat -A prerouting_lan_rule -m statistic --mode nth --every 63 --packet 62 -j MARK --set-mark 72
iptables -t nat -A OUTPUT -o map-tnl -m statistic --mode nth --every 63 --packet 62 -j MARK --set-mark 72

```



# POSTROUTING についても mark 追加対応

POSTROUTINGは /lib/netifd/proto/map.shで作られています。ipv4 over ipv6トンネルに抜けていくPOSTROUTINGも分散させるために、次のようにmarkをつけます。同じ値の範囲：0x0a(10)〜0x48(72)になるようにします。


###修正箇所

```:/lib/netifd/proto/map.sh

130行目あたり

	json_add_array firewall
	  if [ -z "$(eval "echo \$RULE_${k}_PORTSETS")" ]; then
	    json_add_object ""
	      json_add_string type nat
	      json_add_string target SNAT
	      json_add_string family inet
	      json_add_string snat_ip $(eval "echo \$RULE_${k}_IPV4ADDR")
	    json_close_object
	  else
	 	local mark=17     # ■■ 追加 ■■
	    for portset in $(eval "echo \$RULE_${k}_PORTSETS"); do
          for proto in icmp tcp udp; do
	          json_add_object ""
	          json_add_string type nat
	          json_add_string target SNAT
	          json_add_string family inet
	          json_add_string proto "$proto"
	          json_add_string mark "$mark"     # ■■ 追加 ■■
    # ■■ コメントアウト ■■   json_add_boolean connlimit_ports 1
              json_add_string connlimit_ports "1"     # ■■ 追加 ■■
              json_add_string snat_ip $(eval "echo \$RULE_${k}_IPV4ADDR")
              json_add_string snat_port "$portset"

	           json_close_object
           done
           mark=`expr $mark + 1`        # ■■ 追加 ■■
	    done
	  fi


```

再起動すれば完了です。

iptables-save　で確認すれば、POSTROUTINGで「-m mark --mark 0xa」〜「-m mark --mark 0x48」の範囲で追加されています。

```shell-session
-A POSTROUTING -o map-tnl -p tcp -m mark --mark 0xa -m connlimit --connlimit-upto 16 --connlimit-mask 32 --connlimit-daddr -m comment --comment "!fw3: ubus:tnl[map] nat 0" -j SNAT --to-source xxx.xx.xx.xx:1056-1071
.
.
.
-A POSTROUTING -o map-tnl -p tcp -m mark --mark 0x48 -m connlimit --connlimit-upto 16 --connlimit-mask 32 --connlimit-daddr -m comment --comment "!fw3: ubus:tnl[map] nat 187" -j SNAT --to-source xxx.xx.xx.xx:64544-64559
```

これで通信が途切れたり、繋がらないようなことは少し減ると思います。