NetBSD-Users archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

BPF problem



Hello,

I am trying to read bpf packets. It works ok so long as read() returns only one packet's worth of data. Otherwise, it appears the next packet is invalid/mal-formed, and the bpf_hdr contains 0 length bh_caplen and bh_hdrlen values, producing an infinite loop.

Any suggestions as to what I am doing wrong?

Cheers,
   Josh

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>

/* OpenBSD specific */
#ifdef OPENBSD
#include <netinet/in.h>
#include <netinet/in_var.h>
#include <netinet/if_ether.h>
#endif

#include <sys/time.h>
#include <sys/ioctl.h>
#include <sys/sockio.h>
#include <sys/uio.h>
#include <net/bpf.h>
#include <net/if.h>
#include <net/if_ether.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <netinet/udp.h>

int bpf = 0;
char *interface = NULL;
char *filter = NULL;
struct ifreq bound_if;
int buf_len = 0;
int immediate = 1;


void process_packet(struct ether_header *eh) {

        int i;
        unsigned int type = ntohs(eh->ether_type);
        char *src, *dst;
        unsigned long len, src_port, dst_port;
        struct ip *ip_header;
        struct tcphdr *tcp_header;
        struct udphdr *udp_header;

        if (type != ETHERTYPE_IP) {
                printf("Non IP packet (%x)\n", type);
                return;
        }

        /* print out ethernet mac addresses */

        for (i = 0; i < ETHER_ADDR_LEN; i++)
                printf("%s%02x", (i == 0) ? "" : ":", eh->ether_shost[i]);
        for (i = 0; i < ETHER_ADDR_LEN; i++)
                printf("%s%02x", (i == 0) ? " -> " : ":", eh->ether_dhost[i]);
        printf("\n");

        ip_header = (struct ip*) ((char *)eh + ETHER_HDR_LEN);
        len = ntohs(ip_header->ip_len);
        src = strdup(inet_ntoa(ip_header->ip_src));
        dst = strdup(inet_ntoa(ip_header->ip_dst));
        
        if (src == NULL || dst == NULL)
                err(EXIT_FAILURE, "malloc()");

        switch (ip_header->ip_p) {
        case IPPROTO_ICMP:
                printf("ICMP: %d bytes %s -> %s\n", len, src,dst);
                break;
        case IPPROTO_UDP:
                udp_header = (struct udphdr*) ((char *)ip_header + 
sizeof(struct ip));
                src_port = ntohs(udp_header->uh_sport);
                dst_port = ntohs(udp_header->uh_dport);
                printf("UDP: %d bytes %s:%u -> %s:%u\n", 
len,src,src_port,dst,dst_port);
                break;
        case IPPROTO_TCP:
                tcp_header = (struct tcphdr*) ((char *)ip_header + 
sizeof(struct ip));
                src_port = ntohs(tcp_header->th_sport);
                dst_port = ntohs(tcp_header->th_dport);
                printf("TCP: %d bytes %s:%u -> %s:%u\n", 
len,src,src_port,dst,dst_port);
                break;
        default:
                
                printf("BOLLIX: %d bytes %s -> %s\n", len,src,dst);
                break;
        }
        free(src);
        free(dst);

}


int read_packets() {

        ssize_t read_bytes = 0;
        struct ether_header *eth_frame;
        struct bpf_hdr *bpf_packet;
        struct bpf_hdr *bpf_buf = malloc(buf_len);

        if (bpf_buf == NULL)
                err(EXIT_FAILURE, NULL);
        while(1) {
                memset(bpf_buf, 0, buf_len);

                read_bytes = read(bpf, bpf_buf, buf_len);
        
                if (read_bytes == 0) {
                        printf("Hmmm. Sleeping for a bit.\n");
                        sleep(3);
                        continue;
                }
if (read_bytes == EINVAL) err(EXIT_FAILURE, "read()");


                bpf_packet = bpf_buf;
                while (read_bytes > 0) {

                        /*read_bytes -= BPF_WORDALIGN(bpf_packet->bh_hdrlen + 
bpf_packet->bh_caplen); */
read_bytes -= bpf_packet->bh_hdrlen + bpf_packet->bh_caplen;
                        printf("read_bytes now %d\n", read_bytes);
                        
                        eth_frame = (struct ether_header *) ((char *)bpf_packet + 
bpf_packet->bh_hdrlen);

                        process_packet(eth_frame);


bpf_packet = (struct bpf_hdr *) (char *)bpf_packet + (bpf_packet->bh_hdrlen + bpf_packet->bh_datalen);
/*                      bpf_packet = (struct bpf_hdr *) (char *)bpf_packet +  */
/*                          BPF_WORDALIGN((bpf_packet->bh_hdrlen + 
bpf_packet->bh_datalen)); */

                        printf("------------------------------\n");

                }

        }
}

void init_bpf() {

        int i, ret;
        char buff[100];

        /* open device. */
        for (i = 0; i<=99; i++) {
                snprintf(buff, sizeof(buff) - 1, "/dev/bpf%i", i);
                bpf = open(buff, O_RDONLY);
                if (bpf != -1)
                        break;
        }

        if (bpf == -1) {
                printf("Failed to open a bpf device.\n");
                exit(EXIT_FAILURE);
        }

        snprintf(bound_if.ifr_name, IFNAMSIZ, "%s", interface);
if (ioctl(bpf, BIOCSETIF, &bound_if) == -1) err(EXIT_FAILURE, "%s", interface);

        if( ioctl(bpf, BIOCIMMEDIATE, &immediate ) == -1 )
                err(EXIT_FAILURE, "%s", interface);

        if( ioctl(bpf, BIOCGBLEN, &buf_len ) == -1 )
                err(EXIT_FAILURE, "%s", interface);
}

void useage(char *arg0) {
        printf("useage: %s interface\n", arg0);
        exit(EXIT_FAILURE);
}

int main(int argc, char **argv) {

        printf("\nnetwork rangi-o-matic version 0.2\n\n");
        /* parse arguments */
        if (argc < 2)
                useage(argv[0]);
        interface = argv[1];

        init_bpf();
        read_packets();
        return 0;
}






Home | Main Index | Thread Index | Old Index