Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/tests/sys/net/bpf/pcap-test.c
96309 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2025 Gleb Smirnoff <[email protected]>
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. Redistributions in binary form must reproduce the above copyright
12
* notice, this list of conditions and the following disclaimer in the
13
* documentation and/or other materials provided with the distribution.
14
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*
27
*/
28
29
#include <sys/param.h>
30
#include <sys/queue.h>
31
#include <netinet/ip.h>
32
#include <pcap/pcap.h>
33
#include <fcntl.h>
34
#include <unistd.h>
35
#include <stdlib.h>
36
#include <string.h>
37
#include <strings.h>
38
#include <err.h>
39
40
static int
41
strtolerr(const char *s)
42
{
43
int rv;
44
45
if ((rv = (int)strtol(s, NULL, 10)) < 1)
46
errx(1, "bad count %s", s);
47
return (rv);
48
}
49
50
static pcap_direction_t
51
strtodir(const char *s)
52
{
53
static const struct dirstr {
54
const char *str;
55
pcap_direction_t dir;
56
} dirs[] = {
57
{ "in", PCAP_D_IN },
58
{ "out", PCAP_D_OUT },
59
{ "both", PCAP_D_INOUT },
60
{ "inout", PCAP_D_INOUT },
61
};
62
63
for (u_int i = 0; i < nitems(dirs); i++)
64
if (strcasecmp(s, dirs[i].str) == 0)
65
return (dirs[i].dir);
66
errx(1, "bad directions %s", s);
67
}
68
69
static char errbuf[PCAP_ERRBUF_SIZE];
70
71
static pcap_t *
72
pcap_open(const char *name, pcap_direction_t dir)
73
{
74
pcap_t *p;
75
76
if ((p = pcap_create(name, errbuf)) == NULL)
77
errx(1, "pcap_create: %s", errbuf);
78
if (pcap_set_timeout(p, 10) != 0)
79
errx(1, "pcap_set_timeout: %s", pcap_geterr(p));
80
if (pcap_activate(p) != 0)
81
errx(1, "pcap_activate: %s", errbuf);
82
if (pcap_setdirection(p, dir) != 0)
83
errx(1, "pcap_setdirection: %s", pcap_geterr(p));
84
return (p);
85
}
86
87
#if 0
88
/*
89
* Deal with the FreeBSD writer only optimization hack in bpf(4).
90
* Needed only when net.bpf.optimize_writers=1.
91
*/
92
static pcap_t *
93
pcap_rwopen(const char *name, pcap_direction_t dir)
94
{
95
pcap_t *p;
96
struct bpf_program fp;
97
98
p = pcap_open(name, dir);
99
if (pcap_compile(p, &fp, "", 0, PCAP_NETMASK_UNKNOWN) != 0)
100
errx(1, "pcap_compile: %s", pcap_geterr(p));
101
if (pcap_setfilter(p, &fp) != 0)
102
errx(1, "pcap_setfilter: %s", pcap_geterr(p));
103
pcap_freecode(&fp);
104
return (p);
105
}
106
#endif
107
108
static void
109
list(int argc __unused, char *argv[] __unused)
110
{
111
pcap_if_t *all, *p;
112
113
if (pcap_findalldevs(&all, errbuf) != 0)
114
errx(1, "pcap_findalldevs: %s", errbuf);
115
for (p = all; p != NULL; p = p->next)
116
printf("%s ", p->name);
117
printf("\n");
118
pcap_freealldevs(all);
119
}
120
121
/* args: tap file count direction */
122
static void
123
capture(int argc __unused, char *argv[])
124
{
125
pcap_t *p;
126
pcap_dumper_t *d;
127
pcap_direction_t dir;
128
int cnt;
129
130
cnt = strtolerr(argv[2]);
131
dir = strtodir(argv[3]);
132
p = pcap_open(argv[0], dir);
133
134
if ((d = pcap_dump_open(p, argv[1])) == NULL)
135
errx(1, "pcap_dump_open: %s", pcap_geterr(p));
136
137
if (pcap_loop(p, cnt, pcap_dump, (u_char *)d) != 0)
138
errx(1, "pcap_loop: %s", pcap_geterr(p));
139
pcap_dump_close(d);
140
}
141
142
static void
143
inject_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
144
{
145
pcap_t *p = (pcap_t *)user;
146
147
if (h->caplen != h->len)
148
errx(1, "incomplete packet %u of %u", h->caplen, h->len);
149
150
if (pcap_inject(p, bytes, h->caplen) != (int)h->caplen)
151
errx(1, "pcap_inject: %s", errbuf);
152
}
153
154
/* args: tap file count */
155
static void
156
inject(int argc __unused, char *argv[])
157
{
158
pcap_t *p, *d;
159
int cnt;
160
161
cnt = strtolerr(argv[2]);
162
p = pcap_open(argv[0], PCAP_D_INOUT);
163
164
if ((d = pcap_open_offline(argv[1], errbuf)) == NULL)
165
errx(1, "pcap_open_offline: %s", errbuf);
166
if (pcap_loop(d, cnt, inject_packet, (u_char *)p) != 0)
167
errx(1, "pcap_loop: %s", pcap_geterr(p));
168
pcap_close(p);
169
pcap_close(d);
170
}
171
172
struct packet {
173
STAILQ_ENTRY(packet) next;
174
const void *data;
175
u_int caplen;
176
u_int len;
177
};
178
STAILQ_HEAD(plist, packet);
179
180
static void
181
store_packet(u_char *user, const struct pcap_pkthdr *h, const u_char *bytes)
182
{
183
struct plist *list = (struct plist *)user;
184
struct packet *p;
185
186
p = malloc(sizeof(*p));
187
p->data = bytes;
188
p->caplen = h->caplen;
189
p->len = h->len;
190
STAILQ_INSERT_TAIL(list, p, next);
191
}
192
193
/* args: file1 file2 */
194
static void
195
compare(int argc __unused, char *argv[])
196
{
197
pcap_t *f1, *f2;
198
struct plist
199
list1 = STAILQ_HEAD_INITIALIZER(list1),
200
list2 = STAILQ_HEAD_INITIALIZER(list2);
201
struct packet *p1, *p2;
202
u_int cnt;
203
204
if ((f1 = pcap_open_offline(argv[0], errbuf)) == NULL)
205
errx(1, "pcap_open_offline: %s", errbuf);
206
if (pcap_loop(f1, 0, store_packet, (u_char *)&list1) != 0)
207
errx(1, "pcap_loop: %s", pcap_geterr(f1));
208
if ((f2 = pcap_open_offline(argv[1], errbuf)) == NULL)
209
errx(1, "pcap_open_offline: %s", errbuf);
210
if (pcap_loop(f2, 0, store_packet, (u_char *)&list2) != 0)
211
errx(1, "pcap_loop: %s", pcap_geterr(f2));
212
213
for (p1 = STAILQ_FIRST(&list1), p2 = STAILQ_FIRST(&list2), cnt = 1;
214
p1 != NULL && p2 != NULL;
215
p1 = STAILQ_NEXT(p1, next), p2 = STAILQ_NEXT(p2, next), cnt++) {
216
if (p1->len != p2->len)
217
errx(1, "packet #%u length %u != %u",
218
cnt, p1->len, p2->len);
219
if (p1->caplen != p2->caplen)
220
errx(1, "packet #%u capture length %u != %u",
221
cnt, p1->caplen, p2->caplen);
222
if (memcmp(p1->data, p2->data, p1->caplen) != 0)
223
errx(1, "packet #%u payload different", cnt);
224
}
225
if (p1 != NULL || p2 != NULL)
226
errx(1, "packet count different");
227
228
pcap_close(f1);
229
pcap_close(f2);
230
}
231
232
static const struct cmd {
233
const char *cmd;
234
void (*func)(int, char **);
235
u_int argc;
236
} cmds[] = {
237
{ .cmd = "list", .func = list, .argc = 0 },
238
{ .cmd = "inject", .func = inject, .argc = 3 },
239
{ .cmd = "capture", .func = capture,.argc = 4 },
240
{ .cmd = "compare", .func = compare,.argc = 2 },
241
};
242
243
int
244
main(int argc, char *argv[])
245
{
246
247
if (argc < 2) {
248
fprintf(stderr, "Usage: %s ", argv[0]);
249
for (u_int i = 0; i < nitems(cmds); i++)
250
fprintf(stderr, "%s%s", cmds[i].cmd,
251
i != nitems(cmds) - 1 ? "|" : "\n");
252
exit(1);
253
}
254
255
for (u_int i = 0; i < nitems(cmds); i++)
256
if (strcasecmp(argv[1], cmds[i].cmd) == 0) {
257
argc -= 2;
258
argv += 2;
259
if (argc < (int)cmds[i].argc)
260
errx(1, "%s takes %u args",
261
cmds[i].cmd, cmds[i].argc);
262
cmds[i].func(argc, argv);
263
return (0);
264
}
265
266
warnx("Unknown command %s\n", argv[1]);
267
return (1);
268
}
269
270