Commit | Line | Data |
---|---|---|
19b8bc00 MK |
1 | #ifndef lint |
2 | static char *sccsid = "@(#)arp.c 1.1 (Berkeley) %G%"; | |
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 | } |