OpenWrt IPv6プロビジョニングAPI エンドポイントまとめ

:flag_jp: Japanese notation

# PCN（プロビジョニングコントロールネーム）API
::: note
### MAP-Eのルール情報構造
<details><summary>JSON仕様</summary>

```
brIpv6Address: Border Relay（BR) IPv6アドレス
eaBitLength: EA-bit長（IPv4アドレス内にユーザー識別用ビットを何ビット使うか）
ipv4Prefix: 割り当てIPv4プレフィックス
ipv4PrefixLength: IPv4プレフィックス長
ipv6Prefix: 利用者側IPv6プレフィックス
ipv6PrefixLength: 利用者側IPv6プレフィックス長
psIdOffset: PSIDオフセット
```
---
</details>

<details><summary>ipv6PrefixLength</summary>

```
ipv6PrefixLength = 56 - eaBitLength
eaBitLength = 56 - ipv6PrefixLength
ipv6PrefixLength + eaBitLength = 56

ipv6PrefixLength = ipv4PrefixLength + 18
ipv4PrefixLength = ipv6PrefixLength - 18
ipv6PrefixLength - ipv4PrefixLength = 18

eaBitLength = 38 - ipv4PrefixLength
ipv4PrefixLength = 38 - eaBitLength
eaBitLength + ipv4PrefixLength = 38
```
---
</details>
:::

::: note
### 各社プロビジョニング
<details><summary>ルールAPIエンドポイント</summary>

OCNバーチャルコネクト
```
https://rule.map.ocn.ad.jp/?ipv6Prefix=<address>&ipv6PrefixLength=<prefixLength>&code=<API Key>
```

v6プラス
```
https://api.enabler.ne.jp/<API Key>/get_rules?callback=v6plus
```

v6connect
```
https://prod.v6mig.v6connect.net/cpe/v1/config?vendorid=<VENDOR_ID>&product=<PRODUCT>&version=<VERSION>&capability=<CAPABILITY>
```
---
</details>
:::

::: note
### ルールAPIエンドポイント、鍵XOR暗号
<details><summary>OCNバーチャルコネクト用設定実装サンプル</summary>

暗号化
```:python3
cat << 'EOF' > encrypt.py
#!/usr/bin/env python3
"""
Usage:
  ./encrypt.py
説明:
  鍵XOR暗号
"""
import sys

try:
    plaintext_input = input("キーを入力してください: ")
    if not plaintext_input:
        print("Error: Plaintext not provided.", file=sys.stderr)
        sys.exit(1)
    data = plaintext_input.encode('utf-8')
except EOFError:
    print("\nError: Input cancelled.", file=sys.stderr)
    sys.exit(1)
except KeyboardInterrupt:
    print("\nError: Process interrupted.", file=sys.stderr)
    sys.exit(1)

try:
    password_input = input("パスワードを入力してください: ")
    if not password_input:
        print("Error: Password not provided.", file=sys.stderr)
        sys.exit(1)
    key = password_input.encode('utf-8')
except EOFError:
    print("\nError: Input cancelled.", file=sys.stderr)
    sys.exit(1)
except KeyboardInterrupt:
    print("\nError: Process interrupted.", file=sys.stderr)
    sys.exit(1)

encrypted = bytes([b ^ key[i % len(key)] for i, b in enumerate(data)])
print(encrypted.hex())
EOF
./encrypt.py
```
複合化及び実行、取得
※平文キー入力対応
※実際の設定はしません
```:ash:OpenWrt
wget -qO /tmp/internet-api-mape.sh https://raw.githubusercontent.com/site-u2023/aios/main/internet-api-mape.sh; sh /tmp/internet-api-mape.sh
```
---
</details>
:::

### おまけ
::: note
### IPアドレス帯の逆引き検索
<details><summary>実装サンプル</summary>

```
cat << 'EOF' > /tmp/reverse_lookup.sh
#!/bin/ash

RIPE_JSON_FILE="/tmp/ripe_data.json"
TMP_PREFIX_FILE="/tmp/prefixes.txt" 

cleanup() {
    rm -f "$RIPE_JSON_FILE" "$TMP_PREFIX_FILE"
}
trap cleanup EXIT

echo -n "AS番号を入力してください (例: 4713): "
read -r asn

if [ -z "$asn" ]; then
    echo "エラー: AS番号が入力されていません。" >&2
    exit 1
fi

echo -n "検索キーワードをスペース区切りで入力してください (例: ocn.ne.jp docomo): "
read -r keywords_input

if [ -z "$keywords_input" ]; then
    echo "エラー: 検索キーワードが入力されていません。" >&2
    exit 1
fi

search_pattern=$(echo "$keywords_input" | awk '{gsub(/ /, "|"); print}')

echo "AS$asn の情報を取得中 (RIPEstat)"
if ! wget -q -U "nitefood-asn-ash-script/1.0" -O "$RIPE_JSON_FILE" "https://stat.ripe.net/data/announced-prefixes/data.json?resource=${asn}&sourceapp=nitefood-asn-script"; then
    echo "エラー: RIPEstat APIからのデータ取得に失敗しました。AS番号やネットワーク接続を確認してください。" >&2
    rm -f "$RIPE_JSON_FILE" # 失敗時はファイルを消しておく
    exit 1
fi

if [ ! -s "$RIPE_JSON_FILE" ]; then
    echo "エラー: RIPEstat APIからのデータ取得に失敗したか、空の応答が返されました。" >&2
    exit 1
fi

grep '"prefix":' "$RIPE_JSON_FILE" | sed -e 's/.*"prefix": "[[:space:]]*//' -e 's/"[[:space:]]*,[[:space:]]*"[a-zA-Z_]*":.*//' -e 's/"[[:space:]]*//' | sed 's/,$//' > "$TMP_PREFIX_FILE"

if [ ! -s "$TMP_PREFIX_FILE" ]; then
    echo "情報: AS$asn のアナウンスされたプレフィックスがRIPEstat経由で見つからないか、抽出に失敗しました。"
    echo "注意: この抽出方法はJSON構造の変化に弱いため、APIの応答形式が変わると失敗する可能性があります。"
    exit 0
fi

echo "プレフィックスを処理中"
while IFS= read -r prefix_cidr; do
    if [ -z "$prefix_cidr" ]; then
        continue
    fi

    ip_addr=$(echo "$prefix_cidr" | cut -d'/' -f1)
    host_ip=$(echo "$ip_addr" | awk -F. '{OFS="."; if (NF==4) $4+=1; print}')
    hostname_result=""

    if command -v nslookup >/dev/null 2>&1; then
        hostname_result=$(nslookup -timeout=2 -retry=1 "$host_ip" 2>/dev/null)
    elif command -v host >/dev/null 2>&1; then
        hostname_result=$(host -W 2 "$host_ip" 2>/dev/null)
    else
        echo "警告: 'nslookup' および 'host' コマンドが見つかりません。逆引きを実行できません。" >&2
        continue
    fi

    if echo "$hostname_result" | grep -E -q "$search_pattern"; then
        echo "$prefix_cidr"
    fi
done < "$TMP_PREFIX_FILE"

echo "処理完了。"
EOF
sh /tmp/reverse_lookup.sh
```
---
</details>
:::

# 参考
### GUA and PD

https://openwrt.org/docs/guide-developer/network-scripting

https://github.com/openwrt/openwrt/blob/master/package/base-files/files/lib/functions/network.sh

### プロビジョニング

https://github.com/v6pc/v6mig-prov/blob/1.0/spec.md

https://datatracker.ietf.org/doc/html/rfc6334

### config-softwire

https://ipv4.web.fc2.com/map-e.html

### OCNバーチャルコネクト

https://ainoniwa.net/pdoc/05_network/map-e/

https://babibubebo.org/blog/a1269/

https://www.cisco.com/c/en/us/td/docs/ios-xml/ios/ipaddr_nat/configuration/15-mt/nat-15-mt-book/iadnat-map-e.html#concept_ifs_3cy_wjb

https://nyanshiba.com/blog/yamahartx-settings/

### v6プラス

https://blog.ryotak.net/post/mape-over-uni-port-of-hgw/

https://qiita.com/chibiegg/items/917938295f1aad81c3b3

https://blog.hiros.info/2018/06/biglobeipv4-over-ipv6-rtx830.html

https://www.buaq.net/go-262919.html

https://www.rtpro.yamaha.co.jp/RT/docs/v6plus/?utm_source=chatgpt.com

### DS-LITE

https://www.neko6.info/archives/2516

[https://gist.github.com/stkchp/4daea9158439c32d7a70a255d51e568b](https://gist.github.com/stkchp/4daea9158439c32d7a70a255d51e568b
)

https://github.com/cosmo0920/dotfiles/tree/master

### lua

https://github.com/makeding/luci-app-fleth?tab=readme-ov-file

### 他

https://github.com/missing233/map-e

# あとがき

OpenWrtで何かしようとすると、コマンド（パッケージ）の制約が多すぎるね
色々覚えたけど、知的好奇心以上に役に立たない趣味すぎる。。。