AWS IP アドレス 範囲ファイルを IP アドレスの前方一致で絞り込んだりレンジを一緒に表示したりしてみた

AWS IP アドレス 範囲ファイルを IP アドレスの前方一致で絞り込んだりレンジを一緒に表示したりしてみた

curlとjqとその他で、IPアドレスの前方一致でフィルタリングしたりIPアドレス順にソートしたりIPプレフィックスのレンジを一緒に表示したりします。

コンバンハ、千葉(幸)です。

AWSが利用するIPアドレスの情報はip-ranges.jsonとして公開されています。

https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/aws-ip-ranges.html

AWSを利用していく中で、「このIPアドレスってAWSが保有するものなのか?」「どのサービス用のIPアドレスなのか?」が気になることがあります。「このサービスが取りうるIP範囲を知りたい」ではなく、 「このIPアドレスが何で使われているかを知りたい」 という方向です。

ip-ranges.jsonからお目当てのIPアドレスを絞り込んでいくのがちょっと楽になる方法を紹介します。

なお、今回はIPv4アドレスを対象にしています。以降も単に「IPアドレス」と呼称します。

ポイント

  • curlによる出力をjqで整形する
    • IPアドレスの文字列の前方一致で絞り込む
    • IPアドレスでソートする
  • (オプション)ipcalcでネットワークアドレス〜ブロードキャストアドレスのレンジを計算し表示する

なお、ローカルにファイル保存せず、都度curlでダウンロードをする前提でコマンドを考えています。一度の実行で4MB弱のダウンロードが発生します(2025/03/31現在)。繰り返し実行する場合には、一度ローカルにファイルとして保存し、そのファイルに対してjqを実行すると良いでしょう。

動作確認環境

  • macOS
    • curl 8.7.1
    • jq 1.6
    • ipcalc 0.51
  • AWS CloudShell
    • curl 8.5.0
    • jq 不明
    • ipcalc 1.0.1

ip-ranges.jsonをIPアドレスの前方一致でフィルタリングする

「52.192.xx.xx」というIPアドレスについて調べたかったとします。

jqのstartswith関数を用いてフィルタリングできます。

curl -s https://ip-ranges.amazonaws.com/ip-ranges.json \
  | jq '.prefixes[] | select(.ip_prefix | startswith("52.192"))'
実行結果
{
  "ip_prefix": "52.192.0.0/15",
  "region": "ap-northeast-1",
  "service": "AMAZON",
  "network_border_group": "ap-northeast-1"
}
{
  "ip_prefix": "52.192.0.0/15",
  "region": "ap-northeast-1",
  "service": "EC2",
  "network_border_group": "ap-northeast-1"
}

ここでは第二オクテットまでを指定していますが、第三オクテットまで含めたり、第三オクテットの1桁目までだけ含めたり、ということもできます。

ip-ranges.jsonをtsvで出力する

該当する結果が多い場合には、ひとつのIPプレフィックスの情報を1行で確認したくなります。

jqによる出力でtsv形式を指定します。(フィルタリング結果量を多くするために、「52.19」までに拡大)

curl -s https://ip-ranges.amazonaws.com/ip-ranges.json \
  | jq -r '.prefixes[] | select(.ip_prefix | startswith("52.19"))
  | [.ip_prefix, .region, .service, .network_border_group] | @tsv'
実行結果
52.192.0.0/15	ap-northeast-1	AMAZON	ap-northeast-1
52.194.0.0/15	ap-northeast-1	AMAZON	ap-northeast-1
52.196.0.0/14	ap-northeast-1	AMAZON	ap-northeast-1
52.195.198.0/23	ap-northeast-1	AMAZON	ap-northeast-1
52.195.200.0/22	ap-northeast-1	AMAZON	ap-northeast-1
52.19.124.0/23	eu-west-1	WORKSPACES_GATEWAYS	eu-west-1
52.192.0.0/15	ap-northeast-1	EC2	ap-northeast-1
52.194.0.0/15	ap-northeast-1	EC2	ap-northeast-1
52.196.0.0/14	ap-northeast-1	EC2	ap-northeast-1
52.199.127.192/26	ap-northeast-1	CLOUDFRONT	ap-northeast-1

ip-ranges.jsonをIPプレフィックスでソートする

デフォルトでは特にIPプレフィックスはソートされていません。せっかくなら昇順に並べたいものです。

Sort_by関数を組み込んでソートします。

curl -s https://ip-ranges.amazonaws.com/ip-ranges.json \
  | jq -r '.prefixes | map(select(.ip_prefix | startswith("52.19")))
  | sort_by(.ip_prefix | split("/")[0] | split(".") | map(tonumber))
  | .[] | [.ip_prefix, .region, .service, .network_border_group] | @tsv'
実行結果
52.19.124.0/23	eu-west-1	WORKSPACES_GATEWAYS	eu-west-1
52.192.0.0/15	ap-northeast-1	AMAZON	ap-northeast-1
52.192.0.0/15	ap-northeast-1	EC2	ap-northeast-1
52.194.0.0/15	ap-northeast-1	AMAZON	ap-northeast-1
52.194.0.0/15	ap-northeast-1	EC2	ap-northeast-1
52.195.198.0/23	ap-northeast-1	AMAZON	ap-northeast-1
52.195.200.0/22	ap-northeast-1	AMAZON	ap-northeast-1
52.196.0.0/14	ap-northeast-1	AMAZON	ap-northeast-1
52.196.0.0/14	ap-northeast-1	EC2	ap-northeast-1
52.199.127.192/26	ap-northeast-1	CLOUDFRONT	ap-northeast-1
sort_by関数で行なっていること(Claude 3.7 Sonnetによる解説)

1. .ip_prefix

  • 各エントリのIP_prefixフィールドを取得します
  • 例: "52.192.0.0/15"

2. split("/")[0]

  • CIDR表記からスラッシュ(/)で分割し、最初の要素(IPアドレス部分)だけを取り出します
  • 例: "52.192.0.0/15""52.192.0.0"

3. split(".")

  • IPアドレスをドット(.)で分割して配列にします
  • 例: "52.192.0.0"["52", "192", "0", "0"]

4. map(tonumber)

  • 配列の各要素(文字列)を数値に変換します
  • 例: ["52", "192", "0", "0"][52, 192, 0, 0]

5. sort_by(...)

  • 上記の変換結果を使用して配列をソートします
  • 配列の各要素を比較する際に、最初のオクテットから順に比較します
  • 同じ値の場合は次のオクテットを比較します

なぜこの処理が必要か

単純な文字列としてIPアドレスをソートすると、辞書順(アルファベット順)でソートされるため、以下のような問題が発生します。

10.0.0.0    (文字列の先頭が"1"2.0.0.0     (文字列の先頭が"2"52.192.0.0  (文字列の先頭が"5"

しかし、IPアドレスとしては数値的に正しくソートすると以下のようになるべきです。

2.0.0.0     (最初のオクテットが2)
10.0.0.0    (最初のオクテットが10)
52.192.0.0  (最初のオクテットが52)

この式を使用することで、IPアドレスの各オクテットを数値として扱い、正しい数値順でソートすることができます。

ip-ranges.jsonのIPプレフィックスのレンジをあわせて表示する

たとえば「52.196.0.0/14」と言われた時に、それがどのIPアドレスのレンジを表すのかわたしはパッと計算できません。

ipcalcを間に挟むことで、IPレンジも一緒に表示してみます。

あらかじめipcalcをインストールしておきます。

macOSの場合
brew install ipcalc
AWS CloudShellの場合
sudo dnf install ipcalc -y

コマンドも長くなってきたので、前方一致で検索したいIPアドレスを変数に格納する形式にします。

事前に変数に格納
SEARCH_IP_PREFIX="52.19"
curl -s https://ip-ranges.amazonaws.com/ip-ranges.json | \
  jq -r --arg search_ip_prefix "$SEARCH_IP_PREFIX" '.prefixes |
    map(select(.ip_prefix | startswith($search_ip_prefix))) |
    sort_by(.ip_prefix | split("/")[0] | split(".") | map(tonumber)) |
    .[] | [.ip_prefix, .region, .service, .network_border_group] | @tsv' | \
  while IFS=$'\t' read -r prefix region service border_group; do
    network=$(ipcalc "$prefix" | grep "Network:" | awk '{print $2}' | cut -d/ -f1)
    broadcast=$(ipcalc "$prefix" | grep "Broadcast:" | awk '{print $2}')
    ip_range="$network - $broadcast"
    printf "%s\t%s\t%s\t%s\t%s\n" "$prefix" "$region" "$service" "$border_group" "$ip_range"
  done
実行結果
52.19.124.0/23	eu-west-1	WORKSPACES_GATEWAYS	eu-west-1	52.19.124.0 - 52.19.125.255
52.192.0.0/15	ap-northeast-1	AMAZON	ap-northeast-1	52.192.0.0 - 52.193.255.255
52.192.0.0/15	ap-northeast-1	EC2	ap-northeast-1	52.192.0.0 - 52.193.255.255
52.194.0.0/15	ap-northeast-1	AMAZON	ap-northeast-1	52.194.0.0 - 52.195.255.255
52.194.0.0/15	ap-northeast-1	EC2	ap-northeast-1	52.194.0.0 - 52.195.255.255
52.195.198.0/23	ap-northeast-1	AMAZON	ap-northeast-1	52.195.198.0 - 52.195.199.255
52.195.200.0/22	ap-northeast-1	AMAZON	ap-northeast-1	52.195.200.0 - 52.195.203.255
52.196.0.0/14	ap-northeast-1	AMAZON	ap-northeast-1	52.196.0.0 - 52.199.255.255
52.196.0.0/14	ap-northeast-1	EC2	ap-northeast-1	52.196.0.0 - 52.199.255.255
52.199.127.192/26	ap-northeast-1	CLOUDFRONT	ap-northeast-1	52.199.127.192 - 52.199.127.255

一番右の5列目に、52.119.205.0 - 52.119.205.255のような形でIPレンジを表示しています。(/32の場合は5列目が表示されません。)

全体の流れ(Claude 3.7 Sonnetによる解説)

1. AWS IP範囲情報の取得

curl -s https://ip-ranges.amazonaws.com/ip-ranges.json
  • curl: URLからデータを取得するコマンド
  • -s: サイレントモード(進捗情報を表示しない)
  • AWSが公開しているIP範囲のJSON情報を取得

2. jqによるJSONデータの処理

jq -r --arg search_ip_prefix "$SEARCH_IP_PREFIX" '.prefixes |
  map(select(.ip_prefix | startswith($search_ip_prefix))) |
  sort_by(.ip_prefix | split("/")[0] | split(".") | map(tonumber)) |
  .[] | [.ip_prefix, .region, .service, .network_border_group] | @tsv'
  • jq: JSONデータを処理するためのコマンド
  • -r: 生の出力(引用符なし)
  • --arg search_ip_prefix "$SEARCH_IP_PREFIX": 変数を渡す
  • .prefixes: JSONの"prefixes"配列を取得
  • map(select(...)): 指定したIPプレフィックスで始まるエントリをフィルタリング
  • sort_by(...): IPアドレスを数値的に正しくソート
  • .[]: 配列の各要素を処理
  • [.ip_prefix, .region, .service, .network_border_group]: 必要なフィールドを配列に格納
  • @tsv: タブ区切り形式で出力

3. whileループによる各行の処理

while IFS=$'\t' read -r prefix region service border_group; do
  ...
done
  • IFS=$'\t': 入力フィールドの区切り文字をタブに設定
  • read -r prefix...: タブ区切りの入力を変数に読み込む
  • 各行(各IPプレフィックス)に対して処理を実行

4. ipcalcによるIPアドレス範囲の計算

network=$(ipcalc "$prefix" | grep "Network:" | awk '{print $2}' | cut -d/ -f1)
broadcast=$(ipcalc "$prefix" | grep "Broadcast:" | awk '{print $2}')
  • ipcalc: IPアドレス計算ツール
  • grep "Network:": ネットワークアドレス行を抽出
  • awk '{print $2}': 2番目のフィールド(IPアドレス)を抽出
  • cut -d/ -f1: CIDR表記からスラッシュ以降を削除
  • 同様にブロードキャストアドレスも取得
  • ip_range="$network - $broadcast": 範囲を「開始IP - 終了IP」形式で作成

5. 結果の整形と出力

printf "%s\t%s\t%s\t%s\t%s\n" "$prefix" "$region" "$service" "$border_group" "$ip_range"
  • printf: フォーマット付きで出力
  • %s\t: 文字列をタブ区切りで出力
  • 5つのフィールドをタブ区切りで表示
ipcalcについて

ipcalcではたとえば以下のように各種情報が確認できます。

% ipcalc 52.19.124.0/23
Address:   52.19.124.0          00110100.00010011.0111110 0.00000000
Netmask:   255.255.254.0 = 23   11111111.11111111.1111111 0.00000000
Wildcard:  0.0.1.255            00000000.00000000.0000000 1.11111111
=>
Network:   52.19.124.0/23       00110100.00010011.0111110 0.00000000
HostMin:   52.19.124.1          00110100.00010011.0111110 0.00000001
HostMax:   52.19.125.254        00110100.00010011.0111110 1.11111110
Broadcast: 52.19.125.255        00110100.00010011.0111110 1.11111111
Hosts/Net: 510                   Class A

今回はNetwork(の/以降を削ったもの)とBroadcastの値を用いています。
ホストが取りうるIPレンジを出力、ということであればHostMinHostMaxを用いるのもよいでしょう。

番外編:ip-ranges.jsonのプレフィックス長ごとの数を確認する

/24/20などのプレフィックス長がそれぞれどのくらいあるのか気になった時に調べる用です。

curl -s https://ip-ranges.amazonaws.com/ip-ranges.json | jq -r '.prefixes[].ip_prefix | split("/") | last' | sort | uniq -c | awk '{print "/" $2, $1}'

2025/03/31現在の結果はこちら。かなり頻繁に変わっているようです。

実行結果
/11 4
/12 19
/13 42
/14 113
/15 303
/16 528
/17 101
/18 146
/19 78
/20 203
/21 302
/22 588
/23 548
/24 2031
/25 219
/26 507
/27 298
/28 348
/29 344
/30 179
/31 490
/32 1139

終わりに

AWS IPアドレス範囲をcurlやjqを使っていい感じに確認する方法の紹介でした。

「このIPアドレスってどのリージョンのどのサービス用だ?」などを調べたくなった時に思い出してください。

ローカルにダウンロードしたファイルを対象にjqで色々やるパターンは公式ドキュメントに載っていますので、こちらもあわせてご参考ください。

https://docs.aws.amazon.com/ja_jp/vpc/latest/userguide/aws-ip-work-with.html

以上、チバユキ (@batchicchi)がお送りしました。

参考

https://dev.classmethod.jp/articles/jq-ip-address-sort/

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.