ほっしーの技術ネタ備忘録

技術ネタの備忘録です。基本的に私が忘れないためのものです。他の人の役にも立つといいなぁ。

認証エラーログを見て ipfw で ban するやつ

せっかく(10年くらい前に)作ったのでここで公開しておく。

ログを監視して IP アドレスごとバンするやつ

こういうスクリプトを root で走らせておく。

#!/bin/sh

detect() {
        ip=`echo "$1" | egrep -o -e "\[([[:digit:]]+\.){3}[[:digit:]]+\]" | sed -e "s/[][]//g"`
        if [ ! -z "$ip" ]; then
                /sbin/ipfw add 8`date +%H` deny all from $ip to any 2>&1 | /usr/bin/sed 's/^/add ipfw rule: /' | /usr/bin/logger -p auth.info -t ${0##*/} -s
        fi
}

exit_me() {
        kill `jobs -p`
        exit 1
}

PID=$$
trap "exit_me" TERM INT

tail -n 0 -F /var/log/maillog | (trap "kill $PID" TERM INT && while read line; do
       if echo "$line" | egrep -e 'Password mismatch ' > /dev/null 2>&1; then
               detect "$line"
       fi
        if echo "$line" | egrep -e 'SASL LOGIN authentication failed:' > /dev/null 2>&1; then
                detect "$line"
        fi
done) &

wait $!
exit_me

内容を要約すると、 tail -f /var/log/maillog を走らせっぱなしにして、 何か出てくるたびに grep でフィルタして、認証エラーから IP アドレスを抽出したら ipfw のルールにつっこむ。

でっ、その時に 800 番台の番号を振っておく。800 + 現在時刻の hour の値。 例えば、10:34 に流れてきたログから抽出した IP アドレスなら 810 って。 800 番台にしたのは、うちの ipfw ルールが偶然あいてたから。別に何でもいいんだけど。

マッチングルールはまぁいろいろお好みで。 他のコードは、あとで daemon にする時にシグナル周りをいい感じに何とかするためのヤツ。

ほとぼりが冷めたころに ban を解除するやつ

で、あとはこういうスクリプトを cron で毎時 30 分に回す。

#!/bin/sh

export LC_ALL=C
id=`printf "8%02d" \`expr \( \\\`date +%H\\\` + 20 \) % 24\``
echo "delete ipfw rule: $id" | /usr/bin/logger -p auth.info -t ${0##*/}
/sbin/ipfw show | grep "^00$id" | /usr/bin/logger -p auth.info -t ${0##*/}
/sbin/ipfw delete $id > /dev/null 2>&1

20:30 に実行されたら、816 番のルールを全部消す。 だいたい 3 時間くらいで解除する感じかな?別にそんなに厳密にする必要もないので、 書きやすい感じで書いただけ。この辺の数字もお好みで。

最初のスクリプトdaemon にする

/usr/local/etc/rc.d/watch_mx とか適当な名前で下のスクリプトを置いとく。 パスとかは適宜直して使う。

#!/bin/sh
#

# PROVIDE: watch_mx
# REQUIRE: ezjail

. /etc/rc.subr

name=watch_mx
rcvar=watch_mx_enable
command=/usr/sbin/daemon

load_rc_config $name

: ${watch_mx_enable:="NO"}

pidfile=${watch_mx_pidfile:="/var/run/watch_mx.pid"}
command_args="-cfr -P ${pidfile} -t ${name} /usr/local/bin/${name}.sh"

run_rc_command "$1"

こっからメモ書き(ポエム)

/usr/sbin/daemon って初めて使ったけど案外便利ね。

基本的なノリとしては

$ sudo daemon -cfr -P /var/run/watch_mx.pid -t watch_mx sh ~/bin/watch_mx.sh

こんな感じで起動すると、 sh 以降のコマンドを子プロセスとして起動して、 死んでたら再起動したり、シグナルを中継したりしてくれるみたい。

実際、 tail の方に SIGKILL とか送ると勝手に再起動してくれる。 sh の方に送ってもちゃんと再起動してもらうために、 パイプの接続先は子プロセスでも trap してから while read とかしてる。 あんま見かけない書き方だけど、なんか動いてるから多分大丈夫(?)。

LISTEN から accept して fork するだけの、サーバプログラムの共通になりがちなコードの 親プロセス部分の実装が inetd だとするなら、daemon の実実装部分の管理をするだけの 親プロセス部分が daemon といったところか?

ただ、PGID の親が daemon さんになってしまうせいで、 kill -$$ がちゃんと動かないのはハマった。 子プロセスからみた自 PID、 $$ と同じ PGID は存在しないので。 おかげでシグナルトラップをちゃんと動かすのに大変手間取った…… 解決策は

$ kill `jobs -p`

こんな感じ。

素直に perl とかで書けばよかった気がしないでもない。 なんでもかんでも root で動かすとセキュリティホールになるしね。 いずれ作り直したいところではある。

2022-09-29 注:IPv6 対応がバグっているまま10年以上運用していたらしい。まぁ別に害がある訳でもないか……

ssh での接続がなんか遅い問題の対策

なんか知らんけど、前々からさくら VPS にある FreeBSD マシンへ SSH するときに限って、 なんか接続に時間がかかる。

ssh って打ってから公開鍵のパスフレーズを聞かれるまでに体感で 5 秒くらい待たされる。 でも2回目以降は他の場所にあるマシンと同じくらいのリズムでつながるようになる。

……あ~~~~~~~~これ絶対 DNS とか名前引きとかそういうアレだよー……タイムアウトしたりそれがキャッシュされたり忘れたりする挙動、これ絶対 DNS とかそういうやつだよ……

みたいなことを思いながら調べた時の記録。

まずは接続するときに ssh -vvv で接続する。 遅いときは最初にあるサーバからのあいさつが遅い。 つまり返事するまでにサーバが何かしてる。

次。 /etc/ssh/sshd_configLogLevel DEBUG3 にする。 過去のトラウマがフラッシュバックしつつ $ sudo /etc/rc.d/sshd restart & を叩く。 嫌な予感がする時は、最後におまじないのごとく & をつけるのがポイント。こいつがあれば大体救われる。

XXX XX 03:44:32 host sshd[19640]: debug3: Trying to reverse map address 240b:11:xxxx:xxxx:xxxx:xxxx:xxxx:xxxxx.
XXX XX 03:44:35 host sshd[19640]: Connection from <snip>

ほらー!なにこのタイムスタンプの不自然な間は!!! どうみてもクライアントの IPv6 アドレスを逆引きしようとしてタイムアウトしてんじゃん。

$ drill -x 240b:11:xxxx:xxxx:xxxx:xxxx:xxxx:xxxxx
;; Query time: 4267 msec

ほらぁー……

という訳で、原因が分かったので対策します。

今回は /etc/rc.conflocal_unbound_enable="YES" こういうことして、 unbound をローカル用のリゾルバにしてたので、そこに固定のレコードを入れることに。

/etc/unbound/unbound.confserver セクションに以下の行を追加。

local-zone: "0.0.0.2.0.e.4.d.1.1.0.0.b.0.4.2.ip6.arpa." static

そして

$ sudo /etc/rc.d/local_unbound restart
$ drill -x 240b:11:xxxx:xxxx:xxxx:xxxx:xxxx:xxxxx
;; ->>HEADER<<- opcode: QUERY, rcode: NXDOMAIN, id: 23003
;; Query time: 1 msec

ほい。この IP アドレスは誰も返事を返しません。あきらめてください。

これで ssh での接続が格段に速くなりました。やったね。

……これでいいのか?

令和にもなって MTU とか MSS とかを思い出した日

ある日から突然届くようになった daily メールの一部分。

Mail in local queue:
-Queue ID-  --Size-- ----Arrival Time---- -Sender/Recipient-------
4E0851D6401    2276 --- J** 18 22:39:25  ****@*******.com
(conversation with mx01.******.jp[**.**.**.**] timed out while sending end of data -- message may be sent more than once)
                                         *****@***.jp

ほっほー。また postfix でメールが滞留してるんかー。 postqueue -f ぽちーっ。

……あれ?なんで消えないの??? ここからが長かったのであった。

まずは定石通り問題の切り分けから。

  1. まず問題の SMTP サーバに telnet で接続 → 問題なく接続成功
  2. そのまま SMTP をしゃべってみる → 特に応答は問題なさそう
  3. tcpdump しながら再送してみる → 確かに DATA の所で突然応答が消えるな?
  4. 受信者に断ってから telnet でテストメールを送ってみる → え、普通に届いちゃった……
  5. sendmail コマンドで postfix からテストメールを送信 → やっぱり届く????

該当のメールだけなぜか再送できない!!!!!!!

もう知らない。postfix さんのことなんて知らない! スパムフィルタかウイルスチェッカか IDS とかに突然 TCP コネクション切られてるんでしょ!

半泣きになりながらあれこれ調べた結果、ipfw の設定をミスって icmptype 3 を deny にしてたことが判明。

あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙あ゙ん゙????

以下、FreeBSD のソースを読んだ結果。

  • 通常、NIC の MTU は 1,500、 net.inet.tcp.path_mtu_discovery=1 になっている
  • すると TCPプロトコルスタックは MTU から算出した MSS を使い、IP ヘッダの Don't Fragment を立てる
  • 問題なく届けばそれでよし、ダメな場合は ICMP 3.4 が届いて経路上の最低 MTU が分かる
  • それを見て MSS を再調整して再送

これが本来想定されている動作。ここで私は ICMP 3.4 を ipfw でドロップしていたため、 「ICMP 3.4 が届かないってことは MTU は問題ないのに、なんで ACK が返ってこないんだろうねぇ?」 というカーネルおじさんのお気持ちがわかる。

いやわからねぇよ。

ていうか MTU とか MSS なんて、 ブロードバンド☆ とか言ってた時代にいじったっきり すっかり忘れてたテクノロジーだわ。

という訳で、ICMP 3.4 をちゃんと allow ルールとして追加。

…… postqueue -f はい、流れてったー。

ちなみに、 net.inet.tcp.path_mtu_discovery=0 の場合はその辺は経路のノードに適当におまかせするので、

  • MTU?NIC に 1,500 ってついてるからそれでええんやないか?
  • Don't Fragment をつけずに IP パケット投げれば途中で分割とかいい感じにやってくれるんとちゃう?

みたいな感じになるので、これはこれで動きそう。 という訳で結論。

net.inet.tcp.path_mtu_discovery=1 にするなら ICMP 3.4 をちゃんと通しましょう。

それはそう。でもまさかレイヤー3まで潜るハメになるとは思わんかった…… 今はもう令和やぞ。MTU とか MSS の自動調整が効いてない状態だったとか思わんかったし、 なんならどうして突然動かなくなった(最近まで普通に動いてた)んや??

インターネットの気持ち何も分からん。

使い物になる NAT with pf を作る

前回までで FreeBSD の pf で MAP-E ルータとしてかろうじて動く設定になりました。 でもなんかいろいろおかしくて、ちゃんと通信できなかったので今度こそ。

一番の問題。Google が開けない。

tcpdump をいろいろ眺めた結果、おかしな部分は分かった。 gif0 と外との通信がパケット分割されてるようで、再構成できていないせいで NAT のルールが上手く動かなかったりしてたみたい。

という訳で、 pf.conf に以下の設定を追加。

scrub on gif0 all fragment reassemble
scrub on gif0 all reassemble tcp

何が違うのかはよくわからないけど、みんなおまじない的につけてるみたい。

gif0 の MTU が小さい…?

上記の問題を調べてた時に気づいた。 gif0 のデフォルトの MTU が 1280 しかない。 これのせいで MTU の自動調整が上手くきかなかったのか?と思って 1500 にしたりした。

でも別に戻しても動いたのであんま関係ないかも。 単にフラグメントが起きなくなっただけの話なので、こっちで直すのは本質じゃないよね。

で、値をどうしようか。IPv6カプセル化しちゃうし、1500 よりちょっと小さい方がいいのかもしれない。 まぁイマドキなら別に、ちゃんと計算しなくてもとりあえず 1500 にしておけば いい感じに TCP が mss を調整してくれる気がする。

LAN 内のおうちサーバにアクセスできない

常用するならこれはちょっと困る。

まぁ、192.168.64.0/24 からのパケットは全部強制的に NAT して gif0 に流してしまうからなんだけど。 なのでルールをもうちょっとちゃんと設定して、おうちサーバは直通ルートにすれば済む話。

と、思ったんだけれども、別にこのままでも要するに自宅 LAN の外の扱いになっているわけで、 一旦 MAP-E から外に出て、ルータの NAT から入ってきておうちサーバに届くんだよなぁ?

ということは。 この MAP-E の IPv4 アドレスは他の v6 プラスユーザと共有しているので、IPv4 アドレス共有になってるところからは 同様にアクセスできないのかもしれない?のでちゃんと直さないといけないな?

という訳で調べてみたところ、どうやら SYN+ACK が MAP-E の IPv4 アドレス宛になる (SYN の差出人は外からそう見えるので当然) ので、そこで pf の NAT ルールに引っかかって gif0 から投げていて、 ファイアウォールの動的ルールに引っかからないで落とされているみたい。

これに対する特効薬はルーティングでの reply-to っぽい。つまりこう。

pass out log route-to gif0 from 106.73.212.224
pass in log reply-to (em0 XXX.XXX.XXX.XXX) from 106.73.212.224

同じ MAP-E の IPv4 アドレスが差出人のパケットでも、

  • pf の NAT ルールで差出人を差し替えた後の(外向きのパケット)は gif0 から投稿する
  • 一方、同じ IPv4 アドレスから来た SYN パケットへの応答 SYN+ACK は、物理ルータから物理 NIC の em0 から来てるので、本来のデフォルトルートに返す

これでちゃんと動くようになった。 ローカル IP でもグローバル IP でも、ちゃんとおうちサーバへの接続ができたのでよし。 ping もちゃんと導通してた。ID もポートと同じ割り当てになるっぽいのね。

ipfw の整理

っていうか pf に統合すればいいのに。

…と思いながら最小の構成。

allow ipencap from 240b:11:d4e0:2000:6a:49d4:e000:2000 to 2404:9200:225:100::64 via em0
allow ipencap from 2404:9200:225:100::64 to 240b:11:d4e0:2000:6a:49d4:e000:2000 via em0

トンネルの出入り口の IPv6 アドレスの間を通せばいいみたい。 ipencapプロトコル ID 4 番のこと。

他は普段のルールに元々あると思う。中から外にでるルールとか、ICMP を通すルールとか。

ここから先は今後の要検討事項

iPhoneIPv4 アドレスを手動設定しても接続できない

これは……物理ルータの(クソ)仕様なのだろうか?バッキャロー!とつい江戸っ子になってしまいそう。 でも ARP は飛んできてるっぽいんだよなぁ?謎である。

ルータ的なパケットフィルタはどうしようか

一般的なブロードバンドルータにあるようなフィルタの設定、どうしようか? でもイマドキの Windows はパブリックネットワーク設定にしておけば それなりなファイアウォールかかってる気もする。

てかぶっちゃけ、市販のルータだと IPv6ファイアウォールかからないものが多いし、 FreeBSD ルータはすべてパススルーでも特に困らない疑惑?そのうち考えよう。

13.1-R で MAP-E ルータを作ってみる

前回は pfmap-e-portset で NAT した場合のこちら側ポートをいい感じに設定してもらいました。

今回はもっとちゃんとルータっぽくするために、宛先のルーティングをいい感じにします。 MAP-E 経由の宛先だけルーティングテーブルに書くのはしんどいからね。 pf の機能を使うと、宛先ではなく差出人のアドレスを使ってルーティングを切り替えられます。

まず結論

ググってもサンプルがなかったので man pf.conf に書いてある呪文と ソースコードを読み解きながら試行錯誤した結果、動くようになった pf の設定がこれ。

nat log on em0 from 192.168.64.0/24 to any -> 106.73.212.224 map-e-portset 4/8/32
pass all
pass out log route-to gif0 from 106.73.212.224

log は別になくても困らないかも。実験の時はあると便利。ポイントはこの2点。

  • まず先に NAT ルールが効くので、192.168.64.2 から普通のルーティングルールで外に出るパケットはデフォルトルートの em0 から(物理的に存在しているルータに向けて)出てくわけで、 on em0 from 192.168.64.0/24 to any でマッチングしたものを、MAP-E のアドレスに変換します
  • で、NAT ルールで差出人アドレスが差し替えられた状態( from が MAP-E アドレス )のパケットに対してルーティングを切り替えます。

後は環境によるかもだけれども以下は必要なことも。

# sysctl net.inet.ip.forwarding=1
# sudo route delete 172.67.134.3

前者はまぁ FreeBSD でルータを作るときの定型文。後者は前回の記事で追加したルールが今回邪魔になるので。 というのも、先に routegif0 送りにしてしまうと pf でのマッチングが取れなくなってしまうみたい?

接続テスト

まぁそんな訳で、 /usr/local/etc/ezjail/temp の設定から FIB の設定を空欄に戻してやると、

temp_vm# printf "GET /ip HTTP/1.0\r\nHost: ifconfig.io\r\n\r\n" | nc 172.67.134.3 80
<snip>

106.73.212.224

うぇいうぇい。完璧ですね。

ていうか、差出人アドレスの設定をすればいいだけなので、 nc を使ってこれでもよかったみたい。

$ printf "GET /ip HTTP/1.0\r\nHost: ifconfig.io\r\n\r\n" | nc -4 -s 192.168.64.1 ifconfig.io 80
<snip>

106.73.212.224

やったぜ。

物理 NIC を介しているので、適当な Windows マシンがあるなら ネットワークアダプタの設定で IPv6 を無効にしてから IPv4DHCP ではなく手動設定にして、 192.168.64.5/24 とかにしてデフォルトゲートウェイ192.168.64.1 に向ければ MAP-E 経由になります。 ブラウザで https://ifconfig.io にアクセスすればバッチリ、そこには光り輝く(当社比)MAP-E の IPv4 アドレスが!!

速度はどうだろうか

今回はアップロードも測定してみました。

Download/Upload
MAP-E 140Mbps/110Mbps
PPPoE 160Mbps/170Mbps
IPv6 150Mbps/210Mbps

下り速度はまぁ誤差の範囲な気もするけど……上り遅くない??なんで??

まとめ

という訳で、ここまで順番に読むのが面倒な人(特に私)のためのまとめ。これを適当に mape.sh とかにして sudo でたたき込む。

ifconfig em0 inet6 240b:11:d4e0:2000:6a:49d4:e000:2000/128 alias
ifconfig gif0 create up
ifconfig gif0 inet 106.73.212.224/15 106.73.212.224
ifconfig gif0 inet6 tunnel 240b:11:d4e0:2000:6a:49d4:e000:2000 2404:9200:225:100::64

sysctl net.inet.ip.forwarding=1

ifconfig em0 inet 192.168.64.1/24 alias
ifconfig em0 inet 192.168.64.2/32 alias

kldload pf
pfctl -F all
pfctl -f /dev/stdin << PFRULE
nat log on em0 from 192.168.64.0/24 to any -> 106.73.212.224 map-e-portset 4/8/32
pass all
pass out log route-to gif0 from 106.73.212.224
PFRULE
pfctl -e

ipfw add 10 allow ip6 from 240b:11:d4e0:2000:6a:49d4:e000:2000 to 2404:9200:225:100::64
ipfw add 20 allow ip6 from 2404:9200:225:100::64 to 240b:11:d4e0:2000:6a:49d4:e000:2000
ipfw add 30 allow ip from any to any via gif0
ipfw add 40 pass all from 192.168.64.0/24 to any keep-state

ただまだ微妙なところがあって。

  • TCP で大きいパケットを投げるとおかしくなる=MTU の調整とかの関係がなんかおかしい?
  • バッキャローと叫びたくなるルータの仕様なのか、iPhone からパケットが届かない
  • LAN 内にあるおうちサーバに接続できない

もう少し調整しないと実用は難しいのかも。

13.1-R で MAP-E を試してみる

そろそろ 13.0-R のサポートが切れてしまうので、しれっとアップデートしました。

さて。そういうことなので pf の NAT に map-e-portset 対応が増えているのです。

という訳で試してみました。

まずは前回のおさらい

前回の記事を見ながら gif0 を設定。

うーん??どうしてパケットが流れないんだ…… tcpdump を眺めたり netstat -rn を眺めたり ipfw show してみたり。 小一時間ほど散々調べた結果が、

  • NIC に CE アドレス振ってないな??
    • どうやら EUI-64 アドレスを見間違えたようだ……目が節穴になってるや
  • しかも ipfw あけてないじゃん
    • 前回の記事に書いてあったよね?どこ見てるの?
  • というかそもそも IPv6 の default ルートがないんだが???
    • どうして……

ケアレスミスが多いですね。おまえ仕事もそんな感じでやってるのか???

そんな訳で、えらく時間はかかったけれども前回と同じことが 13.1-R でもできることを確認。

ezjail で管理してる仮想マシンから MAP-E 経由で外に出てみよう

ステップバイステップで実験。

まずはホスト側で MAP-E 経由で外にでる宛先 IP アドレスを決める。 今回は ifconfig.io の A レコードを使うことにしたのでこれを。 つまり、仮想的なルータの方で、 ifconfig.io 向けのパケットを gif0 に向けるわけ。

# route add 172.67.134.3 -iface gif0

で、仮想 LAN 的な感じで NIC に IP アドレスを 2 つ設定。 プレフィックスは既存の LAN とぶつからないように。こんなときプログラマは 64 とか使いがち。

# ifconfig em0 inet 192.168.64.1/32 alias
# ifconfig em0 inet 192.168.64.2/32 alias

さらに、FIB 1 番を増設して実験用の ezjail に渡すことにする。 デフォルトルーティングを仮想のルータ向けにしたテーブルを仮想マシンに使わせるわけ。

# sysctl net.fibs=2
# setfib 1 route add default 192.168.64.1 -iface

あれ、ていうかイマドキは FIB って sysctl で増やせるんだ…… 諦めてカーネルビルドする決心したところで気づいたよ。

そして本命。 pf を有効にして NAT の設定。

nat log on gif0 from 192.168.64.0/24 to any -> 106.73.212.224 map-e-portset 4/8/32
pass all

こんな pf.conf を作って読み込ませる。変換先の IP アドレスは外向きのやつ。 map-e-portset の引数は man pf.conf 参照。

# pfctl -f pf.conf
# pfctl -e
# pfctl -sn
nat log on gif0 inet from 192.168.64.0/24 to any -> 106.73.212.224 map-e-portset 4/8/32

最後に /usr/local/etc/ezjail/temp の該当行を編集。

export jail_temp_ip="192.168.64.2"
export jail_temp_fib="1"

あ、ファイアウォール空けるの忘れてた。前回のにこれを追加。

# ipfw add 40 pass all from 192.168.64.0/24 to any keep-state

この状態で jail 内部から以下のコマンドでこちらの IP アドレスを取得。

# printf "GET /ip HTTP/1.0\r\nHost: ifconfig.io\r\n\r\n" | nc 172.67.134.3 80
<snip>

106.73.212.224

無事に MAP-E での IP アドレスが取得できました。今回は nc-p をつけてないのがポイント。 ちなみに jail 自体を setfib して立ち上げてることになるので、中からはいちいち setfib 要らないのは好感。

いじわるして MAP-E で受信アドレスになれないポートを指定してみる。

temp_vm# printf "GET /ip HTTP/1.0\r\nHost: ifconfig.io\r\n\r\n" | nc -p 1025 172.67.134.3 80
<snip>

106.73.212.224
host# pfctl -ss | grep 192.168.64
all tcp 106.73.212.224:21004 (192.168.64.2:1025) -> 172.67.134.3:80       FIN_WAIT_2:FIN_WAIT_2

ちゃんとアドレスとポートを差し替えてくれている様子。素晴らしいですね。

今回はここまで。

MAP-E を試してみる

どうやら、うちにつないでいる v6 プラスだと、MAP-E での IPv4 接続が 無料でついてくるらしい。しかも、PPPoE と比べて速度が出る(IPv6 相当の速度になる)という噂。 ……という訳で、それを試してみたという話。

hoshizuki.hateblo.jp この時と真逆のことをやろうとしているのか……

まずはアドレスを計算する

http://ipv4.web.fc2.com/map-e.html ここで、自分のところに割り振られている IPv6プレフィックスを入力する。 すると、MAP-E 接続に使用する各種パラメータが計算されるという寸法。

v6プラスのIPアドレス&ポートの計算方法: ネトゲー回想録 この辺を読んで自前で計算もできるけど。 一応、RFC とか読んで試してみたけど、ここにある謎の非公開らしい情報がないと、 自前で計算はできないらしい。うーん?

設定する

先人の方々の記事を参考にしつつ。 qiita.com bokut.in

まずは、さっき計算した CE のアドレスを今使ってる物理 NIC に振る。alias で OK。

# ifconfig em0 inet6 240b:11:d4e0:2000:6a:49d4:e000:2000/128 alias

で、CE と peer addr (どちらも IPv6)の間でトンネルを張る。 計算した IPv4 アドレスはここに割り振る。

# ifconfig gif0 create up
# ifconfig gif0 inet 106.73.212.224/15 106.73.212.224
# ifconfig gif0 inet6 tunnel 240b:11:d4e0:2000:6a:49d4:e000:2000 2404:9200:225:100::64

こんな感じになる。

$ ifconfig gif0
gif0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1280
        options=80000<LINKSTATE>
        tunnel inet6 240b:11:d4e0:2000:6a:49d4:e000:2000 --> 2404:9200:225:100::64
        inet 106.73.212.224 --> 106.73.212.224 netmask 0xfffe0000
        groups: gif
        nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>

あと、ファイアウォールもあけておく。

# ipfw add 10 allow ip6 from 240b:11:d4e0:2000:6a:49d4:e000:2000 to 2404:9200:225:100::64
# ipfw add 20 allow ip6 from 2404:9200:225:100::64 to 240b:11:d4e0:2000:6a:49d4:e000:2000
# ipfw add 30 allow ip from any to any via gif0

トンネル間の出入り口の IPv6 パケットは相互にとりあえず全開通。 gif0 も一旦全部通す状態で実験。

これで OK。

通信してみる

MAP-E の仕様として、こちらに割り振られるグローバル IP は複数のユーザで共有していて、 そのアドレス宛の、一部のポート宛のパケットだけが流れてくる。

なので、通信するには「こちら側」のポートを指定できる必要がある。 とりあえず今回は NAPT とかするのは諦めているので(最新の pf ならできるという噂?)、 nc を使って通信してみる。※執筆時は FreeBSD 13.0-R を使ってました。

速度測定に使うサーバは、CDN にそこそこのサイズのファイルがあるものがいい。 あと非 SSL で通信できる必要がある。

……という訳で、今回はとあるサーバを勝手に拝借。

#!/bin/sh

go () {
        printf "GET /hogefuga.tar.gz HTTP/1.0\r\nHost: foobat.org\r\n\r\n" | nc -4 -p $1 xxx.xxx.xxx.xxx 80 > /dev/null
        echo 'done'
}

go 12800 &
go 12801 &

みたいな。これを、 time コマンドで実行して、転送サイズを割れば速度が分かる。 ちなみに go の引数はこちら側で使えるポート。さっきのサイトで計算した範囲のヤツを使う。

あと、測定対象のサーバ向けは gif0 に向けてパケットを投げるように、 ルーティングテーブルも追加する必要がある。

# route add XXX.XXX.XXX.XXX -iface gif0

という訳で速度測定。

IPv6(IPoE) 190.38Mbps, 164.27Mbps, 192.96Mbps
IPv4(PPPoE) 178.06Mbps, 183.91Mbps, 189.23Mbps
IPv4(MAP-E) 175.87Mbps, 162.90Mbps, 144.85Mbps

ん-……PPPoE でも十分な速度でてない???