summaryrefslogtreecommitdiffstats
path: root/pimd/mtracebis_routeget.c
diff options
context:
space:
mode:
Diffstat (limited to 'pimd/mtracebis_routeget.c')
-rw-r--r--pimd/mtracebis_routeget.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/pimd/mtracebis_routeget.c b/pimd/mtracebis_routeget.c
new file mode 100644
index 0000000..20618fa
--- /dev/null
+++ b/pimd/mtracebis_routeget.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Multicast Traceroute for FRRouting
+ * Copyright (C) 2018 Mladen Sablic
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef __linux__
+
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <arpa/inet.h>
+#include <string.h>
+
+#include "mtracebis_netlink.h"
+#include "mtracebis_routeget.h"
+
+static int find_dst(struct nlmsghdr *n, struct in_addr *src, struct in_addr *gw)
+{
+ struct rtmsg *r = NLMSG_DATA(n);
+ int len = n->nlmsg_len;
+ struct rtattr *tb[RTA_MAX + 1];
+
+ len -= NLMSG_LENGTH(sizeof(*r));
+ if (len < 0) {
+ fprintf(stderr, "BUG: wrong nlmsg len %d\n", len);
+ return -1;
+ }
+
+ parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
+ if (tb[RTA_PREFSRC])
+ src->s_addr = *(uint32_t *)RTA_DATA(tb[RTA_PREFSRC]);
+ if (tb[RTA_GATEWAY])
+ gw->s_addr = *(uint32_t *)RTA_DATA(tb[RTA_GATEWAY]);
+ if (tb[RTA_OIF])
+ return *(int *)RTA_DATA(tb[RTA_OIF]);
+ return 0;
+}
+
+int routeget(struct in_addr dst, struct in_addr *src, struct in_addr *gw)
+{
+ struct {
+ struct nlmsghdr n;
+ struct rtmsg r;
+ char buf[1024];
+ } req;
+ int ret;
+ struct rtnl_handle rth = {.fd = -1};
+
+ memset(&req, 0, sizeof(req));
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = RTM_GETROUTE;
+ req.r.rtm_family = AF_INET;
+ req.r.rtm_table = 0;
+ req.r.rtm_protocol = 0;
+ req.r.rtm_scope = 0;
+ req.r.rtm_type = 0;
+ req.r.rtm_src_len = 0;
+ req.r.rtm_dst_len = 0;
+ req.r.rtm_tos = 0;
+
+ addattr_l(&req.n, sizeof(req), RTA_DST, &dst.s_addr, 4);
+ req.r.rtm_dst_len = 32;
+
+ ret = rtnl_open(&rth, 0);
+
+ if (ret < 0 || rth.fd <= 0)
+ return ret;
+
+ if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
+ ret = -1;
+ goto close_rth;
+ }
+
+ ret = find_dst(&req.n, src, gw);
+close_rth:
+ rtnl_close(&rth);
+ return ret;
+}
+
+#endif /* __linux__ */