Home | History | Annotate | Line # | Download | only in arp
arp.c revision 1.1.1.2
      1 /*
      2  * Copyright (c) 1984, 1993
      3  *	The Regents of the University of California.  All rights reserved.
      4  *
      5  * This code is derived from software contributed to Berkeley by
      6  * Sun Microsystems, Inc.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by the University of
     19  *	California, Berkeley and its contributors.
     20  * 4. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  */
     36 
     37 #ifndef lint
     38 static char copyright[] =
     39 "@(#) Copyright (c) 1984, 1993\n\
     40 	The Regents of the University of California.  All rights reserved.\n";
     41 #endif /* not lint */
     42 
     43 #ifndef lint
     44 /*static char sccsid[] = "from: @(#)arp.c	8.2 (Berkeley) 1/2/94";*/
     45 static char *rcsid = "$Id: arp.c,v 1.1.1.2 1994/05/13 08:08:55 mycroft Exp $";
     46 #endif /* not lint */
     47 
     48 /*
     49  * arp - display, set, and delete arp table entries
     50  */
     51 
     52 
     53 #include <sys/param.h>
     54 #include <sys/file.h>
     55 #include <sys/socket.h>
     56 #include <sys/sysctl.h>
     57 
     58 #include <net/if.h>
     59 #include <net/if_dl.h>
     60 #include <net/if_types.h>
     61 #include <net/route.h>
     62 
     63 #include <netinet/in.h>
     64 #include <netinet/if_ether.h>
     65 
     66 #include <arpa/inet.h>
     67 
     68 #include <netdb.h>
     69 #include <errno.h>
     70 #include <nlist.h>
     71 #include <stdio.h>
     72 #include <paths.h>
     73 
     74 extern int errno;
     75 static int pid;
     76 static int kflag;
     77 static int nflag;
     78 static int s = -1;
     79 
     80 main(argc, argv)
     81 	int argc;
     82 	char **argv;
     83 {
     84 	int ch;
     85 
     86 	pid = getpid();
     87 	while ((ch = getopt(argc, argv, "ands")) != EOF)
     88 		switch((char)ch) {
     89 		case 'a':
     90 			dump(0);
     91 			exit(0);
     92 		case 'd':
     93 			if (argc < 3 || argc > 4)
     94 				usage();
     95 			delete(argv[2], argv[3]);
     96 			exit(0);
     97 		case 'n':
     98 			nflag = 1;
     99 			continue;
    100 		case 's':
    101 			if (argc < 4 || argc > 7)
    102 				usage();
    103 			exit(set(argc-2, &argv[2]) ? 1 : 0);
    104 		case '?':
    105 		default:
    106 			usage();
    107 		}
    108 	if (argc != 2)
    109 		usage();
    110 	get(argv[1]);
    111 	exit(0);
    112 }
    113 
    114 /*
    115  * Process a file to set standard arp entries
    116  */
    117 file(name)
    118 	char *name;
    119 {
    120 	FILE *fp;
    121 	int i, retval;
    122 	char line[100], arg[5][50], *args[5];
    123 
    124 	if ((fp = fopen(name, "r")) == NULL) {
    125 		fprintf(stderr, "arp: cannot open %s\n", name);
    126 		exit(1);
    127 	}
    128 	args[0] = &arg[0][0];
    129 	args[1] = &arg[1][0];
    130 	args[2] = &arg[2][0];
    131 	args[3] = &arg[3][0];
    132 	args[4] = &arg[4][0];
    133 	retval = 0;
    134 	while(fgets(line, 100, fp) != NULL) {
    135 		i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2],
    136 		    arg[3], arg[4]);
    137 		if (i < 2) {
    138 			fprintf(stderr, "arp: bad line: %s\n", line);
    139 			retval = 1;
    140 			continue;
    141 		}
    142 		if (set(i, args))
    143 			retval = 1;
    144 	}
    145 	fclose(fp);
    146 	return (retval);
    147 }
    148 
    149 getsocket() {
    150 	if (s < 0) {
    151 		s = socket(PF_ROUTE, SOCK_RAW, 0);
    152 		if (s < 0) {
    153 			perror("arp: socket");
    154 			exit(1);
    155 		}
    156 	}
    157 }
    158 
    159 struct	sockaddr_in so_mask = {8, 0, 0, { 0xffffffff}};
    160 struct	sockaddr_inarp blank_sin = {sizeof(blank_sin), AF_INET }, sin_m;
    161 struct	sockaddr_dl blank_sdl = {sizeof(blank_sdl), AF_LINK }, sdl_m;
    162 int	expire_time, flags, export_only, doing_proxy, found_entry;
    163 struct	{
    164 	struct	rt_msghdr m_rtm;
    165 	char	m_space[512];
    166 }	m_rtmsg;
    167 
    168 /*
    169  * Set an individual arp entry
    170  */
    171 set(argc, argv)
    172 	int argc;
    173 	char **argv;
    174 {
    175 	struct hostent *hp;
    176 	register struct sockaddr_inarp *sin = &sin_m;
    177 	register struct sockaddr_dl *sdl;
    178 	register struct rt_msghdr *rtm = &(m_rtmsg.m_rtm);
    179 	u_char *ea;
    180 	char *host = argv[0], *eaddr = argv[1];
    181 
    182 	getsocket();
    183 	argc -= 2;
    184 	argv += 2;
    185 	sdl_m = blank_sdl;
    186 	sin_m = blank_sin;
    187 	sin->sin_addr.s_addr = inet_addr(host);
    188 	if (sin->sin_addr.s_addr == -1) {
    189 		if (!(hp = gethostbyname(host))) {
    190 			fprintf(stderr, "arp: %s: ", host);
    191 			herror((char *)NULL);
    192 			return (1);
    193 		}
    194 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
    195 		    sizeof sin->sin_addr);
    196 	}
    197 	ea = (u_char *)LLADDR(&sdl_m);
    198 	if (ether_aton(eaddr, ea) == 0)
    199 		sdl_m.sdl_alen = 6;
    200 	doing_proxy = flags = export_only = expire_time = 0;
    201 	while (argc-- > 0) {
    202 		if (strncmp(argv[0], "temp", 4) == 0) {
    203 			struct timeval time;
    204 			gettimeofday(&time, 0);
    205 			expire_time = time.tv_sec + 20 * 60;
    206 		}
    207 		else if (strncmp(argv[0], "pub", 3) == 0) {
    208 			flags |= RTF_ANNOUNCE;
    209 			doing_proxy = SIN_PROXY;
    210 		} else if (strncmp(argv[0], "trail", 5) == 0) {
    211 			printf("%s: Sending trailers is no longer supported\n",
    212 				host);
    213 		}
    214 		argv++;
    215 	}
    216 tryagain:
    217 	if (rtmsg(RTM_GET) < 0) {
    218 		perror(host);
    219 		return (1);
    220 	}
    221 	sin = (struct sockaddr_inarp *)(rtm + 1);
    222 	sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin);
    223 	if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
    224 		if (sdl->sdl_family == AF_LINK &&
    225 		    (rtm->rtm_flags & RTF_LLINFO) &&
    226 		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
    227 		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
    228 		case IFT_ISO88024: case IFT_ISO88025:
    229 			goto overwrite;
    230 		}
    231 		if (doing_proxy == 0) {
    232 			printf("set: can only proxy for %s\n", host);
    233 			return (1);
    234 		}
    235 		if (sin_m.sin_other & SIN_PROXY) {
    236 			printf("set: proxy entry exists for non 802 device\n");
    237 			return(1);
    238 		}
    239 		sin_m.sin_other = SIN_PROXY;
    240 		export_only = 1;
    241 		goto tryagain;
    242 	}
    243 overwrite:
    244 	if (sdl->sdl_family != AF_LINK) {
    245 		printf("cannot intuit interface index and type for %s\n", host);
    246 		return (1);
    247 	}
    248 	sdl_m.sdl_type = sdl->sdl_type;
    249 	sdl_m.sdl_index = sdl->sdl_index;
    250 	return (rtmsg(RTM_ADD));
    251 }
    252 
    253 /*
    254  * Display an individual arp entry
    255  */
    256 get(host)
    257 	char *host;
    258 {
    259 	struct hostent *hp;
    260 	struct sockaddr_inarp *sin = &sin_m;
    261 	u_char *ea;
    262 
    263 	sin_m = blank_sin;
    264 	sin->sin_addr.s_addr = inet_addr(host);
    265 	if (sin->sin_addr.s_addr == -1) {
    266 		if (!(hp = gethostbyname(host))) {
    267 			fprintf(stderr, "arp: %s: ", host);
    268 			herror((char *)NULL);
    269 			exit(1);
    270 		}
    271 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
    272 		    sizeof sin->sin_addr);
    273 	}
    274 	dump(sin->sin_addr.s_addr);
    275 	if (found_entry == 0) {
    276 		printf("%s (%s) -- no entry\n",
    277 		    host, inet_ntoa(sin->sin_addr));
    278 		exit(1);
    279 	}
    280 }
    281 
    282 /*
    283  * Delete an arp entry
    284  */
    285 delete(host, info)
    286 	char *host;
    287 	char *info;
    288 {
    289 	struct hostent *hp;
    290 	register struct sockaddr_inarp *sin = &sin_m;
    291 	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
    292 	struct sockaddr_dl *sdl;
    293 	u_char *ea;
    294 	char *eaddr;
    295 
    296 	if (info && strncmp(info, "pro", 3) )
    297 		export_only = 1;
    298 	getsocket();
    299 	sin_m = blank_sin;
    300 	sin->sin_addr.s_addr = inet_addr(host);
    301 	if (sin->sin_addr.s_addr == -1) {
    302 		if (!(hp = gethostbyname(host))) {
    303 			fprintf(stderr, "arp: %s: ", host);
    304 			herror((char *)NULL);
    305 			return (1);
    306 		}
    307 		bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
    308 		    sizeof sin->sin_addr);
    309 	}
    310 tryagain:
    311 	if (rtmsg(RTM_GET) < 0) {
    312 		perror(host);
    313 		return (1);
    314 	}
    315 	sin = (struct sockaddr_inarp *)(rtm + 1);
    316 	sdl = (struct sockaddr_dl *)(sin->sin_len + (char *)sin);
    317 	if (sin->sin_addr.s_addr == sin_m.sin_addr.s_addr) {
    318 		if (sdl->sdl_family == AF_LINK &&
    319 		    (rtm->rtm_flags & RTF_LLINFO) &&
    320 		    !(rtm->rtm_flags & RTF_GATEWAY)) switch (sdl->sdl_type) {
    321 		case IFT_ETHER: case IFT_FDDI: case IFT_ISO88023:
    322 		case IFT_ISO88024: case IFT_ISO88025:
    323 			goto delete;
    324 		}
    325 	}
    326 	if (sin_m.sin_other & SIN_PROXY) {
    327 		fprintf(stderr, "delete: can't locate %s\n",host);
    328 		return (1);
    329 	} else {
    330 		sin_m.sin_other = SIN_PROXY;
    331 		goto tryagain;
    332 	}
    333 delete:
    334 	if (sdl->sdl_family != AF_LINK) {
    335 		printf("cannot locate %s\n", host);
    336 		return (1);
    337 	}
    338 	if (rtmsg(RTM_DELETE) == 0)
    339 		printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
    340 }
    341 
    342 /*
    343  * Dump the entire arp table
    344  */
    345 dump(addr)
    346 u_long addr;
    347 {
    348 	int mib[6];
    349 	size_t needed;
    350 	char *host, *malloc(), *lim, *buf, *next;
    351 	struct rt_msghdr *rtm;
    352 	struct sockaddr_inarp *sin;
    353 	struct sockaddr_dl *sdl;
    354 	extern int h_errno;
    355 	struct hostent *hp;
    356 
    357 	mib[0] = CTL_NET;
    358 	mib[1] = PF_ROUTE;
    359 	mib[2] = 0;
    360 	mib[3] = AF_INET;
    361 	mib[4] = NET_RT_FLAGS;
    362 	mib[5] = RTF_LLINFO;
    363 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
    364 		quit("route-sysctl-estimate");
    365 	if ((buf = malloc(needed)) == NULL)
    366 		quit("malloc");
    367 	if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
    368 		quit("actual retrieval of routing table");
    369 	lim = buf + needed;
    370 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
    371 		rtm = (struct rt_msghdr *)next;
    372 		sin = (struct sockaddr_inarp *)(rtm + 1);
    373 		sdl = (struct sockaddr_dl *)(sin + 1);
    374 		if (addr) {
    375 			if (addr != sin->sin_addr.s_addr)
    376 				continue;
    377 			found_entry = 1;
    378 		}
    379 		if (nflag == 0)
    380 			hp = gethostbyaddr((caddr_t)&(sin->sin_addr),
    381 			    sizeof sin->sin_addr, AF_INET);
    382 		else
    383 			hp = 0;
    384 		if (hp)
    385 			host = hp->h_name;
    386 		else {
    387 			host = "?";
    388 			if (h_errno == TRY_AGAIN)
    389 				nflag = 1;
    390 		}
    391 		printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
    392 		if (sdl->sdl_alen)
    393 			ether_print(LLADDR(sdl));
    394 		else
    395 			printf("(incomplete)");
    396 		if (rtm->rtm_rmx.rmx_expire == 0)
    397 			printf(" permanent");
    398 		if (sin->sin_other & SIN_PROXY)
    399 			printf(" published (proxy only)");
    400 		if (rtm->rtm_addrs & RTA_NETMASK) {
    401 			sin = (struct sockaddr_inarp *)
    402 				(sdl->sdl_len + (char *)sdl);
    403 			if (sin->sin_addr.s_addr == 0xffffffff)
    404 				printf(" published");
    405 			if (sin->sin_len != 8)
    406 				printf("(wierd)");
    407 		}
    408 		printf("\n");
    409 	}
    410 }
    411 
    412 ether_print(cp)
    413 	u_char *cp;
    414 {
    415 	printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
    416 }
    417 
    418 ether_aton(a, n)
    419 	char *a;
    420 	u_char *n;
    421 {
    422 	int i, o[6];
    423 
    424 	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
    425 					   &o[3], &o[4], &o[5]);
    426 	if (i != 6) {
    427 		fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
    428 		return (1);
    429 	}
    430 	for (i=0; i<6; i++)
    431 		n[i] = o[i];
    432 	return (0);
    433 }
    434 
    435 usage()
    436 {
    437 	printf("usage: arp hostname\n");
    438 	printf("       arp -a [kernel] [kernel_memory]\n");
    439 	printf("       arp -d hostname\n");
    440 	printf("       arp -s hostname ether_addr [temp] [pub]\n");
    441 	printf("       arp -f filename\n");
    442 	exit(1);
    443 }
    444 
    445 rtmsg(cmd)
    446 {
    447 	static int seq;
    448 	int rlen;
    449 	register struct rt_msghdr *rtm = &m_rtmsg.m_rtm;
    450 	register char *cp = m_rtmsg.m_space;
    451 	register int l;
    452 
    453 	errno = 0;
    454 	if (cmd == RTM_DELETE)
    455 		goto doit;
    456 	bzero((char *)&m_rtmsg, sizeof(m_rtmsg));
    457 	rtm->rtm_flags = flags;
    458 	rtm->rtm_version = RTM_VERSION;
    459 
    460 	switch (cmd) {
    461 	default:
    462 		fprintf(stderr, "arp: internal wrong cmd\n");
    463 		exit(1);
    464 	case RTM_ADD:
    465 		rtm->rtm_addrs |= RTA_GATEWAY;
    466 		rtm->rtm_rmx.rmx_expire = expire_time;
    467 		rtm->rtm_inits = RTV_EXPIRE;
    468 		rtm->rtm_flags |= (RTF_HOST | RTF_STATIC);
    469 		sin_m.sin_other = 0;
    470 		if (doing_proxy) {
    471 			if (export_only)
    472 				sin_m.sin_other = SIN_PROXY;
    473 			else {
    474 				rtm->rtm_addrs |= RTA_NETMASK;
    475 				rtm->rtm_flags &= ~RTF_HOST;
    476 			}
    477 		}
    478 		/* FALLTHROUGH */
    479 	case RTM_GET:
    480 		rtm->rtm_addrs |= RTA_DST;
    481 	}
    482 #define NEXTADDR(w, s) \
    483 	if (rtm->rtm_addrs & (w)) { \
    484 		bcopy((char *)&s, cp, sizeof(s)); cp += sizeof(s);}
    485 
    486 	NEXTADDR(RTA_DST, sin_m);
    487 	NEXTADDR(RTA_GATEWAY, sdl_m);
    488 	NEXTADDR(RTA_NETMASK, so_mask);
    489 
    490 	rtm->rtm_msglen = cp - (char *)&m_rtmsg;
    491 doit:
    492 	l = rtm->rtm_msglen;
    493 	rtm->rtm_seq = ++seq;
    494 	rtm->rtm_type = cmd;
    495 	if ((rlen = write(s, (char *)&m_rtmsg, l)) < 0) {
    496 		if (errno != ESRCH || cmd != RTM_DELETE) {
    497 			perror("writing to routing socket");
    498 			return (-1);
    499 		}
    500 	}
    501 	do {
    502 		l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
    503 	} while (l > 0 && (rtm->rtm_seq != seq || rtm->rtm_pid != pid));
    504 	if (l < 0)
    505 		(void) fprintf(stderr, "arp: read from routing socket: %s\n",
    506 		    strerror(errno));
    507 	return (0);
    508 }
    509 
    510 quit(msg)
    511 char *msg;
    512 {
    513 	fprintf(stderr, "%s\n", msg);
    514 	exit(1);
    515 }
    516