IPアドレス変換(10進数・16進数・2進数)

IPアドレスを10進数・16進数・2進数・8進数に変換し、これらの数値を入力すればIPアドレスに戻します。各オクテットを8ビットとその重みで図示するので、計算の過程を追うことができます。

WHATWG URL Standardとinet_atonに基づく解析 · IPv6は128ビットで正確に計算 · ブラウザー内で動作

読み取った形式: ドット付き10進表記

各オクテットの8ビットとその重み198.51.100.77 = 3,325,256,781
オクテット128643216842116進数合計× 重み= 値
19811000110C6128+64+4+2 = 198× 256³16,777,2163,321,888,768
128+64+4+2 × 256³ = 3,321,888,768
51001100113332+16+2+1 = 51× 256²65,5363,342,336
32+16+2+1 × 256² = 3,342,336
100011001006464+32+4 = 100× 25625625,600
64+32+4 × 256 = 25,600
77010011014D64+8+4+1 = 77× 1177
64+8+4+1 × 1 = 77
合計3,325,256,781
= 3,325,256,781
例

IPアドレスを入力するか、その10進数・16進数・2進数・8進数の数値を入力してIPアドレスに戻します。変換はブラウザー内で行い、何も送信しません。

IPv4 · 32ビット

3325256781

198.51.100.77を1つの32ビットの数値で · ドキュメント用アドレス (RFC 5737)

同じ数値をコードで

SELECT INET_ATON('198.51.100.77');3325256781
SELECT '198.51.100.77'::inet - '0.0.0.0'::inet;3325256781
int(ipaddress.ip_address('198.51.100.77'))3325256781
ip2long('198.51.100.77')3325256781
ドット付き10進表記
10進数
16進数
2進数(オクテットごと)
8進数
16進数(オクテットごと)
8進数(オクテットごと)
ブラウザーで(どれも198.51.100.77を開きます)
逆引きDNS名
IPv6表記(IPv4射影)
IPv4 → IPv6

IPアドレスを10進数に変換する方法は?

4つの数にそれぞれ256³、256²、256、1を掛けて合計します:192.168.1.1は192 × 16,777,216 + 168 × 65,536 + 1 × 256 + 1 = 3,232,235,777です。

IPv4アドレスは、8ビットずつ4つに分けて書いた1つの32ビットの数値なので、ドット付きの形と10進数の形は同じ値です。MySQLのドキュメントでは、例として10.0.5.9 = 167773449を挙げています。

192.168.1.1を1つの数値に:各部分にその位の重みを掛けて合計します。
IPアドレスを10進数に変換するツールの画面:各オクテットのビットと重みを足し合わせて1つの数値にする過程IPアドレスを10進数に変換するツールの画面:各オクテットのビットと重みを足し合わせて1つの数値にする過程どの形式でも入力ドット付き10進表記、10進数、16進数、2進数、8進数、URL:入力欄はどれも読み取ります。ビットと重み1のビットがそれぞれの重みを加えます:128 + 64 + 4 + 2 = 198。× 256³、256²、256、1各オクテットにその重みを掛け、最後に合計します。すべての形式で出力16進数、2進数、8進数、ブラウザーが受け付けるURL。それぞれコピーできます。数値アドレス全体を1つの32ビットの数値で表示します。コピーでき、アドレスの種類も示します。
198.51.100.77をビット単位で:各オクテットの重み、続いて × 256³、256²、256、1を掛けて合計し、3,325,256,781になります。

10進数をIPアドレスに変換する方法は?

16,777,216で割り、その余りを65,536で、さらにその余りを256で割ります:3つの商と最後の余りが4つの数になるので、3232235777は192.168.1.1です。

変換ツールに数値を入力すると同じ計算を行い、16進数、2進数、8進数、ブラウザーが受け付ける形式もあわせて表示します。4,294,967,295より大きい数はIPv4アドレスではありません。変換ツールはそれをIPv6の数値として読み、そのことを表示します。

3,232,235,777を割り算で192.168.1.1に戻します。

IPアドレスを2進数に変換する方法は?

4つの数をそれぞれ、重み128、64、32、16、8、4、2、1の8ビットで書きます:192は128 + 64なので11000000、192.168.1.1は11000000.10101000.00000001.00000001です。

重みを左から順に見ていき、その値が残りに収まれば1を書いて引き、収まらなければ0を書きます。168の場合:128は収まる(残り40)、64は収まらない、32は収まる(残り8)、16は収まらない、8は収まる、なので10101000です。2進数から戻すには、1のビットの重みを足します。

192.168.1.1の各オクテットを、128から1までの重みと照らし合わせたもの。

IPアドレスを16進数に変換する方法は?

各オクテットの8ビットを4ビットずつ2つに分け、それぞれを16進数1桁で書きます:192は1100 0000、つまりC0なので、192.168.1.1は0xC0A80101です。

16進数は、IPv6が埋め込みのIPv4アドレスを書くときの形でもあります:::ffff:c0a8:101は192.168.1.1です。ブラウザーは16進数の数値をホストとして受け付けるので、http://0xC0A80101/は192.168.1.1を開きます。

16進数1桁は4ビット:192.168.1.1はC0 A8 01 01です。

http://3232235777で192.168.1.1が開くのはなぜ?

ブラウザーは、数字だけでできたホストを、昔のinet_atonが受け付けるいずれかの形式(10進数1つだけの形も含む)のIPv4アドレスとして読み、ドット付きのアドレスを読み込むからです。

各部分は10進数(URL Standard)、0x付きの16進数、先頭が0の8進数のいずれでもよく、部分が4つより少なければ最後の部分が残りのバイトを埋めます。そのためhttp://192.168.1/は192.168.1.1ではなく192.168.0.1を開きます。pingとcurlも同じ形式を受け付けます。

32ビットを超える数、0で始まる部分に含まれる8や9、5つ目の部分は拒否されます。

アドレスバーに入力開く先
http://3232235777/192.168.1.1
http://0xC0A80101/192.168.1.1
http://0300.0250.1.1/192.168.1.1
http://127.1/127.0.0.1
http://192.168.1/192.168.0.1
http://4294967296/拒否
http://09/拒否
http://192.0.2.1.5/拒否
WHATWGのURLパーサーが各ホストをどう扱うか。

IPアドレスの別表記がセキュリティ上問題になるのはなぜ?

アドレスを文字列として比較するフィルターはだまされることがあるからです:2130706433、0x7f.1、127.1、::ffff:127.0.0.1はすべて127.0.0.1なので、フィルターは文字列ではなく数値として比較しなければなりません。

OWASPは、こうしたエンコーディングをSSRF対策を回避する手口の1つに挙げています。実際にこのバグを出荷したライブラリもあります:npmのnetmaskとipパッケージ、Pythonのipaddress、Goのnetパッケージはいずれも、ある時点で先頭のゼロや別表記を誤って読んでおり、その後修正されています。

厳格なパーサーで解析し、数値に変換してから範囲を比較してください。ブロック対象の範囲のIPv4射影アドレスもブロックしてください。

deny 127.0.0.1

文字列として比較

127.0.0.1ブロック

2130706433すり抜ける

0x7f.1すり抜ける

127.1すり抜ける

::ffff:127.0.0.1すり抜ける

数値として比較

127.0.0.12130706433 · ブロック

21307064332130706433 · ブロック

0x7f.12130706433 · ブロック

127.12130706433 · ブロック

::ffff:127.0.0.12130706433 · ブロック

CVE-2021-28918netmask (npm)CVE-2021-29418netmask (npm)CVE-2021-29424Net::Netmask (Perl)CVE-2021-29921Python ipaddressCVE-2021-29923Go netCVE-2024-29415ip (npm)
1つのルールと、ループバックアドレスの5通りの書き方。続いて関連するセキュリティ勧告。

IPv6アドレスを10進数に変換する方法は?

16ビットのグループ8つで同じように計算します:2001:db8::1は42540766411282592856903984951653826561で、最大39桁になる数値なので、JavaScriptではBigIntが必要です。

IPv6アドレスは2^128個あります。JavaScriptの数値が整数を正確に保持できるのは2^53 − 1までなので、通常の計算ではIPv6の値が気付かないうちに丸められます。Pythonのint(ipaddress.ip_address(…))は正確です。

2001:db8::1を1つの数値にしたものと、JavaScriptの通常の数値で扱った結果。

コードやデータベースでIPアドレスを数値に変換するには?

各プラットフォームの関数を符号なしの型と組み合わせて使います:MySQLのINET_ATON()とINT UNSIGNED、PostgreSQLのinetの引き算、Pythonのint(ipaddress.ip_address(…))、JavaScriptではシフトの後に>>> 0です。

符号付き32ビット整数では128.0.0.0以上のアドレスを保持できません:JavaScriptの<<は192.168.1.1に対して-1062731519を返し、PHPのip2long()は32ビットのビルドで負の値になります。IPv6には、MySQLではINET6_ATON()とVARBINARY(16)を使います。

› SELECT INET_ATON('192.168.1.1'), INET_NTOA(3232235777);
3232235777 | 192.168.1.1

MySQL 8.4

› SELECT '192.168.1.1'::inet - '0.0.0.0'::inet,
       '0.0.0.0'::inet + 3232235777;
3232235777 | 192.168.1.1

PostgreSQL 16

› import ipaddress
int(ipaddress.ip_address('192.168.1.1')), ipaddress.IPv4Address(3232235777)
(3232235777, IPv4Address('192.168.1.1'))

Python ipaddress

› '192.168.1.1'.split('.').reduce((n, o) => (n << 8) | +o, 0) >>> 0
3232235777

JavaScript

› echo ip2long('192.168.1.1'), ' ', long2ip(3232235777);
3232235777 192.168.1.1

PHP 8

2つのデータベースと3つの言語で、192.168.1.1を数値にして元に戻す例。

よくある質問

192.168.1.1を10進数にすると?

3232235777です。各部分にその重みを掛けて合計します:192 × 16,777,216 + 168 × 65,536 + 1 × 256 + 1 = 3,232,235,777。同じ数は16進数で0xC0A80101、2進数で11000000.10101000.00000001.00000001です。ブラウザーはこれをホストとしても受け付けるので、http://3232235777/はhttp://192.168.1.1/と同じアドレスを開きます。

IPv4アドレスの10進数の最大値は?

4,294,967,295で、255.255.255.255にあたります。IPv4アドレスは32ビットの数値なので、0(0.0.0.0)から4,294,967,295までの2^32 = 4,294,967,296個があります。それより大きい数はIPv4アドレスではありません:ブラウザーはhttp://4294967296/を拒否し、この変換ツールはそうした数を128ビットのIPv6の値として読み、そのことを表示します。

3232235777をIPアドレスに戻すには?

16,777,216で割ると1つ目の部分は192、余りは11,010,305です。その余りを65,536で割ると2つ目の部分は168、余りは257です。257を256で割ると3つ目の部分は1、余りは1で、これが4つ目の部分です。答えは192.168.1.1です。変換ツールに数値を入力すれば、各オクテットのビットもあわせて表示されます。

IPアドレスの010のような先頭のゼロは何を意味しますか?

プログラムによって異なります。ブラウザーとinet_atonは先頭にゼロのある部分を8進数として読むため、192.0.2.010は192.0.2.8になりますが、ゼロを無視するツールは192.0.2.10と読みます。2通りの読み方のせいでリクエストがIPフィルターをすり抜けるバグがあったため、PythonとGoは現在こうしたアドレスをはっきり拒否します。IPv4アドレスに先頭のゼロは決して書かないでください。

192.168.1で192.168.0.1が開くのはなぜですか?

3つの部分からなるアドレスでは、最後の部分が下位16ビットを埋めるからです。192.168.1の最後の1は16ビットの数値1、つまり0.1になるので、アドレスは192.168.0.1です。inet_atonとブラウザーは短縮形をこのように読み、192.168.257なら192.168.1.1になります。PostgreSQLのcidr型は192.168.1を別の意味で読み、ネットワーク192.168.1.0/24とみなします。

IPアドレスを手計算で2進数に変換するには?

4つの数それぞれについて、重み128、64、32、16、8、4、2、1を順に見ていき、その重みが収まれば1を書いて引き、収まらなければ0を書きます。168の場合:128は収まる(残り40)、64は収まらない、32は収まる(残り8)、16は収まらない、8は収まる(残り0)なので、10101000です。4つの8ビットのグループをドットでつなぎます。

MySQLでIPアドレスを数値として保存するには?

INET_ATON('10.0.5.9')で変換すると167773449が返るので、その結果をINT UNSIGNEDの列に保存します:符号付きのINTでは127.255.255.255より上のアドレスを保持できません。数値をテキストに戻すにはINET_NTOAを使います。IPv6では、128ビットの値はどの整数型にも収まらないため、INET6_ATONとVARBINARY(16)の列を使います。127.1のような短縮形にINET_ATONを頼らないでください。

JavaScriptやPHPでIPの数値が負になるのはなぜですか?

符号付き32ビット整数として扱われたからです。JavaScriptの<<演算子は符号付きの結果を返すため、シフトで組み立てた192.168.1.1は-1062731519になります。>>> 0を付ければ3232235777が得られます。PHPのip2longも32ビットのビルドでは同じ動作になり、sprintf('%u', …)で符号なしの値を出力できます。影響を受けるのは128.0.0.0以上のアドレスだけなので、このバグは見過ごされがちです。

IPv6アドレスは10進数に変換できますか?

はい。IPv6アドレスは128ビットの数値なので、2001:db8::1は42540766411282592856903984951653826561で、最大値は39桁です。JavaScriptの通常の数値は2^53を超えると精度が落ちるため、ツールはBigIntを使う必要があり、オンラインの変換ツールの中には末尾の桁を間違えるものもあります。Pythonのint(ipaddress.ip_address('2001:db8::1'))なら正確な値が得られます。

http://0x7f000001/は127.0.0.1と同じですか?

はい。ブラウザーや多くのコマンドラインツールは、0xの後に続く16進数のホストを1つの32ビットの数値として読むため、0x7f000001、2130706433、0x7f.1、127.1はすべてループバックアドレスの127.0.0.1を意味します。そのため、セキュリティのフィルターは文字列ではなく数値で比較しなければなりません。これはRFC 3986とOWASPのSSRFチートシートの勧告でもあります。

足りないものはありますか?機能や新しいツールを提案する