Signed-off-by: Sven Eckelmann sven@narfation.org --- bat-hosts.c | 5 +++-- bat-hosts.h | 2 +- bisect_iv.c | 7 ++++--- debug.c | 5 ----- debug.h | 3 +++ debugfs.c | 10 ++++------ debugfs.h | 3 --- functions.c | 2 ++ functions.h | 3 ++- ioctl.c | 3 +-- list-batman.h | 3 --- main.c | 3 --- ping.c | 5 +++++ sys.c | 1 - sys.h | 2 ++ tcpdump.c | 6 +++++- tcpdump.h | 5 ++++- traceroute.c | 4 ++++ translate.c | 1 - 19 files changed, 40 insertions(+), 33 deletions(-)
diff --git a/bat-hosts.c b/bat-hosts.c index ee862da..9d36531 100644 --- a/bat-hosts.c +++ b/bat-hosts.c @@ -21,14 +21,15 @@
-#include <stdio.h> #include <stdint.h> +#include <stdio.h> #include <limits.h> #include <stdlib.h> #include <errno.h> #include <string.h> +#include <stddef.h> +#include <netinet/ether.h>
-#include "main.h" #include "bat-hosts.h" #include "hash.h" #include "functions.h" diff --git a/bat-hosts.h b/bat-hosts.h index 74a4ce5..96abfa9 100644 --- a/bat-hosts.h +++ b/bat-hosts.h @@ -24,7 +24,7 @@ #ifndef _BATCTL_BAT_HOSTS_H #define _BATCTL_BAT_HOSTS_H
-#include <netinet/ether.h> +#include <net/ethernet.h>
#define HOST_NAME_MAX_LEN 50 #define CONF_DIR_LEN 256 diff --git a/bisect_iv.c b/bisect_iv.c index c0f9420..917ffec 100644 --- a/bisect_iv.c +++ b/bisect_iv.c @@ -19,14 +19,15 @@ * */
+#include <stdint.h> #include <stdio.h> #include <stdlib.h> -#include <stdint.h> -#include <unistd.h> #include <string.h> #include <errno.h> +#include <unistd.h> +#include <stddef.h> +#include <netinet/ether.h>
-#include "main.h" #include "bisect_iv.h" #include "bat-hosts.h" #include "hash.h" diff --git a/debug.c b/debug.c index 2589dbc..6b7b648 100644 --- a/debug.c +++ b/debug.c @@ -23,12 +23,7 @@ #include <unistd.h> #include <stdio.h> #include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <sys/types.h> -#include <dirent.h>
-#include "main.h" #include "debug.h" #include "debugfs.h" #include "functions.h" diff --git a/debug.h b/debug.h index 8d9de08..563a7bb 100644 --- a/debug.h +++ b/debug.h @@ -22,6 +22,9 @@ #ifndef _BATCTL_DEBUG_H #define _BATCTL_DEBUG_H
+#include <stddef.h> +#include "main.h" + #define DEBUG_BATIF_PATH_FMT "%s/batman_adv/%s" #define DEBUG_TRANSTABLE_GLOBAL "transtable_global" #define DEBUG_LOG "log" diff --git a/debugfs.c b/debugfs.c index bfedcfe..8033f8b 100644 --- a/debugfs.c +++ b/debugfs.c @@ -19,14 +19,12 @@ */
#include "debugfs.h" -#include <stdio.h> -#include <stdlib.h> #include <errno.h> -#include <sys/vfs.h> -#include <sys/types.h> +#include <stdio.h> +#include <string.h> +#include <sys/mount.h> #include <sys/stat.h> -#include <fcntl.h> -#include <unistd.h> +#include <sys/statfs.h>
#ifndef DEBUGFS_MAGIC #define DEBUGFS_MAGIC 0x64626720 diff --git a/debugfs.h b/debugfs.h index 3981b8b..e608902 100644 --- a/debugfs.h +++ b/debugfs.h @@ -21,9 +21,6 @@ #ifndef __DEBUGFS_H__ #define __DEBUGFS_H__
-#include <sys/mount.h> -#include <string.h> - #ifndef MAX_PATH # define MAX_PATH 256 #endif diff --git a/functions.c b/functions.c index bd4da59..1a33d6d 100644 --- a/functions.c +++ b/functions.c @@ -33,6 +33,8 @@ #include <errno.h> #include <fcntl.h> #include <sys/time.h> +#include <netinet/in.h> +#include <stdint.h>
#include "main.h" #include "functions.h" diff --git a/functions.h b/functions.h index 6720a1b..a96b7ee 100644 --- a/functions.h +++ b/functions.h @@ -22,7 +22,8 @@ #ifndef _BATCTL_FUNCTIONS_H #define _BATCTL_FUNCTIONS_H
-#include <netinet/if_ether.h> +#include <net/ethernet.h> +#include <stddef.h>
#define ETH_STR_LEN 17 diff --git a/ioctl.c b/ioctl.c index 3d5b50d..cbb1aa5 100644 --- a/ioctl.c +++ b/ioctl.c @@ -26,15 +26,14 @@ #include <string.h> #include <unistd.h> #include <sys/ioctl.h> +#include <sys/types.h> #include <sys/socket.h> #include <linux/if.h> #include <linux/sockios.h> #include <linux/ethtool.h> #include <stdint.h>
-#include "main.h" #include "ioctl.h" -#include "debugfs.h"
/* code borrowed from ethtool */ static int statistics_custom_get(int fd, struct ifreq *ifr) diff --git a/list-batman.h b/list-batman.h index 7de5943..aea0f95 100644 --- a/list-batman.h +++ b/list-batman.h @@ -19,9 +19,6 @@ * */
- -#include <stddef.h> /* offsetof() */ - #ifndef _LINUX_LIST_H #define _LINUX_LIST_H
diff --git a/main.c b/main.c index 6b44359..84bb42a 100644 --- a/main.c +++ b/main.c @@ -21,9 +21,7 @@
-#include <sys/types.h> #include <stdio.h> -#include <stdint.h> #include <stdlib.h> #include <unistd.h> #include <string.h> @@ -38,7 +36,6 @@ #include "bisect_iv.h" #include "ioctl.h" #include "functions.h" -#include <err.h>
char mesh_dfl_iface[] = "bat0"; char module_ver_path[] = "/sys/module/batman_adv/version"; diff --git a/ping.c b/ping.c index 4d76484..d505d02 100644 --- a/ping.c +++ b/ping.c @@ -30,6 +30,11 @@ #include <fcntl.h> #include <string.h> #include <math.h> +#include <stddef.h> +#include <stdint.h> +#include <sys/select.h> +#include <sys/time.h> +#include <linux/if_ether.h>
#include "main.h" #include "ping.h" diff --git a/sys.c b/sys.c index 3e60c79..7539f76 100644 --- a/sys.c +++ b/sys.c @@ -25,7 +25,6 @@ #include <stdlib.h> #include <string.h> #include <errno.h> -#include <sys/types.h> #include <dirent.h>
#include "main.h" diff --git a/sys.h b/sys.h index dfc167a..5d207a1 100644 --- a/sys.h +++ b/sys.h @@ -22,6 +22,8 @@ #ifndef _BATCTL_SYS_H #define _BATCTL_SYS_H
+#include "main.h" + #define SYS_BATIF_PATH_FMT "/sys/class/net/%s/mesh/" #define SYS_LOG_LEVEL "log_level" #define SYS_LOG "log" diff --git a/tcpdump.c b/tcpdump.c index 7e0987b..a220c3c 100644 --- a/tcpdump.c +++ b/tcpdump.c @@ -36,8 +36,12 @@ #include <netinet/udp.h> #include <netinet/ip_icmp.h> #include <netinet/if_ether.h> +#include <net/ethernet.h> +#include <stddef.h> +#include <stdint.h> +#include <sys/select.h> +#include <sys/socket.h>
-#include "main.h" #include "tcpdump.h" #include "packet.h" #include "bat-hosts.h" diff --git a/tcpdump.h b/tcpdump.h index 2845576..3c1a0e1 100644 --- a/tcpdump.h +++ b/tcpdump.h @@ -23,7 +23,10 @@ #define _BATCTL_TCPDUMP_H
#include <netpacket/packet.h> -#include <net/ethernet.h> +#include <linux/if_ether.h> +#include <net/if_arp.h> +#include <sys/types.h> +#include "main.h" #include "list-batman.h"
#ifndef ARPHRD_IEEE80211_PRISM diff --git a/traceroute.c b/traceroute.c index d62df5e..0cb0441 100644 --- a/traceroute.c +++ b/traceroute.c @@ -28,6 +28,10 @@ #include <unistd.h> #include <fcntl.h> #include <string.h> +#include <linux/if_ether.h> +#include <stddef.h> +#include <sys/select.h> +#include <sys/time.h>
#include "main.h" #include "traceroute.h" diff --git a/translate.c b/translate.c index 0b4fbc6..da6d593 100644 --- a/translate.c +++ b/translate.c @@ -19,7 +19,6 @@ * */
-#include <netinet/in.h> #include <stdio.h> #include <stdlib.h>
The first implementation of the IP translation functions in cb75e019e74fc11f9547dadd51abbf3c9df2c5e7 ("batctl: Allow to use IPv4 addresses for ping/traceroute") had is focus on implementing it only for IPv4. This is a limitation when other layer 3 protocols are used.
For example, a port to IPv6 would either have to copy the functionality or do a major refactoring when implementing the it resolv functionality. This is not necessary when the functions already expect different layer 3 protocols in the first place and make it easy to find the right place to modify them.
Signed-off-by: Sven Eckelmann sven@narfation.org --- functions.c | 86 ++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 23 deletions(-)
diff --git a/functions.c b/functions.c index 1a33d6d..e4aeb72 100644 --- a/functions.c +++ b/functions.c @@ -416,49 +416,68 @@ out: return mac_result; }
-static uint32_t resolve_ipv4(const char *asc) +static int resolve_l3addr(int ai_family, const char *asc, void *l3addr) { 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; + hints.ai_family = ai_family; ret = getaddrinfo(asc, NULL, &hints, &res); if (ret) - return 0; + return -EADDRNOTAVAIL;
if (res) { - inet4 = (struct sockaddr_in *)res->ai_addr; - addr = inet4->sin_addr.s_addr; + switch (ai_family) { + case AF_INET: + inet4 = (struct sockaddr_in *)res->ai_addr; + memcpy(l3addr, &inet4->sin_addr.s_addr, + sizeof(inet4->sin_addr.s_addr)); + break; + default: + ret = -EINVAL; + } }
freeaddrinfo(res); - return addr; + return ret; }
-static void request_arp(uint32_t ipv4_addr) +static void request_mac_resolve(int ai_family, const void *l3addr) { + const struct sockaddr *sockaddr; struct sockaddr_in inet4; + size_t sockaddr_len; int sock; char t = 0;
- memset(&inet4, 0, sizeof(inet4)); - sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + sock = socket(ai_family, 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)); + switch (ai_family) { + case AF_INET: + memset(&inet4, 0, sizeof(inet4)); + inet4.sin_family = ai_family; + inet4.sin_port = htons(9); + memcpy(&inet4.sin_addr.s_addr, l3addr, + sizeof(inet4.sin_addr.s_addr)); + sockaddr = (const struct sockaddr *)&inet4; + sockaddr_len = sizeof(inet4); + break; + default: + close(sock); + return; + } + + sendto(sock, &t, sizeof(t), 0, sockaddr, sockaddr_len); close(sock); }
-static struct ether_addr *resolve_mac_from_arp(uint32_t ipv4_addr) +static struct ether_addr *resolve_mac_from_cache(int ai_family, + const void *l3addr) { struct ether_addr mac_empty; struct ether_addr *mac_result = NULL, *mac_tmp = NULL; @@ -471,7 +490,12 @@ static struct ether_addr *resolve_mac_from_arp(uint32_t ipv4_addr) size_t column; char *token, *input, *saveptr; int line_invalid; + uint32_t ipv4_addr;
+ if (ai_family != AF_INET) + return NULL; + + memcpy(&ipv4_addr, l3addr, sizeof(ipv4_addr)); memset(&mac_empty, 0, sizeof(mac_empty));
f = fopen("/proc/net/arp", "r"); @@ -527,20 +551,30 @@ static struct ether_addr *resolve_mac_from_arp(uint32_t ipv4_addr) return mac_result; }
-static struct ether_addr *resolve_mac_from_ipv4(const char *asc) +static struct ether_addr *resolve_mac_from_addr(int ai_family, const char *asc) { - uint32_t ipv4_addr; + uint8_t ipv4_addr[4]; + void *l3addr; + int ret; int retries = 5; struct ether_addr *mac_result = NULL;
- ipv4_addr = resolve_ipv4(asc); - if (!ipv4_addr) + switch (ai_family) { + case AF_INET: + l3addr = ipv4_addr; + break; + default: + return NULL; + } + + ret = resolve_l3addr(ai_family, asc, l3addr); + if (ret < 0) return NULL;
while (retries-- && !mac_result) { - mac_result = resolve_mac_from_arp(ipv4_addr); + mac_result = resolve_mac_from_cache(ai_family, l3addr); if (!mac_result) { - request_arp(ipv4_addr); + request_mac_resolve(ai_family, l3addr); usleep(200000); } } @@ -551,12 +585,18 @@ static struct ether_addr *resolve_mac_from_ipv4(const char *asc) struct ether_addr *resolve_mac(const char *asc) { struct ether_addr *mac_result = NULL; + static const int ai_families[] = {AF_INET}; + size_t i;
mac_result = ether_aton(asc); if (mac_result) goto out;
- mac_result = resolve_mac_from_ipv4(asc); + for (i = 0; i < sizeof(ai_families) / sizeof(*ai_families); i++) { + mac_result = resolve_mac_from_addr(ai_families[i], asc); + if (mac_result) + goto out; + }
out: return mac_result;
On Sunday 22 September 2013 16:42:24 Sven Eckelmann wrote:
The first implementation of the IP translation functions in cb75e019e74fc11f9547dadd51abbf3c9df2c5e7 ("batctl: Allow to use IPv4 addresses for ping/traceroute") had is focus on implementing it only for IPv4. This is a limitation when other layer 3 protocols are used.
For example, a port to IPv6 would either have to copy the functionality or do a major refactoring when implementing the it resolv functionality. This is not necessary when the functions already expect different layer 3 protocols in the first place and make it easy to find the right place to modify them.
Signed-off-by: Sven Eckelmann sven@narfation.org
functions.c | 86 ++++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 63 insertions(+), 23 deletions(-)
Applied in revision daf6aa6.
Thanks, Marek
The /proc/net/arp based solution to resolve mac addresses from IP adresses is limited to IPv4 addresses. The table for IPv6 addresses to MAC addresses is only available through rtnetlink. rtnetlink also provides the IPv4 neighbor table and should therefore should be prefered over the /proc/net/arp solution to build an infrastructure for further work on the resolver.
Signed-off-by: Sven Eckelmann sven@narfation.org --- functions.c | 215 +++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 155 insertions(+), 60 deletions(-)
diff --git a/functions.c b/functions.c index e4aeb72..e56479d 100644 --- a/functions.c +++ b/functions.c @@ -21,7 +21,6 @@
#include <netinet/ether.h> -#include <arpa/inet.h> #include <sys/socket.h> #include <netdb.h> #include <sys/types.h> @@ -35,6 +34,11 @@ #include <sys/time.h> #include <netinet/in.h> #include <stdint.h> +#include <linux/netlink.h> +#include <net/ethernet.h> +#include <linux/rtnetlink.h> +#include <linux/neighbour.h> +#include <sys/uio.h>
#include "main.h" #include "functions.h" @@ -476,78 +480,169 @@ static void request_mac_resolve(int ai_family, const void *l3addr) close(sock); }
+static int resolve_mac_from_cache_open(int ai_family) +{ + int socknl; + int ret; + struct { + struct nlmsghdr hdr; + struct ndmsg msg; + } nlreq; + struct sockaddr_nl addrnl; + static uint32_t nr_call = 0; + uint32_t pid = (++nr_call + getpid()) & 0x3FFFFF; + + memset(&addrnl, 0, sizeof(addrnl)); + addrnl.nl_family = AF_NETLINK; + addrnl.nl_pid = pid; + addrnl.nl_groups = 0; + + memset(&nlreq, 0, sizeof(nlreq)); + nlreq.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(nlreq.msg)); + nlreq.hdr.nlmsg_type = RTM_GETNEIGH; + nlreq.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlreq.msg.ndm_family = ai_family; + + socknl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (socknl < 0) + goto out; + + ret = bind(socknl, (struct sockaddr*)&addrnl, sizeof(addrnl)); + if (ret < 0) + goto outclose; + + ret = send(socknl, &nlreq, nlreq.hdr.nlmsg_len, 0); + if (ret < 0) + goto outclose; +out: + return socknl; +outclose: + close(socknl); + return ret; +} + +static ssize_t resolve_mac_from_cache_dump(int ai_family, void **buf) +{ + struct iovec iov; + struct msghdr msg; + size_t buflen = 4096; + ssize_t ret = -1; + int socknl; + + *buf = NULL; + memset(&msg, 0, sizeof(msg)); + memset(&iov, 0, sizeof(iov)); + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_controllen = 0; + msg.msg_control = NULL; + msg.msg_flags = 0; + +retry: + socknl = resolve_mac_from_cache_open(ai_family); + if (socknl < 0) { + ret = socknl; + free(*buf); + goto out; + } + + *buf = realloc(*buf, buflen); + if (!*buf) { + ret = -ENOMEM; + goto err; + } + + iov.iov_len = buflen; + iov.iov_base = *buf; + + ret = recvmsg(socknl, &msg, 0); + if (ret < 0) + goto err; + + close(socknl); + if (msg.msg_flags & MSG_TRUNC) { + buflen *= 2; + goto retry; + } + +out: + return ret; +err: + close(socknl); + free(*buf); + *buf = NULL; + return ret; +} + static struct ether_addr *resolve_mac_from_cache(int ai_family, const void *l3addr) { + static uint8_t l3addr_tmp[16]; + int l3found, llfound; struct ether_addr mac_empty; - struct ether_addr *mac_result = NULL, *mac_tmp = NULL; - 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; - uint32_t ipv4_addr; + struct ether_addr mac_tmp; + struct ether_addr *mac_result = NULL; + void *buf = NULL; + struct nlmsghdr *nh; + struct ndmsg *ndmsg; + struct rtattr *rtattr; + size_t len_payload; + ssize_t len; + size_t l3_len;
- if (ai_family != AF_INET) - return NULL; - - memcpy(&ipv4_addr, l3addr, sizeof(ipv4_addr)); memset(&mac_empty, 0, sizeof(mac_empty));
- f = fopen("/proc/net/arp", "r"); - if (!f) - return NULL; + switch (ai_family) { + case AF_INET: + l3_len = 4; + break; + default: + l3_len = 0; + }
- while (getline(&line, &len, f) != -1) { - if (skip_line) { - skip_line = 0; - continue; - } + len = resolve_mac_from_cache_dump(ai_family, &buf); + if (len < 0) + goto out;
- 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; + for (nh = buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { + if (nh->nlmsg_type == NLMSG_DONE) break; + + l3found = 0; + llfound = 0; + ndmsg = NLMSG_DATA(nh); + len_payload = RTM_PAYLOAD(nh); + + for (rtattr = RTM_RTA(ndmsg); RTA_OK(rtattr, len_payload); + rtattr = RTA_NEXT(rtattr, len_payload)) { + switch (rtattr->rta_type) { + case NDA_DST: + memcpy(&l3addr_tmp, RTA_DATA(rtattr), l3_len); + l3found = 1; + break; + case NDA_LLADDR: + memcpy(&mac_tmp, RTA_DATA(rtattr), + sizeof(mac_tmp)); + if (memcmp(&mac_tmp, &mac_empty, + sizeof(mac_empty)) == 0) + llfound = 0; + else + llfound = 1; + break; + } + } + + if (llfound && l3found) { + if (memcmp(&l3addr_tmp, l3addr, l3_len) == 0) { + mac_result = &mac_tmp; + break; + } } }
- free(line); - fclose(f); + free(buf); +out: return mac_result; }
The /proc/net/arp based solution to resolve mac addresses from IP adresses is limited to IPv4 addresses. The table for IPv6 addresses to MAC addresses is only available through rtnetlink. rtnetlink also provides the IPv4 neighbor table and should therefore should be prefered over the /proc/net/arp solution to build an infrastructure for further work on the resolver.
Signed-off-by: Sven Eckelmann sven@narfation.org --- V2: * optimize for large ARP caches
functions.c | 251 +++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 188 insertions(+), 63 deletions(-)
diff --git a/functions.c b/functions.c index e4aeb72..697c217 100644 --- a/functions.c +++ b/functions.c @@ -21,7 +21,6 @@
#include <netinet/ether.h> -#include <arpa/inet.h> #include <sys/socket.h> #include <netdb.h> #include <sys/types.h> @@ -35,6 +34,12 @@ #include <sys/time.h> #include <netinet/in.h> #include <stdint.h> +#include <linux/netlink.h> +#include <net/ethernet.h> +#include <linux/rtnetlink.h> +#include <linux/neighbour.h> +#include <sys/uio.h> +#include <errno.h>
#include "main.h" #include "functions.h" @@ -476,78 +481,198 @@ static void request_mac_resolve(int ai_family, const void *l3addr) close(sock); }
-static struct ether_addr *resolve_mac_from_cache(int ai_family, - const void *l3addr) +static int resolve_mac_from_cache_open(int ai_family) { - struct ether_addr mac_empty; - struct ether_addr *mac_result = NULL, *mac_tmp = NULL; - struct sockaddr_in inet4; + int socknl; 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; - uint32_t ipv4_addr; + struct { + struct nlmsghdr hdr; + struct ndmsg msg; + } nlreq; + struct sockaddr_nl addrnl; + static uint32_t nr_call = 0; + uint32_t pid = (++nr_call + getpid()) & 0x3FFFFF;
- if (ai_family != AF_INET) - return NULL; + memset(&addrnl, 0, sizeof(addrnl)); + addrnl.nl_family = AF_NETLINK; + addrnl.nl_pid = pid; + addrnl.nl_groups = 0;
- memcpy(&ipv4_addr, l3addr, sizeof(ipv4_addr)); + memset(&nlreq, 0, sizeof(nlreq)); + nlreq.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(nlreq.msg)); + nlreq.hdr.nlmsg_type = RTM_GETNEIGH; + nlreq.hdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; + nlreq.msg.ndm_family = ai_family; + + socknl = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); + if (socknl < 0) + goto out; + + ret = bind(socknl, (struct sockaddr*)&addrnl, sizeof(addrnl)); + if (ret < 0) + goto outclose; + + ret = send(socknl, &nlreq, nlreq.hdr.nlmsg_len, 0); + if (ret < 0) + goto outclose; +out: + return socknl; +outclose: + close(socknl); + return ret; +} + +static ssize_t resolve_mac_from_cache_dump(int sock, void **buf, size_t *buflen) +{ + struct iovec iov; + struct msghdr msg; + ssize_t ret = -1; + int flags = MSG_PEEK | MSG_TRUNC; + + memset(&msg, 0, sizeof(msg)); + memset(&iov, 0, sizeof(iov)); + + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_controllen = 0; + msg.msg_control = NULL; + msg.msg_flags = 0; + + iov.iov_len = *buflen; + iov.iov_base = *buf; + + ret = recvmsg(sock, &msg, flags); + if (ret < 0) + goto err; + + if (msg.msg_flags & MSG_TRUNC) { + if ((size_t)ret <= *buflen) { + ret = -ENOBUFS; + goto err; + } + + while (*buflen <= (size_t)ret) { + if (*buflen == 0) + *buflen = 1; + *buflen *= 2; + } + + *buf = realloc(*buf, *buflen); + if (!*buf) { + ret = -ENOMEM; + *buflen = 0; + goto err; + } + } + flags = 0; + + ret = recvmsg(sock, &msg, flags); + if (ret < 0) + goto err; + + return ret; +err: + free(*buf); + *buf = NULL; + return ret; +} + +static int resolve_mac_from_cache_parse(struct ndmsg *ndmsg, size_t len_payload, + struct ether_addr *mac_addr, + uint8_t *l3addr, + size_t l3_len) +{ + int l3found, llfound; + struct rtattr *rtattr; + struct ether_addr mac_empty; + + l3found = 0; + llfound = 0; 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; + for (rtattr = RTM_RTA(ndmsg); RTA_OK(rtattr, len_payload); + rtattr = RTA_NEXT(rtattr, len_payload)) { + switch (rtattr->rta_type) { + case NDA_DST: + memcpy(l3addr, RTA_DATA(rtattr), l3_len); + l3found = 1; + break; + case NDA_LLADDR: + memcpy(mac_addr, RTA_DATA(rtattr), ETH_ALEN); + if (memcmp(mac_addr, &mac_empty, + sizeof(mac_empty)) == 0) + llfound = 0; + else + llfound = 1; break; } }
- free(line); - fclose(f); + return l3found && llfound; +} + +static struct ether_addr *resolve_mac_from_cache(int ai_family, + const void *l3addr) +{ + static uint8_t l3addr_tmp[16]; + struct ether_addr mac_tmp; + struct ether_addr *mac_result = NULL; + void *buf = NULL; + size_t buflen; + struct nlmsghdr *nh; + ssize_t len; + size_t l3_len; + int socknl; + int parsed; + int finished = 0; + + switch (ai_family) { + case AF_INET: + l3_len = 4; + break; + default: + l3_len = 0; + } + + buflen = 8192; + buf = malloc(buflen); + if (!buf) + goto err; + + socknl = resolve_mac_from_cache_open(ai_family); + if (socknl < 0) + goto err; + + + while (!finished) { + len = resolve_mac_from_cache_dump(socknl, &buf, &buflen); + if (len < 0) + goto err_sock; + + for (nh = buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { + if (nh->nlmsg_type == NLMSG_DONE) { + finished = 1; + break; + } + + parsed = resolve_mac_from_cache_parse(NLMSG_DATA(nh), + RTM_PAYLOAD(nh), + &mac_tmp, + l3addr_tmp, + l3_len); + if (parsed) { + if (memcmp(&l3addr_tmp, l3addr, l3_len) == 0) { + mac_result = &mac_tmp; + break; + } + } + } + } + +err_sock: + close(socknl); +err: + free(buf); return mac_result; }
On Sunday 22 September 2013 19:09:31 Sven Eckelmann wrote:
The /proc/net/arp based solution to resolve mac addresses from IP adresses is limited to IPv4 addresses. The table for IPv6 addresses to MAC addresses is only available through rtnetlink. rtnetlink also provides the IPv4 neighbor table and should therefore should be prefered over the /proc/net/arp solution to build an infrastructure for further work on the resolver.
Signed-off-by: Sven Eckelmann sven@narfation.org
V2:
- optimize for large ARP caches
functions.c | 251 +++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 188 insertions(+), 63 deletions(-)
Applied in revision 4885dc1.
Thanks, Marek
Signed-off-by: Sven Eckelmann sven@narfation.org --- functions.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
diff --git a/functions.c b/functions.c index e56479d..45c2120 100644 --- a/functions.c +++ b/functions.c @@ -426,6 +426,7 @@ static int resolve_l3addr(int ai_family, const char *asc, void *l3addr) struct addrinfo hints; struct addrinfo *res; struct sockaddr_in *inet4; + struct sockaddr_in6 *inet6;
memset(&hints, 0, sizeof(hints)); hints.ai_family = ai_family; @@ -440,6 +441,11 @@ static int resolve_l3addr(int ai_family, const char *asc, void *l3addr) memcpy(l3addr, &inet4->sin_addr.s_addr, sizeof(inet4->sin_addr.s_addr)); break; + case AF_INET6: + inet6 = (struct sockaddr_in6 *)res->ai_addr; + memcpy(l3addr, &inet6->sin6_addr.s6_addr, + sizeof(inet6->sin6_addr.s6_addr)); + break; default: ret = -EINVAL; } @@ -453,6 +459,7 @@ static void request_mac_resolve(int ai_family, const void *l3addr) { const struct sockaddr *sockaddr; struct sockaddr_in inet4; + struct sockaddr_in6 inet6; size_t sockaddr_len; int sock; char t = 0; @@ -471,6 +478,15 @@ static void request_mac_resolve(int ai_family, const void *l3addr) sockaddr = (const struct sockaddr *)&inet4; sockaddr_len = sizeof(inet4); break; + case AF_INET6: + memset(&inet6, 0, sizeof(inet6)); + inet6.sin6_family = ai_family; + inet6.sin6_port = htons(9); + memcpy(&inet6.sin6_addr.s6_addr, l3addr, + sizeof(inet6.sin6_addr.s6_addr)); + sockaddr = (const struct sockaddr *)&inet6; + sockaddr_len = sizeof(inet6); + break; default: close(sock); return; @@ -597,6 +613,9 @@ static struct ether_addr *resolve_mac_from_cache(int ai_family, case AF_INET: l3_len = 4; break; + case AF_INET6: + l3_len = 16; + break; default: l3_len = 0; } @@ -649,6 +668,7 @@ out: static struct ether_addr *resolve_mac_from_addr(int ai_family, const char *asc) { uint8_t ipv4_addr[4]; + uint8_t ipv6_addr[16]; void *l3addr; int ret; int retries = 5; @@ -658,6 +678,9 @@ static struct ether_addr *resolve_mac_from_addr(int ai_family, const char *asc) case AF_INET: l3addr = ipv4_addr; break; + case AF_INET6: + l3addr = ipv6_addr; + break; default: return NULL; } @@ -680,7 +703,7 @@ static struct ether_addr *resolve_mac_from_addr(int ai_family, const char *asc) struct ether_addr *resolve_mac(const char *asc) { struct ether_addr *mac_result = NULL; - static const int ai_families[] = {AF_INET}; + static const int ai_families[] = {AF_INET, AF_INET6}; size_t i;
mac_result = ether_aton(asc);
On Sunday 22 September 2013 16:43:03 Sven Eckelmann wrote:
Signed-off-by: Sven Eckelmann sven@narfation.org
functions.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-)
Applied in revision c760fb3.
Thanks, Marek
On Sun, Sep 22, 2013 at 04:43:03PM +0200, Sven Eckelmann wrote:
Signed-off-by: Sven Eckelmann sven@narfation.org
Patch has been applied, but... I have the feeling somebody forgot to add some documentation: text in usage(), README, man? :)
Cheers,
On Tuesday 24 September 2013 17:20:24 Antonio Quartulli wrote:
On Sun, Sep 22, 2013 at 04:43:03PM +0200, Sven Eckelmann wrote:
Signed-off-by: Sven Eckelmann sven@narfation.org
Patch has been applied, but... I have the feeling somebody forgot to add some documentation: text in usage(), README, man? :)
You are completely right. But I doubt that I will have a lot of time before the weekend.
Kind regards, Sven
On Sun, Sep 22, 2013 at 04:42:23PM +0200, Sven Eckelmann wrote:
Signed-off-by: Sven Eckelmann sven@narfation.org
bat-hosts.c | 5 +++-- bat-hosts.h | 2 +- bisect_iv.c | 7 ++++--- debug.c | 5 ----- debug.h | 3 +++ debugfs.c | 10 ++++------ debugfs.h | 3 --- functions.c | 2 ++ functions.h | 3 ++- ioctl.c | 3 +-- list-batman.h | 3 --- main.c | 3 --- ping.c | 5 +++++ sys.c | 1 - sys.h | 2 ++ tcpdump.c | 6 +++++- tcpdump.h | 5 ++++- traceroute.c | 4 ++++ translate.c | 1 - 19 files changed, 40 insertions(+), 33 deletions(-)
diff --git a/bat-hosts.c b/bat-hosts.c index ee862da..9d36531 100644 --- a/bat-hosts.c +++ b/bat-hosts.c @@ -21,14 +21,15 @@
-#include <stdio.h> #include <stdint.h> +#include <stdio.h>
why is it important to move stdio.h below stdint.h ? Is there a particular reason for that?
Cheers,
On Monday 23 September 2013 09:03:42 Antonio Quartulli wrote:
-#include <stdio.h>
#include <stdint.h>
+#include <stdio.h>
why is it important to move stdio.h below stdint.h ? Is there a particular reason for that?
No, just an artifact of the work on the includes. But now it is an alphabetical order (at least these two items)... so it is extremely important :D
Kind regards, Sven
On Mon, Sep 23, 2013 at 10:18:27AM +0200, Sven Eckelmann wrote:
On Monday 23 September 2013 09:03:42 Antonio Quartulli wrote:
-#include <stdio.h>
#include <stdint.h>
+#include <stdio.h>
why is it important to move stdio.h below stdint.h ? Is there a particular reason for that?
No, just an artifact of the work on the includes. But now it is an alphabetical order (at least these two items)... so it is extremely important :D
lol, ok!
On Sunday 22 September 2013 16:42:23 Sven Eckelmann wrote:
Signed-off-by: Sven Eckelmann sven@narfation.org
bat-hosts.c | 5 +++-- bat-hosts.h | 2 +- bisect_iv.c | 7 ++++--- debug.c | 5 ----- debug.h | 3 +++ debugfs.c | 10 ++++------ debugfs.h | 3 --- functions.c | 2 ++ functions.h | 3 ++- ioctl.c | 3 +-- list-batman.h | 3 --- main.c | 3 --- ping.c | 5 +++++ sys.c | 1 - sys.h | 2 ++ tcpdump.c | 6 +++++- tcpdump.h | 5 ++++- traceroute.c | 4 ++++ translate.c | 1 - 19 files changed, 40 insertions(+), 33 deletions(-)
Applied in revision 62eaa83.
Thanks, Marek
b.a.t.m.a.n@lists.open-mesh.org