|
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 */
|