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

sea.c



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);
}