use the targets size, to suppress a warning.
[AROS.git] / workbench / network / common / C / arp.c
blobcf15ba925a16505603e206f927c3273f53ed7c3d
1 /* $Id$
3 * arp.c --- arp utility for AmiTCP/IP
5 * Copyright © 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>,
6 * Helsinki University of Technology, Finland.
7 * All rights reserved.
8 * Copyright © 2005 Pavel Fedin
10 * Created : Sun Apr 18 05:08:20 1993 ppessi
11 * Last modified: Wed Feb 16 19:48:50 1994 ppessi
13 * $Log: arp.c,v $
14 * Revision 1.2 2005/12/22 06:44:55 sonic_amiga
15 * - Fixed address printout in "arp" tool.
16 * - "netstat" fully works now.
17 * - Improved hostname handling.
18 * - Fixed FD_ACCEPT generation
19 * - DHCP client now supports nameservers option
21 * Revision 1.1.1.1 2005/12/07 10:50:36 sonic_amiga
22 * First full import into the CVS
24 * Revision 3.2 1994/05/02 19:39:03 jraja
25 * Update for the new net.lib
27 * Revision 3.1 1994/02/21 20:32:19 ppessi
28 * Changed the version tag.
30 * Revision 1.10 1993/11/07 00:19:45 ppessi
31 * Reverted back to scanf()
33 * Revision 1.9 1993/10/29 01:26:40 ppessi
34 * Implemented dumping of arp tables.
35 * Cleaned up code, fixed close() bug.
38 static const char version[] __attribute__((used)) = "$VER: arp 3.2 (12.09.2005) "
39 "Copyright © 2005 Pavel Fedin <sonic_amiga@rambler.ru>\n"
40 "Copyright © 1993 AmiTCP/IP Group, <amitcp-group@hut.fi>\n"
41 "Helsinki University of Technology, Finland.\n"
42 "Copyright © 1984 The Regents of the University of California.\n"
43 "All rights reserved.\n";
47 * Copyright © 1984 Regents of the University of California.
48 * All rights reserved.
50 * This code is derived from software contributed to Berkeley by
51 * Sun Microsystems, Inc.
53 * Redistribution and use in source and binary forms, with or without
54 * modification, are permitted provided that the following conditions
55 * are met:
56 * 1. Redistributions of source code must retain the above copyright
57 * notice, this list of conditions and the following disclaimer.
58 * 2. Redistributions in binary form must reproduce the above copyright
59 * notice, this list of conditions and the following disclaimer in the
60 * documentation and/or other materials provided with the distribution.
61 * 3. All advertising materials mentioning features or use of this software
62 * must display the following acknowledgement:
63 * This product includes software developed by the University of
64 * California, Berkeley and its contributors.
65 * 4. Neither the name of the University nor the names of its contributors
66 * may be used to endorse or promote products derived from this software
67 * without specific prior written permission.
69 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
70 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
71 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
72 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
73 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
74 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
75 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
76 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
77 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
78 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
79 * SUCH DAMAGE.
82 /****** netutil.doc/arp *****************************************************
84 * NAME
85 * Arp - address resolution display and control
87 * SYNOPSIS
88 * arp hostname
89 * arp -a [netname | hostname]
90 * arp -d hostname
91 * arp -s hostname address [temp] [pub]
92 * arp -f filename
94 * DESCRIPTION
95 * Arp displays and modifies the Internet to hardware address
96 * translation tables used by the Address Resolution Protocol. The
97 * hardware address is a hexadecimal string with each octet separated
98 * by a colon, for instance 0:12:ff:a. The length of the address must
99 * be correct for the specified interface.
101 * OPTIONS
102 * none If no options are specified (first form above), arp displays
103 * the current ARP entry for hostname. The hostname must either
104 * appear in the hostname database (SEE hosts), or be a DARPA
105 * Internet address expressed in Internet standard "dot
106 * notation". Hostname can also be resolved by nameserver.
108 * -a Display all current ARP entries by reading the address mapping
109 * table of the specified (sub)network. `Hostname' is used to as
110 * default network specifier.
112 * -d If an ARP entry exists for the host called hostname, delete
113 * it. [This requires super-user privileges.]
115 * -s Create an ARP entry for the host called hostname with the
116 * hardware station address address. The hardware station address
117 * is given as hexadecimal bytes separated by colons. If an ARP
118 * entry already exists for hostname, the existing entry is
119 * updated with the new information. The entry is permanent
120 * unless the word temp is given in the command. If the word pub
121 * is specified, the entry is published, which means that this
122 * system will act as an ARP server responding to requests for
123 * hostname even though the host address is not its own.
125 * -f Read file filename and set multiple entries in the ARP tables.
126 * Entries in the file should be of the form:
128 * hostname address [temp] [pub]
130 * Argument meanings are the same as for the -s option.
132 * AUTHOR
133 * Arp was developed by the University of California, Berkeley, for the
134 * BSD Unix system.
136 * SEE ALSO
137 * ifconfig, netif.protocols/arp, "net/if_arp.h"
139 *****************************************************************************
144 * arp - display, set, and delete arp table entries
147 #ifdef AMIGA
148 #include <proto/dos.h>
149 #include <proto/socket.h>
150 #if !defined(__AROS__)
151 #include <clib/netlib_protos.h>
152 #else
153 #include <proto/exec.h>
154 #endif
155 #endif /* AMIGA */
157 #include <sys/param.h>
158 #include <sys/socket.h>
159 #include <sys/sockio.h>
161 #include <arpa/inet.h>
162 #include <netdb.h>
163 #include <netinet/in.h>
164 #include <net/if.h>
166 #include <errno.h>
167 #include <stdlib.h>
168 #include <stdio.h>
169 #if defined(__AROS__)
170 #include <string.h>
171 #include <unistd.h>
172 #endif
174 struct Library * SocketBase;
176 #define max(a,b) ((a) > (b) ? (a) : (b))
178 static int file(char *name);
179 static int set(int argc, char **argv);
180 static void get(char *host);
181 static void delete(char *host);
182 static int arpreq_print(struct arpreq *ar, int bynumber);
183 static void sana_print(const u_char *cp, int len);
184 static int sana_aton(const char *a, u_char *n, u_char *lenp);
185 static void usage(void);
186 static void dump(char *name);
187 char * strsep(register char **stringp, register const char *delim);
189 char usage_str[] =
190 "usage: arp hostname\n"
191 " arp -a [netname | hostname]\n"
192 " arp -d hostname\n"
193 " arp -s hostname address [temp] [pub]\n"
194 " arp -f filename\n";
196 #define SOCKET_VERSION 3
197 const TEXT socket_name[] = "bsdsocket.library";
199 int main(argc, argv)
200 int argc;
201 char **argv;
203 int ch;
205 if (!(SocketBase = OpenLibrary(socket_name, SOCKET_VERSION)))
207 return RETURN_FAIL;
210 while ((ch = getopt(argc, argv, "adsf")) != EOF)
211 switch((char)ch) {
212 case 'a': {
213 char *net;
214 char myname[MAXHOSTNAMELEN];
216 if (argc > 3)
217 usage();
218 if (argc == 3) {
219 net = argv[2];
220 } else {
221 net = myname;
222 gethostname(myname, sizeof(myname));
224 dump(net);
225 exit(0);
227 case 'd':
228 if (argc != 3)
229 usage();
230 delete(argv[2]);
231 exit(0);
232 case 's':
233 if (argc < 4 || argc > 7)
234 usage();
235 exit(set(argc-2, &argv[2]) ? 1 : 0);
236 case 'f':
237 if (argc != 3)
238 usage();
239 exit (file(argv[2]) ? 1 : 0);
240 case '?':
241 default:
242 usage();
244 if (argc != 2)
245 usage();
246 get(argv[1]);
247 exit(0);
251 * Process a file to set standard arp entries
253 static int
254 file(char *name)
256 FILE *fp;
257 int i, retval;
258 char line[100], arg[5][50], *args[5];
260 if ((fp = fopen(name, "r")) == NULL) {
261 fprintf(stderr, "arp: cannot open %s\n", name);
262 exit(1);
265 args[0] = &arg[0][0];
266 args[1] = &arg[1][0];
267 args[2] = &arg[2][0];
268 args[3] = &arg[3][0];
269 args[4] = &arg[4][0];
271 retval = 0;
272 while(fgets(line, 100, fp) != NULL) {
273 i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], arg[3], arg[4]);
274 if (i < 2) {
275 fprintf(stderr, "arp: bad line: %s\n", line);
276 retval = 1;
277 continue;
279 if (set(i, args))
280 retval = 1;
282 fclose(fp);
283 return (retval);
287 * Set an individual arp entry
289 static int
290 set(int argc, char **argv)
292 struct arpreq ar;
293 struct hostent *hp;
294 struct sockaddr_in *sin;
295 u_char *ea;
296 int s;
297 char *host = argv[0], *eaddr = argv[1];
299 argc -= 2;
300 argv += 2;
301 bzero((caddr_t)&ar, sizeof ar);
302 sin = (struct sockaddr_in *)&ar.arp_pa;
303 sin->sin_len = sizeof(*sin);
304 sin->sin_family = AF_INET;
305 sin->sin_addr.s_addr = inet_addr(host);
306 if (sin->sin_addr.s_addr == -1) {
307 if (!(hp = gethostbyname(host))) {
308 fprintf(stderr, "arp: %s: ", host);
309 /* TODO: NicJA - Implement herror() */
310 #if !defined(__AROS__)
311 herror((char *)NULL);
312 #endif
313 return (1);
315 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
316 sizeof sin->sin_addr);
318 ea = (u_char *)ar.arp_ha.sa_data;
319 if (sana_aton(eaddr, ea, &ar.arp_ha.sa_len))
320 return (1);
321 ar.arp_ha.sa_len += 2;
322 ar.arp_flags = ATF_PERM;
323 while (argc-- > 0) {
324 if (strncmp(argv[0], "temp", 4) == 0)
325 ar.arp_flags &= ~ATF_PERM;
326 else if (strncmp(argv[0], "pub", 3) == 0)
327 ar.arp_flags |= ATF_PUBL;
328 else if (strncmp(argv[0], "trail", 5) == 0)
329 ar.arp_flags |= ATF_USETRAILERS;
330 argv++;
333 s = socket(AF_INET, SOCK_DGRAM, 0);
334 if (s < 0) {
335 perror("arp: socket");
336 exit(1);
338 if (IoctlSocket(s, SIOCSARP, (caddr_t)&ar) < 0) {
339 perror(host);
340 exit(1);
342 CloseSocket(s);
344 return (0);
348 * Display an individual arp entry
350 static void
351 get(char *host)
353 struct arpreq ar;
354 struct hostent *hp;
355 struct sockaddr_in *sin;
356 int s;
358 bzero((caddr_t)&ar, sizeof ar);
359 sin = (struct sockaddr_in *)&ar.arp_pa;
360 sin->sin_len = sizeof(*sin);
361 sin->sin_family = AF_INET;
362 sin->sin_addr.s_addr = inet_addr(host);
363 if (sin->sin_addr.s_addr == -1) {
364 if (!(hp = gethostbyname(host))) {
365 fprintf(stderr, "arp: %s: ", host);
366 /* TODO: NicJA - Implement herror() */
367 #if !defined(__AROS__)
368 herror((char *)NULL);
369 #endif
370 exit(1);
372 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, sizeof sin->sin_addr);
374 s = socket(AF_INET, SOCK_DGRAM, 0);
375 if (s < 0) {
376 perror("arp: socket");
377 exit(1);
379 if (IoctlSocket(s, SIOCGARP, (caddr_t)&ar) < 0) {
380 if (errno == ENXIO)
381 printf("%s (%s) -- no entry\n", host, inet_ntoa(sin->sin_addr));
382 else
383 perror("SIOCGARP");
384 exit(1);
386 CloseSocket(s);
388 (void)arpreq_print(&ar, 0);
392 * Delete an arp entry
394 static void
395 delete(char *host)
397 struct arpreq ar;
398 struct hostent *hp;
399 struct sockaddr_in *sin;
400 int s;
402 bzero((caddr_t)&ar, sizeof ar);
403 sin = (struct sockaddr_in *)&ar.arp_pa;
404 sin->sin_len = sizeof(*sin);
405 sin->sin_family = AF_INET;
406 sin->sin_addr.s_addr = inet_addr(host);
407 if (sin->sin_addr.s_addr == -1) {
408 if (!(hp = gethostbyname(host))) {
409 fprintf(stderr, "arp: %s: ", host);
410 /* TODO: NicJA - Implement herror() */
411 #if !defined(__AROS__)
412 herror((char *)NULL);
413 #endif
414 exit(1);
416 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
417 sizeof sin->sin_addr);
419 s = socket(AF_INET, SOCK_DGRAM, 0);
420 if (s < 0) {
421 perror("arp: socket");
422 exit(1);
424 if (IoctlSocket(s, SIOCDARP, (caddr_t)&ar) < 0) {
425 if (errno == ENXIO)
426 printf("%s (%s) -- no entry\n",
427 host, inet_ntoa(sin->sin_addr));
428 else
429 perror("SIOCDARP");
430 exit(1);
432 CloseSocket(s);
433 printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
437 * Dump the entire arp table
439 static void
440 dump(char *host)
442 struct arptabreq atr;
443 struct arpreq *ar;
444 struct sockaddr_in *sin;
445 int s, bynumber;
446 long n;
448 bzero((caddr_t)&atr, sizeof atr);
450 /* Identify the used interface according the host/net name */
451 sin = (struct sockaddr_in *)&atr.atr_arpreq.arp_pa;
452 sin->sin_len = sizeof(*sin);
453 sin->sin_family = AF_INET;
454 sin->sin_addr.s_addr = inet_addr(host);
455 if (sin->sin_addr.s_addr == -1) {
456 struct hostent *hp;
457 struct netent *np = NULL;
458 if (!(hp = gethostbyname(host)) &&
459 !(np = getnetbyname(host))) {
460 fprintf(stderr, "arp: %s: ", host);
461 /* TODO: NicJA - Implement herror() */
462 #if !defined(__AROS__)
463 herror((char *)NULL);
464 #endif
465 exit(1);
467 if (hp)
468 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, sizeof sin->sin_addr);
469 else
470 bcopy((char *)&np->n_net, (char *)&sin->sin_addr, sizeof np->n_net);
473 s = socket(AF_INET, SOCK_DGRAM, 0);
474 if (s < 0) {
475 perror("arp: socket");
476 exit(1);
479 if (IoctlSocket(s, SIOCGARPT, (caddr_t)&atr) < 0) {
480 perror("SIOCGARPT");
481 exit(1);
484 n = atr.atr_size = atr.atr_inuse;
485 if (n) {
486 ar = atr.atr_table = malloc(sizeof(*ar) * n);
487 if (!ar) {
488 perror("arp: malloc");
489 exit(1);
491 if (IoctlSocket(s, SIOCGARPT, (caddr_t)&atr) < 0) {
492 perror("SIOCGARPT");
493 exit(1);
495 /* Entries may be deleted */
496 n = max(n, atr.atr_inuse);
498 CloseSocket(s);
500 bynumber = 0;
501 while (n-- > 0) {
502 bynumber = arpreq_print(ar++, bynumber);
506 static int
507 arpreq_print(struct arpreq *ar, int bynumber)
509 struct sockaddr_in *sin;
510 struct hostent *hp;
511 char *host;
513 sin = (struct sockaddr_in *)&ar->arp_pa;
515 if (bynumber == 0)
516 hp = gethostbyaddr((caddr_t)&sin->sin_addr,
517 sizeof(struct in_addr), AF_INET);
518 else
519 hp = 0;
521 if (hp)
522 host = hp->h_name;
523 else {
524 host = "?";
525 if (h_errno == TRY_AGAIN)
526 bynumber = 1;
529 Printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
530 if (ar->arp_flags & ATF_COM)
531 sana_print(ar->arp_ha.sa_data, ar->arp_ha.sa_len - 2);
532 else
533 Printf("(incomplete)");
534 if (ar->arp_flags & ATF_PERM)
535 Printf(" permanent");
536 if (ar->arp_flags & ATF_PUBL)
537 Printf(" published");
538 if (ar->arp_flags & ATF_USETRAILERS)
539 Printf(" trailers");
540 Printf("\n");
542 return bynumber;
545 static void
546 sana_print(const u_char *cp, int len)
548 char format[] =
549 "%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx";
550 int i; ULONG o[16];
552 if (len) {
553 format[4*len - 1] = '\0';
554 for (i = 0; i < len; i++)
555 o[i] = cp[i];
556 VPrintf(format, (RAWARG)o);
560 static int
561 sana_aton(const char *str, u_char *n, u_char *lenp)
563 int i, chars, o[16];
564 u_char c;
565 const char *a = str;
567 for (i = 0; i < 16; a++) {
568 o[i] = chars = 0;
569 while ((c = *a - '0') <= 9
570 || (c = c - 'A' + '0' + 10) >= 9 && c < 16 /*ABCDEF*/
571 || (c = c - 'a' + 'A') >= 9 && c < 16) /*abcdef*/ {
572 a++; chars++;
573 o[i] = (o[i] << 4) + c;
574 if (o[i] >= 0x100)
575 return 1;
577 if (!chars)
578 return 1;
579 i++;
580 if (*a == '\0')
581 break;
582 else if (*a == ':')
583 continue;
584 return 1;
587 if (i >= 16) {
588 fprintf(stderr, "arp: invalid SANA-II address '%s'\n", str);
589 return (1);
592 *lenp = i;
593 while (i-- > 0)
594 n[i] = o[i];
595 return 0;
598 static void
599 usage(void)
601 puts(usage_str);
603 exit(1);