xref: /spdk/lib/util/net.c (revision 193002f9bc7058c8171e0e1114a4745d4305811e)
1e8671c89SJim Harris /*   SPDX-License-Identifier: BSD-3-Clause
2e8671c89SJim Harris  *   Copyright (C) 2021 Intel Corporation. All rights reserved.
3e8671c89SJim Harris  *   Copyright (C) 2024 Samsung Electronics Co., Ltd.
4e8671c89SJim Harris  *   All rights reserved.
5e8671c89SJim Harris  */
6e8671c89SJim Harris 
7e8671c89SJim Harris #include "spdk/stdinc.h"
8e8671c89SJim Harris #include "spdk/net.h"
97923828fSJim Harris #include "spdk/log.h"
10e8671c89SJim Harris 
11e8671c89SJim Harris int
12e8671c89SJim Harris spdk_net_get_interface_name(const char *ip, char *ifc, size_t len)
13e8671c89SJim Harris {
14e8671c89SJim Harris 	struct ifaddrs *addrs, *iap;
15e8671c89SJim Harris 	struct sockaddr_in *sa;
16e8671c89SJim Harris 	char buf[32];
17e8671c89SJim Harris 	int rc = -ENODEV;
18e8671c89SJim Harris 
19e8671c89SJim Harris 	getifaddrs(&addrs);
20e8671c89SJim Harris 	for (iap = addrs; iap != NULL; iap = iap->ifa_next) {
21e8671c89SJim Harris 		if (!(iap->ifa_addr && (iap->ifa_flags & IFF_UP) && iap->ifa_addr->sa_family == AF_INET)) {
22e8671c89SJim Harris 			continue;
23e8671c89SJim Harris 		}
24e8671c89SJim Harris 		sa = (struct sockaddr_in *)(iap->ifa_addr);
25e8671c89SJim Harris 		inet_ntop(iap->ifa_addr->sa_family, &sa->sin_addr, buf, sizeof(buf));
26e8671c89SJim Harris 		if (strcmp(ip, buf) != 0) {
27e8671c89SJim Harris 			continue;
28e8671c89SJim Harris 		}
29e8671c89SJim Harris 		if (strnlen(iap->ifa_name, len) == len) {
30e8671c89SJim Harris 			rc = -ENOMEM;
31e8671c89SJim Harris 			goto ret;
32e8671c89SJim Harris 		}
33e8671c89SJim Harris 		snprintf(ifc, len, "%s", iap->ifa_name);
34e8671c89SJim Harris 		rc = 0;
35e8671c89SJim Harris 		break;
36e8671c89SJim Harris 	}
37e8671c89SJim Harris ret:
38e8671c89SJim Harris 	freeifaddrs(addrs);
39e8671c89SJim Harris 	return rc;
40e8671c89SJim Harris }
419645ea13SJim Harris 
429645ea13SJim Harris int
439645ea13SJim Harris spdk_net_get_address_string(struct sockaddr *sa, char *addr, size_t len)
449645ea13SJim Harris {
459645ea13SJim Harris 	const char *result = NULL;
469645ea13SJim Harris 
479645ea13SJim Harris 	if (sa == NULL || addr == NULL) {
489645ea13SJim Harris 		return -1;
499645ea13SJim Harris 	}
509645ea13SJim Harris 
519645ea13SJim Harris 	switch (sa->sa_family) {
529645ea13SJim Harris 	case AF_INET:
539645ea13SJim Harris 		result = inet_ntop(AF_INET, &(((struct sockaddr_in *)sa)->sin_addr),
549645ea13SJim Harris 				   addr, len);
559645ea13SJim Harris 		break;
569645ea13SJim Harris 	case AF_INET6:
579645ea13SJim Harris 		result = inet_ntop(AF_INET6, &(((struct sockaddr_in6 *)sa)->sin6_addr),
589645ea13SJim Harris 				   addr, len);
599645ea13SJim Harris 		break;
609645ea13SJim Harris 	default:
619645ea13SJim Harris 		break;
629645ea13SJim Harris 	}
639645ea13SJim Harris 
649645ea13SJim Harris 	if (result != NULL) {
659645ea13SJim Harris 		return 0;
669645ea13SJim Harris 	} else {
679645ea13SJim Harris 		return -errno;
689645ea13SJim Harris 	}
699645ea13SJim Harris }
709645ea13SJim Harris 
719645ea13SJim Harris bool
729645ea13SJim Harris spdk_net_is_loopback(int fd)
739645ea13SJim Harris {
749645ea13SJim Harris 	struct ifaddrs *addrs, *tmp;
759645ea13SJim Harris 	struct sockaddr_storage sa = {};
769645ea13SJim Harris 	socklen_t salen;
779645ea13SJim Harris 	struct ifreq ifr = {};
789645ea13SJim Harris 	char ip_addr[256], ip_addr_tmp[256];
799645ea13SJim Harris 	int rc;
809645ea13SJim Harris 	bool is_loopback = false;
819645ea13SJim Harris 
829645ea13SJim Harris 	salen = sizeof(sa);
839645ea13SJim Harris 	rc = getsockname(fd, (struct sockaddr *)&sa, &salen);
849645ea13SJim Harris 	if (rc != 0) {
859645ea13SJim Harris 		return is_loopback;
869645ea13SJim Harris 	}
879645ea13SJim Harris 
889645ea13SJim Harris 	memset(ip_addr, 0, sizeof(ip_addr));
899645ea13SJim Harris 	rc = spdk_net_get_address_string((struct sockaddr *)&sa, ip_addr, sizeof(ip_addr));
909645ea13SJim Harris 	if (rc != 0) {
919645ea13SJim Harris 		return is_loopback;
929645ea13SJim Harris 	}
939645ea13SJim Harris 
949645ea13SJim Harris 	getifaddrs(&addrs);
959645ea13SJim Harris 	for (tmp = addrs; tmp != NULL; tmp = tmp->ifa_next) {
969645ea13SJim Harris 		if (tmp->ifa_addr && (tmp->ifa_flags & IFF_UP) &&
979645ea13SJim Harris 		    (tmp->ifa_addr->sa_family == sa.ss_family)) {
989645ea13SJim Harris 			memset(ip_addr_tmp, 0, sizeof(ip_addr_tmp));
999645ea13SJim Harris 			rc = spdk_net_get_address_string(tmp->ifa_addr, ip_addr_tmp, sizeof(ip_addr_tmp));
1009645ea13SJim Harris 			if (rc != 0) {
1019645ea13SJim Harris 				continue;
1029645ea13SJim Harris 			}
1039645ea13SJim Harris 
1049645ea13SJim Harris 			if (strncmp(ip_addr, ip_addr_tmp, sizeof(ip_addr)) == 0) {
1059645ea13SJim Harris 				memcpy(ifr.ifr_name, tmp->ifa_name, sizeof(ifr.ifr_name));
1069645ea13SJim Harris 				ioctl(fd, SIOCGIFFLAGS, &ifr);
1079645ea13SJim Harris 				if (ifr.ifr_flags & IFF_LOOPBACK) {
1089645ea13SJim Harris 					is_loopback = true;
1099645ea13SJim Harris 				}
1109645ea13SJim Harris 				goto end;
1119645ea13SJim Harris 			}
1129645ea13SJim Harris 		}
1139645ea13SJim Harris 	}
1149645ea13SJim Harris 
1159645ea13SJim Harris end:
1169645ea13SJim Harris 	freeifaddrs(addrs);
1179645ea13SJim Harris 	return is_loopback;
1189645ea13SJim Harris }
1197923828fSJim Harris 
1207923828fSJim Harris int
1211fcd7d99SJim Harris spdk_net_getaddr(int fd, char *laddr, int llen, uint16_t *lport,
1221fcd7d99SJim Harris 		 char *paddr, int plen, uint16_t *pport)
1237923828fSJim Harris {
1247923828fSJim Harris 	struct sockaddr_storage sa;
1259abdcd99SJim Harris 	int val;
1269abdcd99SJim Harris 	socklen_t len;
1277923828fSJim Harris 	int rc;
1287923828fSJim Harris 
1291fcd7d99SJim Harris 	memset(&sa, 0, sizeof(sa));
1309abdcd99SJim Harris 	len = sizeof(sa);
1319abdcd99SJim Harris 	rc = getsockname(fd, (struct sockaddr *)&sa, &len);
1327923828fSJim Harris 	if (rc != 0) {
1337923828fSJim Harris 		SPDK_ERRLOG("getsockname() failed (errno=%d)\n", errno);
1347923828fSJim Harris 		return -1;
1357923828fSJim Harris 	}
1367923828fSJim Harris 
1377923828fSJim Harris 	switch (sa.ss_family) {
1387923828fSJim Harris 	case AF_UNIX:
1397923828fSJim Harris 		/* Acceptable connection types that don't have IPs */
1407923828fSJim Harris 		return 0;
1417923828fSJim Harris 	case AF_INET:
1427923828fSJim Harris 	case AF_INET6:
1437923828fSJim Harris 		/* Code below will get IP addresses */
1447923828fSJim Harris 		break;
1457923828fSJim Harris 	default:
1467923828fSJim Harris 		/* Unsupported socket family */
1477923828fSJim Harris 		return -1;
1487923828fSJim Harris 	}
1497923828fSJim Harris 
150*193002f9SJim Harris 	if (laddr) {
1511fcd7d99SJim Harris 		rc = spdk_net_get_address_string((struct sockaddr *)&sa, laddr, llen);
1527923828fSJim Harris 		if (rc != 0) {
1531fcd7d99SJim Harris 			SPDK_ERRLOG("spdk_net_get_address_string() failed (errno=%d)\n", rc);
1547923828fSJim Harris 			return -1;
1557923828fSJim Harris 		}
156*193002f9SJim Harris 	}
1577923828fSJim Harris 
1581fcd7d99SJim Harris 	if (lport) {
1597923828fSJim Harris 		if (sa.ss_family == AF_INET) {
1601fcd7d99SJim Harris 			*lport = ntohs(((struct sockaddr_in *)&sa)->sin_port);
1617923828fSJim Harris 		} else if (sa.ss_family == AF_INET6) {
1621fcd7d99SJim Harris 			*lport = ntohs(((struct sockaddr_in6 *)&sa)->sin6_port);
1637923828fSJim Harris 		}
1647923828fSJim Harris 	}
1657923828fSJim Harris 
1669abdcd99SJim Harris 	len = sizeof(val);
1679abdcd99SJim Harris 	rc = getsockopt(fd, SOL_SOCKET, SO_ACCEPTCONN, &val, &len);
1689abdcd99SJim Harris 	if (rc == 0 && val == 1) {
1699abdcd99SJim Harris 		/* It is an error to getaddr for a peer address on a listen socket. */
1709abdcd99SJim Harris 		if (paddr != NULL || pport != NULL) {
1719abdcd99SJim Harris 			SPDK_ERRLOG("paddr, pport not valid on listen sockets\n");
1729abdcd99SJim Harris 			return -1;
1739abdcd99SJim Harris 		}
1749abdcd99SJim Harris 		return 0;
1759abdcd99SJim Harris 	}
1769abdcd99SJim Harris 
1771fcd7d99SJim Harris 	memset(&sa, 0, sizeof(sa));
1789abdcd99SJim Harris 	len = sizeof(sa);
1799abdcd99SJim Harris 	rc = getpeername(fd, (struct sockaddr *)&sa, &len);
1807923828fSJim Harris 	if (rc != 0) {
1817923828fSJim Harris 		SPDK_ERRLOG("getpeername() failed (errno=%d)\n", errno);
1827923828fSJim Harris 		return -1;
1837923828fSJim Harris 	}
1847923828fSJim Harris 
185*193002f9SJim Harris 	if (paddr) {
1861fcd7d99SJim Harris 		rc = spdk_net_get_address_string((struct sockaddr *)&sa, paddr, plen);
1877923828fSJim Harris 		if (rc != 0) {
1881fcd7d99SJim Harris 			SPDK_ERRLOG("spdk_net_get_address_string() failed (errno=%d)\n", rc);
1897923828fSJim Harris 			return -1;
1907923828fSJim Harris 		}
191*193002f9SJim Harris 	}
1927923828fSJim Harris 
1931fcd7d99SJim Harris 	if (pport) {
1947923828fSJim Harris 		if (sa.ss_family == AF_INET) {
1951fcd7d99SJim Harris 			*pport = ntohs(((struct sockaddr_in *)&sa)->sin_port);
1967923828fSJim Harris 		} else if (sa.ss_family == AF_INET6) {
1971fcd7d99SJim Harris 			*pport = ntohs(((struct sockaddr_in6 *)&sa)->sin6_port);
1987923828fSJim Harris 		}
1997923828fSJim Harris 	}
2007923828fSJim Harris 
2017923828fSJim Harris 	return 0;
2027923828fSJim Harris }
203