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