1 //
2 // Copyright (C) 2008-2011 Institute of Telematics, Karlsruhe Institute of Technology (KIT)
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 //
18 
19 #include "IpPacket.h"
20 #include "TcpPacket.h"
21 #include "UdpPacket.h"
22 
23 AnonPrimitive*	IpPacket::anonTos		= NULL;
24 AnonPrimitive*	IpPacket::anonIdentifier	= NULL;
25 AnonPrimitive*	IpPacket::anonFlags		= NULL;
26 AnonPrimitive*	IpPacket::anonFragoffset	= NULL;
27 AnonPrimitive*	IpPacket::anonTtl		= NULL;
28 AnonPrimitive*	IpPacket::anonSourceip		= NULL;
29 AnonPrimitive*	IpPacket::anonDestip		= NULL;
30 AnonPrimitive*	IpPacket::anonOptions		= NULL;
31 
IpPacket(void)32 IpPacket::IpPacket(void)
33 {
34 	options.buf	= NULL;
35 	options.size	= 0;
36 	memset		(&header, 0, sizeof (IP_HEADER));
37 	protocol	= Packet::PROTO_IP;
38 }
39 
~IpPacket(void)40 IpPacket::~IpPacket(void)
41 {
42 	options.destroy ();
43 }
44 
parsePacket()45 bool IpPacket::parsePacket()
46 {
47 	memcpy (&header, buffer, sizeof (IP_HEADER));
48 
49 	//
50 	// check for correct checksum
51 	//
52 
53 	if (Configuration::instance()->getSetBadChecksumsToBad ()) {
54 		uint16_t chksum	= header.checksum;
55 		header.checksum		= 0;
56 		this->checksumgood	= (checksum (&header) == chksum);
57 		header.checksum		= chksum;
58 	}
59 
60 	//
61 	// correct some endianess stuff
62 	//
63 
64 	header.totallen		= swap16(header.totallen);
65 	header.identification	= swap16(header.identification);
66 	header.flags_fragoffset	= swap16(header.flags_fragoffset);
67 	header.checksum		= swap16(header.checksum);
68 
69 	//
70 	// get the next transport layer protocol
71 	//
72 
73 	nextProtocol = IpPacket::getTransportProtocol (header.protocol);
74 
75 	//
76 	// check for correct header values to make sure the packet is not corrupt
77 	// if is is corrupt we will stop the parsing here and return
78 	//
79 
80 	if (! ( IP_HEADER_NO_OPTIONS_LEN <= getHeaderlength () &&
81                 getHeaderlength() <= getTotallen() )) {
82 
83 		layersize	= getSize ();
84 		nextProtocol	= Packet::PROTO_NONE;
85 		options.size	= 0;
86 		options.buf	= NULL;
87 		return true;
88 	}
89 
90 	//
91 	// get the options, if any are provided
92 	//
93 
94 	options.size	= getHeaderlength () - IP_HEADER_NO_OPTIONS_LEN;
95 	options.buf	= NULL;
96 
97 	if (options.size > 0 && getSize () >= IP_HEADER_NO_OPTIONS_LEN + options.size) {
98 		options.buf = (uint8_t*) malloc (options.size);
99 		memcpy (options.buf, buffer + IP_HEADER_NO_OPTIONS_LEN, options.size);
100 	} else
101 		options.size = 0;
102 
103 	layersize = sizeof (IP_HEADER) + options.size;
104 
105 	//
106 	// remove the ethernet padding. Otherwise
107 	// it will be used as payload.
108 	// the ethernet class will add it again
109 	//
110 
111 	if (getSize () > getTotallen ())
112 		this->size = getTotallen ();
113 
114 	return true;
115 }
116 
checksum(PIP_HEADER ipheader)117 uint16_t IpPacket::checksum (PIP_HEADER ipheader)
118 {
119 	return Packet::checksum ((uint8_t*)ipheader, sizeof (IP_HEADER));
120 }
121 
getVersion()122 uint8_t IpPacket::getVersion ()
123 {
124 	return IP_HEADER_VERSION (header.version_len);
125 }
126 
getHeaderlength()127 uint8_t IpPacket::getHeaderlength ()
128 {
129 	return IP_HEADER_LEN (header.version_len);
130 }
131 
getTos()132 uint8_t IpPacket::getTos ()
133 {
134 	return header.typeofservice;
135 }
136 
getIdentification()137 uint16_t IpPacket::getIdentification ()
138 {
139 	return header.identification;
140 }
141 
getFlags()142 uint16_t IpPacket::getFlags ()
143 {
144 	return IP_HEADER_FLAGS (header.flags_fragoffset);
145 }
146 
getFragoffset()147 uint16_t IpPacket::getFragoffset ()
148 {
149 	return IP_HEADER_FRAGOFFSET (header.flags_fragoffset);
150 }
151 
getTtl()152 uint8_t IpPacket::getTtl ()
153 {
154 	return header.ttl;
155 }
156 
getProtocol()157 uint8_t IpPacket::getProtocol ()
158 {
159 	return header.protocol;
160 }
161 
getChecksum()162 uint16_t IpPacket::getChecksum ()
163 {
164 	return header.checksum;
165 }
166 
getSourceip()167 IP_ADDR IpPacket::getSourceip ()
168 {
169 	IP_ADDR ret = {{0}};
170 	memcpy (&ret, &header.sourceip, IP_ADDR_LEN);
171 	return ret;
172 }
173 
getDestip()174 IP_ADDR	IpPacket::getDestip ()
175 {
176 	IP_ADDR ret = {{0}};
177 	memcpy (&ret, &header.destip, IP_ADDR_LEN);
178 	return ret;
179 }
180 
setVersion(uint8_t ver)181 void IpPacket::setVersion (uint8_t ver)
182 {
183 	header.version_len = ((ver & 0xF) << 4) | (getHeaderlength() / 4);
184 }
185 
setHeaderlength(uint8_t len)186 void IpPacket::setHeaderlength (uint8_t len)
187 {
188 	header.version_len = (getVersion() << 4) | ((uint8_t)((len/4) & 0xF));
189 }
190 
setTos(uint8_t tos)191 void IpPacket::setTos (uint8_t tos)
192 {
193 	header.typeofservice = tos;
194 }
195 
setIdentification(uint16_t ident)196 void IpPacket::setIdentification (uint16_t ident)
197 {
198 	header.identification = ident;
199 }
200 
setFlags(uint16_t flgs)201 void IpPacket::setFlags (uint16_t	flgs)
202 {
203 	header.flags_fragoffset = ((uint16_t)(flgs & 0x07) << 13) | getFragoffset();
204 }
205 
setFragoffset(uint16_t fragoff)206 void IpPacket::setFragoffset (uint16_t fragoff)
207 {
208 	header.flags_fragoffset = ((getFlags() & 0x07) << 13) | (0xD & fragoff);
209 }
210 
setTtl(uint8_t tl)211 void IpPacket::setTtl (uint8_t tl)
212 {
213 	header.ttl = tl;
214 }
215 
setProtocol(uint8_t proto)216 void IpPacket::setProtocol (uint8_t proto)
217 {
218 	header.protocol = proto;
219 }
220 
setChecksum(uint16_t checks)221 void IpPacket::setChecksum (uint16_t checks)
222 {
223 	header.checksum = checks;
224 }
225 
setSourceip(IP_ADDR sip)226 void IpPacket::setSourceip (IP_ADDR sip)
227 {
228 	memcpy (&header.sourceip, &sip, IP_ADDR_LEN);
229 }
230 
setDestip(IP_ADDR dip)231 void IpPacket::setDestip (IP_ADDR dip)
232 {
233 	memcpy (&header.destip, &dip, IP_ADDR_LEN);
234 }
235 
getTotallen()236 uint16_t IpPacket::getTotallen ()
237 {
238 	return header.totallen;
239 }
240 
setTotallen(uint16_t totlen)241 void IpPacket::setTotallen (uint16_t totlen)
242 {
243 	header.totallen = totlen;
244 }
245 
assemblePacket()246 void IpPacket::assemblePacket()
247 {
248 	if (nextPacket != NULL) {
249 
250 		// TCP and UDP packets need the source
251 		// and dest IP addresses to calc their
252 		// checksums. So we pass it over here
253 		// where it is already transformed.
254 
255 		if (nextPacket->getProtocol() == Packet::PROTO_TCP) {
256 			((TcpPacket*)nextPacket)->setIpAddresses (getSourceip(), getDestip());
257 		} else if (nextPacket->getProtocol() == Packet::PROTO_UDP) {
258 			((UdpPacket*)nextPacket)->setIpAddresses (getSourceip(), getDestip());
259 		}
260 
261 		nextPacket->assemblePacket ();
262 	}
263 
264 	int thissize = sizeof (IP_HEADER) + options.size;
265 	int nextsize = nextPacket != NULL ? nextPacket->getSize() : 0;
266 
267 	setSize (thissize + nextsize);
268 
269 	if (nextPacket != NULL)
270 		memcpy (buffer + thissize, nextPacket->getBuffer(), nextsize);
271 
272 	//
273 	// adjust length
274 	//
275 
276 	setHeaderlength	(thissize);
277 	setTotallen	(thissize + nextsize);
278 
279 	//
280 	// correct endianess for copying
281 	//
282 
283 	header.totallen		= swap16(header.totallen	);
284 	header.identification	= swap16(header.identification	);
285 	header.flags_fragoffset	= swap16(header.flags_fragoffset);
286 	header.checksum		= swap16(header.checksum	);
287 
288 	//
289 	// calc checksum or set to random if the value was incorrect
290 	//
291 
292 	setChecksum (0);
293 
294 	if (Configuration::instance()->getReCalcChecksums ()) {
295 
296 		if (Configuration::instance()->getSetBadChecksumsToBad () && !checksumgood)
297 			setChecksum (RandomNumberGenerator::generate ());
298 		else
299 			setChecksum (checksum (&header));
300 
301 	} // if (Configuration::instance()->getReCalcChecksums ())
302 
303 	//
304 	// copy into out buffer
305 	//
306 
307 	memcpy (buffer, &header, sizeof (IP_HEADER));
308 	memcpy (buffer + sizeof (IP_HEADER), options.buf,options.size);
309 
310 	//
311 	// convert endianess back
312 	//
313 
314 	header.totallen		= swap16(header.totallen	);
315 	header.identification	= swap16(header.identification	);
316 	header.flags_fragoffset	= swap16(header.flags_fragoffset);
317 	header.checksum		= swap16(header.checksum	);
318 }
319 
setOptions(uint8_t * buf,int len)320 void IpPacket::setOptions (uint8_t* buf, int len)
321 {
322 	options.buf	= (uint8_t*) realloc (options.buf, len);
323 	options.size	= len;
324 	memcpy (options.buf, buf, len);
325 }
326 
getOptions()327 Packet::PAYLOAD_BUFFER IpPacket::getOptions()
328 {
329 	PAYLOAD_BUFFER retbuf;
330 
331 	retbuf.buf = (uint8_t*) malloc (options.size);
332 	retbuf.size = options.size;
333 
334 	memcpy (retbuf.buf, options.buf, options.size);
335 
336 	return retbuf;
337 }
338 
toString()339 string IpPacket::toString ()
340 {
341 	ostringstream out;
342 	Packet::PAYLOAD_BUFFER opts = getOptions ();
343 
344 	out << "IP packet"		<< std::endl
345 		<< "\tversion: \t"	<< (int)getVersion()		<< std::endl
346 		<< "\tlength: \t"	<< (int)getHeaderlength()	<< " bytes" << std::endl
347 		<< "\ttos: \t\t0x"	<< std::hex << std::setw(2)	<< std::setfill ('0')<< (int)getTos () << std::endl << std::dec
348 		<< "\ttotal length: \t" << getTotallen() << " bytes"	<< std::endl
349 		<< "\tident: \t\t0x"	<< std::hex << std::setw(4)	<< std::setfill ('0') << getIdentification () << std::endl << std::dec
350 		<< "\tflags: \t\t0x"	<< std::hex << std::setw(2)	<< std::setfill ('0') << getFlags () << std::endl << std::dec
351 		<< "\tfragoff: \t0x"	<< std::hex << std::setw(4)	<< std::setfill ('0') << getFragoffset () << std::endl << std::dec
352 		<< "\tttl: \t\t"	<< (int)getTtl()		<< std::endl
353 		<< "\tprotocol: \t0x"	<< std::hex << std::setw(2)	<< std::setfill ('0') << (int)getProtocol () << std::endl << std::dec
354 		<< "\tchecksum: \t0x"	<< std::hex << std::setw(4)	<< std::setfill ('0') << getChecksum () << std::endl << std::dec
355 		<< "\tsource ip: \t"	<< getSourceip().toString()	<< std::endl
356 		<< "\tdest ip: \t"	<< getDestip().toString()	<< std::endl
357 		<< "\toptions len: \t"	<< opts.size			<< std::endl
358 		<< "\toptions: \t"	<< opts.toString();
359 
360 	opts.destroy ();
361 	return out.str ();
362 }
363 
getMinProtocolSize()364 uint32_t IpPacket::getMinProtocolSize ()
365 {
366 	return sizeof (IP_HEADER);
367 }
368 
getTransportProtocol(uint8_t proto)369 Packet::PROTOCOL IpPacket::getTransportProtocol (uint8_t proto)
370 {
371 	Packet::PROTOCOL nextproto = Packet::PROTO_DATA_PAYLOAD;
372 
373 	switch (proto) {
374 		case IPTYPE_TCP:	nextproto = Packet::PROTO_TCP;			break;
375 		case IPTYPE_UDP:	nextproto = Packet::PROTO_UDP;			break;
376 		case IPTYPE_ICMP:	nextproto = Packet::PROTO_ICMP;			break;
377 		case IPTYPE_IP:		nextproto = Packet::PROTO_IP;			break;
378 		case IPTYPE_IPV6:	nextproto = Packet::PROTO_IPV6;			break;
379 		default:		nextproto = Packet::PROTO_DATA_PAYLOAD;		break;
380 	}
381 
382 	return nextproto;
383 }
384