xref: /spdk/lib/util/net.c (revision b6875e1ce57743f3b1416016b9c624d79a862af9)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2021 Intel Corporation. All rights reserved.
3  *   Copyright (C) 2024 Samsung Electronics Co., Ltd.
4  *   All rights reserved.
5  */
6 
7 #include "spdk/stdinc.h"
8 #include "spdk/net.h"
9 #include "spdk/log.h"
10 
11 int
12 spdk_net_get_interface_name(const char *ip, char *ifc, size_t len)
13 {
14 	struct ifaddrs *addrs, *iap;
15 	struct sockaddr_in *sa;
16 	char buf[32];
17 	int rc = -ENODEV;
18 
19 	getifaddrs(&addrs);
20 	for (iap = addrs; iap != NULL; iap = iap->ifa_next) {
21 		if (!(iap->ifa_addr && (iap->ifa_flags & IFF_UP) && iap->ifa_addr->sa_family == AF_INET)) {
22 			continue;
23 		}
24 		sa = (struct sockaddr_in *)(iap->ifa_addr);
25 		inet_ntop(iap->ifa_addr->sa_family, &sa->sin_addr, buf, sizeof(buf));
26 		if (strcmp(ip, buf) != 0) {
27 			continue;
28 		}
29 		if (strnlen(iap->ifa_name, len) == len) {
30 			rc = -ENOMEM;
31 			goto ret;
32 		}
33 		snprintf(ifc, len, "%s", iap->ifa_name);
34 		rc = 0;
35 		break;
36 	}
37 ret:
38 	freeifaddrs(addrs);
39 	return rc;
40 }
41 
42 int
43 spdk_net_get_address_string(struct sockaddr *sa, char *addr, size_t len)
44 {
45 	const char *result = NULL;
46 
47 	if (sa == NULL || addr == NULL) {
48 		return -1;
49 	}
50 
51 	switch (sa->sa_family) {
52 	case AF_INET:
53 		result = inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr),
54 				   addr, len);
55 		break;
56 	case AF_INET6:
57 		result = inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr),
58 				   addr, len);
59 		break;
60 	default:
61 		break;
62 	}
63 
64 	if (result != NULL) {
65 		return 0;
66 	} else {
67 		return -errno;
68 	}
69 }
70 
71 bool
72 spdk_net_is_loopback(int fd)
73 {
74 	struct ifaddrs *addrs, *tmp;
75 	struct sockaddr_storage sa = {};
76 	socklen_t salen;
77 	struct ifreq ifr = {};
78 	char ip_addr[256], ip_addr_tmp[256];
79 	int rc;
80 	bool is_loopback = false;
81 
82 	salen = sizeof(sa);
83 	rc = getsockname(fd, (struct sockaddr *)&sa, &salen);
84 	if (rc != 0) {
85 		return is_loopback;
86 	}
87 
88 	memset(ip_addr, 0, sizeof(ip_addr));
89 	rc = spdk_net_get_address_string((struct sockaddr *)&sa, ip_addr, sizeof(ip_addr));
90 	if (rc != 0) {
91 		return is_loopback;
92 	}
93 
94 	getifaddrs(&addrs);
95 	for (tmp = addrs; tmp != NULL; tmp = tmp->ifa_next) {
96 		if (tmp->ifa_addr && (tmp->ifa_flags & IFF_UP) &&
97 		    (tmp->ifa_addr->sa_family == sa.ss_family)) {
98 			memset(ip_addr_tmp, 0, sizeof(ip_addr_tmp));
99 			rc = spdk_net_get_address_string(tmp->ifa_addr, ip_addr_tmp, sizeof(ip_addr_tmp));
100 			if (rc != 0) {
101 				continue;
102 			}
103 
104 			if (strncmp(ip_addr, ip_addr_tmp, sizeof(ip_addr)) == 0) {
105 				memcpy(ifr.ifr_name, tmp->ifa_name, sizeof(ifr.ifr_name));
106 				ioctl(fd, SIOCGIFFLAGS, &ifr);
107 				if (ifr.ifr_flags & IFF_LOOPBACK) {
108 					is_loopback = true;
109 				}
110 				goto end;
111 			}
112 		}
113 	}
114 
115 end:
116 	freeifaddrs(addrs);
117 	return is_loopback;
118 }
119 
120 int
121 spdk_net_getaddr(int fd, char *laddr, int llen, uint16_t *lport,
122 		 char *paddr, int plen, uint16_t *pport)
123 {
124 	struct sockaddr_storage sa;
125 	int val;
126 	socklen_t len;
127 	int rc;
128 
129 	memset(&sa, 0, sizeof(sa));
130 	len = sizeof(sa);
131 	rc = getsockname(fd, (struct sockaddr *)&sa, &len);
132 	if (rc != 0) {
133 		SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
134 		return -1;
135 	}
136 
137 	switch (sa.ss_family) {
138 	case AF_UNIX:
139 		/* Acceptable connection types that don't have IPs */
140 		return 0;
141 	case AF_INET:
142 	case AF_INET6:
143 		/* Code below will get IP addresses */
144 		break;
145 	default:
146 		/* Unsupported socket family */
147 		return -1;
148 	}
149 
150 	if (laddr) {
151 		rc = spdk_net_get_address_string((struct sockaddr *)&sa, laddr, llen);
152 		if (rc != 0) {
153 			SPDK_ERRLOG("spdk_net_get_address_string() failed (errno=%d)\n", rc);
154 			return -1;
155 		}
156 	}
157 
158 	if (lport) {
159 		if (sa.ss_family == AF_INET) {
160 			*lport = ntohs(((struct sockaddr_in *)&sa)->sin_port);
161 		} else if (sa.ss_family == AF_INET6) {
162 			*lport = ntohs(((struct sockaddr_in6 *)&sa)->sin6_port);
163 		}
164 	}
165 
166 	len = sizeof(val);
167 	rc = getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &val, &len);
168 	if (rc == 0 && val == 1) {
169 		/* It is an error to getaddr for a peer address on a listen socket. */
170 		if (paddr != NULL || pport != NULL) {
171 			SPDK_ERRLOG("paddr, pport not valid on listen sockets\n");
172 			return -1;
173 		}
174 		return 0;
175 	}
176 
177 	memset(&sa, 0, sizeof(sa));
178 	len = sizeof(sa);
179 	rc = getpeername(fd, (struct sockaddr *)&sa, &len);
180 	if (rc != 0) {
181 		SPDK_ERRLOG("getpeername() failed (errno=%d)\n", errno);
182 		return -1;
183 	}
184 
185 	if (paddr) {
186 		rc = spdk_net_get_address_string((struct sockaddr *)&sa, paddr, plen);
187 		if (rc != 0) {
188 			SPDK_ERRLOG("spdk_net_get_address_string() failed (errno=%d)\n", rc);
189 			return -1;
190 		}
191 	}
192 
193 	if (pport) {
194 		if (sa.ss_family == AF_INET) {
195 			*pport = ntohs(((struct sockaddr_in *)&sa)->sin_port);
196 		} else if (sa.ss_family == AF_INET6) {
197 			*pport = ntohs(((struct sockaddr_in6 *)&sa)->sin6_port);
198 		}
199 	}
200 
201 	return 0;
202 }
203