IPPOLib
 All Classes Files Functions Variables Typedefs Macros
checksum.cpp
Go to the documentation of this file.
1 /*
2  * ippo-lib - IP oPtion-based active PrObing
3  * An Active Probing Library for IP Options Equipped probes (http://traffic.comics.unina.it/ippolib)
4  *
5  * Copyright : (C) 2012 by Pietro Marchetta, Walter de Donato, Francesco Cesareo,
6  * Antonio Pescape' (PI)
7  * of the COMICS (COMputer for Interaction and
8  * CommunicationS) Group, Dipartimento di Informatica
9  * e Sistemistica of the University of Napoli "Federico II".
10  *
11  * email : pietro.marchetta@unina.it , walter.dedonato@unina.it , cesareo.francesco@gmail.com
12  * pescape@unina.it
13  *
14  * This program is free software: you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation, either version 3 of the License, or
17  * (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program. If not, see <http://www.gnu.org/licenses/>.
26  *
27  */
28 
29 #include "checksum.h"
30 
31 #include <sys/types.h>
32 #include <netinet/in.h>
33 
34 uint16_t udp_sum_calc( uint16_t len_udp,
35  uint32_t src_addr,
36  uint16_t src_port,
37  uint32_t dest_addr,
38  uint16_t dest_port,
39  const void * buff
40  )
41 {
42  uint16_t prot_udp = 17;
43  uint16_t chksum_init = 0;
44  uint16_t udp_len_total = 0;
45  uint32_t sum = 0;
46  uint16_t pad = 0;
47  uint16_t low;
48  uint16_t high;
49  int i;
50 
51  /* if we have an odd number of bytes in the data payload, then set the pad to 1
52  * for special processing
53  */
54  if( len_udp%2 != 0 ) {
55  pad = 1;
56  }
57  /* do the source and destination addresses, first, we have to split them
58  * into 2 shorts instead of the 32 long as sent. Sorry, that's just how they
59  * calculate
60  */
61  low = src_addr;
62  high = ( src_addr>>16 );
63  sum += ( ( uint32_t ) high + ( uint32_t ) low );
64 
65  /* now do the same with the destination address */
66  low = dest_addr;
67  high = ( dest_addr>>16 );
68  sum += ( ( uint32_t ) high + ( uint32_t ) low );
69 
70  /* the protocol and the number and the length of the UDP packet */
71  udp_len_total = len_udp + 8; /* length sent is length of data, need to add 8 */
72  sum += ( ( uint32_t )prot_udp + ( uint32_t )udp_len_total );
73 
74 
75  /* next comes the source and destination ports */
76  sum += ( ( uint32_t )src_port + ( uint32_t ) dest_port );
77 
78  /* Now add the UDP length and checksum=0 bits
79  * The Length will always be 8 bytes plus the length of the udp data sent
80  * and the checksum will always be zero
81  */
82  sum += ( ( uint32_t ) udp_len_total + ( uint32_t ) chksum_init );
83 
84 
85  /* Add all 16 bit words to the sum, if pad is set (ie, odd data length) this will just read up
86  * to the last full 16 bit word.
87  * */
88  for( i=0; i< ( len_udp - pad ); i+=2 ) {
89  high = ntohs(*(uint16_t *)buff);
90  buff +=2;
91  sum += ( uint32_t ) high;
92  }
93 
94  /* ok, if pad is true, then the pointer is now right before the last single byte in
95  * the payload. We only need to add till the end of the string (1-byte) , not the next 2 bytes
96  * as above.
97  */
98  if( pad ) {
99  sum += ntohs( * ( unsigned char * ) buff );
100  }
101 
102  /* keep only the last 16 bits of the 32 bit calculated sum and add the carry overs */
103  while ( sum>>16 ) {
104  sum = ( sum & 0xFFFF ) + ( sum >> 16 );
105  }
106 
107  /* one's compliment the sum */
108  sum = ~sum;
109 
110  /* finally, return the 16bit network formated checksum */
111  return ((uint16_t) htons(sum) );
112 };
113 
114 
115 uint16_t udp_sum_calc2(uint16_t len_udp, uint16_t src_addr[],uint16_t dest_addr[], bool padding, uint16_t buff[])
116 {
117 uint16_t prot_udp=17;
118 uint16_t padd=0;
119 uint16_t word16;
120 uint32_t sum;
121 
122  printf("*");
123  fflush ( stdout );
124  // Find out if the length of data is even or odd number. If odd,
125  // add a padding byte = 0 at the end of packet
126  if (padding==true){
127  padd=1;
128  buff[len_udp]=0;
129  }
130  printf("*");
131  fflush ( stdout );
132  //initialize sum to zero
133  sum=0;
134 
135  // make 16 bit words out of every two adjacent 8 bit words and
136  // calculate the sum of all 16 bit words
137  int i=0;
138  for (i=0;i<len_udp+padd;i=i+2){
139  word16 =((buff[i]<<8)&0xFF00)+(buff[i+1]&0xFF);
140  sum = sum + (unsigned long)word16;
141  }
142  printf("*");
143  fflush ( stdout );
144  // add the UDP pseudo header which contains the IP source and destinationn addresses
145  for (i=0;i<4;i=i+2){
146  word16 =((src_addr[i]<<8)&0xFF00)+(src_addr[i+1]&0xFF);
147  sum=sum+word16;
148  }
149  printf("*");
150  fflush ( stdout );
151  for (i=0;i<4;i=i+2){
152  word16 =((dest_addr[i]<<8)&0xFF00)+(dest_addr[i+1]&0xFF);
153  sum=sum+word16;
154  }
155  // the protocol number and the length of the UDP packet
156  sum = sum + prot_udp + len_udp;
157 
158  // keep only the last 16 bits of the 32 bit calculated sum and add the carries
159  while (sum>>16)
160  sum = (sum & 0xFFFF)+(sum >> 16);
161 
162  // Take the one's complement of sum
163  sum = ~sum;
164 
165 return ((uint16_t) sum);
166 }
167 
168 
169 u_short in_chksum (u_short *addr, int len) {
170 
171 int nleft = len, sum = 0;
172 u_short *w = addr, answer = 0;
173 
174  while (nleft > 1) {
175  sum += *w++;
176  nleft -= 2;
177  }
178 
179  if (nleft == 1) {
180  *(u_char *)(&answer) = *(u_char *)w;
181  sum += answer;
182  }
183 
184  sum = (sum >> 16) + (sum + 0xffff);
185  sum += (sum >> 16);
186  answer = ~sum;
187  return(answer);
188 }
189 
190 
191 unsigned short in_chksum_udp( unsigned short *h, unsigned short * d, int dlen )
192 {
193  unsigned int cksum;
194  unsigned short answer=0;
195 
196  /* PseudoHeader must have 12 bytes */
197  cksum = h[0];
198  cksum += h[1];
199  cksum += h[2];
200  cksum += h[3];
201  cksum += h[4];
202  cksum += h[5];
203 
204  /* UDP must have 8 hdr bytes */
205  cksum += d[0];
206  cksum += d[1];
207  cksum += d[2];
208  cksum += d[3];
209 
210  dlen -= 8; /* bytes */
211  d += 4; /* short's */
212 
213  while(dlen >=32)
214  {
215  cksum += d[0];
216  cksum += d[1];
217  cksum += d[2];
218  cksum += d[3];
219  cksum += d[4];
220  cksum += d[5];
221  cksum += d[6];
222  cksum += d[7];
223  cksum += d[8];
224  cksum += d[9];
225  cksum += d[10];
226  cksum += d[11];
227  cksum += d[12];
228  cksum += d[13];
229  cksum += d[14];
230  cksum += d[15];
231  d += 16;
232  dlen -= 32;
233  }
234 
235  while(dlen >=8)
236  {
237  cksum += d[0];
238  cksum += d[1];
239  cksum += d[2];
240  cksum += d[3];
241  d += 4;
242  dlen -= 8;
243  }
244 
245  while(dlen > 1)
246  {
247  cksum += *d++;
248  dlen -= 2;
249  }
250 
251  if( dlen == 1 )
252  {
253  *(unsigned char*)(&answer) = (*(unsigned char*)d);
254  cksum += answer;
255  }
256 
257  cksum = (cksum >> 16) + (cksum & 0x0000ffff);
258  cksum += (cksum >> 16);
259 
260  return (unsigned short)(~cksum);
261 }
262 
263 
264 
265 unsigned short in_chksum_tcp( unsigned short *h, unsigned short * d, int dlen )
266 {
267  unsigned int cksum;
268  unsigned short answer=0;
269 
270  /* PseudoHeader must have 12 bytes */
271  cksum = h[0];
272  cksum += h[1];
273  cksum += h[2];
274  cksum += h[3];
275  cksum += h[4];
276  cksum += h[5];
277 
278  /* TCP hdr must have 20 hdr bytes */
279  cksum += d[0];
280  cksum += d[1];
281  cksum += d[2];
282  cksum += d[3];
283  cksum += d[4];
284  cksum += d[5];
285  cksum += d[6];
286  cksum += d[7];
287  cksum += d[8];
288  cksum += d[9];
289 
290  dlen -= 20; /* bytes */
291  d += 10; /* short's */
292 
293  while(dlen >=32)
294  {
295  cksum += d[0];
296  cksum += d[1];
297  cksum += d[2];
298  cksum += d[3];
299  cksum += d[4];
300  cksum += d[5];
301  cksum += d[6];
302  cksum += d[7];
303  cksum += d[8];
304  cksum += d[9];
305  cksum += d[10];
306  cksum += d[11];
307  cksum += d[12];
308  cksum += d[13];
309  cksum += d[14];
310  cksum += d[15];
311  d += 16;
312  dlen -= 32;
313  }
314 
315  while(dlen >=8)
316  {
317  cksum += d[0];
318  cksum += d[1];
319  cksum += d[2];
320  cksum += d[3];
321  d += 4;
322  dlen -= 8;
323  }
324 
325  while(dlen > 1)
326  {
327  cksum += *d++;
328  dlen -= 2;
329  }
330 
331  if( dlen == 1 )
332  {
333  /* printf("new checksum odd byte-packet\n"); */
334  *(unsigned char*)(&answer) = (*(unsigned char*)d);
335 
336  /* cksum += (u_int16_t) (*(u_int8_t*)d); */
337 
338  cksum += answer;
339  }
340 
341  cksum = (cksum >> 16) + (cksum & 0x0000ffff);
342  cksum += (cksum >> 16);
343 
344  return (unsigned short)(~cksum);
345 }
346 
347 unsigned short cksum(unsigned short *addr, int len)
348 {
349  int nleft = len;
350  int sum = 0;
351  unsigned short *w = addr;
352  unsigned short answer = 0;
353 
354  while (nleft > 1) {
355  sum = sum + *w++;
356  nleft = nleft - 2;
357  }
358 
359  if (nleft == 1) {
360  *(unsigned char *) (&answer) = *(unsigned char *) w;
361  sum = sum + answer;
362  }
363 
364  sum = (sum >> 16) + (sum & 0xffff);
365  sum = sum + (sum >> 16);
366  answer = ~sum;
367 
368  return answer;
369 }
370 
371 uint16_t ip_sum_calc(uint16_t len_ip_header, uint16_t buff[])
372 {
373 uint16_t word16;
374 uint32_t sum=0;
375 uint16_t i;
376 
377  // make 16 bit words out of every two adjacent 8 bit words in the packet
378  // and add them up
379  for (i=0;i<len_ip_header;i=i+2){
380  word16 =((buff[i]<<8)&0xFF00)+(buff[i+1]&0xFF);
381  sum = sum + (uint32_t) word16;
382  }
383 
384  // take only 16 bits out of the 32 bit sum and add up the carries
385  while (sum>>16)
386  sum = (sum & 0xFFFF)+(sum >> 16);
387 
388  // one's complement the result
389  sum = ~sum;
390 
391 return ((uint16_t) sum);
392 }