Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / network / stacks / AROSTCP / C / arp.c
blob4d2db94ce612776e049ea9ade6d5a4f96781f798
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[] = "$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 extern int errno;
179 #warning "TODO: NicJA - h_errno should be extern .."
180 int h_errno;
182 static int file(char *name);
183 static int set(int argc, char **argv);
184 static void get(char *host);
185 static void delete(char *host);
186 static int arpreq_print(struct arpreq *ar, int bynumber);
187 static void sana_print(const u_char *cp, int len);
188 static int sana_aton(const char *a, u_char *n, u_char *lenp);
189 static void usage(void);
190 static void dump(char *name);
191 char * strsep(register char **stringp, register const char *delim);
193 char usage_str[] =
194 "usage: arp hostname\n"
195 " arp -a [netname | hostname]\n"
196 " arp -d hostname\n"
197 " arp -s hostname address [temp] [pub]\n"
198 " arp -f filename\n";
200 #define SOCKET_VERSION 3
201 const TEXT socket_name[] = "bsdsocket.library";
203 main(argc, argv)
204 int argc;
205 char **argv;
207 int ch;
209 if (!(SocketBase = OpenLibrary(socket_name, SOCKET_VERSION)))
211 return RETURN_FAIL;
214 while ((ch = getopt(argc, argv, "adsf")) != EOF)
215 switch((char)ch) {
216 case 'a': {
217 char *net;
218 char myname[MAXHOSTNAMELEN];
220 if (argc > 3)
221 usage();
222 if (argc == 3) {
223 net = argv[2];
224 } else {
225 net = myname;
226 gethostname(myname, sizeof(myname));
228 dump(net);
229 exit(0);
231 case 'd':
232 if (argc != 3)
233 usage();
234 delete(argv[2]);
235 exit(0);
236 case 's':
237 if (argc < 4 || argc > 7)
238 usage();
239 exit(set(argc-2, &argv[2]) ? 1 : 0);
240 case 'f':
241 if (argc != 3)
242 usage();
243 exit (file(argv[2]) ? 1 : 0);
244 case '?':
245 default:
246 usage();
248 if (argc != 2)
249 usage();
250 get(argv[1]);
251 exit(0);
255 * Process a file to set standard arp entries
257 static int
258 file(char *name)
260 FILE *fp;
261 int i, retval;
262 char line[100], arg[5][50], *args[5];
264 if ((fp = fopen(name, "r")) == NULL) {
265 fprintf(stderr, "arp: cannot open %s\n", name);
266 exit(1);
269 args[0] = &arg[0][0];
270 args[1] = &arg[1][0];
271 args[2] = &arg[2][0];
272 args[3] = &arg[3][0];
273 args[4] = &arg[4][0];
275 retval = 0;
276 while(fgets(line, 100, fp) != NULL) {
277 i = sscanf(line, "%s %s %s %s %s", arg[0], arg[1], arg[2], arg[3], arg[4]);
278 if (i < 2) {
279 fprintf(stderr, "arp: bad line: %s\n", line);
280 retval = 1;
281 continue;
283 if (set(i, args))
284 retval = 1;
286 fclose(fp);
287 return (retval);
291 * Set an individual arp entry
293 static int
294 set(int argc, char **argv)
296 struct arpreq ar;
297 struct hostent *hp;
298 struct sockaddr_in *sin;
299 u_char *ea;
300 int s;
301 char *host = argv[0], *eaddr = argv[1];
303 argc -= 2;
304 argv += 2;
305 bzero((caddr_t)&ar, sizeof ar);
306 sin = (struct sockaddr_in *)&ar.arp_pa;
307 sin->sin_len = sizeof(*sin);
308 sin->sin_family = AF_INET;
309 sin->sin_addr.s_addr = inet_addr(host);
310 if (sin->sin_addr.s_addr == -1) {
311 if (!(hp = gethostbyname(host))) {
312 fprintf(stderr, "arp: %s: ", host);
313 #warning "TODO: NicJA - Implement herror()"
314 #if !defined(__AROS__)
315 herror((char *)NULL);
316 #endif
317 return (1);
319 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
320 sizeof sin->sin_addr);
322 ea = (u_char *)ar.arp_ha.sa_data;
323 if (sana_aton(eaddr, ea, &ar.arp_ha.sa_len))
324 return (1);
325 ar.arp_ha.sa_len += 2;
326 ar.arp_flags = ATF_PERM;
327 while (argc-- > 0) {
328 if (strncmp(argv[0], "temp", 4) == 0)
329 ar.arp_flags &= ~ATF_PERM;
330 else if (strncmp(argv[0], "pub", 3) == 0)
331 ar.arp_flags |= ATF_PUBL;
332 else if (strncmp(argv[0], "trail", 5) == 0)
333 ar.arp_flags |= ATF_USETRAILERS;
334 argv++;
337 s = socket(AF_INET, SOCK_DGRAM, 0);
338 if (s < 0) {
339 perror("arp: socket");
340 exit(1);
342 if (IoctlSocket(s, SIOCSARP, (caddr_t)&ar) < 0) {
343 perror(host);
344 exit(1);
346 CloseSocket(s);
348 return (0);
352 * Display an individual arp entry
354 static void
355 get(char *host)
357 struct arpreq ar;
358 struct hostent *hp;
359 struct sockaddr_in *sin;
360 int s;
362 bzero((caddr_t)&ar, sizeof ar);
363 sin = (struct sockaddr_in *)&ar.arp_pa;
364 sin->sin_len = sizeof(*sin);
365 sin->sin_family = AF_INET;
366 sin->sin_addr.s_addr = inet_addr(host);
367 if (sin->sin_addr.s_addr == -1) {
368 if (!(hp = gethostbyname(host))) {
369 fprintf(stderr, "arp: %s: ", host);
370 #warning "TODO: NicJA - Implement herror()"
371 #if !defined(__AROS__)
372 herror((char *)NULL);
373 #endif
374 exit(1);
376 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, sizeof sin->sin_addr);
378 s = socket(AF_INET, SOCK_DGRAM, 0);
379 if (s < 0) {
380 perror("arp: socket");
381 exit(1);
383 if (IoctlSocket(s, SIOCGARP, (caddr_t)&ar) < 0) {
384 if (errno == ENXIO)
385 printf("%s (%s) -- no entry\n", host, inet_ntoa(sin->sin_addr));
386 else
387 perror("SIOCGARP");
388 exit(1);
390 CloseSocket(s);
392 (void)arpreq_print(&ar, 0);
396 * Delete an arp entry
398 static void
399 delete(char *host)
401 struct arpreq ar;
402 struct hostent *hp;
403 struct sockaddr_in *sin;
404 int s;
406 bzero((caddr_t)&ar, sizeof ar);
407 sin = (struct sockaddr_in *)&ar.arp_pa;
408 sin->sin_len = sizeof(*sin);
409 sin->sin_family = AF_INET;
410 sin->sin_addr.s_addr = inet_addr(host);
411 if (sin->sin_addr.s_addr == -1) {
412 if (!(hp = gethostbyname(host))) {
413 fprintf(stderr, "arp: %s: ", host);
414 #warning "TODO: NicJA - Implement herror()"
415 #if !defined(__AROS__)
416 herror((char *)NULL);
417 #endif
418 exit(1);
420 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr,
421 sizeof sin->sin_addr);
423 s = socket(AF_INET, SOCK_DGRAM, 0);
424 if (s < 0) {
425 perror("arp: socket");
426 exit(1);
428 if (IoctlSocket(s, SIOCDARP, (caddr_t)&ar) < 0) {
429 if (errno == ENXIO)
430 printf("%s (%s) -- no entry\n",
431 host, inet_ntoa(sin->sin_addr));
432 else
433 perror("SIOCDARP");
434 exit(1);
436 CloseSocket(s);
437 printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
441 * Dump the entire arp table
443 static void
444 dump(char *host)
446 struct arptabreq atr;
447 struct arpreq *ar;
448 struct sockaddr_in *sin;
449 int s, bynumber;
450 long n;
452 bzero((caddr_t)&atr, sizeof atr);
454 /* Identify the used interface according the host/net name */
455 sin = (struct sockaddr_in *)&atr.atr_arpreq.arp_pa;
456 sin->sin_len = sizeof(*sin);
457 sin->sin_family = AF_INET;
458 sin->sin_addr.s_addr = inet_addr(host);
459 if (sin->sin_addr.s_addr == -1) {
460 struct hostent *hp;
461 struct netent *np = NULL;
462 if (!(hp = gethostbyname(host)) &&
463 !(np = getnetbyname(host))) {
464 fprintf(stderr, "arp: %s: ", host);
465 #warning "TODO: NicJA - Implement herror()"
466 #if !defined(__AROS__)
467 herror((char *)NULL);
468 #endif
469 exit(1);
471 if (hp)
472 bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, sizeof sin->sin_addr);
473 else
474 bcopy((char *)&np->n_net, (char *)&sin->sin_addr, sizeof np->n_net);
477 s = socket(AF_INET, SOCK_DGRAM, 0);
478 if (s < 0) {
479 perror("arp: socket");
480 exit(1);
483 if (IoctlSocket(s, SIOCGARPT, (caddr_t)&atr) < 0) {
484 perror("SIOCGARPT");
485 exit(1);
488 n = atr.atr_size = atr.atr_inuse;
489 if (n) {
490 ar = atr.atr_table = malloc(sizeof(*ar) * n);
491 if (!ar) {
492 perror("arp: malloc");
493 exit(1);
495 if (IoctlSocket(s, SIOCGARPT, (caddr_t)&atr) < 0) {
496 perror("SIOCGARPT");
497 exit(1);
499 /* Entries may be deleted */
500 n = max(n, atr.atr_inuse);
502 CloseSocket(s);
504 bynumber = 0;
505 while (n-- > 0) {
506 bynumber = arpreq_print(ar++, bynumber);
510 static int
511 arpreq_print(struct arpreq *ar, int bynumber)
513 struct sockaddr_in *sin;
514 struct hostent *hp;
515 char *host;
517 sin = (struct sockaddr_in *)&ar->arp_pa;
519 if (bynumber == 0)
520 hp = gethostbyaddr((caddr_t)&sin->sin_addr,
521 sizeof(struct in_addr), AF_INET);
522 else
523 hp = 0;
525 if (hp)
526 host = hp->h_name;
527 else {
528 host = "?";
529 if (h_errno == TRY_AGAIN)
530 bynumber = 1;
533 Printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
534 if (ar->arp_flags & ATF_COM)
535 sana_print(ar->arp_ha.sa_data, ar->arp_ha.sa_len - 2);
536 else
537 Printf("(incomplete)");
538 if (ar->arp_flags & ATF_PERM)
539 Printf(" permanent");
540 if (ar->arp_flags & ATF_PUBL)
541 Printf(" published");
542 if (ar->arp_flags & ATF_USETRAILERS)
543 Printf(" trailers");
544 Printf("\n");
546 return bynumber;
549 static void
550 sana_print(const u_char *cp, int len)
552 char format[] =
553 "%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx";
554 int i; long o[16];
556 if (len) {
557 format[4*len - 1] = '\0';
558 for (i = 0; i < len; i++)
559 o[i] = cp[i];
560 // vprintf(format, (va_list)o);
561 VPrintf(format, o);
565 static int
566 sana_aton(const char *str, u_char *n, u_char *lenp)
568 int i, chars, o[16];
569 u_char c;
570 const char *a = str;
572 for (i = 0; i < 16; a++) {
573 o[i] = chars = 0;
574 while ((c = *a - '0') <= 9
575 || (c = c - 'A' + '0' + 10) >= 9 && c < 16 /*ABCDEF*/
576 || (c = c - 'a' + 'A') >= 9 && c < 16) /*abcdef*/ {
577 a++; chars++;
578 o[i] = (o[i] << 4) + c;
579 if (o[i] >= 0x100)
580 return 1;
582 if (!chars)
583 return 1;
584 i++;
585 if (*a == '\0')
586 break;
587 else if (*a == ':')
588 continue;
589 return 1;
592 if (i >= 16) {
593 fprintf(stderr, "arp: invalid SANA-II address '%s'\n", str);
594 return (1);
597 *lenp = i;
598 while (i-- > 0)
599 n[i] = o[i];
600 return 0;
603 static void
604 usage(void)
606 printf(usage_str);
608 exit(1);