1 /*
2 ettercap -- checksumming functions
3
4 Copyright (C) ALoR & NaGA
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19
20 */
21
22 #include <ec.h>
23 #include <ec_packet.h>
24 #include <ec_checksum.h>
25
26 /* protos... */
27
28 static u_int16 sum(u_int8 *buf, size_t len);
29 static u_int16 v4_checksum(struct packet_object *po);
30 static u_int16 v6_checksum(struct packet_object *po);
31
32 /*******************************************/
33
34
sum(u_int8 * buf,size_t len)35 static u_int16 sum(u_int8 *buf, size_t len)
36 {
37 /* create union for type punning - elements named as their rep. type */
38 union {
39 u_int8 u_int8 [4];
40 u_int16 u_int16[2];
41 u_int32 u_int32;
42 } u;
43 register u_int8 *cbuf = buf;
44 #if OS_SIZEOF_P == 8
45 register u_int64 csum = 0;
46 #elif OS_SIZEOF_P == 4
47 register u_int32 csum = 0;
48 #endif
49 register unsigned int nleft = len;
50
51
52 #if OS_SIZEOF_P == 8
53 while(nleft >= sizeof(u_int32)) {
54 /* assigning bytes from buffer to union for 64-bit systems */
55 u.u_int8[0] = cbuf[0];
56 u.u_int8[1] = cbuf[1];
57 u.u_int8[2] = cbuf[2];
58 u.u_int8[3] = cbuf[3];
59
60 csum += u.u_int32;
61 cbuf += sizeof(u_int32);
62 nleft -= sizeof(u_int32);
63 }
64 #endif
65
66 while(nleft >= sizeof(u_int16)) {
67 /* assigning bytes from buffer to union for 32-bit systems */
68 u.u_int8[0] = cbuf[0];
69 u.u_int8[1] = cbuf[1];
70
71 csum += u.u_int16[0];
72 cbuf += sizeof(u_int16);
73 nleft -= sizeof(u_int16);
74 }
75
76 if(nleft) {
77 /* one word left */
78 u.u_int8[0] = cbuf[0];
79 u.u_int8[1] = 0;
80
81 csum += u.u_int16[0];
82 cbuf++;
83 nleft--;
84 }
85
86 #if OS_SIZEOF_P == 8
87 csum = (csum >> 32) + (csum & 0xffffffff);
88 csum = (csum >> 32) + (csum & 0xffffffff);
89 #endif
90
91 csum = (csum >> 16) + (csum & 0xffff);
92 csum += (csum >> 16);
93
94 return csum;
95 }
96
97 /*
98 * calculate the checksum of a Layer 3 packet
99 */
100
L3_checksum(u_char * buf,size_t len)101 u_int16 L3_checksum(u_char *buf, size_t len)
102 {
103 u_int16 csum;
104 csum = sum((u_int8 *) buf, len);
105
106 return (u_int16)(~csum);
107 }
108
109 /*
110 * calculate the checksum of a Layer 4 packet
111 */
112
L4_checksum(struct packet_object * po)113 u_int16 L4_checksum(struct packet_object *po)
114 {
115 switch(ntohs(po->L3.proto)) {
116 case LL_TYPE_IP: return v4_checksum(po);
117 case LL_TYPE_IP6: return v6_checksum(po);
118 default: break;
119 }
120
121 return 0;
122 }
123
v4_checksum(struct packet_object * po)124 static u_int16 v4_checksum(struct packet_object *po)
125 {
126 u_int32 csum;
127 int len = po->L4.len + po->DATA.len;
128
129 csum = sum(po->L4.header, len);
130
131 /* check the pseudo header */
132 csum += po->L3.src.addr16[0];
133 csum += po->L3.src.addr16[1];
134 csum += po->L3.dst.addr16[0];
135 csum += po->L3.dst.addr16[1];
136
137 csum += htons((u_int16)po->L4.proto);
138 csum += htons(len);
139
140 csum = (csum >> 16) + (csum & 0xffff);
141 csum += (csum >> 16);
142
143 return (u_int16)(~csum);
144 }
145
v6_checksum(struct packet_object * po)146 static u_int16 v6_checksum(struct packet_object *po)
147 {
148 u_int8 *buf = po->L4.header;
149 u_int16 plen = po->L3.payload_len;
150 u_int32 csum;
151
152 csum = sum(buf, plen);
153
154 csum += sum((uint8_t*)&po->L3.src.addr, ntohs(po->L3.src.addr_len));
155 csum += sum((uint8_t*)&po->L3.dst.addr, ntohs(po->L3.dst.addr_len));
156 csum += htons(plen + po->L4.proto);
157
158 csum = (csum & 0xffff) + (csum >> 16);
159 csum += (csum >> 16);
160
161 return (u_int16)(~csum);
162 }
163
164 /*
165 * calculate the CRC32 of a buffer
166 */
167
CRC_checksum(u_char * buf,size_t len,u_int32 init)168 u_int32 CRC_checksum(u_char *buf, size_t len, u_int32 init)
169 {
170 static unsigned long crc_32_tab[] = {
171 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
172 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
173 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
174 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
175 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
176 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
177 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
178 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
179 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
180 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
181 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
182 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
183 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
184 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
185 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
186 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
187 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
188 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
189 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
190 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
191 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
192 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
193 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
194 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
195 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
196 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
197 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
198 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
199 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
200 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
201 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
202 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
203 };
204
205 u_int32 crc;
206 size_t i;
207
208 crc = init;
209
210 for(i = 0; i < len; i++)
211 crc = crc_32_tab[(crc ^ buf[i]) & 0xff] ^ (crc>>8);
212
213 return crc;
214 }
215
216 /* stolen from wireshark source code (in_cksum.c) */
217
218 /*
219 * Given the network-byte-order value of the checksum field in a packet
220 * header, and the network-byte-order computed checksum of the data
221 * that the checksum covers (including the checksum itself), compute
222 * what the checksum field *should* have been.
223 */
checksum_shouldbe(u_int16 csum,u_int16 computed_sum)224 u_int16 checksum_shouldbe(u_int16 csum, u_int16 computed_sum)
225 {
226 u_int32 shouldbe;
227
228 /*
229 * The value that should have gone into the checksum field
230 * is the negative of the value gotten by summing up everything
231 * *but* the checksum field.
232 *
233 * We can compute that by subtracting the value of the checksum
234 * field from the sum of all the data in the packet, and then
235 * computing the negative of that value.
236 *
237 * "sum" is the value of the checksum field, and "computed_sum"
238 * is the negative of the sum of all the data in the packets,
239 * so that's -(-computed_sum - sum), or (sum + computed_sum).
240 *
241 * All the arithmetic in question is one's complement, so the
242 * addition must include an end-around carry; we do this by
243 * doing the arithmetic in 32 bits (with no sign-extension),
244 * and then adding the upper 16 bits of the sum, which contain
245 * the carry, to the lower 16 bits of the sum, and then do it
246 * again in case *that* sum produced a carry.
247 *
248 * As RFC 1071 notes, the checksum can be computed without
249 * byte-swapping the 16-bit words; summing 16-bit words
250 * on a big-endian machine gives a big-endian checksum, which
251 * can be directly stuffed into the big-endian checksum fields
252 * in protocol headers, and summing words on a little-endian
253 * machine gives a little-endian checksum, which must be
254 * byte-swapped before being stuffed into a big-endian checksum
255 * field.
256 *
257 * "computed_sum" is a network-byte-order value, so we must put
258 * it in host byte order before subtracting it from the
259 * host-byte-order value from the header; the adjusted checksum
260 * will be in host byte order, which is what we'll return.
261 */
262 shouldbe = ntohs(csum);
263 shouldbe += ntohs(computed_sum);
264 shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
265 shouldbe = (shouldbe & 0xFFFF) + (shouldbe >> 16);
266 return shouldbe;
267 }
268
269
270 /* EOF */
271
272 // vim:ts=3:expandtab
273
274