Browse Source

ipcalc: DIY version

master
Maxim Likhachev 4 years ago
parent
commit
3908f3e296
  1. 1
      README.md
  2. 278
      scripts/ipcalc

1
README.md

@ -70,6 +70,7 @@ will create the symbolic link for each script in the \<path> directory.
## Network ## Network
- [check-cert](scripts/check-cert) retrieves information about web site's TLS certificate. - [check-cert](scripts/check-cert) retrieves information about web site's TLS certificate.
- [ipcalc](scripts/ipcalc) is DIY tcl version of [jodies.de/ipcalc](https://jodies.de/ipcalc), it takes an IP address and netmask and calculates the resulting broadcast, network, Cisco wildcard mask, and host range.
## WWW ## WWW

278
scripts/ipcalc

@ -0,0 +1,278 @@
#!/usr/bin/env tclsh
# Copyright (C) 2021, Maxim Lihachev, <envrm@yandex.ru>
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published
# by the Free Software Foundation, version 3.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# ------------------------------------------------------------------------------
#
# DESCRIPTION
#
# DIY project that implement basic `ipcalc' functions for IP Address
# calculating.
#
#
# USAGE
#
# ipcalc ip/mask
# e.g. ipcalc 192.168.0.1/24
# ipcalc 192.168.0.1/255.255.255.0
#
# ------------------------------------------------------------------------------
# Convert integer to binary
proc int2bin {int} {
binary scan [binary format c $int] B* bin
return $bin
}
# Convert binary to integer
proc bin2int {bin} {
expr {"0b$bin"}
}
# Convert binary form of IP address to decimal one
proc binary2decimal {binary_ip} {
join [lmap x [split_binary_ip $binary_ip] {bin2int $x}] {.}
}
# Convert decimal form of IP addrecc to binary one
proc decimal2binary {decimal_ip} {
return [join [lmap x [split $decimal_ip {.}] {int2bin $x}] {.}]
}
# Normalize binary form of IP address
# E.g.:
# 11111111.11111111.11111111.00000000 => 11111111111111111111111100000000
# 11111111 11111111 11111111 00000000 => 11111111111111111111111100000000
proc normalize_binary_ip {ip} {
string map {{.} {} { } {}} $ip
}
# Split normal form of binary IP address to chunks
# E.g.
# 11111111111111111111111100000000 => 11111111 11111111 11111111 00000000
proc split_binary_ip {ip} {
regexp -all -inline .{8} [normalize_binary_ip $ip]
}
# Make a dotted form of binary IP address
# E.g.
# 11111111111111111111111100000000 => 11111111.11111111.11111111.00000000
proc format_binary_ip {binary_ip} {
join [split_binary_ip $binary_ip] {.}
}
# Zip two lists with function
proc zipwith {list1 list2 fx} {
set l1 [regexp -all -inline {.} $list1]
set l2 [regexp -all -inline {.} $list2]
lmap x $l1 y $l2 {apply $fx $x $y}
}
# Bitwise AND digit by digit
# E.g.:
# 11011011
# 11011000
# ||||||||
# 11011000
proc bitwise_and {ip1 ip2} {
join [zipwith $ip1 $ip2 {{x y} {expr {$x & $y}}}] {}
}
# Bitwise OR digit by digit
# E.g.:
# 11011011
# 11011000
# ||||||||
# 11011011
proc bitwise_or {ip1 ip2} {
join [zipwith $ip1 $ip2 {{x y} {expr {$x | $y}}}] {}
}
# Print data in default ipcalc format
proc show {label {decimal {}} {binary {}}} {
puts [format "%-11s%-21s%s" $label $decimal $binary]
}
# ------------------------------------------------------------------------------
# Get network class
proc network_class {ip} {
set first_octet [lindex [split $ip "."] 0]
if {$first_octet <= 127} {
set network_class "Class A"
} elseif {$first_octet <= 191} {
set network_class "Class B"
} elseif {$first_octet <= 223} {
set network_class "Class C"
} elseif {$first_octet <= 239} {
set network_class "Class D"
} elseif {$first_octet <= 247} {
set network_class "Class E"
}
}
# Calculate wildcard
proc wildcard {ip netmask} {
set netmask [integer_netmask $netmask]
set binary_wildcard [format_binary_ip [string repeat 0 $netmask][string repeat 1 [expr {32-$netmask}]]]
set decimal_wildcard [binary2decimal $binary_wildcard]
return [list $decimal_wildcard $binary_wildcard]
}
# Get count of available hosts
proc hosts_count {netmask} {
set netmask [integer_netmask $netmask]
expr {2 ** (32 - $netmask) - ($netmask >= 30 ? 0 : 2)}
}
# 190.0.0.1 10111110.00000000.00000000.00000001
# 255.255.240.0 11111111.11111111.11110000.00000000
# &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
# 190.0.0.0 10111110.00000000.00000000.00000000
proc network {ip netmask} {
set binary_address [normalize_binary_ip [decimal2binary $ip]]
set binary_netmask [normalize_binary_ip [binary_netmask $netmask]]
set binary_network [format_binary_ip [bitwise_and $binary_address $binary_netmask]]
set network [binary2decimal $binary_network]
return [list "${network}/[integer_netmask $netmask]" $binary_network]
}
# 255.255.240.0 11111111.11111111.11110000.00000000
# bit mask 00000000.00000000.00001111.11111111
# 190.0.0.1 10111110.00000000.00000000.00000001
# |||||||||||||||||||||||||||||||||||
# 190.0.15.255 10111110.00000000.00001111.11111111
proc host_broadcast {ip netmask} {
set binary_address [normalize_binary_ip [decimal2binary $ip]]
set binary_netmask [normalize_binary_ip [binary_netmask $netmask]]
# 1 => 0, 0 => 1
set binary_bitmask [string map {1 0 0 1} $binary_netmask]
set binary_broadcast [format_binary_ip [bitwise_or $binary_address $binary_bitmask]]
set host_broadcast [binary2decimal $binary_broadcast]
return [list $host_broadcast $binary_broadcast]
}
# broadcast-1
#
# 190.0.0.1 10111110.00000000.00000000.00000001
# 255.255.240.0 11111111.11111111.11110000.00000000
# 190.0.15.255 10111110.00000000.00001111.11111111
#
# 190.0.15.255-1 10111110.00000000.00001111.11111111-1
# 190.0.15.254 10111110.00000000.00001111.11111110
proc host_max {ip netmask} {
set binary_broadcast [lindex [host_broadcast $ip $netmask] 1]
set binary_max_host [format_binary_ip [expr {[normalize_binary_ip [lindex [host_broadcast $ip $netmask] 1]]-1}]]
set max_host [binary2decimal $binary_max_host]
return [list $max_host $binary_max_host]
}
# network+1
#
# 190.0.0.1 10111110.00000000.00000000.00000001
# 255.255.240.0 11111111.11111111.11110000.00000000
# 190.0.0.0 10111110.00000000.00000000.00000000
#
# 190.0.0.0+1 10111110.00000000.00000000.00000000
# 190.0.0.1 10111110.00000000.00000000.00000001
proc host_min {ip netmask} {
set network [lindex [network $ip $netmask] 1]
set min_host [expr {[normalize_binary_ip $network]+1}]
set binary_min_host [format_binary_ip $min_host]
set decimal_min_host [binary2decimal $min_host]
return [list $decimal_min_host $binary_min_host]
}
proc decimal_netmask {netmask} {
lindex $netmask 0
}
proc integer_netmask {netmask} {
lindex $netmask 1
}
proc binary_netmask {netmask} {
lindex $netmask 2
}
# Calculate netmask in decimal, binary and integer formats
proc netmask {mask} {
proc make_binary_netmask {netmask} {
format_binary_ip [string repeat 1 $netmask][string repeat 0 [expr {32-$netmask}]]
}
proc make_integer_netmask {netmask} {
expr {[llength [split [decimal2binary $netmask] {1}]]-1}
}
if {[string is integer -strict $mask]} {
set integer_netmask $mask
set binary_netmask [make_binary_netmask $mask]
set decimal_netmask [binary2decimal $binary_netmask]
} else {
set integer_netmask [make_integer_netmask $mask]
set binary_netmask [make_binary_netmask $integer_netmask]
set decimal_netmask $mask
}
return [list $decimal_netmask $integer_netmask $binary_netmask]
}
# ------------------------------------------------------------------------------
set script_name [file tail $argv0]
if {$argc < 1} {
puts "USAGE: $script_name ip/mask"
puts " e.g. $script_name 192.168.0.1/24"
puts " $script_name 192.168.0.1/255.255.255.0"
exit 1
}
# ------------------------------------------------------------------------------
lassign [split [string map {{ } {/}} $argv] {/}] address mask
if {$mask != {}} {
set netmask [netmask $mask]
} else {
set netmask [netmask 24]
}
# ------------------------------------------------------------------------------
# Default `ipcalc' output format
show Address: $address [decimal2binary $address]
show Netmask: "[decimal_netmask $netmask] = [integer_netmask $netmask]" [binary_netmask $netmask]
show Wildcard: {*}[wildcard $address $netmask]
show =>
show Network: {*}[network $address $netmask]
show HostMin: {*}[host_min $address $netmask]
show HostMax: {*}[host_max $address $netmask]
show Broadcast: {*}[host_broadcast $address $netmask]
show Host/Net: [hosts_count $netmask] [network_class $address]
show {}
Loading…
Cancel
Save