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