4 Created: Jan 2001 by Philip Homburg <philip@f-mnx.phicoh.com>
9 #define _POSIX_C_SOURCE 2
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>
28 #include <net/gen/netdb.h>
29 #include <net/gen/socket.h>
31 #include <net/gen/arp_io.h>
35 static int do_setuid
= 0;
37 static void do_open(char *devname
);
38 static void show_one(char *hostname
, int do_num
);
39 static void show_all(int do_num
);
40 static void print_one(ipaddr_t ipaddr
, nwio_arp_t
*arpp
, int do_num
);
41 static void delete_all(void);
42 static void delete(char *hostname
);
43 static void do_set(char *hostname
, char *ethername
, int temp
, int pub
,
45 static ipaddr_t
nametoipaddr(char *hostname
);
46 static void fatal(const char *fmt
, ...);
47 static void usage(void);
49 int main(int argc
, char *argv
[])
52 char *hostname
, *ethername
;
54 int a_flag
, d_flag
, n_flag
, s_flag
, S_flag
;
57 (progname
=strrchr(argv
[0],'/')) ? progname
++ : (progname
=argv
[0]);
59 a_flag
= d_flag
= n_flag
= s_flag
= S_flag
= 0;
61 while(c
= getopt(argc
, argv
, "adnsS?I:"), c
!= -1)
66 case 'a': a_flag
= 1; break;
67 case 'd': d_flag
= 1; break;
68 case 'n': n_flag
= 1; break;
69 case 's': s_flag
= 1; break;
70 case 'S': S_flag
= 1; break;
71 case 'I': I_arg
= optarg
; break;
72 default: fatal("getopt failed: '%c'", c
);
76 hostname
= NULL
; /* lint */
77 ethername
= NULL
; /* lint */
78 do_temp
= do_pub
= 0; /* lint */
80 if (n_flag
+ d_flag
+ s_flag
+ S_flag
> 1)
84 if (optind
>= argc
) usage();
85 hostname
= argv
[optind
++];
87 if (optind
>= argc
) usage();
88 ethername
= argv
[optind
++];
93 if (strcasecmp(argv
[optind
], "temp") == 0)
99 if (strcasecmp(argv
[optind
], "pub") == 0)
114 hostname
= argv
[optind
++];
129 hostname
= argv
[optind
++];
143 else if (s_flag
|| S_flag
)
144 do_set(hostname
, ethername
, do_temp
, do_pub
, S_flag
);
148 show_one(hostname
, n_flag
);
152 static void do_open(char *devname
)
157 if (do_setuid
&& devname
)
159 /* Only strings that consist of IP_DEVICE optionally
160 * followed by a number are allowed.
162 l
= strlen(IP_DEVICE
);
163 if (strncmp(devname
, IP_DEVICE
, l
) != 0)
165 else if (strlen(devname
) == l
)
169 strtoul(devname
+l
, &check
, 10);
170 if (check
[0] != '\0')
181 ipfd
= open(devname
, O_RDWR
);
183 fatal("unable to open '%s': %s", devname
, strerror(errno
));
186 static void show_one(char *hostname
, int do_num
)
192 ipaddr
= nametoipaddr(hostname
);
194 arp
.nwa_ipaddr
= ipaddr
;
195 r
= ioctl(ipfd
, NWIOARPGIP
, &arp
);
196 if (r
== -1 && errno
== ENOENT
)
198 print_one(ipaddr
, NULL
, do_num
);
202 fatal("NWIOARPGIP failed: %s", strerror(errno
));
203 print_one(ipaddr
, &arp
, do_num
);
206 static void show_all(int do_num
)
212 /* First get all entries */
215 arptab
= malloc(max
* sizeof(*arptab
));
218 fatal("out of memory, can't get %d bytes",
219 max
*sizeof(*arptab
));
227 arptab
= realloc(arptab
, max
* sizeof(*arptab
));
230 fatal("out of memory, can't get %d bytes",
231 max
*sizeof(*arptab
));
234 r
= ioctl(ipfd
, NWIOARPGNEXT
, &arp
);
235 if (r
== -1 && errno
== ENOENT
)
238 fatal("NWIOARPGNEXT failed: %s", strerror(errno
));
243 for (i
= 0; i
<ind
; i
++)
244 print_one(0, &arptab
[i
], do_num
);
247 static void print_one(ipaddr_t ipaddr
, nwio_arp_t
*arpp
, int do_num
)
253 ipaddr
= arpp
->nwa_ipaddr
;
255 he
= gethostbyaddr((char *)&ipaddr
, sizeof(ipaddr
), AF_INET
);
259 printf("%s (%s)", he
->h_name
, inet_ntoa(ipaddr
));
261 printf("%s", inet_ntoa(ipaddr
));
264 printf(" -- no entry\n");
267 flags
= arpp
->nwa_flags
;
268 if (flags
& NWAF_INCOMPLETE
)
269 printf(" is incomplete");
270 else if (flags
& NWAF_DEAD
)
274 printf(" is at %s", ether_ntoa(&arpp
->nwa_ethaddr
));
275 if (flags
& NWAF_PERM
)
276 printf(" permanent");
277 if (flags
& NWAF_PUB
)
278 printf(" published");
283 static void delete_all(void)
289 /* First get all entries */
292 arptab
= malloc(max
* sizeof(*arptab
));
295 fatal("out of memory, can't get %d bytes",
296 max
*sizeof(*arptab
));
304 arptab
= realloc(arptab
, max
* sizeof(*arptab
));
307 fatal("out of memory, can't get %d bytes",
308 max
*sizeof(*arptab
));
311 r
= ioctl(ipfd
, NWIOARPGNEXT
, &arp
);
312 if (r
== -1 && errno
== ENOENT
)
315 fatal("NWIOARPGNEXT failed: %s", strerror(errno
));
320 for (i
= 0; i
<ind
; i
++)
322 r
= ioctl(ipfd
, NWIOARPDIP
, &arptab
[i
]);
325 if (errno
== EINVAL
|| errno
== ENOENT
)
327 /* Entry is incomplete of entry is already deleted */
330 fatal("unable to delete host %s: %s",
331 inet_ntoa(arptab
[i
].nwa_ipaddr
), strerror(errno
));
335 static void delete(char *hostname
)
341 ipaddr
= nametoipaddr(hostname
);
342 arp
.nwa_ipaddr
= ipaddr
;
343 r
= ioctl(ipfd
, NWIOARPDIP
, &arp
);
348 print_one(ipaddr
, NULL
, 0);
351 fatal("unable to delete host %s: %s", inet_ntoa(ipaddr
),
352 errno
== EINVAL
? "entry is incomplete" : strerror(errno
));
355 static void do_set(char *hostname
, char *ethername
, int temp
, int pub
,
361 ether_addr_t ethaddr
;
363 nwio_ipconf_t ipconf
;
365 ipaddr
= nametoipaddr(hostname
);
366 if (pub
&& strcasecmp(ethername
, "auto") == 0)
368 r
= ioctl(ipfd
, NWIOGIPCONF
, &ipconf
);
370 fatal("NWIOGIPCONF failed: %s", strerror(errno
));
371 arp
.nwa_ipaddr
= ipconf
.nwic_ipaddr
;
372 r
= ioctl(ipfd
, NWIOARPGIP
, &arp
);
374 fatal("NWIOARPGIP failed: %s", strerror(errno
));
375 ethaddr
= arp
.nwa_ethaddr
;
377 else if (eap
= ether_aton(ethername
), eap
!= NULL
)
379 else if (ether_hostton(ethername
, ðaddr
) != 0)
381 fatal("unable to parse ethernet address '%s'",
387 arp
.nwa_ipaddr
= ipaddr
;
388 r
= ioctl(ipfd
, NWIOARPDIP
, &arp
);
389 if (r
== -1 && errno
!= ENOENT
)
391 fatal("unable to delete entry for host %s: %s",
393 errno
== EINVAL
? "incomplete entry" :
398 arp
.nwa_ipaddr
= ipaddr
;
399 arp
.nwa_ethaddr
= ethaddr
;
402 arp
.nwa_flags
|= NWAF_PUB
;
404 arp
.nwa_flags
|= NWAF_PERM
;
405 r
= ioctl(ipfd
, NWIOARPSIP
, &arp
);
408 fatal("unable to set arp entry: %s",
409 errno
== EEXIST
? "entry exists" : strerror(errno
));
413 static ipaddr_t
nametoipaddr(char *hostname
)
418 if (inet_aton(hostname
, &ipaddr
) == 0)
420 he
= gethostbyname(hostname
);
422 fatal("unknown hostname '%s'", hostname
);
423 if (he
->h_addrtype
!= AF_INET
||
424 he
->h_length
!= sizeof(ipaddr
))
426 fatal("strange host '%s': addrtype %d, length %d",
427 he
->h_addrtype
, he
->h_length
);
429 memcpy(&ipaddr
, he
->h_addr
, sizeof(ipaddr
));
435 static char *ether_ntoa(struct ether_addr
*eap
)
437 static char buf
[]= "xx:xx:xx:xx:xx:xx";
439 sprintf(buf
, "%02x:%02x:%02x:%02x:%02x:%02x",
440 eap
->ea_addr
[0], eap
->ea_addr
[1],
441 eap
->ea_addr
[2], eap
->ea_addr
[3],
442 eap
->ea_addr
[4], eap
->ea_addr
[5]);
447 static void fatal(const char *fmt
, ...)
452 fprintf(stderr
, "%s: ", progname
);
453 vfprintf(stderr
, fmt
, ap
);
454 fprintf(stderr
, "\n");
460 static void usage(void)
462 fprintf(stderr
, "Usage:\tarp [-I ip-dev] [-n] hostname\n"
463 "\tarp [-I ip-dev] [-n] -a\n"
464 "\tarp [-I ip-dev] -d hostname\n"
465 "\tarp [-I ip-dev] -d -a\n"
466 "\tarp [-I ip-dev] -s hostname ether-addr [temp] [pub]\n"
467 "\tarp [-I ip-dev] -S hostname ether-addr [temp] [pub]\n");
472 * $PchId: arp.c,v 1.3 2005/01/31 22:31:45 philip Exp $