[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
sea.c
- To: tech@openbsd.org
- Subject: sea.c
- From: Fredrik Widlund <fw@921i.se>
- Date: Sat, 03 Oct 1998 15:07:10 +0200
- Delivery-Date: Sat Oct 3 06:02:30 1998
- Organization: 921 Interactive AB
Skipped sleep and coded some instead.
yawn / lone_wolf (fw@921i.se)
/* sea.c, v 1.0a1 1998/10/03 lone_wolf */
/*
* sea.c : set ethernet interface addresses on openbsd
* Copyright (c) 1998 lone_wolf (Fredrik Widlund) <fw@921i.se>
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. The name of the author(s) may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* sea.c : set ethernet interface addresses on openbsd
*
* Changes the hardware address for ethernet interface(s) on OpenBSD.
* Requires securelevel 0 to write to kernel memory.
*
* Don't know which ethernet chips it will work on.
*
* Takes affect instantly, which might confuse other hosts arp databases.
* Clearing the arp table will make us promote it in arp requests. Guess
* we should broadcast-publish ourself...
*
* If you want to run it interactively (ie. not script it in /etc/rc) you
* must recompile a kernel with 'option insecure' in it, to allow the
* securelevel to remain at zero altitude.
*
* Oh btw, this is not standard procedure. Dont blame me if it takes down
* your system. It is for OpenBSD *exclusively*. Try it on other platforms
* and they will most certainly crash.
*
* Hacked if_ethersubr to keep mr. bsd off the eh for af_unspec, then
* noticed that the exact (letter for letter) patch had been used a year
* ago, for a couple of months, until deraadt ruled it out... I'll keep it
* though. It's still in the cvs tree, of course. Try it out.
*
* How about adding a ifnet flag, like IFF_SENDPROMISC or something, Theo?
*
* This is fresh code, and probably filled with annoying creatures...
*
*
* usage: sea [-vd] interface address [interface address ...]
*
* example: sea -vd fxp0 00:00:6C:6F:6E:65 fxp1 00:00:77:6F:6C:66
*
* options: -v verbose
* -d debug (wont write changes into the kernel vm)
*
* compile: gcc -Wall -o sea sea.c -lkvm
*/
/************/
/* Includes */
/************/
#include <sys/param.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <err.h>
#include <fcntl.h>
#include <kvm.h>
#include <limits.h>
#include <nlist.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
/**********/
/* Macros */
/**********/
#define KREAD(kd, addr, buf) \
if (kvm_read((kd), (addr), (char *) &(buf), sizeof (buf)) != sizeof (buf)) \
{ \
fprintf(stdout, "\n"); \
errx(EXIT_FAILURE, "%s", kvm_geterr(kd)); \
}
#define KWRITE(kd, addr, buf) \
if (kvm_write((kd), (addr), (char *) &(buf), sizeof (buf)) != sizeof (buf)) \
{ \
fprintf(stdout, "\n"); \
errx(EXIT_FAILURE, "%s", kvm_geterr(kd)); \
}
/***********/
/* Globals */
/***********/
extern char *__progname;
extern char *optarg;
extern int optind;
/***********/
/* Program */
/***********/
void usage()
{
fprintf(stdout,
"usage: %s [-vd] interface address [interface address ...]\n",
__progname);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
struct ether_addr *addr;
char buf[_POSIX2_LINE_MAX];
kvm_t *kd;
struct nlist nl[] = {{ "_ifnet" } , {}};
struct ifnet_head ifnet_head;
struct arpcom arpcom;
struct ifnet *ifnet_p;
struct ifaddr ifaddr;
struct sockaddr_dl sdl;
u_long ifnet_addr;
u_long ifaddr_addr;
u_long ifa_addr_addr;
int ch;
int verbose = 0;
int first = 1;
int set = 1;
int found = 0;
int offset;
int nif;
while ((ch = getopt(argc, argv, "dv")) != -1)
{
switch(ch)
{
case 'v':
verbose = 1;
break;
case 'd':
set = 0;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if ((argc == 0 && !verbose) || (argc % 2) != 0)
usage();
nif = argc / 2;
if (argc != 0)
{
for (offset = 0; offset < 2 * nif; offset += 2)
{
if (strlen(argv[offset]) >= IFNAMSIZ)
errx(EXIT_FAILURE, "invalid interface name: %s", argv[offset]);
if ((addr = ether_aton(argv[offset + 1])) == NULL)
errx(EXIT_FAILURE, "invalid interface address for %s",
argv[offset]);
}
}
else
{
set = 0;
}
if ((kd = kvm_openfiles(NULL, NULL, NULL, O_RDWR, buf)) == NULL)
errx(EXIT_FAILURE, "kvm_open: %s", buf);
if (kvm_nlist(kd, nl) < 0 || nl[0].n_type == 0)
errx(EXIT_FAILURE, "no namelist");
KREAD(kd, nl[0].n_value, ifnet_head);
for(ifnet_addr = (u_long) ifnet_head.tqh_first;
ifnet_addr;
ifnet_addr = (u_long) ifnet_p->if_list.tqe_next)
{
if (verbose)
{
if (first)
{
fprintf(stdout, "Name Network Type Address\n");
first = 0;
}
else
fprintf(stdout, "\n");
}
KREAD(kd, ifnet_addr, arpcom);
ifnet_p = (struct ifnet *) &arpcom;
if (verbose)
fprintf(stdout, "%-8s", ifnet_p->if_xname);
ifaddr_addr = (u_long) ifnet_p->if_addrlist.tqh_first;
if(ifaddr_addr == NULL)
continue;
KREAD(kd, ifaddr_addr, ifaddr);
ifa_addr_addr = (u_long) ifaddr.ifa_addr;
KREAD(kd, ifa_addr_addr, sdl);
if (sdl.sdl_family != AF_LINK)
continue;
if (verbose)
fprintf(stdout, "<Link> ");
if (sdl.sdl_type != IFT_ETHER)
continue;
if (verbose)
fprintf(stdout, "<Ether> %s",
ether_ntoa((struct ether_addr *) LLADDR(&sdl)));
for(offset = 0; offset < 2 * nif; offset += 2)
if (strcmp(ifnet_p->if_xname, argv[offset]) == 0)
break;
if (offset >= 2 * nif)
continue;
found++;
addr = ether_aton(argv[offset + 1]);
if (set)
{
bcopy((void *) addr, (void *) LLADDR(&sdl), sizeof(*addr));
KWRITE(kd, ifa_addr_addr, sdl);
bcopy((void *) addr, (void *) arpcom.ac_enaddr, sizeof(*addr));
KWRITE(kd, ifnet_addr, arpcom);
}
if (verbose)
fprintf(stdout, " -> %s", ether_ntoa(addr));
}
if (verbose)
fprintf(stdout, "\n");
if (kvm_close(kd) != 0)
errx(EXIT_FAILURE, "%s", kvm_geterr(kd));
if (found != nif)
errx(EXIT_FAILURE, "could not set all interfaces");
exit(EXIT_SUCCESS);
}