]> git.lizzy.rs Git - minetest.git/blob - src/network/address.cpp
Disable Prometheus in singleplayer mode
[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, IP and port must be equal)
91 bool Address::operator==(const Address &other)
92 {
93         if (other.m_addr_family != m_addr_family || other.m_port != m_port)
94                 return false;
95
96         if (m_addr_family == AF_INET) {
97                 return m_address.ipv4.s_addr == other.m_address.ipv4.s_addr;
98         }
99
100         if (m_addr_family == AF_INET6) {
101                 return memcmp(m_address.ipv6.s6_addr,
102                                 other.m_address.ipv6.s6_addr, 16) == 0;
103         }
104
105         return false;
106 }
107
108 void Address::Resolve(const char *name)
109 {
110         if (!name || name[0] == 0) {
111                 if (m_addr_family == AF_INET)
112                         setAddress(static_cast<u32>(0));
113                 else if (m_addr_family == AF_INET6)
114                         setAddress(static_cast<IPv6AddressBytes*>(nullptr));
115                 return;
116         }
117
118         struct addrinfo *resolved, hints;
119         memset(&hints, 0, sizeof(hints));
120
121         // Setup hints
122         if (g_settings->getBool("enable_ipv6")) {
123                 // AF_UNSPEC allows both IPv6 and IPv4 addresses to be returned
124                 hints.ai_family = AF_UNSPEC;
125         } else {
126                 hints.ai_family = AF_INET;
127         }
128
129         // Do getaddrinfo()
130         int e = getaddrinfo(name, NULL, &hints, &resolved);
131         if (e != 0)
132                 throw ResolveError(gai_strerror(e));
133
134         // Copy data
135         if (resolved->ai_family == AF_INET) {
136                 struct sockaddr_in *t = (struct sockaddr_in *)resolved->ai_addr;
137                 m_addr_family = AF_INET;
138                 m_address.ipv4 = t->sin_addr;
139         } else if (resolved->ai_family == AF_INET6) {
140                 struct sockaddr_in6 *t = (struct sockaddr_in6 *)resolved->ai_addr;
141                 m_addr_family = AF_INET6;
142                 m_address.ipv6 = t->sin6_addr;
143         } else {
144                 m_addr_family = 0;
145         }
146         freeaddrinfo(resolved);
147 }
148
149 // IP address -> textual representation
150 std::string Address::serializeString() const
151 {
152 // windows XP doesnt have inet_ntop, maybe use better func
153 #ifdef _WIN32
154         if (m_addr_family == AF_INET) {
155                 return inet_ntoa(m_address.ipv4);
156         } else if (m_addr_family == AF_INET6) {
157                 std::ostringstream os;
158                 os << std::hex;
159                 for (int i = 0; i < 16; i += 2) {
160                         u16 section = (m_address.ipv6.s6_addr[i] << 8) |
161                                         (m_address.ipv6.s6_addr[i + 1]);
162                         os << section;
163                         if (i < 14)
164                                 os << ":";
165                 }
166                 return os.str();
167         } else {
168                 return "";
169         }
170 #else
171         char str[INET6_ADDRSTRLEN];
172         if (inet_ntop(m_addr_family, (void*) &m_address, str, sizeof(str)) == nullptr)
173                 return "";
174         return str;
175 #endif
176 }
177
178 struct in_addr Address::getAddress() const
179 {
180         return m_address.ipv4;
181 }
182
183 struct in6_addr Address::getAddress6() const
184 {
185         return m_address.ipv6;
186 }
187
188 u16 Address::getPort() const
189 {
190         return m_port;
191 }
192
193 bool Address::isZero() const
194 {
195         if (m_addr_family == AF_INET) {
196                 return m_address.ipv4.s_addr == 0;
197         }
198
199         if (m_addr_family == AF_INET6) {
200                 static const char zero[16] = {0};
201                 return memcmp(m_address.ipv6.s6_addr, zero, 16) == 0;
202         }
203
204         return false;
205 }
206
207 void Address::setAddress(u32 address)
208 {
209         m_addr_family = AF_INET;
210         m_address.ipv4.s_addr = htonl(address);
211 }
212
213 void Address::setAddress(u8 a, u8 b, u8 c, u8 d)
214 {
215         u32 addr = (a << 24) | (b << 16) | (c << 8) | d;
216         setAddress(addr);
217 }
218
219 void Address::setAddress(const IPv6AddressBytes *ipv6_bytes)
220 {
221         m_addr_family = AF_INET6;
222         if (ipv6_bytes)
223                 memcpy(m_address.ipv6.s6_addr, ipv6_bytes->bytes, 16);
224         else
225                 memset(m_address.ipv6.s6_addr, 0, 16);
226 }
227
228 void Address::setPort(u16 port)
229 {
230         m_port = port;
231 }
232
233 void Address::print(std::ostream& s) const
234 {
235         if (m_addr_family == AF_INET6)
236                 s << "[" << serializeString() << "]:" << m_port;
237         else if (m_addr_family == AF_INET)
238                 s << serializeString() << ":" << m_port;
239         else
240                 s << "(undefined)";
241 }
242
243 bool Address::isLocalhost() const
244 {
245         if (isIPv6()) {
246                 static const u8 localhost_bytes[] = {
247                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
248                 static const u8 mapped_ipv4_localhost[] = {
249                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0x7f, 0, 0, 0};
250
251                 auto addr = m_address.ipv6.s6_addr;
252
253                 return memcmp(addr, localhost_bytes, 16) == 0 ||
254                         memcmp(addr, mapped_ipv4_localhost, 13) == 0;
255         }
256
257         auto addr = ntohl(m_address.ipv4.s_addr);
258         return (addr >> 24) == 0x7f;
259 }