Commit | Line | Data |
---|---|---|
19b8bc00 | 1 | #ifndef lint |
6faa5fd4 | 2 | static char *sccsid = "@(#)arp.c 5.2 (Berkeley) %G%"; |
19b8bc00 MK |
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; | |
9a642f1d | 63 | char line[100], arg[5][50], *args[5]; |
19b8bc00 MK |
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]; | |
9a642f1d | 73 | args[4] = &arg[4][0]; |
19b8bc00 | 74 | while(fgets(line, 100, fp) != NULL) { |
9a642f1d MK |
75 | i = sscanf(line, "%s %s %s %s", arg[0], arg[1], arg[2], arg[3], |
76 | arg[4]); | |
19b8bc00 MK |
77 | if (i < 2) { |
78 | fprintf(stderr, "arp: bad line: %s\n", line); | |
79 | continue; | |
80 | } | |
81 | set(i, args); | |
82 | } | |
83 | fclose(fp); | |
84 | } | |
85 | ||
86 | /* | |
87 | * Set an individual arp entry | |
88 | */ | |
89 | set(argc, argv) | |
90 | char **argv; | |
91 | { | |
92 | struct arpreq ar; | |
93 | struct hostent *hp; | |
94 | struct sockaddr_in *sin; | |
b51f832f | 95 | u_char *ea; |
19b8bc00 MK |
96 | int s; |
97 | char *host = argv[0], *eaddr = argv[1]; | |
98 | ||
99 | argc -= 2; | |
100 | argv += 2; | |
19b8bc00 | 101 | bzero((caddr_t)&ar, sizeof ar); |
19b8bc00 | 102 | sin = (struct sockaddr_in *)&ar.arp_pa; |
6faa5fd4 MK |
103 | sin->sin_family = AF_INET; |
104 | sin->sin_addr.s_addr = inet_addr(host); | |
105 | if (sin->sin_addr.s_addr == -1) { | |
106 | hp = gethostbyname(host); | |
107 | if (hp == NULL) { | |
108 | fprintf(stderr, "arp: %s: unknown host\n", host); | |
109 | return; | |
110 | } | |
111 | bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, | |
112 | sizeof sin->sin_addr); | |
113 | } | |
b51f832f | 114 | ea = (u_char *)ar.arp_ha.sa_data; |
19b8bc00 MK |
115 | if (ether_aton(eaddr, ea)) |
116 | return; | |
117 | ar.arp_flags = ATF_PERM; | |
6faa5fd4 | 118 | while (argc-- > 0) { |
19b8bc00 MK |
119 | if (strncmp(argv[0], "temp", 4) == 0) |
120 | ar.arp_flags &= ~ATF_PERM; | |
121 | if (strncmp(argv[0], "pub", 3) == 0) | |
122 | ar.arp_flags |= ATF_PUBL; | |
9a642f1d MK |
123 | if (strncmp(argv[0], "trail", 5) == 0) |
124 | ar.arp_flags |= ATF_USETRAILERS; | |
19b8bc00 MK |
125 | argv++; |
126 | } | |
127 | ||
128 | s = socket(AF_INET, SOCK_DGRAM, 0); | |
129 | if (s < 0) { | |
130 | perror("arp: socket"); | |
131 | exit(1); | |
132 | } | |
133 | if (ioctl(s, SIOCSARP, (caddr_t)&ar) < 0) { | |
134 | perror(host); | |
135 | exit(1); | |
136 | } | |
137 | close(s); | |
138 | } | |
139 | ||
140 | ||
141 | /* | |
142 | * Display an individual arp entry | |
143 | */ | |
144 | get(host) | |
145 | char *host; | |
146 | { | |
147 | struct arpreq ar; | |
148 | struct hostent *hp; | |
149 | struct sockaddr_in *sin; | |
b51f832f | 150 | u_char *ea; |
19b8bc00 MK |
151 | int s; |
152 | ||
19b8bc00 MK |
153 | bzero((caddr_t)&ar, sizeof ar); |
154 | ar.arp_pa.sa_family = AF_INET; | |
155 | sin = (struct sockaddr_in *)&ar.arp_pa; | |
6faa5fd4 MK |
156 | sin->sin_family = AF_INET; |
157 | sin->sin_addr.s_addr = inet_addr(host); | |
158 | if (sin->sin_addr.s_addr == -1) { | |
159 | hp = gethostbyname(host); | |
160 | if (hp == NULL) { | |
161 | fprintf(stderr, "arp: %s: unknown host\n", host); | |
162 | exit(1); | |
163 | } | |
164 | bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, | |
165 | sizeof sin->sin_addr); | |
166 | } | |
19b8bc00 MK |
167 | s = socket(AF_INET, SOCK_DGRAM, 0); |
168 | if (s < 0) { | |
169 | perror("arp: socket"); | |
170 | exit(1); | |
171 | } | |
172 | if (ioctl(s, SIOCGARP, (caddr_t)&ar) < 0) { | |
173 | if (errno == ENXIO) | |
174 | printf("%s (%s) -- no entry\n", | |
175 | host, inet_ntoa(sin->sin_addr)); | |
176 | else | |
177 | perror("SIOCGARP"); | |
178 | exit(1); | |
179 | } | |
180 | close(s); | |
b51f832f | 181 | ea = (u_char *)ar.arp_ha.sa_data; |
19b8bc00 MK |
182 | printf("%s (%s) at ", host, inet_ntoa(sin->sin_addr)); |
183 | if (ar.arp_flags & ATF_COM) | |
184 | ether_print(ea); | |
185 | else | |
186 | printf("(incomplete)"); | |
9a642f1d | 187 | if (ar.arp_flags & ATF_PERM) printf(" permanent"); |
19b8bc00 | 188 | if (ar.arp_flags & ATF_PUBL) printf(" published"); |
9a642f1d | 189 | if (ar.arp_flags & ATF_USETRAILERS) printf(" trailers"); |
19b8bc00 MK |
190 | printf("\n"); |
191 | } | |
192 | ||
193 | /* | |
194 | * Delete an arp entry | |
195 | */ | |
196 | delete(host) | |
197 | char *host; | |
198 | { | |
199 | struct arpreq ar; | |
200 | struct hostent *hp; | |
201 | struct sockaddr_in *sin; | |
202 | int s; | |
203 | ||
19b8bc00 MK |
204 | bzero((caddr_t)&ar, sizeof ar); |
205 | ar.arp_pa.sa_family = AF_INET; | |
206 | sin = (struct sockaddr_in *)&ar.arp_pa; | |
6faa5fd4 MK |
207 | sin->sin_family = AF_INET; |
208 | sin->sin_addr.s_addr = inet_addr(host); | |
209 | if (sin->sin_addr.s_addr == -1) { | |
210 | hp = gethostbyname(host); | |
211 | if (hp == NULL) { | |
212 | fprintf(stderr, "arp: %s: unknown host\n", host); | |
213 | exit(1); | |
214 | } | |
215 | bcopy((char *)hp->h_addr, (char *)&sin->sin_addr, | |
216 | sizeof sin->sin_addr); | |
217 | } | |
19b8bc00 MK |
218 | s = socket(AF_INET, SOCK_DGRAM, 0); |
219 | if (s < 0) { | |
220 | perror("arp: socket"); | |
221 | exit(1); | |
222 | } | |
223 | if (ioctl(s, SIOCDARP, (caddr_t)&ar) < 0) { | |
224 | if (errno == ENXIO) | |
225 | printf("%s (%s) -- no entry\n", | |
226 | host, inet_ntoa(sin->sin_addr)); | |
227 | else | |
228 | perror("SIOCDARP"); | |
229 | exit(1); | |
230 | } | |
231 | close(s); | |
232 | printf("%s (%s) deleted\n", host, inet_ntoa(sin->sin_addr)); | |
233 | } | |
234 | ||
235 | struct nlist nl[] = { | |
236 | #define X_ARPTAB 0 | |
237 | { "_arptab" }, | |
238 | #define X_ARPTAB_SIZE 1 | |
239 | { "_arptab_size" }, | |
240 | { "" }, | |
241 | }; | |
242 | ||
243 | /* | |
244 | * Dump the entire arp table | |
245 | */ | |
246 | dump(kernel, mem) | |
247 | char *kernel, *mem; | |
248 | { | |
249 | int mf, arptab_size, sz; | |
250 | struct arptab *at; | |
251 | struct hostent *hp; | |
252 | char *host; | |
6faa5fd4 | 253 | int bynumber = 0; |
19b8bc00 MK |
254 | |
255 | nlist(kernel, nl); | |
256 | if(nl[X_ARPTAB_SIZE].n_type == 0) { | |
257 | fprintf(stderr, "arp: %s: bad namelist\n", kernel); | |
258 | exit(1); | |
259 | } | |
260 | mf = open(mem, 0); | |
261 | if(mf < 0) { | |
262 | fprintf(fprintf, "arp: cannot open %s\n", mem); | |
263 | exit(1); | |
264 | } | |
265 | lseek(mf, (long)nl[X_ARPTAB_SIZE].n_value, 0); | |
266 | read(mf, &arptab_size, sizeof arptab_size); | |
267 | if (arptab_size <=0 || arptab_size > 1000) { | |
268 | fprintf(stderr, "arp: %s: namelist wrong\n", kernel); | |
269 | exit(1); | |
270 | } | |
271 | sz = arptab_size * sizeof (struct arptab); | |
272 | at = (struct arptab *)malloc(sz); | |
273 | if (at == NULL) { | |
274 | fprintf(stderr, "arp: can't get memory for arptab\n"); | |
275 | exit(1); | |
276 | } | |
277 | lseek(mf, (long)nl[X_ARPTAB].n_value, 0); | |
278 | if (read(mf, (char *)at, sz) != sz) { | |
279 | perror("arp: error reading arptab"); | |
280 | exit(1); | |
281 | } | |
282 | close(mf); | |
283 | for (; arptab_size-- > 0; at++) { | |
284 | if (at->at_iaddr.s_addr == 0 || at->at_flags == 0) | |
285 | continue; | |
6faa5fd4 MK |
286 | if (bynumber == 0) |
287 | hp = gethostbyaddr((caddr_t)&at->at_iaddr, | |
288 | sizeof at->at_iaddr, AF_INET); | |
289 | else | |
290 | hp = 0; | |
19b8bc00 MK |
291 | if (hp) |
292 | host = hp->h_name; | |
6faa5fd4 | 293 | else { |
19b8bc00 | 294 | host = "?"; |
6faa5fd4 MK |
295 | if (h_errno == TRY_AGAIN) |
296 | bynumber = 1; | |
297 | } | |
19b8bc00 MK |
298 | printf("%s (%s) at ", host, inet_ntoa(at->at_iaddr)); |
299 | if (at->at_flags & ATF_COM) | |
b51f832f | 300 | ether_print(at->at_enaddr); |
19b8bc00 MK |
301 | else |
302 | printf("(incomplete)"); | |
9a642f1d | 303 | if (at->at_flags & ATF_PERM) printf(" permanent"); |
19b8bc00 | 304 | if (at->at_flags & ATF_PUBL) printf(" published"); |
9a642f1d | 305 | if (at->at_flags & ATF_USETRAILERS) printf(" trailers"); |
19b8bc00 MK |
306 | printf("\n"); |
307 | } | |
308 | } | |
309 | ||
b51f832f MK |
310 | ether_print(cp) |
311 | u_char *cp; | |
19b8bc00 | 312 | { |
19b8bc00 MK |
313 | printf("%x:%x:%x:%x:%x:%x", cp[0], cp[1], cp[2], cp[3], cp[4], cp[5]); |
314 | } | |
315 | ||
316 | ether_aton(a, n) | |
317 | char *a; | |
b51f832f | 318 | u_char *n; |
19b8bc00 MK |
319 | { |
320 | int i, o[6]; | |
321 | ||
322 | i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o[0], &o[1], &o[2], | |
323 | &o[3], &o[4], &o[5]); | |
324 | if (i != 6) { | |
325 | fprintf(stderr, "arp: invalid Ethernet address '%s'\n", a); | |
326 | return (1); | |
327 | } | |
328 | for (i=0; i<6; i++) | |
b51f832f | 329 | n[i] = o[i]; |
19b8bc00 MK |
330 | return (0); |
331 | } | |
332 | ||
333 | usage() | |
334 | { | |
335 | printf("Usage: arp hostname\n"); | |
336 | printf(" arp -a [/vmunix] [/dev/kmem]\n"); | |
337 | printf(" arp -d hostname\n"); | |
338 | printf(" arp -s hostname ether_addr [temp] [pub]\n"); | |
339 | printf(" arp -f filename\n"); | |
340 | } |