4 Created: Jan 2001 by Philip Homburg <philip@f-mnx.phicoh.com>
9 #define _POSIX_C_SOURCE 2
10 #define _NETBSD_SOURCE 1
20 #include <sys/ioctl.h>
22 #include <net/netlib.h>
23 #include <net/gen/ether.h>
24 #include <net/gen/if_ether.h>
25 #include <net/gen/in.h>
26 #include <net/gen/inet.h>
27 #include <net/gen/ip_io.h>
29 #include <net/gen/socket.h>
31 #include <net/gen/arp_io.h>
33 #include <arpa/inet.h>
37 static int do_setuid
= 0;
39 static void do_open(char *devname
);
40 static void show_one(char *hostname
, int do_num
);
41 static void show_all(int do_num
);
42 static void print_one(ipaddr_t ipaddr
, nwio_arp_t
*arpp
, int do_num
);
43 static void delete_all(void);
44 static void delete(char *hostname
);
45 static void do_set(char *hostname
, char *ethername
, int temp
, int pub
,
47 static ipaddr_t
nametoipaddr(char *hostname
);
48 static void fatal(const char *fmt
, ...);
49 static void usage(void);
51 int main(int argc
, char *argv
[])
54 char *hostname
, *ethername
;
56 int a_flag
, d_flag
, n_flag
, s_flag
, S_flag
;
59 (progname
=strrchr(argv
[0],'/')) ? progname
++ : (progname
=argv
[0]);
61 a_flag
= d_flag
= n_flag
= s_flag
= S_flag
= 0;
63 while(c
= getopt(argc
, argv
, "adnsS?I:"), c
!= -1)
68 case 'a': a_flag
= 1; break;
69 case 'd': d_flag
= 1; break;
70 case 'n': n_flag
= 1; break;
71 case 's': s_flag
= 1; break;
72 case 'S': S_flag
= 1; break;
73 case 'I': I_arg
= optarg
; break;
74 default: fatal("getopt failed: '%c'", c
);
78 hostname
= NULL
; /* lint */
79 ethername
= NULL
; /* lint */
80 do_temp
= do_pub
= 0; /* lint */
82 if (n_flag
+ d_flag
+ s_flag
+ S_flag
> 1)
86 if (optind
>= argc
) usage();
87 hostname
= argv
[optind
++];
89 if (optind
>= argc
) usage();
90 ethername
= argv
[optind
++];
95 if (strcasecmp(argv
[optind
], "temp") == 0)
101 if (strcasecmp(argv
[optind
], "pub") == 0)
116 hostname
= argv
[optind
++];
131 hostname
= argv
[optind
++];
145 else if (s_flag
|| S_flag
)
146 do_set(hostname
, ethername
, do_temp
, do_pub
, S_flag
);
150 show_one(hostname
, n_flag
);
154 static void do_open(char *devname
)
159 if (do_setuid
&& devname
)
161 /* Only strings that consist of IP_DEVICE optionally
162 * followed by a number are allowed.
164 l
= strlen(IP_DEVICE
);
165 if (strncmp(devname
, IP_DEVICE
, l
) != 0)
167 else if (strlen(devname
) == l
)
171 strtoul(devname
+l
, &check
, 10);
172 if (check
[0] != '\0')
183 ipfd
= open(devname
, O_RDWR
);
185 fatal("unable to open '%s': %s", devname
, strerror(errno
));
188 static void show_one(char *hostname
, int do_num
)
194 ipaddr
= nametoipaddr(hostname
);
196 arp
.nwa_ipaddr
= ipaddr
;
197 r
= ioctl(ipfd
, NWIOARPGIP
, &arp
);
198 if (r
== -1 && errno
== ENOENT
)
200 print_one(ipaddr
, NULL
, do_num
);
204 fatal("NWIOARPGIP failed: %s", strerror(errno
));
205 print_one(ipaddr
, &arp
, do_num
);
208 static void show_all(int do_num
)
214 /* First get all entries */
217 arptab
= malloc(max
* sizeof(*arptab
));
220 fatal("out of memory, can't get %d bytes",
221 max
*sizeof(*arptab
));
229 arptab
= realloc(arptab
, max
* sizeof(*arptab
));
232 fatal("out of memory, can't get %d bytes",
233 max
*sizeof(*arptab
));
236 r
= ioctl(ipfd
, NWIOARPGNEXT
, &arp
);
237 if (r
== -1 && errno
== ENOENT
)
240 fatal("NWIOARPGNEXT failed: %s", strerror(errno
));
245 for (i
= 0; i
<ind
; i
++)
246 print_one(0, &arptab
[i
], do_num
);
249 static void print_one(ipaddr_t ipaddr
, nwio_arp_t
*arpp
, int do_num
)
255 ipaddr
= arpp
->nwa_ipaddr
;
257 he
= gethostbyaddr((char *)&ipaddr
, sizeof(ipaddr
), AF_INET
);
261 printf("%s (%s)", he
->h_name
,
262 inet_ntoa(*(struct in_addr
*)&ipaddr
));
264 printf("%s", inet_ntoa(*(struct in_addr
*)&ipaddr
));
267 printf(" -- no entry\n");
270 flags
= arpp
->nwa_flags
;
271 if (flags
& NWAF_INCOMPLETE
)
272 printf(" is incomplete");
273 else if (flags
& NWAF_DEAD
)
277 printf(" is at %s", ether_ntoa(&arpp
->nwa_ethaddr
));
278 if (flags
& NWAF_PERM
)
279 printf(" permanent");
280 if (flags
& NWAF_PUB
)
281 printf(" published");
286 static void delete_all(void)
292 /* First get all entries */
295 arptab
= malloc(max
* sizeof(*arptab
));
298 fatal("out of memory, can't get %d bytes",
299 max
*sizeof(*arptab
));
307 arptab
= realloc(arptab
, max
* sizeof(*arptab
));
310 fatal("out of memory, can't get %d bytes",
311 max
*sizeof(*arptab
));
314 r
= ioctl(ipfd
, NWIOARPGNEXT
, &arp
);
315 if (r
== -1 && errno
== ENOENT
)
318 fatal("NWIOARPGNEXT failed: %s", strerror(errno
));
323 for (i
= 0; i
<ind
; i
++)
325 r
= ioctl(ipfd
, NWIOARPDIP
, &arptab
[i
]);
328 if (errno
== EINVAL
|| errno
== ENOENT
)
330 /* Entry is incomplete of entry is already deleted */
333 fatal("unable to delete host %s: %s",
334 inet_ntoa(*(struct in_addr
*)&arptab
[i
].nwa_ipaddr
),
339 static void delete(char *hostname
)
345 ipaddr
= nametoipaddr(hostname
);
346 arp
.nwa_ipaddr
= ipaddr
;
347 r
= ioctl(ipfd
, NWIOARPDIP
, &arp
);
352 print_one(ipaddr
, NULL
, 0);
355 fatal("unable to delete host %s: %s",
356 inet_ntoa(*(struct in_addr
*)&ipaddr
),
357 errno
== EINVAL
? "entry is incomplete" : strerror(errno
));
360 static void do_set(char *hostname
, char *ethername
, int temp
, int pub
,
366 ether_addr_t ethaddr
;
368 nwio_ipconf_t ipconf
;
370 ipaddr
= nametoipaddr(hostname
);
371 if (pub
&& strcasecmp(ethername
, "auto") == 0)
373 r
= ioctl(ipfd
, NWIOGIPCONF
, &ipconf
);
375 fatal("NWIOGIPCONF failed: %s", strerror(errno
));
376 arp
.nwa_ipaddr
= ipconf
.nwic_ipaddr
;
377 r
= ioctl(ipfd
, NWIOARPGIP
, &arp
);
379 fatal("NWIOARPGIP failed: %s", strerror(errno
));
380 ethaddr
= arp
.nwa_ethaddr
;
382 else if (eap
= ether_aton(ethername
), eap
!= NULL
)
384 else if (ether_hostton(ethername
, ðaddr
) != 0)
386 fatal("unable to parse ethernet address '%s'",
392 arp
.nwa_ipaddr
= ipaddr
;
393 r
= ioctl(ipfd
, NWIOARPDIP
, &arp
);
394 if (r
== -1 && errno
!= ENOENT
)
396 fatal("unable to delete entry for host %s: %s",
397 inet_ntoa(*(struct in_addr
*)&ipaddr
),
398 errno
== EINVAL
? "incomplete entry" :
403 arp
.nwa_ipaddr
= ipaddr
;
404 arp
.nwa_ethaddr
= ethaddr
;
407 arp
.nwa_flags
|= NWAF_PUB
;
409 arp
.nwa_flags
|= NWAF_PERM
;
410 r
= ioctl(ipfd
, NWIOARPSIP
, &arp
);
413 fatal("unable to set arp entry: %s",
414 errno
== EEXIST
? "entry exists" : strerror(errno
));
418 static ipaddr_t
nametoipaddr(char *hostname
)
423 if (inet_aton(hostname
, (struct in_addr
*)&ipaddr
) == 0)
425 he
= gethostbyname(hostname
);
427 fatal("unknown hostname '%s'", hostname
);
428 if (he
->h_addrtype
!= AF_INET
||
429 he
->h_length
!= sizeof(ipaddr
))
431 fatal("strange host '%s': addrtype %d, length %d",
432 he
->h_addrtype
, he
->h_length
);
434 memcpy(&ipaddr
, he
->h_addr
, sizeof(ipaddr
));
440 static char *ether_ntoa(struct ether_addr
*eap
)
442 static char buf
[]= "xx:xx:xx:xx:xx:xx";
444 sprintf(buf
, "%02x:%02x:%02x:%02x:%02x:%02x",
445 eap
->ea_addr
[0], eap
->ea_addr
[1],
446 eap
->ea_addr
[2], eap
->ea_addr
[3],
447 eap
->ea_addr
[4], eap
->ea_addr
[5]);
452 static void fatal(const char *fmt
, ...)
457 fprintf(stderr
, "%s: ", progname
);
458 vfprintf(stderr
, fmt
, ap
);
459 fprintf(stderr
, "\n");
465 static void usage(void)
467 fprintf(stderr
, "Usage:\tarp [-I ip-dev] [-n] hostname\n"
468 "\tarp [-I ip-dev] [-n] -a\n"
469 "\tarp [-I ip-dev] -d hostname\n"
470 "\tarp [-I ip-dev] -d -a\n"
471 "\tarp [-I ip-dev] -s hostname ether-addr [temp] [pub]\n"
472 "\tarp [-I ip-dev] -S hostname ether-addr [temp] [pub]\n");
477 * $PchId: arp.c,v 1.3 2005/01/31 22:31:45 philip Exp $