with one click
IP subnetting and network segmentation
npx skills add https://github.com/ffsshhttiikk/opencode-agents-skills --skill subnettingCopy and paste this command into Claude Code to install the skill
IP subnetting and network segmentation
npx skills add https://github.com/ffsshhttiikk/opencode-agents-skills --skill subnettingCopy and paste this command into Claude Code to install the skill
| name | subnetting |
| description | IP subnetting and network segmentation |
| category | networking |
| difficulty | intermediate |
| tags | ["ip","subnet","network","cidr","routing"] |
| author | OpenCode Community |
| version | 1 |
| last_updated | "2024-01-15T00:00:00.000Z" |
I am Subnetting, the practice of dividing a larger network into smaller, manageable network segments. I enable efficient IP address allocation, improve network performance through broadcast domain reduction, and enhance security through network segmentation. I use CIDR (Classless Inter-Domain Routing) notation to define network boundaries. I help network administrators optimize address space utilization, implement security boundaries, and create hierarchical routing structures. I work with IPv4 and IPv6 addressing schemes, implementing variable length subnet masks (VLSM) for flexible network designs. I enable organizations to build scalable, secure, and manageable network infrastructures.
CIDR Notation: IP address with prefix length (e.g., 192.168.1.0/24)
Subnet Mask: 32-bit value separating network and host portions
Network Address: All host bits set to 0
Broadcast Address: All host bits set to 1
Usable Hosts: 2^(host_bits) - 2 (network + broadcast)
VLSM: Variable Length Subnet Masking for flexible subnet sizes
Supernetting/Route Aggregation: Combining multiple subnets into larger networks
Private Address Ranges: RFC 1918 (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
import ipaddress
from typing import List, Tuple, Optional
from dataclasses import dataclass
from enum import Enum
class IPVersion(Enum):
IPv4 = 4
IPv6 = 6
@dataclass
class SubnetInfo:
network: str
netmask: str
prefix_length: int
version: IPVersion
num_addresses: int
usable_hosts: int
network_address: str
broadcast_address: str
first_usable: str
last_usable: str
cidr: str
binary_netmask: str
classful_class: Optional[str] = None
class SubnetCalculator:
def __init__(self):
pass
def calculate(self, cidr: str) -> SubnetInfo:
"""Calculate all subnet information from CIDR notation"""
net = ipaddress.ip_network(cidr, strict=False)
version = IPVersion.IPv4 if net.version == 4 else IPVersion.IPv6
first_usable = net.network_address + 1 if version == IPVersion.IPv4 else net.network_address
last_usable = net.broadcast_address - 1 if version == IPVersion.IPv4 else net.broadcast_address - 1
num_addresses = net.num_addresses
usable_hosts = max(0, num_addresses - 2) if version == IPVersion.IPv4 else num_addresses - 1
return SubnetInfo(
network=str(net.network_address),
netmask=str(net.netmask),
prefix_length=net.prefixlen,
version=version,
num_addresses=num_addresses,
usable_hosts=usable_hosts,
network_address=str(net.network_address),
broadcast_address=str(net.broadcast_address),
first_usable=str(first_usable),
last_usable=str(last_usable),
cidr=str(net),
binary_netmask=self._to_binary(net.netmask),
classful_class=self._get_classful_class(net.network_address) if version == IPVersion.IPv4 else None
)
def _to_binary(self, netmask) -> str:
"""Convert netmask to binary representation"""
return ''.join(f'{octet:08b}.' for octet in netmask.packed).rstrip('.')
def _get_classful_class(self, ip) -> Optional[str]:
"""Get classful address class"""
first_octet = int(ip.packed[0])
if 1 <= first_octet <= 126:
return "A"
elif 128 <= first_octet <= 191:
return "B"
elif 192 <= first_octet <= 223:
return "C"
elif 224 <= first_octet <= 239:
return "D (Multicast)"
elif 240 <= first_octet <= 255:
return "E (Experimental)"
return None
def subnet_into(self, cidr: str, num_subnets: int = None,
new_prefix: int = None) -> List[SubnetInfo]:
"""Divide a network into smaller subnets"""
net = ipaddress.ip_network(cidr, strict=False)
if new_prefix:
prefix_length = new_prefix
elif num_subnets:
current_prefix = net.prefixlen
needed_bits = (num_subnets - 1).bit_length()
prefix_length = current_prefix + needed_bits
else:
raise ValueError("Must specify num_subnets or new_prefix")
subnets = []
for subnet in net.subnets(new_prefix=prefix_length):
subnets.append(self.calculate(str(subnet)))
return subnets
def summarize_networks(self, networks: List[str]) -> List[SubnetInfo]:
"""Aggregate multiple networks into larger summarized networks"""
nets = [ipaddress.ip_network(n, strict=False) for n in networks]
summarized = list(ipaddress.collapse_addresses(nets))
return [self.calculate(str(s)) for s in summarized]
def find_supernet(self, cidr1: str, cidr2: str) -> Optional[SubnetInfo]:
"""Find the smallest supernet containing two networks"""
net1 = ipaddress.ip_network(cidr1, strict=False)
net2 = ipaddress.ip_network(cidr2, strict=False)
combined = list(ipaddress.collapse_addresses([net1, net2]))
if len(combined) == 1:
return self.calculate(str(combined[0]))
return None
def is_subnet_of(self, subnet: str, parent: str) -> bool:
"""Check if subnet is contained within parent network"""
return ipaddress.ip_network(subnet, strict=False).subnet_of(
ipaddress.ip_network(parent, strict=False)
)
def get_supernet_for_hosts(self, num_hosts: int,
prefer_largest: bool = True) -> SubnetInfo:
"""Find smallest subnet that can accommodate N hosts"""
needed_bits = (num_hosts + 2).bit_length()
prefix_length = 32 - needed_bits
if prefer_largest:
prefix_length = max(0, prefix_length - 1)
network = ipaddress.IPv4Network(f"0.0.0.0/{prefix_length}", strict=False)
return self.calculate(str(network))
def calculate_vlsm(self, host_requirements: List[int],
starting_cidr: str = "192.168.0.0/24") -> List[SubnetInfo]:
"""Variable Length Subnet Masking - assign subnets based on needs"""
net = ipaddress.ip_network(starting_cidr, strict=False)
sorted_reqs = sorted(host_requirements, reverse=True)
subnets = []
current_address = int(net.network_address)
for req in sorted_reqs:
needed_hosts = req + 2 if net.version == 4 else req + 1
needed_bits = (needed_hosts - 1).bit_length()
prefix_length = 32 - needed_bits
subnet_size = 2 ** needed_bits
subnet = ipaddress.IPv4Network(
f"{ipaddress.IPv4Address(current_address)}/{prefix_length}",
strict=False
)
subnets.append(self.calculate(str(subnet)))
current_address += subnet_size
return subnets
def ip_to_binary(self, ip: str) -> str:
"""Convert IP address to binary string"""
packed = ipaddress.ip_address(ip).packed
return ''.join(f'{byte:08b}' for byte in packed)
def get_network_range(self, cidr: str) -> Tuple[str, str]:
"""Get the start and end IP addresses of a network"""
net = ipaddress.ip_network(cidr, strict=False)
return (str(net.network_address), str(net.broadcast_address))
# Example usage
if __name__ == "__main__":
calc = SubnetCalculator()
# Calculate single subnet
print("=== Subnet Analysis: 192.168.1.0/24 ===")
info = calc.calculate("192.168.1.0/24")
print(f"Network: {info.network}")
print(f"Netmask: {info.netmask}")
print(f"Prefix: /{info.prefix_length}")
print(f"Usable Hosts: {info.usable_hosts}")
print(f"Range: {info.first_usable} - {info.last_usable}")
print()
# Subnet division
print("=== Divide into /26 subnets ===")
subnets = calc.subnet_into("192.168.1.0/24", new_prefix=26)
for i, subnet in enumerate(subnets):
print(f"Subnet {i+1}: {subnet.cidr} ({subnet.usable_hosts} hosts)")
print()
# VLSM calculation
print("=== VLSM Allocation ===")
requirements = [50, 25, 10, 10, 5]
vlsm_subnets = calc.calculate_vlsm(requirements)
for i, subnet in enumerate(vlsm_subnets):
print(f"Requirement {requirements[i]} hosts: {subnet.cidr}")
import socket
import subprocess
import concurrent.futures
from typing import List, Dict
from dataclasses import dataclass
from datetime import datetime
from subnetting import SubnetCalculator
@dataclass
class HostInfo:
ip: str
hostname: str
mac_address: str = "Unknown"
status: str = "unknown"
response_time_ms: float = 0.0
open_ports: List[int] = None
last_seen: datetime = None
class NetworkScanner:
def __init__(self, timeout: float = 1.0, max_workers: int = 100):
self.timeout = timeout
self.max_workers = max_workers
self.calculator = SubnetCalculator()
def ping_host(self, ip: str) -> bool:
"""Check if host is reachable via ICMP"""
try:
subprocess.run(
['ping', '-c', '1', '-W', '1', ip],
capture_output=True,
timeout=2
)
return True
except:
return False
def scan_port(self, ip: str, port: int, timeout: float = None) -> bool:
"""Check if a specific port is open"""
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(timeout or self.timeout)
result = sock.connect_ex((ip, port))
sock.close()
return result == 0
def get_hostname(self, ip: str) -> str:
"""Reverse DNS lookup"""
try:
hostname = socket.gethostbyaddr(ip)[0]
return hostname
except:
return "Unknown"
def scan_network(self, cidr: str, ports: List[int] = None) -> List[HostInfo]:
"""Scan entire network for hosts"""
info = self.calculator.calculate(cidr)
hosts = []
for i in range(1, info.num_addresses - 1):
ip = str(info.network_address + i)
if self.ping_host(ip):
host_info = HostInfo(
ip=ip,
hostname=self.get_hostname(ip),
status="online",
last_seen=datetime.now()
)
if ports:
host_info.open_ports = self.scan_ports(ip, ports)
hosts.append(host_info)
return hosts
def scan_ports(self, ip: str, ports: List[int]) -> List[int]:
"""Scan multiple ports on a host"""
open_ports = []
with concurrent.futures.ThreadPoolExecutor(max_workers=50) as executor:
futures = {
executor.submit(self.scan_port, ip, port): port
for port in ports
}
for future in concurrent.futures.as_completed(futures):
port = futures[future]
try:
if future.result():
open_ports.append(port)
except:
pass
return sorted(open_ports)
def scan_common_ports(self, ip: str) -> Dict[int, str]:
"""Scan common service ports"""
common_ports = {
21: "FTP",
22: "SSH",
23: "Telnet",
25: "SMTP",
53: "DNS",
80: "HTTP",
110: "POP3",
143: "IMAP",
443: "HTTPS",
445: "SMB",
3389: "RDP",
8080: "HTTP-Alt"
}
open_ports = self.scan_ports(ip, list(common_ports.keys()))
return {port: common_ports[port] for port in open_ports}
def generate_report(self, hosts: List[HostInfo]) -> str:
"""Generate network scan report"""
report = []
report.append("=" * 60)
report.append("NETWORK SCAN REPORT")
report.append("=" * 60)
report.append(f"Scan Date: {datetime.now().isoformat()}")
report.append(f"Hosts Found: {len(hosts)}")
report.append("")
online_hosts = [h for h in hosts if h.status == "online"]
report.append(f"Online Hosts: {len(online_hosts)}")
for host in sorted(online_hosts, key=lambda x: socket.inet_aton(x.ip)):
report.append("-" * 40)
report.append(f"IP: {host.ip}")
report.append(f"Hostname: {host.hostname}")
report.append(f"Status: {host.status}")
if host.open_ports:
report.append("Open Ports:")
for port in host.open_ports:
report.append(f" - {port}")
return '\n'.join(report)
if __name__ == "__main__":
scanner = NetworkScanner()
print("Scanning network...")
hosts = scanner.scan_network("192.168.1.0/24", [22, 80, 443, 8080])
report = scanner.generate_report(hosts)
print(report)
package main
import (
"fmt"
"os/exec"
"strings"
"net"
"bytes"
"encoding/csv"
)
type Route struct {
Destination string
Gateway string
Genmask string
Flags string
Metric int
Ref int
Use int
Interface string
}
type RoutingTable struct {
routes []Route
}
func (rt *RoutingTable) Parse() error {
output, err := exec.Command("route", "-n").Output()
if err != nil {
return fmt.Errorf("failed to get routing table: %w", err)
}
lines := strings.Split(string(output), "\n")
rt.routes = make([]Route, 0)
for _, line := range lines[1:] {
if strings.TrimSpace(line) == "" || strings.HasPrefix(line, "Kernel") {
continue
}
fields := strings.Fields(line)
if len(fields) < 8 {
continue
}
route := Route{
Destination: fields[0],
Gateway: fields[1],
Genmask: fields[2],
Flags: fields[3],
}
fmt.Sscanf(fields[4], "%d", &route.Metric)
fmt.Sscanf(fields[5], "%d", &route.Ref)
fmt.Sscanf(fields[6], "%d", &route.Use)
route.Interface = fields[7]
rt.routes = append(rt.routes, route)
}
return nil
}
func (rt *RoutingTable) GetRouteForDestination(destination string) *Route {
destIP := net.ParseIP(destination)
var bestMatch *Route
var bestPrefixLen int
for i := range rt.routes {
route := &rt.routes[i]
routeNet := net.ParseIP(route.Destination)
routeMask := net.ParseIP(route.Genmask)
prefixLen := 0
for j := range routeIP := range routeIP {
maskByte := routeMask[j]
for k := 0; k < 8; k++ {
if maskByte&(1<<uint(7-k)) != 0 {
prefixLen++
}
}
}
// Check if destination is in this route's network
match := true
for i := range destIP {
if (destIP[i] & routeMask[i]) != (routeNet[i] & routeMask[i]) {
match = false
break
}
}
if match && prefixLen > bestPrefixLen {
bestPrefixLen = prefixLen
bestMatch = route
}
}
return bestMatch
}
func (rt *RoutingTable) AddRoute(destination, gateway, netmask, interface string, metric int) error {
cmd := exec.Command("route", "add", "-net", destination, "netmask", netmask, "gw", gateway, "metric", fmt.Sprintf("%d", metric), interface)
return cmd.Run()
}
func (rt *RoutingTable) DeleteRoute(destination, netmask string) error {
cmd := exec.Command("route", "del", "-net", destination, "netmask", netmask)
return cmd.Run()
}
func (rt *RoutingTable) ExportToCSV(filename string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()
writer := csv.NewWriter(file)
defer writer.Flush()
headers := []string{"Destination", "Gateway", "Genmask", "Flags", "Metric", "Ref", "Use", "Interface"}
writer.Write(headers)
for _, route := range rt.routes {
row := []string{
route.Destination,
route.Gateway,
route.Genmask,
route.Flags,
fmt.Sprintf("%d", route.Metric),
fmt.Sprintf("%d", route.Ref),
fmt.Sprintf("%d", route.Use),
route.Interface,
}
writer.Write(row)
}
return nil
}
func CalculateSubnet(cidr string) (string, string, error) {
_, ipNet, err := net.ParseCIDR(cidr)
if err != nil {
return "", "", err
}
networkAddress := ipNet.IP.String()
broadcast := make(net.IP, len(ipNet.IP))
for i := range ipNet.IP {
broadcast[i] = ipNet.IP[i] | ^ipNet.Mask[i]
}
broadcastAddress := broadcast.String()
return networkAddress, broadcastAddress, nil
}
func main() {
rt := &RoutingTable{}
if err := rt.Parse(); err != nil {
fmt.Printf("Error parsing routing table: %v\n", err)
return
}
fmt.Println("Current Routing Table:")
fmt.Println("----------------------")
for _, route := range rt.routes {
fmt.Printf("%-15s %-15s %-15s %s\n",
route.Destination, route.Gateway, route.Genmask, route.Interface)
}
route := rt.GetRouteForDestination("8.8.8.8")
if route != nil {
fmt.Printf("\nRoute to 8.8.8.8: Gateway=%s Interface=%s\n",
route.Gateway, route.Interface)
}
}
Statistical physics and thermodynamics
Statistical analysis for scientific research
Statistical analysis and methods
3D structure of biological molecules
Structural biology fundamentals
Svelte reactive JavaScript framework with compile-time optimization