Coverage Report

Created: 2026-10-07 07:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/tcpreplay/src/fragroute/mod_tcp_seg.c
Line
Count
Source
1
/*
2
 * mod_tcp_seg.c
3
 *
4
 * Copyright (c) 2001 Dug Song <dugsong@monkey.org>
5
 *
6
 * $Id$
7
 */
8
9
#include "defines.h"
10
#include "config.h"
11
#include "common.h"
12
#include "iputil.h"
13
#include "lib/queue.h"
14
#include "mod.h"
15
#include "pkt.h"
16
#include "randutil.h"
17
#include <stdio.h>
18
#include <stdlib.h>
19
#include <string.h>
20
21
#ifndef MIN
22
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
23
#endif
24
25
0
#define FAVOR_OLD 1
26
0
#define FAVOR_NEW 2
27
28
static struct tcp_seg_data {
29
    rand_t *rnd;
30
    int size;
31
    int overlap;
32
} tcp_seg_data;
33
34
void *
35
tcp_seg_close(_U_ void *d)
36
0
{
37
0
    if (tcp_seg_data.rnd != NULL)
38
0
        rand_close(tcp_seg_data.rnd);
39
0
    tcp_seg_data.size = 0;
40
0
    return (NULL);
41
0
}
42
43
void *
44
tcp_seg_open(int argc, char *argv[])
45
0
{
46
0
    if (argc < 2) {
47
0
        warn("need segment <size> in bytes");
48
0
        return (NULL);
49
0
    }
50
0
    if (tcp_seg_data.rnd != NULL)
51
0
        rand_close(tcp_seg_data.rnd);
52
0
    tcp_seg_data.rnd = rand_open();
53
54
    /*
55
     * A negative size survives as a negative int, then reaches memcpy() as a
56
     * huge implicitly-converted size_t (and walks the segment loop backwards).
57
     */
58
0
    tcp_seg_data.size = (int)strtol(argv[1], NULL, 10);
59
0
    if (tcp_seg_data.size <= 0 || tcp_seg_data.size > IP_LEN_MAX) {
60
0
        warnx("invalid segment size '%s' (must be between 1 and 65535 bytes)", argv[1]);
61
0
        return (tcp_seg_close(&tcp_seg_data));
62
0
    }
63
0
    if (argc == 3) {
64
0
        if (strcmp(argv[2], "old") == 0 || strcmp(argv[2], "win32") == 0)
65
0
            tcp_seg_data.overlap = FAVOR_OLD;
66
0
        else if (strcmp(argv[2], "new") == 0 || strcmp(argv[2], "unix") == 0)
67
0
            tcp_seg_data.overlap = FAVOR_NEW;
68
0
        else
69
0
            return (tcp_seg_close(&tcp_seg_data));
70
0
    }
71
0
    return (&tcp_seg_data);
72
0
}
73
74
int
75
tcp_seg_apply(_U_ void *d, struct pktq *pktq)
76
0
{
77
0
    struct pkt *pkt, *new, *next;
78
79
0
    for (pkt = TAILQ_FIRST(pktq); pkt != TAILQ_END(pktq); pkt = next) {
80
0
        uint32_t seq;
81
0
        int hl, tl, len;
82
0
        u_char *p;
83
0
        uint16_t eth_type;
84
0
        uint8_t nxt;
85
86
0
        next = TAILQ_NEXT(pkt, pkt_next);
87
88
0
        eth_type = htons(pkt->pkt_eth->eth_type);
89
90
0
        if (pkt->pkt_ip == NULL)
91
0
            continue;
92
93
0
        if (eth_type == ETH_TYPE_IP) {
94
0
            nxt = pkt->pkt_ip->ip_p;
95
0
        } else if (eth_type == ETH_TYPE_IPV6) {
96
0
            nxt = pkt->pkt_ip6->ip6_nxt;
97
0
        } else {
98
0
            continue;
99
0
        }
100
101
0
        if (nxt != IP_PROTO_TCP || pkt->pkt_tcp == NULL || pkt->pkt_tcp_data == NULL ||
102
0
            (pkt->pkt_tcp->th_flags & TH_ACK) == 0 || pkt->pkt_end - pkt->pkt_tcp_data <= tcp_seg_data.size)
103
0
            continue;
104
105
0
        if (eth_type == ETH_TYPE_IP) {
106
0
            hl = pkt->pkt_ip->ip_hl << 2;
107
0
        } else if (eth_type == ETH_TYPE_IPV6) {
108
0
            hl = IP6_HDR_LEN;
109
0
        } else {
110
0
            continue;
111
0
        }
112
113
0
        tl = pkt->pkt_tcp->th_off << 2;
114
0
        seq = ntohl(pkt->pkt_tcp->th_seq);
115
116
0
        for (p = pkt->pkt_tcp_data; p < pkt->pkt_end; p += len) {
117
0
            u_char *p1, *p2;
118
119
0
            if ((new = pkt_new(pkt->pkt_buf_size)) == NULL) {
120
0
                return -1;
121
0
            }
122
123
0
            memcpy(new->pkt_eth, pkt->pkt_eth, (u_char *)pkt->pkt_eth_data - (u_char *)pkt->pkt_eth);
124
0
            p1 = p, p2 = NULL;
125
0
            len = MIN(pkt->pkt_end - p, tcp_seg_data.size);
126
127
0
            if (tcp_seg_data.overlap != 0 && p + (len << 1) < pkt->pkt_end) {
128
0
                struct pkt tmp;
129
0
                u_char tmp_buf[pkt->pkt_buf_size];
130
131
0
                tmp.pkt_buf = tmp_buf;
132
0
                tmp.pkt_buf_size = pkt->pkt_buf_size;
133
0
                rand_strset(tcp_seg_data.rnd, tmp.pkt_buf, len);
134
135
0
                if (tcp_seg_data.overlap == FAVOR_OLD) {
136
0
                    p1 = p + len;
137
0
                    p2 = tmp.pkt_buf;
138
0
                } else if (tcp_seg_data.overlap == FAVOR_NEW) {
139
0
                    p1 = tmp.pkt_buf;
140
0
                    p2 = p + len;
141
0
                }
142
0
                len = tcp_seg_data.size;
143
0
                seq += tcp_seg_data.size;
144
0
            }
145
0
            memcpy(new->pkt_ip, pkt->pkt_ip, hl + tl);
146
0
            new->pkt_ip_data = new->pkt_eth_data + hl;
147
0
            new->pkt_tcp_data = new->pkt_ip_data + tl;
148
0
            memcpy(new->pkt_tcp_data, p1, len);
149
0
            new->pkt_end = new->pkt_tcp_data + len;
150
151
0
            if (eth_type == ETH_TYPE_IP) {
152
0
                new->pkt_ip->ip_id = rand_uint16(tcp_seg_data.rnd);
153
0
                new->pkt_ip->ip_len = htons(hl + tl + len);
154
0
            } else {
155
0
                new->pkt_ip6->ip6_plen = htons(tl + len);
156
0
            }
157
158
0
            new->pkt_tcp->th_seq = htonl(seq);
159
0
            inet_checksum(eth_type, new->pkt_ip, hl + tl + len);
160
0
            TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
161
162
0
            if (p2 != NULL) {
163
0
                if ((new = pkt_dup(new)) == NULL) {
164
0
                    return -1;
165
0
                }
166
167
0
                new->pkt_ts.tv_usec = 1;
168
0
                if (eth_type == ETH_TYPE_IP) {
169
0
                    new->pkt_ip->ip_id = rand_uint16(tcp_seg_data.rnd);
170
0
                    new->pkt_ip->ip_len = htons(hl + tl + (len << 1));
171
0
                } else if (eth_type == ETH_TYPE_IPV6) {
172
0
                    new->pkt_ip6->ip6_plen = htons(tl + (len << 1));
173
0
                }
174
0
                new->pkt_tcp->th_seq = htonl(seq - len);
175
176
0
                memcpy(new->pkt_tcp_data, p, len);
177
0
                memcpy(new->pkt_tcp_data + len, p2, len);
178
0
                new->pkt_end = new->pkt_tcp_data + (len << 1);
179
0
                inet_checksum(eth_type, new->pkt_ip, hl + tl + (len << 1));
180
0
                TAILQ_INSERT_BEFORE(pkt, new, pkt_next);
181
0
                p += len;
182
0
            }
183
0
            seq += len;
184
0
        }
185
0
        TAILQ_REMOVE(pktq, pkt, pkt_next);
186
0
        pkt_free(pkt);
187
0
    }
188
0
    return (0);
189
0
}
190
191
struct mod mod_tcp_seg = {
192
        "tcp_seg",                  /* name */
193
        "tcp_seg <size> [old|new]", /* usage */
194
        tcp_seg_open,               /* open */
195
        tcp_seg_apply,              /* apply */
196
        tcp_seg_close               /* close */
197
};