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