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