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