/* sea.c, v 1.0a2 1998/10/05 lone_wolf */ /* * sea.c : set ethernet interface addresses on openbsd * Copyright (c) 1998 lone_wolf (Fredrik Widlund) * * * 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. * * v1.0a2 is hackerished and actually quite improved... * * This is still 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) * -h help * * compile: gcc -Wall -O2 -o sea sea.c -lkvm */ /************/ /* Includes */ /************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /**********/ /* Macros */ /**********/ #define KREAD(kd, addr, buf) \ if (kvm_read((kd), (addr), (char *) (buf), sizeof (*buf)) != sizeof (*buf)) \ errx(EXIT_FAILURE, "%s", kvm_geterr(kd)); #define KWRITE(kd, addr, buf) \ if (kvm_write((kd), (addr), (char *) (buf), sizeof (*buf)) != sizeof (*buf)) \ errx(EXIT_FAILURE, "%s", kvm_geterr(kd)); /***********/ /* Globals */ /***********/ extern char *__progname; extern char *optarg; extern int optind; /**************/ /* Prototypes */ /**************/ int if_sethwaddrs(char **if_data, int nif, int verbose, int debug); void usage(); /***********/ /* Program */ /***********/ void usage() { fprintf(stdout, "usage: %s [-vdh] interface address [interface address ...]\n", __progname); exit(EXIT_FAILURE); } int main(int argc, char **argv) { int ch, verbose, debug, found, i, nif; struct ether_addr *addr; verbose = debug = 0; while ((ch = getopt(argc, argv, "dvh")) != -1) switch(ch) { case 'v': verbose = 1; break; case 'd': debug = 1 ; break; case 'h': default : usage(); } argc -= optind; argv += optind; if (argc % 2 != 0) usage(); nif = argc/2; for (i=0; i < nif; i++) if (strlen(argv[2*i]) >= IFNAMSIZ) errx(EXIT_FAILURE, "invalid interface name: %s", argv[2*i]); else if ((addr = ether_aton(argv[2*i+1])) == NULL) errx(EXIT_FAILURE, "invalid interface address for %s", argv[2*i]); found = if_sethwaddrs(argv, nif, verbose, debug); if (nif && found == 0) errx(EXIT_FAILURE, "unable to find any of the interfaces"); else if (found != nif) for (i = 0; i < nif; i++) if (argv[2*i][0]) fprintf(stderr, "%-8s not found\n", argv[2*i]); exit(EXIT_SUCCESS); } int if_sethwaddrs(char **if_data, int nif, int verbose, int debug) { char buf[_POSIX2_LINE_MAX]; kvm_t *kd; struct ether_addr *addr; 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 n, found = 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) { KREAD(kd, ifnet_addr, &arpcom); ifnet_p = (struct ifnet *) &arpcom; 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 || sdl.sdl_type != IFT_ETHER) continue; if (!nif) { fprintf(stdout, "%-8s %s\n", ifnet_p->if_xname, ether_ntoa((struct ether_addr *) LLADDR(&sdl))); continue; } for (n = 0; n < nif && strcmp(ifnet_p->if_xname, if_data[2*n]); n++) {} if (n >= nif) continue; if_data[2*n][0] = '\0'; found++; addr = ether_aton(if_data[2*n+1]); if (!debug) { KWRITE(kd, ifnet_addr + ((char *)&arpcom.ac_enaddr - (char *)&arpcom), addr); KWRITE(kd, ifa_addr_addr + ((char *)&sdl.sdl_data + sdl.sdl_nlen - (char *)&sdl), addr); } if (verbose) { fprintf(stdout, "%-8s %s", ifnet_p->if_xname, ether_ntoa((struct ether_addr *) LLADDR(&sdl))); fprintf(stdout, " -> %s\n", ether_ntoa(addr)); } } if (kvm_close(kd) != 0) errx(EXIT_FAILURE, "%s", kvm_geterr(kd)); return found; }