####################################################
# by wiebe @ QuakeNet
#
####################################################


####################################################
# cidr:help:pubm
####################################################
bind pubm fvlomn|fvlomn "% ${botnet-nick} help cidr" cidr:help:pubm
proc cidr:help:pubm { n u h c t } {
  lappend o "cidr: usage cidr <IP/cidr>|<IP/netmask>|<IP1> <IP2>"
  lappend o "cidr: 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 {[string equal [info procs cnotice] ""]} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "cidr: " } }
  putloglev c $c "help: $n $u $h $c cidr"
  return 1
}


####################################################
# cidr:help:msg
####################################################
bind msgm fvlomn|fvlomn "help cidr" cidr:help:msgm
proc cidr:help:msgm { n u h t } {
  lappend o "cidr: usage cidr <IP/cidr>|<IP/netmask>|<IP1> <IP2>"
  lappend o "cidr: 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 {[string equal [info procs cnotice] ""]} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "cidr: " } }
  putcmdlog "($n!$u) !$h! help cidr"
  return 1
}


####################################################
# cidr:pub
####################################################
bind pubm fvlomn|fvlomn "% ${botnet-nick} cidr" cidr:pubm
bind pubm fvlomn|fvlomn "% ${botnet-nick} cidr *" cidr:pubm
proc cidr:pubm { n u h c t } {
  set t [join [lrange [split $t] 2 end]]
  if {[string equal $t ""]} {
    lappend o "cidr: usage cidr <IP/cidr>|<IP/netmask>|<IP1> <IP2>"
  } else {
    set o [cidr:main $t]; set m [lindex [split [getchanmode $c]] 0]
    if {![string match *m* $m] || [botisop $c] || [botishalfop $c] || [botisvoice $c]} {
      if {[string match *c* $m] } { set o [stripcodes bcru $o] }
      if {[string equal [info procs privmsg] ""]} { foreach l $o { puthelp "PRIVMSG $c :$l" }
      } else { foreach l $o { privmsg $c $l puthelp "cidr: " } }
      set o ""
    }
  }
  if {[string equal [info procs cnotice] ""]} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "cidr: " } }
  putloglev c $c "cidr: $n $u $h $c $t"
  return 1
}


####################################################
# cidr:msg
####################################################
bind msg fvlomn|fvlomn cidr cidr:msg
proc cidr:msg { n u h t } {
  if {[string equal $t ""]} { lappend o "cidr: usage cidr <IP/cidr>|<IP/netmask>|<IP1> <IP2>"
  } else { set o [cidr:main $t] }
  if {[string equal [info procs cnotice] ""]} { foreach l $o { puthelp "NOTICE $n :$l" }
  } else { foreach l $o { cnotice $n $l puthelp "cidr: " } }
  return 1
}


####################################################
# cidr:dcc
####################################################
bind dcc -|- cidr cidr:dcc
proc cidr:dcc { h i t } {
  if {[string equal $t ""]} {
    lappend o "cidr: usage cidr <IP/cidr>|<IP/netmask>|<IP1> <IP2>"
    lappend o "cidr: 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."
  } else { set o [cidr:main $t] }
  foreach l $o { putidx $i $l }
  return 1
}


####################################################
# cidr:main
####################################################
proc cidr:main { t } {
  set t [split $t]; set a [lindex $t 0]; set b [lindex $t 1]
  set c [cidr:validip $a]; set d [cidr:validip $b]; set e [cidr:netmask2cidr $a]
  if {[cidr:validcidr $a]} {
    lappend o "cidr: [cidr:cidr $a]"
  } elseif {![string equal $e "-1"]} {
    lappend o "cidr [cidr:cidr $e]"
  } elseif {$c && $d} {
    lappend o "cidr: [cidr:iprange $a $b]"
  } elseif {!$c} {
    lappend o "cidr: invalid IP, IP/cidr or IP/netmask $a"
  } elseif {!$d} {
    lappend o "cidr: invalid IP $b"
  } else {
    lappend o "cidr: invalid IP, IP/cidr or IP/netmask $a"
  }
  return $o
}


####################################################
# cidr:longip
####################################################
proc cidr:longip { i } {
  if {![cidr:validip $i]} { return "" }
  set i [split $i .]
  set a [lindex $i 0]; set b [lindex $i 1]; set c [lindex $i 2]; set d [lindex $i 3]
  set l [expr "$a.*256*256*256 + $b.*256*256 + $c.*256 + $d"]; set l [lindex [split $l .] 0]
  return $l
}


####################################################
# cidr:validip
####################################################
proc cidr:validip { i } {
  if {[regexp {^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$} $i]} { return 1 }
  return 0
}


####################################################
# cidr:validcidr
####################################################
proc cidr:validcidr { i } {
  if {[regexp {^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/(\d|[12]\d|3[0-2])$} $i]} { return 1 }
  return 0
}


####################################################
# cidr:netmask2cidr
####################################################
proc cidr:netmask2cidr { n } {
  if {![regexp {^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$} $n]} { return -1 }
  set n [split $n /]; set i [lindex $n 0]; set n [lindex $n 1]
  set m "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 c [lsearch [split $m] $n]
  if {[string equal $c "-1"]} { return -1 }
  set c [expr 32 - $c]
  return $i/$c
}


####################################################
# cidr:shortip
####################################################
proc cidr:shortip { l } {
  set a [expr fmod($l,pow(256,3))]; set b [expr $l - $a]
  lappend i [lindex [split [expr $b / pow(256,3)] .] 0]
  set c [expr fmod($a,pow(256,2))]; set d [expr $a - $c]
  lappend i [lindex [split [expr $d / pow(256,2)] .] 0]
  set e [expr fmod($c,256)]; set f [expr $c - $e]
  lappend i [lindex [split [expr $f / 256] .] 0]
  lappend i [lindex [split [expr $c - $f] .] 0]
  set i [join $i .]
  return $i
}


set scriptdb(cidr) {
  "provides cidr command for looking up cidr info"
}


####################################################
# code beyond this point is not mine, see credits below
#
# small changes made, code shortened
# adjusted for use in this script, comments removed
####################################################

####################################################
# 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
####################################################

####################################################
# cidr:IPtoHex
####################################################
proc cidr:IPtoHex { IP } {
  binary scan [binary format c4 [split $IP .]] H8 Hex
  return $Hex
}

####################################################
# cidr:hexToIP
####################################################
proc cidr:hexToIP { Hex } {
  binary scan [binary format H8 $Hex] c4 IPtmp
  foreach num $IPtmp { lappend IP [expr ($num + 0x100) % 0x100] }
  set IP [join $IP .]
  return $IP
}

####################################################
# cidr:CIDRtoHexNetmask
####################################################
proc 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
}

####################################################
# cidr:ipisValid
####################################################
proc cidr:ipisValid { IP } {
  regsub -all {[.0-9]} $IP {} tmpStr
  if {$tmpStr != ""} { return 0 }
  regsub -all {[0-9]} $IP {} tmpStr
  if {$tmpStr != "..."} { return 0 }
  foreach b [split $IP .] {
    if {[string length $b] == 0} { return 0 }
    set ob $b
    scan $b %d b
    if {$b < 0 | $b > 255} { return 0 }
  }
  return 1
}

####################################################
# cidr:CIDRisValid
####################################################
proc 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
  if {$CIDR < 0 | $CIDR > 32} { return 0 }
  return 1
}

####################################################
# cidr:networkAddress
####################################################
proc 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
}

####################################################
# cidr:broadcastAddress
####################################################
proc cidr:broadcastAddress { hexIP hexNetmask } {
  set tmpBrdAddr [expr 0x$hexIP | ( 0x$hexNetmask ^ 0xffffffff )]
  binary scan [binary format I $tmpBrdAddr] H8 broadcastAddress
  return $broadcastAddress
}

####################################################
# cidr:cidr2
####################################################
proc cidr:cidr2 { IP CIDR } {
  if {![cidr:ipisValid $IP]} { error "IP is not valid" }
  if {![cidr:CIDRisValid $CIDR]} { error "CIDR is not valid" }
  set hexIP [cidr:IPtoHex $IP]
  set hexNetmask [cidr:CIDRtoHexNetmask $CIDR]
  set hexNetworkAddress [cidr:networkAddress $hexIP $hexNetmask]
  set hexBroadcastAddress [cidr:broadcastAddress $hexIP $hexNetmask]
  set networkAddress [cidr:hexToIP $hexNetworkAddress]
  set broadcastAddress [cidr:hexToIP $hexBroadcastAddress]
  return "$networkAddress $broadcastAddress"
}

####################################################
# cidr:cidr
####################################################
proc cidr:cidr { IP } {
  set IP [split $IP /]; set CIDR [lindex $IP 1]; set IP [lindex $IP 0]
  if {![cidr:ipisValid $IP]} { return "$IP is not a valid IP." }
  if {![cidr:CIDRisValid $CIDR]} { return "$CIDR is not valid (valid 0-32)." }
  set hexIP [cidr:IPtoHex $IP]
  set hexNetmask [cidr:CIDRtoHexNetmask $CIDR]
  set netmask [cidr:hexToIP $hexNetmask]
  set hexNetworkAddress [cidr:networkAddress $hexIP $hexNetmask]
  set networkAddress [cidr:hexToIP $hexNetworkAddress]
  set hexBroadcastAddress [cidr:broadcastAddress $hexIP $hexNetmask]
  set broadcastAddress [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 [cidr:hexToIP $firstIP]
     binary scan [binary format I [expr 0x$hexBroadcastAddress - 1]]\
  	H8 lastIP
  set lastIP [cidr:hexToIP $lastIP]
  if { [string equal $CIDR 32] || [string equal $CIDR 31] } { set firstIP -; set lastIP - }
  lappend o "Netmask: $netmask"
  lappend o "HexNetmask: 0x$hexNetmask"
  lappend o "NetworkAddress: $networkAddress"
  lappend o "BroadcastAddress: $broadcastAddress"
  lappend o "# IPs: $numIPs"
  lappend o "First IP: $firstIP"
  lappend o "Last IP: $lastIP"
  lappend o "CIDR: $networkAddress/$CIDR"
  lappend o "CIDR range: $networkAddress   $broadcastAddress"
  set o [join $o "     "]
  return $o
}

####################################################
# cidr:iprange
####################################################
proc cidr:iprange { ip1 ip2 } {
  set long1 [cidr:longip $ip1]; set long2 [cidr:longip $ip2]
  if {$long1 > $long2} { set long1 [cidr:longip $ip2]; set long2 [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 [cidr:shortip $ip]
      set hexIP [cidr:IPtoHex $ip]
      set hexNetmask [cidr:CIDRtoHexNetmask $x]
      set netmask [cidr:hexToIP $hexNetmask]
      set hexNetworkAddress [cidr:networkAddress $hexIP $hexNetmask]
      set networkAddress [cidr:hexToIP $hexNetworkAddress]
      set hexBroadcastAddress [cidr:broadcastAddress $hexIP $hexNetmask]
      set broadcastAddress [cidr:hexToIP $hexBroadcastAddress]
      set longnetworkAddress [cidr:longip $networkAddress]
      set longbroadcastAddress [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 [cidr:shortip $ip]

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

