Some minor fixes/adaptions. Somehow payload shows lots of Zeros --> Bug?
[netsniff-ng.git] / src / lib / rx_ring.c
blob4512c893092c866480c4566d704a4362c3d4f974
1 /* XXX: Coding Style - use the tool indent with the following (Linux kernel
2 * code indents)
4 * indent -nbad -bap -nbc -bbo -hnl -br -brs -c33 -cd33 -ncdb -ce -ci4 \
5 * -cli0 -d0 -di1 -nfc1 -i8 -ip0 -l80 -lp -npcs -nprs -npsl -sai \
6 * -saf -saw -ncs -nsc -sob -nfca -cp33 -ss -ts8 -il1
9 * netsniff-ng
11 * High performance network sniffer for packet inspection
13 * Copyright (C) 2009, 2010 Daniel Borkmann <danborkmann@googlemail.com>
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or (at
18 * your option) any later version.
20 * This program is distributed in the hope that it will be useful, but
21 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 * for more details.
25 * You should have received a copy of the GNU General Public License along
26 * with this program; if not, write to the Free Software Foundation, Inc.,
27 * 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
29 * Note: Your kernel has to be compiled with CONFIG_PACKET_MMAP=y option in
30 * order to use this.
34 * Contains:
35 * Mostly RX_RING related stuff and other networking code
38 #include <stdio.h>
39 #include <stdint.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <assert.h>
43 #include <errno.h>
44 #include <unistd.h>
46 #include <net/if.h>
47 #include <arpa/inet.h>
49 #include <sys/ioctl.h>
50 #include <sys/mman.h>
52 #include <linux/if_ether.h>
53 #include <linux/if_packet.h>
54 #include <linux/filter.h>
56 #include <netsniff-ng/macros.h>
57 #include <netsniff-ng/types.h>
58 #include <netsniff-ng/rx_ring.h>
60 /**
61 * destroy_virt_ring - Destroys virtual RX_RING buffer
62 * @sock: socket
63 * @rb: ring buffer
65 void destroy_virt_ring(int sock, ring_buff_t * rb)
67 assert(rb);
69 memset(&(rb->layout), 0, sizeof(rb->layout));
70 setsockopt(sock, SOL_PACKET, PACKET_RX_RING, (void *)&(rb->layout),
71 sizeof(rb->layout));
73 if (rb->buffer) {
74 munmap(rb, rb->len);
75 rb->buffer = 0;
76 rb->len = 0;
79 free(rb->frames);
82 /**
83 * create_virt_ring - Creates virtual RX_RING buffer
84 * @sock: socket
85 * @rb: ring buffer
87 void create_virt_ring(int sock, ring_buff_t * rb)
89 int ret;
91 assert(rb);
93 memset(&(rb->layout), 0, sizeof(rb->layout));
95 /* max: getpagesize() << 11 for i386 */
96 rb->layout.tp_block_size = getpagesize() << 2;
97 rb->layout.tp_frame_size = TPACKET_ALIGNMENT << 7;
99 /* max: 15 for i386 */
100 rb->layout.tp_block_nr = 1 << 13;
101 rb->layout.tp_frame_nr =
102 rb->layout.tp_block_size / rb->layout.tp_frame_size *
103 rb->layout.tp_block_nr;
105 __retry_sso:
106 ret = setsockopt(sock, SOL_PACKET, PACKET_RX_RING,
107 (void *)&(rb->layout), sizeof(rb->layout));
109 if (errno == ENOMEM && rb->layout.tp_block_nr > 1) {
110 rb->layout.tp_block_nr >>= 1;
111 rb->layout.tp_frame_nr =
112 rb->layout.tp_block_size / rb->layout.tp_frame_size *
113 rb->layout.tp_block_nr;
115 goto __retry_sso;
118 if (ret < 0) {
119 perr("setsockopt: creation of rx ring failed: %d - ", errno);
121 close(sock);
122 exit(EXIT_FAILURE);
125 rb->len = rb->layout.tp_block_size * rb->layout.tp_block_nr;
127 dbg("%.2f MB allocated for rx ring \n", 1.f * rb->len / (1024 * 1024));
128 dbg(" [ %d blocks, %d frames ] \n", rb->layout.tp_block_nr,
129 rb->layout.tp_frame_nr);
130 dbg(" [ %d frames per block ]\n",
131 rb->layout.tp_block_size / rb->layout.tp_frame_size);
132 dbg(" [ framesize: %d bytes, blocksize: %d bytes ]\n\n",
133 rb->layout.tp_frame_size, rb->layout.tp_block_size);
137 * mmap_virt_ring - Memory maps virtual RX_RING kernel buffer into userspace
138 * in order to avoid syscalls for fetching packet buffers
139 * @sock: socket
140 * @rb: ring buffer
142 void mmap_virt_ring(int sock, ring_buff_t * rb)
144 assert(rb);
146 rb->buffer = mmap(0, rb->len, PROT_READ | PROT_WRITE, MAP_SHARED, sock,
148 if (rb->buffer == MAP_FAILED) {
149 perr("mmap: cannot mmap the rx ring: %d - ", errno);
151 destroy_virt_ring(sock, rb);
152 close(sock);
154 exit(EXIT_FAILURE);
159 * bind_dev_to_ring - Binds virtual RX_RING to network device
160 * @sock: socket
161 * @ifindex: device number
162 * @rb: ring buffer
164 void bind_dev_to_ring(int sock, int ifindex, ring_buff_t * rb)
166 int ret;
168 assert(rb);
170 memset(&(rb->params), 0, sizeof(rb->params));
172 rb->params.sll_family = AF_PACKET;
173 rb->params.sll_protocol = htons(ETH_P_ALL);
174 rb->params.sll_ifindex = ifindex;
175 rb->params.sll_hatype = 0;
176 rb->params.sll_halen = 0;
177 rb->params.sll_pkttype = 0;
179 ret = bind(sock, (struct sockaddr *)&(rb->params),
180 sizeof(struct sockaddr_ll));
181 if (ret < 0) {
182 perr("bind: cannot bind device: %d - ", errno);
184 close(sock);
185 exit(EXIT_FAILURE);
190 * put_dev_into_promisc_mode - Puts network device into promiscuous mode
191 * @sock: socket
192 * @ifindex: device number
194 void put_dev_into_promisc_mode(int sock, int ifindex)
196 int ret;
197 struct packet_mreq mr;
199 memset(&mr, 0, sizeof(mr));
201 mr.mr_ifindex = ifindex;
202 mr.mr_type = PACKET_MR_PROMISC;
204 /* This is better than ioctl(), because the kernel now manages the
205 promisc flag for itself via internal counters. If the socket will
206 be closed the kernel decrements the counters automatically which
207 will not work with ioctl(). There, you have to manage things
208 manually ... */
210 ret = setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP,
211 &mr, sizeof(mr));
212 if (ret < 0) {
213 perr("setsockopt: cannot set dev %d to promisc mode: %d - ",
214 ifindex, errno);
216 close(sock);
217 exit(EXIT_FAILURE);
222 * inject_kernel_bpf - Binds filter code to socket
223 * @sock: socket
224 * @bpf: Berkeley Packet Filter code
225 * @len: length of bpf
227 void inject_kernel_bpf(int sock, struct sock_filter *bpf, int len)
229 int ret;
230 struct sock_fprog filter;
232 assert(bpf);
234 memset(&filter, 0, sizeof(filter));
236 filter.len = len / sizeof(struct sock_filter);
237 filter.filter = bpf;
239 ret = setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER,
240 &filter, sizeof(filter));
241 if (ret < 0) {
242 perr("setsockopt: filter cannot be injected: %d - ", errno);
244 close(sock);
245 exit(EXIT_FAILURE);
250 * ethdev_to_ifindex - Translates device name into device number
251 * @sock: socket
252 * @dev: device name
254 int ethdev_to_ifindex(int sock, char *dev)
256 int ret;
257 struct ifreq ethreq;
259 memset(&ethreq, 0, sizeof(ethreq));
260 strncpy(ethreq.ifr_name, dev, IFNAMSIZ);
262 ret = ioctl(sock, SIOCGIFINDEX, &ethreq);
263 if (ret < 0) {
264 perr("ioctl: cannot determine dev number for %s: %d - ",
265 ethreq.ifr_name, errno);
267 close(sock);
268 exit(EXIT_FAILURE);
271 return (ethreq.ifr_ifindex);
275 * net_stat - Grabs and prints current socket statistics
276 * @sock: socket
278 void net_stat(int sock)
280 int ret;
281 struct tpacket_stats kstats;
282 socklen_t slen = sizeof(kstats);
284 memset(&kstats, 0, sizeof(kstats));
286 ret = getsockopt(sock, SOL_PACKET, PACKET_STATISTICS, &kstats, &slen);
287 if (ret > -1) {
288 dbg("%d frames incoming\n", kstats.tp_packets);
289 dbg("%d frames passed filter\n",
290 kstats.tp_packets - kstats.tp_drops);
291 dbg("%d frames failed filter (due to out of space)\n",
292 kstats.tp_drops);
297 * alloc_pf_sock - Allocates a raw PF_PACKET socket
299 int alloc_pf_sock(void)
301 int sock = socket(PF_PACKET, SOCK_RAW, 0);
302 if (sock < 0) {
303 perr("alloc pf socket");
304 exit(EXIT_FAILURE);
307 return (sock);
311 * parse_rules - Parses a BPF rulefile
312 * @rulefile: path to rulefile
313 * @bpf: sock filter
314 * @len: len of bpf
316 void parse_rules(char *rulefile, struct sock_filter **bpf, int *len)
318 int ret;
319 uint32_t count;
320 char buff[128] = { 0 };
322 struct sock_filter sf_single;
324 assert(bpf);
326 FILE *fp = fopen(rulefile, "r");
327 if (!fp) {
328 perr("cannot read rulefile - ");
329 exit(EXIT_FAILURE);
332 dbg("parsing rulefile %s\n", rulefile);
334 count = 0;
335 while (fgets(buff, sizeof(buff), fp) != NULL) {
336 buff[sizeof(buff) - 1] = 0;
337 memset(&sf_single, 0, sizeof(sf_single));
339 ret = sscanf(buff, "{ 0x%x, %d, %d, 0x%08x },",
340 (unsigned int *)((void *)&(sf_single.code)),
341 (int *)((void *)&(sf_single.jt)),
342 (int *)((void *)&(sf_single.jf)), &(sf_single.k));
343 if (ret != 4) {
344 /* No valid bpf opcode format, might be a comment or
345 a syntax error */
346 continue;
349 *len += 1;
350 *bpf = (struct sock_filter *)realloc(*bpf,
351 *len * sizeof(sf_single));
353 memcpy(&(*bpf)[*len - 1], &sf_single, sizeof(sf_single));
355 dbg("line %d: { 0x%x, %d, %d, 0x%08x }\n", count++,
356 (*bpf)[*len - 1].code,
357 (*bpf)[*len - 1].jt,
358 (*bpf)[*len - 1].jf, (*bpf)[*len - 1].k);
361 dbg("\n");
362 fclose(fp);