* [B.A.T.M.A.N.] [PATCHv4 2/4] batctl: Allow to use IPv4 addresses for ping/traceroute
2012-10-14 20:20 [B.A.T.M.A.N.] [PATCHv4 1/4] batctl: Translate client mac to originator mac for ping/traceroute Sven Eckelmann
@ 2012-10-14 20:20 ` Sven Eckelmann
2012-10-16 17:57 ` Marek Lindner
2012-10-14 20:20 ` [B.A.T.M.A.N.] [PATCHv4 3/4] batctl: Allow to skip header in debug table output Sven Eckelmann
` (2 subsequent siblings)
3 siblings, 1 reply; 7+ messages in thread
From: Sven Eckelmann @ 2012-10-14 20:20 UTC (permalink / raw)
To: b.a.t.m.a.n
IPv4 addresses and hostnames are easier to remember than many MAC addresses.
batctl can automatically resolve the MAC address of the target device when the
IP is configured on top of the batman-adv device and the source and destination
batman-adv interface are in the same IPv4 subnet.
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
rebased on DAT
README | 4 +-
functions.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
functions.h | 1 +
man/batctl.8 | 18 ++++---
ping.c | 6 +--
traceroute.c | 6 +--
6 files changed, 170 insertions(+), 14 deletions(-)
diff --git a/README b/README
index 04a6e66..cefcf24 100644
--- a/README
+++ b/README
@@ -81,7 +81,7 @@ batctl ping
Sends a Layer 2 batman-adv ping to check round trip time and connectivity
-Usage: batctl ping [parameters] mac|bat-host
+Usage: batctl ping [parameters] mac|bat-host|host-name|IPv4-address
parameters:
-c ping packet count
-h print this help
@@ -107,7 +107,7 @@ batctl traceroute
Traceroute sends 3 packets to each hop, awaits the answers and prints out the
response times.
-Usage: batctl traceroute [parameters] mac|bat-host
+Usage: batctl traceroute [parameters] mac|bat-host|host-name|IPv4-address
Example:
diff --git a/functions.c b/functions.c
index 7875716..a500444 100644
--- a/functions.c
+++ b/functions.c
@@ -22,6 +22,9 @@
#define _GNU_SOURCE
#include <netinet/ether.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netdb.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -402,3 +405,149 @@ out:
free(line);
return mac_result;
}
+
+static uint32_t resolve_ipv4(const char *asc)
+{
+ int ret;
+ struct addrinfo hints;
+ struct addrinfo *res;
+ struct sockaddr_in *inet4;
+ uint32_t addr = 0;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ ret = getaddrinfo(asc, NULL, &hints, &res);
+ if (ret)
+ return 0;
+
+ if (res) {
+ inet4 = (struct sockaddr_in *)res->ai_addr;
+ addr = inet4->sin_addr.s_addr;
+ }
+
+ freeaddrinfo(res);
+ return addr;
+}
+
+static void request_arp(uint32_t ipv4_addr)
+{
+ struct sockaddr_in inet4;
+ int sock;
+ char t = 0;
+
+ memset(&inet4, 0, sizeof(inet4));
+ sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ if (sock < 0)
+ return;
+
+ inet4.sin_family = AF_INET;
+ inet4.sin_port = htons(9);
+ inet4.sin_addr.s_addr = ipv4_addr;
+ sendto(sock, &t, sizeof(t), 0, (const struct sockaddr *)&inet4,
+ sizeof(inet4));
+ close(sock);
+}
+
+static struct ether_addr *resolve_mac_from_arp(uint32_t ipv4_addr)
+{
+ struct ether_addr mac_empty;
+ struct ether_addr *mac_result = NULL, *mac_tmp;
+ struct sockaddr_in inet4;
+ int ret;
+ FILE *f;
+ size_t len = 0;
+ char *line = NULL;
+ int skip_line = 1;
+ size_t column;
+ char *token, *input, *saveptr;
+ int line_invalid;
+
+ memset(&mac_empty, 0, sizeof(mac_empty));
+
+ f = fopen("/proc/net/arp", "r");
+ if (!f)
+ return NULL;
+
+ while (getline(&line, &len, f) != -1) {
+ if (skip_line) {
+ skip_line = 0;
+ continue;
+ }
+
+ line_invalid = 0;
+ column = 0;
+ input = line;
+ while ((token = strtok_r(input, " \t", &saveptr))) {
+ input = NULL;
+
+ if (column == 0) {
+ ret = inet_pton(AF_INET, token, &inet4.sin_addr);
+ if (ret != 1) {
+ line_invalid = 1;
+ break;
+ }
+ }
+
+ if (column == 3) {
+ mac_tmp = ether_aton(token);
+ if (!mac_tmp || memcmp(mac_tmp, &mac_empty,
+ sizeof(mac_empty)) == 0) {
+ line_invalid = 1;
+ break;
+ }
+ }
+
+ column++;
+ }
+
+ if (column < 4)
+ line_invalid = 1;
+
+ if (line_invalid)
+ continue;
+
+ if (ipv4_addr == inet4.sin_addr.s_addr) {
+ mac_result = mac_tmp;
+ break;
+ }
+ }
+
+ free(line);
+ fclose(f);
+ return mac_result;
+}
+
+static struct ether_addr *resolve_mac_from_ipv4(const char *asc)
+{
+ uint32_t ipv4_addr;
+ int retries = 5;
+ struct ether_addr *mac_result = NULL;
+
+ ipv4_addr = resolve_ipv4(asc);
+ if (!ipv4_addr)
+ return NULL;
+
+ while (retries-- && !mac_result) {
+ mac_result = resolve_mac_from_arp(ipv4_addr);
+ if (!mac_result) {
+ request_arp(ipv4_addr);
+ usleep(200000);
+ }
+ }
+
+ return mac_result;
+}
+
+struct ether_addr *resolve_mac(const char *asc)
+{
+ struct ether_addr *mac_result = NULL;
+
+ mac_result = ether_aton(asc);
+ if (mac_result)
+ goto out;
+
+ mac_result = resolve_mac_from_ipv4(asc);
+
+out:
+ return mac_result;
+}
diff --git a/functions.h b/functions.h
index a59bb24..0ec1d1a 100644
--- a/functions.h
+++ b/functions.h
@@ -38,6 +38,7 @@ int read_file(char *dir, char *path, int read_opt,
float orig_timeout, float watch_interval);
int write_file(char *dir, char *fname, char *arg1, char *arg2);
struct ether_addr *translate_mac(char *mesh_iface, struct ether_addr *mac);
+struct ether_addr *resolve_mac(const char *asc);
extern char *line_ptr;
diff --git a/man/batctl.8 b/man/batctl.8
index 369be20..804682e 100644
--- a/man/batctl.8
+++ b/man/batctl.8
@@ -212,19 +212,25 @@ tt - translation table counters
All counters without a prefix concern payload (pure user data) traffic.
.RE
.br
-.IP "\fBping\fP|\fBp\fP [\fB\-c count\fP][\fB\-i interval\fP][\fB\-t time\fP][\fB\-R\fP][\fB\-T\fP] \fBMAC_address\fP|\fBbat\-host_name\fP"
+.IP "\fBping\fP|\fBp\fP [\fB\-c count\fP][\fB\-i interval\fP][\fB\-t time\fP][\fB\-R\fP][\fB\-T\fP] \fBMAC_address\fP|\fBbat\-host_name\fP|\fBhost_name\fP|\fBIPv4_address\fP"
Layer 2 ping of a MAC address or bat\-host name. batctl will try to find the bat\-host name if the given parameter was
-not a MAC address. The "\-c" option tells batctl how man pings should be sent before the program exits. Without the "\-c"
+not a MAC address. It can also try to guess the MAC address using an IPv4 address or a hostname when
+the IPv4 address was configured on top of the batman-adv interface of the destination device and both source and
+destination devices are in the same IPv4 subnet.
+The "\-c" option tells batctl how man pings should be sent before the program exits. Without the "\-c"
option batctl will continue pinging without end. Use CTRL + C to stop it. With "\-i" and "\-t" you can set the default
interval between pings and the timeout time for replies, both in seconds. When run with "\-R", the route taken by the ping
messages will be recorded. With "\-T" you can disable the automatic translation of a client MAC address to the originator
address which is responsible for this client.
.br
-.IP "\fBtraceroute\fP|\fBtr\fP [\fB\-n\fP][\fB\-T\fP] \fBMAC_address\fP|\fBbat\-host_name\fP"
+.IP "\fBtraceroute\fP|\fBtr\fP [\fB\-n\fP][\fB\-T\fP] \fBMAC_address\fP|\fBbat\-host_name\fP|\fBhost_name\fP|\fBIPv4_address\fP"
Layer 2 traceroute to a MAC address or bat\-host name. batctl will try to find the bat\-host name if the given parameter
-was not a MAC address. batctl will send 3 packets to each host and display the response time. If "\-n" is given batctl will
-not replace the MAC addresses with bat\-host names in the output. With "\-T" you can disable the automatic translation of a
-client MAC address to the originator address which is responsible for this client.
+was not a MAC address. It can also try to guess the MAC address using an IPv4 address or a hostname when
+the IPv4 address was configured on top of the batman-adv interface of the destination device and both source and
+destination devices are in the same IPv4 subnet.
+batctl will send 3 packets to each host and display the response time. If "\-n" is given batctl will
+not replace the MAC addresses with bat\-host names in the output. With "\-T" you can disable the automatic translation
+of a client MAC address to the originator address which is responsible for this client.
.br
.IP "\fBtcpdump\fP|\fBtd\fP [\fB\-c\fP][\fB\-n\fP][\fB\-p filter\fP][\fB\-x filter\fP] \fBinterface ...\fP"
batctl will display all packets that are seen on the given interface(s). A variety of options to filter the output
diff --git a/ping.c b/ping.c
index 02132f4..51d18e8 100644
--- a/ping.c
+++ b/ping.c
@@ -44,7 +44,7 @@ char is_aborted = 0;
void ping_usage(void)
{
- printf("Usage: batctl [options] ping [parameters] mac|bat-host \n");
+ printf("Usage: batctl [options] ping [parameters] mac|bat-host|host_name|IPv4_address \n");
printf("parameters:\n");
printf(" \t -c ping packet count \n");
printf(" \t -h print this help\n");
@@ -137,10 +137,10 @@ int ping(char *mesh_iface, int argc, char **argv)
dst_mac = &bat_host->mac_addr;
if (!dst_mac) {
- dst_mac = ether_aton(dst_string);
+ dst_mac = resolve_mac(dst_string);
if (!dst_mac) {
- printf("Error - the ping destination is not a mac address or bat-host name: %s\n", dst_string);
+ printf("Error - mac address of the ping destination could not be resolved and is not a bat-host name: %s\n", dst_string);
goto out;
}
}
diff --git a/traceroute.c b/traceroute.c
index 4e42419..ac2f1fa 100644
--- a/traceroute.c
+++ b/traceroute.c
@@ -43,7 +43,7 @@
void traceroute_usage(void)
{
- printf("Usage: batctl [options] traceroute [parameters] mac|bat-host \n");
+ printf("Usage: batctl [options] traceroute [parameters] mac|bat-host|host_name|IPv4_address \n");
printf("parameters:\n");
printf(" \t -h print this help\n");
printf(" \t -n don't convert addresses to bat-host names\n");
@@ -99,10 +99,10 @@ int traceroute(char *mesh_iface, int argc, char **argv)
dst_mac = &bat_host->mac_addr;
if (!dst_mac) {
- dst_mac = ether_aton(dst_string);
+ dst_mac = resolve_mac(dst_string);
if (!dst_mac) {
- printf("Error - the traceroute destination is not a mac address or bat-host name: %s\n", dst_string);
+ printf("Error - mac address of the ping destination could not be resolved and is not a bat-host name: %s\n", dst_string);
goto out;
}
}
--
1.7.10.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* [B.A.T.M.A.N.] [PATCHv4 3/4] batctl: Allow to skip header in debug table output
2012-10-14 20:20 [B.A.T.M.A.N.] [PATCHv4 1/4] batctl: Translate client mac to originator mac for ping/traceroute Sven Eckelmann
2012-10-14 20:20 ` [B.A.T.M.A.N.] [PATCHv4 2/4] batctl: Allow to use IPv4 addresses " Sven Eckelmann
@ 2012-10-14 20:20 ` Sven Eckelmann
2012-10-16 18:00 ` Marek Lindner
2012-10-14 20:21 ` [B.A.T.M.A.N.] [PATCHv4 4/4] batctl: Add filter option for debug tables Sven Eckelmann
2012-10-16 17:46 ` [B.A.T.M.A.N.] [PATCHv4 1/4] batctl: Translate client mac to originator mac for ping/traceroute Marek Lindner
3 siblings, 1 reply; 7+ messages in thread
From: Sven Eckelmann @ 2012-10-14 20:20 UTC (permalink / raw)
To: b.a.t.m.a.n
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
rebased on DAT
debug.c | 18 +++++++++++++++---
debug.h | 1 +
functions.c | 7 ++++++-
functions.h | 3 ++-
main.c | 2 +-
man/batctl.8 | 3 +++
sys.c | 14 +++++++-------
7 files changed, 35 insertions(+), 13 deletions(-)
diff --git a/debug.c b/debug.c
index a230a12..260448b 100644
--- a/debug.c
+++ b/debug.c
@@ -38,36 +38,43 @@ const struct debug_table_data batctl_debug_tables[BATCTL_TABLE_NUM] = {
.opt_long = "originators",
.opt_short = "o",
.debugfs_name = "originators",
+ .header_lines = 2,
},
{
.opt_long = "gateways",
.opt_short = "gwl",
.debugfs_name = "gateways",
+ .header_lines = 1,
},
{
.opt_long = "translocal",
.opt_short = "tl",
.debugfs_name = "transtable_local",
+ .header_lines = 1,
},
{
.opt_long = "transglobal",
.opt_short = "tg",
.debugfs_name = "transtable_global",
+ .header_lines = 2,
},
{
.opt_long = "claimtable",
.opt_short = "cl",
.debugfs_name = "bla_claim_table",
+ .header_lines = 2,
},
{
.opt_long = "backbonetable",
.opt_short = "bbt",
.debugfs_name = "bla_backbone_table",
+ .header_lines = 2,
},
{
.opt_long = "dat_cache",
.opt_short = "dc",
.debugfs_name = "dat_cache",
+ .header_lines = 2,
},
};
@@ -78,6 +85,7 @@ void debug_table_usage(int debug_table)
printf("parameters:\n");
printf(" \t -h print this help\n");
printf(" \t -n don't replace mac addresses with bat-host names\n");
+ printf(" \t -H don't show the header\n");
printf(" \t -w [interval] watch mode - refresh the table continuously\n");
if (debug_table == BATCTL_TABLE_ORIGINATORS)
@@ -93,7 +101,7 @@ int handle_debug_table(char *mesh_iface, int debug_table, int argc, char **argv)
float watch_interval = 1;
opterr = 0;
- while ((optchar = getopt(argc, argv, "hnw:t:")) != -1) {
+ while ((optchar = getopt(argc, argv, "hnw:t:H")) != -1) {
switch (optchar) {
case 'h':
debug_table_usage(debug_table);
@@ -126,6 +134,9 @@ int handle_debug_table(char *mesh_iface, int debug_table, int argc, char **argv)
return EXIT_FAILURE;
}
break;
+ case 'H':
+ read_opt |= SKIP_HEADER;
+ break;
case '?':
if (optopt == 't')
printf("Error - option '-t' needs a number as argument\n");
@@ -152,7 +163,8 @@ int handle_debug_table(char *mesh_iface, int debug_table, int argc, char **argv)
debugfs_make_path(DEBUG_BATIF_PATH_FMT "/", mesh_iface, full_path, sizeof(full_path));
return read_file(full_path, (char *)batctl_debug_tables[debug_table].debugfs_name,
- read_opt, orig_timeout, watch_interval);
+ read_opt, orig_timeout, watch_interval,
+ batctl_debug_tables[debug_table].header_lines);
}
static void log_usage(void)
@@ -190,6 +202,6 @@ int log_print(char *mesh_iface, int argc, char **argv)
}
debugfs_make_path(DEBUG_BATIF_PATH_FMT "/", mesh_iface, full_path, sizeof(full_path));
- res = read_file(full_path, DEBUG_LOG, read_opt, 0, 0);
+ res = read_file(full_path, DEBUG_LOG, read_opt, 0, 0, 0);
return res;
}
diff --git a/debug.h b/debug.h
index 5bd7f3e..3fa2830 100644
--- a/debug.h
+++ b/debug.h
@@ -40,6 +40,7 @@ struct debug_table_data {
const char opt_long[OPT_LONG_MAX_LEN];
const char opt_short[OPT_SHORT_MAX_LEN];
const char debugfs_name[DEBUG_TABLE_PATH_MAX_LEN];
+ size_t header_lines;
};
extern const struct debug_table_data batctl_debug_tables[BATCTL_TABLE_NUM];
diff --git a/functions.c b/functions.c
index a500444..57c2bba 100644
--- a/functions.c
+++ b/functions.c
@@ -162,7 +162,7 @@ static void file_open_problem_dbg(char *dir, char *fname, char *full_path)
}
int read_file(char *dir, char *fname, int read_opt,
- float orig_timeout, float watch_interval)
+ float orig_timeout, float watch_interval, size_t header_lines)
{
struct ether_addr *mac_addr;
struct bat_host *bat_host;
@@ -171,6 +171,7 @@ int read_file(char *dir, char *fname, int read_opt,
char full_path[500], *buff_ptr, *space_ptr, extra_char;
size_t len = 0;
FILE *fp = NULL;
+ size_t line;
if (read_opt & USE_BAT_HOSTS)
bat_hosts_init(read_opt);
@@ -180,6 +181,7 @@ int read_file(char *dir, char *fname, int read_opt,
strncat(full_path, fname, sizeof(full_path) - strlen(full_path));
open:
+ line = 0;
fp = fopen(full_path, "r");
if (!fp) {
@@ -195,6 +197,9 @@ open:
read:
while (getline(&line_ptr, &len, fp) != -1) {
+ if (line++ < header_lines && read_opt & SKIP_HEADER)
+ continue;
+
/* the buffer will be handled elsewhere */
if (read_opt & USE_READ_BUFF)
break;
diff --git a/functions.h b/functions.h
index 0ec1d1a..6e427f4 100644
--- a/functions.h
+++ b/functions.h
@@ -35,7 +35,7 @@ char *get_name_by_macaddr(struct ether_addr *mac_addr, int read_opt);
char *get_name_by_macstr(char *mac_str, int read_opt);
int file_exists(const char *fpath);
int read_file(char *dir, char *path, int read_opt,
- float orig_timeout, float watch_interval);
+ float orig_timeout, float watch_interval, size_t header_lines);
int write_file(char *dir, char *fname, char *arg1, char *arg2);
struct ether_addr *translate_mac(char *mesh_iface, struct ether_addr *mac);
struct ether_addr *resolve_mac(const char *asc);
@@ -52,4 +52,5 @@ enum {
SILENCE_ERRORS = 0x20,
NO_OLD_ORIGS = 0x40,
COMPAT_FILTER = 0x80,
+ SKIP_HEADER = 0x100,
};
diff --git a/main.c b/main.c
index 01a435b..647818d 100644
--- a/main.c
+++ b/main.c
@@ -118,7 +118,7 @@ int main(int argc, char **argv)
if (strcmp(argv[1], "-v") == 0) {
printf("batctl %s [batman-adv: ", SOURCE_VERSION);
- ret = read_file("", module_ver_path, USE_READ_BUFF | SILENCE_ERRORS, 0, 0);
+ ret = read_file("", module_ver_path, USE_READ_BUFF | SILENCE_ERRORS, 0, 0, 0);
if ((line_ptr) && (line_ptr[strlen(line_ptr) - 1] == '\n'))
line_ptr[strlen(line_ptr) - 1] = '\0';
diff --git a/man/batctl.8 b/man/batctl.8
index 804682e..feb1a17 100644
--- a/man/batctl.8
+++ b/man/batctl.8
@@ -168,6 +168,9 @@ All of the debug tables support the following options:
.RS 10
\-n do not replace the MAC addresses with bat\-host names in the output
.RE
+.RS 10
+\-H do not show the header of the debug table
+.RE
.RS 7
The originator table also supports the "\-t" filter option to remove all originators from the output that have not been seen
diff --git a/sys.c b/sys.c
index 3d5e129..9591416 100644
--- a/sys.c
+++ b/sys.c
@@ -136,7 +136,7 @@ static int print_interfaces(char *mesh_iface)
while ((iface_dir = readdir(iface_base_dir)) != NULL) {
snprintf(path_buff, PATH_BUFF_LEN, SYS_MESH_IFACE_FMT, iface_dir->d_name);
- res = read_file("", path_buff, USE_READ_BUFF | SILENCE_ERRORS, 0, 0);
+ res = read_file("", path_buff, USE_READ_BUFF | SILENCE_ERRORS, 0, 0, 0);
if (res != EXIT_SUCCESS)
continue;
@@ -153,7 +153,7 @@ static int print_interfaces(char *mesh_iface)
line_ptr = NULL;
snprintf(path_buff, PATH_BUFF_LEN, SYS_IFACE_STATUS_FMT, iface_dir->d_name);
- res = read_file("", path_buff, USE_READ_BUFF | SILENCE_ERRORS, 0, 0);
+ res = read_file("", path_buff, USE_READ_BUFF | SILENCE_ERRORS, 0, 0, 0);
if (res != EXIT_SUCCESS) {
printf("<error reading status>\n");
continue;
@@ -318,7 +318,7 @@ int handle_loglevel(char *mesh_iface, int argc, char **argv)
goto out;
}
- res = read_file(path_buff, SYS_LOG_LEVEL, USE_READ_BUFF, 0, 0);
+ res = read_file(path_buff, SYS_LOG_LEVEL, USE_READ_BUFF, 0, 0, 0);
if (res != EXIT_SUCCESS)
goto out;
@@ -382,7 +382,7 @@ int handle_sys_setting(char *mesh_iface, int setting, int argc, char **argv)
if (argc == 1) {
res = read_file(path_buff, (char *)batctl_settings[setting].sysfs_name,
- NO_FLAGS, 0, 0);
+ NO_FLAGS, 0, 0, 0);
goto out;
}
@@ -445,7 +445,7 @@ int handle_gw_setting(char *mesh_iface, int argc, char **argv)
snprintf(path_buff, PATH_BUFF_LEN, SYS_BATIF_PATH_FMT, mesh_iface);
if (argc == 1) {
- res = read_file(path_buff, SYS_GW_MODE, USE_READ_BUFF, 0, 0);
+ res = read_file(path_buff, SYS_GW_MODE, USE_READ_BUFF, 0, 0, 0);
if (res != EXIT_SUCCESS)
goto out;
@@ -465,10 +465,10 @@ int handle_gw_setting(char *mesh_iface, int argc, char **argv)
switch (gw_mode) {
case GW_MODE_CLIENT:
- res = read_file(path_buff, SYS_GW_SEL, USE_READ_BUFF, 0, 0);
+ res = read_file(path_buff, SYS_GW_SEL, USE_READ_BUFF, 0, 0, 0);
break;
case GW_MODE_SERVER:
- res = read_file(path_buff, SYS_GW_BW, USE_READ_BUFF, 0, 0);
+ res = read_file(path_buff, SYS_GW_BW, USE_READ_BUFF, 0, 0, 0);
break;
default:
printf("off\n");
--
1.7.10.4
^ permalink raw reply related [flat|nested] 7+ messages in thread* [B.A.T.M.A.N.] [PATCHv4 4/4] batctl: Add filter option for debug tables
2012-10-14 20:20 [B.A.T.M.A.N.] [PATCHv4 1/4] batctl: Translate client mac to originator mac for ping/traceroute Sven Eckelmann
2012-10-14 20:20 ` [B.A.T.M.A.N.] [PATCHv4 2/4] batctl: Allow to use IPv4 addresses " Sven Eckelmann
2012-10-14 20:20 ` [B.A.T.M.A.N.] [PATCHv4 3/4] batctl: Allow to skip header in debug table output Sven Eckelmann
@ 2012-10-14 20:21 ` Sven Eckelmann
2012-10-16 17:46 ` [B.A.T.M.A.N.] [PATCHv4 1/4] batctl: Translate client mac to originator mac for ping/traceroute Marek Lindner
3 siblings, 0 replies; 7+ messages in thread
From: Sven Eckelmann @ 2012-10-14 20:21 UTC (permalink / raw)
To: b.a.t.m.a.n
Users may only want to query information about specific originator or clients
when looking at the debug tables. This can easily be done using a simple grep
when the originator mac is known. More problematic are clients or IP addresses.
The user has to perform the steps already done for ping/traceroute to get the
correct MAC address.
This filter functionality can also be added as part of batctl since the
functionality for mac translation is already in batctl. This even allows to
keep the header of the debug output intact while grep'ing for a specific
address.
This can for example be used to query the TQ of the path until the gateway
originator for a specific IP is reached.
$ batctl o -H -F ${IP}|sed -e 's/).*$//' -e 's/^.*(//'
Signed-off-by: Sven Eckelmann <sven@narfation.org>
---
rebased on DAT
Makefile | 2 +-
debug.c | 27 ++++++++--
filter.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
filter.h | 43 +++++++++++++++
functions.c | 5 ++
functions.h | 2 +
man/batctl.8 | 12 +++--
7 files changed, 250 insertions(+), 9 deletions(-)
create mode 100644 filter.c
create mode 100644 filter.h
diff --git a/Makefile b/Makefile
index 4379837..a4b6c11 100755
--- a/Makefile
+++ b/Makefile
@@ -24,7 +24,7 @@ export CONFIG_BATCTL_BISECT=n
# batctl build
BINARY_NAME = batctl
-OBJ = main.o bat-hosts.o functions.o sys.o debug.o ping.o traceroute.o tcpdump.o hash.o vis.o debugfs.o ioctl.o list-batman.o
+OBJ = main.o bat-hosts.o functions.o sys.o debug.o ping.o traceroute.o tcpdump.o hash.o vis.o debugfs.o ioctl.o list-batman.o filter.o
OBJ_BISECT = bisect_iv.o
MANPAGE = man/batctl.8
diff --git a/debug.c b/debug.c
index 260448b..d939eaa 100644
--- a/debug.c
+++ b/debug.c
@@ -32,6 +32,7 @@
#include "debug.h"
#include "debugfs.h"
#include "functions.h"
+#include "filter.h"
const struct debug_table_data batctl_debug_tables[BATCTL_TABLE_NUM] = {
{
@@ -86,6 +87,8 @@ void debug_table_usage(int debug_table)
printf(" \t -h print this help\n");
printf(" \t -n don't replace mac addresses with bat-host names\n");
printf(" \t -H don't show the header\n");
+ printf(" \t -F addr - add filter to only show lines about this address\n");
+ printf(" \t -T do not try to translate client mac addresses when adding filters\n");
printf(" \t -w [interval] watch mode - refresh the table continuously\n");
if (debug_table == BATCTL_TABLE_ORIGINATORS)
@@ -94,14 +97,17 @@ void debug_table_usage(int debug_table)
int handle_debug_table(char *mesh_iface, int debug_table, int argc, char **argv)
{
- int optchar, read_opt = USE_BAT_HOSTS;
+ int optchar, read_opt = USE_BAT_HOSTS | TRANSLATE_MAC;
char full_path[MAX_PATH+1];
char *debugfs_mnt;
float orig_timeout;
float watch_interval = 1;
+ int ret;
opterr = 0;
- while ((optchar = getopt(argc, argv, "hnw:t:H")) != -1) {
+ filter_init();
+
+ while ((optchar = getopt(argc, argv, "hnw:t:HTF:")) != -1) {
switch (optchar) {
case 'h':
debug_table_usage(debug_table);
@@ -137,6 +143,13 @@ int handle_debug_table(char *mesh_iface, int debug_table, int argc, char **argv)
case 'H':
read_opt |= SKIP_HEADER;
break;
+ case 'T':
+ read_opt &= ~TRANSLATE_MAC;
+ break;
+ case 'F':
+ read_opt |= USE_FILTER;
+ filter_add(mesh_iface, optarg, read_opt);
+ break;
case '?':
if (optopt == 't')
printf("Error - option '-t' needs a number as argument\n");
@@ -162,9 +175,13 @@ int handle_debug_table(char *mesh_iface, int debug_table, int argc, char **argv)
}
debugfs_make_path(DEBUG_BATIF_PATH_FMT "/", mesh_iface, full_path, sizeof(full_path));
- return read_file(full_path, (char *)batctl_debug_tables[debug_table].debugfs_name,
- read_opt, orig_timeout, watch_interval,
- batctl_debug_tables[debug_table].header_lines);
+ ret = read_file(full_path, (char *)batctl_debug_tables[debug_table].debugfs_name,
+ read_opt, orig_timeout, watch_interval,
+ batctl_debug_tables[debug_table].header_lines);
+
+ filter_free();
+
+ return ret;
}
static void log_usage(void)
diff --git a/filter.c b/filter.c
new file mode 100644
index 0000000..88dd425
--- /dev/null
+++ b/filter.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2007-2012 B.A.T.M.A.N. contributors:
+ *
+ * Andreas Langer <an.langer@gmx.de>, Marek Lindner <lindner_marek@yahoo.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdint.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+#include "main.h"
+#include "filter.h"
+#include "hash.h"
+#include "functions.h"
+
+
+static struct hashtable_t *filter_hash = NULL;
+
+static int compare_mac(void *data1, void *data2)
+{
+ return (memcmp(data1, data2, sizeof(struct ether_addr)) == 0 ? 1 : 0);
+}
+
+static int choose_mac(void *data, int32_t size)
+{
+ unsigned char *key = data;
+ uint32_t hash = 0, m_size = sizeof(struct ether_addr);
+ size_t i;
+
+ for (i = 0; i < m_size; i++) {
+ hash += key[i];
+ hash += (hash << 10);
+ hash ^= (hash >> 6);
+ }
+
+ hash += (hash << 3);
+ hash ^= (hash >> 11);
+ hash += (hash << 15);
+
+ return hash % size;
+}
+
+void filter_add(char *mesh_iface, const char *addr, int read_opt)
+{
+ struct ether_addr *mac_addr;
+ struct filter *filter;
+ struct hashtable_t *swaphash;
+
+ mac_addr = resolve_mac(addr);
+ if (!mac_addr) {
+ fprintf(stderr, "Warning - unable to resolve mac address for %s\n", addr);
+ return;
+ }
+
+ if (read_opt & TRANSLATE_MAC)
+ mac_addr = translate_mac(mesh_iface, mac_addr);
+
+ filter = malloc(sizeof(*filter));
+ if (!filter) {
+ fprintf(stderr, "Error - could not allocate memory: %s\n", strerror(errno));
+ return;
+ }
+
+ memcpy(&filter->mac_addr, mac_addr, sizeof(struct ether_addr));
+
+ hash_add(filter_hash, filter);
+ if (filter_hash->elements * 4 > filter_hash->size) {
+ swaphash = hash_resize(filter_hash, filter_hash->size * 2);
+
+ if (swaphash)
+ filter_hash = swaphash;
+ else
+ fprintf(stderr, "Warning - couldn't resize filter hash table\n");
+ }
+}
+
+int filter_match_line(const char *line)
+{
+ char *line_ptr, *buff_ptr, *space_ptr;
+ int ret = 0;
+ struct ether_addr *mac_addr;
+ struct filter *filter;
+
+ line_ptr = strdup(line);
+ if (!line_ptr)
+ return 0;
+
+ buff_ptr = line_ptr;
+
+ while ((space_ptr = strchr(buff_ptr, ' ')) != NULL) {
+
+ *space_ptr = '\0';
+
+ if (strlen(buff_ptr) == ETH_STR_LEN + 1) {
+ switch (buff_ptr[ETH_STR_LEN]) {
+ case ',':
+ case ')':
+ buff_ptr[ETH_STR_LEN] = '\0';
+ break;
+ }
+ }
+
+ if (strlen(buff_ptr) != ETH_STR_LEN)
+ goto next;
+
+ mac_addr = ether_aton(buff_ptr);
+ if (!mac_addr)
+ goto next;
+
+ filter = filter_find_by_mac(mac_addr);
+ if (filter) {
+ ret = 1;
+ goto out;
+ }
+
+next:
+ buff_ptr = space_ptr + 1;
+ }
+
+out:
+ free(line_ptr);
+ return ret;
+}
+
+void filter_init(void)
+{
+ filter_hash = hash_new(64, compare_mac, choose_mac);
+ if (!filter_hash)
+ printf("Warning - could not create filter hash table\n");
+}
+
+struct filter *filter_find_by_mac(struct ether_addr *mac)
+{
+ if (!filter_hash)
+ return NULL;
+
+ return (struct filter *)hash_find(filter_hash, (char *)mac);
+}
+
+static void filter_entry_free(void *data)
+{
+ free(data);
+}
+
+void filter_free(void)
+{
+ if (filter_hash)
+ hash_delete(filter_hash, filter_entry_free);
+}
diff --git a/filter.h b/filter.h
new file mode 100644
index 0000000..a7d997a
--- /dev/null
+++ b/filter.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2009-2012 B.A.T.M.A.N. contributors:
+ *
+ * Marek Lindner <lindner_marek@yahoo.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA
+ *
+ */
+
+
+
+#ifndef _FILTER_H
+#define _FILTER_H 1
+
+#include <netinet/ether.h>
+
+#define HOST_NAME_MAX_LEN 50
+#define CONF_DIR_LEN 256
+
+
+struct filter {
+ struct ether_addr mac_addr;
+} __attribute__((packed));
+
+void filter_init(void);
+void filter_add(char *mesh_iface, const char *addr, int read_opt);
+struct filter *filter_find_by_mac(struct ether_addr *mac);
+int filter_match_line(const char *line);
+void filter_free(void);
+
+#endif
diff --git a/functions.c b/functions.c
index 57c2bba..98d45d5 100644
--- a/functions.c
+++ b/functions.c
@@ -38,6 +38,7 @@
#include "main.h"
#include "functions.h"
#include "bat-hosts.h"
+#include "filter.h"
#include "sys.h"
#include "debug.h"
#include "debugfs.h"
@@ -215,6 +216,10 @@ read:
continue;
}
+ if (read_opt & USE_FILTER && line > header_lines &&
+ !filter_match_line(line_ptr))
+ continue;
+
/* replace mac addresses with bat host names */
buff_ptr = line_ptr;
diff --git a/functions.h b/functions.h
index 6e427f4..2dd91e3 100644
--- a/functions.h
+++ b/functions.h
@@ -53,4 +53,6 @@ enum {
NO_OLD_ORIGS = 0x40,
COMPAT_FILTER = 0x80,
SKIP_HEADER = 0x100,
+ USE_FILTER = 0x200,
+ TRANSLATE_MAC = 0x400,
};
diff --git a/man/batctl.8 b/man/batctl.8
index feb1a17..52c8dae 100644
--- a/man/batctl.8
+++ b/man/batctl.8
@@ -163,13 +163,19 @@ mounted batctl will attempt to do this step for you.
All of the debug tables support the following options:
.RS 10
-\-w refresh the list every second or add a number to let it refresh at a custom interval in seconds (with optional decimal places)
+\-w refresh the list every second or add a number to let it refresh at a custom interval in seconds (with optional decimal places)
.RE
.RS 10
-\-n do not replace the MAC addresses with bat\-host names in the output
+\-n do not replace the MAC addresses with bat\-host names in the output
.RE
.RS 10
-\-H do not show the header of the debug table
+\-H do not show the header of the debug table
+.RE
+.RS 10
+\-F addr add filter to only show lines about the address
+.RE
+.RS 10
+\-T do not try to translate client mac addresses when adding filters
.RE
.RS 7
--
1.7.10.4
^ permalink raw reply related [flat|nested] 7+ messages in thread