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.
1189 lines
27 KiB
1189 lines
27 KiB
7 years ago
|
diff --git a/tools/send_arp.linux.c b/tools/send_arp.linux.c
|
||
|
index e1c1960..477100a 100644
|
||
|
--- a/tools/send_arp.linux.c
|
||
|
+++ b/tools/send_arp.linux.c
|
||
|
@@ -7,6 +7,23 @@
|
||
|
* 2 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
|
||
|
+ * YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
|
||
|
+ */
|
||
|
+
|
||
|
+/* Andrew Beekhof, Lars Ellenberg:
|
||
|
+ * Based on arping from iputils,
|
||
|
+ * adapted to the command line conventions established by the libnet based
|
||
|
+ * send_arp tool as used by the IPaddr and IPaddr2 resource agents.
|
||
|
+ * The libnet based send_arp, and its command line argument convention,
|
||
|
+ * was first added to the heartbeat project by Matt Soffen.
|
||
|
+ *
|
||
|
+ * Latest "resync" with iputils as of:
|
||
|
+ * git://git.linux-ipv6.org/gitroot/iputils.git
|
||
|
+ * 511f8356e22615479c3cc16bca64d72d204f6df3
|
||
|
+ * Fri Jul 24 10:48:47 2015
|
||
|
+ * To get various bugfixes and support for infiniband and other link layer
|
||
|
+ * addresses which do not fit into plain "sockaddr_ll", and broadcast addresses
|
||
|
+ * that may be different from memset(,0xff,).
|
||
|
*/
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
@@ -16,12 +33,17 @@
|
||
|
#include <sys/file.h>
|
||
|
#include <sys/time.h>
|
||
|
#include <sys/signal.h>
|
||
|
+#include <signal.h>
|
||
|
#include <sys/ioctl.h>
|
||
|
-#include <linux/if.h>
|
||
|
+#include <net/if.h>
|
||
|
#include <linux/if_packet.h>
|
||
|
#include <linux/if_ether.h>
|
||
|
#include <net/if_arp.h>
|
||
|
#include <sys/uio.h>
|
||
|
+#ifdef CAPABILITIES
|
||
|
+#include <sys/prctl.h>
|
||
|
+#include <sys/capability.h>
|
||
|
+#endif
|
||
|
|
||
|
#include <netdb.h>
|
||
|
#include <unistd.h>
|
||
|
@@ -32,40 +54,85 @@
|
||
|
#include <netinet/in.h>
|
||
|
#include <arpa/inet.h>
|
||
|
|
||
|
-static void usage(void) __attribute__((noreturn));
|
||
|
+#ifdef USE_SYSFS
|
||
|
+#include <sysfs/libsysfs.h>
|
||
|
+struct sysfs_devattr_values;
|
||
|
+#endif
|
||
|
|
||
|
-static int quit_on_reply;
|
||
|
-static char *device;
|
||
|
-static int ifindex;
|
||
|
-static char *source;
|
||
|
-static struct in_addr src, dst;
|
||
|
-static char *target;
|
||
|
-static int dad = 0, unsolicited = 0, advert = 0;
|
||
|
-static int quiet = 0;
|
||
|
-static int count = -1;
|
||
|
-static int timeout = 0;
|
||
|
-static int unicasting = 0;
|
||
|
-static int s = 0;
|
||
|
-static int broadcast_only = 0;
|
||
|
+#ifndef WITHOUT_IFADDRS
|
||
|
+#include <ifaddrs.h>
|
||
|
+#endif
|
||
|
|
||
|
-static struct sockaddr_ll me;
|
||
|
-static struct sockaddr_ll he;
|
||
|
+#ifdef USE_IDN
|
||
|
+#include <idna.h>
|
||
|
+#include <locale.h>
|
||
|
+#endif
|
||
|
|
||
|
-static struct timeval start, last;
|
||
|
+static char SNAPSHOT[] = "s20121221";
|
||
|
|
||
|
-static int sent, brd_sent;
|
||
|
-static int received, brd_recv, req_recv;
|
||
|
+static void usage(void) __attribute__((noreturn));
|
||
|
+
|
||
|
+#ifndef DEFAULT_DEVICE
|
||
|
+#define DEFAULT_DEVICE "eth0"
|
||
|
+#endif
|
||
|
+#ifdef DEFAULT_DEVICE
|
||
|
+# define DEFAULT_DEVICE_STR DEFAULT_DEVICE
|
||
|
+#else
|
||
|
+# define DEFAULT_DEVICE NULL
|
||
|
+#endif
|
||
|
+
|
||
|
+struct device {
|
||
|
+ const char *name;
|
||
|
+ int ifindex;
|
||
|
+#ifndef WITHOUT_IFADDRS
|
||
|
+ struct ifaddrs *ifa;
|
||
|
+#endif
|
||
|
+#ifdef USE_SYSFS
|
||
|
+ struct sysfs_devattr_values *sysfs;
|
||
|
+#endif
|
||
|
+};
|
||
|
+
|
||
|
+int quit_on_reply=0;
|
||
|
+struct device device = {
|
||
|
+ .name = DEFAULT_DEVICE,
|
||
|
+};
|
||
|
+char *source;
|
||
|
+struct in_addr src, dst;
|
||
|
+char *target;
|
||
|
+int dad, unsolicited, advert;
|
||
|
+int quiet;
|
||
|
+int count=-1;
|
||
|
+int timeout;
|
||
|
+int unicasting;
|
||
|
+int s;
|
||
|
+int broadcast_only;
|
||
|
+
|
||
|
+struct sockaddr_storage me;
|
||
|
+struct sockaddr_storage he;
|
||
|
+
|
||
|
+struct timeval start, last;
|
||
|
+
|
||
|
+int sent, brd_sent;
|
||
|
+int received, brd_recv, req_recv;
|
||
|
+
|
||
|
+#ifndef CAPABILITIES
|
||
|
+static uid_t euid;
|
||
|
+#endif
|
||
|
|
||
|
#define MS_TDIFF(tv1,tv2) ( ((tv1).tv_sec-(tv2).tv_sec)*1000 + \
|
||
|
((tv1).tv_usec-(tv2).tv_usec)/1000 )
|
||
|
|
||
|
-static void print_hex(unsigned char *p, int len);
|
||
|
-static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM);
|
||
|
-static void set_signal(int signo, void (*handler)(void));
|
||
|
-static int send_pack(int s, struct in_addr src, struct in_addr dst,
|
||
|
- struct sockaddr_ll *ME, struct sockaddr_ll *HE);
|
||
|
-static void finish(void);
|
||
|
-static void catcher(void);
|
||
|
+#define OFFSET_OF(name,ele) ((size_t)&((name *)0)->ele)
|
||
|
+
|
||
|
+static socklen_t sll_len(size_t halen)
|
||
|
+{
|
||
|
+ socklen_t len = OFFSET_OF(struct sockaddr_ll, sll_addr) + halen;
|
||
|
+ if (len < sizeof(struct sockaddr_ll))
|
||
|
+ len = sizeof(struct sockaddr_ll);
|
||
|
+ return len;
|
||
|
+}
|
||
|
+
|
||
|
+#define SLL_LEN(hln) sll_len(hln)
|
||
|
|
||
|
void usage(void)
|
||
|
{
|
||
|
@@ -80,14 +147,18 @@ void usage(void)
|
||
|
" -V : print version and exit\n"
|
||
|
" -c count : how many packets to send\n"
|
||
|
" -w timeout : how long to wait for a reply\n"
|
||
|
- " -I device : which ethernet device to use (eth0)\n"
|
||
|
+ " -I device : which ethernet device to use"
|
||
|
+#ifdef DEFAULT_DEVICE_STR
|
||
|
+ " (" DEFAULT_DEVICE_STR ")"
|
||
|
+#endif
|
||
|
+ "\n"
|
||
|
" -s source : source ip address\n"
|
||
|
" destination : ask for what ip address\n"
|
||
|
);
|
||
|
exit(2);
|
||
|
}
|
||
|
|
||
|
-void set_signal(int signo, void (*handler)(void))
|
||
|
+static void set_signal(int signo, void (*handler)(void))
|
||
|
{
|
||
|
struct sigaction sa;
|
||
|
|
||
|
@@ -97,7 +168,126 @@ void set_signal(int signo, void (*handler)(void))
|
||
|
sigaction(signo, &sa, NULL);
|
||
|
}
|
||
|
|
||
|
-int send_pack(int s, struct in_addr src, struct in_addr dst,
|
||
|
+#ifdef CAPABILITIES
|
||
|
+static const cap_value_t caps[] = { CAP_NET_RAW, };
|
||
|
+static cap_flag_value_t cap_raw = CAP_CLEAR;
|
||
|
+#endif
|
||
|
+
|
||
|
+static void limit_capabilities(void)
|
||
|
+{
|
||
|
+#ifdef CAPABILITIES
|
||
|
+ cap_t cap_p;
|
||
|
+
|
||
|
+ cap_p = cap_get_proc();
|
||
|
+ if (!cap_p) {
|
||
|
+ perror("arping: cap_get_proc");
|
||
|
+ exit(-1);
|
||
|
+ }
|
||
|
+
|
||
|
+ cap_get_flag(cap_p, CAP_NET_RAW, CAP_PERMITTED, &cap_raw);
|
||
|
+
|
||
|
+ if (cap_raw != CAP_CLEAR) {
|
||
|
+ if (cap_clear(cap_p) < 0) {
|
||
|
+ perror("arping: cap_clear");
|
||
|
+ exit(-1);
|
||
|
+ }
|
||
|
+
|
||
|
+ cap_set_flag(cap_p, CAP_PERMITTED, 1, caps, CAP_SET);
|
||
|
+
|
||
|
+ if (cap_set_proc(cap_p) < 0) {
|
||
|
+ perror("arping: cap_set_proc");
|
||
|
+ if (errno != EPERM)
|
||
|
+ exit(-1);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
|
||
|
+ perror("arping: prctl");
|
||
|
+ exit(-1);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (setuid(getuid()) < 0) {
|
||
|
+ perror("arping: setuid");
|
||
|
+ exit(-1);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (prctl(PR_SET_KEEPCAPS, 0) < 0) {
|
||
|
+ perror("arping: prctl");
|
||
|
+ exit(-1);
|
||
|
+ }
|
||
|
+
|
||
|
+ cap_free(cap_p);
|
||
|
+#else
|
||
|
+ euid = geteuid();
|
||
|
+#endif
|
||
|
+}
|
||
|
+
|
||
|
+static int modify_capability_raw(int on)
|
||
|
+{
|
||
|
+#ifdef CAPABILITIES
|
||
|
+ cap_t cap_p;
|
||
|
+
|
||
|
+ if (cap_raw != CAP_SET)
|
||
|
+ return on ? -1 : 0;
|
||
|
+
|
||
|
+ cap_p = cap_get_proc();
|
||
|
+ if (!cap_p) {
|
||
|
+ perror("arping: cap_get_proc");
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ cap_set_flag(cap_p, CAP_EFFECTIVE, 1, caps, on ? CAP_SET : CAP_CLEAR);
|
||
|
+
|
||
|
+ if (cap_set_proc(cap_p) < 0) {
|
||
|
+ perror("arping: cap_set_proc");
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ cap_free(cap_p);
|
||
|
+#else
|
||
|
+ if (setuid(on ? euid : getuid())) {
|
||
|
+ perror("arping: setuid");
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+#endif
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int enable_capability_raw(void)
|
||
|
+{
|
||
|
+ return modify_capability_raw(1);
|
||
|
+}
|
||
|
+
|
||
|
+static int disable_capability_raw(void)
|
||
|
+{
|
||
|
+ return modify_capability_raw(0);
|
||
|
+}
|
||
|
+
|
||
|
+static void drop_capabilities(void)
|
||
|
+{
|
||
|
+#ifdef CAPABILITIES
|
||
|
+ cap_t cap_p = cap_init();
|
||
|
+
|
||
|
+ if (!cap_p) {
|
||
|
+ perror("arping: cap_init");
|
||
|
+ exit(-1);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (cap_set_proc(cap_p) < 0) {
|
||
|
+ perror("arping: cap_set_proc");
|
||
|
+ exit(-1);
|
||
|
+ }
|
||
|
+
|
||
|
+ cap_free(cap_p);
|
||
|
+#else
|
||
|
+ if (setuid(getuid()) < 0) {
|
||
|
+ perror("arping: setuid");
|
||
|
+ exit(-1);
|
||
|
+ }
|
||
|
+#endif
|
||
|
+}
|
||
|
+
|
||
|
+static int send_pack(int s, struct in_addr src, struct in_addr dst,
|
||
|
struct sockaddr_ll *ME, struct sockaddr_ll *HE)
|
||
|
{
|
||
|
int err;
|
||
|
@@ -130,7 +320,7 @@ int send_pack(int s, struct in_addr src, struct in_addr dst,
|
||
|
p+=4;
|
||
|
|
||
|
gettimeofday(&now, NULL);
|
||
|
- err = sendto(s, buf, p-buf, 0, (struct sockaddr*)HE, sizeof(*HE));
|
||
|
+ err = sendto(s, buf, p-buf, 0, (struct sockaddr*)HE, SLL_LEN(ah->ar_hln));
|
||
|
if (err == p-buf) {
|
||
|
last = now;
|
||
|
sent++;
|
||
|
@@ -140,7 +330,7 @@ int send_pack(int s, struct in_addr src, struct in_addr dst,
|
||
|
return err;
|
||
|
}
|
||
|
|
||
|
-void finish(void)
|
||
|
+static void finish(void)
|
||
|
{
|
||
|
if (!quiet) {
|
||
|
printf("Sent %d probes (%d broadcast(s))\n", sent, brd_sent);
|
||
|
@@ -158,40 +348,43 @@ void finish(void)
|
||
|
printf("\n");
|
||
|
fflush(stdout);
|
||
|
}
|
||
|
-
|
||
|
- if (dad) {
|
||
|
- fflush(stdout);
|
||
|
- exit(!!received);
|
||
|
- }
|
||
|
-
|
||
|
+ fflush(stdout);
|
||
|
+ if (dad)
|
||
|
+ exit(!!received);
|
||
|
if (unsolicited)
|
||
|
exit(0);
|
||
|
-
|
||
|
- fflush(stdout);
|
||
|
exit(!received);
|
||
|
}
|
||
|
|
||
|
-void catcher(void)
|
||
|
+static void catcher(void)
|
||
|
{
|
||
|
- struct timeval tv;
|
||
|
+ struct timeval tv, tv_s, tv_o;
|
||
|
|
||
|
gettimeofday(&tv, NULL);
|
||
|
|
||
|
if (start.tv_sec==0)
|
||
|
start = tv;
|
||
|
|
||
|
- if (count-- == 0 || (timeout && MS_TDIFF(tv,start) > timeout*1000 + 500))
|
||
|
+ timersub(&tv, &start, &tv_s);
|
||
|
+ tv_o.tv_sec = timeout;
|
||
|
+ tv_o.tv_usec = 500 * 1000;
|
||
|
+
|
||
|
+ if (count-- == 0 || (timeout && timercmp(&tv_s, &tv_o, >)))
|
||
|
finish();
|
||
|
|
||
|
- if (last.tv_sec==0 || MS_TDIFF(tv,last) > 500) {
|
||
|
- send_pack(s, src, dst, &me, &he);
|
||
|
+ timersub(&tv, &last, &tv_s);
|
||
|
+ tv_o.tv_sec = 0;
|
||
|
+
|
||
|
+ if (last.tv_sec==0 || timercmp(&tv_s, &tv_o, >)) {
|
||
|
+ send_pack(s, src, dst,
|
||
|
+ (struct sockaddr_ll *)&me, (struct sockaddr_ll *)&he);
|
||
|
if (count == 0 && unsolicited)
|
||
|
finish();
|
||
|
}
|
||
|
alarm(1);
|
||
|
}
|
||
|
|
||
|
-void print_hex(unsigned char *p, int len)
|
||
|
+static void print_hex(unsigned char *p, int len)
|
||
|
{
|
||
|
int i;
|
||
|
for (i=0; i<len; i++) {
|
||
|
@@ -201,7 +394,7 @@ void print_hex(unsigned char *p, int len)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
-int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
|
||
|
+static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
|
||
|
{
|
||
|
struct timeval tv;
|
||
|
struct arphdr *ah = (struct arphdr*)buf;
|
||
|
@@ -231,7 +424,7 @@ int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
|
||
|
return 0;
|
||
|
if (ah->ar_pln != 4)
|
||
|
return 0;
|
||
|
- if (ah->ar_hln != me.sll_halen)
|
||
|
+ if (ah->ar_hln != ((struct sockaddr_ll *)&me)->sll_halen)
|
||
|
return 0;
|
||
|
if (len < sizeof(*ah) + 2*(4 + ah->ar_hln))
|
||
|
return 0;
|
||
|
@@ -242,7 +435,7 @@ int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
|
||
|
return 0;
|
||
|
if (src.s_addr != dst_ip.s_addr)
|
||
|
return 0;
|
||
|
- if (memcmp(p+ah->ar_hln+4, &me.sll_addr, ah->ar_hln))
|
||
|
+ if (memcmp(p+ah->ar_hln+4, ((struct sockaddr_ll *)&me)->sll_addr, ah->ar_hln))
|
||
|
return 0;
|
||
|
} else {
|
||
|
/* DAD packet was:
|
||
|
@@ -260,7 +453,7 @@ int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
|
||
|
*/
|
||
|
if (src_ip.s_addr != dst.s_addr)
|
||
|
return 0;
|
||
|
- if (memcmp(p, &me.sll_addr, me.sll_halen) == 0)
|
||
|
+ if (memcmp(p, ((struct sockaddr_ll *)&me)->sll_addr, ((struct sockaddr_ll *)&me)->sll_halen) == 0)
|
||
|
return 0;
|
||
|
if (src.s_addr && src.s_addr != dst_ip.s_addr)
|
||
|
return 0;
|
||
|
@@ -276,7 +469,7 @@ int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
|
||
|
printf("for %s ", inet_ntoa(dst_ip));
|
||
|
s_printed = 1;
|
||
|
}
|
||
|
- if (memcmp(p+ah->ar_hln+4, me.sll_addr, ah->ar_hln)) {
|
||
|
+ if (memcmp(p+ah->ar_hln+4, ((struct sockaddr_ll *)&me)->sll_addr, ah->ar_hln)) {
|
||
|
if (!s_printed)
|
||
|
printf("for ");
|
||
|
printf("[");
|
||
|
@@ -299,16 +492,78 @@ int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM)
|
||
|
brd_recv++;
|
||
|
if (ah->ar_op == htons(ARPOP_REQUEST))
|
||
|
req_recv++;
|
||
|
- if (quit_on_reply)
|
||
|
+ if (quit_on_reply || (count == 0 && received == sent))
|
||
|
finish();
|
||
|
if(!broadcast_only) {
|
||
|
- memcpy(he.sll_addr, p, me.sll_halen);
|
||
|
+ memcpy(((struct sockaddr_ll *)&he)->sll_addr, p, ((struct sockaddr_ll *)&me)->sll_halen);
|
||
|
unicasting=1;
|
||
|
}
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
-#include <signal.h>
|
||
|
+#ifdef USE_SYSFS
|
||
|
+union sysfs_devattr_value {
|
||
|
+ unsigned long ulong;
|
||
|
+ void *ptr;
|
||
|
+};
|
||
|
+
|
||
|
+enum {
|
||
|
+ SYSFS_DEVATTR_IFINDEX,
|
||
|
+ SYSFS_DEVATTR_FLAGS,
|
||
|
+ SYSFS_DEVATTR_ADDR_LEN,
|
||
|
+#if 0
|
||
|
+ SYSFS_DEVATTR_TYPE,
|
||
|
+ SYSFS_DEVATTR_ADDRESS,
|
||
|
+#endif
|
||
|
+ SYSFS_DEVATTR_BROADCAST,
|
||
|
+ SYSFS_DEVATTR_NUM
|
||
|
+};
|
||
|
+
|
||
|
+struct sysfs_devattr_values
|
||
|
+{
|
||
|
+ char *ifname;
|
||
|
+ union sysfs_devattr_value value[SYSFS_DEVATTR_NUM];
|
||
|
+};
|
||
|
+
|
||
|
+static int sysfs_devattr_ulong_dec(char *ptr, struct sysfs_devattr_values *v, unsigned idx);
|
||
|
+static int sysfs_devattr_ulong_hex(char *ptr, struct sysfs_devattr_values *v, unsigned idx);
|
||
|
+static int sysfs_devattr_macaddr(char *ptr, struct sysfs_devattr_values *v, unsigned idx);
|
||
|
+
|
||
|
+struct sysfs_devattrs {
|
||
|
+ const char *name;
|
||
|
+ int (*handler)(char *ptr, struct sysfs_devattr_values *v, unsigned int idx);
|
||
|
+ int free;
|
||
|
+} sysfs_devattrs[SYSFS_DEVATTR_NUM] = {
|
||
|
+ [SYSFS_DEVATTR_IFINDEX] = {
|
||
|
+ .name = "ifindex",
|
||
|
+ .handler = sysfs_devattr_ulong_dec,
|
||
|
+ },
|
||
|
+ [SYSFS_DEVATTR_ADDR_LEN] = {
|
||
|
+ .name = "addr_len",
|
||
|
+ .handler = sysfs_devattr_ulong_dec,
|
||
|
+ },
|
||
|
+ [SYSFS_DEVATTR_FLAGS] = {
|
||
|
+ .name = "flags",
|
||
|
+ .handler = sysfs_devattr_ulong_hex,
|
||
|
+ },
|
||
|
+#if 0
|
||
|
+ [SYSFS_DEVATTR_TYPE] = {
|
||
|
+ .name = "type",
|
||
|
+ .handler = sysfs_devattr_ulong_dec,
|
||
|
+ },
|
||
|
+ [SYSFS_DEVATTR_ADDRESS] = {
|
||
|
+ .name = "address",
|
||
|
+ .handler = sysfs_devattr_macaddr,
|
||
|
+ .free = 1,
|
||
|
+ },
|
||
|
+#endif
|
||
|
+ [SYSFS_DEVATTR_BROADCAST] = {
|
||
|
+ .name = "broadcast",
|
||
|
+ .handler = sysfs_devattr_macaddr,
|
||
|
+ .free = 1,
|
||
|
+ },
|
||
|
+};
|
||
|
+#endif
|
||
|
|
||
|
static void byebye(int nsig)
|
||
|
{
|
||
|
@@ -317,26 +572,477 @@ static void byebye(int nsig)
|
||
|
exit(nsig);
|
||
|
}
|
||
|
|
||
|
+/*
|
||
|
+ * find_device()
|
||
|
+ *
|
||
|
+ * This function checks 1) if the device (if given) is okay for ARP,
|
||
|
+ * or 2) find fist appropriate device on the system.
|
||
|
+ *
|
||
|
+ * Return value:
|
||
|
+ * >0 : Succeeded, and appropriate device not found.
|
||
|
+ * device.ifindex remains 0.
|
||
|
+ * 0 : Succeeded, and approptiate device found.
|
||
|
+ * device.ifindex is set.
|
||
|
+ * <0 : Failed. Support not found, or other
|
||
|
+ * : system error. Try other method.
|
||
|
+ *
|
||
|
+ * If an appropriate device found, it is recorded inside the
|
||
|
+ * "device" variable for later reference.
|
||
|
+ *
|
||
|
+ * We have several implementations for this.
|
||
|
+ * by_ifaddrs(): requires getifaddr() in glibc, and rtnetlink in
|
||
|
+ * kernel. default and recommended for recent systems.
|
||
|
+ * by_sysfs(): requires libsysfs , and sysfs in kernel.
|
||
|
+ * by_ioctl(): unable to list devices without ipv4 address; this
|
||
|
+ * means, you need to supply the device name for
|
||
|
+ * DAD purpose.
|
||
|
+ */
|
||
|
+/* Common check for ifa->ifa_flags */
|
||
|
+static int check_ifflags(unsigned int ifflags, int fatal)
|
||
|
+{
|
||
|
+ if (!(ifflags & IFF_UP)) {
|
||
|
+ if (fatal) {
|
||
|
+ if (!quiet)
|
||
|
+ printf("Interface \"%s\" is down\n", device.name);
|
||
|
+ exit(2);
|
||
|
+ }
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ if (ifflags & (IFF_NOARP | IFF_LOOPBACK)) {
|
||
|
+ if (fatal) {
|
||
|
+ if (!quiet)
|
||
|
+ printf("Interface \"%s\" is not ARPable\n", device.name);
|
||
|
+ exit(dad ? 0 : 2);
|
||
|
+ }
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int find_device_by_ifaddrs(void)
|
||
|
+{
|
||
|
+#ifndef WITHOUT_IFADDRS
|
||
|
+ int rc;
|
||
|
+ struct ifaddrs *ifa0, *ifa;
|
||
|
+ int count = 0;
|
||
|
+
|
||
|
+ rc = getifaddrs(&ifa0);
|
||
|
+ if (rc) {
|
||
|
+ perror("getifaddrs");
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (ifa = ifa0; ifa; ifa = ifa->ifa_next) {
|
||
|
+ if (!ifa->ifa_addr)
|
||
|
+ continue;
|
||
|
+ if (ifa->ifa_addr->sa_family != AF_PACKET)
|
||
|
+ continue;
|
||
|
+ if (device.name && ifa->ifa_name && strcmp(ifa->ifa_name, device.name))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (check_ifflags(ifa->ifa_flags, device.name != NULL) < 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (!((struct sockaddr_ll *)ifa->ifa_addr)->sll_halen)
|
||
|
+ continue;
|
||
|
+ if (!ifa->ifa_broadaddr)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ device.ifa = ifa;
|
||
|
+
|
||
|
+ if (count++)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (count == 1 && device.ifa) {
|
||
|
+ device.ifindex = if_nametoindex(device.ifa->ifa_name);
|
||
|
+ if (!device.ifindex) {
|
||
|
+ perror("arping: if_nametoindex");
|
||
|
+ freeifaddrs(ifa0);
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ device.name = device.ifa->ifa_name;
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ return 1;
|
||
|
+#else
|
||
|
+ return -1;
|
||
|
+#endif
|
||
|
+}
|
||
|
+
|
||
|
+#ifdef USE_SYSFS
|
||
|
+static void sysfs_devattr_values_init(struct sysfs_devattr_values *v, int do_free)
|
||
|
+{
|
||
|
+ int i;
|
||
|
+ if (do_free) {
|
||
|
+ free(v->ifname);
|
||
|
+ for (i = 0; i < SYSFS_DEVATTR_NUM; i++) {
|
||
|
+ if (sysfs_devattrs[i].free)
|
||
|
+ free(v->value[i].ptr);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ memset(v, 0, sizeof(*v));
|
||
|
+}
|
||
|
+
|
||
|
+static int sysfs_devattr_ulong(char *ptr, struct sysfs_devattr_values *v, unsigned int idx,
|
||
|
+ unsigned int base)
|
||
|
+{
|
||
|
+ unsigned long *p;
|
||
|
+ char *ep;
|
||
|
+
|
||
|
+ if (!ptr || !v)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ p = &v->value[idx].ulong;
|
||
|
+ errno = 0;
|
||
|
+ *p = strtoul(ptr, &ep, base);
|
||
|
+ if ((*ptr && isspace(*ptr & 0xff)) || errno || (*ep != '\0' && *ep != '\n'))
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ return 0;
|
||
|
+out:
|
||
|
+ return -1;
|
||
|
+}
|
||
|
+
|
||
|
+static int sysfs_devattr_ulong_dec(char *ptr, struct sysfs_devattr_values *v, unsigned int idx)
|
||
|
+{
|
||
|
+ int rc = sysfs_devattr_ulong(ptr, v, idx, 10);
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
+static int sysfs_devattr_ulong_hex(char *ptr, struct sysfs_devattr_values *v, unsigned int idx)
|
||
|
+{
|
||
|
+ int rc = sysfs_devattr_ulong(ptr, v, idx, 16);
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
+static int sysfs_devattr_macaddr(char *ptr, struct sysfs_devattr_values *v, unsigned int idx)
|
||
|
+{
|
||
|
+ unsigned char *m;
|
||
|
+ int i;
|
||
|
+ unsigned int addrlen;
|
||
|
+
|
||
|
+ if (!ptr || !v)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ addrlen = v->value[SYSFS_DEVATTR_ADDR_LEN].ulong;
|
||
|
+ m = malloc(addrlen);
|
||
|
+
|
||
|
+ for (i = 0; i < addrlen; i++) {
|
||
|
+ if (i && *(ptr + i * 3 - 1) != ':')
|
||
|
+ goto out;
|
||
|
+ if (sscanf(ptr + i * 3, "%02hhx", &m[i]) != 1)
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ v->value[idx].ptr = m;
|
||
|
+ return 0;
|
||
|
+out:
|
||
|
+ free(m);
|
||
|
+ return -1;
|
||
|
+}
|
||
|
+#endif
|
||
|
+
|
||
|
+static int find_device_by_sysfs(void)
|
||
|
+{
|
||
|
+ int rc = -1;
|
||
|
+#ifdef USE_SYSFS
|
||
|
+ struct sysfs_class *cls_net;
|
||
|
+ struct dlist *dev_list;
|
||
|
+ struct sysfs_class_device *dev;
|
||
|
+ struct sysfs_attribute *dev_attr;
|
||
|
+ struct sysfs_devattr_values sysfs_devattr_values;
|
||
|
+ int count = 0;
|
||
|
+
|
||
|
+ if (!device.sysfs) {
|
||
|
+ device.sysfs = malloc(sizeof(*device.sysfs));
|
||
|
+ sysfs_devattr_values_init(device.sysfs, 0);
|
||
|
+ }
|
||
|
+
|
||
|
+ cls_net = sysfs_open_class("net");
|
||
|
+ if (!cls_net) {
|
||
|
+ perror("sysfs_open_class");
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ dev_list = sysfs_get_class_devices(cls_net);
|
||
|
+ if (!dev_list) {
|
||
|
+ perror("sysfs_get_class_devices");
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ sysfs_devattr_values_init(&sysfs_devattr_values, 0);
|
||
|
+
|
||
|
+ dlist_for_each_data(dev_list, dev, struct sysfs_class_device) {
|
||
|
+ int i;
|
||
|
+ int rc = -1;
|
||
|
+
|
||
|
+ if (device.name && strcmp(dev->name, device.name))
|
||
|
+ goto do_next;
|
||
|
+
|
||
|
+ sysfs_devattr_values_init(&sysfs_devattr_values, 1);
|
||
|
+
|
||
|
+ for (i = 0; i < SYSFS_DEVATTR_NUM; i++) {
|
||
|
+
|
||
|
+ dev_attr = sysfs_get_classdev_attr(dev, sysfs_devattrs[i].name);
|
||
|
+ if (!dev_attr) {
|
||
|
+ perror("sysfs_get_classdev_attr");
|
||
|
+ rc = -1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (sysfs_read_attribute(dev_attr)) {
|
||
|
+ perror("sysfs_read_attribute");
|
||
|
+ rc = -1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ rc = sysfs_devattrs[i].handler(dev_attr->value, &sysfs_devattr_values, i);
|
||
|
+
|
||
|
+ if (rc < 0)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (rc < 0)
|
||
|
+ goto do_next;
|
||
|
+
|
||
|
+ if (check_ifflags(sysfs_devattr_values.value[SYSFS_DEVATTR_FLAGS].ulong,
|
||
|
+ device.name != NULL) < 0)
|
||
|
+ goto do_next;
|
||
|
+
|
||
|
+ if (!sysfs_devattr_values.value[SYSFS_DEVATTR_ADDR_LEN].ulong)
|
||
|
+ goto do_next;
|
||
|
+
|
||
|
+ if (device.sysfs->value[SYSFS_DEVATTR_IFINDEX].ulong) {
|
||
|
+ if (device.sysfs->value[SYSFS_DEVATTR_FLAGS].ulong & IFF_RUNNING)
|
||
|
+ goto do_next;
|
||
|
+ }
|
||
|
+
|
||
|
+ sysfs_devattr_values.ifname = strdup(dev->name);
|
||
|
+ if (!sysfs_devattr_values.ifname) {
|
||
|
+ perror("malloc");
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ sysfs_devattr_values_init(device.sysfs, 1);
|
||
|
+ memcpy(device.sysfs, &sysfs_devattr_values, sizeof(*device.sysfs));
|
||
|
+ sysfs_devattr_values_init(&sysfs_devattr_values, 0);
|
||
|
+
|
||
|
+ if (count++)
|
||
|
+ break;
|
||
|
+
|
||
|
+ continue;
|
||
|
+do_next:
|
||
|
+ sysfs_devattr_values_init(&sysfs_devattr_values, 1);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (count == 1) {
|
||
|
+ device.ifindex = device.sysfs->value[SYSFS_DEVATTR_IFINDEX].ulong;
|
||
|
+ device.name = device.sysfs->ifname;
|
||
|
+ }
|
||
|
+ rc = !device.ifindex;
|
||
|
+out:
|
||
|
+ sysfs_close_class(cls_net);
|
||
|
+#endif
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
+static int check_device_by_ioctl(int s, struct ifreq *ifr)
|
||
|
+{
|
||
|
+ if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) {
|
||
|
+ perror("ioctl(SIOCGIFINDEX");
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (check_ifflags(ifr->ifr_flags, device.name != NULL) < 0)
|
||
|
+ return 1;
|
||
|
+
|
||
|
+ if (ioctl(s, SIOCGIFINDEX, ifr) < 0) {
|
||
|
+ perror("ioctl(SIOCGIFINDEX");
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int find_device_by_ioctl(void)
|
||
|
+{
|
||
|
+ int s;
|
||
|
+ struct ifreq *ifr0, *ifr, *ifr_end;
|
||
|
+ size_t ifrsize = sizeof(*ifr);
|
||
|
+ struct ifconf ifc;
|
||
|
+ static struct ifreq ifrbuf;
|
||
|
+ int count = 0;
|
||
|
+
|
||
|
+ s = socket(AF_INET, SOCK_DGRAM, 0);
|
||
|
+ if (s < 0) {
|
||
|
+ perror("socket");
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+
|
||
|
+ memset(&ifrbuf, 0, sizeof(ifrbuf));
|
||
|
+
|
||
|
+ if (device.name) {
|
||
|
+ strncpy(ifrbuf.ifr_name, device.name, sizeof(ifrbuf.ifr_name) - 1);
|
||
|
+ if (check_device_by_ioctl(s, &ifrbuf))
|
||
|
+ goto out;
|
||
|
+ count++;
|
||
|
+ } else {
|
||
|
+ do {
|
||
|
+ int rc;
|
||
|
+ ifr0 = malloc(ifrsize);
|
||
|
+ if (!ifr0) {
|
||
|
+ perror("malloc");
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ ifc.ifc_buf = (char *)ifr0;
|
||
|
+ ifc.ifc_len = ifrsize;
|
||
|
+
|
||
|
+ rc = ioctl(s, SIOCGIFCONF, &ifc);
|
||
|
+ if (rc < 0) {
|
||
|
+ perror("ioctl(SIOCFIFCONF");
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (ifc.ifc_len + sizeof(*ifr0) + sizeof(struct sockaddr_storage) - sizeof(struct sockaddr) <= ifrsize)
|
||
|
+ break;
|
||
|
+ ifrsize *= 2;
|
||
|
+ free(ifr0);
|
||
|
+ ifr0 = NULL;
|
||
|
+ } while(ifrsize < INT_MAX / 2);
|
||
|
+
|
||
|
+ if (!ifr0) {
|
||
|
+ fprintf(stderr, "arping: too many interfaces!?\n");
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ ifr_end = (struct ifreq *)(((char *)ifr0) + ifc.ifc_len - sizeof(*ifr0));
|
||
|
+ for (ifr = ifr0; ifr <= ifr_end; ifr++) {
|
||
|
+ if (check_device_by_ioctl(s, &ifrbuf))
|
||
|
+ continue;
|
||
|
+ memcpy(&ifrbuf.ifr_name, ifr->ifr_name, sizeof(ifrbuf.ifr_name));
|
||
|
+ if (count++)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ close(s);
|
||
|
+
|
||
|
+ if (count == 1) {
|
||
|
+ device.ifindex = ifrbuf.ifr_ifindex;
|
||
|
+ device.name = ifrbuf.ifr_name;
|
||
|
+ }
|
||
|
+ return !device.ifindex;
|
||
|
+out:
|
||
|
+ close(s);
|
||
|
+ return -1;
|
||
|
+}
|
||
|
+
|
||
|
+static int find_device(void)
|
||
|
+{
|
||
|
+ int rc;
|
||
|
+ rc = find_device_by_ifaddrs();
|
||
|
+ if (rc >= 0)
|
||
|
+ goto out;
|
||
|
+ rc = find_device_by_sysfs();
|
||
|
+ if (rc >= 0)
|
||
|
+ goto out;
|
||
|
+ rc = find_device_by_ioctl();
|
||
|
+out:
|
||
|
+ return rc;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * set_device_broadcast()
|
||
|
+ *
|
||
|
+ * This fills the device "broadcast address"
|
||
|
+ * based on information found by find_device() funcion.
|
||
|
+ */
|
||
|
+static int set_device_broadcast_ifaddrs_one(struct device *device, unsigned char *ba, size_t balen, int fatal)
|
||
|
+{
|
||
|
+#ifndef WITHOUT_IFADDRS
|
||
|
+ struct ifaddrs *ifa;
|
||
|
+ struct sockaddr_ll *sll;
|
||
|
+
|
||
|
+ if (!device)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ ifa = device->ifa;
|
||
|
+ if (!ifa)
|
||
|
+ return -1;
|
||
|
+
|
||
|
+ sll = (struct sockaddr_ll *)ifa->ifa_broadaddr;
|
||
|
+
|
||
|
+ if (sll->sll_halen != balen) {
|
||
|
+ if (fatal) {
|
||
|
+ if (!quiet)
|
||
|
+ printf("Address length does not match...\n");
|
||
|
+ exit(2);
|
||
|
+ }
|
||
|
+ return -1;
|
||
|
+ }
|
||
|
+ memcpy(ba, sll->sll_addr, sll->sll_halen);
|
||
|
+ return 0;
|
||
|
+#else
|
||
|
+ return -1;
|
||
|
+#endif
|
||
|
+}
|
||
|
+static int set_device_broadcast_sysfs(struct device *device, unsigned char *ba, size_t balen)
|
||
|
+{
|
||
|
+#ifdef USE_SYSFS
|
||
|
+ struct sysfs_devattr_values *v;
|
||
|
+ if (!device)
|
||
|
+ return -1;
|
||
|
+ v = device->sysfs;
|
||
|
+ if (!v)
|
||
|
+ return -1;
|
||
|
+ if (v->value[SYSFS_DEVATTR_ADDR_LEN].ulong != balen)
|
||
|
+ return -1;
|
||
|
+ memcpy(ba, v->value[SYSFS_DEVATTR_BROADCAST].ptr, balen);
|
||
|
+ return 0;
|
||
|
+#else
|
||
|
+ return -1;
|
||
|
+#endif
|
||
|
+}
|
||
|
+
|
||
|
+static int set_device_broadcast_fallback(struct device *device, unsigned char *ba, size_t balen)
|
||
|
+{
|
||
|
+ if (!quiet)
|
||
|
+ fprintf(stderr, "WARNING: using default broadcast address.\n");
|
||
|
+ memset(ba, -1, balen);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static void set_device_broadcast(struct device *dev, unsigned char *ba, size_t balen)
|
||
|
+{
|
||
|
+ if (!set_device_broadcast_ifaddrs_one(dev, ba, balen, 0))
|
||
|
+ return;
|
||
|
+ if (!set_device_broadcast_sysfs(dev, ba, balen))
|
||
|
+ return;
|
||
|
+ set_device_broadcast_fallback(dev, ba, balen);
|
||
|
+}
|
||
|
+
|
||
|
int
|
||
|
main(int argc, char **argv)
|
||
|
{
|
||
|
int socket_errno;
|
||
|
int ch;
|
||
|
- uid_t uid = getuid();
|
||
|
int hb_mode = 0;
|
||
|
|
||
|
signal(SIGTERM, byebye);
|
||
|
signal(SIGPIPE, byebye);
|
||
|
-
|
||
|
- device = strdup("eth0");
|
||
|
-
|
||
|
+
|
||
|
+ limit_capabilities();
|
||
|
+
|
||
|
+#ifdef USE_IDN
|
||
|
+ setlocale(LC_ALL, "");
|
||
|
+#endif
|
||
|
+
|
||
|
+ enable_capability_raw();
|
||
|
+
|
||
|
s = socket(PF_PACKET, SOCK_DGRAM, 0);
|
||
|
socket_errno = errno;
|
||
|
|
||
|
- if (setuid(uid)) {
|
||
|
- perror("arping: setuid");
|
||
|
- exit(-1);
|
||
|
- }
|
||
|
+ disable_capability_raw();
|
||
|
|
||
|
while ((ch = getopt(argc, argv, "h?bfDUAqc:w:s:I:Vr:i:p:")) != EOF) {
|
||
|
switch(ch) {
|
||
|
@@ -367,7 +1073,7 @@ main(int argc, char **argv)
|
||
|
timeout = atoi(optarg);
|
||
|
break;
|
||
|
case 'I':
|
||
|
- device = optarg;
|
||
|
+ device.name = optarg;
|
||
|
break;
|
||
|
case 'f':
|
||
|
quit_on_reply=1;
|
||
|
@@ -376,7 +1082,7 @@ main(int argc, char **argv)
|
||
|
source = optarg;
|
||
|
break;
|
||
|
case 'V':
|
||
|
- printf("send_arp utility\n");
|
||
|
+ printf("send_arp utility, based on arping from iputils-%s\n", SNAPSHOT);
|
||
|
exit(0);
|
||
|
case 'p':
|
||
|
case 'i':
|
||
|
@@ -405,7 +1111,7 @@ main(int argc, char **argv)
|
||
|
*/
|
||
|
|
||
|
unsolicited = 1;
|
||
|
- device = argv[optind];
|
||
|
+ device.name = argv[optind];
|
||
|
target = argv[optind+1];
|
||
|
|
||
|
} else {
|
||
|
@@ -417,10 +1123,8 @@ main(int argc, char **argv)
|
||
|
target = *argv;
|
||
|
}
|
||
|
|
||
|
- if (device == NULL) {
|
||
|
- fprintf(stderr, "arping: device (option -I) is required\n");
|
||
|
- usage();
|
||
|
- }
|
||
|
+ if (device.name && !*device.name)
|
||
|
+ device.name = NULL;
|
||
|
|
||
|
if (s < 0) {
|
||
|
errno = socket_errno;
|
||
|
@@ -428,39 +1132,42 @@ main(int argc, char **argv)
|
||
|
exit(2);
|
||
|
}
|
||
|
|
||
|
- if (1) {
|
||
|
- struct ifreq ifr;
|
||
|
- memset(&ifr, 0, sizeof(ifr));
|
||
|
- strncpy(ifr.ifr_name, device, IFNAMSIZ-1);
|
||
|
- if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
|
||
|
- fprintf(stderr, "arping: unknown iface %s\n", device);
|
||
|
- exit(2);
|
||
|
- }
|
||
|
- ifindex = ifr.ifr_ifindex;
|
||
|
+ if (find_device() < 0)
|
||
|
+ exit(2);
|
||
|
|
||
|
- if (ioctl(s, SIOCGIFFLAGS, (char*)&ifr)) {
|
||
|
- perror("ioctl(SIOCGIFFLAGS)");
|
||
|
+ if (!device.ifindex) {
|
||
|
+ if (device.name) {
|
||
|
+ fprintf(stderr, "arping: Device %s not available.\n", device.name);
|
||
|
exit(2);
|
||
|
}
|
||
|
- if (!(ifr.ifr_flags&IFF_UP)) {
|
||
|
- if (!quiet)
|
||
|
- printf("Interface \"%s\" is down\n", device);
|
||
|
- exit(2);
|
||
|
- }
|
||
|
- if (ifr.ifr_flags&(IFF_NOARP|IFF_LOOPBACK)) {
|
||
|
- if (!quiet)
|
||
|
- printf("Interface \"%s\" is not ARPable\n", device);
|
||
|
- exit(dad?0:2);
|
||
|
- }
|
||
|
+ fprintf(stderr, "arping: device (option -I) is required.\n");
|
||
|
+ usage();
|
||
|
}
|
||
|
|
||
|
if (inet_aton(target, &dst) != 1) {
|
||
|
struct hostent *hp;
|
||
|
- hp = gethostbyname2(target, AF_INET);
|
||
|
+ char *idn = target;
|
||
|
+#ifdef USE_IDN
|
||
|
+ int rc;
|
||
|
+
|
||
|
+ rc = idna_to_ascii_lz(target, &idn, 0);
|
||
|
+
|
||
|
+ if (rc != IDNA_SUCCESS) {
|
||
|
+ fprintf(stderr, "arping: IDN encoding failed: %s\n", idna_strerror(rc));
|
||
|
+ exit(2);
|
||
|
+ }
|
||
|
+#endif
|
||
|
+
|
||
|
+ hp = gethostbyname2(idn, AF_INET);
|
||
|
if (!hp) {
|
||
|
fprintf(stderr, "arping: unknown host %s\n", target);
|
||
|
exit(2);
|
||
|
}
|
||
|
+
|
||
|
+#ifdef USE_IDN
|
||
|
+ free(idn);
|
||
|
+#endif
|
||
|
+
|
||
|
memcpy(&dst, hp->h_addr, 4);
|
||
|
}
|
||
|
|
||
|
@@ -480,9 +1187,13 @@ main(int argc, char **argv)
|
||
|
perror("socket");
|
||
|
exit(2);
|
||
|
}
|
||
|
- if (device) {
|
||
|
- if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1)
|
||
|
+ if (device.name) {
|
||
|
+ enable_capability_raw();
|
||
|
+
|
||
|
+ if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device.name, strlen(device.name)+1) == -1)
|
||
|
perror("WARNING: interface is ignored");
|
||
|
+
|
||
|
+ disable_capability_raw();
|
||
|
}
|
||
|
memset(&saddr, 0, sizeof(saddr));
|
||
|
saddr.sin_family = AF_INET;
|
||
|
@@ -514,9 +1225,9 @@ main(int argc, char **argv)
|
||
|
close(probe_fd);
|
||
|
};
|
||
|
|
||
|
- me.sll_family = AF_PACKET;
|
||
|
- me.sll_ifindex = ifindex;
|
||
|
- me.sll_protocol = htons(ETH_P_ARP);
|
||
|
+ ((struct sockaddr_ll *)&me)->sll_family = AF_PACKET;
|
||
|
+ ((struct sockaddr_ll *)&me)->sll_ifindex = device.ifindex;
|
||
|
+ ((struct sockaddr_ll *)&me)->sll_protocol = htons(ETH_P_ARP);
|
||
|
if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) {
|
||
|
perror("bind");
|
||
|
exit(2);
|
||
|
@@ -529,18 +1240,20 @@ main(int argc, char **argv)
|
||
|
exit(2);
|
||
|
}
|
||
|
}
|
||
|
- if (me.sll_halen == 0) {
|
||
|
+ if (((struct sockaddr_ll *)&me)->sll_halen == 0) {
|
||
|
if (!quiet)
|
||
|
- printf("Interface \"%s\" is not ARPable (no ll address)\n", device);
|
||
|
+ printf("Interface \"%s\" is not ARPable (no ll address)\n", device.name);
|
||
|
exit(dad?0:2);
|
||
|
}
|
||
|
|
||
|
he = me;
|
||
|
- memset(he.sll_addr, -1, he.sll_halen);
|
||
|
+
|
||
|
+ set_device_broadcast(&device, ((struct sockaddr_ll *)&he)->sll_addr,
|
||
|
+ ((struct sockaddr_ll *)&he)->sll_halen);
|
||
|
|
||
|
if (!quiet) {
|
||
|
printf("ARPING %s ", inet_ntoa(dst));
|
||
|
- printf("from %s %s\n", inet_ntoa(src), device ? : "");
|
||
|
+ printf("from %s %s\n", inet_ntoa(src), device.name ? : "");
|
||
|
}
|
||
|
|
||
|
if (!src.s_addr && !dad) {
|
||
|
@@ -548,6 +1261,8 @@ main(int argc, char **argv)
|
||
|
exit(2);
|
||
|
}
|
||
|
|
||
|
+ drop_capabilities();
|
||
|
+
|
||
|
set_signal(SIGINT, finish);
|
||
|
set_signal(SIGALRM, catcher);
|
||
|
|
||
|
@@ -556,7 +1271,7 @@ main(int argc, char **argv)
|
||
|
while(1) {
|
||
|
sigset_t sset, osset;
|
||
|
unsigned char packet[4096];
|
||
|
- struct sockaddr_ll from;
|
||
|
+ struct sockaddr_storage from;
|
||
|
socklen_t alen = sizeof(from);
|
||
|
int cc;
|
||
|
|
||
|
@@ -565,11 +1280,12 @@ main(int argc, char **argv)
|
||
|
perror("arping: recvfrom");
|
||
|
continue;
|
||
|
}
|
||
|
+
|
||
|
sigemptyset(&sset);
|
||
|
sigaddset(&sset, SIGALRM);
|
||
|
sigaddset(&sset, SIGINT);
|
||
|
sigprocmask(SIG_BLOCK, &sset, &osset);
|
||
|
- recv_pack(packet, cc, &from);
|
||
|
+ recv_pack(packet, cc, (struct sockaddr_ll *)&from);
|
||
|
sigprocmask(SIG_SETMASK, &osset, NULL);
|
||
|
}
|
||
|
}
|