Blame src/libnet_link_bpf.c

Packit 03b34a
/*
Packit 03b34a
 *  $Id: libnet_link_bpf.c,v 1.6 2004/01/28 19:45:00 mike Exp $
Packit 03b34a
 *
Packit 03b34a
 *  libnet
Packit 03b34a
 *  libnet_link_bpf.c - low-level bpf routines
Packit 03b34a
 *
Packit 03b34a
 *  Copyright (c) 1998 - 2004 Mike D. Schiffman <mike@infonexus.com>
Packit 03b34a
 *  All rights reserved.
Packit 03b34a
 *
Packit 03b34a
 * Copyright (c) 1993, 1994, 1995, 1996, 1998
Packit 03b34a
 *	The Regents of the University of California.  All rights reserved.
Packit 03b34a
 *
Packit 03b34a
 * Redistribution and use in source and binary forms, with or without
Packit 03b34a
 * modification, are permitted provided that: (1) source code distributions
Packit 03b34a
 * retain the above copyright notice and this paragraph in its entirety, (2)
Packit 03b34a
 * distributions including binary code include the above copyright notice and
Packit 03b34a
 * this paragraph in its entirety in the documentation or other materials
Packit 03b34a
 * provided with the distribution, and (3) all advertising materials mentioning
Packit 03b34a
 * features or use of this software display the following acknowledgement:
Packit 03b34a
 * ``This product includes software developed by the University of California,
Packit 03b34a
 * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of
Packit 03b34a
 * the University nor the names of its contributors may be used to endorse
Packit 03b34a
 * or promote products derived from this software without specific prior
Packit 03b34a
 * written permission.
Packit 03b34a
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
Packit 03b34a
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
Packit 03b34a
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
Packit 03b34a
 */
Packit 03b34a
Packit 03b34a
#include <sys/param.h>  /* optionally get BSD define */
Packit 03b34a
#include <sys/timeb.h>
Packit 03b34a
#include <sys/file.h>
Packit 03b34a
#include <sys/ioctl.h>
Packit 03b34a
Packit 03b34a
#include <sys/types.h>
Packit 03b34a
#include <sys/time.h>
Packit 03b34a
#include <net/bpf.h>
Packit 03b34a
Packit 03b34a
#if (HAVE_CONFIG_H)
Packit 03b34a
#include "../include/config.h"
Packit 03b34a
#endif 
Packit 03b34a
#include "../include/libnet.h"
Packit 03b34a
#include <sys/sysctl.h>
Packit 03b34a
#include <net/route.h>
Packit 03b34a
#include <net/if_dl.h>
Packit 03b34a
#include <net/if_types.h>
Packit 03b34a
#include "../include/gnuc.h"
Packit 03b34a
Packit 03b34a
#include <bpf.h>
Packit 03b34a
Packit 03b34a
#ifdef HAVE_OS_PROTO_H
Packit 03b34a
#include "../include/os-proto.h"
Packit 03b34a
#endif
Packit 03b34a
Packit 03b34a
int
Packit 03b34a
libnet_bpf_open(char *err_buf)
Packit 03b34a
{
Packit 03b34a
    int i, fd;
Packit 03b34a
    char device[] = "/dev/bpf000";
Packit 03b34a
Packit 03b34a
    /*
Packit 03b34a
     *  Go through all the minors and find one that isn't in use.
Packit 03b34a
     */
Packit 03b34a
    for (i = 0;;i++)
Packit 03b34a
    {
Packit 03b34a
        sprintf(device, "/dev/bpf%d", i);
Packit 03b34a
Packit 03b34a
        fd = open(device, O_RDWR);
Packit 03b34a
        if (fd == -1 && errno == EBUSY)
Packit 03b34a
        {
Packit 03b34a
            /*
Packit 03b34a
             *  Device is busy.
Packit 03b34a
             */
Packit 03b34a
            continue;
Packit 03b34a
        }
Packit 03b34a
        else
Packit 03b34a
        {
Packit 03b34a
            /*
Packit 03b34a
             *  Either we've got a valid file descriptor, or errno is not
Packit 03b34a
             *  EBUSY meaning we've probably run out of devices.
Packit 03b34a
             */
Packit 03b34a
            break;
Packit 03b34a
        }
Packit 03b34a
    }
Packit 03b34a
Packit 03b34a
    if (fd == -1)
Packit 03b34a
    {
Packit 03b34a
        snprintf(err_buf, LIBNET_ERRBUF_SIZE, "%s(): open(): (%s): %s\n",
Packit 03b34a
                __func__, device, strerror(errno));
Packit 03b34a
    }
Packit 03b34a
    return (fd);
Packit 03b34a
}
Packit 03b34a
Packit 03b34a
Packit 03b34a
int
Packit 03b34a
libnet_open_link(libnet_t *l)
Packit 03b34a
{
Packit 03b34a
    struct ifreq ifr;
Packit 03b34a
    struct bpf_version bv;
Packit 03b34a
    uint v;
Packit 03b34a
Packit 03b34a
#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) && !(__APPLE__)
Packit 03b34a
    uint spoof_eth_src = 1;
Packit 03b34a
#endif
Packit 03b34a
Packit 03b34a
    if (l == NULL)
Packit 03b34a
    { 
Packit 03b34a
        return (-1);
Packit 03b34a
    } 
Packit 03b34a
Packit 03b34a
    if (l->device == NULL)
Packit 03b34a
    {
Packit 03b34a
        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): NULL device\n", 
Packit 03b34a
                __func__);
Packit 03b34a
        goto bad;
Packit 03b34a
    }
Packit 03b34a
Packit 03b34a
    l->fd = libnet_bpf_open((char*)l->err_buf);
Packit 03b34a
    if (l->fd == -1)
Packit 03b34a
    {
Packit 03b34a
        goto bad;
Packit 03b34a
    }
Packit 03b34a
Packit 03b34a
    /*
Packit 03b34a
     *  Get bpf version.
Packit 03b34a
     */
Packit 03b34a
    if (ioctl(l->fd, BIOCVERSION, (caddr_t)&bv) < 0)
Packit 03b34a
    {
Packit 03b34a
        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCVERSION: %s\n",
Packit 03b34a
                __func__, strerror(errno));
Packit 03b34a
        goto bad;
Packit 03b34a
    }
Packit 03b34a
Packit 03b34a
    if (bv.bv_major != BPF_MAJOR_VERSION || bv.bv_minor < BPF_MINOR_VERSION)
Packit 03b34a
    {
Packit 03b34a
        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
Packit 03b34a
                "%s(): kernel bpf filter out of date\n", __func__);
Packit 03b34a
        goto bad;
Packit 03b34a
    }
Packit 03b34a
Packit 03b34a
    /*
Packit 03b34a
     *  Attach network interface to bpf device.
Packit 03b34a
     */
Packit 03b34a
	strncpy(ifr.ifr_name, l->device, sizeof(ifr.ifr_name) - 1);
Packit 03b34a
    ifr.ifr_name[sizeof(ifr.ifr_name) - 1] = '\0';
Packit 03b34a
Packit 03b34a
    if (ioctl(l->fd, BIOCSETIF, (caddr_t)&ifr) == -1)
Packit 03b34a
    {
Packit 03b34a
        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCSETIF: (%s): %s\n",
Packit 03b34a
                __func__, l->device, strerror(errno));
Packit 03b34a
        goto bad;
Packit 03b34a
    }
Packit 03b34a
Packit 03b34a
    /*
Packit 03b34a
     *  Get the data link-layer type.
Packit 03b34a
     */
Packit 03b34a
    if (ioctl(l->fd, BIOCGDLT, (caddr_t)&v) == -1)
Packit 03b34a
    {
Packit 03b34a
        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCGDLT: %s\n",
Packit 03b34a
                __func__, strerror(errno));
Packit 03b34a
        goto bad;
Packit 03b34a
    }
Packit 03b34a
Packit 03b34a
    /*
Packit 03b34a
     *  NetBSD and FreeBSD BPF have an ioctl for enabling/disabling
Packit 03b34a
     *  automatic filling of the link level source address.
Packit 03b34a
     */
Packit 03b34a
#if defined(BIOCGHDRCMPLT) && defined(BIOCSHDRCMPLT) && !(__APPLE__)
Packit 03b34a
    if (ioctl(l->fd, BIOCSHDRCMPLT, &spoof_eth_src) == -1)
Packit 03b34a
    {
Packit 03b34a
        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): BIOCSHDRCMPLT: %s\n",
Packit 03b34a
                __func__, strerror(errno));
Packit 03b34a
        goto bad;
Packit 03b34a
    }
Packit 03b34a
#endif
Packit 03b34a
Packit 03b34a
    /*
Packit 03b34a
     *  Assign link type and offset.
Packit 03b34a
     */
Packit 03b34a
    switch (v)
Packit 03b34a
    {
Packit 03b34a
        case DLT_SLIP:
Packit 03b34a
            l->link_offset = 0x10;
Packit 03b34a
            break;
Packit 03b34a
        case DLT_RAW:
Packit 03b34a
            l->link_offset = 0x0;
Packit 03b34a
            break;
Packit 03b34a
        case DLT_PPP:
Packit 03b34a
            l->link_offset = 0x04;
Packit 03b34a
            break;
Packit 03b34a
        case DLT_EN10MB:
Packit 03b34a
        default:
Packit 03b34a
            l->link_offset = 0xe;     /* default to ethernet */
Packit 03b34a
            break;
Packit 03b34a
    }
Packit 03b34a
#if _BSDI_VERSION - 0 >= 199510
Packit 03b34a
    switch (v)
Packit 03b34a
    {
Packit 03b34a
        case DLT_SLIP:
Packit 03b34a
            v = DLT_SLIP_BSDOS;
Packit 03b34a
            l->link_offset = 0x10;
Packit 03b34a
            break;
Packit 03b34a
        case DLT_PPP:
Packit 03b34a
            v = DLT_PPP_BSDOS;
Packit 03b34a
            l->link_offset = 0x04;
Packit 03b34a
            break;
Packit 03b34a
    }
Packit 03b34a
#endif
Packit 03b34a
    l->link_type = v;
Packit 03b34a
Packit 03b34a
    return (1);
Packit 03b34a
Packit 03b34a
bad:
Packit 03b34a
    if (l->fd > 0)
Packit 03b34a
    {
Packit 03b34a
        close(l->fd);      /* this can fail ok */
Packit 03b34a
    }
Packit 03b34a
    return (-1);
Packit 03b34a
}
Packit 03b34a
Packit 03b34a
Packit 03b34a
int
Packit 03b34a
libnet_close_link(libnet_t *l)
Packit 03b34a
{
Packit 03b34a
    if (close(l->fd) == 0)
Packit 03b34a
    {
Packit 03b34a
        return (1);
Packit 03b34a
    }
Packit 03b34a
    else
Packit 03b34a
    {
Packit 03b34a
        return (-1);
Packit 03b34a
    }
Packit 03b34a
}
Packit 03b34a
Packit 03b34a
Packit 03b34a
int
Packit 03b34a
libnet_write_link(libnet_t *l, const uint8_t *packet, uint32_t size)
Packit 03b34a
{
Packit 03b34a
    int c;
Packit 03b34a
Packit 03b34a
    if (l == NULL)
Packit 03b34a
    { 
Packit 03b34a
        return (-1);
Packit 03b34a
    } 
Packit 03b34a
Packit 03b34a
    c = write(l->fd, packet, size);
Packit 03b34a
    if (c != size)
Packit 03b34a
    {
Packit 03b34a
        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE,
Packit 03b34a
                "%s(): %d bytes written (%s)\n", __func__, c, strerror(errno));
Packit 03b34a
    }
Packit 03b34a
    return (c);
Packit 03b34a
}
Packit 03b34a
Packit 03b34a
Packit 03b34a
struct libnet_ether_addr *
Packit 03b34a
libnet_get_hwaddr(libnet_t *l)
Packit 03b34a
{
Packit 03b34a
    int mib[6];
Packit 03b34a
    size_t len;
Packit 03b34a
    int8_t *buf, *next, *end;
Packit 03b34a
    struct if_msghdr *ifm;
Packit 03b34a
    struct sockaddr_dl *sdl;
Packit 03b34a
    /* This implementation is not-reentrant. */
Packit 03b34a
    static struct libnet_ether_addr ea;
Packit 03b34a
Packit 03b34a
    mib[0] = CTL_NET;
Packit 03b34a
    mib[1] = AF_ROUTE;
Packit 03b34a
    mib[2] = 0;
Packit 03b34a
    mib[3] = AF_LINK;
Packit 03b34a
    mib[4] = NET_RT_IFLIST;
Packit 03b34a
    mib[5] = 0;
Packit 03b34a
Packit 03b34a
    if (l == NULL)
Packit 03b34a
    { 
Packit 03b34a
        return (NULL);
Packit 03b34a
    } 
Packit 03b34a
Packit 03b34a
    if (l->device == NULL)
Packit 03b34a
    {           
Packit 03b34a
        if (libnet_select_device(l) == -1)
Packit 03b34a
        {
Packit 03b34a
            /* err msg set in libnet_select_device */ 
Packit 03b34a
            return (NULL);
Packit 03b34a
        }
Packit 03b34a
    }
Packit 03b34a
Packit 03b34a
    if (sysctl(mib, 6, NULL, &len, NULL, 0) == -1)
Packit 03b34a
    {
Packit 03b34a
        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): sysctl(): %s\n",
Packit 03b34a
                __func__, strerror(errno));
Packit 03b34a
        return (NULL);
Packit 03b34a
    }
Packit 03b34a
Packit 03b34a
    buf = (int8_t *)malloc(len);
Packit 03b34a
    if (buf == NULL)
Packit 03b34a
    {
Packit 03b34a
        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): malloc(): %s\n",
Packit 03b34a
                __func__, strerror(errno));
Packit 03b34a
        return (NULL);
Packit 03b34a
    }
Packit 03b34a
    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0)
Packit 03b34a
    {
Packit 03b34a
        snprintf(l->err_buf, LIBNET_ERRBUF_SIZE, "%s(): sysctl(): %s\n",
Packit 03b34a
                __func__, strerror(errno));
Packit 03b34a
        free(buf);
Packit 03b34a
        return (NULL);
Packit 03b34a
    }
Packit 03b34a
    end = buf + len;
Packit 03b34a
Packit 03b34a
    for (next = buf ; next < end ; next += ifm->ifm_msglen)
Packit 03b34a
    {
Packit 03b34a
        ifm = (struct if_msghdr *)next;
Packit 03b34a
        if (ifm->ifm_version != RTM_VERSION)
Packit 03b34a
            continue;
Packit 03b34a
        if (ifm->ifm_type == RTM_IFINFO)
Packit 03b34a
        {
Packit 03b34a
            sdl = (struct sockaddr_dl *)(ifm + 1);
Packit 03b34a
            if (sdl->sdl_type != IFT_ETHER)
Packit 03b34a
                continue;
Packit 03b34a
            if (strncmp(&sdl->sdl_data[0], l->device, sdl->sdl_nlen) == 0)
Packit 03b34a
            {
Packit 03b34a
                memcpy(ea.ether_addr_octet, LLADDR(sdl), ETHER_ADDR_LEN);
Packit 03b34a
                break;
Packit 03b34a
            }
Packit 03b34a
        }
Packit 03b34a
    }
Packit 03b34a
    free(buf);
Packit 03b34a
    return (&ea);
Packit 03b34a
}
Packit 03b34a
Packit 03b34a
Packit 03b34a
/* EOF */