Windowsで溜まり続けるキャッシュを消す。
Windows はアプリごとにキャッシュを持っていて、Tempなどにまとめて管理する文化がない。
まぁLinuxとかRuby Bundler なんかも同じなんですけど。
せめて、Windowsのディスクのクリーンアップが「$APPDATA/**/Cache」フォルダの中身は容赦なく消すぞ。みたいな仕様にしてくれたらなぁっと思う。
キャッシュ関連を削除
rm -Recurse -Force -Confirm:$false C:\Users\takuya\AppData\Local\NuGet\Cache\* rm -Recurse -Force -Confirm:$false C:\Users\takuya\scoop\cache\* rm -Recurse -Force -Confirm:$false 'C:\ProgramData\Package Cache\*' rm -Recurse -Force -Confirm:$false C:\ProgramData\chocolatey\logs\chocolatey.*.log rm -Recurse -Force -Confirm:$false C:\ProgramData\chocolatey\logs\choco.summary.*.log rm -Recurse -Force -Confirm:$false C:\ProgramData\ChocolateyHttpCache/* rm -Recurse -Force -Confirm:$false C:\ProgramData\Emurasoft\EmEditor\updates\* rm -Recurse -Force -Confirm:$false 'C:\ProgramData\Apple Computer\Installer Cache\*' ## ゴミ箱を空に echo y | powershell Clear-RecycleBin
他にも、キャッシュを持ってるフォルダは見つかり次第に追加していこうと思う
タスクスケジューラに登録する。
こんな感じで、コマンドを登録して、定期的に実行することにした。
<?xml version="1.0" encoding="UTF-16"?> <Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task"> <RegistrationInfo> <Date>2024-09-11T14:42:35.0215253</Date> <Author>takuya</Author> <URI>\takuya\Cleanup Caches</URI> </RegistrationInfo> <Triggers /> <Principals /> <Settings /> <Actions Context="Author"> <Exec> <Command>powershell.exe</Command> <Arguments>-WindowStyle Hidden -ExecutionPolicy Bypass -File ""C:\Users\takuya\misc-app\maintenance\remove-cache.ps1"</Arguments> </Exec> </Actions> </Task>
キャッシュは溜めないでほしい
キャッシュがSSD居座ることで、SSDの容量に居座る。そのためログとキャッシュある箇所は二度と書き込みされないのに、ずっとデータが有る。SSDはキャッシュの箇所など認識しないので、データ有りとなる。SSDは空き容量をやりくりながら書き込みを平準化する。SSDを容量ギリギリ迄使っていると、結果としていつも同じ箇所に書き込みが続いて、寿命を縮めることになる。
アプリつくる人はキャッシュ消せよ!1年以上も残してるんじゃないよ。っていうかボリューム・シャドウコピーがあるんだから、ボリューム・シャドウコピーを前提として上書きしてほしい。ボリューム・シャドウコピーならWindowsが管理してくれるんだから。
起動用のキャッシュならともかく、アップデート用のキャッシュは複数溜まってたりするので絶対に消してほしい。
WindowsでのiPhoneバックアップの場所
windows のiTunesに取得したバックアップの場所
Windows内部に作ったバックアップの場所。
C:\Users\takuya\AppData\Roaming\Apple Computer\MobileSync\Backup

バックアップの削除はここから行う。

うっかり、AppData内部のデータを消さないように
ローカルのバックアップって意味あるの?
「あります。」
- iCloudバックアップは容量不足になりがちで、Appleに1ドル吸われる。
- iCloudバックアップは全データを取り出さない(指定データのみ)
- iCloudバックアップから取り出しは遅い。
- iCloudバックアップでは一部アプリのセキュア・データが復元されない
あらゆるデータをバックアップ取るのであれば、ローカルが一番ですね。
機種間でのデータ移行も確実に行えます。
いくら高速インターネットだの、高速WiFiだといっても、iCloudからデータ取り出しで20MB/sくらいしか速度が出ないんですから。ローカルに持っておくのがストレス無いですね。
lxc の root ストレージを作り直す。( Failed getting root disk: No root device could be found)
LXC のstorage を作り直す
LXCを整理するのには、ストレージを消して作り直すと手っ取り早い
ストレージをすべて消して空っぽにした状態
takuya@:~$ lxc storage ls +------+--------+--------+-------------+---------+-------+ | NAME | DRIVER | SOURCE | DESCRIPTION | USED BY | STATE | +------+--------+--------+-------------+---------+-------+
lxc のストレージを消すには、used by で利用しているlxd インスタンスをlxc delete $NAMEで消す必要もある。
lxc コマンドは、次のようにすると、sudo なし一般ユーザも利用可能。
sudo usermod -aG lxd takuya
default が used by 1 だったらそれも消す
lxc profile device remove default root
ストレージを再生成する。
lxc storage create default btrfs
root (イメージ保存先)を割り当てる。
path=/ を割り当てる。
lxc profile device add default root disk path=/ pool=default
この作業を忘れると、次のように root device (stoage ) がないと怒られる。
Failed getting root disk: No root device could be found
btrfs の圧縮オプションを入れておく。
btrfs は圧縮オプションを入れておくといいかもしれない。(おまじない)
lxc storage set default btrfs.mount_options compress=zstd
zstd 圧縮が効いていることを確認
lxc storage get default btrfs.mount_options
イメージをlaunchして確認
LXC_NAME=test-ubuntu RELEASE=22.04 lxc launch ubuntu:$RELEASE $LXC_NAME
btrfs の圧縮オプションが効いていることも確認
lxc exec $LXC_NAME 'mount' | grep btrfs | grep zstd /var/snap/lxd/common/lxd/disks/default.img on / type btrfs (rw,relatime,idmapped,compress=zstd:3, ssd,space_cache=v2,user_subvol_rm_allowed, subvolid=257,subvol=/containers/test)
btrfs なんで subvol=/containers/test でLXC_NAMEが入っていて、compress=zstd:3, になって圧縮オプションも継続していることが確認できる。
まとめ
lxc のストレージの作り直し。
lxc storage delete $NAME lxc storage create $NAME lxc profile device add default root disk path=/ pool=$NAME
lxd init をしてもいいけど、ストレージだけ作り直せる。使えると便利。
dockerfileでAPTプロキシとシェル変数を渡す例。
docker build で apt installを高速化
docker build で毎回ダウンロードが公式レポジトリから行われるのが、心苦しい。
無駄な通信が発生している。そして何より遅い
ビルド例
export APT_HTTP_PROXY=http://192.168.2.21:3142
docker build --build-arg APT_HTTP_PROXY=${APT_HTTP_PROXY} -t sample .
Dockerfileの例
dockerfile で次のように記述すればいい。
FROM ubuntu:20.04 ENV DEBCONF_NOWARNINGS=yes ARG APT_HTTP_PROXY ENV APT_HTTP_PROXY=${APT_HTTP_PROXY} RUN echo "Apt Config" && \ echo "APT::Install-Suggests 0;\nAPT::Install-Recommends 0;" \ | tee /etc/apt/apt.conf.d/00-no-install-recommends && \ echo "path-exclude=/usr/share/locale/*\npath-exclude=/usr/share/man/*\npath-exclude=/usr/share/doc/*\n" \ | tee /etc/dpkg/dpkg.cfg.d/01-nodoc && \ echo "Acquire::HTTP::Proxy \"${APT_HTTP_PROXY}\";" >> /etc/apt/apt.conf.d/01proxy && \ echo 'Acquire::HTTPS::Proxy "false";' >> /etc/apt/apt.conf.d/01proxy && \ apt-get update && \ apt-get upgrade -y
とくにポイントになるのは、次の二行
echo "Acquire::HTTP::Proxy \"${APT_HTTP_PROXY}\";" >> /etc/apt/apt.conf.d/01proxy && \
echo 'Acquire::HTTPS::Proxy "false";' >> /etc/apt/apt.conf.d/01proxy && \
また、プロキシ設定をビルド時変数で渡す箇所を利用して、再利用性を高める。
ARG APT_HTTP_PROXY
ENV APT_HTTP_PROXY=${APT_HTTP_PROXY}
dockerfile のコツ
docker build を実行するシェルから変数を渡すのに、--build-arg が使える。
Dockerfileでは、ビルド変数を受け取るARG $NAMEがある。
ARG $NAME で受け取った変数をビルド用変数としてENV NAME=$NAMEで展開する。
RUN cmd はENV 変数を使う。
このように書いておけば、Dockerfile にビルド時の変数を使える。
そして、ビルド時に変数を渡す
docker build --build-arg APT_HTTP_PROXY=${APT_HTTP_PROXY}
APTプロキシを使うコツ
プロキシ自体はdocker run sameersbn/apt-cacher-ng で起動できる。
https:// のレポジトリは、httpを強制すれば簡単にプロキシが可能
sed -e 's|https:|http:|' -i /etc/apt/sources.list.d/docker.list
apt update は http でプロキシつながるのは次のような動作背景にある。
- apt update で、http://apt.example.tld/ へ プロキシ経由でアクセスする。
- apt update の結果が取得される。
過去の資料
過去の関連資料です。
- https://takuya-1st.hatenablog.jp/entry/2024/01/15/083000
- https://takuya-1st.hatenablog.jp/entry/2022/04/26/165445
- https://takuya-1st.hatenablog.jp/entry/2020/12/21/040116
apt インストールは「何度も実行する」ために存在するわけではない。通信はプロキシでキャッシュするしか無い。
またaptのRUNより手前を書換えるとdockerfileのキャッシュがうまく効かないんですよね。とくにRUNを1回で済ませようとすると、毎回aptが実行されて、数秒の待ち時間が必要。その待ち時間が10秒でも回数が30回を超えてくると流石に面倒なです。
OpenWRTでパケットをマークして許可する(ポリシールーティング)
WEB-UI ( Luci )を使った場合
Luci で ip rule を作って ip route テーブルを作ることはできる。
前回やったコマンドからのポリシールーティングをLuCI(WEB)経由でやる話です。
やることは次の通り。
nftables でマークを扱う。
マーク済パケットをAcceptする。prerouting で マークする。ip rule でルーティングテーブルを分ける。

nftables のprerouting(マーク条件)を別テーブルにする

ポリシールーティング用のルーティングテーブル
ip rule 設定で、マーク済パケット専用のルーティングテーブルを作る。
設定の Neworking -> routing -> { Static IPv6 route , IPv6 Rule }を編集して次のような設定を作る。
IPv6 Routing の設定

IPv6 Rulesの設定

この結果、次のような設定が作られる。
config route6 option interface 'wg0' option target '2000::/3' option gateway 'fd00:aaa:afac:1919::1' option table '666' config rule6 option lookup '666' option mark '0x29a'
これで専用のルーティングテーブルを作ることができるし、MARKに一致したルールを作ることができる。
この結果はコマンドから確認できる。
ルールが作成される。
> ip -6 rule list 1: from all fwmark 0x29a lookup 666
ルーティングが設定される。
> ip -6 route show table 666 2000::/3 via fd00:aaa:afac:1919::1 dev wg0 proto static metric 1024 pref medium
ルーティングをテストする。(google.comのAAAA経路)
> GGv6=2404:6800:400a:80b::200e > ip -6 route get fibmatch $GGv6 mark 666 2000::/3 via fd00:aaa:afac:1919::1 dev wg0 table 666 proto static metric 1024 pref medium
マーク済パケットの経路が作られたことがわかった。
ファイアウォール設定で、マークを付ける。

config rule option name 'Add Mark' option family 'ipv6' list proto 'all' list src_ip 'fd03:3304:1128:3939::3' option target 'MARK' option set_mark '666' option src 'lan6' option dest '*'
ここで、ミスしちゃいけないのが、source zone をちゃんと入れること。
発信 zoneを入れると、 inet fw4 のmangle_preroutingにルールが作られる。
src zone を適当にAnyとかすると mangle_forwardやmangle_output に入ってしまう。悩ましい
この設定で、nft に次のルールが追加された
> nft list chain inet fw4 mangle_prerouting
table inet fw4 {
chain mangle_prerouting {
type filter hook prerouting priority mangle; policy accept;
iifname "br-lan" ip6 saddr fd03:3304:1128:3939::3 counter meta mark set 0x0000029a comment "!fw4: Add Mark"
}
}
指定したSRC Addr のパケットをマークしている。
マークしたパケットを許可する
マークをつけたパケットを、Forward許可する。

次のような設定ができる。
config rule option name 'Accept Mark' option family 'ipv6' option src '*' option target 'ACCEPT' option mark '666' list proto 'all' option dest '*'
この設定の結果として、nft に次のルールが追加される
> nft list chain inet fw4 forward
table inet fw4 {
chain forward {
type filter hook forward priority filter; policy drop;
meta nfproto ipv6 meta mark 0x0000029a counter accept comment "!fw4: Accept Mark" # これ
## 略
jump handle_reject
}
}
以上によって、マークしてパケットを流せる
OpenWrtLuCIの画面から、ファイアウォールでマークしたパケットを、転送することが出来た。
OpenWRT はいいおもちゃ。
設定がミスっていても、確認できるし。コマンドから強引にパケット通せるし。
やり方がわからないときは、コマンドで作ってから、同じ設定をLuCIで試せばいいし。
メーカ製品を使うと手当たり次第に試す羽目になり、どうしてもストレスを感じる。 マニュアルがあっても正解がわからないので難しい。
その点では、OpenWrtを使えばLinuxだしコマンドで行けるし、WRT限定事象かどうかもUbuntuやRaspiでも試したりでミスの発見を着実に歩みを進められるので本当に嬉しい。
OpenWrtにfw4でポリシールーティングを入れる
OpenWrtでポリシールーティングを入れる
ポリシールーティングを入れると何が嬉しいのか。
OpenWrtの nftables (nft) では inet fw4 のテーブルに全部入っている。
しかしLuciのZONE転送の許可拒否とTraffic Acceptをうまく両立するのが大変だった。
Zone 転送とNAT許可設定でforwardがゴチャゴチャするからシンプルにしたい。
OpenWrtのZONE転送設定はdefault が reject である。
nft で別テーブルを作ってacceptを追加しても、デフォルトのテーブル inet fw4 でZONE転送にマッチしてreject される。コマンドでinet fw4 の forward チェインに許可する設定を追加して forward を acceptする。
しかし、nft table inet fw4 テーブルのforward チェイン記述が大量になる。追いかけるのが面倒になり諦めた。 特に、forwardチェインにIPアドレスを直接記述ルールを大量に書いて全体を見失い、パケット疎通ミスを引き起こしまくった。
そこで、forwardチェインをシンプル制御をうまくやる。このためにマークを使ったポリシールーティングを活用する。
全体の方針
- nftables で パケットにマークを付ける
- openwrt のfw4 にマーク済パケットのFowardをAcceptする設定をいれる。
- ip rule でマーク済パケット用のルーティングテーブルを作る。
パケットをマークしなくても目的は達成できるものの、上記で書いた問題(foward設定が肥大化する)ということがあるので、実験用のネットワークはnftablesの別テーブルに切り出しを実現する。別テーブルでマークする設定を書いておけば、グチャグチャにしても影響範囲は抑えられる。
今回作るネットワーク
ルータ間の転送としてはありふれている

マークしたパケットを別のGWを流したい。
ただ、マークしたパケットを、別の経路で流そうということである。

nftables の処理。
このとき、FowardでAcceptするのはマーク済みのパケットだけとする。

nftables では、prerouting で条件マッチしたパケットにマークを付ける。fowardでマーク済パケットの転送をAcceptする。
ルーティングテーブルやFOWARDチェインに細かい条件を書いていくと数が増えてしまい煩雑になる。
その防止のため、prerouting で仕訳処理を先に済ませ、マークする。
nft のテーブルを分けて管理する。
nftables にはチェインを別テーブルに分割できるので、prerouting を別テーブルに分けてしまう。

パケットをマークする条件を別テーブルにして条件に特化したテーブルを用意して、そこだけ見て管理するようにする。
実際の処理
実際に作った作業は次のとおりになる
OpenWrt でforwardへマーク済みAcceptを入れる。
acceptするルールは、シンプルにする。MARK されたパケットを許可する。
MARK=666
FW4='inet fw4'
HANDLE_REJECT=$(nft -a list chain $FW4 forward | grep handle_reject | grep -oP '(?<=handle )+\d+' )
COMMENT=accept_sample
nft insert rule "$FW4" forward position $HANDLE_REJECT \
mark $MARK counter accept comment "\"takuya: ${COMMENT} \""
結果を確認する。
> nft list chain inet fw4 forward
table inet fw4 {
chain forward {
type filter hook forward priority filter; policy drop;
## Luci で入れたルール
rule ...
# 末尾に追加された
meta mark 0x0000029a counter packets 250 bytes 21272 accept comment "takuya: accept_v6_sample "
jump handle_reject
}
}
末尾(handle_rejectの直前)に、ルールが追加された。
OpenWRT が作るfw4 のforwardテーブルは、default が DROP になっていて、且つ、未マッチはREJECTに送られる。そのためforward中にACCEPTを差込む必要があった。
パケットをマークするnftテーブルを作る
マーキングする条件を書くため専用テーブルを作る。
先ほどマークしたパケットを「Accept」するように書いた。ここでは、指定条件パケットをマーク済にするための新しく別テーブルを作り、その中にチェインを作ったうえで、ルールをいれる。
次の名前で、テーブルを作ってprerouting のチェインを作る。
TABLE='ip6 marking_sample'
nft create table $TABLE
nft create chain "$TBL" prerouting {\
type filter hook prerouting priority filter \; policy accept \; \
}
prerouting で マーク条件を作る。
TABLE='ip6 marking_sample' IIF=br-lan MARK=666 DNET=2404:6800:400a:80b::/64 PC=fd01:b::3/64 nft insert rule $TABLE prerouting \ iifname $IIF ip6 daddr $DNET \ ip6 saddr $PC \ counter meta mark set $MARK
今回書いたサンプル条件は、google.com AAAA 2404:6800:400a:80b::200e(2024-08-16現在)のパケットはマークとした。
この記述で、マッチしたパケットはマーキングされ、inet fw4 forwardを通過するときに、マーク済なのでforward ACCEPTされる。
masquerade の追加
また、マークされたパケットが出ていくときにmasquerade しておく
TABLE='ip6 marking_sample'
OIF=wg0
MARK=666
DNET=2404:6800:400a:80b::/64
nft create chain $TABLE postrouting { \
type nat hook postrouting priority filter\; policy accept \; \
}
nft add rule $TABLE postrouting \
oifname $OIF ip6 daddr $DNET counter masquerade
OpenWrtの場合は、ZONE設定でチェックをいれるとMASQURADEは記入しなくても大丈夫ですが、念の為。
ip rule を作る(ポリシールーティング)
マーク済パケット専用のルーティングが必要。
ここで専用のルーティングテーブルを作る。
MARK=666 GW2=fd00:aaa:afac:1919::1 ip -6 rule del table $MARK >& /dev/null ip -6 rule add fwmark $MARK table $MARK ip -6 route add $DNET dev $OIF via $GW2 table $MARK
ルーティングをテストする
MARK=666 GG=2404:6800:400a:80b::200e ip -6 route get fibmatch $GG mark $MARK
上記のfibmatchを使うと、マッチしたrouting ルールをそのまま表示してくれて便利。add したルールがそのまま表示されればチェック・オッケ。
削除するときは、次のコマンドで
MARK=666 ip -6 rule del table $MARK >& /dev/null ip -6 route flush table $MARK
ミスったらflushしたりdeleteすれば良い。
今回は、google.com AAAAのv6アドレスからサブネット指定した。この宛先アドレスをDNET='2000::/3' にすることで、v6のグローバルIP空間をすべてをルーティング対象にできるはず。2000::/3は::/0 やdefault よりもわかりやすいかと思う。デフォルト使うとリンクローカルとかも混じって面倒かも。
mark をacceptするメリット。
フォワード・チェインが溢れずに済んだ。
nftablesは、jump で書いてもいい。しかし、jump jump であふれかえるとjumpのjumpで追跡が煩雑だった。そしてフォワードでジャンプすると、管理が OpenWrt のLuci生成のfw4 と混在してしまう。Openwrt のデフォルトであるfw4はluci の画面設定に依存する。fw4にコマンドで追記していると、どこで追記されたのか、ジャンプ追跡が煩雑すぎた。luci由来のfw4をあまりゴチャゴチャさせたくない。
また、ルートを変えたいときに、専用のテーブルを触るだけで済むし、一時的に止めたければ、マーク付与テーブルをdelete すれば済むのが嬉しい。
更にnft はhandleを使うのが面倒。jump でルールを書いたり、delete add したり、add flag dormant とかも、ちょっとした作業に毎回変わるHANDLEを探すのが手間で仕方ない。今回用にマークをつけるテーブル消す・テーブル作るで代用すると遊びやすくなった。
そういうことで、nft のHANDLEを使わずに、マークをつかうことにした。見るべき箇所がOpenWrtから切り離した別テーブル(マークを付けるテーブル)に限定できて管理がだいぶ楽になりました。
v6 NAT
今回の例は、v6 で NAT66 する例になるのだけど、v6 でNATをする意味ないって思うかもしれないけど、v6 NATも使えると割と便利なんですよね。
「IPv6ではNATをしない(不要)」などと教科書には書いてるけど、NATあったほうが絶対便利。好きなIPoEの接続点を出口に据えて、任意ISPから出て回線テストもしやすい。やっぱりv6 NATはアリじゃないかな。
セキュリティについてもNATは防波堤になり得る気がする。グローバルIPv6で通信するv6は、OSのファイアウォール機能に依存するわけで。OSに脆弱性、つまりLinuxのnftablesやWindowsファイアウォールに脆弱性があった場合は、大事故になると思うんですね。またユーザーがコピペで安易な許可設定をしてしまう可能性も怖い。
windows のTCP/IP v6の脆弱性
NAT66するべきだと思う理由にゼロデイ攻撃がある。
グローバルIPが割り当てられていると、OSの脆弱性の影響をもろに受ける。
OSのFWに脆弱性があると、グローバルIPが割あたっているすべての端末に影響が出る。
そう思っていたのだが、出てしまった。出てしまったのです。脆弱性が
CVE-2024-38063でWindowsのTCP/IPのスタック脆弱性でリモートコードの実行されるゼロデイ発覚していた。
パッチでるまでv6 オフにするレベル。ってやつです。
緊急パッチはでたものの・・・やっぱり、NAT66でNATもありなかって考えました。端末のIPを管理するにしてもULAのほうが何かと楽かも・・・
TCPなのでFWでCONNECTEDを見てれば大丈夫なはずではある。v6関連のチェックが甘くてstate new が通っちゃったりしてないですよね。
今回はv6 NAT とポリシールーティングで指定PCのGWを変えた。
今回は、OpenWrtのfw4 やLuciを使わずに、指定PCや指定サブネットだけは、v6 空間に出られるようにする設定を試してみた。
wireguardやStrongswanのようなVPNと組み合わせて、好きな箇所からv6アドレス出ていけるし設定をシンプルにする目処がたった
Linux箱をルータにしておくとちょっとした思いつきが試せて良いね。
nft で指定位置にinsert する
nft で指定位置にinsert する
既存のルールが次のようになっているとき
table inet fw4 {
chain forward { # handle 2
type filter hook forward priority filter; policy drop;
$EXISTS_RULE # handle 2340
$EXISTS_RULE # handle 2341
$EXISTS_RULE # handle 2345
$EXISTS_RULE # handle 2346
jump handle_reject # handle 2352
}
}
指定位置(jump handle_reject 2532 ) の直前にルールを入れたい
nft insert rule inet fw4 forward position 2352 mark 666 counter accept
結果は次のようになっている
table inet fw4 {
chain forward { # handle 2
type filter hook forward priority filter; policy drop;
$EXISTS_RULE # handle 2340
$EXISTS_RULE # handle 2341
$EXISTS_RULE # handle 2345
$EXISTS_RULE # handle 2346
meta mark 0x0000029a accept # handle 2563 <=== 挿入
jump handle_reject # handle 2352
}
}
HANDLEを探す
末尾の一つ前に入れたいとき、特定のルールの直前に入れたいときなどあるだろうが、grep して探すしか無い。
GREPできるようなコメントがとても重要になってくる。
TBL='inet fw4' CHAIN='foward' UNIQUE='handle_reject' nft -a list chain $TBL $CHAIN | grep handle_reject | grep -oP '(?<=handle )+\d+'
ユニークなコメントが有ると、ハンドル探索が楽。
TBL='my_table' UNIQUE_COMMENT=':Quu9xeik' nft -a list table $TBL | grep $UNIQUE_COMMENT | grep -oP '(?<=handle )+\d+'
直後はADD
insert の変わりに、ADDもできる
nft add rule $TBL $CHAIN position 2352 mark 666 counter accept
指定位置のinsertが便利
特定のルールの直前に挿入(INSERT)と特定のルールの直後に追加(ADD)をができるのは、nftの特徴で便利。
ファイアウォールは先頭の一つあとや末尾の1つまえをよく使うと思うので、よく使う挿入箇所はショートカット出来てほしいところ・・・悩ましい。
nftablesのfowardが記述が大量になる問題。
nftablesのテーブルのルールがあふれる
どんなに整理しても、既存のforward テーブルがあふれかえることは避けられない。
細かく条件を入れればいれるほど、forward テーブルに処理が集中してしまい、結局のところiptables時代と何も変わらない気がします。
table inet fw4 {
chain forward {
# policy DROPなのでACCPETを列挙するのだが
type filter hook forward priority filter; policy drop;
$RULE_001 jump_to_accept
$RULE_002 jump_to_accept
$RULE_003 jump_to_accept
$RULE_004 jump_to_accept
$RULE_005 jump_to_accept
# ... あふれかえる Accept
$RULE_256 accept
jump handle_reject
}
chain handle_reject {
reject comment "!fw4: Reject any other traffic"
}
}
jump 先にjumpがあったりすると、追いかけるのが面倒になり嫌になる。
既存テーブルと干渉しやすいから躊躇する
iptablesのときもそうだったけど、ルールが増えてくると追いかけるのが面倒になる。新規でルールを突っ込むのを躊躇します。
OpenWrtのようなnftableを自動生成するソフトウェアが入ってると尚更です。
initスクリプトで追加したのか、GUIからの自動生成かが全くわからん。誰がいつどこでなんのために入れたのか。メモが残せない。
解決策1 commentを使う。
いちばん簡単な解決策はコメントを使う。
table inet fw4 {
chain forward {
type filter hook forward priority filter; policy drop;
$RULE_001 jump_to_accept comment "# by takuya for Router A "
$RULE_002 jump_to_accept comment "#!fw4 handle ..."
$RULE_003 jump_to_accept comment "# by takuya for Router Be "
$RULE_004 jump_to_accept comment "# org.example.www "
$RULE_005 jump_to_accept
# ... コメントにも限界が。。。
$RULE_256 accept
jump handle_reject
}
}
コメントに、識別IDや名前空間を編み出してルール化することになる。のだけど、nftablesってjump / goto で関数のようにルールを使い回せるのが魅力じゃん。
だったら一つのforwardテーブルに集中するのって、本末転倒な気がしなくもない。
解決策2 ポリシールーティングをする
コメントでもあふれることは避けられないのだから、指定パケットは、別にルーティングを用意して、メインのnftablesのテーブルとは全く別の許可設定やとルーティングするようにしたほうがすっきるするかもしれない。
ポリシールーティングの例
マークの有無でパケットをフィルタリングする。
マークしたパケットを許可すれば良い
nft insert rule $TABLE forward mark $MARK counter accept
なので、マークを付けるまでの箇所でルールをいっぱい作れる。
nft_table_name=takuya_mangle iif=eth1 oif=wan2 GW2=10.0.0.2 mark_num=1111 to_addr='1.1.1.1/32' MAIN_TABLE='inet fw4' # -- ルーティングテーブルを追加 ip rule add fwmark $mark_num table $mark_num ip route add $to_addr dev $OIF via $GW table $mark_num # -- nftables でごちゃごちゃとマーク nft create table ip $nft_table_name nft create chain ip $nft_table_name prerouting nft insert rule ip $nft_table_name prerouting \ iifname $iif ip daddr $to_addr \ counter meta mark set $mark_num \ comment \"takuya_mangle_sample\" ## マークしたパケットを許可 nft insert rule $MAIN_TABLE forward mark $mark_num counter accept
このように書いておけば、マーク済パケットをFoward許可なので、prerouting でマークするときに条件を書くので、forwardにはマークだけになり、set mark している箇所を探せば良くなり、forwardにルールが増えないのでとても便利になる。jump 記述を捨てられる。
上記の例のように、マーク済のパケットのDefaultルートを変更できるので、特定PCからの特定宛先だけは別経路を通るように設定できるし、Fowardにはマークだけになってルールはシンプルになる。
ip route add src xxxで ソースのアドレスも指定できるのだけどテーブルを分けたほうが楽だよね。
これにより、fowardのAccept、DROPの順番などを意識せずに、マークを付けたか付いてないかで判断すれば良くなる。つまり条件でマッチするしないをmark unset / mark set の問題に置き換えることができて、複雑化する条件を管理することができる。
解決策3
まとめられるものはまとめる。
nftables は ipset が使えるので、@name= { .... } のリストを使ってできる限りまとめる。
nft insert rule inet fw4 prerouting iifname $IIF ip saddr @ipset_01 counter
また、nftables は { "A" , "B" } の列挙ができるので、まとめられるものはできる限りまとめる。
nft insert rule inet fw4 prerouting iifname { "wan1", "wan2" } ip saddr @ipset_01 counter
ipset の代わりにグルーピングする追加例
nft add table my_table
nft add set my_table my_pc { type ipv4_addr \; flags interval \; }
nft add element inet my_table my_pc { "192.168.1.100" }
nft add element inet my_table my_pc { "192.168.1.101" }
追加結果は次のようになる。
table my_table {
set my_pc {
type ipv4_addr
flags interval
elements = { 192.168.2.100, 192.168.2.101 }
}
}
上記のようにすると、my_table 中のルールで@my_pc という配列が使える。配列が@マークなのは、なんかBashっぽいけど我慢
ただ、まとめすぎると、なぜ「グルーピング」したのかわからなくなるので、これも辛いところ。
なやましい
とりあえず、先頭にINSERTしておけばなんとかできたiptablesが愛おしい。
仮想マシン上にnftablesをいっぱい用意して用途別にnftablesをべつマシンで処理したほうが良くねーかもう。
昔ながらのFWに万能を求めアレコレと処理するというアプローチが間違ってる気がする。
仮想ネットワークと仮想マシンで用途別にパケットをさばくルーティングをするルーティングPC群として設計したほうが影響範囲を絞って耐障害性も誤操作寛容性も上がるんじゃないのかなぁ。
小さな物を組み合わせて大きなものを作るというアプローチで、小さなFWを仮想ネットワークで組み合わせて巨大なFWを構成するというアプローチが現代的なんだろうなぁ。
そうなるとnftablesっている?
nftablesでaccept後のdropにマッチを回避できない。
nftablesでacceptとdropにマッチするとdropになる問題
nftablesを使ってると、accept しても他のテーブルでreject(drop)されてしまうことがある。
複数テーブルでaccept と dropが混合しちゃう
例えば、tableAとtableBにforwardの許可設定を書くわけよ。tableAでAcceptしてるのに、tableBで reject されるから、結果として reject になっちゃう。
table ip tableA {
chain forward {
type filter hook forward priority filter; policy drop;
iifname br0 oifname eth1 ip6 daddr 1.1.1.1 accept comment "# cf"
jump handle_reject
}
}
table inet tableB {
chain forward {
type filter hook forward priority filter; policy drop;
$RULE_A accept
jump handle_reject
}
}
8.8.8.8へのforwardを許可する例と拒否する例を同時に入れる。
例えば、8.8.8.8 との通信を許可(Accept)と拒否(Reject)を同時に入れるとどうなるかを見てみよう。
先に結果を述べておくと accept & rejectつまり、true & false となり結果はfalse(拒否・REJECT)になる
8.8.8.8 をforward accept する
nft create table ip allow8888
nft create chain ip allow8888 forward { type filter hook forward priority filter\; policy drop\; }
nft add rule ip allow8888 forward iifname br0 oifname wan0 ip daddr 8.8.8.8 counter accept
nft list table ip allow8888
8.8.8.8 をforward reject する
nft create table ip deny8888
nft create chain ip deny8888 forward { type filter hook forward priority filter\; policy accept\; }
nft add rule ip deny8888 forward iifname br0 oifname wan0 ip daddr 8.8.8.8 counter reject
nft list table ip deny8888
パケット送るとreject(unreachable)になる
PS C:\Users\takuya> ping 8.8.8.8 Pinging 8.8.8.8 with 32 bytes of data: Reply from 192.168.1.1: Destination port unreachable. Reply from 192.168.1.1: Destination port unreachable. Reply from 192.168.1.1: Destination port unreachable. Reply from 192.168.1.1: Destination port unreachable.
カウンタ結果は次のようになる。
table ip deny8888 {
chain forward {
type filter hook forward priority filter; policy drop;
iifname "br0" oifname "wan0" ip daddr 8.8.8.8 counter packets 8 bytes 520 reject
}
}
table ip allow8888 {
chain forward {
type filter hook forward priority filter; policy drop;
iifname "br0" oifname "wan0" ip daddr 8.8.8.8 counter packets 8 bytes 520 accept
}
}
カウンタ結果を見ると一目瞭然だが、両方のカウンタが回っている。すなわち、パケットは正しく処理されている。AcceptされたあとにRejectが評価されるのだ。
これはPriorityだろうと思うかもしれ無いが、優先度を変えても結果は同じである。accept が先に処理されてもあとからRejectされるし、Rejectを先にするとAcceptまで到達しない。
ということなので、ブロックされるルールの直前にルールを差し込む必要がある。
どうしたらいいんだ。nftables。accept箇所の先もあるんだ。Acceptでは移行をスキップできないんだ止まらいんだ。どうすれば良いのか。
ちゃんと、insert して指定場所に突っ込むしか無い。
めんどくさいことこの上ないが、ちゃんとルールをINSERTして指定場所に差し込む必要がある。
そうすると、こんどはforwardにルールが集中してしまう、そしてjump があるために、追いかけるのが更に面倒になる。
forwardを見てもjump 、jump jump jump の多段Jumpが大量に記載されることになり、iptablesより追いかけるのが面倒になり・・・
困っちゃうよ。nftables
jump 追いかけるのが面倒。
複数テーブルと複数のチェインがあるので、追いかけにくい。どこでDropされてるのかはcounterを入れて調べることができる。jump さきで jump されてしまうと脳内メモリが追いつかない。
しかし、drop されているルールを回避するのはめんどくさい。
nftables test dump みたいなコマンドがほしい。どのjumpを通ってどこにマッチしてdrop/rejectされてるのか追いかけるのが大変だよ。
nft monitor trace
一応、nft monitor と meta nftrace set 1 で追いかけることができるのだが。
nft add chain inet fw4 filter { type filter hook prerouting priority -301\; }
nft add rule inet fw4 filter trace_chain meta nftrace set 1
nftace がなんか動かないんですよねぇ。
Error: syntax error, unexpected meta add rule inet fw4 filter trace_chain meta nftrace set 1
もしかしたら、カーネルモジュール??
counterで地道に追いかけてるけど地獄。。。
nftables で、パケットが該当ルールに届いているかチェックする方法
nftables で、パケットが該当ルールに来ているかチェックする方法
パケットの行先が不明のとき、どこまでマッチしているか調べる必要がある。このときcounter を使うのが一番簡単。
例えば、Google(v6) 宛のパケットを探したい
次のように、ターゲットとなるチェインにカウンタをINSERTする。
GGv6='2404:6800:400a:80b::200e' TBL='inet fw4' CHN='handle_reject' nft insert rule $TBL $CHN meta nfproto ipv6 ip6 daddr $GGv6 counter
このように、カウンタをいれる。実際にはもっと具体的な条件で挟む。( iifname / oifname / ip6 saddr / daddr など具体的に。)
カウンタが進むかチェックする
カウンタをいれたチェインを確認する
nft list chain $TBL $CHN
最初は、パケット数=0、バイト数=0である。
table inet fw4 {
chain handle_reject {
ip6 daddr 2404:6800:400a:80b::200e counter packets 0 bytes 0
meta l4proto tcp reject with tcp reset comment "!fw4: Reject TCP traffic"
reject comment "!fw4: Reject any other traffic"
}
}
ping などでパケットを送ってみる。
ping 2404:6800:400a:80b::200e Destination port unreachable. Destination port unreachable. Destination port unreachable. Destination port unreachable.
パケット数を再確認します。
nft list chain $TBL $CHN
カウントが進んでいるのがわかります。パケット数=4、バイト数=320
table inet fw4 {
chain handle_reject {
ip6 daddr 2404:6800:400a:80b::200e counter packets 4 bytes 320
meta l4proto tcp reject with tcp reset comment "!fw4: Reject TCP traffic"
reject comment "!fw4: Reject any other traffic"
}
}
このように、パケットの「カウント」を任意の場所に条件付きで挟み込んで、どこのチェインで処理されたかを知ることができる。
特に、reject / drop の手前に差し込むと効果がある。
nft がおかしいときは counter で探す。
accept -> accept -> reject のように accept後にどこかでreject されてパケットが捨てられる可能性が高いためである。
nftablesでは、複数テーブルで処理されて、chainA accept && chainB reject => reject のように複数チェインのどこかでDROPやREJECTされてしまい、気付かないうちにDROPされて届かないということが頻発する。
そのため、カウンタでどこに来ているかを慎重にチェックしないと、思わぬところでリジェクトされて届かない。
Gitlab をAPIで使ってレポジトリ(プロジェクト)を管理。レポジトリのコピーと移動
Gitlab を整理したんですが。
レポジトリの取捨選択と移動が手間なので、APIでコマンドから行いました。
レポジトリを整理し選抜して新サーバーに移動するかどうか決めるときに、100件くらいと削除を繰り返すのが面倒だったので、インポートを使わずに必要なレポジトリだけをclone して push することにした。
Gitlab のAPIで解決させる
APIはパーソナルアクセストークンを使って、プロジェクトの一覧、グループの一覧、グループのプロジェクトの一覧から、プロジェクトのレポジトリを一覧したり削除したり、新規作成できる。
APIを使って面倒な削除処理とClone処理を少しでも改善することにする。
GitLabのAPIを使う。
APIを使えば、アクセス可能なプロジェクトの名前やURLを取得し、git clone や git push を連続的に行うことができる。
APIキーの作成
パーソナルトークンを発行する。

ここで発行したアクセス・トークンを使う。
APIキーのテスト(自分のユーザー情報を取得)
自分のユーザー情報
MY_TOKEN=glpat-XXXXXXXXX-2g HOST=git.example.com ## 確認する。 curl -s -H "PRIVATE-TOKEN: $MY_TOKEN" "https://$HOST/api/v4/user" | jq -r .id ## 保存する。 USERID=$(curl -s -H "PRIVATE-TOKEN: $MY_TOKEN" "https://$HOST/api/v4/user" | jq -r .id)
このように、TOKENを使えば簡単にアクセスできることがわかる。TOKENの確認に自分のユーザー情報取得し、動作チェックすとする。
プロジェクト一覧を取得する
自分がアクセス可能なプロジェクト一覧を取得する。
MY_TOKEN=glpat-XXXXXXXXX-2g HOST=git.example.com curl --header "PRIVATE-TOKEN: $MY_TOKEN" "https://$HOST/api/v4/projects"
自分のプロジェクト一覧
自分のパーソナルなプロジェクト(レポジトリ)を一覧する。
MY_TOKEN=glpat-XXXXXXXXX-2g HOST=git.example.com USERID=$(curl -s -H "PRIVATE-TOKEN: $MY_TOKEN" "https://$HOST/api/v4/user" | jq -r .id) curl -H "PRIVATE-TOKEN: $MY_TOKEN" "https://$HOST/api/v4/users/$USERID/projects" | jq .
一覧系は、all_available をつけないと、一部が欠損する。
グループ一覧
MY_TOKEN=glpat-XXXXXXXXX-2g HOST=git.example.com curl --header "PRIVATE-TOKEN: $MY_TOKEN" "https://$HOST/api/v4/groups?all_available=yes&top_level_only=yes"
一覧系は、all_available をつけないと、一部が欠損する。
グループ内のプロジェクト一覧
MY_TOKEN=glpat-XXXXXXXXX-2g HOST=git.example.com curl --header "PRIVATE-TOKEN: $MY_TOKEN" \ "https://$HOST/api/v4/groups/154/projects"
bashやjs で使いやすく可能する
プロジェクトを見やすく、整形して加工する。配列などにしておけば、シェルコマンドから使いやすい。
MY_TOKEN=glpat-XXXXXXXXX-2g
HOST=git.example.com
USERID=$(curl -s -H "PRIVATE-TOKEN: $MY_TOKEN" "https://$HOST/api/v4/user" | jq -r .id)
curl -H "PRIVATE-TOKEN: $MY_TOKEN" "https://$HOST/api/v4/users/$USERID/projects" > p.json
cat p.json | jq '[ .[] | { id:.id, name:.name, desc: .description , path: .path, ssh: .ssh_url_to_repo } ]'
cat p.json | jq .[] | jq ' "\(.name) \(.ssh_url_to_repo)" ' -r
cat p.json | jq .[] | jq ' "\"\(.path)\": \(.ssh_url_to_repo)" ' -r
cat p.json | jq .[] | jq ' "project=\"\(.name)\";project_path=\"\(.path)\"" ' -r
プロジェクト個別の情報を見る。
プロジェクトの設定情報や参加者などを個別に見る。
PRJID=55 curl -X GET -H "PRIVATE-TOKEN: $MY_TOKEN" "https://$HOST/api/v4/projects/$PRJID"
プロジェクトを消す。
要らないな。と思ったプロジェクト消す。
PRJID=55 curl -X DELETE -H "PRIVATE-TOKEN: $MY_TOKEN" "https://$HOST/api/v4/projects/$PRJID"
もっと簡単にまとめて消す
ARR='35 37 39'
for i in $ARR; do
echo $i
curl -s -X DELETE -H "PRIVATE-TOKEN: $MY_TOKEN" "https://$HOST/api/v4/projects/${i}" | jq .
done
WEB画面から行うと確認が入ってめんどくさいので、APIから削除する。削除は即座に行われる。二度と復活できない。
プロジェクトをまとめてCloneする。
自分の個人プロジェクトのレポジトリをまとめてgit clone する。
MY_TOKEN=glpat-XXXXXXXXX-2g HOST=git.example.com USERID=$(curl -s -H "PRIVATE-TOKEN: $MY_TOKEN" "https://$HOST/api/v4/user" | jq -r .id) curl -H "PRIVATE-TOKEN: $MY_TOKEN" "https://$HOST/api/v4/users/$USERID/projects" > p.json cat ../p.json | jq .[] | jq '.ssh_url_to_repo' \ | xargs -I@ git clone @
プロジェクトを作成する。
プロジェクトの作成をする。
TOKEN2=glpat-TOKE2
HOST2=other.gitlab.example.tld
JSON='
{
"name": "sample-webui",
"path": "sample-webui",
"initialize_with_readme": false
}
'
curl -X POST -H "PRIVATE-TOKEN: $TOKEN2 " \
-H "Content-Type: application/json" \
--data "$JSON" \
--url "https://$HOST2/api/v4/projects/"
プロジェクトのレポジトリへまとめてPushする。
以上を踏まえて、一括してgit clone て、一括してgit push する。
ここまでの例を使って、すでに不要なプロジェクトを消したので、残るのは別サーバーに移動するものだけが残っています。
例えば、下記のようにgitlab間のレポジトリのコピーを行うことができる。
TOKEN01=glpat-TOKEN-11
HOST1=git.example.com
TOKEN02=glpat-TOKEN-22
HOST2=other.gitlab.example.tld
HOST2_SSH_PORT=23456
function list_ssh_url_to_repo(){
USERID=$(curl -s -H "PRIVATE-TOKEN: $TOKEN01" "https://$HOST1/api/v4/user" | jq -r .id)
curl -H "PRIVATE-TOKEN: $TOKEN01" "https://$HOST1/api/v4/users/$USERID/projects" \
| jq .[] | jq ' "\"\(.path)\" \"\(.ssh_url_to_repo)\"" ' -r
}
function create_project(){
name=$1
JSON="{ \"name\": \"${name}\", \"path\": \"${name}\",
\"initialize_with_readme\": false }"
curl -s -X POST -H "PRIVATE-TOKEN: $TOKEN02 " \
-H "Content-Type: application/json" \
--data "$JSON" \
--url "https://$HOST2/api/v4/projects/"
}
function push_repository(){
name=$1
cd $name
pwd
git remote rename origin old-origin
## とりあえず、自分のユーザーに固定する。
git remote add origin ssh://git@${HOST2}:$HOST2_SSH_PORT/takuya/${name}.git
git push --set-upstream origin --all
git push --set-upstream origin --tags
cd ..
}
## HOST1 のレポジトリを一旦手元にコピーして
mkdir work
cd work
for $url in $( list_ssh_url_to_repo ) ; do
git clone $url
done
# HOST2 へ全部pushする。
for name in $( ls -l ); do
create_project $name
push_repository $name
done
cd ..
rm -r work
もちろん、プロジェクトのTODOや作業ログを含めて移動するとなると、凝ったスクリプトにするとか、バックアップを使う必要があるけど、プロジェクトのレポジトリを移動するだけなら、APIでURLを出して、git clone して、新しいGitLabにプロジェクト作成してgit push すれば良いわけです。
gitlabやgithubを使わずに、ベアレポジトリを扱ってたら、「プロジェクト」の概念がなかったのでもっと簡単だったのですが。
レポジトリを保存するだけに、プロジェクト単位になるのはちょっとした作業になりますね。
vscodium - VSCode の自由ソフトウェア版に移行する。
vs code は MSなので将来が不安
MSはいまは、とてもフレンドリーに見えるとはいえ、過去の行動を考えると不安だ。
また、Googleが自由ソフトウェアを食い物にしている現状を考えてもVS Codeは今後に不安を覚える
VS Codium に移行する
そんなに気にすることでもないかもしれないが。

MS VSCode に利用状況といえど、蒐集されるのは、気分がいいものではない。
インストール
chco install vscodium
起動など
ロゴに著作権があるので、ロゴは変わるが、その他で特筆すべき変化はない。


何ら通常と変わらない。

しばらく使ってみることにする。
エディタのタブサイズを設定した。

PlainTextファイルはタブサイズを「別途」で指定しないと上書きできないようになってた。TAB=8はデカすぎるねん。
Windowsの右クリックメニューを占拠された
VSCodiumでもVs Code と同じようにすべてのファイルに対する右クリックメニューが作られた。こういうところは真似しなくて良いんですよ。。。
## VS Code 同様にCodiumがうるさいので消す。 New-ItemProperty -LiteralPath 'HKLM:\SOFTWARE\Classes\Drive\shell\VSCodium' -Name 'LegacyDisable' -PropertyType 'String' -Value '' Move-Item -LiteralPath 'HKLM:\SOFTWARE\Classes\Drive\shell\VSCodium' -Destination 'HKLM:\SOFTWARE\Classes\Drive\shellex\VSCodium' New-ItemProperty -LiteralPath 'HKLM:\SOFTWARE\Classes\Directory\shell\VSCodium' -Name 'LegacyDisable' -PropertyType 'String' -Value '' Move-Item -LiteralPath 'HKLM:\SOFTWARE\Classes\Directory\shell\VSCodium' -Destination 'HKLM:\SOFTWARE\Classes\Directory\shellex\VSCodium' Move-Item -LiteralPath 'HKLM:\SOFTWARE\Classes\*\shell\VSCodium' -Destination 'HKLM:\SOFTWARE\Classes\*\shellex\VSCodium'
VSCodeと同じように消すことになった
.bat ファイルのように、Openを上書きできないものは、Shellメニューに追加する。
## vs code 開くに追加 ## .bat New-Item -Path 'HKCU:\SOFTWARE\Classes\batfile' -ItemType Directory New-Item -Path 'HKCU:\SOFTWARE\Classes\batfile\shell' -ItemType Directory New-Item -Path 'HKCU:\SOFTWARE\Classes\batfile\shell\VSCodium' -ItemType Directory New-Item -Path 'HKCU:\SOFTWARE\Classes\batfile\shell\VSCodium\command' -ItemType Directory New-ItemProperty -Path 'HKCU:\SOFTWARE\Classes\batfile\shell\VSCodium' -Name 'Icon' -Value "C:\Program Files\VSCodium\VSCodium.exe" New-ItemProperty -Path 'HKCU:\SOFTWARE\Classes\batfile\shell\VSCodium\command' -Name '(Default)' -Value '"C:\Program Files\VSCodium\VSCodium.exe" "%1"'
wsl で xming(vcxsrv) 経由で mpv を起動する。
wsl からXwindowのウインドウアプリを起動するには
WSLでウインドウを使うアプリ起動するには、WSLからX Window サーバーに接続すれば良い。
https://takuya-1st.hatenablog.jp/entry/2020/11/08/135059
殆どの場合は、これで動く
mpv は動かない
mpv は openGLが必要なのでそのままだとエラーになる。
大きく分けて2つのエラーが出てくる
error: XDG_RUNTIME_DIR is invalid or not set in the environment. X Error of failed request: GLXUnsupportedPrivateRequest
- XDG_RUNTIME_DIR がない
- GLX が使えない
いかにエラーメッセージを残しておく。
[vo/gpu/x11] X11 error: BadRequest (invalid request code or no such operation) [vo/gpu/x11] Type: 0, display: 0x7fe33c003f80, resourceid: 5a, serial: 10 [vo/gpu/x11] Error code: 1, request code: 92, minor code: 19 [vo/gpu/opengl] Suspected software renderer or indirect context. [vo/gpu] VT_GETMODE failed: Inappropriate ioctl for device [vo/gpu/opengl] Failed to set up VT switcher. Terminal switching will be unavailable. [vo/gpu/opengl] Listing DRM devices with drmGetDevices failed! (No such file or directory) [vo/gpu/opengl] Failed to find a usable DRM primary node! [vo/gpu/opengl] Failed to create KMS. [vo/gpu-next/x11] X11 error: BadRequest (invalid request code or no such operation) [vo/gpu-next/x11] Type: 0, display: 0x7fe33c0d0820, resourceid: 5a, serial: 10 [vo/gpu-next/x11] Error code: 1, request code: 92, minor code: 19 [vo/gpu-next/opengl] Suspected software renderer or indirect context. [vo/gpu-next] Can't handle VT release - signal already used [vo/gpu-next/opengl] Failed to set up VT switcher. Terminal switching will be unavailable. [vo/gpu-next/opengl] Listing DRM devices with drmGetDevices failed! (No such file or directory) [vo/gpu-next/opengl] Failed to find a usable DRM primary node! [vo/gpu-next/opengl] Failed to create KMS. [vo/vdpau/x11] X11 error: BadRequest (invalid request code or no such operation) [vo/vdpau/x11] Type: 0, display: 0x7fe33c0d0820, resourceid: 5a, serial: 10 [vo/vdpau/x11] Error code: 1, request code: 92, minor code: 19 Failed to open VDPAU backend libvdpau_nvidia.so: cannot open shared object file: No such file or directory [vo/vdpau] Error when calling vdp_device_create_x11: 1 [vo/xv/x11] X11 error: BadRequest (invalid request code or no such operation) [vo/xv/x11] Type: 0, display: 0x7fe33c0d0820, resourceid: 5a, serial: 10 [vo/xv/x11] Error code: 1, request code: 92, minor code: 19 Xlib: extension "XVideo" missing on display "127.0.0.1:0.0". [vo/xv] Xv not supported by this X11 version/driver X Error of failed request: GLXUnsupportedPrivateRequest Major opcode of failed request: 143 (GLX) Minor opcode of failed request: 17 (X_GLXVendorPrivateWithReply) Serial number of failed request: 124 Current serial number in output stream: 124
対応 XDG_RUNTIME_DIR
XDG_RUNTIME_DIR が無いのであれば作れば良い。
export XDG_RUNTIME_DIR=/tmp/xdg-runtime-$USER mkdir -p $XDG_RUNTIME_DIR chmod 700 $XDG_RUNTIME_DIR
対応 OpenGL (GLX) をつけて起動
VcXsrv を起動するときに、Windows のOpenGLを使うように指定しておく
"C:\Program Files\VcXsrv\vcxsrv.exe" :0 -multiwindow -clipboard -wgl
注意事項として、VcXsrv を使うこと。Xmingの場合は GL 関連のライブラリが含まれてないことがるので、Xmingのビルドとインストールを見直す必要がある。( -wglオプションがなかった )めんどうだったんだよね。VcXsrvなら動いたのでこっちを使うことにした。
次のように起動した

タスクトレイに常駐している

WScript(JScript)で起動する場合は、スペースがうざいが、次のようにする。
var ws = WScript.Createobject("WScript.Shell")
ws.Run('\"C:/Program Files/VcXsrv/vcxsrv.exe\" :0 -multiwindow -clipboard -wgl',0)
mpv 起動
以上のことを終わらせると、mpv を起動することができた。

サウンド再生
ただ、まだサウンドがでてこない。
X Windowサーバーにあれこれ設定しても多分徒労なので、PulseAudio をネットワーク越しに使うことにする。
C:/Users/takuya/AppData/Roaming/PulseAudio/bin/pulseaudio.exe
以上で、MPVをWSLのコンソールから使うことができた。
まとめ
wsl で mpv をインストールして動画再生
## wsl 側 sudo apt update && sudo apt install mpv export DISPLAY=localhost:0.0 export XDG_RUNTIME_DIR=/tmp/xdg-runtime-$USER mkdir -p $XDG_RUNTIME_DIR chmod 700 $XDG_RUNTIME_DIR
choco install vcxsrv "C:\Program Files\VcXsrv\vcxsrv.exe" :0 -multiwindow -clipboard -wgl
再生開始
# wsl から mpv http://127.0.0.1/example/sample.mp4
サウンドに関しては、PulseAudioのインストールを参考に設定する。
これで、mpv をコマンドから扱えるので、mpv に関する調査をするのに、Ubuntuマシンを用意せずに済む。Windowsから行える。便利。
2024-08-09
WScript で起動する方法を追加。
mpv でキー操作を書き換える。
mpv のスキップ機能が不便なので改善する。
mpv はinput.conf で キー操作を上書き(変更)できるので、設定を変更して便利に使いたい。
設定ファイルの場所と・作成
touch ~/.config/mpv/input.conf cat ~/.config/mpv/input.conf
設定ファイルはGlobalでもUserでもどちらでもいい
~/.config/mpv/input.conf
UP osd-msg seek 300 exact DOWN osd-msg seek -300 exact RIGHT osd-msg seek 20 exact LEFT osd-msg seek -20 exact
キーと、操作内容を書いた.
osd-msg は画面に現在の再生位置を表示する。osdは on screen display とかでよく使われる用語。ここの s は status の s かもれしれない。設定自体は--osd-on-seek=<no,bar,msg,msg-bar> に相当する。
再生スキップ時に何分スキップしたか見えないと不便なので、をon にしてる。
seek で 指定秒数をスキップする。書式は、seek <target> [<flags>]
この設定を応用すれば、スクショを撮ってその場でアップロードとかもできるかもしれない。
参考資料
mpv の設定を書いて、起動オプションを省略する
mpv の設定は以下の場所に設置できる。
上記に設定ファイル(mpv.conf)を設置すると、起動時に読み込まれる。
ファイル名も固定で指定できて/etc/mpv/{mpv.conf,input.conf} のファイルを指定できる。input.conf はキー操作に関する設定。mpv.conf は起動オプションに関する設定である。ファイル名も設定で変えられるはずだが、変えないほうが無難だと思う。
設定例
たとえば、コマンドのオプションの次の場合
mpv --fullscreen
設定ファイルは次のようになる。
touch ~/.config/mpv/{mpv.conf,input.conf}
## 設定例 fullscreen=yes
引数で=XX と変数を与えない場合、つまり引数の有無で判断する場合は、YESを書いてあげる。
つぎに、コマンドのオプションで値を与える場合
mpv --audio-device=alsa/sysdefault
値がある場合は次のようになる。
## 設定例 audio-device=alsa/sysdefault
この場合は、設定ファイルにそのまま書けばいい
起動オプションと設定の対応
設定自体は、公式サイトに解説がある。
公式サイトの解説によれば、次のように対応してる。
| Option | Configuration file entry |
|---|---|
| --flag | flag |
| -opt val | opt=val |
| --opt=val | opt=val |
| -opt "has spaces" | opt=has spaces |
設定例
設定書式は INI 形式である。
# normal top-level option fullscreen=yes audio-device=alsa/sysdefault hr-seek=yes #hr-seek-demuxer-offset=20 #hr-seek-framedrop=no # a profile that can be enabled with --profile=big-cache [big-cache] cache=yes demuxer-max-bytes=512MiB demuxer-readahead-secs=20 [network] profile-desc="profile for content over network" force-window=immediate # you can also include other profiles profile=big-cache [reduce-judder] video-sync=display-resample interpolation=yes # using a profile again extends it [network] demuxer-max-back-bytes=512MiB # reference a builtin profile profile=fast
こんな感じに色々と設定できる。