• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 IFACE	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;
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 *ai = xgetaddrinfo(host, NULL, AF_INET, SOCK_STREAM, 0, 0);
90 
91   memcpy(sa, ai->ai_addr, ai->ai_addrlen);
92   freeaddrinfo(ai);
93 }
94 
check_flags(int * i,char ** argv)95 static void check_flags(int *i, char** argv)
96 {
97   struct sockaddr sa;
98   int flag = *i, j;
99   struct flags {
100     char *name;
101     int or, flag;
102   } f[] = {
103     {"pub",  1 ,ATF_PUBL},
104     {"priv", 0 ,~ATF_PUBL},
105     {"trail", 1, ATF_USETRAILERS},
106     {"temp", 0, ~ATF_PERM},
107     {"dontpub",1, ATF_DONTPUB},
108   };
109 
110   for (;*argv; argv++) {
111     for (j = 0;  j < ARRAY_LEN(f); j++) {
112       if (!strcmp(*argv, f[j].name)) {
113         (f[j].or) ?(flag |= f[j].flag):(flag &= f[j].flag);
114         break;
115       }
116     }
117     if (j > 4 && !strcmp(*argv, "netmask")) {
118       if (!*++argv) error_exit("NULL netmask");
119       if (strcmp(*argv, "255.255.255.255")) {
120         resolve_host(toys.optargs[0], &sa);
121         memcpy(&req.arp_netmask, &sa, sizeof(sa));
122         flag |= ATF_NETMASK;
123       } else argv++;
124     } else if (j > 4 && !strcmp(*argv, "dev")) {
125       if (!*++argv) error_exit("NULL dev");
126       TT.device = *argv;
127     } else if (j > 4) error_exit("invalid arg");
128   }
129   *i = flag;
130 }
131 
set_entry(void)132 static int set_entry(void)
133 {
134   int flags = 0;
135 
136   if (!toys.optargs[1]) error_exit("bad syntax");
137 
138   if (!FLAG(D)) {
139     char *ptr = toys.optargs[1];
140     char *p = ptr, *hw_addr = req.arp_ha.sa_data;
141 
142     while (*hw_addr && (p-ptr) < 6) {
143       int val, len;
144 
145       if (*hw_addr == ':') hw_addr++;
146       if (!sscanf(hw_addr, "%2x%n", &val, &len)) break;
147       hw_addr += len;
148       *p++ = val;
149     }
150 
151     if ((p-ptr) != 6 || *hw_addr)
152       error_exit("bad hw addr '%s'", req.arp_ha.sa_data);
153   } else {
154     struct ifreq ifre;
155 
156     xstrncpy(ifre.ifr_name, toys.optargs[1], IFNAMSIZ);
157     xioctl(TT.sockfd, SIOCGIFHWADDR, &ifre);
158     if (FLAG(H) && ifre.ifr_hwaddr.sa_family != ARPHRD_ETHER)
159       error_exit("protocol type mismatch");
160     memcpy(&req.arp_ha, &(ifre.ifr_hwaddr), sizeof(req.arp_ha));
161   }
162 
163   flags = ATF_PERM | ATF_COM;
164   if (toys.optargs[2]) check_flags(&flags, (toys.optargs+2));
165   req.arp_flags = flags;
166   xstrncpy(req.arp_dev, TT.device, sizeof(req.arp_dev));
167   xioctl(TT.sockfd, SIOCSARP, &req);
168 
169   if (FLAG(v)) xprintf("Entry set for %s\n", toys.optargs[0]);
170   return 0;
171 }
172 
ip_to_host(struct sockaddr * sa,int flag)173 static int ip_to_host(struct sockaddr *sa, int flag)
174 {
175   int status = 0;
176   char hbuf[NI_MAXHOST] = {0,}, sbuf[NI_MAXSERV] = {0,};
177   socklen_t len = sizeof(struct sockaddr_in6);
178 
179   *toybuf = 0;
180   if (!(status = getnameinfo(sa, len, hbuf, sizeof(hbuf), sbuf,
181           sizeof(sbuf), flag))) {
182     strcpy(toybuf, hbuf);
183     return 0;
184   }
185   return 1;
186 }
187 
delete_entry(void)188 static int delete_entry(void)
189 {
190   int flags = ATF_PERM;
191 
192   if (toys.optargs[1]) check_flags(&flags, (toys.optargs+1));
193   req.arp_flags = flags;
194   xstrncpy(req.arp_dev, TT.device, sizeof(req.arp_dev));
195   xioctl(TT.sockfd, SIOCDARP, &req);
196 
197   if (FLAG(v)) xprintf("Delete entry for  %s\n", toys.optargs[0]);
198   return 0;
199 }
200 
arp_main(void)201 void arp_main(void)
202 {
203   struct sockaddr sa;
204   char ip[16], hw_addr[30], mask[16], dev[16], *host_ip = NULL;
205   FILE *fp;
206   int h_type, type, flag, i, entries = 0, disp = 0;
207 
208   TT.device = "";
209   memset(&sa, 0, sizeof(sa));
210   TT.sockfd = xsocket(AF_INET, SOCK_STREAM, 0);
211 
212   if (FLAG(A) || FLAG(p)) {
213     if ((type = get_index(aftype,
214             (TT.af_type_A)?TT.af_type_A:TT.af_type_p)) != AF_INET)
215       error_exit((type != -1)?"only inet supported by kernel":"unknown family");
216   }
217 
218   req.arp_ha.sa_family = ARPHRD_ETHER;
219   if (FLAG(H)) {
220     if ((type = get_index(hwtype, TT.hw_type)) != ARPHRD_ETHER)
221       error_exit((type != -1)?"h/w type not supported":"unknown h/w type");
222     req.arp_ha.sa_family = type;
223   }
224 
225   if (FLAG(s) || FLAG(d)) {
226     if (!toys.optargs[0]) error_exit("-%c needs a host name", FLAG(d)?'d':'s');
227     resolve_host(toys.optargs[0], &sa);
228     memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr));
229 
230     if (FLAG(s) && !set_entry()) return;
231     if (FLAG(d) && !delete_entry()) return;
232   }
233 
234   // Show arp cache.
235 
236   if (toys.optargs[0]) {
237     resolve_host(toys.optargs[0], &sa);
238     ip_to_host(&sa, NI_NUMERICHOST);
239     host_ip = xstrdup(toybuf);
240   }
241 
242   fp = xfopen("/proc/net/arp", "r");
243   fgets(toybuf, sizeof(toybuf), fp); // Skip header.
244   while (fscanf(fp, "%15s 0x%x 0x%x %29s %15s %15s",
245                 ip, &h_type, &flag, hw_addr, mask, dev) == 6) {
246     char *host_name = "?";
247 
248     entries++;
249     if ((FLAG(H) && get_index(hwtype, TT.hw_type) != h_type) ||
250       (FLAG(i) && strcmp(TT.interface, dev)) ||
251       (toys.optargs[0] && strcmp(host_ip, ip))) {
252       continue;
253     }
254 
255     resolve_host(ip, &sa);
256     if (FLAG(n)) ip_to_host(&sa, NI_NUMERICHOST);
257     else if (!ip_to_host(&sa, NI_NAMEREQD)) host_name = toybuf;
258 
259     disp++;
260     printf("%s (%s) at" , host_name, ip);
261 
262     for (i = 0; hwtype[i].name; i++)
263       if (hwtype[i].val & h_type) break;
264     if (!hwtype[i].name) error_exit("unknown h/w type");
265 
266     if (!(flag & ATF_COM)) {
267       if ((flag & ATF_PUBL)) printf(" *");
268       else printf(" <incomplete>");
269     } else printf(" %s [%s]", hw_addr, hwtype[i].name);
270 
271     if (flag & ATF_NETMASK) printf("netmask %s ", mask);
272 
273     for (i = 0; flag_type[i].name; i++)
274       if (flag_type[i].val & flag) printf(" %s", flag_type[i].name);
275 
276     printf(" on %s\n", dev);
277   }
278 
279   if (FLAG(v))
280     xprintf("Entries: %d\tSkipped: %d\tFound: %d\n",
281         entries, entries - disp, disp);
282   if (toys.optargs[0] && !disp)
283     xprintf("%s (%s) -- no entry\n", toys.optargs[0], host_ip);
284 
285   if (CFG_TOYBOX_FREE) {
286     free(host_ip);
287     fclose(fp);
288   }
289 }
290