Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.os.linux.misc > #85981

Re: CIDR Calculator

From John Ames <commodorejohn@gmail.com>
Newsgroups comp.os.linux.misc
Subject Re: CIDR Calculator
Date 2026-04-27 13:31 -0700
Organization A place where nothing fits quite right
Message-ID <20260427133111.00001bba@gmail.com> (permalink)
References <XnsB43B9C55314F7makowiecatnycapdotrE@157.180.91.226>

Show all headers | View raw


On Mon, 27 Apr 2026 19:22:04 -0000 (UTC)
Joe Makowiec <makowiec@invalid.invalid> wrote:

> However, if you feed it something like 192.168.0.8 to 192.168.5.200,
> it gives back a bunch of ranges with a number of /29s and /26s, a
> couple of /24s and a total of a dozen ranges. What i want is a
> calculator which will look at the high and the low, and figure out
> that 192.168.0.0/21 will cover the whole thing.
> 
> Added useless information: what prompts this request is that my 
> mailserver has been getting hit with a bunch of sasl hack attempts, 
> many of which come from Bharti Airtel, which I assume is an ISP or a 
> wireless / cellphone provider.

Funnily enough, I was just having to do this the other way 'round some
months ago - whitelisting StarLink and its nineteen billion /8s for
certain customers as we try to block wardialing on our RDP servers. If
it helps, this is the utility I came up with - not *exactly* what you
specified, but it'll sort a list of CIDRs and combine contiguous ranges
into single entries.

Written in FreeBasic. Usage: melonballer [in-file] [out-file]

### melonballer.bas ###

type cidr
  ip as ulong
  r as ubyte
end type

function parseCider(s as string) as cidr
  dim as string z
  dim as integer i, j
  dim as ubyte q(5)
  dim as cidr c
  z = ""
  j = 0
  for i = 1 to len(s)
    if asc(mid(s,i,1)) >= asc("0") and asc(mid(s,i,1)) <= asc("9") then
      z = z & mid(s,i,1)
    else
      q(j) = val(z)
      j += 1
      z = ""
    endif
  next
  if z <> "" then
    q(j) = val(z)
    j += 1
  endif
  if j < 5 or q(4) > 31 then
    c.ip = 0
    c.r = 32
  else
    c.ip = q(0) shl 24
    c.ip = c.ip or (q(1) shl 16)
    c.ip = c.ip or (q(2) shl 8)
    c.ip = c.ip or q(3)
    c.r = q(4)
  endif
  parseCider = c
end function

function squeezeCider(ipBase as ulong, ipBound as ulong) as cidr
  ' Returns a CIDR covering the given range.
  dim as cidr c
  dim as ulong i
  c.ip = ipBase
  i = ipBound - ipBase
  c.r = 0
  do while i > 1
    i = i shr 1
    c.r += 1
  loop
  c.r = 32 - c.r
  squeezeCider = c
end function

function ipMin(c as cidr) as ulong
  dim as long i
  i = -1 shl (32 - c.r)
  ipMin = c.ip and i
end function

function ipMax(c as cidr) as ulong
  ipMax = c.ip + (1 shl (32 - c.r)) - 1
end function

function contiguous(foo as cidr, bar as cidr) as Boolean
  ' Returns true if foo comes after bar.
  contiguous = false
  if ipMax(bar) + 1 = foo.ip then contiguous = true
end function

function contained(foo as cidr, bar as cidr) as Boolean
  ' Returns true if foo falls within bar.
  contained = false
  if foo.ip >= bar.ip and ipMax(foo) <= ipMax(bar) then contained = true
end function

function powerOfTwo(i as ulong) as Boolean
  ' Returns true if i is a power of two.
  dim as ulong j
  powerOfTwo = false
  if i = 1 then powerOfTwo = true
  if i <= 1 then exit function
  j = 1 shl 31
  do while ((i and j) = 0) and j <> 0
    j = j shr 1
  loop
  j -= 1
  if ((i and j) = 0) and j <> 0 then powerOfTwo = true
end function

function printCider(c as cidr) as string
  dim as string s
  s = ""
  s &= str(c.ip shr 24) & "." & str((c.ip shr 16) and 255) & "." & str((c.ip shr 8) and 255) & "." & str(c.ip and 255) & "/" & str(c.r)
  printCider = s
end function

function printIp(ip as ulong) as string
  dim as string s
  s = ""
  s &= str(ip shr 24) & "." & str((ip shr 16) and 255) & "." & str((ip shr 8) and 255) & "." & str(ip and 255)
  printIp = s
end function


open command(1) for input as 1

dim as integer i, j, k, bookmark
dim as cidr cList(), oList(), c
dim as string s

' Build the input list.

do while not eof(1)
  line input #1, s
  c = parseCider(trim(s))
  if ubound(cList) < 0 then
    redim cList(0)
    cList(0) = c
    continue do
  endif
  redim preserve cList(ubound(cList) + 1)
  cList(ubound(cList)) = c
loop

close 1

' Build the output list.

redim oList(0)
oList(0) = cList(0)

for i = 1 to ubound(cList)
  for j = 0 to uBound(oList)
    ' Have we already covered this range?
    if contained(cList(i), oList(j)) then goto skipEntry
    if contiguous(cList(i), oList(j)) then
      ' We've hit a block of contiguous addresses - see how far it goes before we can't combine them.
      bookmark = i
      k = i + 1
      do while k <= ubound(cList)
        ' If we're no longer contiguous; stop searching.
        if not contiguous(cList(k), cList(k - 1)) then exit do
        ' Is the range we're covering a power of two?
        if powerOfTwo((ipMax(cList(k)) + 1) - oList(j).ip) then bookmark = k
        k += 1
      loop
      ' The range from oList(j) to cList(bookmark) is contiguous and power-of-two-sized; combine it.
      s = printCider(oList(j))
      for k = i to bookmark
        s &= ", " & printCider(cList(k))
      next
      c = squeezeCider(oList(j).ip, ipMax(cList(bookmark)) + 1)
      if ipMin(c) = oList(j).ip and ipMax(c) = ipMax(cList(bookmark)) then
        oList(j) = c
        s &= " -> " & printCider(c)
        print s
        print "Min: "; printIp(ipMin(cList(i))), "Max: "; printIp(ipMax(cList(bookmark))), printCider(c); ": "; printIp(ipMin(c)); " - "; printIp(ipMax(c))
        print
        ' Advance past cList(bookmark).
        i = bookmark
      endif
      goto skipEntry
    endif
  next j
  ' If we've gotten this far and have neither skipped nor combined, add it to the output list.
  redim preserve oList(ubound(oList) + 1)
  oList(ubound(oList)) = cList(i)
  skipEntry:
next i

' Write the output list.

open command(2) for output as 1

for i = 0 to ubound(oList)
  print #1, printCider(oList(i))
next

close 1

Back to comp.os.linux.misc | Previous | NextPrevious in thread | Next in thread | Find similar


Thread

CIDR Calculator Joe Makowiec <makowiec@invalid.invalid> - 2026-04-27 19:22 +0000
  Re: CIDR Calculator John Ames <commodorejohn@gmail.com> - 2026-04-27 13:31 -0700
    Re: CIDR Calculator Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-04-29 01:59 +0000
  Re: CIDR Calculator Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-04-27 22:35 +0000
  Re: CIDR Calculator Marc Haber <mh+usenetspam2616@zugschl.us> - 2026-04-28 07:49 +0200
    Re: CIDR Calculator Rene Kita <mail@rkta.de> - 2026-04-29 07:09 +0000
      Re: CIDR Calculator Lawrence D’Oliveiro <ldo@nz.invalid> - 2026-04-29 08:05 +0000
  Re: CIDR Calculator Fritz Wuehler <fritz@spamexpire-202604.rodent.frell.theremailer.net> - 2026-04-29 00:08 +0200
  Re: CIDR Calculator 🇵🇱Jacek Marcin Jaworski🇵🇱 <jmj@energokod.gda.pl> - 2026-04-29 07:10 +0200
    Re: CIDR Calculator 🇵🇱Jacek Marcin Jaworski🇵🇱 <jmj@energokod.gda.pl> - 2026-04-29 23:52 +0200

csiph-web