CINXE.COM
ip-range-calc
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <!-- Facebook Sharing --> <meta property="og:title" content="ftools" /> <meta property="og:description" content="Fastily's Tools" /> <meta property="og:image" content="https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/Toolforge_logo.svg/480px-Toolforge_logo.svg.png" /> <!-- Googlebot --> <meta name="description" content="Fastily's Wikipedia Tools. Privacy First: No ads, no tracking, no nonsense." /> <title>ip-range-calc</title> <!-- favicon --> <link rel="icon" href="https://tools-static.wmflabs.org/toolforge/favicons/favicon.ico" type="image/x-icon"> <!-- CSS --> <link rel="stylesheet" href="https://tools-static.wmflabs.org/cdnjs/ajax/libs/twitter-bootstrap/4.6.1/css/bootstrap.min.css" crossorigin="anonymous"> </head> <body> <nav class="navbar navbar-expand-md navbar-light bg-light" id="main-nav"> <div class="container-fluid"> <a href="/" class="navbar-brand"><span style="font-family:'Trebuchet MS';color:Indigo;font-weight:bold;"><span style="font-size:120%;">F</span><span style="font-size:90%;">TOOLS</span></span></a> <button class="navbar-toggler" data-toggle="collapse" data-target="#navbarNav"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse" id="navbarNav"> <ul class="navbar-nav ml-auto"> <li class="nav-item"> <a class="nav-link" href="https://github.com/fastily/ftools">Source</a> </li> <li class="nav-item"> <a class="nav-link" href="https://toolforge.org">Toolforge</a> </li> </ul> </div> </div> </nav> <header> <div class="container jumbotron mt-4"> <h1 class="display-4">ip-range-calc</h1> <p class="lead">(calculate the smallest CIDR block encompassing a given list of IP addresses)</p> </div> </header> <section class="container mb-5"> <div id="app"> <form> <div class="form-group mb-4"> <label for="mainTextInput">List the IP addresses below (one per line)</label> <textarea class="form-control" rows="7" id="mainTextInput" v-model.trim="inputText"></textarea> </div> <fieldset class="form-group mb-4"> <legend class="col-form-label">What kind of IP addresses are these?</legend> <div class="form-check"> <input class="form-check-input" type="radio" name="ipv4Radio" id="exampleRadios1" value="4" v-model="selectedIPType"> <label class="form-check-label" for="ipv4Radio">IPv4</label> </div> <div class="form-check"> <input class="form-check-input" type="radio" name="ipv6Radio" id="exampleRadios2" value="6" v-model="selectedIPType"> <label class="form-check-label" for="ipv6Radio">IPv6</label> </div> </fieldset> <input type="button" value="Calculate" class="btn btn-primary" v-on:click.prevent="calculate" :disabled="!inputText"> </form> <div class="card mt-4" v-show="showResult"> <div class="card-header">Result</div> <div class="card-body">{{resultText}}</div> </div> <div class="alert alert-warning mt-2" role="alert" v-if="showBigRangeWarning">鈿狅笍 MediaWiki prohibits rangeblocks this large. Try experimenting with multiple, smaller ranges.</div> </div> </section> <script src="https://tools-static.wmflabs.org/cdnjs/ajax/libs/jquery/3.5.1/jquery.min.js" crossorigin="anonymous"></script> <script src="https://tools-static.wmflabs.org/cdnjs/ajax/libs/twitter-bootstrap/4.6.1/js/bootstrap.bundle.min.js" crossorigin="anonymous"></script> <script src="https://tools-static.wmflabs.org/cdnjs/ajax/libs/vue/3.2.27/vue.global.prod.min.js" crossorigin="anonymous"></script> <script src="https://tools-static.wmflabs.org/cdnjs/ajax/libs/ipaddr.js/2.0.1/ipaddr.min.js" crossorigin="anonymous"></script> <script> Vue.createApp({ data() { return { inputText: "", selectedIPType: "4", resultText: "", showBigRangeWarning: false, showResult: false }; }, methods: { calculate() { this.showBigRangeWarning = false; let [protocol, cnt, warningThreshold] = this.selectedIPType === "4" ? [ipaddr.IPv4, 32, 16] : [ipaddr.IPv6, 128, 19]; // validate and parse IP addresses from user input const addrs = []; for (const ip of this.inputText.split("\n").map(s => s.replace(/[\u200B-\u200F]/, "").trim()).filter(s => s)) { if (!protocol.isValid(ip)) return alert(`ERROR: "${ip}" is not a valid IPv${this.selectedIPType} address, please fix this before proceeding.`); addrs.push(ipaddr.parse(ip)); } // count backwards until we get a CIDR match const first = addrs[0]; for (const ip of addrs.slice(1)) while (!ip.match(first, cnt) && cnt) cnt--; // show warning for big ranges if (cnt < warningThreshold) this.showBigRangeWarning = true; // apply appropriate subnet mask to first IP address const addrBytes = first.toByteArray(), mask = protocol.subnetMaskFromPrefixLength(cnt).toByteArray(); for (let i = 0; i < mask.length; i++) addrBytes[i] &= mask[i]; this.resultText = `${ipaddr.fromByteArray(addrBytes).toString()}/${cnt}` this.showResult = true; } } }).mount("#app"); </script> </body> </html>