#by wiebe @ QuakeNet
#cidr <ip>/<cidr>
#cidr <ip>/<netmask>
#cidr <ip1> <ip2>





#help cidr pub
bind pubm fvlomn|fvlomn "% ${botnet-nick} help cidr" c_cidr:help:pub

proc c_cidr:help:pub { nick uhost handle chan text } {
  lappend output "Usage: cidr <IP>/<cidr|netmask>"
  lappend output "Usage: cidr <IP1> <IP2>"
  lappend output "Shows netmask, hexnetmask, networkaddress, broadcast address, number of IPs, first & last IP, CIDR and CIDR range for the given ip/cidr, ip/netmask or range from IP1 to IP2."
  if { [catch {set x [cnotice $nick $output]} error] || !$x } {
    foreach t $output { puthelp "NOTICE $nick :$t" }
  }
  putloglev c $chan "[lindex [split $text] 1]: $nick $uhost $handle $chan [join [lrange [split $text] 2 end]]"
}



#help cidr msg
bind msgm fvlomn|fvlomn "help cidr" c_cidr:help:msg

proc c_cidr:help:msg { nick uhost handle text } {
  lappend output "Usage: cidr <IP>/<cidr|netmask>"
  lappend output "Usage: cidr <IP1> <IP2>"
  lappend output "Shows netmask, hexnetmask, networkaddress, broadcast address, number of IPs, first & last IP, CIDR and CIDR range for the given ip/cidr, ip/netmask or range from IP1 to IP2."
  if { [catch {set x [cnotice $nick $output]} error] || !$x } {
    foreach t $output { puthelp "NOTICE $nick :$t" }
  }
  putcmdlog "($nick!$uhost) !$handle! $text"
}



#cidr pub
bind pubm fvlomn|fvlomn "% ${botnet-nick} cidr" c_cidr:pub
bind pubm fvlomn|fvlomn "% ${botnet-nick} cidr *" c_cidr:pub

proc c_cidr:pub { nick uhost handle chan text } {
  set mask [join [lrange [split $text] 2 end]]
  set mask1 [lindex [split $mask] 0]
  set mask2 [lindex [split $mask] 1]
  set cidr [lindex [split $mask1 /] 1]
  set validcidr [c_cidr:netmask2cidr $cidr]
  set ip1 [lindex [split $mask1 /] 0]
  set ip2 $mask2
  set output ""
  if { [string equal $mask1 ""] } {
    lappend output "Usage: cidr <IP>/<cidr|netmask>"
    lappend output "Usage: cidr <IP1> <IP2>"
#mask2 is not valid ip, mask2 exits
  } elseif { ![regexp {^(?:(?:2(?:[0-4]\d?|5[0-5])|[01]?\d{1,2})(?:\.|$)){4}$} $mask2] && ![string equal $mask2 ""] } {
    lappend output "Invalid IP: $mask2"
#mask1 is not valid ip, mask2 exists
  } elseif { ![regexp {^(?:(?:2(?:[0-4]\d?|5[0-5])|[01]?\d{1,2})(?:\.|$)){4}$} $mask1] && ![string equal $mask2 ""] } {
    lappend output "Invalid IP: $mask1"
#ip1 is not a valid ip
  } elseif { ![regexp {^(?:(?:2(?:[0-4]\d?|5[0-5])|[01]?\d{1,2})(?:\.|$)){4}$} $ip1] } {
    lappend output "Invalid IP: $ip1"
#cidr is not valid cidr/netmask
  } elseif { [string equal $mask2 ""] && [string equal $validcidr -1] } {
    lappend output "Invalid CIDR or netmask: $cidr"
#crap used in $mask1
  } elseif { [string equal $mask2 ""] && ![string equal $ip1/$cidr $mask1] } {
    lappend output "Invalid IP/CIDR or IP/netmask: $mask1"
#cidr
  } elseif { [string equal $mask2 ""] } {
    puthelp "PRIVMSG $chan :[join [c_cidr:cidr $ip1 $validcidr] "   "]"
#netmask
  } else {
    puthelp "PRIVMSG $chan :[join [c_cidr:iprange $mask1 $mask2] "   "]"
  }
  if { [catch {set x [cnotice $nick $output]} error] || !$x } {
    foreach t $output { puthelp "NOTICE $nick :$t" }
  }
  putloglev c $chan "[lindex [split $text] 1]: $nick $uhost $handle $chan [join [lrange [split $text] 2 end]]"
}




#cidr msg
bind msg fvlomn|fvlomn cidr c_cidr:msg

proc c_cidr:msg { nick uhost handle text } {
  set mask $text
  set mask1 [lindex [split $mask] 0]
  set mask2 [lindex [split $mask] 1]
  set cidr [lindex [split $mask1 /] 1]
  set validcidr [c_cidr:netmask2cidr $cidr]
  set ip1 [lindex [split $mask1 /] 0]
  set ip2 $mask2
  set output ""
  if { [string equal $mask1 ""] } {
    lappend output "Usage: cidr <IP>/<cidr|netmask>"
    lappend output "Usage: cidr <IP1> <IP2>"
#mask2 is not valid ip, mask2 exits
  } elseif { ![regexp {^(?:(?:2(?:[0-4]\d?|5[0-5])|[01]?\d{1,2})(?:\.|$)){4}$} $mask2] && ![string equal $mask2 ""] } {
    lappend output "Invalid IP: $mask2"
#mask1 is not valid ip, mask2 exists
  } elseif { ![regexp {^(?:(?:2(?:[0-4]\d?|5[0-5])|[01]?\d{1,2})(?:\.|$)){4}$} $mask1] && ![string equal $mask2 ""] } {
    lappend output "Invalid IP: $mask1"
#ip1 is not a valid ip
  } elseif { ![regexp {^(?:(?:2(?:[0-4]\d?|5[0-5])|[01]?\d{1,2})(?:\.|$)){4}$} $ip1] } {
    lappend output "Invalid IP: $ip1"
#cidr is not valid cidr/netmask
  } elseif { [string equal $mask2 ""] && [string equal $validcidr -1] } {
    lappend output "Invalid CIDR or netmask: $cidr"
#crap used in $mask1
  } elseif { [string equal $mask2 ""] && ![string equal $ip1/$cidr $mask1] } {
    lappend output "Invalid IP/CIDR or IP/netmask: $mask1"
#cidr
  } elseif { [string equal $mask2 ""] } {
    lappend output "[join [c_cidr:cidr $ip1 $validcidr] "   "]"
#netmask
  } else {
    lappend output "[join [c_cidr:iprange $mask1 $mask2] "   "]"
  }
  if { [catch {set x [cnotice $nick $output]} error] || !$x } {
    foreach t $output { puthelp "NOTICE $nick :$t" }
  }
  return 1
}



#cidr dcc
bind dcc fvlomn|fvlomn cidr c_cidr:dcc

proc c_cidr:dcc { handle idx text } {
  set mask $text
  set mask1 [lindex [split $mask] 0]
  set mask2 [lindex [split $mask] 1]
  set cidr [lindex [split $mask1 /] 1]
  set validcidr [c_cidr:netmask2cidr $cidr]
  set ip1 [lindex [split $mask1 /] 0]
  set ip2 $mask2
  set output ""
  if { [string equal $mask1 ""] } {
    putidx $idx "Usage: cidr <IP>/<cidr|netmask>"
    putidx $idx "Usage: cidr <IP1> <IP2>"
#mask2 is not valid ip, mask2 exits
  } elseif { ![regexp {^(?:(?:2(?:[0-4]\d?|5[0-5])|[01]?\d{1,2})(?:\.|$)){4}$} $mask2] && ![string equal $mask2 ""] } {
    putidx $idx "Invalid IP: $mask2"
#mask1 is not valid ip, mask2 exists
  } elseif { ![regexp {^(?:(?:2(?:[0-4]\d?|5[0-5])|[01]?\d{1,2})(?:\.|$)){4}$} $mask1] && ![string equal $mask2 ""] } {
    putidx $idx "Invalid IP: $mask1"
#ip1 is not a valid ip
  } elseif { ![regexp {^(?:(?:2(?:[0-4]\d?|5[0-5])|[01]?\d{1,2})(?:\.|$)){4}$} $ip1] } {
    putidx $idx "Invalid IP: $ip1"
#cidr is not valid cidr/netmask
  } elseif { [string equal $mask2 ""] && [string equal $validcidr -1] } {
    putidx $idx "Invalid CIDR or netmask: $cidr"
#crap used in $mask1
  } elseif { [string equal $mask2 ""] && ![string equal $ip1/$cidr $mask1] } {
    putidx $idx "Invalid IP/CIDR or IP/netmask: $mask1"
#cidr
  } elseif { [string equal $mask2 ""] } {
    foreach r [c_cidr:cidr $ip1 $validcidr] {
      putidx $idx "  $r"
    }
#netmask
  } else {
    foreach r [c_cidr:iprange $mask1 $mask2] {
      putidx $idx "  $r"
    }
  }
  return 1
}




# not by me

#http://wiki.tcl.tk/8909
#!/bin/sh
# Emacs: please open this file in -*-Tcl-*- mode
#
# Author: Mark Oakden http://wiki.tcl.tk/MNO
# Version: 1.1
#
# Note: this is almost certainly riddled with byte order
# and 32-bit assumptions.
#
# Changes since 1.0:-
#  changed usage of regsub to accomodate earlier tcl/tk versions than 8.4.1
#  changed layout to accomodate PocketPC better
#
# the next but one line restarts with tclsh...
# DO NOT REMOVE THIS BACKSLASH -> \
#    exec tclsh "$0" ${1+"$@"}
#
#package require Tk
#
#
# IPtoHex assumes IP has already been validated
proc c_cidr:IPtoHex { IP } {
    binary scan [binary format c4 [split $IP .]] H8 Hex
    return $Hex
}
proc c_cidr:hexToIP { Hex } {
    binary scan [binary format H8 $Hex] c4 IPtmp
    foreach num $IPtmp {
	# binary scan "c" format gives signed int - the following
	# [expr]-ology converts to unsigned (from [binary] manpage)
	lappend IP [expr ($num + 0x100) % 0x100]
    }
    set IP [join $IP .]
    return $IP
}
proc c_cidr:CIDRtoHexNetmask { CIDR } {
    set zeros [expr 32 - $CIDR]
    set ones $CIDR
    set binaryCIDR [string repeat 1 $ones]
    append binaryCIDR [string repeat 0 $zeros]
    binary scan [binary format B32 $binaryCIDR] H8 HexNetmask
    return $HexNetmask
}
proc c_cidr:ipisValid { IP } {
    # must contain only dots and digits
    # this originally read:-
    #if { [regsub -all {[.0-9]} $IP {}] != "" } {
    #	return 0
    #}
    regsub -all {[.0-9]} $IP {} tmpStr
    if { $tmpStr != "" } {
	return 0
    }
    # however this appears to be a 8.4.1-ism which doesn't work with
    # earlier versions (e.g. the 8.4a2 version that the PocketPC tcltk
    # version is based on.
    #
    # exactly three dots
    regsub -all {[0-9]} $IP {} tmpStr
    if { $tmpStr != "..." } {
	return 0
    }
    # each numerical component is between 0 and 255
    foreach b [split $IP .] {
	if { [string length $b] == 0 } {
	    return 0
	}
	set ob $b
	scan $b %d b ;# allow for leading zeros which tcl thinks are octal
	if { $b < 0 | $b > 255 } {
	    return 0
	}
    }
    return 1
}
proc c_cidr:CIDRisValid { CIDR } {
    if { [string length $CIDR] == 0 } {
	return 0
    }
    regsub -all {[0-9]} $CIDR {} tmpStr
    if { [string length $tmpStr] != 0 } {
	return 0
    }
    scan $CIDR %d $CIDR
    # 4 is arbitrary restriction on my part, but no-one uses CIDR to
    # amalgamate multiple class A addresses! CIDR of 31 and 32 are
    # non-useful also (/31 would leave just two IP addresses in the
    # subnet, one of which would be the network address, the other
    # the broadcast address - i.e. no usable IPs)
    if { $CIDR < 0 | $CIDR > 32 } {
 	return 0
    }
    return 1
}
 # IP and netmask in Hex, returns hex
proc c_cidr:networkAddress { hexIP hexNetmask } {
    set compNetmask [expr 0x$hexNetmask ^ 0xffffffff]
    set tmpNetAddr [expr ( 0x$hexIP | $compNetmask ) ^ $compNetmask]
    binary scan [binary format I $tmpNetAddr] H8 networkAddress
    return $networkAddress
}
# IP and netmask in Hex, returns hex
proc c_cidr:broadcastAddress { hexIP hexNetmask } {
    set tmpBrdAddr [expr 0x$hexIP | ( 0x$hexNetmask ^ 0xffffffff )]
    binary scan [binary format I $tmpBrdAddr] H8 broadcastAddress
    return $broadcastAddress
}

proc c_cidr:cidr { IP CIDR } {
  if { ![c_cidr:ipisValid $IP] } {
    return "$IP is not a valid IP."
  }
  if { ![c_cidr:CIDRisValid $CIDR] } {
    return "$CIDR is not valid (valid 0-32)."
  }
  set hexIP [c_cidr:IPtoHex $IP]
  set hexNetmask [c_cidr:CIDRtoHexNetmask $CIDR]
  set netmask [c_cidr:hexToIP $hexNetmask]
  set hexNetworkAddress [c_cidr:networkAddress $hexIP $hexNetmask]
  set networkAddress [c_cidr:hexToIP $hexNetworkAddress]
  set hexBroadcastAddress [c_cidr:broadcastAddress $hexIP $hexNetmask]
  set broadcastAddress [c_cidr:hexToIP $hexBroadcastAddress]
  set numIPs [expr 0x$hexBroadcastAddress - 0x$hexNetworkAddress +1]
  if { [string match -* $numIPs] } { set numIPs [string range $numIPs 1 end] }
  set x 2
  set y 0
  set r ""
  while { ![string equal [string range $numIPs end-$x end-$y] ""] } {
    set r [linsert $r 0 [string range $numIPs end-$x end-$y]]
    incr x 3
    incr y 3
  }
  set numIPs [join $r ,]

     binary scan [binary format I [expr 0x$hexNetworkAddress + 1]] \
  	H8 firstIP
  set firstIP [c_cidr:hexToIP $firstIP]
     binary scan [binary format I [expr 0x$hexBroadcastAddress - 1]]\
  	H8 lastIP
  set lastIP [c_cidr:hexToIP $lastIP]
  if { [string equal $CIDR 32] || [string equal $CIDR 31] } {
    set firstIP -
    set lastIP -
  }
  lappend output "Netmask: $netmask"
  lappend output "HexNetmask: 0x$hexNetmask"
  lappend output "NetworkAddress: $networkAddress"
  lappend output "BroadcastAddress: $broadcastAddress"
  lappend output "# IPs: $numIPs"
  lappend output "First IP: $firstIP"
  lappend output "Last IP: $lastIP"
  lappend output "CIDR: $networkAddress/$CIDR"
  lappend output "CIDR range: $networkAddress   $broadcastAddress"
  return $output
}


proc c_cidr:iprange { ip1 ip2 } {
  if { ![regexp {^(?:(?:2(?:[0-4]\d?|5[0-5])|[01]?\d{1,2})(?:\.|$)){4}$} $ip1] } { return }
  if { ![regexp {^(?:(?:2(?:[0-4]\d?|5[0-5])|[01]?\d{1,2})(?:\.|$)){4}$} $ip2] } { return }
  set long1 [c_cidr:longip $ip1]
  set long2 [c_cidr:longip $ip2]
  if { $long1 > $long2 } {
    set long1 [c_cidr:longip $ip2]
    set long2 [c_cidr:longip $ip1]
  }
  set diff [expr $long2 - $long1]
  set x 32
  while { $x >= 0 } {
    if { [expr pow(2,32 - $x)] >= $diff } {
      set ip [expr ($diff / 2.) + $long1]
      set ip [c_cidr:shortip $ip]
      set hexIP [c_cidr:IPtoHex $ip]
      set hexNetmask [c_cidr:CIDRtoHexNetmask $x]
      set netmask [c_cidr:hexToIP $hexNetmask]
      set hexNetworkAddress [c_cidr:networkAddress $hexIP $hexNetmask]
      set networkAddress [c_cidr:hexToIP $hexNetworkAddress]
      set hexBroadcastAddress [c_cidr:broadcastAddress $hexIP $hexNetmask]
      set broadcastAddress [c_cidr:hexToIP $hexBroadcastAddress]
      set longnetworkAddress [c_cidr:longip $networkAddress]
      set longbroadcastAddress [c_cidr:longip $broadcastAddress]
      if { $longnetworkAddress <= $long1 && $longbroadcastAddress >= $long2 } {
        break
      }
    }
    incr x -1
  }
  set CIDR $x
  set ip [expr ($diff / 2.) + $long1]
  set ip [lindex [split $ip .] 0]
  set IP [c_cidr:shortip $ip]

  set hexIP [c_cidr:IPtoHex $IP]
  set hexNetmask [c_cidr:CIDRtoHexNetmask $CIDR]
  set netmask [c_cidr:hexToIP $hexNetmask]
  set hexNetworkAddress [c_cidr:networkAddress $hexIP $hexNetmask]
  set networkAddress [c_cidr:hexToIP $hexNetworkAddress]
  set hexBroadcastAddress [c_cidr:broadcastAddress $hexIP $hexNetmask]
  set broadcastAddress [c_cidr:hexToIP $hexBroadcastAddress]
  set numIPs [expr 0x$hexBroadcastAddress - 0x$hexNetworkAddress +1]
     binary scan [binary format I [expr 0x$hexNetworkAddress + 1]] \
  	H8 firstIP
  set firstIP [c_cidr:hexToIP $firstIP]
     binary scan [binary format I [expr 0x$hexBroadcastAddress - 1]]\
  	H8 lastIP
  set lastIP [c_cidr:hexToIP $lastIP]
  if { [string equal $CIDR 32] || [string equal $CIDR 31] } {
    set firstIP -
    set lastIP -
  }
  lappend output "IP range: $ip1 $ip2"
  lappend output "netmask: $netmask"
  lappend output "hexnetmask: 0x$hexNetmask"
  lappend output "networkaddress: $networkAddress"
  lappend output "broadcastaddress: $broadcastAddress"
  lappend output "# IPs: $numIPs"
  lappend output "first IP: $firstIP"
  lappend output "last IP: $lastIP"
  lappend output "CIDR: $networkAddress/$CIDR"
  lappend output "CIDR range: $networkAddress $broadcastAddress"
  return $output
}



#longip
proc c_cidr:longip { ip } {
  if { ![regexp {^(?:(?:2(?:[0-4]\d?|5[0-5])|[01]?\d{1,2})(?:\.|$)){4}$} $ip] } { return }
  set ip1 [lindex [split $ip .] 0]
  set ip2 [lindex [split $ip .] 1]
  set ip3 [lindex [split $ip .] 2]
  set ip4 [lindex [split $ip .] 3]
  set longip [lindex [split [expr "$ip1. *256*256*256 + $ip2. *256*256 + $ip3. *256 + $ip4"] .] 0]
  return $longip
}



#shortip
proc c_cidr:shortip { longip } {
  set temp1 [expr fmod($longip,pow(256,3))]
  set temp2 [expr $longip - $temp1]
  set ip1 [lindex [split [expr $temp2 / pow(256,3)] .] 0]

  set temp3 [expr fmod($temp1,pow(256,2))]
  set temp4 [expr $temp1 - $temp3]
  set ip2 [lindex [split [expr $temp4 / pow(256,2)] .] 0]

  set temp5 [expr fmod($temp3,256)]
  set temp6 [expr $temp3 - $temp5]
  set ip3 [lindex [split [expr $temp6 / 256] .] 0]

  set ip4 [lindex [split [expr $temp3 - $temp6] .] 0]

  return $ip1.$ip2.$ip3.$ip4
}



#netmask2cidr
proc c_cidr:netmask2cidr { netmask } {
  if { [string is digit $netmask] && $netmask >= 0 && $netmask <= 32 } { return $netmask }
  set netmasks "255.255.255.255 255.255.255.254 255.255.255.252 255.255.255.248 255.255.255.240 255.255.255.224 255.255.255.192 255.255.255.12 255.255.255.0 255.255.254.0 255.255.252.0 255.255.248.0 255.255.240.0 255.255.224.0 255.255.192.0 255.255.128.0 255.255.0.0 255.254.0.0 255.252.0.0 255.248.0.0 255.240.0.0 255.224.0.0 255.192.0.0 255.128.0.0 255.0.0.0 254.0.0.0 252.0.0.0 248.0.0.0 240.0.0.0 224.0.0.0 192.0.0.0 128.0.0.0 0.0.0.0"
  set cidr [lsearch [split $netmasks] $netmask]
  if { [string equal $cidr -1] } { return -1 }
  set cidr [expr 32 - $cidr]
  return $cidr
}

