1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2017 Petr Vorel <pvorel@suse.cz>
4 */
5
6 #include <sys/socket.h>
7 #include <linux/rtnetlink.h>
8 #include <net/if.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11
12 #define TST_NO_DEFAULT_MAIN
13 #include "tst_test.h"
14
15 #include "tst_net.h"
16
17 static char *iface;
18 static int prefix;
19
usage(const char * cmd)20 static void usage(const char *cmd)
21 {
22 fprintf(stderr, "USAGE:\n"
23 "%s IP_LHOST[/PREFIX]\n"
24 "%s -r IP_RHOST[/PREFIX]\n"
25 "%s -h\n\n"
26 "Set prefix and interface name for given IP.\n"
27 "Prefix and interface are found from kernel exported info (rtnetlink).\n\n"
28 "EXPORTED VARIABLES:\n"
29 "Export one of the following variables:\n"
30 "IPV4_LPREFIX: IPv4 prefix for IPV4_LNETWORK\n"
31 "IPV4_RPREFIX: IPv4 prefix for IPV4_RNETWORK\n"
32 "IPV6_LPREFIX: IPv6 prefix for IPV6_LNETWORK\n"
33 "IPV6_RPREFIX: IPv6 prefix for IPV6_RNETWORK\n"
34 "Export one of the following variables (if found):\n"
35 "LHOST_IFACES: iface name of the local host\n"
36 "RHOST_IFACES: iface name of the remote host\n\n"
37 "PARAMS:\n"
38 "-h this help\n"
39 "-r export remote environment variables\n",
40 cmd, cmd, cmd);
41 }
42
read_iface_prefix(const char * ip_str,int is_ipv6)43 static int read_iface_prefix(const char *ip_str, int is_ipv6)
44 {
45 uint8_t family = is_ipv6 ? AF_INET6 : AF_INET;
46
47 char buf[16384];
48 unsigned int len;
49
50 struct {
51 struct nlmsghdr nlhdr;
52 struct ifaddrmsg addrmsg;
53 } msg;
54
55 struct nlmsghdr *retmsg;
56
57 int sock = SAFE_SOCKET(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
58
59 memset(&msg, 0, sizeof(msg));
60 msg.nlhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg));
61 msg.nlhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ROOT;
62 msg.nlhdr.nlmsg_type = RTM_GETADDR;
63 msg.addrmsg.ifa_family = family;
64
65 SAFE_SEND(1, sock, &msg, msg.nlhdr.nlmsg_len, 0);
66 len = recv(sock, buf, sizeof(buf), 0);
67 retmsg = (struct nlmsghdr *)buf;
68
69 while NLMSG_OK(retmsg, len) {
70 char ifname[IFNAMSIZ];
71 struct ifaddrmsg *retaddr;
72 struct rtattr *retrta;
73 char pradd[128];
74 int attlen;
75
76 retaddr = (struct ifaddrmsg *)NLMSG_DATA(retmsg);
77 retrta = (struct rtattr *)IFA_RTA(retaddr);
78 attlen = IFA_PAYLOAD(retmsg);
79
80 while RTA_OK(retrta, attlen) {
81 if (retrta->rta_type == IFA_ADDRESS) {
82 inet_ntop(family, RTA_DATA(retrta), pradd,
83 sizeof(pradd));
84
85 if_indextoname(retaddr->ifa_index, ifname);
86
87 if (!strcmp(pradd, ip_str)) {
88 prefix = retaddr->ifa_prefixlen;
89 iface = strdup(ifname);
90 return 0;
91 }
92 }
93 retrta = RTA_NEXT(retrta, attlen);
94 }
95 retmsg = NLMSG_NEXT(retmsg, len);
96 }
97
98 return -1;
99 }
100
print_ivar(const char * name,unsigned int val)101 static void print_ivar(const char *name, unsigned int val)
102 {
103 printf("export %s=%d\n", name, val);
104 }
105
main(int argc,char * argv[])106 int main(int argc, char *argv[])
107 {
108 char *ip_str = NULL, *prefix_str = NULL;
109 int is_ipv6, is_rhost = 0;
110 struct in_addr ip;
111 struct in6_addr ip6;
112
113 int is_usage = argc > 1 && (!strcmp(argv[1], "-h") ||
114 !strcmp(argv[1], "--help"));
115 if (argc < 2 || is_usage) {
116 usage(argv[0]);
117 exit(is_usage ? EXIT_SUCCESS : EXIT_FAILURE);
118 }
119 if (!strcmp(argv[1], "-r"))
120 is_rhost = 1;
121
122 ip_str = argv[is_rhost ? 2 : 1];
123 is_ipv6 = !!strchr(ip_str, ':');
124
125 prefix_str = strchr(ip_str, '/');
126 if (prefix_str) {
127 prefix = get_prefix(ip_str, is_ipv6);
128 tst_res_comment(TINFO,
129 "IP address '%s' contains prefix %d, using it and don't search for iface.\n",
130 ip_str, prefix);
131 } else if (read_iface_prefix(ip_str, is_ipv6)) {
132 tst_res_comment(TINFO,
133 "prefix and interface not found for '%s'.\n", ip_str);
134 exit(EXIT_SUCCESS);
135 }
136
137 /* checks for validity of IP string */
138 if (is_ipv6)
139 get_in6_addr(ip_str, &ip6);
140 else
141 get_in_addr(ip_str, &ip);
142
143 print_svar_change(is_rhost ? "RHOST_IFACES" : "LHOST_IFACES", iface);
144 if (is_ipv6)
145 print_ivar(is_rhost ? "IPV6_RPREFIX" : "IPV6_LPREFIX", prefix);
146 else
147 print_ivar(is_rhost ? "IPV4_RPREFIX" : "IPV4_LPREFIX", prefix);
148
149 exit(EXIT_SUCCESS);
150 }
151