All Classes Namespaces Files Functions Pages
checksum.tcl
Go to the documentation of this file.
1 ##
2 # @brief Basic namespace for all Excentis Tcl extensions
3 #
4 namespace eval excentis {
5 
6 ##
7 # @brief Namespace for Excentis Tcl extensions for basic functions.
8 #
9 # This includes functionality such as:
10 # - Network frame generation
11 # - Address parsing and conversion
12 # - ...
13 #
14 namespace eval basic {
15 
16 ## \file
17 #
18 # @brief Utility module that provides functionality for <b>manually calculating various checksums</b> within both TCP and UDP frames.
19 #
20 # @copyright Excentis nv - www.excentis.com
21 #
22 
23 proc Checksum.Udp.Calculate { frame {vlanCount 0} } {
24  # calculates the udp checksum of a full ethernet frame <frame> (without ethernet crc tail) and with an ipv4 header.
25  # the frame is provided as a list of bytes in 0xXX or 0xxx format
26  # the checksum is returned as a list of 2 bytes in 0xXX format (e.g. 0x1A 0x0C)
27  #
28  # @param frame The frame as a list of bytes in hex notation 0xXX
29  # @param vlanCount The number of VLAN tags the frame contains
30  #
31  # @return The UDP checksum as a list of bytes in hex notation
32  ##
33 
34  set temp $frame
35  set frame [list]
36  foreach {byte} $temp {
37  lappend frame [format 0x%02X $byte]
38  }
39 
40  #- Calculate start of L3 header
41  set offSet [expr 14 + $vlanCount * 4]
42  set frame [lrange $frame $offSet end]
43 
44  #- Grab the L3 and L4 header fields needed for pseudoheader
45  set protocol [ lrange $frame 9 9 ]
46  set sourceIp [ lrange $frame 12 15 ]
47  set destIp [ lrange $frame 16 19 ]
48  set sourcePort [ lrange $frame 20 21 ]
49  set destPort [ lrange $frame 22 23 ]
50  set udpLength [ lrange $frame 24 25 ]
51  set udpData [ lrange $frame 28 end ]
52 
53  #- Create the checksum base from pseudoheader, data and optional padding
54  set checksumCalcBytes [ list ]
55  eval lappend checksumCalcBytes $sourceIp $destIp "0x00" $protocol $udpLength $sourcePort $destPort $udpLength "0x00" "0x00" $udpData
56  if { [ expr [llength $udpData ] % 2 ] != 0} {
57  eval lappend checksumCalcBytes "0x00"
58  }
59 
60  #- Return the checksum
61  return [ ::excentis::basic::CheckSum.16 $checksumCalcBytes ]
62 }
63 
64 #**************************************************************************************************
65 
66 proc Checksum.Udpv6.Calculate { frame {vlanCount 0} } {
67  # calculates the udp checksum of a full ethernet frame <frame> (without ethernet crc tail) and with an ipv6 header.
68  # the frame is provided as a list of bytes in 0xXX format
69  # the checksum is returned as a list of 2 bytes in 0xXX format (e.g. 0x1A 0x0C)
70  #
71  # @param frame The frame as a list of bytes in hex notation
72  # @param vlanCount The number of VLAN tags the frame contains
73  #
74  # @return The UDP checksum as a list of bytes in hex notation
75  ##
76 
77  set temp $frame
78  set frame [list]
79  foreach {byte} $temp {
80  lappend frame [format 0x%02X $byte]
81  }
82 
83  #- Calculate start of L3 header
84  set offSet [expr 14 + $vlanCount * 4]
85  set frame [lrange $frame $offSet end]
86 
87  #- Grab the L3 and L4 header fields needed for pseudoheader
88  set nextHeader [ lrange $frame 6 6 ]
89  set sourceIp [ lrange $frame 8 23 ]
90  set destIp [ lrange $frame 24 39 ]
91  set sourcePort [ lrange $frame 40 41 ]
92  set destPort [ lrange $frame 42 43 ]
93  set udpLength [ lrange $frame 44 45 ]
94  set udpData [ lrange $frame 48 end ]
95 
96  #- Create the checksum base from pseudoheader, data and optional padding
97  set checksumCalcBytes [ list ]
98  eval lappend checksumCalcBytes $sourceIp $destIp "0x00" "0x00" $udpLength "0x00" "0x00" "0x00" $nextHeader $sourcePort $destPort $udpLength "0x00" "0x00" $udpData
99  if { [ expr [llength $udpData ] % 2 ] != 0} {
100  eval lappend checksumCalcBytes "0x00"
101  }
102 
103  #- Return the checksum
104  return [ ::excentis::basic::CheckSum.16 $checksumCalcBytes ]
105 }
106 
107 #**************************************************************************************************
108 
109 proc Checksum.Tcp.Calculate { frame {vlanCount 0} } {
110  # calculates the tcp checksum of a full ethernet frame <frame> (without ethernet crc tail) and with an ipv4 header.
111  # the frame is provided as a list of bytes in 0xXX or 0xxx format
112  # the checksum is returned as a list of 2 bytes in 0xXX format (e.g. 0x1A 0x0C)
113  #
114  # @param frame The frame as a list of bytes in hex notation
115  # @param vlanCount The number of VLAN tags the frame contains
116  #
117  # @return The TCP checksum as a list of bytes in hex notation
118  ##
119 
120  set temp $frame
121  set frame [list]
122  foreach {byte} $temp {
123  lappend frame [format 0x%02X $byte]
124  }
125 
126  #- Calculate start of L3 header
127  set offSet [expr 14 + $vlanCount * 4]
128  set frame [lrange $frame $offSet end]
129 
130  #- Grab the L3 and L4 header fields needed for pseudoheader
131  set tcpLength [Short.To.Hex [ expr 0x[Hex.To.String [ lrange $frame 2 3 ]] - 20 ]]
132  set protocol [ lrange $frame 9 9 ]
133  set sourceIp [ lrange $frame 12 15 ]
134  set destIp [ lrange $frame 16 19 ]
135  set sourcePort [ lrange $frame 20 21 ]
136  set destPort [ lrange $frame 22 23 ]
137  set seqNumber [ lrange $frame 24 27 ]
138  set ackNumber [ lrange $frame 28 31 ]
139  set stuff [ lrange $frame 32 33 ]
140  set window [ lrange $frame 34 35 ]
141  set urgPointer [ lrange $frame 38 39 ]
142  set tcpData [ lrange $frame 40 end ]
143 
144  #- Create the checksum base from pseudoheader, data and optional padding
145  set checksumCalcBytes [ list ]
146  eval lappend checksumCalcBytes $sourceIp $destIp "0x00" $protocol $tcpLength $sourcePort $destPort $seqNumber $ackNumber $stuff $window "0x00" "0x00" $urgPointer $tcpData
147  if { [ expr [llength $tcpData ] % 2 ] != 0} {
148  eval lappend checksumCalcBytes "0x00"
149  }
150 
151  #- Return the checksum
152  return [ ::excentis::basic::CheckSum.16 $checksumCalcBytes ]
153 }
154 
155 #**************************************************************************************************
156 
157 proc Checksum.Tcpv6.Calculate { frame {vlanCount 0} } {
158  # calculates the tcp checksum of a full ethernet frame <frame> (without ethernet crc tail) and with an ipv6 header.
159  # the frame is provided as a list of bytes in 0xXX or 0xxx format
160  # the checksum is returned as a list of 2 bytes in 0xXX format (e.g. 0x1A 0x0C)
161  #
162  # @param frame The frame as a list of bytes in hex notation
163  # @param vlanCount The number of VLAN tags the frame contains
164  #
165  # @return The TCP checksum as a list of bytes in hex notation
166  ##
167 
168  set temp $frame
169  set frame [list]
170  foreach {byte} $temp {
171  lappend frame [format 0x%02X $byte]
172  }
173 
174  #- Calculate start of L3 header
175  set offSet [expr 14 + $vlanCount * 4]
176  set frame [lrange $frame $offSet end]
177 
178  #- Grab the L3 and L4 header fields needed for pseudoheader
179  set tcpLength [ lrange $frame 4 5 ]
180  set nextHeader [ lrange $frame 6 6 ]
181  set sourceIp [ lrange $frame 8 23 ]
182  set destIp [ lrange $frame 24 39 ]
183  set sourcePort [ lrange $frame 40 41 ]
184  set destPort [ lrange $frame 42 43 ]
185  set seqNumber [ lrange $frame 44 47 ]
186  set ackNumber [ lrange $frame 48 51 ]
187  set stuff [ lrange $frame 52 53 ]
188  set window [ lrange $frame 54 55 ]
189  set urgPointer [ lrange $frame 58 59 ]
190  set tcpData [ lrange $frame 60 end ]
191 
192  #- Create the checksum base from pseudoheader, data and optional padding
193  set checksumCalcBytes [ list ]
194  eval lappend checksumCalcBytes $sourceIp $destIp $tcpLength "0x00" "0x00" "0x00" $nextHeader $sourcePort $destPort $seqNumber $ackNumber $stuff $window "0x00" "0x00" $urgPointer $tcpData
195  if { [ expr [llength $tcpData ] % 2 ] != 0} {
196  eval lappend checksumCalcBytes "0x00"
197  }
198 
199  #- Return the checksum
200  return [ ::excentis::basic::CheckSum.16 $checksumCalcBytes ]
201 }
202 
203 #**************************************************************************************************
204 
205 proc Checksum.Ipv4.Calculate { frame {vlanCount 0} } {
206  # calculates the ipv4 header of a full ethernet frame <frame> (without ethernet crc tail)
207  # the frame is provided as a list of bytes in 0xXX format
208  # the checksum is returned as a list of 2 bytes in 0xXX format (e.g. 0x1A 0x0C)
209  #
210  # @param frame The frame as a list of bytes in hex notation
211  # @param vlanCount The number of VLAN tags the frame contains
212  #
213  # @return The IPv4 header checksum as a list of bytes in hex notation
214  ##
215  set temp $frame
216  set frame [list]
217  foreach { byte } $temp {
218  lappend frame [format 0x%02X $byte]
219  }
220 
221  #- Calculate start of L3 header
222  set offSet [expr 14 + $vlanCount * 4]
223  set frame [lrange $frame $offSet end]
224 
225  #- Grab the L3 header fields (except the checksum bytes)
226  set ihl [ expr [lindex $frame 0] & 0x0F ]
227  set prechecksum [ lrange $frame 0 9 ]
228  set postchecksum [ lrange $frame 12 [expr 4 * $ihl - 1] ]
229 
230  #- Return the checksum
231  return [ ::excentis::basic::CheckSum.16 [join [list $prechecksum "0x00 0x00" $postchecksum]] ]
232 }
233 
234 #**************************************************************************************************
235 
236 }
237 
238 }