JSでサブネットマスクの計算

2021-02-04
javascriptnode.js%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0
    

目次

概要

JSでIPv4のサブネットマスクの計算を行った時の記録及び自分用メモです。

JSでIPの計算を行う機会なんて殆どないかもしれませんが、(node.jsは別として) 重要な理論を整理するためにJSで実装してみました。

JSによるサブネットマスク関連の計算

大前提としてサブネットの計算を整理しておきます。

※ ここに記載しているコードは"最低限の機能"しか実装しておらず、入力値をチェックする機構はないので注意が必要です。例外的な値を入力すると誤作動します。

IPv4アドレス文字列をNumber型に変換する

IPv4アドレスの文字列、例えば 192.168.0.1 といった形式の文字列をbit演算を利用して計算するために Number型 に変換しておきます。

具体的には次のような手順で変換します。

192.168.0.1 # IPアドレス表記11000000.10101000.00000000.00000001 # 2進数に変換3232235521 # 10進数表記
// IPv4 to binary string
const ip2bin = (ip) => ip.split(".").map(e => Number(e).toString(2).padStart(8, '0')).join('')
// IPv4 to Number
const ip2long = (ip) => parseInt(ip2bin(ip), 2)
// Number to IPv4
const long2ip = (num) => {
    let bin = Number(num).toString(2).padStart(32, '0')
    return [
        bin.slice(0, 8),
        bin.slice(8, 16),
        bin.slice(16, 24),
        bin.slice(24, 32),
    ].map(e => parseInt(e, 2)).join('.')
}

console.log(ip2bin("192.0.34.166")) // 11000000000000000010001010100110
console.log(ip2long("192.0.34.166")) // 3221234342
console.log(long2ip(ip2long("192.0.34.166"))) // 192.0.34.166

余談ですが、ip2long/long2ipはPHPで同じ名前の関数が存在します。

ip2long - php.net

これらを参考にしました。

CIDR と サブネットの相互変換

CIDRは2進数で表示された場合の先頭からの1の数を表しており、1〜32の値となります。

なので次のような関係が成り立ちます。

26  # CIDR11111111.11111111.11111111.11000000 # 26個1を並べ2進数表記に変換255.255.255.192 # 1バイト(=8bit)ずつに区切ってそれぞれを10進数に変換する

コードにするとこのようになります。

// CIDR to Number
const cidr2long = (cidr) => parseInt(String("").padStart(cidr, '1').padEnd(32, '0'), 2)
// CIDR to SubnetMask
const cidr2subnetmask = (num) => long2ip(cidr2long(num))
// SubnetMask to CIDR
const subnetmask2cidr = (ip) => ip2bin(ip).split('1').length - 1

console.log(cidr2subnetmask(26)) // 255.255.255.192
console.log(subnetmask2cidr("255.255.255.192")) // 26

ネットワークアドレス と ブロードキャストアドレス

ネットワークアドレス(開始アドレス)は、IPアドレスとサブネットマスクのAND(論理積)で求められます。

また、ブロードキャストアドレス(終了アドレス)は、IPアドレスと反転したサブネットマスクのOR(論理和)で求められます。

ただし、そのままビット演算子を利用して論理積や論理和を求めようとすると32ビット符号付き整数として計算されてしまうため符号なしとして計算してやる必要があります。

具体的には論理右シフト>>>を利用して "符号なし" に変換します。

したがって、ネットワークアドレスとブロードキャストアドレスは次のように求めます。

// ネットワークアドレス
const getNetworkAddr = (ip, subnetmask) => (ip & subnetmask) >>> 0
// ブロードキャストアドレス
const getBroadcastAddr = (ip, subnetmask) => (ip | ~subnetmask) >>> 0

クラス

IPアドレスは使用するネットワークの規模によってクラスA〜C + 特殊用としての「D」や実験用の「E」に分かれています。

  • クラスA 0.0.0.0 ~ 127.255.255.255
  • クラスB 128.0.0.0 ~ 191.255.255.255
  • クラスC 192.0.0.0 ~ 223.255.255.255
  • クラスD 224.0.0.0 ~ 239.255.255.255
  • クラスE 240.0.0.0 ~ 255.255.255.255

これを次のようにコードに落としました。

const getClass = (ip) => {
    if (ip2long("0.0.0.0") <= ip && ip <= ip2long("127.255.255.255")) {
        return 'A'
    }
    if (ip2long("128.0.0.0") <= ip && ip <= ip2long("191.255.255.255")) {
        return 'B'
    }
    if (ip2long("192.0.0.0") <= ip && ip <= ip2long("223.255.255.255")) {
        return 'C'
    }
    if (ip2long("224.0.0.0") <= ip && ip <= ip2long("239.255.255.255")) {
        return 'D'
    }
    if (ip2long("240.0.0.0") <= ip && ip <= ip2long("255.255.255.255")) {
        return 'E'
    }
    return false;
}
console.log(getClass(ip2long("192.168.0.1"))) // C

改めて計算方法を整理する

改めて整理してサブネットマスク関連の一連の計算を行います。コード全て載せます。

const ip2bin = (ip) => ip.split(".").map(e => Number(e).toString(2).padStart(8, '0')).join('')

const ip2long = (ip) => parseInt(ip2bin(ip), 2)

const long2ip = (num) => {
    let bin = Number(num).toString(2).padStart(32, '0')
    return [
        bin.slice(0, 8),
        bin.slice(8, 16),
        bin.slice(16, 24),
        bin.slice(24, 32),
    ].map(e => parseInt(e, 2)).join('.')
}

const cidr2long = (cidr) => parseInt(String("").padStart(cidr, '1').padEnd(32, '0'), 2)

const cidr2subnetmask = (num) => long2ip(cidr2long(Number(num)))

const subnetmask2cidr = (ip) => ip2bin(ip).split('1').length - 1

const getNetworkAddr = (ip, subnetmask) => (ip & subnetmask) >>> 0

const getBroadcastAddr = (ip, subnetmask) => (ip | ~subnetmask) >>> 0

const getClass = (ip) => {
    if (ip2long("0.0.0.0") <= ip && ip <= ip2long("127.255.255.255")) {
        return 'A'
    }
    if (ip2long("128.0.0.0") <= ip && ip <= ip2long("191.255.255.255")) {
        return 'B'
    }
    if (ip2long("192.0.0.0") <= ip && ip <= ip2long("223.255.255.255")) {
        return 'C'
    }
    if (ip2long("224.0.0.0") <= ip && ip <= ip2long("239.255.255.255")) {
        return 'D'
    }
    if (ip2long("240.0.0.0") <= ip && ip <= ip2long("255.255.255.255")) {
        return 'E'
    }
    return false;
}

const ipLong = ip2long("192.168.0.1")
const cidr = cidr2long(24)
console.log(`
IPアドレス: ${long2ip(ipLong)}
サブネットマスク: /${subnetmask2cidr("255.255.255.0")} (${cidr2subnetmask(24)})
ネットワークアドレス: ${long2ip(getNetworkAddr(ipLong, cidr))}
使用可能IP: ${long2ip(getNetworkAddr(ipLong, cidr) + 1)}${long2ip(getBroadcastAddr(ipLong, cidr) - 1)}
ブロードキャストアドレス: ${long2ip(getBroadcastAddr(ipLong, cidr))}
アドレス数: ${getBroadcastAddr(ipLong, cidr) - getNetworkAddr(ipLong, cidr) + 1}
ホストアドレス数: ${getBroadcastAddr(ipLong, cidr) - getNetworkAddr(ipLong, cidr) - 1}
IPアドレスクラス: ${getClass(ipLong)}
`)

そして出力結果がこちらになります。サブネット計算サイトの結果と一致しました。

IPアドレス: 192.168.0.1
サブネットマスク: /24 (255.255.255.0)
ネットワークアドレス: 192.168.0.0
使用可能IP: 192.168.0.1 〜 192.168.0.254
ブロードキャストアドレス: 192.168.0.255
アドレス数: 256
ホストアドレス数: 254
IPアドレスクラス: C

参考にさせていただいたサイト

サブネットマスクとは? - CMAN

JSで32ビット符号付き整数に対してのビット演算でハマった - 404 motivation not found

IPアドレス(クラスの概念) - @network Cisco・アライド実機で学ぶ

    
s-yoshiki
s-yoshiki
githubtwitterqiita
Web作ってますが、インタラクティブなプログラミングも好きです。
JavaScript / Vue / node.js / PHP / AWS / OpenCV

関連記事

JSで32ビット符号付き整数に対してのビット演算でハマった
具体例 参考にしたサイト JSでサブネットマスクの計算を行おうとしたとき、ビット演算でハマりました。その時のメモです。 JSでサブネットマスクの計算 JSでビット演算子を利用する場合 3…

JSでIPアドレスがサブネットマスクで指定した範囲内にあるか判定する
IPアドレスが指定した範囲内にあるかどうか判定 参考にしたサイト JSでIPアドレス(IPv4)が指定したサブネットの範囲に含まれるか判定するロジックを作った時の記録です。 IPアドレスが指定した範囲内にあるかどうか判定 処理としては、IP…

プログラムの数値計算で発生する誤差の種類 丸め誤差・打ち切り誤差・桁落ち
はじめに 誤差の種類 丸め誤差 打ち切り誤差 桁落ち 情報落ち 桁溢れ誤差 参考にしたサイト コンピュータで出てくる誤差はいくつかありますが、 それらをコードに落として整理しました。 はじめに 例えば の計算の答えは 0.6666666666…

AWS Amplify に Next.js (SSG) で作ったアプリをデプロイする
はじめに 操作 Next.js (React) アプリの作成、Gitへのプッシュ AWS Amplifyでプロジェクト作成 参考にしたサイト この記事では、React / Next.js アプリケーションを作成し、AWS Amplify…

Typescriptに入門した
初期作業 とりあえずHello World 初期作業 typescript環境を作っていきます。 とりあえずHello World まず、次のサンプルコードを作成します。 typescriptファイルをビルドします。

Vue/Nuxt.js 触ってた人が Next.js に入門する
はじめに 実施環境 学習ガイド Create a Next.js App Navigate Between Pages ページの作成 リンク Assets, Metadata, and CSS Assets メタデータ CSS…

10進数から2進数 2進数から10進数への変換 JavaScript
10進数から2進数 2進数から10進数 テスト 10進数から2進数、2進数から10進数への変換を行うJavaScriptのコードの紹介。 JSの場合、10進数から2進数への変換はメソッド。2進数から1…

JavaScriptの配列ショートハンド (AtCoder用)

JavaScriptでワーシャルフロイド法を実装
AtCoder ABC012 D問題 D - バスと避けられない運命 解説 実装 AtCoder ABC012 の D問題でワーシャルフロイド法が利用できる問題が出てきたので、 JavaScriptで実装しました。 AtCoder ABC012 D問題 D…

GitHub Actions で Gatsby をビルドし Amazon S3 にデプロイする
GitHub Actions について あらかじめ準備しておくもの AWS IAM ユーザを環境変数にセットする workflowの記述 ビルド バッジを利用する 終わりに 参考にしたところ Gatsbyで作った静的サイトを、GitHub Actions…

最新の投稿

フェールセーフやフェールソフト・フールプルーフ 障害対策用語のまとめ

JSで32ビット符号付き整数に対してのビット演算でハマった
具体例 参考にしたサイト JSでサブネットマスクの計算を行おうとしたとき、ビット演算でハマりました。その時のメモです。 JSでサブネットマスクの計算 JSでビット演算子を利用する場合 3…

Gitにプロキシを設定する
プロキシを設定する 確認 Gitでプロキシを通しておくメモです。 プロキシを設定する 以下のコマンドでproxyを通します。 ※ がプロキシのURL…

JSでIPアドレスがサブネットマスクで指定した範囲内にあるか判定する
IPアドレスが指定した範囲内にあるかどうか判定 参考にしたサイト JSでIPアドレス(IPv4)が指定したサブネットの範囲に含まれるか判定するロジックを作った時の記録です。 IPアドレスが指定した範囲内にあるかどうか判定 処理としては、IP…

プログラムの数値計算で発生する誤差の種類 丸め誤差・打ち切り誤差・桁落ち
はじめに 誤差の種類 丸め誤差 打ち切り誤差 桁落ち 情報落ち 桁溢れ誤差 参考にしたサイト コンピュータで出てくる誤差はいくつかありますが、 それらをコードに落として整理しました。 はじめに 例えば の計算の答えは 0.6666666666…

JSでサブネットマスクの計算
JSによるサブネットマスク関連の計算 IPv4アドレス文字列をNumber型に変換する CIDR と サブネットの相互変換 ネットワークアドレス と ブロードキャストアドレス クラス 改めて計算方法を整理する 参考にさせていただいたサイト JSでIPv…

Homebrew で php7.4 + Xdebug をインストール
php7.4のインストール Xdebugのインストール php.ini に追記 参考にさせていただいたサイト phpunitのカバレッジを算出を行うためにMacにHomebrewでphp7.4をインストールしようとした際の記録です。 php7.…

CentOS で スマートにプロキシを設定する
コマンドライン上で通す よりスマートに設定する 設定ファイルに記述 CentOSでプロキシを通す設定のメモです。 プロキシ環境で yum/dnf でリポジトリを更新する場合や、curl/wget…

MySQL8.0 で利用できるパラメータを表示する方法
オプションの表示 mysql8.0でmy.cnfなどで利用できるパラメータ一覧を出す方法。 オプションの表示 オプションの表示は次のコマンドで実施できます mysqld — The MySQL Server 【MySQLパラメーター比較資料】MySQL 5.…

CentOS に MySQL8.0をインストールする
はじめに 環境 起動 MySQLインストール my.cnf の設定 プロセス立ち上げ エラー The designated data directory /var/lib/mysql/ is unusable. You can remove all files…

Tags

Dates

© 2021   404 motivation not found