You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
303 lines
7.6 KiB
303 lines
7.6 KiB
/* arp.c - manipulate the system ARP cache
|
|
*
|
|
* Copyright 2014 Sandeep Sharma <sandeep.jack2756@gmail.com>
|
|
* Copyright 2014 Kyungwan Han <asura321@gamil.com>
|
|
* No Standard
|
|
|
|
USE_ARP(NEWTOY(arp, "vi:nDsdap:A:H:[+Ap][!sd]", TOYFLAG_USR|TOYFLAG_BIN))
|
|
|
|
config ARP
|
|
bool "arp"
|
|
default n
|
|
help
|
|
usage: arp
|
|
[-vn] [-H HWTYPE] [-i IF] -a [HOSTNAME]
|
|
[-v] [-i IF] -d HOSTNAME [pub]
|
|
[-v] [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [temp]
|
|
[-v] [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [netmask MASK] pub
|
|
[-v] [-H HWTYPE] [-i IF] -Ds HOSTNAME IFACE [netmask MASK] pub
|
|
|
|
Manipulate ARP cache
|
|
|
|
-a Display (all) hosts
|
|
-s Set new ARP entry
|
|
-d Delete a specified entry
|
|
-v Verbose
|
|
-n Don't resolve names
|
|
-i IF Network interface
|
|
-D Read <hwaddr> from given device
|
|
-A,-p AF Protocol family
|
|
-H HWTYPE Hardware address type
|
|
|
|
*/
|
|
|
|
#define FOR_arp
|
|
#include "toys.h"
|
|
#include <net/if_arp.h>
|
|
|
|
GLOBALS(
|
|
char *hw_type;
|
|
char *af_type_A;
|
|
char *af_type_p;
|
|
char *interface;
|
|
|
|
int sockfd;
|
|
char *device;
|
|
)
|
|
|
|
struct arpreq req; //Global request structure
|
|
|
|
struct type {
|
|
char *name;
|
|
int val;
|
|
};
|
|
|
|
struct type hwtype[] = {
|
|
{"ether", ARPHRD_ETHER },
|
|
{"loop" ,ARPHRD_LOOPBACK},
|
|
{"ppp" ,ARPHRD_PPP},
|
|
{"infiniband" ,ARPHRD_INFINIBAND},
|
|
{NULL, -1},
|
|
};
|
|
|
|
struct type aftype[] = {
|
|
{"inet", AF_INET },
|
|
{"inet6" ,AF_INET6},
|
|
{"unspec" ,AF_UNSPEC},
|
|
{NULL, -1},
|
|
};
|
|
|
|
struct type flag_type[] = {
|
|
{"PERM", ATF_PERM },
|
|
{"PUB" ,ATF_PUBL},
|
|
{"DONTPUB" ,ATF_DONTPUB},
|
|
{"TRAIL" ,ATF_USETRAILERS},
|
|
{NULL, -1},
|
|
};
|
|
|
|
static int get_index(struct type arr[], char *name)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; arr[i].name; i++)
|
|
if (!strcmp(arr[i].name, name)) break;
|
|
return arr[i].val;
|
|
}
|
|
|
|
static void resolve_host(char *host, struct sockaddr *sa)
|
|
{
|
|
struct addrinfo hints, *res = NULL;
|
|
int ret;
|
|
|
|
memset(&hints, 0, sizeof hints);
|
|
hints.ai_family = AF_INET;
|
|
hints.ai_socktype = SOCK_STREAM;
|
|
if ((ret = getaddrinfo(host, NULL, &hints, &res)))
|
|
perror_exit("%s", gai_strerror(ret));
|
|
|
|
memcpy(sa, res->ai_addr, res->ai_addrlen);
|
|
freeaddrinfo(res);
|
|
}
|
|
|
|
static void check_flags(int *i, char** argv)
|
|
{
|
|
struct sockaddr sa;
|
|
int flag = *i, j;
|
|
struct flags {
|
|
char *name;
|
|
int or, flag;
|
|
} f[] = {
|
|
{"pub", 1 ,ATF_PUBL},
|
|
{"priv", 0 ,~ATF_PUBL},
|
|
{"trail", 1, ATF_USETRAILERS},
|
|
{"temp", 0, ~ATF_PERM},
|
|
{"dontpub",1, ATF_DONTPUB},
|
|
};
|
|
|
|
for (;*argv; argv++) {
|
|
for (j = 0; j < ARRAY_LEN(f); j++) {
|
|
if (!strcmp(*argv, f[j].name)) {
|
|
(f[j].or) ?(flag |= f[j].flag):(flag &= f[j].flag);
|
|
break;
|
|
}
|
|
}
|
|
if (j > 4 && !strcmp(*argv, "netmask")) {
|
|
if (!*++argv) error_exit("NULL netmask");
|
|
if (strcmp(*argv, "255.255.255.255")) {
|
|
resolve_host(toys.optargs[0], &sa);
|
|
memcpy(&req.arp_netmask, &sa, sizeof(sa));
|
|
flag |= ATF_NETMASK;
|
|
} else argv++;
|
|
} else if (j > 4 && !strcmp(*argv, "dev")) {
|
|
if (!*++argv) error_exit("NULL dev");
|
|
TT.device = *argv;
|
|
} else if (j > 4) error_exit("invalid arg");
|
|
}
|
|
*i = flag;
|
|
}
|
|
|
|
static int set_entry(void)
|
|
{
|
|
int flags = 0;
|
|
|
|
if (!toys.optargs[1]) error_exit("bad syntax");
|
|
|
|
if (!(toys.optflags & FLAG_D)) {
|
|
char *ptr = toys.optargs[1];
|
|
char *p = ptr, *hw_addr = req.arp_ha.sa_data;
|
|
|
|
while (*hw_addr && (p-ptr) < 6) {
|
|
int val, len;
|
|
|
|
if (*hw_addr == ':') hw_addr++;
|
|
if (!sscanf(hw_addr, "%2x%n", &val, &len)) break;
|
|
hw_addr += len;
|
|
*p++ = val;
|
|
}
|
|
|
|
if ((p-ptr) != 6 || *hw_addr)
|
|
error_exit("bad hw addr '%s'", req.arp_ha.sa_data);
|
|
} else {
|
|
struct ifreq ifre;
|
|
|
|
xstrncpy(ifre.ifr_name, toys.optargs[1], IFNAMSIZ);
|
|
xioctl(TT.sockfd, SIOCGIFHWADDR, &ifre);
|
|
if ((toys.optflags & FLAG_H) && (ifre.ifr_hwaddr.sa_family != ARPHRD_ETHER))
|
|
error_exit("protocol type mismatch");
|
|
memcpy(&req.arp_ha, &(ifre.ifr_hwaddr), sizeof(req.arp_ha));
|
|
}
|
|
|
|
flags = ATF_PERM | ATF_COM;
|
|
if (toys.optargs[2]) check_flags(&flags, (toys.optargs+2));
|
|
req.arp_flags = flags;
|
|
xstrncpy(req.arp_dev, TT.device, sizeof(req.arp_dev));
|
|
xioctl(TT.sockfd, SIOCSARP, &req);
|
|
|
|
if (toys.optflags & FLAG_v) xprintf("Entry set for %s\n", toys.optargs[0]);
|
|
return 0;
|
|
}
|
|
|
|
static int ip_to_host(struct sockaddr *sa, int flag)
|
|
{
|
|
int status = 0;
|
|
char hbuf[NI_MAXHOST] = {0,}, sbuf[NI_MAXSERV] = {0,};
|
|
socklen_t len = sizeof(struct sockaddr_in6);
|
|
|
|
*toybuf = 0;
|
|
if (!(status = getnameinfo(sa, len, hbuf, sizeof(hbuf), sbuf,
|
|
sizeof(sbuf), flag))) {
|
|
strcpy(toybuf, hbuf);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int delete_entry(void)
|
|
{
|
|
int flags;
|
|
|
|
flags = ATF_PERM;
|
|
if (toys.optargs[1]) check_flags(&flags, (toys.optargs+1));
|
|
req.arp_flags = flags;
|
|
xstrncpy(req.arp_dev, TT.device, sizeof(req.arp_dev));
|
|
xioctl(TT.sockfd, SIOCDARP, &req);
|
|
|
|
if (toys.optflags & FLAG_v) xprintf("Delete entry for %s\n", toys.optargs[0]);
|
|
return 0;
|
|
}
|
|
|
|
void arp_main(void)
|
|
{
|
|
struct sockaddr sa;
|
|
char ip[128], hw_addr[128], mask[12], dev[128], *host_ip = NULL, *buf;
|
|
int h_type, type, flag, i, fd, entries = 0, disp = 0;
|
|
|
|
TT.device = "";
|
|
memset(&sa, 0, sizeof(sa));
|
|
memset(&req, 0, sizeof(req));
|
|
TT.sockfd = xsocket(AF_INET, SOCK_STREAM, 0);
|
|
|
|
if ((toys.optflags & FLAG_A) || (toys.optflags & FLAG_p)) {
|
|
if ((type = get_index(aftype,
|
|
(TT.af_type_A)?TT.af_type_A:TT.af_type_p)) != AF_INET)
|
|
error_exit((type != -1)?"only inet supported by kernel":"unknown family");
|
|
}
|
|
|
|
req.arp_ha.sa_family = ARPHRD_ETHER;
|
|
if (toys.optflags & FLAG_H) {
|
|
if ((type = get_index(hwtype, TT.hw_type)) != ARPHRD_ETHER)
|
|
error_exit((type != -1)?"h/w type not supported":"unknown h/w type");
|
|
req.arp_ha.sa_family = type;
|
|
}
|
|
|
|
if (((toys.optflags & FLAG_s) || toys.optflags & FLAG_d)) {
|
|
if (!toys.optargs[0]) error_exit("host name req");
|
|
resolve_host(toys.optargs[0], &sa);
|
|
memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr));
|
|
}
|
|
|
|
if ((toys.optflags & FLAG_s) && !set_entry()) return;
|
|
if ((toys.optflags & FLAG_d) && !delete_entry()) return;
|
|
|
|
//show arp chache
|
|
fd = xopenro("/proc/net/arp");
|
|
buf = get_line(fd);
|
|
free(buf); //skip first line
|
|
|
|
if (toys.optargs[0]) {
|
|
resolve_host(toys.optargs[0], &sa);
|
|
ip_to_host(&sa, NI_NUMERICHOST);
|
|
host_ip = xstrdup(toybuf);
|
|
}
|
|
|
|
while ((buf = get_line(fd))) {
|
|
char *host_name = "?";
|
|
|
|
if ((sscanf(buf, "%s 0x%x 0x%x %s %s %s\n", ip,
|
|
&h_type, &flag, hw_addr, mask, dev )) != 6) break;
|
|
entries++;
|
|
if (((toys.optflags & FLAG_H) && (get_index(hwtype, TT.hw_type) != h_type))
|
|
|| ((toys.optflags & FLAG_i) && strcmp(TT.interface, dev))
|
|
|| (toys.optargs[0] && strcmp(host_ip, ip))) {
|
|
free(buf);
|
|
continue;
|
|
}
|
|
|
|
resolve_host(buf, &sa);
|
|
if (!(toys.optflags & FLAG_n)) {
|
|
if (!ip_to_host(&sa, NI_NAMEREQD)) host_name = toybuf;
|
|
} else ip_to_host(&sa, NI_NUMERICHOST);
|
|
|
|
disp++;
|
|
printf("%s (%s) at" , host_name, ip);
|
|
|
|
for (i = 0; hwtype[i].name; i++)
|
|
if (hwtype[i].val & h_type) break;
|
|
if (!hwtype[i].name) error_exit("unknown h/w type");
|
|
|
|
if (!(flag & ATF_COM)) {
|
|
if ((flag & ATF_PUBL)) printf(" *");
|
|
else printf(" <incomplete>");
|
|
} else printf(" %s [%s]", hw_addr, hwtype[i].name);
|
|
|
|
if (flag & ATF_NETMASK) printf("netmask %s ", mask);
|
|
|
|
for (i = 0; flag_type[i].name; i++)
|
|
if (flag_type[i].val & flag) printf(" %s", flag_type[i].name);
|
|
|
|
printf(" on %s\n", dev);
|
|
free(buf);
|
|
}
|
|
|
|
if (toys.optflags & FLAG_v)
|
|
xprintf("Entries: %d\tSkipped: %d\tFound: %d\n",
|
|
entries, entries - disp, disp);
|
|
if (!disp) xprintf("No Match found in %d entries\n", entries);
|
|
|
|
if (CFG_TOYBOX_FREE) {
|
|
free(host_ip);
|
|
free(buf);
|
|
xclose(fd);
|
|
}
|
|
}
|