]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socket.cpp
...because every now and again, i have to do a massive commit.
[user/henk/code/inspircd.git] / src / socket.cpp
1 /*       +------------------------------------+
2  *       | Inspire Internet Relay Chat Daemon |
3  *       +------------------------------------+
4  *
5  *  InspIRCd: (C) 2002-2010 InspIRCd Development Team
6  * See: http://wiki.inspircd.org/Credits
7  *
8  * This program is free but copyrighted software; see
9  *            the file COPYING for details.
10  *
11  * ---------------------------------------------------
12  */
13
14 #include "inspircd.h"
15 #include "socket.h"
16 #include "socketengine.h"
17 using irc::sockets::sockaddrs;
18
19 /** This will bind a socket to a port. It works for UDP/TCP.
20  * It can only bind to IP addresses, if you wish to bind to hostnames
21  * you should first resolve them using class 'Resolver'.
22  */
23 bool InspIRCd::BindSocket(int sockfd, int port, const char* addr, bool dolisten)
24 {
25         sockaddrs servaddr;
26         int ret;
27
28         if ((*addr == '*' || *addr == '\0') && port == -1)
29         {
30                 /* Port -1: Means UDP IPV4 port binding - Special case
31                  * used by DNS engine.
32                  */
33                 memset(&servaddr, 0, sizeof(servaddr));
34                 servaddr.in4.sin_family = AF_INET;
35         }
36         else if (!irc::sockets::aptosa(addr, port, servaddr))
37                 return false;
38
39         ret = SE->Bind(sockfd, servaddr);
40
41         if (ret < 0)
42         {
43                 return false;
44         }
45         else
46         {
47                 if (dolisten)
48                 {
49                         if (SE->Listen(sockfd, Config->MaxConn) == -1)
50                         {
51                                 this->Logs->Log("SOCKET",DEFAULT,"ERROR in listen(): %s",strerror(errno));
52                                 return false;
53                         }
54                         else
55                         {
56                                 this->Logs->Log("SOCKET",DEBUG,"New socket binding for %d with listen: %s:%d", sockfd, addr, port);
57                                 SE->NonBlocking(sockfd);
58                                 return true;
59                         }
60                 }
61                 else
62                 {
63                         this->Logs->Log("SOCKET",DEBUG,"New socket binding for %d without listen: %s:%d", sockfd, addr, port);
64                         return true;
65                 }
66         }
67 }
68
69 int InspIRCd::BindPorts(FailedPortList &failed_ports)
70 {
71         int bound = 0;
72         std::vector<ListenSocket*> old_ports(ports.begin(), ports.end());
73
74         ConfigTagList tags = ServerInstance->Config->ConfTags("bind");
75         for(ConfigIter i = tags.first; i != tags.second; ++i)
76         {
77                 ConfigTag* tag = i->second;
78                 std::string porttag = tag->getString("port");
79                 std::string Addr = tag->getString("address");
80
81                 if (strncasecmp(Addr.c_str(), "::ffff:", 7) == 0)
82                         this->Logs->Log("SOCKET",DEFAULT, "Using 4in6 (::ffff:) isn't recommended. You should bind IPv4 addresses directly instead.");
83
84                 irc::portparser portrange(porttag, false);
85                 int portno = -1;
86                 while (0 != (portno = portrange.GetToken()))
87                 {
88                         irc::sockets::sockaddrs bindspec;
89                         irc::sockets::aptosa(Addr, portno, bindspec);
90                         std::string bind_readable = irc::sockets::satouser(bindspec);
91
92                         bool skip = false;
93                         for (std::vector<ListenSocket*>::iterator n = old_ports.begin(); n != old_ports.end(); ++n)
94                         {
95                                 if ((**n).bind_desc == bind_readable)
96                                 {
97                                         skip = true;
98                                         old_ports.erase(n);
99                                         break;
100                                 }
101                         }
102                         if (!skip)
103                         {
104                                 ListenSocket *ll = new ListenSocket(tag, Addr, portno);
105                                 if (ll->GetFd() > -1)
106                                 {
107                                         bound++;
108                                         ports.push_back(ll);
109                                 }
110                                 else
111                                 {
112                                         failed_ports.push_back(std::make_pair(bind_readable, strerror(errno)));
113                                         delete ll;
114                                 }
115                         }
116                 }
117         }
118
119         std::vector<ListenSocket*>::iterator n = ports.begin();
120         for (std::vector<ListenSocket*>::iterator o = old_ports.begin(); o != old_ports.end(); ++o)
121         {
122                 while (n != ports.end() && *n != *o)
123                         n++;
124                 if (n == ports.end())
125                 {
126                         this->Logs->Log("SOCKET",ERROR,"Port bindings slipped out of vector, aborting close!");
127                         break;
128                 }
129
130                 this->Logs->Log("SOCKET",DEFAULT, "Port binding %s was removed from the config file, closing.",
131                         (**n).bind_desc.c_str());
132                 delete *n;
133
134                 // this keeps the iterator valid, pointing to the next element
135                 n = ports.erase(n);
136         }
137
138         return bound;
139 }
140
141 bool irc::sockets::aptosa(const std::string& addr, int port, irc::sockets::sockaddrs& sa)
142 {
143         memset(&sa, 0, sizeof(sa));
144         if (addr.empty() || addr.c_str()[0] == '*')
145         {
146 #ifdef IPV6
147                 sa.in6.sin6_family = AF_INET6;
148                 sa.in6.sin6_port = htons(port);
149 #else
150                 sa.in4.sin_family = AF_INET;
151                 sa.in4.sin_port = htons(port);
152 #endif
153                 return true;
154         }
155         else if (inet_pton(AF_INET, addr.c_str(), &sa.in4.sin_addr) > 0)
156         {
157                 sa.in4.sin_family = AF_INET;
158                 sa.in4.sin_port = htons(port);
159                 return true;
160         }
161         else if (inet_pton(AF_INET6, addr.c_str(), &sa.in6.sin6_addr) > 0)
162         {
163                 sa.in6.sin6_family = AF_INET6;
164                 sa.in6.sin6_port = htons(port);
165                 return true;
166         }
167         return false;
168 }
169
170 int irc::sockets::sockaddrs::port() const
171 {
172         if (sa.sa_family == AF_INET)
173                 return ntohs(in4.sin_port);
174         if (sa.sa_family == AF_INET6)
175                 return ntohs(in6.sin6_port);
176         return -1;
177 }
178
179 std::string irc::sockets::sockaddrs::addr() const
180 {
181         char addrv[INET6_ADDRSTRLEN+1];
182         if (sa.sa_family == AF_INET)
183         {
184                 if (!inet_ntop(AF_INET, &in4.sin_addr, addrv, sizeof(addrv)))
185                         return "";
186                 return addrv;
187         }
188         else if (sa.sa_family == AF_INET6)
189         {
190                 if (!inet_ntop(AF_INET6, &in6.sin6_addr, addrv, sizeof(addrv)))
191                         return "";
192                 return addrv;
193         }
194         return "";
195 }
196
197 bool irc::sockets::satoap(const irc::sockets::sockaddrs& sa, std::string& addr, int &port)
198 {
199         port = sa.port();
200         addr = sa.addr();
201         return !addr.empty();
202 }
203
204 static const char all_zero[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
205
206 std::string irc::sockets::sockaddrs::str() const
207 {
208         char buffer[MAXBUF];
209         if (sa.sa_family == AF_INET)
210         {
211 #ifndef IPV6
212                 if (in4.sin_addr.s_addr == 0)
213                 {
214                         sprintf(buffer, "*:%u", ntohs(in4.sin_port));
215                 }
216                 else
217 #endif
218                 {
219                         const uint8_t* bits = reinterpret_cast<const uint8_t*>(&in4.sin_addr);
220                         sprintf(buffer, "%d.%d.%d.%d:%u", bits[0], bits[1], bits[2], bits[3], ntohs(in4.sin_port));
221                 }
222         }
223         else if (sa.sa_family == AF_INET6)
224         {
225 #ifdef IPV6
226                 if (!memcmp(all_zero, &in6.sin6_addr, 16))
227                 {
228                         sprintf(buffer, "*:%u", ntohs(in6.sin6_port));
229                 }
230                 else
231 #endif
232                 {
233                         buffer[0] = '[';
234                         if (!inet_ntop(AF_INET6, &in6.sin6_addr, buffer+1, MAXBUF - 10))
235                                 return "<unknown>"; // should never happen, buffer is large enough
236                         int len = strlen(buffer);
237                         // no need for snprintf, buffer has at least 9 chars left, max short len = 5
238                         sprintf(buffer + len, "]:%u", ntohs(in6.sin6_port));
239                 }
240         }
241         else
242                 return "<unknown>";
243         return std::string(buffer);
244 }
245
246 int irc::sockets::sockaddrs::sa_size() const
247 {
248         if (sa.sa_family == AF_INET)
249                 return sizeof(in4);
250         if (sa.sa_family == AF_INET6)
251                 return sizeof(in6);
252         return 0;
253 }
254
255 static void sa2cidr(irc::sockets::cidr_mask& cidr, const irc::sockets::sockaddrs& sa, int range)
256 {
257         const unsigned char* base;
258         cidr.type = sa.sa.sa_family;
259         if (cidr.type == AF_INET)
260         {
261                 base = (unsigned char*)&sa.in4.sin_addr;
262                 if (range > 32)
263                         range = 32;
264         }
265         else if (cidr.type == AF_INET6)
266         {
267                 base = (unsigned char*)&sa.in6.sin6_addr;
268                 if (range > 128)
269                         range = 128;
270         }
271         else
272         {
273                 base = (unsigned char*)"";
274                 range = 0;
275         }
276         cidr.length = range;
277         unsigned int border = range / 8;
278         unsigned int bitmask = (0xFF00 >> (range & 7)) & 0xFF;
279         for(unsigned int i=0; i < 16; i++)
280         {
281                 if (i < border)
282                         cidr.bits[i] = base[i];
283                 else if (i == border)
284                         cidr.bits[i] = base[i] & bitmask;
285                 else
286                         cidr.bits[i] = 0;
287         }
288 }
289
290 irc::sockets::cidr_mask::cidr_mask(const irc::sockets::sockaddrs& sa, int range)
291 {
292         sa2cidr(*this, sa, range);
293 }
294
295 irc::sockets::cidr_mask::cidr_mask(const std::string& mask)
296 {
297         std::string::size_type bits_chars = mask.rfind('/');
298         irc::sockets::sockaddrs sa;
299
300         if (bits_chars == std::string::npos)
301         {
302                 irc::sockets::aptosa(mask, 0, sa);
303                 sa2cidr(*this, sa, 128);
304         }
305         else
306         {
307                 int range = atoi(mask.substr(bits_chars + 1).c_str());
308                 irc::sockets::aptosa(mask.substr(0, bits_chars), 0, sa);
309                 sa2cidr(*this, sa, range);
310         }
311 }
312
313 std::string irc::sockets::cidr_mask::str() const
314 {
315         irc::sockets::sockaddrs sa;
316         sa.sa.sa_family = type;
317         unsigned char* base;
318         int len;
319         if (type == AF_INET)
320         {
321                 base = (unsigned char*)&sa.in4.sin_addr;
322                 len = 4;
323         }
324         else if (type == AF_INET6)
325         {
326                 base = (unsigned char*)&sa.in6.sin6_addr;
327                 len = 16;
328         }
329         else
330                 return "";
331         memcpy(base, bits, len);
332         return sa.addr() + "/" + ConvToStr(length);
333 }
334
335 bool irc::sockets::cidr_mask::operator==(const cidr_mask& other) const
336 {
337         return type == other.type && length == other.length &&
338                 0 == memcmp(bits, other.bits, 16);
339 }
340
341 bool irc::sockets::cidr_mask::operator<(const cidr_mask& other) const
342 {
343         return type < other.type || length < other.length ||
344                 memcmp(bits, other.bits, 16) < 0;
345 }
346
347 bool irc::sockets::cidr_mask::match(const irc::sockets::sockaddrs& addr) const
348 {
349         if (addr.sa.sa_family != type)
350                 return false;
351         irc::sockets::cidr_mask tmp(addr, length);
352         return tmp == *this;
353 }
354