netsniff-ng: pcap: fix multi-file dump with dropped privs
[netsniff-ng.git] / src / pcap_sg.c
blobf49b032b5351101a56328d700a03ec39a62bbceb
1 /*
2 * netsniff-ng - the packet sniffing beast
3 * By Daniel Borkmann <daniel@netsniff-ng.org>
4 * Copyright 2011 Daniel Borkmann.
5 * Subject to the GPL, version 2.
6 */
8 #include <stdio.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <sys/uio.h>
13 #include <unistd.h>
15 #include "pcap.h"
16 #include "xmalloc.h"
17 #include "xio.h"
18 #include "xutils.h"
19 #include "locking.h"
20 #include "built_in.h"
22 #define IOVSIZ 1000
23 #define ALLSIZ (PAGE_SIZE * 3)
24 #define ALLSIZ_2K (PAGE_SIZE * 3) // 12K max
25 #define ALLSIZ_JUMBO (PAGE_SIZE * 16) // 64K max
27 static struct iovec iov[IOVSIZ];
28 static unsigned long c = 0;
29 static struct spinlock lock;
30 static ssize_t iov_used;
32 static int pcap_sg_pull_file_header(int fd, uint32_t *linktype)
34 ssize_t ret;
35 struct pcap_filehdr hdr;
37 ret = read(fd, &hdr, sizeof(hdr));
38 if (unlikely(ret != sizeof(hdr)))
39 return -EIO;
41 pcap_validate_header(&hdr);
43 *linktype = hdr.linktype;
45 return 0;
48 static int pcap_sg_push_file_header(int fd, uint32_t linktype)
50 ssize_t ret;
51 struct pcap_filehdr hdr;
53 fmemset(&hdr, 0, sizeof(hdr));
54 pcap_prepare_header(&hdr, linktype, 0, PCAP_DEFAULT_SNAPSHOT_LEN);
56 ret = write_or_die(fd, &hdr, sizeof(hdr));
57 if (unlikely(ret != sizeof(hdr))) {
58 whine("Failed to write pkt file header!\n");
59 return -EIO;
62 return 0;
65 static ssize_t pcap_sg_write_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
66 uint8_t *packet, size_t len)
68 ssize_t ret;
70 spinlock_lock(&lock);
72 if (unlikely(c == IOVSIZ)) {
73 ret = writev(fd, iov, IOVSIZ);
74 if (ret < 0)
75 panic("writev I/O error!\n");
77 c = 0;
80 iov[c].iov_len = 0;
81 fmemcpy(iov[c].iov_base, hdr, sizeof(*hdr));
83 iov[c].iov_len += sizeof(*hdr);
84 fmemcpy(iov[c].iov_base + iov[c].iov_len, packet, len);
86 iov[c].iov_len += len;
87 ret = iov[c].iov_len;
89 c++;
91 spinlock_unlock(&lock);
93 return ret;
96 static int pcap_sg_prepare_reading_pcap(int fd)
98 spinlock_lock(&lock);
99 if (readv(fd, iov, IOVSIZ) <= 0)
100 return -EIO;
102 iov_used = 0;
103 c = 0;
104 spinlock_unlock(&lock);
106 return 0;
109 static ssize_t pcap_sg_read_pcap_pkt(int fd, struct pcap_pkthdr *hdr,
110 uint8_t *packet, size_t len)
112 ssize_t ret = 0;
114 /* In contrast to writing, reading gets really ugly ... */
115 spinlock_lock(&lock);
117 if (likely(iov[c].iov_len - iov_used >= sizeof(*hdr))) {
118 fmemcpy(hdr, iov[c].iov_base + iov_used, sizeof(*hdr));
119 iov_used += sizeof(*hdr);
120 } else {
121 size_t offset = 0;
122 ssize_t remainder;
124 offset = iov[c].iov_len - iov_used;
125 remainder = sizeof(*hdr) - offset;
126 if (remainder < 0)
127 remainder = 0;
129 bug_on(offset + remainder != sizeof(*hdr));
131 fmemcpy(hdr, iov[c].iov_base + iov_used, offset);
133 iov_used = 0;
134 c++;
136 if (c == IOVSIZ) {
137 /* We need to refetch! */
138 c = 0;
139 if (readv(fd, iov, IOVSIZ) <= 0) {
140 ret = -EIO;
141 goto out_err;
145 /* Now we copy the remainder and go on with business ... */
146 fmemcpy((uint8_t *) hdr + offset,
147 iov[c].iov_base + iov_used, remainder);
148 iov_used += remainder;
151 /* header read completed */
153 if (unlikely(hdr->caplen == 0 || hdr->caplen > len)) {
154 ret = -EINVAL; /* Bogus packet */
155 goto out_err;
158 /* now we read data ... */
160 if (likely(iov[c].iov_len - iov_used >= hdr->caplen)) {
161 fmemcpy(packet, iov[c].iov_base + iov_used, hdr->caplen);
162 iov_used += hdr->caplen;
163 } else {
164 size_t offset = 0;
165 ssize_t remainder;
167 offset = iov[c].iov_len - iov_used;
168 remainder = hdr->caplen - offset;
169 if (remainder < 0)
170 remainder = 0;
172 bug_on(offset + remainder != hdr->caplen);
174 fmemcpy(packet, iov[c].iov_base + iov_used, offset);
176 iov_used = 0;
177 c++;
179 if (c == IOVSIZ) {
180 /* We need to refetch! */
181 c = 0;
182 if (readv(fd, iov, IOVSIZ) <= 0) {
183 ret = -EIO;
184 goto out_err;
188 /* Now we copy the remainder and go on with business ... */
189 fmemcpy(packet + offset, iov[c].iov_base + iov_used, remainder);
190 iov_used += remainder;
193 spinlock_unlock(&lock);
195 return sizeof(*hdr) + hdr->caplen;
197 out_err:
198 spinlock_unlock(&lock);
199 return ret;
202 static void pcap_sg_fsync_pcap(int fd)
204 ssize_t ret;
206 spinlock_lock(&lock);
207 ret = writev(fd, iov, c);
208 if (ret < 0)
209 panic("writev I/O error!\n");
211 c = 0;
213 fdatasync(fd);
214 spinlock_unlock(&lock);
217 const struct pcap_file_ops pcap_sg_ops = {
218 .name = "scatter-gather",
219 .pull_file_header = pcap_sg_pull_file_header,
220 .push_file_header = pcap_sg_push_file_header,
221 .write_pcap_pkt = pcap_sg_write_pcap_pkt,
222 .prepare_reading_pcap = pcap_sg_prepare_reading_pcap,
223 .read_pcap_pkt = pcap_sg_read_pcap_pkt,
224 .fsync_pcap = pcap_sg_fsync_pcap,
227 int init_pcap_sg(int jumbo_support)
229 unsigned long i;
230 size_t allocsz = 0;
232 c = 0;
234 fmemset(iov, 0, sizeof(iov));
236 if (jumbo_support)
237 allocsz = ALLSIZ_JUMBO;
238 else
239 allocsz = ALLSIZ_2K;
241 for (i = 0; i < IOVSIZ; ++i) {
242 iov[i].iov_base = xzmalloc_aligned(allocsz, 64);
243 iov[i].iov_len = allocsz;
246 spinlock_init(&lock);
248 set_ioprio_rt();
250 return pcap_ops_group_register(&pcap_sg_ops, PCAP_OPS_SG);
253 void cleanup_pcap_sg(void)
255 unsigned long i;
257 spinlock_destroy(&lock);
259 for (i = 0; i < IOVSIZ; ++i)
260 xfree(iov[i].iov_base);
262 pcap_ops_group_unregister(PCAP_OPS_SG);