2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2010 Emmanuel Roullit.
5 * Subject to the GPL, version 2.
11 #include <netinet/in.h> /* for htons() */
13 /* Shamelessly taken and adapted from tcpdump */
16 * Compute an IP header checksum.
17 * Don't modifiy the packet.
19 static inline uint16_t calc_csum(void *addr
, size_t len
, int csum
)
24 const uint16_t *w
= (const uint16_t *) addr
;
27 * Our algorithm is simple, using a 32 bit accumulator (sum),
28 * we add sequential 16 bit words to it, and at the end, fold
29 * back all the carry bits from the top 16 bits into the lower
38 sum
+= htons(*(const uint8_t *) w
<< 8);
41 * Add back carry outs from top 16 bits to low 16 bits
43 sum
= (sum
>> 16) + (sum
& 0xFFFF); /* add hi 16 to low 16 */
44 sum
+= (sum
>> 16); /* add carry */
45 answer
= ~sum
; /* truncate to 16 bits */
51 * Given the host-byte-order value of the checksum field in a packet
52 * header, and the network-byte-order computed checksum of the data
53 * that the checksum covers (including the checksum itself), compute
54 * what the checksum field *should* have been.
56 static inline uint16_t csum_expected(uint16_t sum
, uint16_t computed_sum
)
61 * The value that should have gone into the checksum field
62 * is the negative of the value gotten by summing up everything
63 * *but* the checksum field.
65 * We can compute that by subtracting the value of the checksum
66 * field from the sum of all the data in the packet, and then
67 * computing the negative of that value.
69 * "sum" is the value of the checksum field, and "computed_sum"
70 * is the negative of the sum of all the data in the packets,
71 * so that's -(-computed_sum - sum), or (sum + computed_sum).
73 * All the arithmetic in question is one's complement, so the
74 * addition must include an end-around carry; we do this by
75 * doing the arithmetic in 32 bits (with no sign-extension),
76 * and then adding the upper 16 bits of the sum, which contain
77 * the carry, to the lower 16 bits of the sum, and then do it
78 * again in case *that* sum produced a carry.
80 * As RFC 1071 notes, the checksum can be computed without
81 * byte-swapping the 16-bit words; summing 16-bit words
82 * on a big-endian machine gives a big-endian checksum, which
83 * can be directly stuffed into the big-endian checksum fields
84 * in protocol headers, and summing words on a little-endian
85 * machine gives a little-endian checksum, which must be
86 * byte-swapped before being stuffed into a big-endian checksum
89 * "computed_sum" is a network-byte-order value, so we must put
90 * it in host byte order before subtracting it from the
91 * host-byte-order value from the header; the adjusted checksum
92 * will be in host byte order, which is what we'll return.
96 shouldbe
+= ntohs(computed_sum
);
97 shouldbe
= (shouldbe
& 0xFFFF) + (shouldbe
>> 16);
98 shouldbe
= (shouldbe
& 0xFFFF) + (shouldbe
>> 16);
103 static inline uint16_t tcp_sum_calc(uint16_t len_tcp
, uint16_t src_addr
[],
104 uint16_t dest_addr
[], uint8_t padding
,
111 uint16_t prot_tcp
= IPPROTO_TCP
;
114 * Find out if the length of data is even or odd number. If odd,
115 * add a padding byte = 0 at the end of packet.
117 if ((padding
& 1) == 1) {
123 * Make 16 bit words out of every two adjacent 8 bit words and
124 * calculate the sum of all 16 vit words.
126 for (i
= 0; i
< len_tcp
+ padd
; i
= i
+ 2) {
127 word16
= ((buff
[i
] << 8) & 0xFF00) + (buff
[i
+ 1] & 0xFF);
128 sum
+= (unsigned long) word16
;
132 * Add the TCP pseudo header which contains: the IP source and
133 * destinationn addresses.
135 for (i
= 0; i
< 4; i
= i
+ 2) {
136 word16
= ((src_addr
[i
] << 8) & 0xFF00) +
137 (src_addr
[i
+ 1] & 0xFF);
141 for (i
= 0; i
< 4; i
= i
+ 2) {
142 word16
= ((dest_addr
[i
] << 8) & 0xFF00) +
143 (dest_addr
[i
+ 1] & 0xFF);
147 /* The protocol number and the length of the TCP packet. */
148 sum
+= (prot_tcp
+ len_tcp
);
151 * Keep only the last 16 bits of the 32 bit calculated sum and
155 sum
= (sum
& 0xFFFF) + (sum
>> 16);
157 /* Take the one's complement of sum. */
160 return (uint16_t) sum
;