xref: /original-bsd/usr.sbin/arp/arp.c (revision 7e7b101a)
1 #ifndef lint
2 static	char *sccsid = "@(#)arp.c	1.1 (Berkeley) 03/30/84";
3 #endif
4 
5 /*
6  * arp - display, set, and delete arp table entries
7  */
8 
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <sys/ioctl.h>
14 #include <errno.h>
15 #include <netdb.h>
16 #include <nlist.h>
17 #include <net/if.h>
18 #include <netinet/if_ether.h>
19 
20 extern int errno;
21 
22 main(argc, argv)
23 	char **argv;
24 {
25 	if (argc >= 2 && strcmp(argv[1], "-a") == 0) {
26 		char *kernel = "/vmunix", *mem = "/dev/kmem";
27 
28 		if (argc >= 3)
29 			kernel = argv[2];
30 		if (argc >= 4)
31 			mem = argv[3];
32 		dump(kernel, mem);
33 		exit(0);
34 	}
35 	if (argc == 2) {
36 		get(argv[1]);
37 		exit(0);
38 	}
39 	if (argc >= 4 && strcmp(argv[1], "-s") == 0) {
40 		set(argc-2, &argv[2]);
41 		exit(0);
42 	}
43 	if (argc == 3 && strcmp(argv[1], "-d") == 0) {
44 		delete(argv[2]);
45 		exit(0);
46 	}
47 	if (argc == 3 && strcmp(argv[1], "-f") == 0) {
48 		file(argv[2]);
49 		exit(0);
50 	}
51 	usage();
52 	exit(1);
53 }
54 
55 /*
56  * Process a file to set standard arp entries
57  */
58 file(name)
59 	char *name;
60 {
61 	FILE *fp;
62 	int i;
63 	char line[100], arg[4][50], *args[4];
64 
65 	if ((fp = fopen(name, "r")) == NULL) {
66 		fprintf(stderr, "arp: cannot open %s\n", name);
67 		exit(1);
68 	}
69 	args[0] = &arg[0][0];
70 	args[1] = &arg[1][0];
71 	args[2] = &arg[2][0];
72 	args[3] = &arg[3][0];
73 	while(fgets(line, 100, fp) != NULL) {
74 		i = sscanf(line, "%s %s %s %s", arg[0], arg[1], arg[2], arg[3]);
75 		if (i < 2) {
76 			fprintf(stderr, "arp: bad line: %s\n", line);
77 			continue;
78 		}
79 		set(i, args);
80 	}
81 	fclose(fp);
82 }
83 
84 /*
85  * Set an individual arp entry
86  */
87 set(argc, argv)
88 	char **argv;
89 {
90 	struct arpreq ar;
91 	struct hostent *hp;
92 	struct sockaddr_in *sin;
93 	struct ether_addr *ea;
94 	int s;
95 	char *host = argv[0], *eaddr = argv[1];
96 
97 	argc -= 2;
98 	argv += 2;
99 	hp = gethostbyname(host);
100 	if (hp == NULL) {
101 		fprintf(stderr, "arp: %s: unknown host\n", host);
102 		return (1);
103 	}
104 	bzero((caddr_t)&ar, sizeof ar);
105 	ar.arp_pa.sa_family = AF_INET;
106 	sin = (struct sockaddr_in *)&ar.arp_pa;
107 	sin->sin_addr = *(struct in_addr *)hp->h_addr;
108 	ea = (struct ether_addr *)ar.arp_ha.sa_data;
109 	if (ether_aton(eaddr, ea))
110 		return;
111 	ar.arp_flags = ATF_PERM;
112 	while(argc-- > 0) {
113 		if (strncmp(argv[0], "temp", 4) == 0)
114 			ar.arp_flags &= ~ATF_PERM;
115 		if (strncmp(argv[0], "pub", 3) == 0)
116 			ar.arp_flags |= ATF_PUBL;
117 		argv++;
118 	}
119 
120 	s = socket(AF_INET, SOCK_DGRAM, 0);
121 	if (s < 0) {
122                 perror("arp: socket");
123                 exit(1);
124         }
125 	if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) {
126 		perror(host);
127 		exit(1);
128 	}
129 	close(s);
130 }
131 
132 
133 /*
134  * Display an individual arp entry
135  */
136 get(host)
137 	char *host;
138 {
139 	struct arpreq ar;
140 	struct hostent *hp;
141 	struct sockaddr_in *sin;
142 	struct ether_addr *ea;
143 	int s;
144 
145 	hp = gethostbyname(host);
146 	if (hp == NULL) {
147 		fprintf(stderr, "arp: %s: unknown host\n", host);
148 		exit(1);
149 	}
150 	bzero((caddr_t)&ar, sizeof ar);
151 	ar.arp_pa.sa_family = AF_INET;
152 	sin = (struct sockaddr_in *)&ar.arp_pa;
153 	sin->sin_addr = *(struct in_addr *)hp->h_addr;
154 	s = socket(AF_INET, SOCK_DGRAM, 0);
155 	if (s < 0) {
156                 perror("arp: socket");
157                 exit(1);
158         }
159 	if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) {
160 		if (errno == ENXIO)
161 			printf("%s (%s) -- no entry\n",
162 			    host, inet_ntoa(sin->sin_addr));
163 		else
164 			perror("SIOCGARP");
165 		exit(1);
166 	}
167 	close(s);
168 	ea = (struct ether_addr *)ar.arp_ha.sa_data;
169 	printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr));
170 	if (ar.arp_flags & ATF_COM)
171 		ether_print(ea);
172 	else
173 		printf("(incomplete)");
174 	if (!(ar.arp_flags & ATF_PERM)) printf(" temporary");
175 	if (ar.arp_flags & ATF_PUBL) printf(" published");
176 	printf("\n");
177 }
178 
179 /*
180  * Delete an arp entry
181  */
182 delete(host)
183 	char *host;
184 {
185 	struct arpreq ar;
186 	struct hostent *hp;
187 	struct sockaddr_in *sin;
188 	int s;
189 
190 	hp = gethostbyname(host);
191 	if (hp == NULL) {
192 		fprintf(stderr, "arp: %s: unknown host\n", host);
193 		exit(1);
194 	}
195 	bzero((caddr_t)&ar, sizeof ar);
196 	ar.arp_pa.sa_family = AF_INET;
197 	sin = (struct sockaddr_in *)&ar.arp_pa;
198 	sin->sin_addr = *(struct in_addr *)hp->h_addr;
199 	s = socket(AF_INET, SOCK_DGRAM, 0);
200 	if (s < 0) {
201                 perror("arp: socket");
202                 exit(1);
203         }
204 	if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) {
205 		if (errno == ENXIO)
206 			printf("%s (%s) -- no entry\n",
207 			    host, inet_ntoa(sin->sin_addr));
208 		else
209 			perror("SIOCDARP");
210 		exit(1);
211 	}
212 	close(s);
213 	printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr));
214 }
215 
216 struct nlist nl[] = {
217 #define	X_ARPTAB	0
218 	{ "_arptab" },
219 #define	X_ARPTAB_SIZE	1
220 	{ "_arptab_size" },
221 	{ "" },
222 };
223 
224 /*
225  * Dump the entire arp table
226  */
227 dump(kernel, mem)
228 	char *kernel, *mem;
229 {
230 	int mf, arptab_size, sz;
231 	struct arptab *at;
232 	struct hostent *hp;
233 	char *host;
234 
235 	nlist(kernel, nl);
236 	if(nl[X_ARPTAB_SIZE].n_type == 0) {
237 		fprintf(stderr, "arp: %s: bad namelist\n", kernel);
238 		exit(1);
239 	}
240 	mf = open(mem, 0);
241 	if(mf < 0) {
242 		fprintf(fprintf, "arp: cannot open %s\n", mem);
243 		exit(1);
244 	}
245 	lseek(mf, (long)nl[X_ARPTAB_SIZE].n_value, 0);
246 	read(mf, &arptab_size, sizeof arptab_size);
247 	if (arptab_size <=0 || arptab_size > 1000) {
248 		fprintf(stderr, "arp: %s: namelist wrong\n", kernel);
249 		exit(1);
250 	}
251 	sz = arptab_size * sizeof (struct arptab);
252 	at = (struct arptab *)malloc(sz);
253 	if (at == NULL) {
254 		fprintf(stderr, "arp: can't get memory for arptab\n");
255 		exit(1);
256 	}
257 	lseek(mf, (long)nl[X_ARPTAB].n_value, 0);
258 	if (read(mf, (char *)at, sz) != sz) {
259 		perror("arp: error reading arptab");
260 		exit(1);
261 	}
262 	close(mf);
263 	for (; arptab_size-- > 0; at++) {
264 		if (at->at_iaddr.s_addr == 0 || at->at_flags == 0)
265 			continue;
266 		hp = gethostbyaddr((caddr_t)&at->at_iaddr, sizeof at->at_iaddr,
267 			AF_INET);
268 		if (hp)
269 			host = hp->h_name;
270 		else
271 			host = "?";
272 		printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr));
273 		if (at->at_flags & ATF_COM)
274 			ether_print(&at->at_enaddr);
275 		else
276 			printf("(incomplete)");
277 		if (!(at->at_flags & ATF_PERM)) printf(" temporary");
278 		if (at->at_flags & ATF_PUBL) printf(" published");
279 		printf("\n");
280 	}
281 }
282 
283 ether_print(ea)
284 	struct ether_addr *ea;
285 {
286 	u_char *cp = &ea->ether_addr_octet[0];
287 
288 	printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]);
289 }
290 
291 ether_aton(a, n)
292 	char *a;
293 	struct ether_addr *n;
294 {
295 	int i, o[6];
296 
297 	i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2],
298 					   &o[3], &o[4], &o[5]);
299 	if (i != 6) {
300 		fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a);
301 		return (1);
302 	}
303 	for (i=0; i<6; i++)
304 		n->ether_addr_octet[i] = o[i];
305 	return (0);
306 }
307 
308 usage()
309 {
310 	printf("Usage: arp hostname\n");
311 	printf("       arp -a [/vmunix] [/dev/kmem]\n");
312 	printf("       arp -d hostname\n");
313 	printf("       arp -s hostname ether_addr [temp] [pub]\n");
314 	printf("       arp -f filename\n");
315 }
316