diff options
| author | Yuval Adam <_@yuv.al> | 2025-05-21 17:59:44 +0200 |
|---|---|---|
| committer | Yuval Adam <_@yuv.al> | 2025-05-21 17:59:44 +0200 |
| commit | f043c0bae4242f117bf3ea545228709e11db6a2e (patch) | |
| tree | b761d07e5559650f90116dba73bcedf93ed6cc76 | |
| parent | 10a5f6c5d9280bd375db64f6581d9a554ce2c496 (diff) | |
Initial guide
| -rw-r--r-- | package-lock.json | 62 | ||||
| -rw-r--r-- | package.json | 5 | ||||
| -rw-r--r-- | src/components/Prose.astro | 27 | ||||
| -rw-r--r-- | src/content/cidr-guide.md | 74 | ||||
| -rw-r--r-- | src/pages/cidr-calculator-subnet-guide.astro | 113 | ||||
| -rw-r--r-- | src/styles/global.css | 3 |
6 files changed, 280 insertions, 4 deletions
diff --git a/package-lock.json b/package-lock.json index 44fc123..66398f3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@astrojs/react": "^4.2.7", "@tailwindcss/vite": "^4.1.5", + "@types/netmask": "^2.0.5", "@types/react": "^19.1.3", "@types/react-dom": "^19.1.3", "astro": "^5.7.12", @@ -19,7 +20,7 @@ "tailwindcss": "^4.1.5" }, "devDependencies": { - "@types/netmask": "^2.0.5" + "@tailwindcss/typography": "^0.5.16" } }, "node_modules/@ampproject/remapping": { @@ -1840,6 +1841,22 @@ "node": ">= 10" } }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz", + "integrity": "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1" + } + }, "node_modules/@tailwindcss/vite": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.7.tgz", @@ -1947,7 +1964,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@types/netmask/-/netmask-2.0.5.tgz", "integrity": "sha512-9Q5iw9+pHZBVLDG700dlQSWWHTYvOb8KfPjfQTNckCYky4IyjV2xh81+RgC1CCwqv92bYLpz1cVKyJav0B88uQ==", - "dev": true, "license": "MIT" }, "node_modules/@types/nlcst": { @@ -3627,6 +3643,27 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, "node_modules/longest-streak": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", @@ -4782,6 +4819,20 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/prismjs": { "version": "1.30.0", "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz", @@ -5792,6 +5843,13 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, "node_modules/vfile": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", diff --git a/package.json b/package.json index e5540fb..47be3c8 100644 --- a/package.json +++ b/package.json @@ -20,5 +20,8 @@ "react": "^19.1.0", "react-dom": "^19.1.0", "tailwindcss": "^4.1.5" + }, + "devDependencies": { + "@tailwindcss/typography": "^0.5.16" } -}
\ No newline at end of file +} diff --git a/src/components/Prose.astro b/src/components/Prose.astro new file mode 100644 index 0000000..aecfca2 --- /dev/null +++ b/src/components/Prose.astro @@ -0,0 +1,27 @@ +--- +// Prose component for styling markdown content +--- + +<div + class="prose prose-lg max-w-none mx-auto px-4 sm:px-6 lg:px-8 py-8 + prose-headings:font-bold prose-headings:text-gray-900 prose-headings:mb-4 prose-headings:mt-8 + prose-h1:text-4xl prose-h1:mt-0 + prose-h2:text-2xl prose-h2:border-b prose-h2:border-gray-200 prose-h2:pb-2 + prose-h3:text-xl + prose-p:text-gray-700 prose-p:my-4 prose-p:leading-relaxed + prose-a:text-blue-600 prose-a:font-medium prose-a:no-underline hover:prose-a:underline + prose-strong:font-bold prose-strong:text-gray-900 + prose-ul:my-6 prose-ul:list-disc prose-ul:pl-6 + prose-ol:my-6 prose-ol:list-decimal prose-ol:pl-6 + prose-li:my-2 prose-li:text-gray-700 + prose-blockquote:border-l-4 prose-blockquote:border-blue-500 prose-blockquote:pl-4 prose-blockquote:py-1 prose-blockquote:my-6 prose-blockquote:bg-blue-50 prose-blockquote:rounded-r-md + prose-blockquote:text-gray-700 prose-blockquote:italic + prose-img:rounded-lg prose-img:shadow-md prose-img:my-8 + prose-hr:my-8 prose-hr:border-gray-200 + prose-code:text-gray-800 prose-code:bg-gray-100 prose-code:px-1 prose-code:py-0.5 prose-code:rounded prose-code:text-sm + prose-pre:bg-gray-900 prose-pre:text-gray-100 prose-pre:p-4 prose-pre:rounded-lg prose-pre:overflow-x-auto prose-pre:my-6 + prose-pre:shadow-md prose-pre:text-sm + dark:prose-invert dark:prose-pre:bg-gray-800 dark:prose-code:bg-gray-800 dark:prose-blockquote:bg-gray-800" +> + <slot /> +</div> diff --git a/src/content/cidr-guide.md b/src/content/cidr-guide.md new file mode 100644 index 0000000..38fe8b2 --- /dev/null +++ b/src/content/cidr-guide.md @@ -0,0 +1,74 @@ +# CIDR Calculator & Subnet Guide + +Convert CIDR blocks to IP ranges and master subnetting for IPv4 & IPv6—all in one place. + +--- + +## What is CIDR? + +**Classless Inter-Domain Routing (CIDR)** is the system that replaced the old class-A/B/C scheme in 1993. +A network is written as + +``` +address/prefix-length → 10.0.0.0/24 +``` + +The *prefix length* (the number after the slash) tells routers how many of the 32 bits belong to the network portion: + +* `10.0.0.0/24` → 24 network bits + 8 host bits → **256** addresses (254 usable) +* `10.0.0.0/30` → 30 network bits + 2 host bits → **4** addresses (2 usable) + +CIDR lets ISPs advertise aggregated “supernets” such as `203.0.113.0/22` instead of listing a thousand individual /24 routes—shrinking global routing tables and conserving address space. + +--- + +## CIDR → IP Range Converter + +Paste any block—say `192.168.15.64/27`—into the calculator. Behind the scenes it: + +1. **Bitwise-ANDs** the IP with the mask to find the **network address**. +2. **Inverts** the mask and ORs it with the IP to get the **broadcast address**. +3. Offsets ±1 to reveal the **first** and **last usable hosts**. + +Hit **Copy Share Link** to bookmark or send an exact result. + +--- + +## Subnetting Tutorial — Quick Steps + +Subnetting seems daunting until you break it into four predictable moves: + +1. **Convert the prefix** `/26` → `255 .255 .255 .192` +2. **Find block size** 256 − 192 = 64 +3. **List subnet starts** 0, 64, 128, 192 +4. **Pick your block** Usable hosts = block size − 2 (62 in a /26) + +> **Example** +> Split `172.16.0.0/16` into at least 10 equal subnets. +> *Need ≥10 blocks → 4 extra bits (2⁴ = 16)* +> New prefix = **/20**. Each /20 holds 4094 hosts. +> Ranges begin 172.16.0.0, 172.16.16.0, 172.16.32.0 … to 172.16.240.0. + +--- + +## IPv6 Subnetting Basics + +The slash notation is identical in IPv6—just with 128-bit addresses. + +* **/64** is the standard LAN size → 18 quintillion addresses +* Providers often delegate: + + * `/48` — 65 536 customer /64s + * `/56` — 256 /64s + * `/60` — 16 /64s + +Toggle **IPv6** in the calculator and try `2001:db8::/48` to explore the range graphically. + +--- + +## Further Reading & Tools + +* RFC 4632 — *Classless Inter-Domain Routing for IPv6* +* RFC 1519 — *CIDR Address Allocation for IPv4* +* [cidr.xyz source code](https://github.com/yuvadm/cidr.xyz) +* *Subnetting Examples* blog series (coming soon) diff --git a/src/pages/cidr-calculator-subnet-guide.astro b/src/pages/cidr-calculator-subnet-guide.astro new file mode 100644 index 0000000..09b553a --- /dev/null +++ b/src/pages/cidr-calculator-subnet-guide.astro @@ -0,0 +1,113 @@ +--- +import Layout from "../layouts/Layout.astro"; +import Cidr from "../components/Cidr"; +import { faqs } from "../content/faqs.ts"; +import Prose from "../components/Prose.astro"; + +// ──────────────────────────────────────────────────────────── +// Metadata +// ──────────────────────────────────────────────────────────── +const title = "CIDR Calculator & Subnet Guide — IP Ranges, Masks & IPv6"; +const description = + "Free interactive CIDR calculator and comprehensive plain‑language guide covering subnetting, IP ranges, subnet masks and IPv6 addressing."; + +// FAQ structured‑data (kept in sync with UI) +const faqJsonLd = { + "@context": "https://schema.org", + "@type": "FAQPage", + mainEntity: faqs.map(({ q, a }) => ({ + "@type": "Question", + name: q, + acceptedAnswer: { "@type": "Answer", text: a }, + })), +}; + +import { Content as GuideContent } from "../content/cidr-guide.md"; +--- + +<Layout title={title} description={description}> + { + /** + ──────────────────────────────────────────────────────────── + Hero + ────────────────────────────────────────────────────────────*/ + } + <header + class="relative isolate overflow-hidden bg-gradient-to-br from-blue-50 via-indigo-50 to-white rounded-xl shadow-sm" + > + <div class="mx-auto max-w-7xl px-4 py-20 sm:py-24 lg:px-6 text-center"> + <h1 + class="text-4xl font-extrabold tracking-tight text-gray-900 sm:text-6xl" + > + CIDR Calculator & Subnet Guide + </h1> + <p class="mt-4 text-lg sm:text-xl max-w-2xl mx-auto text-gray-700"> + Convert CIDR blocks to IP ranges and master subnetting for IPv4 + & IPv6 — in one streamlined resource. + </p> + </div> + </header> + + { + /** + ──────────────────────────────────────────────────────────── + Calculator block + ────────────────────────────────────────────────────────────*/ + } + <section class="mx-auto mt-12 max-w-4xl px-2 sm:px-4"> + <Cidr client:load /> + </section> + + { + /** + ──────────────────────────────────────────────────────────── + Table of Contents (desktop only for cleanliness) + ────────────────────────────────────────────────────────────*/ + } + <nav + aria-label="Page sections" + class="hidden lg:block sticky top-0 z-10 bg-white/90 backdrop-blur border-b border-gray-200" + > + <div class="mx-auto max-w-4xl px-4"> + <ul + class="flex flex-wrap justify-center gap-6 py-3 text-sm font-medium text-gray-600" + > + <li> + <a href="#what-is-cidr" class="hover:text-blue-600" + >What is CIDR?</a + > + </li> + <li> + <a href="#cidr-to-ip" class="hover:text-blue-600" + >CIDR → IP range</a + > + </li> + <li> + <a href="#subnetting-tutorial" class="hover:text-blue-600" + >Subnetting tutorial</a + > + </li> + <li> + <a href="#ipv6" class="hover:text-blue-600">IPv6 basics</a> + </li> + <li><a href="#faq" class="hover:text-blue-600">FAQ</a></li> + <li> + <a href="#resources" class="hover:text-blue-600" + >Resources</a + > + </li> + </ul> + </div> + </nav> + + <Prose> + <GuideContent /> + </Prose> + + {/** Structured‑data block */} + <script + type="application/ld+json" + is:inline + set:html={JSON.stringify(faqJsonLd, null, 2)} + /> +</Layout> diff --git a/src/styles/global.css b/src/styles/global.css index a461c50..cba2dd6 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -1 +1,2 @@ -@import "tailwindcss";
\ No newline at end of file +@import "tailwindcss"; +@plugin '@tailwindcss/typography';
\ No newline at end of file |
