1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34#define FOR_arp
35#include "toys.h"
36#include <net/if_arp.h>
37
38GLOBALS(
39 char *hw_type;
40 char *af_type_A;
41 char *af_type_p;
42 char *interface;
43
44 int sockfd;
45 char *device;
46)
47
48struct arpreq req;
49
50struct type {
51 char *name;
52 int val;
53};
54
55struct type hwtype[] = {
56 {"ether", ARPHRD_ETHER },
57 {"loop" ,ARPHRD_LOOPBACK},
58 {"ppp" ,ARPHRD_PPP},
59 {"infiniband" ,ARPHRD_INFINIBAND},
60 {NULL, -1},
61};
62
63struct type aftype[] = {
64 {"inet", AF_INET },
65 {"inet6" ,AF_INET6},
66 {"unspec" ,AF_UNSPEC},
67 {NULL, -1},
68};
69
70struct type flag_type[] = {
71 {"PERM", ATF_PERM },
72 {"PUB" ,ATF_PUBL},
73 {"DONTPUB" ,ATF_DONTPUB},
74 {"TRAIL" ,ATF_USETRAILERS},
75 {NULL, -1},
76};
77
78static int get_index(struct type arr[], char *name)
79{
80 int i;
81
82 for (i = 0; arr[i].name; i++)
83 if (!strcmp(arr[i].name, name)) break;
84 return arr[i].val;
85}
86
87
88void get_hw_add(char *hw_addr, char *ptr)
89{
90 char *p = ptr, *hw = hw_addr;
91
92 while (*hw_addr && (p-ptr) < 6) {
93 int val, len = 0;
94
95 if (*hw_addr == ':') hw_addr++;
96 sscanf(hw_addr, "%2x%n", &val, &len);
97 if (!len || len > 2) break;
98 hw_addr += len;
99 *p++ = val;
100 }
101
102 if ((p-ptr) != 6 || *hw_addr)
103 error_exit("bad hw addr '%s'", hw);
104}
105
106static void resolve_host(char *host, struct sockaddr *sa)
107{
108 struct addrinfo hints, *res = NULL;
109 int ret;
110
111 memset(&hints, 0, sizeof hints);
112 hints.ai_family = AF_INET;
113 hints.ai_socktype = SOCK_STREAM;
114 if ((ret = getaddrinfo(host, NULL, &hints, &res)))
115 perror_exit("%s", gai_strerror(ret));
116
117 memcpy(sa, res->ai_addr, res->ai_addrlen);
118 freeaddrinfo(res);
119}
120
121static void check_flags(int *i, char** argv)
122{
123 struct sockaddr sa;
124 int flag = *i, j;
125 struct flags {
126 char *name;
127 int or, flag;
128 } f[] = {
129 {"pub", 1 ,ATF_PUBL},
130 {"priv", 0 ,~ATF_PUBL},
131 {"trail", 1, ATF_USETRAILERS},
132 {"temp", 0, ~ATF_PERM},
133 {"dontpub",1, ATF_DONTPUB},
134 };
135
136 for (;*argv; argv++) {
137 for (j = 0; j < ARRAY_LEN(f); j++) {
138 if (!strcmp(*argv, f[j].name)) {
139 (f[j].or) ?(flag |= f[j].flag):(flag &= f[j].flag);
140 break;
141 }
142 }
143 if (j > 4 && !strcmp(*argv, "netmask")) {
144 if (!*++argv) error_exit("NULL netmask");
145 if (strcmp(*argv, "255.255.255.255")) {
146 resolve_host(toys.optargs[0], &sa);
147 memcpy(&req.arp_netmask, &sa, sizeof(sa));
148 flag |= ATF_NETMASK;
149 } else argv++;
150 } else if (j > 4 && !strcmp(*argv, "dev")) {
151 if (!*++argv) error_exit("NULL dev");
152 TT.device = *argv;
153 } else if (j > 4) error_exit("invalid arg");
154 }
155 *i = flag;
156}
157
158static int set_entry(void)
159{
160 int flags = 0;
161
162 if (!toys.optargs[1]) error_exit("bad syntax");
163
164 if (!(toys.optflags & FLAG_D)) get_hw_add(toys.optargs[1], (char*)&req.arp_ha.sa_data);
165 else {
166 struct ifreq ifre;
167
168 xstrncpy(ifre.ifr_name, toys.optargs[1], IFNAMSIZ);
169 xioctl(TT.sockfd, SIOCGIFHWADDR, &ifre);
170 if ((toys.optflags & FLAG_H) && (ifre.ifr_hwaddr.sa_family != ARPHRD_ETHER))
171 error_exit("protocol type mismatch");
172 memcpy(&req.arp_ha, &(ifre.ifr_hwaddr), sizeof(req.arp_ha));
173 }
174
175 flags = ATF_PERM | ATF_COM;
176 if (toys.optargs[2]) check_flags(&flags, (toys.optargs+2));
177 req.arp_flags = flags;
178 xstrncpy(req.arp_dev, TT.device, sizeof(req.arp_dev));
179 xioctl(TT.sockfd, SIOCSARP, &req);
180
181 if (toys.optflags & FLAG_v) xprintf("Entry set for %s\n", toys.optargs[0]);
182 return 0;
183}
184
185static int ip_to_host(struct sockaddr *sa, int flag)
186{
187 int status = 0;
188 char hbuf[NI_MAXHOST] = {0,}, sbuf[NI_MAXSERV] = {0,};
189 socklen_t len = sizeof(struct sockaddr_in6);
190
191 *toybuf = 0;
192 if (!(status = getnameinfo(sa, len, hbuf, sizeof(hbuf), sbuf,
193 sizeof(sbuf), flag))) {
194 strcpy(toybuf, hbuf);
195 return 0;
196 }
197 return 1;
198}
199
200static int delete_entry(void)
201{
202 int flags;
203
204 flags = ATF_PERM;
205 if (toys.optargs[1]) check_flags(&flags, (toys.optargs+1));
206 req.arp_flags = flags;
207 xstrncpy(req.arp_dev, TT.device, sizeof(req.arp_dev));
208 xioctl(TT.sockfd, SIOCDARP, &req);
209
210 if (toys.optflags & FLAG_v) xprintf("Delete entry for %s\n", toys.optargs[0]);
211 return 0;
212}
213
214void arp_main(void)
215{
216 struct sockaddr sa;
217 char ip[128], hw_addr[128], mask[12], dev[128], *host_ip = NULL, *buf;
218 int h_type, type, flag, i, fd, entries = 0, disp = 0;
219
220 TT.device = "";
221 memset(&sa, 0, sizeof(sa));
222 memset(&req, 0, sizeof(req));
223 TT.sockfd = xsocket(AF_INET, SOCK_STREAM, 0);
224
225 if ((toys.optflags & FLAG_A) || (toys.optflags & FLAG_p)) {
226 if ((type = get_index(aftype,
227 (TT.af_type_A)?TT.af_type_A:TT.af_type_p)) != AF_INET)
228 error_exit((type != -1)?"only inet supported by kernel":"unknown family");
229 }
230
231 req.arp_ha.sa_family = ARPHRD_ETHER;
232 if (toys.optflags & FLAG_H) {
233 if ((type = get_index(hwtype, TT.hw_type)) != ARPHRD_ETHER)
234 error_exit((type != -1)?"h/w type not supported":"unknown h/w type");
235 req.arp_ha.sa_family = type;
236 }
237
238 if (((toys.optflags & FLAG_s) || toys.optflags & FLAG_d)) {
239 if (!toys.optargs[0]) error_exit("host name req");
240 resolve_host(toys.optargs[0], &sa);
241 memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr));
242 }
243
244 if ((toys.optflags & FLAG_s) && !set_entry()) return;
245 if ((toys.optflags & FLAG_d) && !delete_entry()) return;
246
247
248 fd = xopenro("/proc/net/arp");
249 buf = get_line(fd);
250 free(buf);
251
252 if (toys.optargs[0]) {
253 resolve_host(toys.optargs[0], &sa);
254 ip_to_host(&sa, NI_NUMERICHOST);
255 host_ip = xstrdup(toybuf);
256 }
257
258 while ((buf = get_line(fd))) {
259 char *host_name = "?";
260
261 if ((sscanf(buf, "%s 0x%x 0x%x %s %s %s\n", ip,
262 &h_type, &flag, hw_addr, mask, dev )) != 6) break;
263 entries++;
264 if (((toys.optflags & FLAG_H) && (get_index(hwtype, TT.hw_type) != h_type))
265 || ((toys.optflags & FLAG_i) && strcmp(TT.interface, dev))
266 || (toys.optargs[0] && strcmp(host_ip, ip))) {
267 free(buf);
268 continue;
269 }
270
271 resolve_host(buf, &sa);
272 if (!(toys.optflags & FLAG_n)) {
273 if (!ip_to_host(&sa, NI_NAMEREQD)) host_name = toybuf;
274 } else ip_to_host(&sa, NI_NUMERICHOST);
275
276 disp++;
277 printf("%s (%s) at" , host_name, ip);
278
279 for (i = 0; hwtype[i].name; i++)
280 if (hwtype[i].val & h_type) break;
281 if (!hwtype[i].name) error_exit("unknown h/w type");
282
283 if (!(flag & ATF_COM)) {
284 if ((flag & ATF_PUBL)) printf(" *");
285 else printf(" <incomplete>");
286 } else printf(" %s [%s]", hw_addr, hwtype[i].name);
287
288 if (flag & ATF_NETMASK) printf("netmask %s ", mask);
289
290 for (i = 0; flag_type[i].name; i++)
291 if (flag_type[i].val & flag) printf(" %s", flag_type[i].name);
292
293 printf(" on %s\n", dev);
294 free(buf);
295 }
296
297 if (toys.optflags & FLAG_v)
298 xprintf("Entries: %d\tSkipped: %d\tFound: %d\n",
299 entries, entries - disp, disp);
300 if (!disp) xprintf("No Match found in %d entries\n", entries);
301
302 if (CFG_TOYBOX_FREE) {
303 free(host_ip);
304 free(buf);
305 xclose(fd);
306 }
307}
308