-
Notifications
You must be signed in to change notification settings - Fork 1
/
checksum.c
143 lines (98 loc) · 3.86 KB
/
checksum.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* ----------------------------------------------------------------------------
SOURCE FILE
Name: checksum.c
Program: Port Forwarder
Developer: Andrew Burian
Jordan Marling
Created On: 2015-03-15
Functions:
unsigned short tcp_csum(unsigned short *packet)
unsigned short csum(unsigned short *buf, int nwords)
Description:
Contains all checksum functions used in the application.
Revisions:
(none)
---------------------------------------------------------------------------- */
#include "portforward.h"
/* ----------------------------------------------------------------------------
FUNCTION
Name: TCP Checksum
Prototype: unsigned short tcp_csum(unsigned short *packet)
Developer: Andrew Burian
Created On: 2015-03-15
Parameters:
unsigned short *packet
the start of the tcp packet to checksum
Return Values:
The checksum of the data block
Description:
Does a checksum on the TCP "pseudo header" because they couldn't just use
a standard checksum could they?
Revisions:
2015-03-20
Jordan Marling
Fixed the algorithm. The TCP header wasn't being copied fully because it
was in network byte order. also it now takes into account tcp header options.
---------------------------------------------------------------------------- */
unsigned short tcp_csum(struct iphdr *ip_header, struct tcphdr *tcp_header){
unsigned short total_len = ntohs(ip_header->tot_len);
unsigned short checksum;
// tcp lengths
int tcpopt_len = (tcp_header->doff * 4) - 20;
int tcpdatalen = total_len - (tcp_header->doff*4) - (ip_header->ihl*4);
// pseudo header
struct pseudoTcpHeader pseudohead;
int totaltcp_len = sizeof(struct pseudoTcpHeader) + sizeof(struct tcphdr) + tcpopt_len + tcpdatalen;
unsigned short *psuedoheader_tcpsegment = (unsigned short*)malloc(totaltcp_len);
pseudohead.ip_src = ip_header->saddr;
pseudohead.ip_dst = ip_header->daddr;
pseudohead.zero = 0;
pseudohead.protocol = IPPROTO_TCP;
pseudohead.tcp_len = htons(sizeof(struct tcphdr) + tcpopt_len + tcpdatalen);
// put the pseudo header into memory
memcpy((unsigned char*)psuedoheader_tcpsegment, &pseudohead, sizeof(struct pseudoTcpHeader));
// put the tcp header into memory
memcpy((unsigned char*)psuedoheader_tcpsegment + sizeof(struct pseudoTcpHeader), (unsigned char*)tcp_header, sizeof(struct tcphdr));
// put the tcp options into memory
memcpy((unsigned char*)psuedoheader_tcpsegment + sizeof(struct pseudoTcpHeader) + sizeof(struct tcphdr), (unsigned char*)ip_header + (ip_header->ihl * 4) + sizeof(struct tcphdr), tcpopt_len);
// put the tcp data into memory
memcpy((unsigned char*)psuedoheader_tcpsegment + sizeof(struct pseudoTcpHeader) + sizeof(struct tcphdr) + tcpopt_len, (unsigned char*)tcp_header + (tcp_header->doff * 4), tcpdatalen);
checksum = csum(psuedoheader_tcpsegment, totaltcp_len);
free(psuedoheader_tcpsegment);
return checksum;
}
/* ----------------------------------------------------------------------------
FUNCTION
Name: Checksum
Prototype: unsigned short csum(unsigned short *buf, int nwords)
Developer: Andrew Burian
Created On: 2015-03-15
Parameters:
unsigned short *buf
the start of the data to checksum
int nwords
the number of short (16b) words to include in the sum
Return Values:
The checksum of the data block
Description:
Taken from an implementation of RFC 1071, computes a standard internet
checksum
Revisions:
2015-03-20
Jordan Marling
Changed from words to bytes
---------------------------------------------------------------------------- */
unsigned short csum(unsigned short *buf, int nwords){
unsigned long sum;
for(sum = 0; nwords > 1; nwords -= 2) {
sum += *buf++;
}
// add the left-over byte
if(nwords > 0)
sum += *(unsigned char *)buf;
// turn the 32 bit words to 16 bit.
while (sum >> 16) {
sum = (sum & 0xffff) + (sum >> 16);
}
return (unsigned short)~sum;
}