~peter-pearse/ubuntu/natty/net-tools/prop001

1 by Bernd Eckenfels
Import upstream version 1.60
1
/*
2
 * arp                This file contains an implementation of the command
3
 *              that maintains the kernel's ARP cache.  It is derived
4
 *              from Berkeley UNIX arp(8), but cleaner and with sup-
5
 *              port for devices other than Ethernet.
6
 *
7
 * NET-TOOLS    A collection of programs that form the base set of the
8
 *              NET-3 Networking Distribution for the LINUX operating
9
 *              system.
10
 *
5 by Tollef Fog Heen
* Merge with Debian
11
 * Version:     $Id: arp.c,v 1.24 2005/05/16 04:30:17 ecki Exp $
1 by Bernd Eckenfels
Import upstream version 1.60
12
 *
13
 * Maintainer:  Bernd 'eckes' Eckenfels, <net-tools@lina.inka.de>
14
 *
15
 * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
16
 *
17
 * Changes:
18
 *              (based on work from Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>)
19
 *              Alan Cox        :       modified for NET3
20
 *              Andrew Tridgell :       proxy arp netmasks
21
 *              Bernd Eckenfels :       -n option
22
 *              Bernd Eckenfels :       Use only /proc for display
23
 *       {1.60} Bernd Eckenfels :       new arpcode (-i) for 1.3.42 but works 
24
 *                                      with 1.2.x, too
25
 *       {1.61} Bernd Eckenfels :       more verbose messages
26
 *       {1.62} Bernd Eckenfels :       check -t for hw adresses and try to
27
 *                                      explain EINVAL (jeff)
28
 *970125 {1.63} Bernd Eckenfels :       -a print hardwarename instead of tiltle
29
 *970201 {1.64} Bernd Eckenfels :       net-features.h support
30
 *970203 {1.65} Bernd Eckenfels :       "#define" in "#if", 
31
 *                                      -H|-A additional to -t|-p
32
 *970214 {1.66} Bernd Eckenfels :       Fix optarg required for -H and -A
33
 *970412 {1.67} Bernd Eckenfels :       device=""; is default
34
 *970514 {1.68} Bernd Eckenfels :       -N and -D
35
 *970517 {1.69} Bernd Eckenfels :       usage() fixed
36
 *970622 {1.70} Bernd Eckenfels :       arp -d priv
37
 *970106 {1.80} Bernd Eckenfels :       new syntax without -D and with "dev <If>",
38
 *                                      ATF_MAGIC, ATF_DONTPUB support. 
39
 *                                      Typo fix (Debian Bug#5728 Giuliano Procida)
40
 *970803 {1.81} Bernd Eckenfels :       removed junk comment line 1
41
 *970925 {1.82} Bernd Eckenfels :       include fix for libc6
42
 *980213 (1.83) Phil Blundell:          set ATF_COM on new entries
43
 *980629 (1.84) Arnaldo Carvalho de Melo: gettext instead of catgets
44
 *990101 {1.85} Bernd Eckenfels		fixed usage and return codes
45
 *990105 (1.86) Phil Blundell:		don't ignore EINVAL in arp_set
46
 *991121 (1.87) Bernd Eckenfels:	yes --device has a mandatory arg
47
 *010404 (1.88) Arnaldo Carvalho de Melo: use setlocale
48
 *
49
 *              This program is free software; you can redistribute it
50
 *              and/or  modify it under  the terms of  the GNU General
51
 *              Public  License as  published  by  the  Free  Software
52
 *              Foundation;  either  version 2 of the License, or  (at
53
 *              your option) any later version.
54
 */
55
#include <sys/types.h>
56
#include <sys/socket.h>
57
#include <sys/ioctl.h>
58
#include <net/if.h>
59
/* #include <linux/netdevice.h> */
60
/* #include <linux/if_arp.h>    */
61
#include <net/if_arp.h>
62
#include <stdlib.h>
63
#include <stdio.h>
64
#include <errno.h>
65
#include <ctype.h>
66
#include <fcntl.h>
67
#include <string.h>
68
#include <getopt.h>
69
#include <unistd.h>
70
#include "net-support.h"
71
#include "pathnames.h"
72
#include "version.h"
73
#include "config.h"
74
#include "intl.h"
75
#include "util.h"
76
77
#define DFLT_AF	"inet"
78
#define DFLT_HW	"ether"
79
80
#define FEATURE_ARP
81
#include "lib/net-features.h"
82
83
char *Release = RELEASE, *Version = "arp 1.88 (2001-04-04)";
84
85
int opt_n = 0;			/* do not resolve addresses     */
86
int opt_N = 0;			/* use symbolic names           */
87
int opt_v = 0;			/* debugging output flag        */
88
int opt_D = 0;			/* HW-address is devicename     */
89
int opt_e = 0;			/* 0=BSD output, 1=new linux    */
90
int opt_a = 0;			/* all entries, substring match */
91
struct aftype *ap;		/* current address family       */
92
struct hwtype *hw;		/* current hardware type        */
93
int sockfd = 0;			/* active socket descriptor     */
94
int hw_set = 0;			/* flag if hw-type was set (-H) */
95
char device[16] = "";		/* current device               */
96
static void usage(void);
97
98
/* Delete an entry from the ARP cache. */
99
static int arp_del(char **args)
100
{
101
    char host[128];
102
    struct arpreq req;
103
    struct sockaddr sa;
104
    int flags = 0;
3 by Bernd Eckenfels
* typo fix in po/de.po for german arp command output (Closes: Bug #176151)
105
    int deleted = 0;
1 by Bernd Eckenfels
Import upstream version 1.60
106
107
    memset((char *) &req, 0, sizeof(req));
108
109
    /* Resolve the host name. */
110
    if (*args == NULL) {
111
	fprintf(stderr, _("arp: need host name\n"));
112
	return (-1);
113
    }
114
    safe_strncpy(host, *args, (sizeof host));
115
    if (ap->input(0, host, &sa) < 0) {
116
	ap->herror(host);
117
	return (-1);
118
    }
119
    /* If a host has more than one address, use the correct one! */
120
    memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
121
122
    if (hw_set)
123
	req.arp_ha.sa_family = hw->type;
124
125
    req.arp_flags = ATF_PERM;
126
    args++;
127
    while (*args != NULL) {
128
	if (opt_v)
129
	    fprintf(stderr, "args=%s\n", *args);
130
	if (!strcmp(*args, "pub")) {
131
	    flags |= 1;
132
	    args++;
133
	    continue;
134
	}
135
	if (!strcmp(*args, "priv")) {
136
	    flags |= 2;
137
	    args++;
138
	    continue;
139
	}
140
	if (!strcmp(*args, "temp")) {
141
	    req.arp_flags &= ~ATF_PERM;
142
	    args++;
143
	    continue;
144
	}
145
	if (!strcmp(*args, "trail")) {
146
	    req.arp_flags |= ATF_USETRAILERS;
147
	    args++;
148
	    continue;
149
	}
150
	if (!strcmp(*args, "dontpub")) {
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
151
#ifdef ATF_DONTPUB
1 by Bernd Eckenfels
Import upstream version 1.60
152
	    req.arp_flags |= ATF_DONTPUB;
153
#else
154
	    ENOSUPP("arp", "ATF_DONTPUB");
155
#endif
156
	    args++;
157
	    continue;
158
	}
159
	if (!strcmp(*args, "auto")) {
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
160
#ifdef ATF_MAGIC
1 by Bernd Eckenfels
Import upstream version 1.60
161
	    req.arp_flags |= ATF_MAGIC;
162
#else
163
	    ENOSUPP("arp", "ATF_MAGIC");
164
#endif
165
	    args++;
166
	    continue;
167
	}
168
	if (!strcmp(*args, "dev")) {
169
	    if (*++args == NULL)
170
		usage();
171
	    safe_strncpy(device, *args, sizeof(device));
172
	    args++;
173
	    continue;
174
	}
175
	if (!strcmp(*args, "netmask")) {
176
	    if (*++args == NULL)
177
		usage();
178
	    if (strcmp(*args, "255.255.255.255") != 0) {
179
		strcpy(host, *args);
180
		if (ap->input(0, host, &sa) < 0) {
181
		    ap->herror(host);
182
		    return (-1);
183
		}
184
		memcpy((char *) &req.arp_netmask, (char *) &sa,
185
		       sizeof(struct sockaddr));
186
		req.arp_flags |= ATF_NETMASK;
187
	    }
188
	    args++;
189
	    continue;
190
	}
191
	usage();
192
    }
3 by Bernd Eckenfels
* typo fix in po/de.po for german arp command output (Closes: Bug #176151)
193
194
    // if neighter priv nor pub is given, work on both
1 by Bernd Eckenfels
Import upstream version 1.60
195
    if (flags == 0)
196
	flags = 3;
197
198
    strcpy(req.arp_dev, device);
199
3 by Bernd Eckenfels
* typo fix in po/de.po for german arp command output (Closes: Bug #176151)
200
    /* unfortuatelly the kernel interface does not allow us to
201
       delete private entries anlone, so we need this hack
202
       to avoid "not found" errors if we try both. */
203
    deleted = 0;
1 by Bernd Eckenfels
Import upstream version 1.60
204
205
    /* Call the kernel. */
206
    if (flags & 2) {
207
	if (opt_v)
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
208
	    fprintf(stderr, "arp: SIOCDARP(dontpub)\n");
3 by Bernd Eckenfels
* typo fix in po/de.po for german arp command output (Closes: Bug #176151)
209
	if (ioctl(sockfd, SIOCDARP, &req) < 0) {
210
	    if ((errno == ENXIO) || (errno == ENOENT)) {
1 by Bernd Eckenfels
Import upstream version 1.60
211
		if (flags & 1)
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
212
		    goto dontpub;
1 by Bernd Eckenfels
Import upstream version 1.60
213
		printf(_("No ARP entry for %s\n"), host);
214
		return (-1);
215
	    }
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
216
	    perror("SIOCDARP(dontpub)");
1 by Bernd Eckenfels
Import upstream version 1.60
217
	    return (-1);
3 by Bernd Eckenfels
* typo fix in po/de.po for german arp command output (Closes: Bug #176151)
218
	} else
219
	  deleted = 1;
1 by Bernd Eckenfels
Import upstream version 1.60
220
    }
3 by Bernd Eckenfels
* typo fix in po/de.po for german arp command output (Closes: Bug #176151)
221
    if (!deleted && (flags & 1)) {
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
222
      dontpub:
1 by Bernd Eckenfels
Import upstream version 1.60
223
	req.arp_flags |= ATF_PUBL;
224
	if (opt_v)
225
	    fprintf(stderr, "arp: SIOCDARP(pub)\n");
226
	if (ioctl(sockfd, SIOCDARP, &req) < 0) {
3 by Bernd Eckenfels
* typo fix in po/de.po for german arp command output (Closes: Bug #176151)
227
	    if ((errno == ENXIO) || (errno == ENOENT)) {
1 by Bernd Eckenfels
Import upstream version 1.60
228
		printf(_("No ARP entry for %s\n"), host);
229
		return (-1);
230
	    }
231
	    perror("SIOCDARP(pub)");
232
	    return (-1);
233
	}
234
    }
235
    return (0);
236
}
237
238
/* Get the hardware address to a specified interface name */
239
static int arp_getdevhw(char *ifname, struct sockaddr *sa, struct hwtype *hw)
240
{
241
    struct ifreq ifr;
242
    struct hwtype *xhw;
243
244
    strcpy(ifr.ifr_name, ifname);
245
    if (ioctl(sockfd, SIOCGIFHWADDR, &ifr) < 0) {
246
	fprintf(stderr, _("arp: cant get HW-Address for `%s': %s.\n"), ifname, strerror(errno));
247
	return (-1);
248
    }
249
    if (hw && (ifr.ifr_hwaddr.sa_family != hw->type)) {
250
	fprintf(stderr, _("arp: protocol type mismatch.\n"));
251
	return (-1);
252
    }
253
    memcpy((char *) sa, (char *) &(ifr.ifr_hwaddr), sizeof(struct sockaddr));
254
255
    if (opt_v) {
256
	if (!(xhw = get_hwntype(ifr.ifr_hwaddr.sa_family)) || (xhw->print == 0)) {
257
	    xhw = get_hwntype(-1);
258
	}
259
	fprintf(stderr, _("arp: device `%s' has HW address %s `%s'.\n"), ifname, xhw->name, xhw->print((char *)&ifr.ifr_hwaddr.sa_data));
260
    }
261
    return (0);
262
}
263
264
/* Set an entry in the ARP cache. */
265
static int arp_set(char **args)
266
{
267
    char host[128];
268
    struct arpreq req;
269
    struct sockaddr sa;
270
    int flags;
271
272
    memset((char *) &req, 0, sizeof(req));
273
274
    /* Resolve the host name. */
275
    if (*args == NULL) {
276
	fprintf(stderr, _("arp: need host name\n"));
277
	return (-1);
278
    }
279
    safe_strncpy(host, *args++, (sizeof host));
280
    if (ap->input(0, host, &sa) < 0) {
281
	ap->herror(host);
282
	return (-1);
283
    }
284
    /* If a host has more than one address, use the correct one! */
285
    memcpy((char *) &req.arp_pa, (char *) &sa, sizeof(struct sockaddr));
286
287
    /* Fetch the hardware address. */
288
    if (*args == NULL) {
289
	fprintf(stderr, _("arp: need hardware address\n"));
290
	return (-1);
291
    }
292
    if (opt_D) {
293
	if (arp_getdevhw(*args++, &req.arp_ha, hw_set ? hw : NULL) < 0)
294
	    return (-1);
295
    } else {
296
	if (hw->input(*args++, &req.arp_ha) < 0) {
297
	    fprintf(stderr, _("arp: invalid hardware address\n"));
298
	    return (-1);
299
	}
300
    }
301
302
    /* Check out any modifiers. */
303
    flags = ATF_PERM | ATF_COM;
304
    while (*args != NULL) {
305
	if (!strcmp(*args, "temp")) {
306
	    flags &= ~ATF_PERM;
307
	    args++;
308
	    continue;
309
	}
310
	if (!strcmp(*args, "pub")) {
311
	    flags |= ATF_PUBL;
312
	    args++;
313
	    continue;
314
	}
315
	if (!strcmp(*args, "priv")) {
316
	    flags &= ~ATF_PUBL;
317
	    args++;
318
	    continue;
319
	}
320
	if (!strcmp(*args, "trail")) {
321
	    flags |= ATF_USETRAILERS;
322
	    args++;
323
	    continue;
324
	}
325
	if (!strcmp(*args, "dontpub")) {
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
326
#ifdef ATF_DONTPUB
1 by Bernd Eckenfels
Import upstream version 1.60
327
	    flags |= ATF_DONTPUB;
328
#else
329
	    ENOSUPP("arp", "ATF_DONTPUB");
330
#endif
331
	    args++;
332
	    continue;
333
	}
334
	if (!strcmp(*args, "auto")) {
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
335
#ifdef ATF_MAGIC
1 by Bernd Eckenfels
Import upstream version 1.60
336
	    flags |= ATF_MAGIC;
337
#else
338
	    ENOSUPP("arp", "ATF_MAGIC");
339
#endif
340
	    args++;
341
	    continue;
342
	}
343
	if (!strcmp(*args, "dev")) {
344
	    if (*++args == NULL)
345
		usage();
346
	    safe_strncpy(device, *args, sizeof(device));
347
	    args++;
348
	    continue;
349
	}
350
	if (!strcmp(*args, "netmask")) {
351
	    if (*++args == NULL)
352
		usage();
353
	    if (strcmp(*args, "255.255.255.255") != 0) {
354
		strcpy(host, *args);
355
		if (ap->input(0, host, &sa) < 0) {
356
		    ap->herror(host);
357
		    return (-1);
358
		}
359
		memcpy((char *) &req.arp_netmask, (char *) &sa,
360
		       sizeof(struct sockaddr));
361
		flags |= ATF_NETMASK;
362
	    }
363
	    args++;
364
	    continue;
365
	}
366
	usage();
367
    }
368
369
    /* Fill in the remainder of the request. */
370
    req.arp_flags = flags;
371
372
    strcpy(req.arp_dev, device);
373
374
    /* Call the kernel. */
375
    if (opt_v)
376
	fprintf(stderr, "arp: SIOCSARP()\n");
377
    if (ioctl(sockfd, SIOCSARP, &req) < 0) {
378
        perror("SIOCSARP");
379
	return (-1);
380
    }
381
    return (0);
382
}
383
384
385
/* Process an EtherFile */
386
static int arp_file(char *name)
387
{
388
    char buff[1024];
389
    char *sp, *args[32];
390
    int linenr, argc;
391
    FILE *fp;
392
393
    if ((fp = fopen(name, "r")) == NULL) {
394
	fprintf(stderr, _("arp: cannot open etherfile %s !\n"), name);
395
	return (-1);
396
    }
397
    /* Read the lines in the file. */
398
    linenr = 0;
399
    while (fgets(buff, sizeof(buff), fp) != (char *) NULL) {
400
	linenr++;
401
	if (opt_v == 1)
402
	    fprintf(stderr, ">> %s", buff);
403
	if ((sp = strchr(buff, '\n')) != (char *) NULL)
404
	    *sp = '\0';
405
	if (buff[0] == '#' || buff[0] == '\0')
406
	    continue;
407
408
	argc = getargs(buff, args);
409
	if (argc < 2) {
410
	    fprintf(stderr, _("arp: format error on line %u of etherfile %s !\n"),
411
		    linenr, name);
412
	    continue;
413
	}
414
	if (strchr (args[0], ':') != NULL) {
415
	    /* We have a correct ethers file, switch hw adress and hostname
416
	       for arp */
417
	    char *cp;
418
	    cp = args[1];
419
	    args[1] = args[0];
420
	    args[0] = cp;
421
	}
422
	if (arp_set(args) != 0)
423
	    fprintf(stderr, _("arp: cannot set entry on line %u of etherfile %s !\n"),
424
		    linenr, name);
425
    }
426
427
    (void) fclose(fp);
428
    return (0);
429
}
430
431
432
/* Print the contents of an ARP request block. */
433
static void arp_disp_2(char *name, int type, int arp_flags, char *hwa, char *mask, char *dev)
434
{
435
    static int title = 0;
436
    struct hwtype *xhw;
437
    char flags[10];
438
439
    xhw = get_hwntype(type);
440
    if (xhw == NULL)
441
	xhw = get_hwtype(DFLT_HW);
442
443
    if (title++ == 0) {
444
	printf(_("Address                  HWtype  HWaddress           Flags Mask            Iface\n"));
445
    }
446
    /* Setup the flags. */
447
    flags[0] = '\0';
448
    if (arp_flags & ATF_COM)
449
	strcat(flags, "C");
450
    if (arp_flags & ATF_PERM)
451
	strcat(flags, "M");
452
    if (arp_flags & ATF_PUBL)
453
	strcat(flags, "P");
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
454
#ifdef ATF_MAGIC
1 by Bernd Eckenfels
Import upstream version 1.60
455
    if (arp_flags & ATF_MAGIC)
456
	strcat(flags, "A");
457
#endif
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
458
#ifdef ATF_DONTPUB
1 by Bernd Eckenfels
Import upstream version 1.60
459
    if (arp_flags & ATF_DONTPUB)
460
	strcat(flags, "!");
461
#endif
462
    if (arp_flags & ATF_USETRAILERS)
463
	strcat(flags, "T");
464
465
    if (!(arp_flags & ATF_NETMASK))
466
	mask = "";
467
468
    printf("%-23.23s  ", name);
469
470
    if (!(arp_flags & ATF_COM)) {
471
	if (arp_flags & ATF_PUBL)
3 by Bernd Eckenfels
* typo fix in po/de.po for german arp command output (Closes: Bug #176151)
472
	    printf("%-8.8s%-20.20s", "*", _("<from_interface>"));
1 by Bernd Eckenfels
Import upstream version 1.60
473
	else
474
	    printf("%-8.8s%-20.20s", "", _("(incomplete)"));
475
    } else {
476
	printf("%-8.8s%-20.20s", xhw->name, hwa);
477
    }
478
479
    printf("%-6.6s%-15.15s %s\n", flags, mask, dev);
480
}
481
482
/* Print the contents of an ARP request block. */
483
static void arp_disp(char *name, char *ip, int type, int arp_flags, char *hwa, char *mask, char *dev)
484
{
485
    struct hwtype *xhw;
486
487
    xhw = get_hwntype(type);
488
    if (xhw == NULL)
489
	xhw = get_hwtype(DFLT_HW);
490
491
    printf(_("%s (%s) at "), name, ip);
492
493
    if (!(arp_flags & ATF_COM)) {
494
	if (arp_flags & ATF_PUBL)
3 by Bernd Eckenfels
* typo fix in po/de.po for german arp command output (Closes: Bug #176151)
495
	    printf("<from_interface> ");
1 by Bernd Eckenfels
Import upstream version 1.60
496
	else
497
	    printf(_("<incomplete> "));
498
    } else {
499
	printf("%s [%s] ", hwa, xhw->name);
500
    }
501
502
    if (arp_flags & ATF_NETMASK)
503
	printf(_("netmask %s "), mask);
504
505
    if (arp_flags & ATF_PERM)
506
	printf("PERM ");
507
    if (arp_flags & ATF_PUBL)
3 by Bernd Eckenfels
* typo fix in po/de.po for german arp command output (Closes: Bug #176151)
508
	printf("PUB ");
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
509
#ifdef ATF_MAGIC
1 by Bernd Eckenfels
Import upstream version 1.60
510
    if (arp_flags & ATF_MAGIC)
511
	printf("AUTO ");
512
#endif
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
513
#ifdef ATF_DONTPUB
1 by Bernd Eckenfels
Import upstream version 1.60
514
    if (arp_flags & ATF_DONTPUB)
515
	printf("DONTPUB ");
516
#endif
517
    if (arp_flags & ATF_USETRAILERS)
518
	printf("TRAIL ");
519
520
    printf(_("on %s\n"), dev);
521
}
522
523
524
/* Display the contents of the ARP cache in the kernel. */
525
static int arp_show(char *name)
526
{
527
    char host[100];
528
    struct sockaddr sa;
529
    char ip[100];
530
    char hwa[100];
531
    char mask[100];
532
    char line[200];
533
    char dev[100];
534
    int type, flags;
535
    FILE *fp;
536
    char *hostname;
537
    int num, entries = 0, showed = 0;
538
539
    host[0] = '\0';
540
541
    if (name != NULL) {
542
	/* Resolve the host name. */
543
	safe_strncpy(host, name, (sizeof host));
544
	if (ap->input(0, host, &sa) < 0) {
545
	    ap->herror(host);
546
	    return (-1);
547
	}
548
	safe_strncpy(host, ap->sprint(&sa, 1), sizeof(host));
549
    }
550
    /* Open the PROCps kernel table. */
551
    if ((fp = fopen(_PATH_PROCNET_ARP, "r")) == NULL) {
552
	perror(_PATH_PROCNET_ARP);
553
	return (-1);
554
    }
555
    /* Bypass header -- read until newline */
556
    if (fgets(line, sizeof(line), fp) != (char *) NULL) {
557
	strcpy(mask, "-");
558
	strcpy(dev, "-");
559
	/* Read the ARP cache entries. */
560
	for (; fgets(line, sizeof(line), fp);) {
561
	    num = sscanf(line, "%s 0x%x 0x%x %100s %100s %100s\n",
562
			 ip, &type, &flags, hwa, mask, dev);
563
	    if (num < 4)
564
		break;
565
566
	    entries++;
567
	    /* if the user specified hw-type differs, skip it */
568
	    if (hw_set && (type != hw->type))
569
		continue;
570
571
	    /* if the user specified address differs, skip it */
572
	    if (host[0] && strcmp(ip, host))
573
		continue;
574
575
	    /* if the user specified device differs, skip it */
576
	    if (device[0] && strcmp(dev, device))
577
		continue;
578
579
	    showed++;
580
	    /* This IS ugly but it works -be */
581
	    if (opt_n)
582
		hostname = "?";
583
	    else {
584
		if (ap->input(0, ip, &sa) < 0)
585
		    hostname = ip;
586
		else
587
		    hostname = ap->sprint(&sa, opt_n | 0x8000);
588
		if (strcmp(hostname, ip) == 0)
589
		    hostname = "?";
590
	    }
591
592
	    if (opt_e)
593
		arp_disp_2(hostname[0] == '?' ? ip : hostname, type, flags, hwa, mask, dev);
594
	    else
595
		arp_disp(hostname, ip, type, flags, hwa, mask, dev);
596
	}
597
    }
598
    if (opt_v)
599
	printf(_("Entries: %d\tSkipped: %d\tFound: %d\n"), entries, entries - showed, showed);
600
601
    if (!showed) {
602
	if (host[0] && !opt_a)
603
	    printf(_("%s (%s) -- no entry\n"), name, host);
604
	else if (hw_set || host[0] || device[0]) {
605
	    printf(_("arp: in %d entries no match found.\n"), entries);
606
	}
607
    }
608
    (void) fclose(fp);
609
    return (0);
610
}
611
612
static void version(void)
613
{
614
    fprintf(stderr, "%s\n%s\n%s\n", Release, Version, Features);
615
    exit(E_VERSION);
616
}
617
618
static void usage(void)
619
{
620
    fprintf(stderr, _("Usage:\n  arp [-vn]  [<HW>] [-i <if>] [-a] [<hostname>]             <-Display ARP cache\n"));
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
621
    fprintf(stderr, _("  arp [-v]          [-i <if>] -d  <host> [pub]               <-Delete ARP entry\n"));
3 by Bernd Eckenfels
* typo fix in po/de.po for german arp command output (Closes: Bug #176151)
622
    fprintf(stderr, _("  arp [-vnD] [<HW>] [-i <if>] -f  [<filename>]            <-Add entry from file\n"));
4 by Ian Jackson
Look up TCP/UDP protocol numbers using correct protocol, not
623
    fprintf(stderr, _("  arp [-v]   [<HW>] [-i <if>] -s  <host> <hwaddr> [temp]            <-Add entry\n"));
624
    fprintf(stderr, _("  arp [-v]   [<HW>] [-i <if>] -Ds <host> <if> [netmask <nm>] pub          <-''-\n\n"));
1 by Bernd Eckenfels
Import upstream version 1.60
625
    
626
    fprintf(stderr, _("        -a                       display (all) hosts in alternative (BSD) style\n"));
627
    fprintf(stderr, _("        -s, --set                set a new ARP entry\n"));
628
    fprintf(stderr, _("        -d, --delete             delete a specified entry\n"));
629
    fprintf(stderr, _("        -v, --verbose            be verbose\n"));
630
    fprintf(stderr, _("        -n, --numeric            don't resolve names\n"));
631
    fprintf(stderr, _("        -i, --device             specify network interface (e.g. eth0)\n"));
632
    fprintf(stderr, _("        -D, --use-device         read <hwaddr> from given device\n"));
633
    fprintf(stderr, _("        -A, -p, --protocol       specify protocol family\n"));
634
    fprintf(stderr, _("        -f, --file               read new entries from file or from /etc/ethers\n\n"));
635
636
    fprintf(stderr, _("  <HW>=Use '-H <hw>' to specify hardware address type. Default: %s\n"), DFLT_HW);
637
    fprintf(stderr, _("  List of possible hardware types (which support ARP):\n"));
638
    print_hwlist(1); /* 1 = ARPable */
639
    exit(E_USAGE);
640
}
641
642
int main(int argc, char **argv)
643
{
644
    int i, lop, what;
645
    struct option longopts[] =
646
    {
647
	{"verbose", 0, 0, 'v'},
648
	{"version", 0, 0, 'V'},
649
	{"all", 0, 0, 'a'},
650
	{"delete", 0, 0, 'd'},
651
	{"file", 0, 0, 'f'},
652
	{"numeric", 0, 0, 'n'},
653
	{"set", 0, 0, 's'},
654
	{"protocol", 1, 0, 'A'},
655
	{"hw-type", 1, 0, 'H'},
656
	{"device", 1, 0, 'i'},
657
	{"help", 0, 0, 'h'},
658
	{"use-device", 0, 0, 'D'},
659
	{"symbolic", 0, 0, 'N'},
660
	{NULL, 0, 0, 0}
661
    };
662
663
#if I18N
664
    setlocale (LC_ALL, "");
665
    bindtextdomain("net-tools", "/usr/share/locale");
666
    textdomain("net-tools");
667
#endif
668
669
    /* Initialize variables... */
670
    if ((hw = get_hwtype(DFLT_HW)) == NULL) {
671
	fprintf(stderr, _("%s: hardware type not supported!\n"), DFLT_HW);
672
	return (-1);
673
    }
674
    if ((ap = get_aftype(DFLT_AF)) == NULL) {
675
	fprintf(stderr, _("%s: address family not supported!\n"), DFLT_AF);
676
	return (-1);
677
    }
678
    what = 0;
679
680
    /* Fetch the command-line arguments. */
681
    /* opterr = 0; */
682
    while ((i = getopt_long(argc, argv, "A:H:adfp:nsei:t:vh?DNV", longopts, &lop)) != EOF)
683
	switch (i) {
684
	case 'a':
685
	    what = 1;
686
	    opt_a = 1;
687
	    break;
688
	case 'f':
689
	    what = 2;
690
	    break;
691
	case 'd':
692
	    what = 3;
693
	    break;
694
	case 's':
695
	    what = 4;
696
	    break;
697
698
699
	case 'e':
700
	    opt_e = 1;
701
	    break;
702
	case 'n':
703
	    opt_n = FLAG_NUM;
704
	    break;
705
	case 'D':
706
	    opt_D = 1;
707
	    break;
708
	case 'N':
709
	    opt_N = FLAG_SYM;
710
	    fprintf(stderr, _("arp: -N not yet supported.\n"));
711
	    break;
712
	case 'v':
713
	    opt_v = 1;
714
	    break;
715
716
	case 'A':
717
	case 'p':
718
	    ap = get_aftype(optarg);
719
	    if (ap == NULL) {
720
		fprintf(stderr, _("arp: %s: unknown address family.\n"),
721
			optarg);
722
		exit(-1);
723
	    }
724
	    break;
725
	case 'H':
726
	case 't':
727
	    hw = get_hwtype(optarg);
728
	    if (hw == NULL) {
729
		fprintf(stderr, _("arp: %s: unknown hardware type.\n"),
730
			optarg);
731
		exit(-1);
732
	    }
733
	    hw_set = 1;
734
	    break;
735
	case 'i':
736
	    safe_strncpy(device, optarg, sizeof(device));
737
	    break;
738
739
	case 'V':
740
	    version();
741
	case '?':
742
	case 'h':
743
	default:
744
	    usage();
745
	}
746
747
    if (ap->af != AF_INET) {
748
	fprintf(stderr, _("arp: %s: kernel only supports 'inet'.\n"),
749
		ap->name);
750
	exit(-1);
751
    }
752
753
    /* If not hw type specified get default */
754
    if(hw_set==0)
755
	if ((hw = get_hwtype(DFLT_HW)) == NULL) {
756
	  fprintf(stderr, _("%s: hardware type not supported!\n"), DFLT_HW);
757
	  return (-1);
758
	}
759
760
    if (hw->alen <= 0) {
761
	fprintf(stderr, _("arp: %s: hardware type without ARP support.\n"),
762
		hw->name);
763
	exit(-1);
764
    }
765
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
766
	perror("socket");
767
	exit(-1);
768
    }
769
    /* Now see what we have to do here... */
770
    switch (what) {
771
    case 0:
772
	opt_e = 1;
773
	what = arp_show(argv[optind]);
774
	break;
775
776
    case 1:			/* show an ARP entry in the cache */
777
	what = arp_show(argv[optind]);
778
	break;
779
780
    case 2:			/* process an EtherFile */
781
	what = arp_file(argv[optind] ? argv[optind] : "/etc/ethers");
782
	break;
783
784
    case 3:			/* delete an ARP entry from the cache */
785
	what = arp_del(&argv[optind]);
786
	break;
787
788
    case 4:			/* set an ARP entry in the cache */
789
	what = arp_set(&argv[optind]);
790
	break;
791
792
    default:
793
	usage();
794
    }
795
796
    exit(what);
797
}