4 namespace eval excentis {
14 namespace eval basic {
25 proc ByteList.Check { byteList } {
34 return [ regexp {^[ \t]*((0[xX][0-9a-fA-F]{1,2}[ \t]+)*)(0[xX][0-9a-fA-F]{1,2}){0,1}[ \t]*$} $byteList dummy s_stripped dummy1 dummy2 ]
38 proc Mac.To.Hex { macAddress } {
61 set macAddress [
string trim $macAddress ]
63 if {[ string equal $macAddress "" ]} {
64 error "The given MAC address \"$macAddress\" is empty"
68 if {[ regexp {^((([0-9a-fA-F]{2})[" ":-]([0-9a-fA-F]{2})[" ":-]([0-9a-fA-F]{2})[" ":-]([0-9a-fA-F]{2})[" ":-]([0-9a-fA-F]{2})[" ":-])(([0-9a-fA-F]{2})))$} $macAddress dummy1 dummy2 dummy3 a b c d e f ]} {
73 foreach letter { a b c d e } { append macAddress "0x[ subst $[ subst $letter ]] " }
74 append macAddress "0x$f"
75 } elseif {[ regexp {^(((0x[0-9a-fA-F]{2})[" ":-](0x[0-9a-fA-F]{2})[" ":-](0x[0-9a-fA-F]{2})[" ":-](0x[0-9a-fA-F]{2})[" ":-](0x[0-9a-fA-F]{2})[" ":-])((0x[0-9a-fA-F]{2})))$} $macAddress dummy1 dummy2 dummy3 a b c d e f ]} {
76 # 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF
77 # 0xFF:0xFF:0xFF:0xFF:0xFF:0xFF
78 # 0xFF-0xFF-0xFF-0xFF-0xFF-0xFF
80 foreach letter { a b c d e } { append macAddress "0x[ string range [ subst $[ subst $letter ]] 2 end ] " }
81 append macAddress "0x[ string range $f 2 end ]"
82 } elseif {[ regexp {^(0x[0-9a-fA-F]{2})(0x[0-9a-fA-F]{2})(0x[0-9a-fA-F]{2})(0x[0-9a-fA-F]{2})(0x[0-9a-fA-F]{2})(0x[0-9a-fA-F]{2})$} $macAddress dummy1 a b c d e f ]} {
83 # 0xFF0xFF0xFF0xFF0xFF0xFF
85 foreach letter { a b c d e } { append macAddress "0x[ string range [ subst $[ subst $letter ]] 2 end ] " }
86 append macAddress "0x[ string range $f 2 end ]"
87 } elseif {[ regexp {^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$} $macAddress dummy a b c d e f ]} {
90 foreach letter { a b c d e } { append macAddress "0x[ subst $[ subst $letter ]] " }
91 append macAddress "0x$f"
92 } elseif {[ regexp {^(([0-9a-fA-F]{2})([0-9a-fA-F]{2}))[" "-:.](([0-9a-fA-F]{2})([0-9a-fA-F]{2}))[" "-:.](([0-9a-fA-F]{2})([0-9a-fA-F]{2}))$} $macAddress dummy1 dummy2 a b dummy3 c d dummy4 e f ]} {
98 foreach letter { a b c d e } { append macAddress "0x[ subst $[ subst $letter ]] " }
99 append macAddress "0x$f"
101 error "The given MAC address \"$macAddress\" is not in a valid format or contains wrong characters!\
102 \nAllowed formats are enumerated in the helpbox"
113 proc IPv4.IsValid { ip } {
123 return [ regexp {^(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]?)\.(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]?)$} $ip match ip1 ip2 ip3 ip4 ]
127 proc IPv4.IsNullIpAddress { ip } {
137 return [ regexp {^([0]{1,3})\.([0]{1,3})\.([0]{1,3})\.([0]{1,3})$} $ip match ip1 ip2 ip3 ip4 ]
141 proc IPv4.IsThisNetwork { ip } {
151 return [ regexp {^([0]{1,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]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$} $ip match ip1 ip2 ip3 ip4 ]
155 proc IPv4.IsLoopback { ip } {
165 return [ regexp {^(127)\.(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]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$} $ip match ip1 ip2 ip3 ip4 ]
169 proc IPv4.IsMulticast { ip } {
179 return [
expr [ regexp {^(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]?)\.(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]?)$} $ip match ip1 ip2 ip3 ip4 ] && \
180 [
expr ( $ip1 & 0xf0 ) == 0xe0 ] ]
184 proc IPv4.IsBroadcast { ip { netmask "" } } {
199 if { [ string equal "${netmask}" "" ]} {
200 return [
string equal "${ip}" "255.255.255.255" ]
207 set ipBytes [
split "${ip}" "." ]
208 set netmaskBytes [
split "${netmask}" "." ]
209 foreach ipPart $ipBytes netmaskPart $netmaskBytes {
210 set broadcastPart [
expr ( ${ipPart} & ${netmaskPart} ) | ( ~ ${netmaskPart} & 0x0ff ) ]
211 if { $ipPart != $broadcastPart} {
219 proc IPv6.IsComplete { ip } {
228 set pattern_8hex {^([0-9A-Fa-f]{1,4}:){7}[0-9A-Fa-f]{1,4}$}
229 return [ regexp -- $pattern_8hex $ip ]
233 proc IPv6.IsCompressed { ip } {
251 set pattern_compressedhex {(^(([0-9A-Fa-f]{1,4}(((:[0-9A-Fa-f]{1,4}){5}::[0-9A-Fa-f]{1,4})|((:[0-9A-Fa-f]{1,4}){4}::[0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,1})|((:[0-9A-Fa-f]{1,4}){3}::[0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,2})|((:[0-9A-Fa-f]{1,4}){2}::[0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,3})|(:[0-9A-Fa-f]{1,4}::[0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,4})|(::[0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,5})))$|^(::[0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,6})$)|^::$)}
252 return [ regexp -- $pattern_compressedhex $ip ]
256 proc IPv6.Isv4Inv6 { ip } {
262 set pattern_hex6dec4 {^([0-9A-Fa-f]{1,4}):([0-9A-Fa-f]{1,4}):([0-9A-Fa-f]{1,4}):([0-9A-Fa-f]{1,4}):([0-9A-Fa-f]{1,4}):([0-9A-Fa-f]{1,4}):([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]{1}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]{1}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]{1}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$}
263 return [ regexp -- $pattern_hex6dec4 $ip ]
267 proc IPv6.IsCompressedv4Inv6 { ip } {
276 set pattern_hex6dec4_compressed {^(([0-9A-Fa-f]{1,4}:)*)[:]?((:[0-9A-Fa-f]{1,4})*):([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]{1}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]{1}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])[.]{1}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$}
277 return [ regexp -- $pattern_hex6dec4_compressed $ip ]
281 proc IPv6.IsValid { ip } {
296 proc IPv6.IsMulticast { ip } {
298 [ regexp -- {^([Ff]{2}[0-9A-Fa-f]{2}):} $ip ]
301 proc IP.IsValid { ip } {
315 proc IP.To.Hex { ip } {
323 if { ![ IPv4.IsValid $ip ]} {
324 error "IP.To.Hex: Invalid IPv4 Format: '$ip'"
327 if { ![ regexp {^([0-9]*)\.([0-9]*)\.([0-9]*)\.([0-9]*)$} $ip dummy ip1 ip2 ip3 ip4 ]} {
328 error "IP.To.Hex: Invalid IPv4 Format: '$ip'"
335 proc Hex.To.IP { hex } {
359 set hexMap [
string map {":" "" "." "" ";" "" "-" "" " " "" "0x" ""} $hex ]
360 if { [ string length $hexMap ] != 8 || [
string is xdigit $hexMap ] != 1} {
361 error "Hex.To.IP: Invalid hexadecimal IPv4 value : '${hex}'"
365 append result [
format "%d" 0x[
string range $hexMap 0 1 ] ] "." [
format "%d" 0x[
string range $hexMap 2 3 ] ] "."
366 append result [
format "%d" 0x[
string range $hexMap 4 5 ] ] "." [
format "%d" 0x[
string range $hexMap 6 7 ] ]
372 proc Byte.To.Hex { byte } {
382 if { [ string equal $byte "" ] || ![
string is integer $byte ]} {
383 error "Byte.To.Hex: Invalid Byte format <$byte>"
386 error "Byte.To.Hex: Byte <$byte> greater than 255 (0xFF)"
389 return [
format "0x%02x" [
expr ( $byte & 0xFF ) ] ]
393 proc Short.To.Hex { short } {
404 if { [ string equal $short "" ] || ![
string is integer $short ]} {
405 error "Short.To.Hex: Invalid Short format <$short>"
407 if { $short > 0xFFFF} {
408 error "Short.To.Hex: Short <$short> greater than 65535 (0xFFFF)"
411 return [ list [
format "0x%02x" [
expr ( ( $short / 0x100 ) & 0xFF ) ] ] [
format "0x%02x" [
expr ( $short & 0xFF ) ] ] ]
415 proc CheckSum.16 { byteList } {
429 if { ![ ByteList.Check $byteList ]} {
430 error "CheckSum.16 : Invalid ByteList, expecting list of 0xXX, where X is a hexadecimal value, got $byteList"
433 set length [
llength $byteList ]
434 if { [ expr ( $length % 2 ) ]} {
435 error "CheckSum.16 : ByteList is expected to hold multiple of 2 elements"
438 set twoByteList [ list ]
439 foreach {byte1 byte2} $byteList {
440 lappend twoByteList [
expr ( $byte1 * 0x100 + $byte2 ) ]
445 foreach twoByte $twoByteList {
446 incr checkSum $twoByte
447 if { $checkSum > 0xFFFF} {
448 set checkSum [
expr ( $checkSum & 0xFFFF ) ]
454 set checkSum [
expr ( 0xFFFF - $checkSum ) ]
457 return [ list [
format "0x%02x" [
expr ( $checkSum / 0x100 ) & 0xFF ] ] [
format "0x%02x" [
expr ( $checkSum & 0xFF ) ] ] ]
461 proc IPv6.To.Hex { ip } {
469 set octets [
split $ip ":" ]
471 if { [ IPv6.IsComplete $ip ]} {
472 foreach octet $octets {
473 set decOctet [
scan $octet "%x" ]
474 lappend result [
format "0x%02x" [
expr ( $decOctet / 0x100 ) & 0xFF ] ] [
format "0x%02x" [
expr ( $decOctet & 0xFF ) ] ]
476 }
elseif { [ IPv6.IsCompressed $ip ]} {
477 set length [
llength $octets ]
478 for {
set teller 0} { $teller < $length} {
incr teller} {
479 set octet [
lindex $octets $teller ]
481 if { [ string equal $octet "" ]} {
482 if { $teller == 0 || $teller == ( $length - 1 )} {
484 lappend result 0x00 0x00
487 for {
set i $length} { $i < 9} {
incr i} {
488 lappend result 0x00 0x00
493 set decOctet [
scan $octet "%x" ]
494 lappend result [
format "0x%02x" [
expr ( $decOctet / 0x100 ) & 0xFF ] ] [
format "0x%02x" [
expr ( $decOctet & 0xFF ) ] ]
499 error "IPv6.To.Hex: Unsupported IPv6 format: '$ip'"
506 proc Hex.To.IPv6 { hex } {
518 set hexMap [
string map { ":" "" "." "" ";" "" " " "" "0x" ""} $hex ]
519 if { [ string length $hexMap ] != 32 || [
string is xdigit $hexMap ] != 1} {
520 error "Hex.To.IPv6: Invalid hexadecimal IPv6 value : '${hex}'"
523 append result [
string range $hexMap 0 3 ] ":" [
string range $hexMap 4 7 ] ":"\
524 [
string range $hexMap 8 11 ] ":" [
string range $hexMap 12 15 ] ":" \
525 [
string range $hexMap 16 19 ] ":" [
string range $hexMap 20 23 ] ":" \
526 [
string range $hexMap 24 27 ] ":" [
string range $hexMap 28 31 ]
532 proc IP.Increment { address { amount 1 } } {
543 if { ![ IPv4.IsValid $address ]} {
544 error "IP.To.Hex: Invalid IPv4 Format: '$address'"
548 foreach integer [ split $address "." ] {
549 set ipInt [
expr $ipInt * 256 + $integer ]
552 set hexIp [
format %08x [
expr $ipInt & 0xFFFFFFFF ] ]
557 proc IPv6.Increment { address { amount 1 } } {
569 set hexList [
split $address ":" ]
571 if { ![ IPv6.IsValid $address ]} {
572 error "IPv6.Increment: Invalid IPv6 Format: '$address'"
578 if { [ set lpos [ lsearch $hexList {} ] ] != -1} {
579 set zeros [
expr 9 - [
llength $hexList ] ]
580 for {
set i 0} { $i < $zeros} {
incr i} {
581 lappend zeroList 0000
583 set hexList [
eval lreplace [ list $hexList ] $lpos $lpos $zeroList ]
586 if { [ llength $hexList ] != 8} {
587 error "IPv6.Increment: Error during convertion, did not receive 8 parts after decompressing address"
591 set hexResults [ list ]
593 for {
set i 7} { $i >= 0} {
incr i -1} {
594 set decPart [
expr [
scan [
lindex $hexList $i ] "%x" ] + $carry ]
596 set hexResults [
linsert $hexResults 0 [
format "%04x" [
expr $decPart & 0xFFFF ] ] ]
597 set carry [
expr ( $decPart >> 16 ) & 0xFFFF ]
603 proc Mac.Increment { address } {
623 if { ![ regexp {^((([0-9a-fA-F]{1,2})[" ":-]([0-9a-fA-F]{1,2})[" ":-]([0-9a-fA-F]{1,2})[" ":-]([0-9a-fA-F]{1,2})[" ":-]([0-9a-fA-F]{1,2})[" ":-])(([0-9a-fA-F]{1,2})))$} $address dummy1 dummy2 dummy3 a b c d e f ]} {
624 error "Mac.Increment: Invalid MAC address format"
626 set hexInt1 0x[
format "%02x%02x%02x" [
scan $a "%x" ] [
scan $b "%x" ] [
scan $c "%x" ] ]
627 set hexInt2 0x[
format "%02x%02x%02x" [
scan $d "%x" ] [
scan $e "%x" ] [
scan $f "%x" ] ]
629 if { $hexInt2 > 0xFFFFFF} {
632 set hexString [
format "%06x%06x" [
expr $hexInt1 & 0xFFFFFF ] [
expr $hexInt2 & 0xFFFFFF ] ]
634 return [
format "%s:%s:%s:%s:%s:%s" [
string range $hexString 0 1 ] [
string range $hexString 2 3 ] [
string range $hexString 4 5 ] [
string range $hexString 6 7 ] [
string range $hexString 8 9 ] [
string range $hexString 10 11 ] ]
638 proc Multicast.IP.To.Mac { multicastAddress } {
647 set ipList [
IP.To.Hex $multicastAddress ]
649 set macList [ list "01" "00" "5E" ]
650 lappend macList [
format "%02X" [
expr [
lindex $ipList 1 ] & 0x7F ] ]
651 lappend macList [
format "%02X" [
lindex $ipList 2 ] ]
652 lappend macList [
format "%02X" [
lindex $ipList 3 ] ]
654 set multicastMac [
string toupper [
join $macList ":" ] ]
660 proc Multicast.IPv6.To.Mac { ipv6MulticastAddress } {
674 set macList [ list "33" "33" ]
675 lappend macList [
format "%02X" [
lindex $ipList end-3 ] ]
676 lappend macList [
format "%02X" [
lindex $ipList end-2 ] ]
677 lappend macList [
format "%02X" [
lindex $ipList end-1 ] ]
678 lappend macList [
format "%02X" [
lindex $ipList end ] ]
680 set multicastMac [
string toupper [
join $macList ":" ] ]
686 proc String.To.Hex { byteString } {
695 if { [ expr [ string length $byteString ] % 2 ] != 0} {
696 error "String.To.Hex: Invalid string format, need even number of characters <$byteString>"
699 set byteString [
string toupper $byteString ]
701 foreach {1 2} [ split $byteString {} ] {
lappend result "0x$1$2"}
706 proc Hex.To.String { byteList } {
715 set formattedByteList [ list]
716 foreach value $byteList {
lappend formattedByteList [
format "%02X" $value ]}
717 return [
join $formattedByteList "" ]