132 lines
3.4 KiB
Text
132 lines
3.4 KiB
Text
//
|
|
// Canonicalize CIDR
|
|
//
|
|
// Using FutureBasic 7.0.34
|
|
// August 25, R.W
|
|
//
|
|
// Given a Classless Inter-Domain Routing (CIDR)
|
|
// IPv4 address, returns the canonical form.
|
|
//
|
|
|
|
Int networkWidth // network width in bits
|
|
CFStringRef errorCode // global err and CCIDR
|
|
CFStringRef CCIDR // canonical CIDR IPv4
|
|
|
|
// Type for IP address
|
|
begin record IPv4_Address
|
|
Int octets[3] // xxx.xxx.xxx.xx/xx
|
|
end record
|
|
|
|
// Validate CIDR string
|
|
local fn ValidateCIDR(ip as IPv4_Address, SnetworkWidth as Int, cidr as CFStringRef) as Boolean
|
|
Int i
|
|
boolean result
|
|
result = _True
|
|
if instr(0, cidr, @"/") == NSNotFound
|
|
errorCode = concat(@"Bad CIDR ",cidr)
|
|
result = _False
|
|
return result
|
|
end if
|
|
if SnetworkWidth < 1 || SnetworkWidth > 32 //validate network width
|
|
errorCode = concat(@"Bad Net Width",str(networkWidth))
|
|
result = _False
|
|
return result
|
|
end if
|
|
for i = 0 to 3
|
|
if ip.octets[i] > 255
|
|
errorCode = concat(@"Bad Octet ",str(ip.octets[i]))
|
|
result = _False
|
|
return result
|
|
end if
|
|
next
|
|
end fn = result
|
|
|
|
// Check if a character is a digit
|
|
local fn IsDigit(ch as CFStringRef) as boolean
|
|
Boolean IsDigit
|
|
IsDigit = (ucc(ch) > 47) && (ucc(ch) < 58)
|
|
end fn = IsDigit
|
|
|
|
// Parse CIDR string into IP structure and network width
|
|
local fn ParseIPv4_Address(cidr as CFStringRef) as IPv4_Address
|
|
IPv4_Address ip
|
|
Int i, slashPos, currentOctet, octetValue
|
|
CFStringRef ipPart
|
|
ipPart = @""
|
|
slashPos = instr(0, cidr, @"/")
|
|
if slashPos > 0
|
|
ipPart = left(cidr, slashPos)
|
|
networkWidth = Intval(mid(cidr, slashPos + 1))
|
|
else
|
|
ipPart = cidr
|
|
networkWidth = -1
|
|
end if
|
|
currentOctet = 0: octetValue = 0
|
|
for i = 0 to len(ipPart)-1
|
|
select case mid(ipPart, i, 1)
|
|
case @"."
|
|
ip.octets[currentOctet] = octetValue
|
|
currentOctet ++
|
|
octetValue = 0
|
|
case else
|
|
if fn IsDigit(mid(ipPart, i, 1))
|
|
octetValue = octetValue * 10 + Intval(mid(ipPart, i, 1))
|
|
end if
|
|
end select
|
|
next
|
|
ip.octets[currentOctet] = octetValue
|
|
end fn = ip
|
|
|
|
// Apply network mask to IP
|
|
local fn ApplyNetworkMask(ip as IPv4_Address, SnetworkWidth as Int) as IPv4_Address
|
|
IPv4_Address result
|
|
Int completeOctets, remainingBits, i
|
|
result = ip
|
|
completeOctets = SnetworkWidth \ 8 //octet bits
|
|
remainingBits = SnetworkWidth AND 7
|
|
if completeOctets < 4
|
|
result.octets[completeOctets] = result.octets[completeOctets] AND (255 - 2^(8 - remainingBits) + 1)
|
|
for i = completeOctets + 1 to 3
|
|
result.octets[i] = 0
|
|
next
|
|
end if
|
|
end fn = result
|
|
|
|
// Process a CIDR string, sets global CCIDR
|
|
local fn ProcessCIDR(cidr as CFStringRef) as CFStringRef
|
|
IPv4_Address ip
|
|
CFStringRef result
|
|
Int i
|
|
result = @""
|
|
ip = fn ParseIPv4_Address(cidr)
|
|
if fn ValidateCIDR(ip, networkWidth, cidr) // validate
|
|
ip = fn ApplyNetworkMask(ip, networkWidth)
|
|
result = mid(str(ip.octets[0]),1)
|
|
for i = 1 to 3
|
|
result = concat(result,@".",mid(str(ip.octets[i]),1))
|
|
next
|
|
result = concat(result,@"/",mid(str(networkWidth),1))
|
|
else
|
|
print@ errorCode
|
|
end if
|
|
CCIDR = result
|
|
end fn = result
|
|
|
|
//
|
|
// Main
|
|
|
|
Window 1,@"Canonicalize CIDR"
|
|
print@
|
|
|
|
// Test data from the Rosetta Stone task
|
|
|
|
CFStringRef cidr(5) = {@"87.70.141.1/22", @"36.18.154.103/12", @"62.62.197.11/29", ¬
|
|
@"67.137.119.181/4", @"161.214.74.21/24", @"184.232.176.184/18"}
|
|
|
|
for Int i = 0 to 5
|
|
print@ fn ProcessCIDR(cidr(i))
|
|
next
|
|
|
|
HandleEvents
|
|
|
|
//
|