/* * Copyright (c) 2017 Petr Vorel <pvorel@suse.cz> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 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, see <http://www.gnu.org/licenses/>. */ #include <sys/socket.h> #include <linux/rtnetlink.h> #include <net/if.h> #include <stdio.h> #include <stdlib.h> #define TST_NO_DEFAULT_MAIN #include "tst_test.h" #include "tst_net.h" static char *iface; static int prefix; static void usage(const char *cmd) { fprintf(stderr, "USAGE:\n" "%s IP_LHOST[/PREFIX]\n" "%s -r IP_RHOST[/PREFIX]\n" "%s -h\n\n" "Set prefix and interface name for given IP.\n" "Prefix and interface are found from kernel exported info (rtnetlink).\n\n" "EXPORTED VARIABLES:\n" "Export one of the following variables:\n" "IPV4_LPREFIX: IPv4 prefix for IPV4_LNETWORK\n" "IPV4_RPREFIX: IPv4 prefix for IPV4_RNETWORK\n" "IPV6_LPREFIX: IPv6 prefix for IPV6_LNETWORK\n" "IPV6_RPREFIX: IPv6 prefix for IPV6_RNETWORK\n" "Export one of the following variables (if found):\n" "LHOST_IFACES: iface name of the local host\n" "RHOST_IFACES: iface name of the remote host\n\n" "PARAMS:\n" "-h this help\n" "-r export remote environment variables\n", cmd, cmd, cmd); } static int read_iface_prefix(const char *ip_str, int is_ipv6) { uint8_t family = is_ipv6 ? AF_INET6 : AF_INET; char buf[16384]; unsigned int len; struct { struct nlmsghdr nlhdr; struct ifaddrmsg addrmsg; } msg; struct nlmsghdr *retmsg; int sock = SAFE_SOCKET(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); memset(&msg, 0, sizeof(msg)); msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT; msg.nlhdr.nlmsg_type = RTM_GETADDR; msg.addrmsg.ifa_family = family; SAFE_SEND(1, sock, &msg, msg.nlhdr.nlmsg_len, 0); len = recv(sock, buf, sizeof(buf), 0); retmsg = (struct nlmsghdr *)buf; while NLMSG_OK(retmsg, len) { char ifname[IFNAMSIZ]; struct ifaddrmsg *retaddr; struct rtattr *retrta; char pradd[128]; int attlen; retaddr = (struct ifaddrmsg *)NLMSG_DATA(retmsg); retrta = (struct rtattr *)IFA_RTA(retaddr); attlen = IFA_PAYLOAD(retmsg); while RTA_OK(retrta, attlen) { if (retrta->rta_type == IFA_ADDRESS) { inet_ntop(family, RTA_DATA(retrta), pradd, sizeof(pradd)); if_indextoname(retaddr->ifa_index, ifname); if (!strcmp(pradd, ip_str)) { prefix = retaddr->ifa_prefixlen; iface = strdup(ifname); return 0; } } retrta = RTA_NEXT(retrta, attlen); } retmsg = NLMSG_NEXT(retmsg, len); } return -1; } static void print_ivar(const char *name, unsigned int val) { printf("export %s=%d\n", name, val); } int main(int argc, char *argv[]) { char *ip_str = NULL, *prefix_str = NULL; int is_ipv6, is_rhost = 0; struct in_addr ip; struct in6_addr ip6; int is_usage = argc > 1 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")); if (argc < 2 || is_usage) { usage(argv[0]); exit(is_usage ? EXIT_SUCCESS : EXIT_FAILURE); } if (!strcmp(argv[1], "-r")) is_rhost = 1; ip_str = argv[is_rhost ? 2 : 1]; is_ipv6 = !!strchr(ip_str, ':'); prefix_str = strchr(ip_str, '/'); if (prefix_str) { prefix = get_prefix(ip_str, is_ipv6); tst_res_comment(TINFO, "IP address '%s' contains prefix %d, using it and don't search for iface.\n", ip_str, prefix); } else if (read_iface_prefix(ip_str, is_ipv6)) { tst_res_comment(TINFO, "prefix and interface not found for '%s'.\n", ip_str); exit(EXIT_SUCCESS); } /* checks for validity of IP string */ if (is_ipv6) get_in6_addr(ip_str, &ip6); else get_in_addr(ip_str, &ip); print_svar_change(is_rhost ? "RHOST_IFACES" : "LHOST_IFACES", iface); if (is_ipv6) print_ivar(is_rhost ? "IPV6_RPREFIX" : "IPV6_LPREFIX", prefix); else print_ivar(is_rhost ? "IPV4_RPREFIX" : "IPV4_LPREFIX", prefix); exit(EXIT_SUCCESS); }