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