Click
Loading...
Searching...
No Matches
tcphelper.hh
1/*
2 * tcphelper.hh - Provides several methods that can be used by elements to manage TCP packets
3 * Romain Gaillard
4 * Tom Barbette
5 */
6
7#ifndef MIDDLEBOX_TCPHELPER_HH
8#define MIDDLEBOX_TCPHELPER_HH
9
10#include <click/config.h>
11#include <click/glue.hh>
12#include <clicknet/tcp.h>
13#include <clicknet/ip.h>
14#include <click/element.hh>
15#include <click/ipflowid.hh>
16#include <functional>
17
18
19#if HAVE_DPDK
20#include <click/dpdkdevice.hh>
21#endif
22#include "iphelper.hh"
23
24#if HAVE_DPDK
25#include <rte_ip.h>
26
27#if RTE_VERSION >= RTE_VERSION_NUM(22,07,0,0)
28#define PKT_TX_TCP_CKSUM RTE_MBUF_F_TX_TCP_CKSUM
29#define PKT_TX_IP_CKSUM RTE_MBUF_F_TX_IP_CKSUM
30#define PKT_TX_IPV4 RTE_MBUF_F_TX_IPV4
31#endif
32
33#endif
34
35CLICK_DECLS
36
43class TCPHelper : public IPHelper
44{
45public:
46 TCPHelper() CLICK_COLD;
47
48
49 WritablePacket* forgeRst(Packet* packet) {
50 // Get the information needed to ack the given packet
51 uint32_t saddr = getDestinationAddress(packet);
52 uint32_t daddr = getSourceAddress(packet);
53 uint16_t sport = getDestinationPort(packet);
54 uint16_t dport = getSourcePort(packet);
55 tcp_seq_t ack = getSequenceNumber(packet);
56 tcp_seq_t seq = getAckNumber(packet);
57 uint8_t flag = TH_RST;
58
59 // Craft the packet
60 WritablePacket* forged = forgePacket(saddr, daddr, sport, dport, seq, ack, 0, flag);
61 return forged;
62 }
63
77 WritablePacket* forgePacket(uint32_t saddr, uint32_t daddr, uint16_t sport, uint16_t dport,
78 tcp_seq_t seq, tcp_seq_t ack, uint16_t winSize, uint8_t flags,
79 uint32_t contentSize = 0) const;
80
86 uint16_t getDestinationPort(Packet* packet) const;
87
93 uint16_t getSourcePort(Packet* packet) const;
94
100 inline static tcp_seq_t getSequenceNumber(Packet* packet);
101
107 inline static tcp_seq_t getAckNumber(Packet* packet);
108
115 inline tcp_seq_t getNextSequenceNumber(Packet* packet) const;
116
122 uint16_t getWindowSize(Packet *packet) const;
123
129 void setWindowSize(WritablePacket *packet, uint16_t winSize) const;
130
136 inline static bool isTCP(Packet* packet);
137
143 inline static bool isSyn(Packet* packet);
144
150 inline static bool isFin(Packet* packet);
151
157 inline static bool isRst(Packet* packet);
158
164 inline static bool isAck(Packet* packet);
165
172 inline static bool checkFlag(Packet *packet, uint8_t flag);
173
179 inline static unsigned getPayloadLength(Packet* packet);
180
186 unsigned char* getPayload(WritablePacket* packet) const;
187
193 const unsigned char* getPayloadConst(Packet* packet) const;
194
200 uint16_t getPayloadOffset(Packet* packet) const;
201
208 void setPayload(WritablePacket* packet, const unsigned char* payload, uint32_t length) const;
209
215 void setSequenceNumber(WritablePacket* packet, tcp_seq_t seq) const;
216
222 void setAckNumber(WritablePacket* packet, tcp_seq_t ack) const;
223
230 static bool isJustAnAck(Packet* packet, const bool or_fin=false);
231
237 uint8_t getFlags(Packet* packet) const;
238
243 static inline void computeTCPChecksum(WritablePacket* packet);
244
249 static inline void resetTCPChecksum(WritablePacket* packet);
250
251 static int iterateOptions(Packet *packet, std::function<bool(uint8_t,void*)> fnt);
252
253 static void printPacket(Packet* p);
254};
255
256inline void TCPHelper::printPacket(Packet* p) {
257 String sup = "";
258 String flags = "";
259 if (isSyn(p))
260 flags += "S";
261 if (isAck(p)) {
262 flags += "A";
263 sup += "ACK " + String(ntohl(p->tcp_header()->th_ack));
264 }
265 if (isRst(p))
266 flags += "R";
267
268 click_chatter("%s: %u+%u [%s] %s %s", p->timestamp_anno().unparse().c_str(), ntohl(p->tcp_header()->th_seq), getPayloadLength(p), flags.c_str(), IPFlowID(p).unparse().c_str(), sup.c_str());
269}
270
271inline tcp_seq_t
273{
274 tcp_seq_t currentSeq = getSequenceNumber(packet);
275
276 // Compute the size of the current payload
277 tcp_seq_t nextSeq = currentSeq + getPayloadLength(packet);
278
279 // FIN and SYN packets count for one in the sequence number
280 if(isFin(packet) || isSyn(packet))
281 nextSeq++;
282
283 return nextSeq;
284}
285
287{
288 click_ip *iph = packet->ip_header();
289 click_tcp *tcph = packet->tcp_header();
290
291 unsigned plen = ntohs(iph->ip_len) - (iph->ip_hl << 2);
292 tcph->th_sum = 0;
293 unsigned csum = click_in_cksum((unsigned char *)tcph, plen);
294 tcph->th_sum = click_in_cksum_pseudohdr(csum, iph, plen);
295}
296
298{
299 click_ip *iph = packet->ip_header();
300 click_tcp *tcph = packet->tcp_header();
301
302 iph->ip_sum = 0;
303 tcph->th_sum = 0;
304#if HAVE_DPDK
305 if (!DPDKDevice::is_dpdk_buffer(packet))
306 {
307 click_chatter("Not a DPDK buffer. For max performance, arrange TCP element to always work on DPDK buffers");
308#else
309 {
310#endif
311 computeTCPChecksum(packet);
312 return;
313 }
314#if HAVE_DPDK
315
316# if !CLICK_PACKET_USE_DPDK
317 rte_mbuf* mbuf = (struct rte_mbuf *) packet->destructor_argument();
318# else
319 rte_mbuf* mbuf = (struct rte_mbuf *) packet;
320# endif
321 mbuf->l2_len = packet->mac_header_length();
322 mbuf->l3_len = packet->network_header_length();
323 mbuf->l4_len = tcph->th_off << 2;
324 mbuf->ol_flags |= PKT_TX_TCP_CKSUM | PKT_TX_IP_CKSUM | PKT_TX_IPV4;
325 tcph->th_sum = rte_ipv4_phdr_cksum((const struct rte_ipv4_hdr *)iph, mbuf->ol_flags);
326#endif
327}
328
329inline void TCPHelper::setSequenceNumber(WritablePacket* packet, tcp_seq_t seq) const
330{
331 click_tcp *tcph = packet->tcp_header();
332
333 tcph->th_seq = htonl(seq);
334}
335
336inline tcp_seq_t TCPHelper::getSequenceNumber(Packet* packet)
337{
338 const click_tcp *tcph = packet->tcp_header();
339
340 return ntohl(tcph->th_seq);
341}
342
343inline tcp_seq_t TCPHelper::getAckNumber(Packet* packet)
344{
345 const click_tcp *tcph = packet->tcp_header();
346
347 return ntohl(tcph->th_ack);
348}
349
350inline void TCPHelper::setAckNumber(WritablePacket* packet, tcp_seq_t ack) const
351{
352 click_tcp *tcph = packet->tcp_header();
353
354 tcph->th_ack = htonl(ack);
355}
356
357inline uint16_t TCPHelper::getWindowSize(Packet *packet) const
358{
359 const click_tcp *tcph = packet->tcp_header();
360
361 return ntohs(tcph->th_win);
362}
363
364inline void TCPHelper::setWindowSize(WritablePacket *packet, uint16_t winSize) const
365{
366 click_tcp *tcph = packet->tcp_header();
367
368 tcph->th_win = htons(winSize);
369}
370
371inline unsigned TCPHelper::getPayloadLength(Packet* packet)
372{
373 const click_ip *iph = packet->ip_header();
374 unsigned iph_len = iph->ip_hl << 2;
375 uint16_t ip_len = ntohs(iph->ip_len);
376
377 const click_tcp *tcph = packet->tcp_header();
378 unsigned tcp_offset = tcph->th_off << 2;
379
380 return ip_len - iph_len - tcp_offset;
381}
382
383inline unsigned char* TCPHelper::getPayload(WritablePacket* packet) const
384{
385 click_tcp *tcph = packet->tcp_header();
386
387 // Compute the offset of the TCP payload
388 unsigned tcph_len = tcph->th_off << 2;
389 return (unsigned char*)packet->transport_header() + tcph_len;
390}
391
392inline const unsigned char* TCPHelper::getPayloadConst(Packet* packet) const
393{
394 const click_tcp *tcph = packet->tcp_header();
395
396 // Compute the offset of the TCP payload
397 unsigned tcph_len = tcph->th_off << 2;
398 return (const unsigned char*)packet->transport_header() + tcph_len;
399}
400
401inline void TCPHelper::setPayload(WritablePacket* packet, const unsigned char* payload,
402 uint32_t length) const
403{
404 click_tcp *tcph = packet->tcp_header();
405
406 // Compute the offset of the TCP payload
407 unsigned tcph_len = tcph->th_off << 2;
408
409 unsigned char* payloadPtr = (unsigned char*)packet->transport_header() + tcph_len;
410 memcpy(payloadPtr, payload, length);
411}
412
413inline uint16_t TCPHelper::getPayloadOffset(Packet* packet) const
414{
415 const click_tcp *tcph = packet->tcp_header();
416
417 // Compute the offset of the TCP payload
418 unsigned tcph_len = tcph->th_off << 2;
419 uint16_t offset = (uint16_t)(packet->transport_header() + tcph_len - packet->data());
420
421 return offset;
422}
423
424
425inline uint16_t TCPHelper::getSourcePort(Packet* packet) const
426{
427 const click_tcp *tcph = packet->tcp_header();
428
429 return ntohs(tcph->th_sport);
430}
431
432inline uint16_t TCPHelper::getDestinationPort(Packet* packet) const
433{
434 const click_tcp *tcph = packet->tcp_header();
435
436 return ntohs(tcph->th_dport);
437}
438
439inline bool TCPHelper::isTCP(Packet* packet)
440{
441 return packet->ip_header()->ip_p == IP_PROTO_TCP;
442}
443
444inline bool TCPHelper::isSyn(Packet* packet)
445{
446 return checkFlag(packet, TH_SYN);
447}
448
449inline bool TCPHelper::isFin(Packet* packet)
450{
451 return checkFlag(packet, TH_FIN);
452}
453
454inline bool TCPHelper::isRst(Packet* packet)
455{
456 return checkFlag(packet, TH_RST);
457}
458
459inline bool TCPHelper::isAck(Packet* packet)
460{
461 return checkFlag(packet, TH_ACK);
462}
463
464inline bool TCPHelper::checkFlag(Packet *packet, uint8_t flag)
465{
466 const click_tcp *tcph = packet->tcp_header();
467 uint8_t flags = tcph->th_flags;
468
469 // Check if the packet has the given flag
470 if(flags & flag)
471 return true;
472 else
473 return false;
474}
475
476inline uint8_t TCPHelper::getFlags(Packet *packet) const
477{
478 const click_tcp *tcph = packet->tcp_header();
479 return tcph->th_flags;
480}
481
482inline bool TCPHelper::isJustAnAck(Packet* packet, const bool or_fin)
483{
484 const click_tcp *tcph = packet->tcp_header();
485 uint8_t flags = tcph->th_flags;
486
487 // If we have a payload, we are more than just an ACK
488 if(getPayloadLength(packet) > 0)
489 return false;
490
491 // If we have other flags, we are more than just an ACK
492 if(flags == TH_ACK || (or_fin && flags == (TH_ACK | TH_FIN)))
493 return true;
494 else
495 return false;
496}
497
498
499CLICK_ENDDECLS
500
501#endif
This class provides several methods that can be used by elements that inherits from it in order to ma...
Definition iphelper.hh:23
uint32_t getSourceAddress(Packet *packet) const
Return the IP source address of the packet.
Definition iphelper.hh:98
uint32_t getDestinationAddress(Packet *packet) const
Return the IP destination address of the packet.
Definition iphelper.hh:105
A network packet.
Definition packet.hh:68
uint32_t mac_header_length() const
Return the MAC header length.
Definition packet.hh:2556
const click_tcp * tcp_header() const
Return the packet's transport header pointer as TCP.
Definition packet.hh:1553
const click_ip * ip_header() const
Return the packet's network header pointer as IPv4.
Definition packet.hh:1523
const unsigned char * data() const
Return the packet's data pointer.
Definition packet.hh:1207
const unsigned char * transport_header() const
Return the packet's transport header pointer.
Definition packet.hh:1495
const Timestamp & timestamp_anno() const
Return the timestamp annotation.
Definition packet.hh:1596
uint32_t network_header_length() const
Return the network header length.
Definition packet.hh:2577
A string of characters.
Definition string.hh:22
const char * c_str() const
Null-terminate the string.
Definition string.hh:519
This class provides several methods that can be used by elements that inherits from it to manage TCP ...
Definition tcphelper.hh:44
static bool isAck(Packet *packet)
Indicate whether a packet is an ACK packet.
Definition tcphelper.hh:459
static bool isTCP(Packet *packet)
Indicate whether a packet is a TCP packet.
Definition tcphelper.hh:439
tcp_seq_t getNextSequenceNumber(Packet *packet) const
Return the sequence number of the packet that will be received after the given one.
Definition tcphelper.hh:272
unsigned char * getPayload(WritablePacket *packet) const
Return the payload of a TCP packet.
Definition tcphelper.hh:383
void setAckNumber(WritablePacket *packet, tcp_seq_t ack) const
Set the ack number of a TCP packet.
Definition tcphelper.hh:350
static tcp_seq_t getAckNumber(Packet *packet)
Return the ack number of a packet.
Definition tcphelper.hh:343
uint16_t getPayloadOffset(Packet *packet) const
Return the offset of the payload in a TCP packet.
Definition tcphelper.hh:413
static bool checkFlag(Packet *packet, uint8_t flag)
Check if a given flag is set in a packet.
Definition tcphelper.hh:464
static bool isSyn(Packet *packet)
Indicate whether a packet is a SYN packet.
Definition tcphelper.hh:444
void setSequenceNumber(WritablePacket *packet, tcp_seq_t seq) const
Set the sequence number of a TCP packet.
Definition tcphelper.hh:329
static tcp_seq_t getSequenceNumber(Packet *packet)
Return the sequence number of a packet.
Definition tcphelper.hh:336
uint8_t getFlags(Packet *packet) const
Return the flags of a TCP packet.
Definition tcphelper.hh:476
uint16_t getWindowSize(Packet *packet) const
Return the window size set in the header of a packet.
Definition tcphelper.hh:357
uint16_t getSourcePort(Packet *packet) const
Return the source port of a packet.
Definition tcphelper.hh:425
static void resetTCPChecksum(WritablePacket *packet)
Reset the TCP checksum of a packet and set it in its header.
Definition tcphelper.hh:297
static bool isRst(Packet *packet)
Indicate whether a packet is a RST packet.
Definition tcphelper.hh:454
uint16_t getDestinationPort(Packet *packet) const
Return the destination port of a packet.
Definition tcphelper.hh:432
static unsigned getPayloadLength(Packet *packet)
Return the length of the TCP payload of a packet.
Definition tcphelper.hh:371
void setWindowSize(WritablePacket *packet, uint16_t winSize) const
Set the window size in the TCP header of a packet.
Definition tcphelper.hh:364
WritablePacket * forgePacket(uint32_t saddr, uint32_t daddr, uint16_t sport, uint16_t dport, tcp_seq_t seq, tcp_seq_t ack, uint16_t winSize, uint8_t flags, uint32_t contentSize=0) const
Create a TCP packet.
Definition tcphelper.cc:33
static bool isJustAnAck(Packet *packet, const bool or_fin=false)
Indicate whether the packet is just an ACK without any additional information.
Definition tcphelper.hh:482
void setPayload(WritablePacket *packet, const unsigned char *payload, uint32_t length) const
Set the payload of a TCP packet.
Definition tcphelper.hh:401
const unsigned char * getPayloadConst(Packet *packet) const
Return the payload of a TCP packet.
Definition tcphelper.hh:392
static void computeTCPChecksum(WritablePacket *packet)
Compute the TCP checksum of a packet and set it in its header.
Definition tcphelper.hh:286
static bool isFin(Packet *packet)
Indicate whether a packet is a FIN packet.
Definition tcphelper.hh:449
String unparse() const
Unparse this timestamp into a String.
Definition timestamp.cc:240
A network packet believed not to be shared.
Definition packet.hh:1004
Click's Element class.