Coverage Report

Created: 2026-01-16 07:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fuzzpcap/fuzz_pcap.c
Line
Count
Source
1
// Copyright (c) 2021 Catena cyber
2
// Author Philippe Antoine <p.antoine@catenacyber.fr>
3
4
#define _GNU_SOURCE
5
#include <stdint.h>
6
#include <stddef.h>
7
#include <string.h>
8
#include <stdlib.h>
9
10
#include <pcap/pcap.h>
11
12
#include "fuzz_pcap.h"
13
14
47.1k
int FPC_IsFuzzPacketCapture(const uint8_t *Data, size_t Size) {
15
47.1k
    if (Size < FPC0_HEADER_LEN) {
16
2
        return 0;
17
2
    }
18
47.1k
    if (memcmp(Data, FPC0_MAGIC, FPC0_MAGIC_LEN - 1) != 0) {
19
28
        return 0;
20
28
    }
21
47.0k
    if (FPC_datalink_to(Data[FPC0_MAGIC_LEN-1] & 0x7F) == FPC_DATALINK_ERROR) {
22
1
        return 0;
23
1
    }
24
47.0k
    return 1;
25
47.0k
}
26
27
94.1k
uint32_t FPC_datalink_to(uint8_t in) {
28
94.1k
    if (in == DLT_NULL || in == DLT_EN10MB) {
29
94.1k
        return in;
30
94.1k
    }
31
1
    return (uint32_t) FPC_DATALINK_ERROR;
32
94.1k
}
33
34
0
uint8_t FPC_datalink_from(uint32_t in) {
35
0
    if (in == DLT_NULL || in == DLT_EN10MB) {
36
0
        return in;
37
0
    }
38
0
    return FPC_DATALINK_ERROR;
39
0
}
40
41
47.1k
int FPC_init(FPC_buffer_t *r, const uint8_t *Data, size_t Size) {
42
47.1k
    if (!FPC_IsFuzzPacketCapture(Data, Size)) {
43
31
        return -1;
44
31
    }
45
47.0k
    r->Data = Data;
46
47.0k
    r->Size = Size;
47
47.0k
    r->datalink = FPC_datalink_to(Data[FPC0_MAGIC_LEN-1] & 0x7F);
48
47.0k
    r->tcpSingleStream = (Data[FPC0_MAGIC_LEN-1] & 0x80);
49
47.0k
    if (r->tcpSingleStream) {
50
23.0k
        r->offset = FPC0_HEADER_LEN;
51
24.0k
    } else {
52
24.0k
        r->offset = FPC0_MAGIC_LEN;
53
24.0k
    }
54
47.0k
    memset(r->pkt, 0, FPC_SNAPLEN);
55
47.0k
    r->tcpState = FPC_TCP_STATE_START;
56
47.0k
    r->seqCliAckSrv = 0x10000000;
57
47.0k
    r->seqSrvAckCli = 0x20000000;
58
47.0k
    r->nb = 0;
59
47.0k
    return 0;
60
47.1k
}
61
62
45.8k
#define FPC_TCP_FLAG_SYN 0x02
63
7.26M
#define FPC_TCP_FLAG_ACK 0x10
64
68.8k
#define FPC_TCP_FLAGS_NEG_OFFSET 7
65
66
7.24M
#define FPC_NULL_HEADER "\x02\x00\x00\x00"
67
14.4M
#define FPC_NULL_HEADER_LEN 4
68
69
16.0k
#define FPC_ETH_HEADER "\x00\x01\x02\x03\x04\x05\x00\x01\x02\x03\x04\x05\x08\x00"
70
32.0k
#define FPC_ETH_HEADER_LEN 14
71
72
7.26M
#define FPC_IP4_HEADER "\x45\x00\xff\xff\x00\x00\x40\x00\x40\x06\x00\x00\x7f\x00\x00\x01" \
73
7.26M
"\x7f\x00\x00\x01"
74
29.0M
#define FPC_IP4_HEADER_LEN 20
75
76
7.26M
#define FPC_TCP_HEADER_END "\xFF\xFF\x00\x00\x00\x00"
77
14.5M
#define FPC_TCP_HEADER_END_LEN 6
78
79
7.26M
static bpf_u_int32 buildTCPpacket(FPC_buffer_t *pkts, bool s2c, size_t plen) {
80
7.26M
    bpf_u_int32 r = 0;
81
7.26M
    if (pkts->datalink == DLT_NULL) {
82
7.24M
        memcpy(pkts->pkt, FPC_NULL_HEADER, FPC_NULL_HEADER_LEN);
83
7.24M
        r = FPC_NULL_HEADER_LEN;
84
7.24M
    } else if (pkts->datalink == DLT_EN10MB) {
85
16.0k
        memcpy(pkts->pkt, FPC_ETH_HEADER, FPC_ETH_HEADER_LEN);
86
16.0k
        r = FPC_ETH_HEADER_LEN;
87
16.0k
    } else {
88
        //unreachable
89
0
        abort();
90
0
    }
91
7.26M
    memcpy(pkts->pkt+r, FPC_IP4_HEADER, FPC_IP4_HEADER_LEN);
92
7.26M
    pkts->pkt[r+2] = (plen + FPC_IP4_HEADER_LEN + 20) >> 8;
93
7.26M
    pkts->pkt[r+3] = (plen + FPC_IP4_HEADER_LEN+ 20);
94
7.26M
    r += FPC_IP4_HEADER_LEN;
95
    //ports
96
7.26M
    if (s2c) {
97
3.55M
        memcpy(pkts->pkt+r, pkts->Data+FPC0_MAGIC_LEN, 2);
98
3.55M
        memcpy(pkts->pkt+r+2, pkts->Data+FPC0_MAGIC_LEN+2, 2);
99
3.55M
        pkts->pkt[r+4] = pkts->seqSrvAckCli >> 24;
100
3.55M
        pkts->pkt[r+5] = pkts->seqSrvAckCli >> 16;
101
3.55M
        pkts->pkt[r+6] = pkts->seqSrvAckCli >> 8;
102
3.55M
        pkts->pkt[r+7] = pkts->seqSrvAckCli;
103
3.55M
        pkts->pkt[r+8] = pkts->seqCliAckSrv >> 24;
104
3.55M
        pkts->pkt[r+9] = pkts->seqCliAckSrv >> 16;
105
3.55M
        pkts->pkt[r+10] = pkts->seqCliAckSrv >> 8;
106
3.55M
        pkts->pkt[r+11] = pkts->seqCliAckSrv;
107
3.71M
    } else {
108
3.71M
        memcpy(pkts->pkt+r, pkts->Data+FPC0_MAGIC_LEN+2, 2);
109
3.71M
        memcpy(pkts->pkt+r+2, pkts->Data+FPC0_MAGIC_LEN, 2);
110
3.71M
        pkts->pkt[r+4] = pkts->seqCliAckSrv >> 24;
111
3.71M
        pkts->pkt[r+5] = pkts->seqCliAckSrv >> 16;
112
3.71M
        pkts->pkt[r+6] = pkts->seqCliAckSrv >> 8;
113
3.71M
        pkts->pkt[r+7] = pkts->seqCliAckSrv;
114
3.71M
        if (pkts->tcpState != FPC_TCP_STATE_SYN) {
115
3.68M
            pkts->pkt[r+8] = pkts->seqSrvAckCli >> 24;
116
3.68M
            pkts->pkt[r+9] = pkts->seqSrvAckCli >> 16;
117
3.68M
            pkts->pkt[r+10] = pkts->seqSrvAckCli >> 8;
118
3.68M
            pkts->pkt[r+11] = pkts->seqSrvAckCli;
119
3.68M
        }
120
3.71M
    }
121
7.26M
    r += 12;
122
7.26M
    pkts->pkt[r] = 0x50; // TCP length
123
7.26M
    if (pkts->tcpState == FPC_TCP_STATE_ESTABLISHED) {
124
7.21M
        pkts->pkt[r+1] = FPC_TCP_FLAG_ACK; // flags
125
7.21M
    } else {
126
45.8k
        pkts->pkt[r+1] = 0; // flags
127
45.8k
    }
128
7.26M
    r+=2;
129
7.26M
    memcpy(pkts->pkt+r, FPC_TCP_HEADER_END, FPC_TCP_HEADER_END_LEN);
130
7.26M
    r+=FPC_TCP_HEADER_END_LEN;
131
7.26M
    return r;
132
7.26M
}
133
134
7.26M
#define FCP_BASE_TIME 0x601cf51a
135
136
9.12M
int FPC_next_pcap(FPC_buffer_t *pkts, struct pcap_pkthdr *header, const uint8_t **pkt) {
137
9.12M
    *pkt = pkts->Data + pkts->offset + FPC_TS_MAXSIZE;
138
9.12M
    const uint8_t *next = memmem(pkts->Data + pkts->offset, pkts->Size - pkts->offset, FPC0_MAGIC, FPC0_MAGIC_LEN);
139
9.12M
    if (next == NULL) {
140
19.2k
        next = pkts->Data + pkts->Size;
141
19.2k
    }
142
9.12M
    if (next < *pkt) {
143
        //wrong input
144
2.78k
        return -1;
145
2.78k
    }
146
147
9.12M
    memset(header, 0, sizeof(struct pcap_pkthdr));
148
9.12M
    header->ts.tv_sec = *((time_t *) (pkts->Data + pkts->offset));
149
9.12M
    if (header->ts.tv_sec < 0) {
150
842k
        header->ts.tv_sec = 0;
151
842k
    }
152
9.12M
    header->ts.tv_usec = *((suseconds_t *) (pkts->Data + pkts->offset + FPC_TS_MAXSIZE/2));
153
    // Limit microseconds to 1 million
154
9.12M
    header->ts.tv_usec = ((header->ts.tv_usec % 1000000) + 1000000) % 1000000;
155
9.12M
    header->caplen = next - (*pkt);
156
9.12M
    pkts->offset += header->caplen + FPC_TS_MAXSIZE + FPC0_MAGIC_LEN;
157
9.12M
    header->len = header->caplen;
158
9.12M
    return 1;
159
9.12M
}
160
161
7.26M
int FPC_next_tcp(FPC_buffer_t *pkts, struct pcap_pkthdr *header, const uint8_t **pkt) {
162
7.26M
    *pkt = pkts->Data + pkts->offset;
163
7.26M
    const uint8_t *next = memmem(pkts->Data + pkts->offset, pkts->Size - pkts->offset, FPC0_MAGIC, FPC0_MAGIC_LEN);
164
7.26M
    if (next == NULL) {
165
26.5k
        next = pkts->Data + pkts->Size;
166
26.5k
    }
167
7.26M
    if (next < *pkt) {
168
        //wrong input
169
0
        return -1;
170
0
    }
171
172
7.26M
    memset(header, 0, sizeof(struct pcap_pkthdr));
173
7.26M
    header->ts.tv_sec = FCP_BASE_TIME;
174
7.26M
    header->ts.tv_usec = pkts->nb;
175
7.26M
    pkts->nb++;
176
7.26M
    header->caplen = next - (*pkt);
177
178
7.26M
    if (pkts->tcpState > FPC_TCP_STATE_SYNACK) {
179
7.19M
        pkts->offset += header->caplen + FPC0_MAGIC_LEN;
180
7.19M
    }
181
7.26M
    switch (pkts->tcpState) {
182
22.9k
        case FPC_TCP_STATE_START:
183
22.9k
        pkts->tcpState = FPC_TCP_STATE_SYN;
184
22.9k
        header->caplen = buildTCPpacket(pkts, false, 0);
185
22.9k
        *pkt = pkts->pkt;
186
22.9k
        pkts->pkt[header->caplen-FPC_TCP_FLAGS_NEG_OFFSET] |= FPC_TCP_FLAG_SYN;
187
22.9k
        pkts->seqCliAckSrv++;
188
22.9k
        break;
189
190
22.9k
        case FPC_TCP_STATE_SYN:
191
22.9k
        pkts->tcpState = FPC_TCP_STATE_SYNACK;
192
22.9k
        header->caplen = buildTCPpacket(pkts, true, 0);
193
22.9k
        *pkt = pkts->pkt;
194
22.9k
        pkts->pkt[header->caplen-FPC_TCP_FLAGS_NEG_OFFSET] |= FPC_TCP_FLAG_SYN | FPC_TCP_FLAG_ACK;
195
22.9k
        pkts->seqSrvAckCli++;
196
22.9k
        break;
197
198
22.9k
        case FPC_TCP_STATE_SYNACK:
199
22.9k
        pkts->tcpState = FPC_TCP_STATE_ESTABLISHED;
200
22.9k
        header->caplen = buildTCPpacket(pkts, false, 0);
201
22.9k
        *pkt = pkts->pkt;
202
22.9k
        pkts->pkt[header->caplen-FPC_TCP_FLAGS_NEG_OFFSET] |= FPC_TCP_FLAG_ACK;
203
22.9k
        break;
204
205
7.19M
        case FPC_TCP_STATE_ESTABLISHED:
206
7.19M
        if (header->caplen < 1) {
207
79
            return -1;
208
79
        }
209
7.19M
        header->caplen--;
210
7.19M
        bool s2c = (*pkt[0]) & 1;
211
7.19M
        header->len = buildTCPpacket(pkts, s2c, header->caplen);
212
7.19M
        if (header->caplen + header->len > FPC_SNAPLEN) {
213
630
            header->caplen = FPC_SNAPLEN - header->len;
214
630
        }
215
7.19M
        memcpy(pkts->pkt+header->len, *pkt+1, header->caplen);
216
7.19M
        if (s2c) {
217
3.52M
            pkts->seqSrvAckCli += header->caplen;
218
3.66M
        } else {
219
3.66M
            pkts->seqCliAckSrv += header->caplen;
220
3.66M
        }
221
7.19M
        header->caplen += header->len;
222
7.19M
        *pkt = pkts->pkt;
223
7.19M
        break;
224
7.26M
    }
225
7.26M
    header->len = header->caplen;
226
7.26M
    return 1;
227
7.26M
}
228
229
16.4M
int FPC_next(FPC_buffer_t *pkts, struct pcap_pkthdr *header, const uint8_t **pkt) {
230
16.4M
    if (pkts->offset >= pkts->Size) {
231
40.5k
        return 0;
232
40.5k
    }
233
234
16.3M
    if (pkts->tcpSingleStream) {
235
7.26M
        return FPC_next_tcp(pkts, header, pkt);
236
7.26M
    } //else
237
9.12M
    return FPC_next_pcap(pkts, header, pkt);
238
16.3M
}