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