arp.c revision 20287
11553Srgrimes/*
21553Srgrimes * Copyright (c) 1984, 1993
31553Srgrimes *	The Regents of the University of California.  All rights reserved.
41553Srgrimes *
51553Srgrimes * This code is derived from software contributed to Berkeley by
61553Srgrimes * Sun Microsystems, Inc.
71553Srgrimes *
81553Srgrimes * Redistribution and use in source and binary forms, with or without
91553Srgrimes * modification, are permitted provided that the following conditions
101553Srgrimes * are met:
111553Srgrimes * 1. Redistributions of source code must retain the above copyright
121553Srgrimes *    notice, this list of conditions and the following disclaimer.
131553Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141553Srgrimes *    notice, this list of conditions and the following disclaimer in the
151553Srgrimes *    documentation and/or other materials provided with the distribution.
161553Srgrimes * 3. All advertising materials mentioning features or use of this software
171553Srgrimes *    must display the following acknowledgement:
181553Srgrimes *	This product includes software developed by the University of
191553Srgrimes *	California, Berkeley and its contributors.
201553Srgrimes * 4. Neither the name of the University nor the names of its contributors
211553Srgrimes *    may be used to endorse or promote products derived from this software
221553Srgrimes *    without specific prior written permission.
231553Srgrimes *
241553Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251553Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261553Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271553Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281553Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291553Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301553Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311553Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321553Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331553Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341553Srgrimes * SUCH DAMAGE.
351553Srgrimes */
361553Srgrimes
371553Srgrimes#ifndef lint
3813977Sphkstatic char const copyright[] =
391553Srgrimes"@(#) Copyright (c) 1984, 1993\n\
401553Srgrimes	The Regents of the University of California.  All rights reserved.\n";
411553Srgrimes#endif /* not lint */
421553Srgrimes
431553Srgrimes#ifndef lint
4413977Sphkstatic char const sccsid[] = "@(#)from: arp.c	8.2 (Berkeley) 1/2/94";
4520287Swollmanstatic char const freebsdid[] = "$Id: arp.c,v 1.4 1996/02/08 21:05:52 phk Exp $";
461553Srgrimes#endif /* not lint */
471553Srgrimes
481553Srgrimes/*
491553Srgrimes * arp - display, set, and delete arp table entries
501553Srgrimes */
511553Srgrimes
521553Srgrimes
531553Srgrimes#include <sys/param.h>
541553Srgrimes#include <sys/file.h>
551553Srgrimes#include <sys/socket.h>
5613977Sphk#include <sys/sockio.h>
571553Srgrimes#include <sys/sysctl.h>
5813977Sphk#include <sys/ioctl.h>
5920287Swollman#include <sys/time.h>
601553Srgrimes
611553Srgrimes#include <net/if.h>
621553Srgrimes#include <net/if_dl.h>
631553Srgrimes#include <net/if_types.h>
641553Srgrimes#include <net/route.h>
651553Srgrimes
661553Srgrimes#include <netinet/in.h>
671553Srgrimes#include <netinet/if_ether.h>
681553Srgrimes
691553Srgrimes#include <arpa/inet.h>
701553Srgrimes
711553Srgrimes#include <netdb.h>
721553Srgrimes#include <errno.h>
731553Srgrimes#include <nlist.h>
741553Srgrimes#include <stdio.h>
7513977Sphk#include <stdlib.h>
7613977Sphk#include <unistd.h>
7713977Sphk#include <strings.h>
781553Srgrimes#include <paths.h>
791553Srgrimes
8013977Sphkvoid dump(u_long addr);
8113977Sphkint delete(char *host, char *info);
8213977Sphkvoid ether_print(u_char *cp);
8313977Sphkvoid usage(void);
8413977Sphkint set(int argc, char **argv);
8513977Sphkvoid get(char *host);
8613977Sphkint file(char *name);
8713977Sphkvoid getsocket(void);
8813977Sphkint ether_aton(char *a, u_char *n);
8913977Sphkint rtmsg(int cmd);
9013977Sphkvoid quit(char *msg);
9113977Sphkint get_ether_addr(u_long ipaddr, u_char *hwaddr);
9213977Sphk
931553Srgrimesstatic int pid;
941553Srgrimesstatic int nflag;
951553Srgrimesstatic int s = -1;
961553Srgrimes
9713977Sphkint
981553Srgrimesmain(argc, argv)
991553Srgrimes	int argc;
1001553Srgrimes	char **argv;
1011553Srgrimes{
1021553Srgrimes	int ch;
1031553Srgrimes
1041553Srgrimes	pid = getpid();
10513977Sphk	while ((ch = getopt(argc, argv, "andfsS")) != EOF)
1061553Srgrimes		switch((char)ch) {
1071553Srgrimes		case 'a':
1081553Srgrimes			dump(0);
1091553Srgrimes			exit(0);
1101553Srgrimes		case 'd':
1111553Srgrimes			if (argc < 3 || argc > 4)
1121553Srgrimes				usage();
1131553Srgrimes			delete(argv[2], argv[3]);
1141553Srgrimes			exit(0);
1151553Srgrimes		case 'n':
1161553Srgrimes			nflag = 1;
1171553Srgrimes			continue;
11813977Sphk		case 'S':
11913977Sphk			delete(argv[2], NULL);
12013977Sphk			/* FALL THROUGH */
1211553Srgrimes		case 's':
1221553Srgrimes			if (argc < 4 || argc > 7)
1231553Srgrimes				usage();
1241553Srgrimes			exit(set(argc-2, &argv[2]) ? 1 : 0);
1259874Sjkh		case 'f' :
1269874Sjkh			if (argc != 3)
1279874Sjkh				usage();
12813977Sphk			return (file(argv[2]));
1291553Srgrimes		case '?':
1301553Srgrimes		default:
1311553Srgrimes			usage();
1321553Srgrimes		}
1331553Srgrimes	if (argc != 2)
1341553Srgrimes		usage();
1351553Srgrimes	get(argv[1]);
1361553Srgrimes	exit(0);
1371553Srgrimes}
1381553Srgrimes
1391553Srgrimes/*
1401553Srgrimes * Process a file to set standard arp entries
1411553Srgrimes */
14213977Sphkint
14313977Sphkfile(char *name)
1441553Srgrimes{
1451553Srgrimes	FILE *fp;
1461553Srgrimes	int i, retval;
1471553Srgrimes	char line[100], arg[5][50], *args[5];
1481553Srgrimes
1491553Srgrimes	if ((fp = fopen(name, "r")) == NULL) {
1501553Srgrimes		fprintf(stderr, "arp: cannot open %s\n", name);
1511553Srgrimes		exit(1);
1521553Srgrimes	}
1531553Srgrimes	args[0] = &arg[0][0];
1541553Srgrimes	args[1] = &arg[1][0];
1551553Srgrimes	args[2] = &arg[2][0];
1561553Srgrimes	args[3] = &arg[3][0];
1571553Srgrimes	args[4] = &arg[4][0];
1581553Srgrimes	retval = 0;
1591553Srgrimes	while(fgets(line, 100, fp) != NULL) {
1601553Srgrimes		i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
1611553Srgrimes		    arg[3], arg[4]);
1621553Srgrimes		if (i < 2) {
1631553Srgrimes			fprintf(stderr, "arp: bad line: %s\n", line);
1641553Srgrimes			retval = 1;
1651553Srgrimes			continue;
1661553Srgrimes		}
1671553Srgrimes		if (set(i, args))
1681553Srgrimes			retval = 1;
1691553Srgrimes	}
1701553Srgrimes	fclose(fp);
1711553Srgrimes	return (retval);
1721553Srgrimes}
1731553Srgrimes
17413977Sphkvoid
17513977Sphkgetsocket(void)
17613977Sphk{
1771553Srgrimes	if (s < 0) {
1781553Srgrimes		s = socket(PF_ROUTE, SOCK_RAW, 0);
1791553Srgrimes		if (s < 0) {
1801553Srgrimes			perror("arp: socket");
1811553Srgrimes			exit(1);
1821553Srgrimes		}
1831553Srgrimes	}
1841553Srgrimes}
1851553Srgrimes
1861553Srgrimesstruct	sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}};
1871553Srgrimesstruct	sockaddr_inarp blank_sin = {sizeof(blank_sin), AF_INET }, sin_m;
1881553Srgrimesstruct	sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
1891553Srgrimesint	expire_time, flags, export_only, doing_proxy, found_entry;
1901553Srgrimesstruct	{
1911553Srgrimes	struct	rt_msghdr m_rtm;
1921553Srgrimes	char	m_space[512];
1931553Srgrimes}	m_rtmsg;
1941553Srgrimes
1951553Srgrimes/*
1968857Srgrimes * Set an individual arp entry
1971553Srgrimes */
19813977Sphkint
19913977Sphkset(int argc, char **argv)
2001553Srgrimes{
2011553Srgrimes	struct hostent *hp;
2021553Srgrimes	register struct sockaddr_inarp *sin = &sin_m;
2031553Srgrimes	register struct sockaddr_dl *sdl;
2041553Srgrimes	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
2051553Srgrimes	u_char *ea;
2061553Srgrimes	char *host = argv[0], *eaddr = argv[1];
2071553Srgrimes
2081553Srgrimes	getsocket();
2091553Srgrimes	argc -= 2;
2101553Srgrimes	argv += 2;
2111553Srgrimes	sdl_m = blank_sdl;
2121553Srgrimes	sin_m = blank_sin;
2131553Srgrimes	sin->sin_addr.s_addr = inet_addr(host);
2141553Srgrimes	if (sin->sin_addr.s_addr == -1) {
2151553Srgrimes		if (!(hp = gethostbyname(host))) {
2161553Srgrimes			fprintf(stderr, "arp: %s: ", host);
2171553Srgrimes			herror((char *)NULL);
2181553Srgrimes			return (1);
2191553Srgrimes		}
2201553Srgrimes		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
2211553Srgrimes		    sizeof sin->sin_addr);
2221553Srgrimes	}
2231553Srgrimes	doing_proxy = flags = export_only = expire_time = 0;
2241553Srgrimes	while (argc-- > 0) {
2251553Srgrimes		if (strncmp(argv[0], "temp", 4) == 0) {
2261553Srgrimes			struct timeval time;
2271553Srgrimes			gettimeofday(&time, 0);
2281553Srgrimes			expire_time = time.tv_sec + 20 * 60;
2291553Srgrimes		}
2301553Srgrimes		else if (strncmp(argv[0], "pub", 3) == 0) {
2311553Srgrimes			flags |= RTF_ANNOUNCE;
2321553Srgrimes			doing_proxy = SIN_PROXY;
2331553Srgrimes		} else if (strncmp(argv[0], "trail", 5) == 0) {
2341553Srgrimes			printf("%s: Sending trailers is no longer supported\n",
2351553Srgrimes				host);
2361553Srgrimes		}
2371553Srgrimes		argv++;
2381553Srgrimes	}
23913977Sphk	ea = (u_char *)LLADDR(&sdl_m);
24013977Sphk	if (doing_proxy && !strcmp(eaddr, "auto")) {
24113977Sphk		if (!get_ether_addr(sin->sin_addr.s_addr, ea)) {
24213977Sphk			return (1);
24313977Sphk		}
24413977Sphk		sdl_m.sdl_alen = 6;
24513977Sphk	} else {
24613977Sphk		if (ether_aton(eaddr, ea) == 0)
24713977Sphk			sdl_m.sdl_alen = 6;
24813977Sphk	}
2491553Srgrimestryagain:
2501553Srgrimes	if (rtmsg(RTM_GET) < 0) {
2511553Srgrimes		perror(host);
2521553Srgrimes		return (1);
2531553Srgrimes	}
2541553Srgrimes	sin = (struct sockaddr_inarp *)(rtm + 1);
2551553Srgrimes	sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin);
2561553Srgrimes	if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
2571553Srgrimes		if (sdl->sdl_family == AF_LINK &&
2581553Srgrimes		    (rtm->rtm_flags & RTF_LLINFO) &&
2591553Srgrimes		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
2601553Srgrimes		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
2611553Srgrimes		case IFT_ISO88024: case IFT_ISO88025:
2621553Srgrimes			goto overwrite;
2631553Srgrimes		}
2641553Srgrimes		if (doing_proxy == 0) {
2651553Srgrimes			printf("set: can only proxy for %s\n", host);
2661553Srgrimes			return (1);
2671553Srgrimes		}
2681553Srgrimes		if (sin_m.sin_other & SIN_PROXY) {
2691553Srgrimes			printf("set: proxy entry exists for non 802 device\n");
2701553Srgrimes			return(1);
2711553Srgrimes		}
2721553Srgrimes		sin_m.sin_other = SIN_PROXY;
2731553Srgrimes		export_only = 1;
2741553Srgrimes		goto tryagain;
2751553Srgrimes	}
2761553Srgrimesoverwrite:
2771553Srgrimes	if (sdl->sdl_family != AF_LINK) {
2781553Srgrimes		printf("cannot intuit interface index and type for %s\n", host);
2791553Srgrimes		return (1);
2801553Srgrimes	}
2811553Srgrimes	sdl_m.sdl_type = sdl->sdl_type;
2821553Srgrimes	sdl_m.sdl_index = sdl->sdl_index;
2831553Srgrimes	return (rtmsg(RTM_ADD));
2841553Srgrimes}
2851553Srgrimes
2861553Srgrimes/*
2871553Srgrimes * Display an individual arp entry
2881553Srgrimes */
28913977Sphkvoid
29013977Sphkget(char *host)
2911553Srgrimes{
2921553Srgrimes	struct hostent *hp;
2931553Srgrimes	struct sockaddr_inarp *sin = &sin_m;
2941553Srgrimes
2951553Srgrimes	sin_m = blank_sin;
2961553Srgrimes	sin->sin_addr.s_addr = inet_addr(host);
2971553Srgrimes	if (sin->sin_addr.s_addr == -1) {
2981553Srgrimes		if (!(hp = gethostbyname(host))) {
2991553Srgrimes			fprintf(stderr, "arp: %s: ", host);
3001553Srgrimes			herror((char *)NULL);
3011553Srgrimes			exit(1);
3021553Srgrimes		}
3031553Srgrimes		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
3041553Srgrimes		    sizeof sin->sin_addr);
3051553Srgrimes	}
3061553Srgrimes	dump(sin->sin_addr.s_addr);
3071553Srgrimes	if (found_entry == 0) {
3081553Srgrimes		printf("%s (%s) -- no entry\n",
3091553Srgrimes		    host, inet_ntoa(sin->sin_addr));
3101553Srgrimes		exit(1);
3111553Srgrimes	}
3121553Srgrimes}
3131553Srgrimes
3141553Srgrimes/*
3158857Srgrimes * Delete an arp entry
3161553Srgrimes */
31713977Sphkint
31813977Sphkdelete(char *host, char *info)
3191553Srgrimes{
3201553Srgrimes	struct hostent *hp;
3211553Srgrimes	register struct sockaddr_inarp *sin = &sin_m;
3221553Srgrimes	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
3231553Srgrimes	struct sockaddr_dl *sdl;
3241553Srgrimes
3251553Srgrimes	if (info && strncmp(info, "pro", 3) )
3261553Srgrimes		export_only = 1;
3271553Srgrimes	getsocket();
3281553Srgrimes	sin_m = blank_sin;
3291553Srgrimes	sin->sin_addr.s_addr = inet_addr(host);
3301553Srgrimes	if (sin->sin_addr.s_addr == -1) {
3311553Srgrimes		if (!(hp = gethostbyname(host))) {
3321553Srgrimes			fprintf(stderr, "arp: %s: ", host);
3331553Srgrimes			herror((char *)NULL);
3341553Srgrimes			return (1);
3351553Srgrimes		}
3361553Srgrimes		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
3371553Srgrimes		    sizeof sin->sin_addr);
3381553Srgrimes	}
3391553Srgrimestryagain:
3401553Srgrimes	if (rtmsg(RTM_GET) < 0) {
3411553Srgrimes		perror(host);
3421553Srgrimes		return (1);
3431553Srgrimes	}
3441553Srgrimes	sin = (struct sockaddr_inarp *)(rtm + 1);
3451553Srgrimes	sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin);
3461553Srgrimes	if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
3471553Srgrimes		if (sdl->sdl_family == AF_LINK &&
3481553Srgrimes		    (rtm->rtm_flags & RTF_LLINFO) &&
3491553Srgrimes		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
3501553Srgrimes		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
3511553Srgrimes		case IFT_ISO88024: case IFT_ISO88025:
3521553Srgrimes			goto delete;
3531553Srgrimes		}
3541553Srgrimes	}
3551553Srgrimes	if (sin_m.sin_other & SIN_PROXY) {
3561553Srgrimes		fprintf(stderr, "delete: can't locate %s\n",host);
3571553Srgrimes		return (1);
3581553Srgrimes	} else {
3591553Srgrimes		sin_m.sin_other = SIN_PROXY;
3601553Srgrimes		goto tryagain;
3611553Srgrimes	}
3621553Srgrimesdelete:
3631553Srgrimes	if (sdl->sdl_family != AF_LINK) {
3641553Srgrimes		printf("cannot locate %s\n", host);
3651553Srgrimes		return (1);
3661553Srgrimes	}
36713977Sphk	if (rtmsg(RTM_DELETE) == 0) {
3681553Srgrimes		printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
36913977Sphk		return (0);
37013977Sphk	}
37113977Sphk	return (1);
3721553Srgrimes}
3731553Srgrimes
3741553Srgrimes/*
3751553Srgrimes * Dump the entire arp table
3761553Srgrimes */
37713977Sphkvoid
37813977Sphkdump(u_long addr)
3791553Srgrimes{
3801553Srgrimes	int mib[6];
3811553Srgrimes	size_t needed;
3821553Srgrimes	char *host, *malloc(), *lim, *buf, *next;
3831553Srgrimes	struct rt_msghdr *rtm;
3841553Srgrimes	struct sockaddr_inarp *sin;
3851553Srgrimes	struct sockaddr_dl *sdl;
3861553Srgrimes	extern int h_errno;
3871553Srgrimes	struct hostent *hp;
3881553Srgrimes
3891553Srgrimes	mib[0] = CTL_NET;
3901553Srgrimes	mib[1] = PF_ROUTE;
3911553Srgrimes	mib[2] = 0;
3921553Srgrimes	mib[3] = AF_INET;
3931553Srgrimes	mib[4] = NET_RT_FLAGS;
3941553Srgrimes	mib[5] = RTF_LLINFO;
3951553Srgrimes	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
3961553Srgrimes		quit("route-sysctl-estimate");
3971553Srgrimes	if ((buf = malloc(needed)) == NULL)
3981553Srgrimes		quit("malloc");
3991553Srgrimes	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
4001553Srgrimes		quit("actual retrieval of routing table");
4011553Srgrimes	lim = buf + needed;
4021553Srgrimes	for (next = buf; next < lim; next += rtm->rtm_msglen) {
4031553Srgrimes		rtm = (struct rt_msghdr *)next;
4041553Srgrimes		sin = (struct sockaddr_inarp *)(rtm + 1);
4051553Srgrimes		sdl = (struct sockaddr_dl *)(sin + 1);
4061553Srgrimes		if (addr) {
4071553Srgrimes			if (addr != sin->sin_addr.s_addr)
4081553Srgrimes				continue;
4091553Srgrimes			found_entry = 1;
4101553Srgrimes		}
4111553Srgrimes		if (nflag == 0)
4121553Srgrimes			hp = gethostbyaddr((caddr_t)&(sin->sin_addr),
4131553Srgrimes			    sizeof sin->sin_addr, AF_INET);
4141553Srgrimes		else
4151553Srgrimes			hp = 0;
4161553Srgrimes		if (hp)
4171553Srgrimes			host = hp->h_name;
4181553Srgrimes		else {
4191553Srgrimes			host = "?";
4201553Srgrimes			if (h_errno == TRY_AGAIN)
4211553Srgrimes				nflag = 1;
4221553Srgrimes		}
4231553Srgrimes		printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
4241553Srgrimes		if (sdl->sdl_alen)
4251553Srgrimes			ether_print(LLADDR(sdl));
4261553Srgrimes		else
4271553Srgrimes			printf("(incomplete)");
4281553Srgrimes		if (rtm->rtm_rmx.rmx_expire == 0)
4291553Srgrimes			printf(" permanent");
4301553Srgrimes		if (sin->sin_other & SIN_PROXY)
4311553Srgrimes			printf(" published (proxy only)");
4321553Srgrimes		if (rtm->rtm_addrs & RTA_NETMASK) {
4331553Srgrimes			sin = (struct sockaddr_inarp *)
4341553Srgrimes				(sdl->sdl_len + (char *)sdl);
4351553Srgrimes			if (sin->sin_addr.s_addr == 0xffffffff)
4361553Srgrimes				printf(" published");
4371553Srgrimes			if (sin->sin_len != 8)
4381553Srgrimes				printf("(wierd)");
4391553Srgrimes		}
4401553Srgrimes		printf("\n");
4411553Srgrimes	}
4421553Srgrimes}
4431553Srgrimes
44413977Sphkvoid
44513977Sphkether_print(u_char *cp)
4461553Srgrimes{
4471553Srgrimes	printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
4481553Srgrimes}
4491553Srgrimes
45013977Sphkint
45113977Sphkether_aton(char *a, u_char *n)
4521553Srgrimes{
4531553Srgrimes	int i, o[6];
4541553Srgrimes
4551553Srgrimes	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
4561553Srgrimes					   &o[3], &o[4], &o[5]);
4571553Srgrimes	if (i != 6) {
4581553Srgrimes		fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
4591553Srgrimes		return (1);
4601553Srgrimes	}
4611553Srgrimes	for (i=0; i<6; i++)
4621553Srgrimes		n[i] = o[i];
4631553Srgrimes	return (0);
4641553Srgrimes}
4651553Srgrimes
46613977Sphkvoid
46713977Sphkusage(void)
4681553Srgrimes{
4691553Srgrimes	printf("usage: arp hostname\n");
4701553Srgrimes	printf("       arp -a [kernel] [kernel_memory]\n");
4711553Srgrimes	printf("       arp -d hostname\n");
4721553Srgrimes	printf("       arp -s hostname ether_addr [temp] [pub]\n");
47313977Sphk	printf("       arp -S hostname ether_addr [temp] [pub]\n");
4741553Srgrimes	printf("       arp -f filename\n");
4751553Srgrimes	exit(1);
4761553Srgrimes}
4771553Srgrimes
47813977Sphkint
47913977Sphkrtmsg(int cmd)
4801553Srgrimes{
4811553Srgrimes	static int seq;
4821553Srgrimes	int rlen;
4831553Srgrimes	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
4841553Srgrimes	register char *cp = m_rtmsg.m_space;
4851553Srgrimes	register int l;
4861553Srgrimes
4871553Srgrimes	errno = 0;
4881553Srgrimes	if (cmd == RTM_DELETE)
4891553Srgrimes		goto doit;
4901553Srgrimes	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
4911553Srgrimes	rtm->rtm_flags = flags;
4921553Srgrimes	rtm->rtm_version = RTM_VERSION;
4931553Srgrimes
4941553Srgrimes	switch (cmd) {
4951553Srgrimes	default:
4961553Srgrimes		fprintf(stderr, "arp: internal wrong cmd\n");
4971553Srgrimes		exit(1);
4981553Srgrimes	case RTM_ADD:
4991553Srgrimes		rtm->rtm_addrs |= RTA_GATEWAY;
5001553Srgrimes		rtm->rtm_rmx.rmx_expire = expire_time;
5011553Srgrimes		rtm->rtm_inits = RTV_EXPIRE;
5021553Srgrimes		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
5031553Srgrimes		sin_m.sin_other = 0;
5041553Srgrimes		if (doing_proxy) {
5051553Srgrimes			if (export_only)
5061553Srgrimes				sin_m.sin_other = SIN_PROXY;
5071553Srgrimes			else {
5081553Srgrimes				rtm->rtm_addrs |= RTA_NETMASK;
5091553Srgrimes				rtm->rtm_flags &= ~RTF_HOST;
5101553Srgrimes			}
5111553Srgrimes		}
5121553Srgrimes		/* FALLTHROUGH */
5131553Srgrimes	case RTM_GET:
5141553Srgrimes		rtm->rtm_addrs |= RTA_DST;
5151553Srgrimes	}
5161553Srgrimes#define NEXTADDR(w, s) \
5171553Srgrimes	if (rtm->rtm_addrs & (w)) { \
5181553Srgrimes		bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
5191553Srgrimes
5201553Srgrimes	NEXTADDR(RTA_DST, sin_m);
5211553Srgrimes	NEXTADDR(RTA_GATEWAY, sdl_m);
5221553Srgrimes	NEXTADDR(RTA_NETMASK, so_mask);
5231553Srgrimes
5241553Srgrimes	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
5251553Srgrimesdoit:
5261553Srgrimes	l = rtm->rtm_msglen;
5271553Srgrimes	rtm->rtm_seq = ++seq;
5281553Srgrimes	rtm->rtm_type = cmd;
5291553Srgrimes	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
5301553Srgrimes		if (errno != ESRCH || cmd != RTM_DELETE) {
5311553Srgrimes			perror("writing to routing socket");
5321553Srgrimes			return (-1);
5331553Srgrimes		}
5341553Srgrimes	}
5351553Srgrimes	do {
5361553Srgrimes		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
5371553Srgrimes	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
5381553Srgrimes	if (l < 0)
5391553Srgrimes		(void) fprintf(stderr, "arp: read from routing socket: %s\n",
5401553Srgrimes		    strerror(errno));
5411553Srgrimes	return (0);
5421553Srgrimes}
5431553Srgrimes
54413977Sphkvoid
54513977Sphkquit(char *msg)
5461553Srgrimes{
5471553Srgrimes	fprintf(stderr, "%s\n", msg);
5481553Srgrimes	exit(1);
5491553Srgrimes}
55013977Sphk
55113977Sphk/*
55213977Sphk * get_ether_addr - get the hardware address of an interface on the
55313977Sphk * the same subnet as ipaddr.
55413977Sphk */
55513977Sphk#define MAX_IFS		32
55613977Sphk
55713977Sphkint
55813977Sphkget_ether_addr(u_long ipaddr, u_char *hwaddr)
55913977Sphk{
56013977Sphk	struct ifreq *ifr, *ifend, *ifp;
56113977Sphk	u_long ina, mask;
56213977Sphk	struct sockaddr_dl *dla;
56313977Sphk	struct ifreq ifreq;
56413977Sphk	struct ifconf ifc;
56513977Sphk	struct ifreq ifs[MAX_IFS];
56613977Sphk	int s;
56713977Sphk
56813977Sphk	s = socket(AF_INET, SOCK_DGRAM, 0);
56913977Sphk	if (s < 0) {
57013977Sphk		perror("socket");
57113977Sphk		exit(1);
57213977Sphk	}
57313977Sphk
57413977Sphk	ifc.ifc_len = sizeof(ifs);
57513977Sphk	ifc.ifc_req = ifs;
57613977Sphk	if (ioctl(s, SIOCGIFCONF, &ifc) < 0) {
57713977Sphk		fprintf(stderr, "ioctl(SIOCGIFCONF): \n");
57813977Sphk		close(s);
57913977Sphk		return 0;
58013977Sphk	}
58113977Sphk
58213977Sphk	/*
58313977Sphk	* Scan through looking for an interface with an Internet
58413977Sphk	* address on the same subnet as `ipaddr'.
58513977Sphk	*/
58613977Sphk	ifend = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
58713977Sphk	for (ifr = ifc.ifc_req; ifr < ifend; ) {
58813977Sphk		if (ifr->ifr_addr.sa_family == AF_INET) {
58913977Sphk			ina = ((struct sockaddr_in *)
59013977Sphk				&ifr->ifr_addr)->sin_addr.s_addr;
59113977Sphk			strncpy(ifreq.ifr_name, ifr->ifr_name,
59213977Sphk				sizeof(ifreq.ifr_name));
59313977Sphk			/*
59413977Sphk			 * Check that the interface is up,
59513977Sphk			 * and not point-to-point or loopback.
59613977Sphk			 */
59713977Sphk			if (ioctl(s, SIOCGIFFLAGS, &ifreq) < 0)
59813977Sphk				continue;
59913977Sphk			if ((ifreq.ifr_flags &
60013977Sphk			     (IFF_UP|IFF_BROADCAST|IFF_POINTOPOINT|
60113977Sphk					IFF_LOOPBACK|IFF_NOARP))
60213977Sphk			     != (IFF_UP|IFF_BROADCAST))
60313977Sphk				goto nextif;
60413977Sphk			/*
60513977Sphk			 * Get its netmask and check that it's on
60613977Sphk			 * the right subnet.
60713977Sphk			 */
60813977Sphk			if (ioctl(s, SIOCGIFNETMASK, &ifreq) < 0)
60913977Sphk				continue;
61013977Sphk			mask = ((struct sockaddr_in *)
61113977Sphk				&ifreq.ifr_addr)->sin_addr.s_addr;
61213977Sphk			if ((ipaddr & mask) != (ina & mask))
61313977Sphk				goto nextif;
61413977Sphk			break;
61513977Sphk		}
61613977Sphknextif:
61713977Sphk		ifr = (struct ifreq *)
61813977Sphk		    ((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
61913977Sphk	}
62013977Sphk
62113977Sphk	if (ifr >= ifend) {
62213977Sphk		close(s);
62313977Sphk		return 0;
62413977Sphk	}
62513977Sphk
62613977Sphk	/*
62713977Sphk	* Now scan through again looking for a link-level address
62813977Sphk	* for this interface.
62913977Sphk	*/
63013977Sphk	ifp = ifr;
63113977Sphk	for (ifr = ifc.ifc_req; ifr < ifend; ) {
63213977Sphk		if (strcmp(ifp->ifr_name, ifr->ifr_name) == 0
63313977Sphk		    && ifr->ifr_addr.sa_family == AF_LINK) {
63413977Sphk			/*
63513977Sphk			 * Found the link-level address - copy it out
63613977Sphk			 */
63713977Sphk		 	dla = (struct sockaddr_dl *) &ifr->ifr_addr;
63813977Sphk			memcpy(hwaddr,  LLADDR(dla), dla->sdl_alen);
63913977Sphk			close (s);
64013977Sphk			printf("using interface %s for proxy with address ",
64113977Sphk				ifp->ifr_name);
64213977Sphk			ether_print(hwaddr);
64313977Sphk			printf("\n");
64413977Sphk			return dla->sdl_alen;
64513977Sphk		}
64613977Sphk		ifr = (struct ifreq *)
64713977Sphk			((char *)&ifr->ifr_addr + ifr->ifr_addr.sa_len);
64813977Sphk	}
64913977Sphk	return 0;
65013977Sphk}
651