Parsing packets from BPF
Web Server forum
Back To The Forum Home!Search!Private Messaging System

Web Server Talk Web Server Talk > Unix and Linux reviews > Free Unix support > Unix Programming > Parsing packets from BPF




  Last Thread   Next Thread Next
  Show Printable Version Email this Page Subscribe to this Thread      Post New Thread    Post A Reply      

    Parsing packets from BPF  
chris


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
06-26-04 03:11 PM

I can now capture packets via the BPF so I need to begin parsing them.

Do I do something like this?

struct bpfhdr *bpfHdr;
struct iphdr *ipHdr;

read(bpf, buf, len)
bpfHdr = (struct bpfhdr *) buf;
ipHdr = (struct ipHdr *) buf + bpfHdr->bh_hdrlen;






[ Post a follow-up to this message ]



    Re: Parsing packets from BPF  
Lev Walkin


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
06-26-04 03:11 PM

chris wrote:
> I can now capture packets via the BPF so I need to begin parsing them.
>
> Do I do something like this?
>
> struct bpfhdr *bpfHdr;
> struct iphdr *ipHdr;
>
> read(bpf, buf, len)
> bpfHdr = (struct bpfhdr *) buf;
> ipHdr = (struct ipHdr *) buf + bpfHdr->bh_hdrlen;


/* Read data */
read_len = read(bpf_fd, ps->buf, ps->buf_size);

/* Process data */
for(packet = ps->buf; (packet - ps->buf) < read_len;
packet += BPF_WORDALIGN(bpf_header->bh_hdrlen
+ bpf_header->bh_caplen) )
{
void *packet_start = packet + bpf_header->bh_hdrlen;
int toend_size = rd-((char *)ip_start-(char *)ps->buf);
int captured_size = bpf_header->bh_caplen;
if(toend_size < captured_size)  /* Paranoya */
captured_size = toend_size;

process_packet(packet_start, captured_size);
}


--
Lev Walkin
vlm@lionet.info





[ Post a follow-up to this message ]



    Re: Parsing packets from BPF  
chris


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
06-27-04 03:38 AM

Lev Walkin wrote:

> chris wrote:
> 
>
>
>
>     /* Read data */
>     read_len = read(bpf_fd, ps->buf, ps->buf_size);
>
>         /* Process data */
>         for(packet = ps->buf; (packet - ps->buf) < read_len;
>                   packet += BPF_WORDALIGN(bpf_header->bh_hdrlen
>                           + bpf_header->bh_caplen) )
>         {
>                 void *packet_start = packet + bpf_header->bh_hdrlen;
>                 int toend_size = rd-((char *)ip_start-(char *)ps->buf);
>                 int captured_size = bpf_header->bh_caplen;
>                 if(toend_size < captured_size)  /* Paranoya */
>                         captured_size = toend_size;
>
>         process_packet(packet_start, captured_size);
>         }
>
>

Thanks for the code, I just have a few questions: How come bpf_header is
never incremented? Isn't there a bpfhdr for each packet (since there
can be more than one packet per read())? Could you also explain the
toend_size stuff?

Thanks again.





[ Post a follow-up to this message ]



    Re: Parsing packets from BPF  
Lev Walkin


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
06-28-04 01:59 PM

chris wrote:
> Lev Walkin wrote:
> 
>
> Thanks for the code, I just have a few questions: How come bpf_header is
>  never incremented?

I wanted it to be our little secret ;)

#define bpf_header      ((struct bpf_hdr *)packet)

> Isn't there a bpfhdr for each packet (since there
> can be more than one packet per read())? Could you also explain the
> toend_size stuff?

The BPF user supplies the buffer reasonably big to accomodate several
packets. The kernel has similar buffer too.

Ideally, a kernel would never add another packet into its own buffer,
when there isn't enough space for the whole packet. It would just
drop the packet.

In addition to that, it would be ideal if the userspace buffer is
equal or bigger than the kernel buffer.

Given these two conditions, it is clear to see that the simple loop
over buffer's contents is completely safe:

for(packet = ps->buf; (packet - ps->buf) < read_len;
packet += BPF_WORALIGN(
((struct bpf_header *)packet)->bh_hdrlen
+ ((struct bpf_header *)packet)->bh_caplen) ) {
/*
* Please note that a packet pointer here points
* to the packet completely contained within
* the allocated buffer.
*/
}

However, unless these conditions are met (i.e., kernel does not throw
away packet when it can't be fully accomodated by the free kernel buffer
space, or the user-level buffer size is less than the kernel-buffer one),
there is no trust for the (packet) pointer. It can point to the start
of the packet which is not completely contained within the buffer space.
So, if one would want to print the packet contents, a buffer overrun
may occur.

For example, let's take an example of the kernel buffer larger than
the user space one:

Kernel buffer:
[packet-1][packet-2][packet-3][some-free-space]<END OF BUFFE
R>
User-space buffer:
[packet-1][packet-2][pack<END OF BUFFER>

Although kernel is presumably cautious as to not to put packet-4 into
its own buffer because the free space is too short for packet-4, the
user-space buffer will be filled UP TO the
MIN(kernel-buffer-useful-content-size, user-space-buffer-size).
When user-space-buffer-size is less than kernel-buffer-useful-content-size,
as shown above, the for() loop will yield a (packet) pointer pointing
to the start of packet-3. It is clear that the user space buffer does not
contain the whole packet.

It should be obvious by now that inside the for() loop one should check
that the end of packet is contained within the buffer. Hence, the
"toend_size" usage. That variable holds the amount of space between
the current start-of-a-packet pointer and the end of the allocated
buffer space (or the minimum between the allocated buffer space and
the number of bytes available in that buffer, {read_len|rd}, as shown
in the original example).

It should also be obvious, that I've made a mistake there by not checking
if the "bpf_header->bh_caplen" is fully contained inside the buffer space
in the first place. The correct loop would look like this:

#define bpf_header      ((struct bpf_hdr *)packet)
size_t buf_size = ...;
char buffer[buf_size];
char *packet;
char *safe_end_of_data;
ssize_t read_len;

/* Read data */
read_len = read(bpf_fd, buffer, buf_size);

/* Make sure there is at least one complete bpf header */
safe_end_of_data = buffer + (read_len - sizeof(struct bpf_hdr));

/* Process data */
for(packet = buffer; packet < safe_end_of_data;
packet += BPF_WORDALIGN(bpf_header->bh_hdrlen
+ bpf_header->bh_caplen) )
{
void *packet_start = packet + bpf_header->bh_hdrlen;
int toend_size = read_len - (packet - buffer);
int captured_size = bpf_header->bh_caplen;

if(toend_size < captured_size)  /* Paranoya */
captured_size = toend_size;

process_packet(packet_start, captured_size);
}


> Thanks again.


--
Lev Walkin
vlm@lionet.info





[ Post a follow-up to this message ]



    Re: Parsing packets from BPF  
Nils O. Selåsdal


View Ip Address Report This Message To A Moderator Edit/Delete Message


 
06-30-04 01:45 AM

On Fri, 25 Jun 2004 18:45:23 +0000, chris wrote:

> I can now capture packets via the BPF so I need to begin parsing them.
>
> Do I do something like this?
>
> struct bpfhdr *bpfHdr;
> struct iphdr *ipHdr;
>
> read(bpf, buf, len)
> bpfHdr = (struct bpfhdr *) buf;
> ipHdr = (struct ipHdr *) buf + bpfHdr->bh_hdrlen;
Just as a side note,have you considered the pcap library ?
(www.tcpdump.org), it makes writing network sniffers real easy.






[ Post a follow-up to this message ]



    Sponsored Links  




 





   All times are GMT. The time now is 08:46 AM.      Post New Thread    Post A Reply      
  Last Thread   Next Thread Next


Most Popular forums 

Forum Jump:
Rate This Thread:

Forum Rules:
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts
HTML code is OFF
vB code is ON
Smilies are ON
[IMG] code is OFF
 
Medical and Health forum | Computer Games Reviews | Graphics design forum

Back To The Top
Home | Usercp | Faq | Register