Translated using Weblate (Chinese (Simplified))
[oweals/minetest.git] / src / network / address.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include "address.h"
21
22 #include <cstdio>
23 #include <iostream>
24 #include <cstdlib>
25 #include <cstring>
26 #include <cerrno>
27 #include <sstream>
28 #include <iomanip>
29 #include "network/networkexceptions.h"
30 #include "util/string.h"
31 #include "util/numeric.h"
32 #include "constants.h"
33 #include "debug.h"
34 #include "settings.h"
35 #include "log.h"
36
37 #ifdef _WIN32
38 // Without this some of the network functions are not found on mingw
39 #ifndef _WIN32_WINNT
40 #define _WIN32_WINNT 0x0501
41 #endif
42 #include <windows.h>
43 #include <winsock2.h>
44 #include <ws2tcpip.h>
45 #define LAST_SOCKET_ERR() WSAGetLastError()
46 typedef SOCKET socket_t;
47 typedef int socklen_t;
48 #else
49 #include <sys/types.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <fcntl.h>
53 #include <netdb.h>
54 #include <unistd.h>
55 #include <arpa/inet.h>
56 #define LAST_SOCKET_ERR() (errno)
57 typedef int socket_t;
58 #endif
59
60 /*
61         Address
62 */
63
64 Address::Address()
65 {
66         memset(&m_address, 0, sizeof(m_address));
67 }
68
69 Address::Address(u32 address, u16 port)
70 {
71         memset(&m_address, 0, sizeof(m_address));
72         setAddress(address);
73         setPort(port);
74 }
75
76 Address::Address(u8 a, u8 b, u8 c, u8 d, u16 port)
77 {
78         memset(&m_address, 0, sizeof(m_address));
79         setAddress(a, b, c, d);
80         setPort(port);
81 }
82
83 Address::Address(const IPv6AddressBytes *ipv6_bytes, u16 port)
84 {
85         memset(&m_address, 0, sizeof(m_address));
86         setAddress(ipv6_bytes);
87         setPort(port);
88 }
89
90 // Equality (address family, address and port must be equal)
91 bool Address::operator==(const Address &address)
92 {
93         if (address.m_addr_family != m_addr_family || address.m_port != m_port)
94                 return false;
95
96         if (m_addr_family == AF_INET) {
97                 return m_address.ipv4.sin_addr.s_addr ==
98                        address.m_address.ipv4.sin_addr.s_addr;
99         }
100
101         if (m_addr_family == AF_INET6) {
102                 return memcmp(m_address.ipv6.sin6_addr.s6_addr,
103                                        address.m_address.ipv6.sin6_addr.s6_addr, 16) == 0;
104         }
105
106         return false;
107 }
108
109 bool Address::operator!=(const Address &address)
110 {
111         return !(*this == address);
112 }
113
114 void Address::Resolve(const char *name)
115 {
116         if (!name || name[0] == 0) {
117                 if (m_addr_family == AF_INET) {
118                         setAddress((u32)0);
119                 } else if (m_addr_family == AF_INET6) {
120                         setAddress((IPv6AddressBytes *)0);
121                 }
122                 return;
123         }
124
125         struct addrinfo *resolved, hints;
126         memset(&hints, 0, sizeof(hints));
127
128         // Setup hints
129         hints.ai_socktype = 0;
130         hints.ai_protocol = 0;
131         hints.ai_flags = 0;
132         if (g_settings->getBool("enable_ipv6")) {
133                 // AF_UNSPEC allows both IPv6 and IPv4 addresses to be returned
134                 hints.ai_family = AF_UNSPEC;
135         } else {
136                 hints.ai_family = AF_INET;
137         }
138
139         // Do getaddrinfo()
140         int e = getaddrinfo(name, NULL, &hints, &resolved);
141         if (e != 0)
142                 throw ResolveError(gai_strerror(e));
143
144         // Copy data
145         if (resolved->ai_family == AF_INET) {
146                 struct sockaddr_in *t = (struct sockaddr_in *)resolved->ai_addr;
147                 m_addr_family = AF_INET;
148                 m_address.ipv4 = *t;
149         } else if (resolved->ai_family == AF_INET6) {
150                 struct sockaddr_in6 *t = (struct sockaddr_in6 *)resolved->ai_addr;
151                 m_addr_family = AF_INET6;
152                 m_address.ipv6 = *t;
153         } else {
154                 freeaddrinfo(resolved);
155                 throw ResolveError("");
156         }
157         freeaddrinfo(resolved);
158 }
159
160 // IP address -> textual representation
161 std::string Address::serializeString() const
162 {
163 // windows XP doesnt have inet_ntop, maybe use better func
164 #ifdef _WIN32
165         if (m_addr_family == AF_INET) {
166                 u8 a, b, c, d;
167                 u32 addr;
168                 addr = ntohl(m_address.ipv4.sin_addr.s_addr);
169                 a = (addr & 0xFF000000) >> 24;
170                 b = (addr & 0x00FF0000) >> 16;
171                 c = (addr & 0x0000FF00) >> 8;
172                 d = (addr & 0x000000FF);
173                 return itos(a) + "." + itos(b) + "." + itos(c) + "." + itos(d);
174         } else if (m_addr_family == AF_INET6) {
175                 std::ostringstream os;
176                 for (int i = 0; i < 16; i += 2) {
177                         u16 section = (m_address.ipv6.sin6_addr.s6_addr[i] << 8) |
178                                       (m_address.ipv6.sin6_addr.s6_addr[i + 1]);
179                         os << std::hex << section;
180                         if (i < 14)
181                                 os << ":";
182                 }
183                 return os.str();
184         } else
185                 return std::string("");
186 #else
187         char str[INET6_ADDRSTRLEN];
188         if (inet_ntop(m_addr_family,
189                             (m_addr_family == AF_INET)
190                                             ? (void *)&(m_address.ipv4.sin_addr)
191                                             : (void *)&(m_address.ipv6.sin6_addr),
192                             str, INET6_ADDRSTRLEN) == NULL) {
193                 return std::string("");
194         }
195         return std::string(str);
196 #endif
197 }
198
199 struct sockaddr_in Address::getAddress() const
200 {
201         return m_address.ipv4; // NOTE: NO PORT INCLUDED, use getPort()
202 }
203
204 struct sockaddr_in6 Address::getAddress6() const
205 {
206         return m_address.ipv6; // NOTE: NO PORT INCLUDED, use getPort()
207 }
208
209 u16 Address::getPort() const
210 {
211         return m_port;
212 }
213
214 int Address::getFamily() const
215 {
216         return m_addr_family;
217 }
218
219 bool Address::isIPv6() const
220 {
221         return m_addr_family == AF_INET6;
222 }
223
224 bool Address::isZero() const
225 {
226         if (m_addr_family == AF_INET) {
227                 return m_address.ipv4.sin_addr.s_addr == 0;
228         }
229
230         if (m_addr_family == AF_INET6) {
231                 static const char zero[16] = {0};
232                 return memcmp(m_address.ipv6.sin6_addr.s6_addr, zero, 16) == 0;
233         }
234         return false;
235 }
236
237 void Address::setAddress(u32 address)
238 {
239         m_addr_family = AF_INET;
240         m_address.ipv4.sin_family = AF_INET;
241         m_address.ipv4.sin_addr.s_addr = htonl(address);
242 }
243
244 void Address::setAddress(u8 a, u8 b, u8 c, u8 d)
245 {
246         m_addr_family = AF_INET;
247         m_address.ipv4.sin_family = AF_INET;
248         u32 addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
249         m_address.ipv4.sin_addr.s_addr = addr;
250 }
251
252 void Address::setAddress(const IPv6AddressBytes *ipv6_bytes)
253 {
254         m_addr_family = AF_INET6;
255         m_address.ipv6.sin6_family = AF_INET6;
256         if (ipv6_bytes)
257                 memcpy(m_address.ipv6.sin6_addr.s6_addr, ipv6_bytes->bytes, 16);
258         else
259                 memset(m_address.ipv6.sin6_addr.s6_addr, 0, 16);
260 }
261
262 void Address::setPort(u16 port)
263 {
264         m_port = port;
265 }
266
267 void Address::print(std::ostream *s) const
268 {
269         if (m_addr_family == AF_INET6)
270                 *s << "[" << serializeString() << "]:" << m_port;
271         else
272                 *s << serializeString() << ":" << m_port;
273 }
274
275 bool Address::isLocalhost() const
276 {
277         if (isIPv6()) {
278                 static const unsigned char localhost_bytes[] = {
279                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
280                 static const unsigned char mapped_ipv4_localhost[] = {
281                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 0};
282
283                 auto addr = m_address.ipv6.sin6_addr.s6_addr;
284
285                 return memcmp(addr, localhost_bytes, 16) == 0 ||
286                         memcmp(addr, mapped_ipv4_localhost, 13) == 0;
287         }
288
289         return (m_address.ipv4.sin_addr.s_addr & 0xFF) == 0x7f;
290 }