]> git.netwichtig.de Git - user/henk/code/inspircd.git/blob - src/socket.cpp
PURE_STATIC fixes to use normal <module> tags
[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                         if (!irc::sockets::aptosa(Addr, portno, bindspec))
90                                 continue;
91                         std::string bind_readable = bindspec.str();
92
93                         bool skip = false;
94                         for (std::vector<ListenSocket*>::iterator n = old_ports.begin(); n != old_ports.end(); ++n)
95                         {
96                                 if ((**n).bind_desc == bind_readable)
97                                 {
98                                         skip = true;
99                                         old_ports.erase(n);
100                                         break;
101                                 }
102                         }
103                         if (!skip)
104                         {
105                                 ListenSocket* ll = new ListenSocket(tag, bindspec);
106
107                                 if (ll->GetFd() > -1)
108                                 {
109                                         bound++;
110                                         ports.push_back(ll);
111                                 }
112                                 else
113                                 {
114                                         failed_ports.push_back(std::make_pair(bind_readable, strerror(errno)));
115                                         delete ll;
116                                 }
117                         }
118                 }
119         }
120
121         std::vector<ListenSocket*>::iterator n = ports.begin();
122         for (std::vector<ListenSocket*>::iterator o = old_ports.begin(); o != old_ports.end(); ++o)
123         {
124                 while (n != ports.end() && *n != *o)
125                         n++;
126                 if (n == ports.end())
127                 {
128                         this->Logs->Log("SOCKET",DEFAULT,"Port bindings slipped out of vector, aborting close!");
129                         break;
130                 }
131
132                 this->Logs->Log("SOCKET",DEFAULT, "Port binding %s was removed from the config file, closing.",
133                         (**n).bind_desc.c_str());
134                 delete *n;
135
136                 // this keeps the iterator valid, pointing to the next element
137                 n = ports.erase(n);
138         }
139
140         return bound;
141 }
142
143 bool irc::sockets::aptosa(const std::string& addr, int port, irc::sockets::sockaddrs& sa)
144 {
145         memset(&sa, 0, sizeof(sa));
146         if (addr.empty() || addr.c_str()[0] == '*')
147         {
148                 if (ServerInstance->Config->WildcardIPv6)
149                 {
150                         sa.in6.sin6_family = AF_INET6;
151                         sa.in6.sin6_port = htons(port);
152                 }
153                 else
154                 {
155                         sa.in4.sin_family = AF_INET;
156                         sa.in4.sin_port = htons(port);
157                 }
158                 return true;
159         }
160         else if (inet_pton(AF_INET, addr.c_str(), &sa.in4.sin_addr) > 0)
161         {
162                 sa.in4.sin_family = AF_INET;
163                 sa.in4.sin_port = htons(port);
164                 return true;
165         }
166         else if (inet_pton(AF_INET6, addr.c_str(), &sa.in6.sin6_addr) > 0)
167         {
168                 sa.in6.sin6_family = AF_INET6;
169                 sa.in6.sin6_port = htons(port);
170                 return true;
171         }
172         return false;
173 }
174
175 int irc::sockets::sockaddrs::port() const
176 {
177         if (sa.sa_family == AF_INET)
178                 return ntohs(in4.sin_port);
179         if (sa.sa_family == AF_INET6)
180                 return ntohs(in6.sin6_port);
181         return -1;
182 }
183
184 std::string irc::sockets::sockaddrs::addr() const
185 {
186         char addrv[INET6_ADDRSTRLEN+1];
187         if (sa.sa_family == AF_INET)
188         {
189                 if (!inet_ntop(AF_INET, &in4.sin_addr, addrv, sizeof(addrv)))
190                         return "";
191                 return addrv;
192         }
193         else if (sa.sa_family == AF_INET6)
194         {
195                 if (!inet_ntop(AF_INET6, &in6.sin6_addr, addrv, sizeof(addrv)))
196                         return "";
197                 return addrv;
198         }
199         return "";
200 }
201
202 bool irc::sockets::satoap(const irc::sockets::sockaddrs& sa, std::string& addr, int &port)
203 {
204         port = sa.port();
205         addr = sa.addr();
206         return !addr.empty();
207 }
208
209 static const char all_zero[16] = {0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 };
210
211 std::string irc::sockets::sockaddrs::str() const
212 {
213         char buffer[MAXBUF];
214         if (sa.sa_family == AF_INET)
215         {
216                 const uint8_t* bits = reinterpret_cast<const uint8_t*>(&in4.sin_addr);
217                 sprintf(buffer, "%d.%d.%d.%d:%u", bits[0], bits[1], bits[2], bits[3], ntohs(in4.sin_port));
218         }
219         else if (sa.sa_family == AF_INET6)
220         {
221                 buffer[0] = '[';
222                 if (!inet_ntop(AF_INET6, &in6.sin6_addr, buffer+1, MAXBUF - 10))
223                         return "<unknown>"; // should never happen, buffer is large enough
224                 int len = strlen(buffer);
225                 // no need for snprintf, buffer has at least 9 chars left, max short len = 5
226                 sprintf(buffer + len, "]:%u", ntohs(in6.sin6_port));
227         }
228         else
229                 return "<unknown>";
230         return std::string(buffer);
231 }
232
233 int irc::sockets::sockaddrs::sa_size() const
234 {
235         if (sa.sa_family == AF_INET)
236                 return sizeof(in4);
237         if (sa.sa_family == AF_INET6)
238                 return sizeof(in6);
239         return 0;
240 }
241
242 static void sa2cidr(irc::sockets::cidr_mask& cidr, const irc::sockets::sockaddrs& sa, int range)
243 {
244         const unsigned char* base;
245         cidr.type = sa.sa.sa_family;
246         if (cidr.type == AF_INET)
247         {
248                 base = (unsigned char*)&sa.in4.sin_addr;
249                 if (range > 32)
250                         range = 32;
251         }
252         else if (cidr.type == AF_INET6)
253         {
254                 base = (unsigned char*)&sa.in6.sin6_addr;
255                 if (range > 128)
256                         range = 128;
257         }
258         else
259         {
260                 base = (unsigned char*)"";
261                 range = 0;
262         }
263         cidr.length = range;
264         unsigned int border = range / 8;
265         unsigned int bitmask = (0xFF00 >> (range & 7)) & 0xFF;
266         for(unsigned int i=0; i < 16; i++)
267         {
268                 if (i < border)
269                         cidr.bits[i] = base[i];
270                 else if (i == border)
271                         cidr.bits[i] = base[i] & bitmask;
272                 else
273                         cidr.bits[i] = 0;
274         }
275 }
276
277 irc::sockets::cidr_mask::cidr_mask(const irc::sockets::sockaddrs& sa, int range)
278 {
279         sa2cidr(*this, sa, range);
280 }
281
282 irc::sockets::cidr_mask::cidr_mask(const std::string& mask)
283 {
284         std::string::size_type bits_chars = mask.rfind('/');
285         irc::sockets::sockaddrs sa;
286
287         if (bits_chars == std::string::npos)
288         {
289                 irc::sockets::aptosa(mask, 0, sa);
290                 sa2cidr(*this, sa, 128);
291         }
292         else
293         {
294                 int range = atoi(mask.substr(bits_chars + 1).c_str());
295                 irc::sockets::aptosa(mask.substr(0, bits_chars), 0, sa);
296                 sa2cidr(*this, sa, range);
297         }
298 }
299
300 std::string irc::sockets::cidr_mask::str() const
301 {
302         irc::sockets::sockaddrs sa;
303         sa.sa.sa_family = type;
304         unsigned char* base;
305         int len;
306         if (type == AF_INET)
307         {
308                 base = (unsigned char*)&sa.in4.sin_addr;
309                 len = 4;
310         }
311         else if (type == AF_INET6)
312         {
313                 base = (unsigned char*)&sa.in6.sin6_addr;
314                 len = 16;
315         }
316         else
317                 return "";
318         memcpy(base, bits, len);
319         return sa.addr() + "/" + ConvToStr((int)length);
320 }
321
322 bool irc::sockets::cidr_mask::operator==(const cidr_mask& other) const
323 {
324         return type == other.type && length == other.length &&
325                 0 == memcmp(bits, other.bits, 16);
326 }
327
328 bool irc::sockets::cidr_mask::operator<(const cidr_mask& other) const
329 {
330         return type < other.type || length < other.length ||
331                 memcmp(bits, other.bits, 16) < 0;
332 }
333
334 bool irc::sockets::cidr_mask::match(const irc::sockets::sockaddrs& addr) const
335 {
336         if (addr.sa.sa_family != type)
337                 return false;
338         irc::sockets::cidr_mask tmp(addr, length);
339         return tmp == *this;
340 }
341