xref: /minix3/usr.sbin/arp/arp.c (revision 04e82b7dc953b4811330afd420ce7f2547aea63f)
1*04e82b7dSDavid van Moolenbroek /*	$NetBSD: arp.c,v 1.53 2015/07/31 04:02:40 ozaki-r Exp $ */
2*04e82b7dSDavid van Moolenbroek 
3*04e82b7dSDavid van Moolenbroek /*
4*04e82b7dSDavid van Moolenbroek  * Copyright (c) 1984, 1993
5*04e82b7dSDavid van Moolenbroek  *	The Regents of the University of California.  All rights reserved.
6*04e82b7dSDavid van Moolenbroek  *
7*04e82b7dSDavid van Moolenbroek  * This code is derived from software contributed to Berkeley by
8*04e82b7dSDavid van Moolenbroek  * Sun Microsystems, Inc.
9*04e82b7dSDavid van Moolenbroek  *
10*04e82b7dSDavid van Moolenbroek  * Redistribution and use in source and binary forms, with or without
11*04e82b7dSDavid van Moolenbroek  * modification, are permitted provided that the following conditions
12*04e82b7dSDavid van Moolenbroek  * are met:
13*04e82b7dSDavid van Moolenbroek  * 1. Redistributions of source code must retain the above copyright
14*04e82b7dSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer.
15*04e82b7dSDavid van Moolenbroek  * 2. Redistributions in binary form must reproduce the above copyright
16*04e82b7dSDavid van Moolenbroek  *    notice, this list of conditions and the following disclaimer in the
17*04e82b7dSDavid van Moolenbroek  *    documentation and/or other materials provided with the distribution.
18*04e82b7dSDavid van Moolenbroek  * 3. Neither the name of the University nor the names of its contributors
19*04e82b7dSDavid van Moolenbroek  *    may be used to endorse or promote products derived from this software
20*04e82b7dSDavid van Moolenbroek  *    without specific prior written permission.
21*04e82b7dSDavid van Moolenbroek  *
22*04e82b7dSDavid van Moolenbroek  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23*04e82b7dSDavid van Moolenbroek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24*04e82b7dSDavid van Moolenbroek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25*04e82b7dSDavid van Moolenbroek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26*04e82b7dSDavid van Moolenbroek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27*04e82b7dSDavid van Moolenbroek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28*04e82b7dSDavid van Moolenbroek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29*04e82b7dSDavid van Moolenbroek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30*04e82b7dSDavid van Moolenbroek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31*04e82b7dSDavid van Moolenbroek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*04e82b7dSDavid van Moolenbroek  * SUCH DAMAGE.
33*04e82b7dSDavid van Moolenbroek  */
34*04e82b7dSDavid van Moolenbroek 
35*04e82b7dSDavid van Moolenbroek #include <sys/cdefs.h>
36*04e82b7dSDavid van Moolenbroek #ifndef lint
37*04e82b7dSDavid van Moolenbroek __COPYRIGHT("@(#) Copyright (c) 1984, 1993\
38*04e82b7dSDavid van Moolenbroek  The Regents of the University of California.  All rights reserved.");
39*04e82b7dSDavid van Moolenbroek #endif /* not lint */
40*04e82b7dSDavid van Moolenbroek 
41*04e82b7dSDavid van Moolenbroek #ifndef lint
42*04e82b7dSDavid van Moolenbroek #if 0
43*04e82b7dSDavid van Moolenbroek static char sccsid[] = "@(#)arp.c	8.3 (Berkeley) 4/28/95";
44*04e82b7dSDavid van Moolenbroek #else
45*04e82b7dSDavid van Moolenbroek __RCSID("$NetBSD: arp.c,v 1.53 2015/07/31 04:02:40 ozaki-r Exp $");
46*04e82b7dSDavid van Moolenbroek #endif
47*04e82b7dSDavid van Moolenbroek #endif /* not lint */
48*04e82b7dSDavid van Moolenbroek 
49*04e82b7dSDavid van Moolenbroek /*
50*04e82b7dSDavid van Moolenbroek  * arp - display, set, and delete arp table entries
51*04e82b7dSDavid van Moolenbroek  */
52*04e82b7dSDavid van Moolenbroek 
53*04e82b7dSDavid van Moolenbroek #include <sys/param.h>
54*04e82b7dSDavid van Moolenbroek #include <sys/file.h>
55*04e82b7dSDavid van Moolenbroek #include <sys/socket.h>
56*04e82b7dSDavid van Moolenbroek #include <sys/sysctl.h>
57*04e82b7dSDavid van Moolenbroek #include <sys/ioctl.h>
58*04e82b7dSDavid van Moolenbroek 
59*04e82b7dSDavid van Moolenbroek #include <net/if.h>
60*04e82b7dSDavid van Moolenbroek #include <net/if_dl.h>
61*04e82b7dSDavid van Moolenbroek #include <net/if_ether.h>
62*04e82b7dSDavid van Moolenbroek #include <net/if_types.h>
63*04e82b7dSDavid van Moolenbroek #include <net/route.h>
64*04e82b7dSDavid van Moolenbroek #include <netinet/in.h>
65*04e82b7dSDavid van Moolenbroek #include <netinet/if_inarp.h>
66*04e82b7dSDavid van Moolenbroek #include <arpa/inet.h>
67*04e82b7dSDavid van Moolenbroek 
68*04e82b7dSDavid van Moolenbroek #include <err.h>
69*04e82b7dSDavid van Moolenbroek #include <errno.h>
70*04e82b7dSDavid van Moolenbroek #include <netdb.h>
71*04e82b7dSDavid van Moolenbroek #include <nlist.h>
72*04e82b7dSDavid van Moolenbroek #include <paths.h>
73*04e82b7dSDavid van Moolenbroek #include <stdio.h>
74*04e82b7dSDavid van Moolenbroek #include <stdlib.h>
75*04e82b7dSDavid van Moolenbroek #include <string.h>
76*04e82b7dSDavid van Moolenbroek #include <unistd.h>
77*04e82b7dSDavid van Moolenbroek #include <ifaddrs.h>
78*04e82b7dSDavid van Moolenbroek 
79*04e82b7dSDavid van Moolenbroek #include "prog_ops.h"
80*04e82b7dSDavid van Moolenbroek 
81*04e82b7dSDavid van Moolenbroek static int is_llinfo(const struct sockaddr_dl *, int);
82*04e82b7dSDavid van Moolenbroek static int delete(const char *, const char *);
83*04e82b7dSDavid van Moolenbroek static void dump(uint32_t);
84*04e82b7dSDavid van Moolenbroek static void delete_all(void);
85*04e82b7dSDavid van Moolenbroek static void sdl_print(const struct sockaddr_dl *);
86*04e82b7dSDavid van Moolenbroek static int getifname(u_int16_t, char *, size_t);
87*04e82b7dSDavid van Moolenbroek static int atosdl(const char *s, struct sockaddr_dl *sdl);
88*04e82b7dSDavid van Moolenbroek static int file(const char *);
89*04e82b7dSDavid van Moolenbroek static void get(const char *);
90*04e82b7dSDavid van Moolenbroek static int getinetaddr(const char *, struct in_addr *);
91*04e82b7dSDavid van Moolenbroek static int getsocket(void);
92*04e82b7dSDavid van Moolenbroek static struct rt_msghdr *
93*04e82b7dSDavid van Moolenbroek 	rtmsg(const int, const int, const struct sockaddr_inarp *,
94*04e82b7dSDavid van Moolenbroek 	    const struct sockaddr_dl *);
95*04e82b7dSDavid van Moolenbroek static int set(int, char **);
96*04e82b7dSDavid van Moolenbroek static void usage(void) __dead;
97*04e82b7dSDavid van Moolenbroek 
98*04e82b7dSDavid van Moolenbroek static int aflag, nflag, vflag;
99*04e82b7dSDavid van Moolenbroek static struct sockaddr_in so_mask = {
100*04e82b7dSDavid van Moolenbroek 	.sin_len = 8,
101*04e82b7dSDavid van Moolenbroek 	.sin_addr = {
102*04e82b7dSDavid van Moolenbroek 		.s_addr = 0xffffffff
103*04e82b7dSDavid van Moolenbroek 	}
104*04e82b7dSDavid van Moolenbroek };
105*04e82b7dSDavid van Moolenbroek static struct sockaddr_inarp blank_sin = {
106*04e82b7dSDavid van Moolenbroek 	.sin_len = sizeof(blank_sin),
107*04e82b7dSDavid van Moolenbroek 	.sin_family = AF_INET
108*04e82b7dSDavid van Moolenbroek };
109*04e82b7dSDavid van Moolenbroek static struct sockaddr_dl blank_sdl = {
110*04e82b7dSDavid van Moolenbroek 	.sdl_len = sizeof(blank_sdl),
111*04e82b7dSDavid van Moolenbroek 	.sdl_family = AF_LINK
112*04e82b7dSDavid van Moolenbroek };
113*04e82b7dSDavid van Moolenbroek 
114*04e82b7dSDavid van Moolenbroek static int expire_time, flags, export_only, doing_proxy, found_entry;
115*04e82b7dSDavid van Moolenbroek 
116*04e82b7dSDavid van Moolenbroek int
main(int argc,char ** argv)117*04e82b7dSDavid van Moolenbroek main(int argc, char **argv)
118*04e82b7dSDavid van Moolenbroek {
119*04e82b7dSDavid van Moolenbroek 	int ch;
120*04e82b7dSDavid van Moolenbroek 	int op = 0;
121*04e82b7dSDavid van Moolenbroek 
122*04e82b7dSDavid van Moolenbroek 	setprogname(argv[0]);
123*04e82b7dSDavid van Moolenbroek 
124*04e82b7dSDavid van Moolenbroek 	while ((ch = getopt(argc, argv, "andsfv")) != -1)
125*04e82b7dSDavid van Moolenbroek 		switch((char)ch) {
126*04e82b7dSDavid van Moolenbroek 		case 'a':
127*04e82b7dSDavid van Moolenbroek 			aflag = 1;
128*04e82b7dSDavid van Moolenbroek 			break;
129*04e82b7dSDavid van Moolenbroek 		case 'd':
130*04e82b7dSDavid van Moolenbroek 		case 's':
131*04e82b7dSDavid van Moolenbroek 		case 'f':
132*04e82b7dSDavid van Moolenbroek 			if (op)
133*04e82b7dSDavid van Moolenbroek 				usage();
134*04e82b7dSDavid van Moolenbroek 			op = ch;
135*04e82b7dSDavid van Moolenbroek 			break;
136*04e82b7dSDavid van Moolenbroek 		case 'n':
137*04e82b7dSDavid van Moolenbroek 			nflag = 1;
138*04e82b7dSDavid van Moolenbroek 			break;
139*04e82b7dSDavid van Moolenbroek 		case 'v':
140*04e82b7dSDavid van Moolenbroek 			vflag = 1;
141*04e82b7dSDavid van Moolenbroek 			break;
142*04e82b7dSDavid van Moolenbroek 		default:
143*04e82b7dSDavid van Moolenbroek 			usage();
144*04e82b7dSDavid van Moolenbroek 		}
145*04e82b7dSDavid van Moolenbroek 	argc -= optind;
146*04e82b7dSDavid van Moolenbroek 	argv += optind;
147*04e82b7dSDavid van Moolenbroek 
148*04e82b7dSDavid van Moolenbroek 	if (!op && aflag)
149*04e82b7dSDavid van Moolenbroek 		op = 'a';
150*04e82b7dSDavid van Moolenbroek 
151*04e82b7dSDavid van Moolenbroek 	if (prog_init && prog_init() == -1)
152*04e82b7dSDavid van Moolenbroek 		err(1, "init failed");
153*04e82b7dSDavid van Moolenbroek 
154*04e82b7dSDavid van Moolenbroek 	switch((char)op) {
155*04e82b7dSDavid van Moolenbroek 	case 'a':
156*04e82b7dSDavid van Moolenbroek 		dump(0);
157*04e82b7dSDavid van Moolenbroek 		break;
158*04e82b7dSDavid van Moolenbroek 	case 'd':
159*04e82b7dSDavid van Moolenbroek 		if (aflag && argc == 0)
160*04e82b7dSDavid van Moolenbroek 			delete_all();
161*04e82b7dSDavid van Moolenbroek 		else {
162*04e82b7dSDavid van Moolenbroek 			if (aflag || argc < 1 || argc > 2)
163*04e82b7dSDavid van Moolenbroek 				usage();
164*04e82b7dSDavid van Moolenbroek 			(void)delete(argv[0], argv[1]);
165*04e82b7dSDavid van Moolenbroek 		}
166*04e82b7dSDavid van Moolenbroek 		break;
167*04e82b7dSDavid van Moolenbroek 	case 's':
168*04e82b7dSDavid van Moolenbroek 		if (argc < 2 || argc > 7)
169*04e82b7dSDavid van Moolenbroek 			usage();
170*04e82b7dSDavid van Moolenbroek 		return (set(argc, argv) ? 1 : 0);
171*04e82b7dSDavid van Moolenbroek 	case 'f':
172*04e82b7dSDavid van Moolenbroek 		if (argc != 1)
173*04e82b7dSDavid van Moolenbroek 			usage();
174*04e82b7dSDavid van Moolenbroek 		return (file(argv[0]));
175*04e82b7dSDavid van Moolenbroek 	default:
176*04e82b7dSDavid van Moolenbroek 		if (argc != 1)
177*04e82b7dSDavid van Moolenbroek 			usage();
178*04e82b7dSDavid van Moolenbroek 		get(argv[0]);
179*04e82b7dSDavid van Moolenbroek 		break;
180*04e82b7dSDavid van Moolenbroek 	}
181*04e82b7dSDavid van Moolenbroek 	return (0);
182*04e82b7dSDavid van Moolenbroek }
183*04e82b7dSDavid van Moolenbroek 
184*04e82b7dSDavid van Moolenbroek /*
185*04e82b7dSDavid van Moolenbroek  * Process a file to set standard arp entries
186*04e82b7dSDavid van Moolenbroek  */
187*04e82b7dSDavid van Moolenbroek static int
file(const char * name)188*04e82b7dSDavid van Moolenbroek file(const char *name)
189*04e82b7dSDavid van Moolenbroek {
190*04e82b7dSDavid van Moolenbroek 	char *line, *argv[5];
191*04e82b7dSDavid van Moolenbroek 	int i, retval;
192*04e82b7dSDavid van Moolenbroek 	FILE *fp;
193*04e82b7dSDavid van Moolenbroek 
194*04e82b7dSDavid van Moolenbroek 	if (!strcmp(name, "-")) {
195*04e82b7dSDavid van Moolenbroek 		fp = stdin;
196*04e82b7dSDavid van Moolenbroek 	} else {
197*04e82b7dSDavid van Moolenbroek 		fp = fopen(name, "r");
198*04e82b7dSDavid van Moolenbroek 		if (fp == NULL) {
199*04e82b7dSDavid van Moolenbroek 			err(1, "Cannot open %s", name);
200*04e82b7dSDavid van Moolenbroek 		}
201*04e82b7dSDavid van Moolenbroek 	}
202*04e82b7dSDavid van Moolenbroek 	retval = 0;
203*04e82b7dSDavid van Moolenbroek 	for (; (line = fparseln(fp, NULL, NULL, NULL, 0)) != NULL; free(line)) {
204*04e82b7dSDavid van Moolenbroek 		char **ap, *inputstring;
205*04e82b7dSDavid van Moolenbroek 
206*04e82b7dSDavid van Moolenbroek 		inputstring = line;
207*04e82b7dSDavid van Moolenbroek 		for (ap = argv; ap < &argv[sizeof(argv) / sizeof(argv[0])] &&
208*04e82b7dSDavid van Moolenbroek 		    (*ap = stresep(&inputstring, " \t", '\\')) != NULL;) {
209*04e82b7dSDavid van Moolenbroek 		       if (**ap != '\0')
210*04e82b7dSDavid van Moolenbroek 				ap++;
211*04e82b7dSDavid van Moolenbroek 		}
212*04e82b7dSDavid van Moolenbroek 		i = ap - argv;
213*04e82b7dSDavid van Moolenbroek 		if (i < 2) {
214*04e82b7dSDavid van Moolenbroek 			warnx("bad line: %s", line);
215*04e82b7dSDavid van Moolenbroek 			retval = 1;
216*04e82b7dSDavid van Moolenbroek 			continue;
217*04e82b7dSDavid van Moolenbroek 		}
218*04e82b7dSDavid van Moolenbroek 		if (set(i, argv))
219*04e82b7dSDavid van Moolenbroek 			retval = 1;
220*04e82b7dSDavid van Moolenbroek 	}
221*04e82b7dSDavid van Moolenbroek 	if (fp != stdin)
222*04e82b7dSDavid van Moolenbroek 		(void)fclose(fp);
223*04e82b7dSDavid van Moolenbroek 	return retval;
224*04e82b7dSDavid van Moolenbroek }
225*04e82b7dSDavid van Moolenbroek 
226*04e82b7dSDavid van Moolenbroek static int
getsocket(void)227*04e82b7dSDavid van Moolenbroek getsocket(void)
228*04e82b7dSDavid van Moolenbroek {
229*04e82b7dSDavid van Moolenbroek 	int s;
230*04e82b7dSDavid van Moolenbroek 	s = prog_socket(PF_ROUTE, SOCK_RAW, 0);
231*04e82b7dSDavid van Moolenbroek 	if (s < 0)
232*04e82b7dSDavid van Moolenbroek 		err(1, "socket");
233*04e82b7dSDavid van Moolenbroek 	return s;
234*04e82b7dSDavid van Moolenbroek }
235*04e82b7dSDavid van Moolenbroek 
236*04e82b7dSDavid van Moolenbroek static int
getlink(const char * name,struct sockaddr_dl * sdl)237*04e82b7dSDavid van Moolenbroek getlink(const char *name, struct sockaddr_dl *sdl)
238*04e82b7dSDavid van Moolenbroek {
239*04e82b7dSDavid van Moolenbroek 	struct ifaddrs *ifap, *ifa;
240*04e82b7dSDavid van Moolenbroek 
241*04e82b7dSDavid van Moolenbroek 	if (getifaddrs(&ifap) != 0) {
242*04e82b7dSDavid van Moolenbroek 		warn("getifaddrs");
243*04e82b7dSDavid van Moolenbroek 		return 0;
244*04e82b7dSDavid van Moolenbroek 	}
245*04e82b7dSDavid van Moolenbroek 
246*04e82b7dSDavid van Moolenbroek 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
247*04e82b7dSDavid van Moolenbroek 		if (ifa->ifa_addr->sa_family != AF_LINK)
248*04e82b7dSDavid van Moolenbroek 			continue;
249*04e82b7dSDavid van Moolenbroek 		if (strcmp(ifa->ifa_name, name) != 0)
250*04e82b7dSDavid van Moolenbroek 			continue;
251*04e82b7dSDavid van Moolenbroek 		memcpy(sdl, ifa->ifa_addr, sizeof(*sdl));
252*04e82b7dSDavid van Moolenbroek 		freeifaddrs(ifap);
253*04e82b7dSDavid van Moolenbroek 		return 1;
254*04e82b7dSDavid van Moolenbroek 	}
255*04e82b7dSDavid van Moolenbroek 	freeifaddrs(ifap);
256*04e82b7dSDavid van Moolenbroek 	return 0;
257*04e82b7dSDavid van Moolenbroek }
258*04e82b7dSDavid van Moolenbroek 
259*04e82b7dSDavid van Moolenbroek /*
260*04e82b7dSDavid van Moolenbroek  * Set an individual arp entry
261*04e82b7dSDavid van Moolenbroek  */
262*04e82b7dSDavid van Moolenbroek static int
set(int argc,char ** argv)263*04e82b7dSDavid van Moolenbroek set(int argc, char **argv)
264*04e82b7dSDavid van Moolenbroek {
265*04e82b7dSDavid van Moolenbroek 	struct sockaddr_inarp *sina;
266*04e82b7dSDavid van Moolenbroek 	struct sockaddr_dl *sdl;
267*04e82b7dSDavid van Moolenbroek 	struct rt_msghdr *rtm;
268*04e82b7dSDavid van Moolenbroek 	char *host = argv[0], *eaddr;
269*04e82b7dSDavid van Moolenbroek 	struct sockaddr_inarp sin_m = blank_sin; /* struct copy */
270*04e82b7dSDavid van Moolenbroek 	struct sockaddr_dl sdl_m = blank_sdl; /* struct copy */
271*04e82b7dSDavid van Moolenbroek 	int s;
272*04e82b7dSDavid van Moolenbroek 
273*04e82b7dSDavid van Moolenbroek 	eaddr = argv[1];
274*04e82b7dSDavid van Moolenbroek 
275*04e82b7dSDavid van Moolenbroek 	s = getsocket();
276*04e82b7dSDavid van Moolenbroek 	argc -= 2;
277*04e82b7dSDavid van Moolenbroek 	argv += 2;
278*04e82b7dSDavid van Moolenbroek 
279*04e82b7dSDavid van Moolenbroek 	if (getinetaddr(host, &sin_m.sin_addr) == -1)
280*04e82b7dSDavid van Moolenbroek 		return (1);
281*04e82b7dSDavid van Moolenbroek 	if (atosdl(eaddr, &sdl_m))
282*04e82b7dSDavid van Moolenbroek 		warnx("invalid link-level address '%s'", eaddr);
283*04e82b7dSDavid van Moolenbroek 	doing_proxy = flags = export_only = expire_time = 0;
284*04e82b7dSDavid van Moolenbroek 	for (; argc-- > 0; argv++) {
285*04e82b7dSDavid van Moolenbroek 		if (strncmp(argv[0], "temp", 4) == 0) {
286*04e82b7dSDavid van Moolenbroek 			struct timeval timev;
287*04e82b7dSDavid van Moolenbroek 			(void)gettimeofday(&timev, 0);
288*04e82b7dSDavid van Moolenbroek 			expire_time = timev.tv_sec + 20 * 60;
289*04e82b7dSDavid van Moolenbroek 		}
290*04e82b7dSDavid van Moolenbroek 		else if (strncmp(argv[0], "pub", 3) == 0) {
291*04e82b7dSDavid van Moolenbroek 			flags |= RTF_ANNOUNCE;
292*04e82b7dSDavid van Moolenbroek 			doing_proxy = SIN_PROXY;
293*04e82b7dSDavid van Moolenbroek 			if (argc && strncmp(argv[1], "pro", 3) == 0) {
294*04e82b7dSDavid van Moolenbroek 			        export_only = 1;
295*04e82b7dSDavid van Moolenbroek 			        argc--; argv++;
296*04e82b7dSDavid van Moolenbroek 			}
297*04e82b7dSDavid van Moolenbroek 		} else if (strncmp(argv[0], "trail", 5) == 0) {
298*04e82b7dSDavid van Moolenbroek 			warnx("%s: Sending trailers is no longer supported",
299*04e82b7dSDavid van Moolenbroek 			    host);
300*04e82b7dSDavid van Moolenbroek 		} else if (strcmp(argv[0], "ifscope") == 0) {
301*04e82b7dSDavid van Moolenbroek 			if (argc == 0) {
302*04e82b7dSDavid van Moolenbroek 				warnx("missing interface for ifscope");
303*04e82b7dSDavid van Moolenbroek 				continue;
304*04e82b7dSDavid van Moolenbroek 			}
305*04e82b7dSDavid van Moolenbroek 			argc--;
306*04e82b7dSDavid van Moolenbroek 			argv++;
307*04e82b7dSDavid van Moolenbroek 			if (!getlink(argv[0], &sdl_m))
308*04e82b7dSDavid van Moolenbroek 				warnx("cannot get link address for %s", argv[0]);
309*04e82b7dSDavid van Moolenbroek 		}
310*04e82b7dSDavid van Moolenbroek 
311*04e82b7dSDavid van Moolenbroek 	}
312*04e82b7dSDavid van Moolenbroek 	if (memcmp(&sdl_m, &blank_sdl, sizeof(blank_sdl)))
313*04e82b7dSDavid van Moolenbroek 		goto out;
314*04e82b7dSDavid van Moolenbroek tryagain:
315*04e82b7dSDavid van Moolenbroek 	rtm = rtmsg(s, RTM_GET, &sin_m, &sdl_m);
316*04e82b7dSDavid van Moolenbroek 	if (rtm == NULL) {
317*04e82b7dSDavid van Moolenbroek 		warn("%s", host);
318*04e82b7dSDavid van Moolenbroek 		return (1);
319*04e82b7dSDavid van Moolenbroek 	}
320*04e82b7dSDavid van Moolenbroek 	sina = (struct sockaddr_inarp *)(void *)(rtm + 1);
321*04e82b7dSDavid van Moolenbroek 	sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(sina->sin_len) +
322*04e82b7dSDavid van Moolenbroek 	    (char *)(void *)sina);
323*04e82b7dSDavid van Moolenbroek 	if (sina->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
324*04e82b7dSDavid van Moolenbroek 		if (is_llinfo(sdl, rtm->rtm_flags))
325*04e82b7dSDavid van Moolenbroek 			goto overwrite;
326*04e82b7dSDavid van Moolenbroek 		if (doing_proxy == 0) {
327*04e82b7dSDavid van Moolenbroek 			warnx("set: can only proxy for %s", host);
328*04e82b7dSDavid van Moolenbroek 			return (1);
329*04e82b7dSDavid van Moolenbroek 		}
330*04e82b7dSDavid van Moolenbroek 		if (sin_m.sin_other & SIN_PROXY) {
331*04e82b7dSDavid van Moolenbroek 			warnx("set: proxy entry exists for non 802 device");
332*04e82b7dSDavid van Moolenbroek 			return (1);
333*04e82b7dSDavid van Moolenbroek 		}
334*04e82b7dSDavid van Moolenbroek 		sin_m.sin_other = SIN_PROXY;
335*04e82b7dSDavid van Moolenbroek 		export_only = 1;
336*04e82b7dSDavid van Moolenbroek 		goto tryagain;
337*04e82b7dSDavid van Moolenbroek 	}
338*04e82b7dSDavid van Moolenbroek overwrite:
339*04e82b7dSDavid van Moolenbroek 	if (sdl->sdl_family != AF_LINK) {
340*04e82b7dSDavid van Moolenbroek 		warnx("cannot intuit interface index and type for %s",
341*04e82b7dSDavid van Moolenbroek 		    host);
342*04e82b7dSDavid van Moolenbroek 		return (1);
343*04e82b7dSDavid van Moolenbroek 	}
344*04e82b7dSDavid van Moolenbroek 	sdl_m.sdl_type = sdl->sdl_type;
345*04e82b7dSDavid van Moolenbroek 	sdl_m.sdl_index = sdl->sdl_index;
346*04e82b7dSDavid van Moolenbroek out:
347*04e82b7dSDavid van Moolenbroek 	sin_m.sin_other = 0;
348*04e82b7dSDavid van Moolenbroek 	if (doing_proxy && export_only)
349*04e82b7dSDavid van Moolenbroek 		sin_m.sin_other = SIN_PROXY;
350*04e82b7dSDavid van Moolenbroek 	rtm = rtmsg(s, RTM_ADD, &sin_m, &sdl_m);
351*04e82b7dSDavid van Moolenbroek 	if (vflag)
352*04e82b7dSDavid van Moolenbroek 		(void)printf("%s (%s) added\n", host, eaddr);
353*04e82b7dSDavid van Moolenbroek 	return (rtm == NULL) ? 1 : 0;
354*04e82b7dSDavid van Moolenbroek }
355*04e82b7dSDavid van Moolenbroek 
356*04e82b7dSDavid van Moolenbroek /*
357*04e82b7dSDavid van Moolenbroek  * Display an individual arp entry
358*04e82b7dSDavid van Moolenbroek  */
359*04e82b7dSDavid van Moolenbroek static void
get(const char * host)360*04e82b7dSDavid van Moolenbroek get(const char *host)
361*04e82b7dSDavid van Moolenbroek {
362*04e82b7dSDavid van Moolenbroek 	struct sockaddr_inarp sin = blank_sin; /* struct copy */
363*04e82b7dSDavid van Moolenbroek 
364*04e82b7dSDavid van Moolenbroek 	if (getinetaddr(host, &sin.sin_addr) == -1)
365*04e82b7dSDavid van Moolenbroek 		exit(1);
366*04e82b7dSDavid van Moolenbroek 	dump(sin.sin_addr.s_addr);
367*04e82b7dSDavid van Moolenbroek 	if (found_entry == 0)
368*04e82b7dSDavid van Moolenbroek 		errx(1, "%s (%s) -- no entry", host, inet_ntoa(sin.sin_addr));
369*04e82b7dSDavid van Moolenbroek }
370*04e82b7dSDavid van Moolenbroek 
371*04e82b7dSDavid van Moolenbroek 
372*04e82b7dSDavid van Moolenbroek static int
is_llinfo(const struct sockaddr_dl * sdl,int rtflags)373*04e82b7dSDavid van Moolenbroek is_llinfo(const struct sockaddr_dl *sdl, int rtflags)
374*04e82b7dSDavid van Moolenbroek {
375*04e82b7dSDavid van Moolenbroek 	if (sdl->sdl_family != AF_LINK ||
376*04e82b7dSDavid van Moolenbroek 	    (rtflags & (RTF_LLINFO|RTF_GATEWAY)) != RTF_LLINFO)
377*04e82b7dSDavid van Moolenbroek 		return 0;
378*04e82b7dSDavid van Moolenbroek 
379*04e82b7dSDavid van Moolenbroek 	switch (sdl->sdl_type) {
380*04e82b7dSDavid van Moolenbroek 	case IFT_ETHER:
381*04e82b7dSDavid van Moolenbroek 	case IFT_FDDI:
382*04e82b7dSDavid van Moolenbroek 	case IFT_ISO88023:
383*04e82b7dSDavid van Moolenbroek 	case IFT_ISO88024:
384*04e82b7dSDavid van Moolenbroek 	case IFT_ISO88025:
385*04e82b7dSDavid van Moolenbroek 	case IFT_ARCNET:
386*04e82b7dSDavid van Moolenbroek 		return 1;
387*04e82b7dSDavid van Moolenbroek 	default:
388*04e82b7dSDavid van Moolenbroek 		return 0;
389*04e82b7dSDavid van Moolenbroek 	}
390*04e82b7dSDavid van Moolenbroek }
391*04e82b7dSDavid van Moolenbroek 
392*04e82b7dSDavid van Moolenbroek /*
393*04e82b7dSDavid van Moolenbroek  * Delete an arp entry
394*04e82b7dSDavid van Moolenbroek  */
395*04e82b7dSDavid van Moolenbroek int
delete(const char * host,const char * info)396*04e82b7dSDavid van Moolenbroek delete(const char *host, const char *info)
397*04e82b7dSDavid van Moolenbroek {
398*04e82b7dSDavid van Moolenbroek 	struct sockaddr_inarp *sina;
399*04e82b7dSDavid van Moolenbroek 	struct sockaddr_dl *sdl;
400*04e82b7dSDavid van Moolenbroek 	struct rt_msghdr *rtm;
401*04e82b7dSDavid van Moolenbroek 	struct sockaddr_inarp sin_m = blank_sin; /* struct copy */
402*04e82b7dSDavid van Moolenbroek 	struct sockaddr_dl sdl_m = blank_sdl; /* struct copy */
403*04e82b7dSDavid van Moolenbroek 	int s;
404*04e82b7dSDavid van Moolenbroek 
405*04e82b7dSDavid van Moolenbroek 	s = getsocket();
406*04e82b7dSDavid van Moolenbroek 	if (info && strncmp(info, "pro", 3) == 0)
407*04e82b7dSDavid van Moolenbroek 		 sin_m.sin_other = SIN_PROXY;
408*04e82b7dSDavid van Moolenbroek 	if (getinetaddr(host, &sin_m.sin_addr) == -1)
409*04e82b7dSDavid van Moolenbroek 		return (1);
410*04e82b7dSDavid van Moolenbroek tryagain:
411*04e82b7dSDavid van Moolenbroek 	rtm = rtmsg(s, RTM_GET, &sin_m, &sdl_m);
412*04e82b7dSDavid van Moolenbroek 	if (rtm == NULL) {
413*04e82b7dSDavid van Moolenbroek 		warn("%s", host);
414*04e82b7dSDavid van Moolenbroek 		return (1);
415*04e82b7dSDavid van Moolenbroek 	}
416*04e82b7dSDavid van Moolenbroek 	sina = (struct sockaddr_inarp *)(void *)(rtm + 1);
417*04e82b7dSDavid van Moolenbroek 	sdl = (struct sockaddr_dl *)(void *)(RT_ROUNDUP(sina->sin_len) +
418*04e82b7dSDavid van Moolenbroek 	    (char *)(void *)sina);
419*04e82b7dSDavid van Moolenbroek 	if (sina->sin_addr.s_addr == sin_m.sin_addr.s_addr &&
420*04e82b7dSDavid van Moolenbroek 	    is_llinfo(sdl, rtm->rtm_flags))
421*04e82b7dSDavid van Moolenbroek 		goto delete;
422*04e82b7dSDavid van Moolenbroek 	if (sin_m.sin_other & SIN_PROXY) {
423*04e82b7dSDavid van Moolenbroek 		warnx("delete: can't locate %s", host);
424*04e82b7dSDavid van Moolenbroek 		return (1);
425*04e82b7dSDavid van Moolenbroek 	} else {
426*04e82b7dSDavid van Moolenbroek 		sin_m.sin_other = SIN_PROXY;
427*04e82b7dSDavid van Moolenbroek 		goto tryagain;
428*04e82b7dSDavid van Moolenbroek 	}
429*04e82b7dSDavid van Moolenbroek delete:
430*04e82b7dSDavid van Moolenbroek 	if (sdl->sdl_family != AF_LINK) {
431*04e82b7dSDavid van Moolenbroek 		(void)warnx("cannot locate %s", host);
432*04e82b7dSDavid van Moolenbroek 		return (1);
433*04e82b7dSDavid van Moolenbroek 	}
434*04e82b7dSDavid van Moolenbroek 	rtm = rtmsg(s, RTM_DELETE, &sin_m, sdl);
435*04e82b7dSDavid van Moolenbroek 	if (rtm == NULL)
436*04e82b7dSDavid van Moolenbroek 		return (1);
437*04e82b7dSDavid van Moolenbroek 	if (vflag)
438*04e82b7dSDavid van Moolenbroek 		(void)printf("%s (%s) deleted\n", host,
439*04e82b7dSDavid van Moolenbroek 		    inet_ntoa(sin_m.sin_addr));
440*04e82b7dSDavid van Moolenbroek 	return (0);
441*04e82b7dSDavid van Moolenbroek }
442*04e82b7dSDavid van Moolenbroek 
443*04e82b7dSDavid van Moolenbroek /*
444*04e82b7dSDavid van Moolenbroek  * Dump the entire arp table
445*04e82b7dSDavid van Moolenbroek  */
446*04e82b7dSDavid van Moolenbroek void
dump(uint32_t addr)447*04e82b7dSDavid van Moolenbroek dump(uint32_t addr)
448*04e82b7dSDavid van Moolenbroek {
449*04e82b7dSDavid van Moolenbroek 	int mib[6];
450*04e82b7dSDavid van Moolenbroek 	size_t needed;
451*04e82b7dSDavid van Moolenbroek 	char ifname[IFNAMSIZ];
452*04e82b7dSDavid van Moolenbroek 	char *lim, *buf, *next;
453*04e82b7dSDavid van Moolenbroek         const char *host;
454*04e82b7dSDavid van Moolenbroek 	struct rt_msghdr *rtm;
455*04e82b7dSDavid van Moolenbroek 	struct sockaddr_inarp *sina;
456*04e82b7dSDavid van Moolenbroek 	struct sockaddr_dl *sdl;
457*04e82b7dSDavid van Moolenbroek 	struct hostent *hp;
458*04e82b7dSDavid van Moolenbroek 
459*04e82b7dSDavid van Moolenbroek 	mib[0] = CTL_NET;
460*04e82b7dSDavid van Moolenbroek 	mib[1] = PF_ROUTE;
461*04e82b7dSDavid van Moolenbroek 	mib[2] = 0;
462*04e82b7dSDavid van Moolenbroek 	mib[3] = AF_INET;
463*04e82b7dSDavid van Moolenbroek 	mib[4] = NET_RT_FLAGS;
464*04e82b7dSDavid van Moolenbroek 	mib[5] = RTF_LLINFO;
465*04e82b7dSDavid van Moolenbroek 	if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
466*04e82b7dSDavid van Moolenbroek 		err(1, "route-sysctl-estimate");
467*04e82b7dSDavid van Moolenbroek 	if (needed == 0)
468*04e82b7dSDavid van Moolenbroek 		return;
469*04e82b7dSDavid van Moolenbroek 	if ((buf = malloc(needed)) == NULL)
470*04e82b7dSDavid van Moolenbroek 		err(1, "malloc");
471*04e82b7dSDavid van Moolenbroek 	if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
472*04e82b7dSDavid van Moolenbroek 		err(1, "actual retrieval of routing table");
473*04e82b7dSDavid van Moolenbroek 	lim = buf + needed;
474*04e82b7dSDavid van Moolenbroek 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
475*04e82b7dSDavid van Moolenbroek 		rtm = (struct rt_msghdr *)(void *)next;
476*04e82b7dSDavid van Moolenbroek 		sina = (struct sockaddr_inarp *)(void *)(rtm + 1);
477*04e82b7dSDavid van Moolenbroek 		sdl = (struct sockaddr_dl *)(void *)
478*04e82b7dSDavid van Moolenbroek 		    (RT_ROUNDUP(sina->sin_len) + (char *)(void *)sina);
479*04e82b7dSDavid van Moolenbroek 		if (addr) {
480*04e82b7dSDavid van Moolenbroek 			if (addr != sina->sin_addr.s_addr)
481*04e82b7dSDavid van Moolenbroek 				continue;
482*04e82b7dSDavid van Moolenbroek 			found_entry = 1;
483*04e82b7dSDavid van Moolenbroek 		}
484*04e82b7dSDavid van Moolenbroek 		if (nflag == 0)
485*04e82b7dSDavid van Moolenbroek 			hp = gethostbyaddr((const char *)(void *)
486*04e82b7dSDavid van Moolenbroek 			    &(sina->sin_addr),
487*04e82b7dSDavid van Moolenbroek 			    sizeof sina->sin_addr, AF_INET);
488*04e82b7dSDavid van Moolenbroek 		else
489*04e82b7dSDavid van Moolenbroek 			hp = NULL;
490*04e82b7dSDavid van Moolenbroek 
491*04e82b7dSDavid van Moolenbroek 		host = hp ? hp->h_name : "?";
492*04e82b7dSDavid van Moolenbroek 
493*04e82b7dSDavid van Moolenbroek 		(void)printf("%s (%s) at ", host, inet_ntoa(sina->sin_addr));
494*04e82b7dSDavid van Moolenbroek 		if (sdl->sdl_alen)
495*04e82b7dSDavid van Moolenbroek 			sdl_print(sdl);
496*04e82b7dSDavid van Moolenbroek 		else
497*04e82b7dSDavid van Moolenbroek 			(void)printf("(incomplete)");
498*04e82b7dSDavid van Moolenbroek 
499*04e82b7dSDavid van Moolenbroek 		if (sdl->sdl_index) {
500*04e82b7dSDavid van Moolenbroek 			if (getifname(sdl->sdl_index, ifname, sizeof(ifname)) == 0)
501*04e82b7dSDavid van Moolenbroek 				(void)printf(" on %s", ifname);
502*04e82b7dSDavid van Moolenbroek 		}
503*04e82b7dSDavid van Moolenbroek 
504*04e82b7dSDavid van Moolenbroek 		if (rtm->rtm_rmx.rmx_expire == 0)
505*04e82b7dSDavid van Moolenbroek 			(void)printf(" permanent");
506*04e82b7dSDavid van Moolenbroek 		if (sina->sin_other & SIN_PROXY)
507*04e82b7dSDavid van Moolenbroek 			(void)printf(" published (proxy only)");
508*04e82b7dSDavid van Moolenbroek 		if (rtm->rtm_addrs & RTA_NETMASK) {
509*04e82b7dSDavid van Moolenbroek 			sina = (struct sockaddr_inarp *)(void *)
510*04e82b7dSDavid van Moolenbroek 			    (RT_ROUNDUP(sdl->sdl_len) + (char *)(void *)sdl);
511*04e82b7dSDavid van Moolenbroek 			if (sina->sin_addr.s_addr == 0xffffffff)
512*04e82b7dSDavid van Moolenbroek 				(void)printf(" published");
513*04e82b7dSDavid van Moolenbroek 			if (sina->sin_len != 8)
514*04e82b7dSDavid van Moolenbroek 				(void)printf("(weird)");
515*04e82b7dSDavid van Moolenbroek 		}
516*04e82b7dSDavid van Moolenbroek 		(void)printf("\n");
517*04e82b7dSDavid van Moolenbroek 	}
518*04e82b7dSDavid van Moolenbroek 	free(buf);
519*04e82b7dSDavid van Moolenbroek }
520*04e82b7dSDavid van Moolenbroek 
521*04e82b7dSDavid van Moolenbroek /*
522*04e82b7dSDavid van Moolenbroek  * Delete the entire arp table
523*04e82b7dSDavid van Moolenbroek  */
524*04e82b7dSDavid van Moolenbroek void
delete_all(void)525*04e82b7dSDavid van Moolenbroek delete_all(void)
526*04e82b7dSDavid van Moolenbroek {
527*04e82b7dSDavid van Moolenbroek 	int mib[6];
528*04e82b7dSDavid van Moolenbroek 	size_t needed;
529*04e82b7dSDavid van Moolenbroek 	char addr[sizeof("000.000.000.000\0")];
530*04e82b7dSDavid van Moolenbroek 	char *lim, *buf, *next;
531*04e82b7dSDavid van Moolenbroek 	struct rt_msghdr *rtm;
532*04e82b7dSDavid van Moolenbroek 	struct sockaddr_inarp *sina;
533*04e82b7dSDavid van Moolenbroek 
534*04e82b7dSDavid van Moolenbroek 	mib[0] = CTL_NET;
535*04e82b7dSDavid van Moolenbroek 	mib[1] = PF_ROUTE;
536*04e82b7dSDavid van Moolenbroek 	mib[2] = 0;
537*04e82b7dSDavid van Moolenbroek 	mib[3] = AF_INET;
538*04e82b7dSDavid van Moolenbroek 	mib[4] = NET_RT_FLAGS;
539*04e82b7dSDavid van Moolenbroek 	mib[5] = RTF_LLINFO;
540*04e82b7dSDavid van Moolenbroek 	if (prog_sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
541*04e82b7dSDavid van Moolenbroek 		err(1, "route-sysctl-estimate");
542*04e82b7dSDavid van Moolenbroek 	if (needed == 0)
543*04e82b7dSDavid van Moolenbroek 		return;
544*04e82b7dSDavid van Moolenbroek 	if ((buf = malloc(needed)) == NULL)
545*04e82b7dSDavid van Moolenbroek 		err(1, "malloc");
546*04e82b7dSDavid van Moolenbroek 	if (prog_sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
547*04e82b7dSDavid van Moolenbroek 		err(1, "actual retrieval of routing table");
548*04e82b7dSDavid van Moolenbroek 	lim = buf + needed;
549*04e82b7dSDavid van Moolenbroek 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
550*04e82b7dSDavid van Moolenbroek 		rtm = (struct rt_msghdr *)(void *)next;
551*04e82b7dSDavid van Moolenbroek 		sina = (struct sockaddr_inarp *)(void *)(rtm + 1);
552*04e82b7dSDavid van Moolenbroek 		(void)snprintf(addr, sizeof(addr), "%s",
553*04e82b7dSDavid van Moolenbroek 		    inet_ntoa(sina->sin_addr));
554*04e82b7dSDavid van Moolenbroek 		(void)delete(addr, NULL);
555*04e82b7dSDavid van Moolenbroek 	}
556*04e82b7dSDavid van Moolenbroek 	free(buf);
557*04e82b7dSDavid van Moolenbroek }
558*04e82b7dSDavid van Moolenbroek 
559*04e82b7dSDavid van Moolenbroek void
sdl_print(const struct sockaddr_dl * sdl)560*04e82b7dSDavid van Moolenbroek sdl_print(const struct sockaddr_dl *sdl)
561*04e82b7dSDavid van Moolenbroek {
562*04e82b7dSDavid van Moolenbroek 	char hbuf[NI_MAXHOST];
563*04e82b7dSDavid van Moolenbroek 
564*04e82b7dSDavid van Moolenbroek 	if (getnameinfo((const struct sockaddr *)(const void *)sdl,
565*04e82b7dSDavid van Moolenbroek 	    (socklen_t)sdl->sdl_len,
566*04e82b7dSDavid van Moolenbroek 	    hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0)
567*04e82b7dSDavid van Moolenbroek 		(void)printf("<invalid>");
568*04e82b7dSDavid van Moolenbroek 	else
569*04e82b7dSDavid van Moolenbroek 		(void)printf("%s", hbuf);
570*04e82b7dSDavid van Moolenbroek }
571*04e82b7dSDavid van Moolenbroek 
572*04e82b7dSDavid van Moolenbroek static int
atosdl(const char * ss,struct sockaddr_dl * sdl)573*04e82b7dSDavid van Moolenbroek atosdl(const char *ss, struct sockaddr_dl *sdl)
574*04e82b7dSDavid van Moolenbroek {
575*04e82b7dSDavid van Moolenbroek 	int i;
576*04e82b7dSDavid van Moolenbroek 	unsigned long b;
577*04e82b7dSDavid van Moolenbroek 	char *endp;
578*04e82b7dSDavid van Moolenbroek 	char *p;
579*04e82b7dSDavid van Moolenbroek 	char *t, *r;
580*04e82b7dSDavid van Moolenbroek 
581*04e82b7dSDavid van Moolenbroek 	p = LLADDR(sdl);
582*04e82b7dSDavid van Moolenbroek 	endp = ((char *)(void *)sdl) + sdl->sdl_len;
583*04e82b7dSDavid van Moolenbroek 	i = 0;
584*04e82b7dSDavid van Moolenbroek 
585*04e82b7dSDavid van Moolenbroek 	b = strtoul(ss, &t, 16);
586*04e82b7dSDavid van Moolenbroek 	if (b > 255 || t == ss)
587*04e82b7dSDavid van Moolenbroek 		return 1;
588*04e82b7dSDavid van Moolenbroek 
589*04e82b7dSDavid van Moolenbroek 	*p++ = (char)b;
590*04e82b7dSDavid van Moolenbroek 	++i;
591*04e82b7dSDavid van Moolenbroek 	while ((p < endp) && (*t++ == ':')) {
592*04e82b7dSDavid van Moolenbroek 		b = strtoul(t, &r, 16);
593*04e82b7dSDavid van Moolenbroek 		if (b > 255 || r == t)
594*04e82b7dSDavid van Moolenbroek 			break;
595*04e82b7dSDavid van Moolenbroek 		*p++ = (char)b;
596*04e82b7dSDavid van Moolenbroek 		++i;
597*04e82b7dSDavid van Moolenbroek 		t = r;
598*04e82b7dSDavid van Moolenbroek 	}
599*04e82b7dSDavid van Moolenbroek 	sdl->sdl_alen = i;
600*04e82b7dSDavid van Moolenbroek 
601*04e82b7dSDavid van Moolenbroek 	return 0;
602*04e82b7dSDavid van Moolenbroek }
603*04e82b7dSDavid van Moolenbroek 
604*04e82b7dSDavid van Moolenbroek static void
usage(void)605*04e82b7dSDavid van Moolenbroek usage(void)
606*04e82b7dSDavid van Moolenbroek {
607*04e82b7dSDavid van Moolenbroek 	const char *progname;
608*04e82b7dSDavid van Moolenbroek 
609*04e82b7dSDavid van Moolenbroek 	progname = getprogname();
610*04e82b7dSDavid van Moolenbroek 	(void)fprintf(stderr, "Usage: %s [-n] hostname\n", progname);
611*04e82b7dSDavid van Moolenbroek 	(void)fprintf(stderr, "	      %s [-nv] -a\n", progname);
612*04e82b7dSDavid van Moolenbroek 	(void)fprintf(stderr, "	      %s [-v] -d [-a|hostname [pub [proxy]]]\n",
613*04e82b7dSDavid van Moolenbroek 	    progname);
614*04e82b7dSDavid van Moolenbroek 	(void)fprintf(stderr, "       %s -s hostname ether_addr [temp] [pub [proxy]]\n",
615*04e82b7dSDavid van Moolenbroek 	    progname);
616*04e82b7dSDavid van Moolenbroek 	(void)fprintf(stderr, "       %s -f filename\n", progname);
617*04e82b7dSDavid van Moolenbroek 	exit(1);
618*04e82b7dSDavid van Moolenbroek }
619*04e82b7dSDavid van Moolenbroek 
620*04e82b7dSDavid van Moolenbroek static struct rt_msghdr *
rtmsg(const int s,const int cmd,const struct sockaddr_inarp * sin,const struct sockaddr_dl * sdl)621*04e82b7dSDavid van Moolenbroek rtmsg(const int s, const int cmd, const struct sockaddr_inarp *sin,
622*04e82b7dSDavid van Moolenbroek     const struct sockaddr_dl *sdl)
623*04e82b7dSDavid van Moolenbroek {
624*04e82b7dSDavid van Moolenbroek 	static int seq;
625*04e82b7dSDavid van Moolenbroek 	struct rt_msghdr *rtm;
626*04e82b7dSDavid van Moolenbroek 	char *cp;
627*04e82b7dSDavid van Moolenbroek 	int l;
628*04e82b7dSDavid van Moolenbroek 	static struct {
629*04e82b7dSDavid van Moolenbroek 		struct	rt_msghdr m_rtm;
630*04e82b7dSDavid van Moolenbroek 		char	m_space[512];
631*04e82b7dSDavid van Moolenbroek 	} m_rtmsg;
632*04e82b7dSDavid van Moolenbroek 	pid_t pid;
633*04e82b7dSDavid van Moolenbroek 
634*04e82b7dSDavid van Moolenbroek 	rtm = &m_rtmsg.m_rtm;
635*04e82b7dSDavid van Moolenbroek 	cp = m_rtmsg.m_space;
636*04e82b7dSDavid van Moolenbroek 	errno = 0;
637*04e82b7dSDavid van Moolenbroek 
638*04e82b7dSDavid van Moolenbroek 	if (cmd == RTM_DELETE)
639*04e82b7dSDavid van Moolenbroek 		goto doit;
640*04e82b7dSDavid van Moolenbroek 	(void)memset(&m_rtmsg, 0, sizeof(m_rtmsg));
641*04e82b7dSDavid van Moolenbroek 	rtm->rtm_flags = flags;
642*04e82b7dSDavid van Moolenbroek 	rtm->rtm_version = RTM_VERSION;
643*04e82b7dSDavid van Moolenbroek 
644*04e82b7dSDavid van Moolenbroek 	switch (cmd) {
645*04e82b7dSDavid van Moolenbroek 	default:
646*04e82b7dSDavid van Moolenbroek 		errx(1, "internal wrong cmd");
647*04e82b7dSDavid van Moolenbroek 		/*NOTREACHED*/
648*04e82b7dSDavid van Moolenbroek 	case RTM_ADD:
649*04e82b7dSDavid van Moolenbroek 		rtm->rtm_addrs |= RTA_GATEWAY;
650*04e82b7dSDavid van Moolenbroek 		rtm->rtm_rmx.rmx_expire = expire_time;
651*04e82b7dSDavid van Moolenbroek 		rtm->rtm_inits = RTV_EXPIRE;
652*04e82b7dSDavid van Moolenbroek 		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
653*04e82b7dSDavid van Moolenbroek 		if (doing_proxy) {
654*04e82b7dSDavid van Moolenbroek 			if (!export_only) {
655*04e82b7dSDavid van Moolenbroek 				rtm->rtm_addrs |= RTA_NETMASK;
656*04e82b7dSDavid van Moolenbroek 				rtm->rtm_flags &= ~RTF_HOST;
657*04e82b7dSDavid van Moolenbroek 			}
658*04e82b7dSDavid van Moolenbroek 		}
659*04e82b7dSDavid van Moolenbroek 		/* FALLTHROUGH */
660*04e82b7dSDavid van Moolenbroek 	case RTM_GET:
661*04e82b7dSDavid van Moolenbroek 		rtm->rtm_addrs |= RTA_DST;
662*04e82b7dSDavid van Moolenbroek 	}
663*04e82b7dSDavid van Moolenbroek 
664*04e82b7dSDavid van Moolenbroek #define NEXTADDR(w, s) \
665*04e82b7dSDavid van Moolenbroek 	if (rtm->rtm_addrs & (w)) { \
666*04e82b7dSDavid van Moolenbroek 		(void)memcpy(cp, &s, \
667*04e82b7dSDavid van Moolenbroek 		    (size_t)((const struct sockaddr *)&s)->sa_len); \
668*04e82b7dSDavid van Moolenbroek 		RT_ADVANCE(cp, ((const struct sockaddr *)&s)); \
669*04e82b7dSDavid van Moolenbroek 	}
670*04e82b7dSDavid van Moolenbroek 
671*04e82b7dSDavid van Moolenbroek 	NEXTADDR(RTA_DST, *sin);
672*04e82b7dSDavid van Moolenbroek 	NEXTADDR(RTA_GATEWAY, *sdl);
673*04e82b7dSDavid van Moolenbroek 	NEXTADDR(RTA_NETMASK, so_mask);
674*04e82b7dSDavid van Moolenbroek 
675*04e82b7dSDavid van Moolenbroek 	rtm->rtm_msglen = cp - (char *)(void *)&m_rtmsg;
676*04e82b7dSDavid van Moolenbroek doit:
677*04e82b7dSDavid van Moolenbroek 	l = rtm->rtm_msglen;
678*04e82b7dSDavid van Moolenbroek 	rtm->rtm_seq = ++seq;
679*04e82b7dSDavid van Moolenbroek 	rtm->rtm_type = cmd;
680*04e82b7dSDavid van Moolenbroek #ifdef __minix
681*04e82b7dSDavid van Moolenbroek 	/*
682*04e82b7dSDavid van Moolenbroek 	 * Borrow from the future by setting the "this is a link-local request"
683*04e82b7dSDavid van Moolenbroek 	 * flag on all routing socket requests.  IMPORTANT: this change may be
684*04e82b7dSDavid van Moolenbroek 	 * dropped with the resync to NetBSD 8 as it will do the same thing,
685*04e82b7dSDavid van Moolenbroek 	 * although slightly differently (and hence may not create a conflict).
686*04e82b7dSDavid van Moolenbroek 	 */
687*04e82b7dSDavid van Moolenbroek 	rtm->rtm_flags |= RTF_LLDATA;
688*04e82b7dSDavid van Moolenbroek #endif /* __minix */
689*04e82b7dSDavid van Moolenbroek 	if (prog_write(s, &m_rtmsg, (size_t)l) < 0) {
690*04e82b7dSDavid van Moolenbroek 		if (errno != ESRCH || cmd != RTM_DELETE) {
691*04e82b7dSDavid van Moolenbroek 			warn("writing to routing socket");
692*04e82b7dSDavid van Moolenbroek 			return NULL;
693*04e82b7dSDavid van Moolenbroek 		}
694*04e82b7dSDavid van Moolenbroek 	}
695*04e82b7dSDavid van Moolenbroek 
696*04e82b7dSDavid van Moolenbroek 	pid = prog_getpid();
697*04e82b7dSDavid van Moolenbroek 	do {
698*04e82b7dSDavid van Moolenbroek 		l = prog_read(s, &m_rtmsg, sizeof(m_rtmsg));
699*04e82b7dSDavid van Moolenbroek 	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
700*04e82b7dSDavid van Moolenbroek 	if (l < 0)
701*04e82b7dSDavid van Moolenbroek 		warn("read from routing socket");
702*04e82b7dSDavid van Moolenbroek 	return rtm;
703*04e82b7dSDavid van Moolenbroek }
704*04e82b7dSDavid van Moolenbroek 
705*04e82b7dSDavid van Moolenbroek static int
getinetaddr(const char * host,struct in_addr * inap)706*04e82b7dSDavid van Moolenbroek getinetaddr(const char *host, struct in_addr *inap)
707*04e82b7dSDavid van Moolenbroek {
708*04e82b7dSDavid van Moolenbroek 	struct hostent *hp;
709*04e82b7dSDavid van Moolenbroek 
710*04e82b7dSDavid van Moolenbroek 	if (inet_aton(host, inap) == 1)
711*04e82b7dSDavid van Moolenbroek 		return (0);
712*04e82b7dSDavid van Moolenbroek 	if ((hp = gethostbyname(host)) == NULL) {
713*04e82b7dSDavid van Moolenbroek 		warnx("%s: %s", host, hstrerror(h_errno));
714*04e82b7dSDavid van Moolenbroek 		return (-1);
715*04e82b7dSDavid van Moolenbroek 	}
716*04e82b7dSDavid van Moolenbroek 	(void)memcpy(inap, hp->h_addr, sizeof(*inap));
717*04e82b7dSDavid van Moolenbroek 	return (0);
718*04e82b7dSDavid van Moolenbroek }
719*04e82b7dSDavid van Moolenbroek 
720*04e82b7dSDavid van Moolenbroek static int
getifname(u_int16_t ifindex,char * ifname,size_t l)721*04e82b7dSDavid van Moolenbroek getifname(u_int16_t ifindex, char *ifname, size_t l)
722*04e82b7dSDavid van Moolenbroek {
723*04e82b7dSDavid van Moolenbroek 	int i;
724*04e82b7dSDavid van Moolenbroek 	struct ifaddrs *addr;
725*04e82b7dSDavid van Moolenbroek 	const struct sockaddr_dl *sdl = NULL;
726*04e82b7dSDavid van Moolenbroek 	static struct ifaddrs* ifaddrs = NULL;
727*04e82b7dSDavid van Moolenbroek 
728*04e82b7dSDavid van Moolenbroek 	if (ifaddrs == NULL) {
729*04e82b7dSDavid van Moolenbroek 		i = getifaddrs(&ifaddrs);
730*04e82b7dSDavid van Moolenbroek 		if (i != 0)
731*04e82b7dSDavid van Moolenbroek 			err(1, "getifaddrs");
732*04e82b7dSDavid van Moolenbroek 	}
733*04e82b7dSDavid van Moolenbroek 
734*04e82b7dSDavid van Moolenbroek 	for (addr = ifaddrs; addr; addr = addr->ifa_next) {
735*04e82b7dSDavid van Moolenbroek 		if (addr->ifa_addr == NULL ||
736*04e82b7dSDavid van Moolenbroek 		    addr->ifa_addr->sa_family != AF_LINK)
737*04e82b7dSDavid van Moolenbroek 			continue;
738*04e82b7dSDavid van Moolenbroek 
739*04e82b7dSDavid van Moolenbroek 		sdl = (const struct sockaddr_dl *)(void *)addr->ifa_addr;
740*04e82b7dSDavid van Moolenbroek 		if (sdl && sdl->sdl_index == ifindex) {
741*04e82b7dSDavid van Moolenbroek 			(void) strlcpy(ifname, addr->ifa_name, l);
742*04e82b7dSDavid van Moolenbroek 			return 0;
743*04e82b7dSDavid van Moolenbroek 		}
744*04e82b7dSDavid van Moolenbroek 	}
745*04e82b7dSDavid van Moolenbroek 
746*04e82b7dSDavid van Moolenbroek 	return -1;
747*04e82b7dSDavid van Moolenbroek }
748