]>
Commit | Line | Data |
---|---|---|
12471842 PL |
1 | /* |
2 | * This file is part of PowerDNS or dnsdist. | |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
870a0fe4 AT |
22 | #ifdef HAVE_CONFIG_H |
23 | #include "config.h" | |
24 | #endif | |
c1e527e3 | 25 | #include "iputils.hh" |
26 | #include "sstuff.hh" | |
27 | #include "statbag.hh" | |
7b85069a | 28 | #include <atomic> |
29 | #include <sys/mman.h> | |
30 | #include <thread> | |
c1e527e3 | 31 | StatBag S; |
32 | ||
65ae9609 | 33 | static std::atomic<uint64_t>* g_counter; |
7b85069a | 34 | |
65ae9609 | 35 | static void printStatus() |
7b85069a | 36 | { |
37 | auto prev= g_counter->load(); | |
38 | for(;;) { | |
39 | sleep(1); | |
40 | cout<<g_counter->load()-prev<<"\t"<<g_counter->load()<<endl; | |
41 | prev=g_counter->load(); | |
42 | } | |
43 | } | |
44 | ||
65ae9609 RG |
45 | static void usage() { |
46 | cerr<<"Syntax: dumresp LOCAL-ADDRESS LOCAL-PORT NUMBER-OF-PROCESSES [tcp]"<<endl; | |
47 | } | |
48 | ||
49 | static void turnQueryIntoResponse(dnsheader* dh) | |
50 | { | |
51 | (*g_counter)++; | |
52 | ||
53 | dh->qr=1; | |
54 | dh->ad=0; | |
55 | } | |
56 | ||
57 | static void tcpConnectionHandler(int sock) | |
58 | try | |
59 | { | |
60 | char buffer[1500]; | |
61 | auto dh = reinterpret_cast<struct dnsheader*>(buffer); | |
62 | ||
63 | for (;;) { | |
64 | uint16_t len = 0; | |
65 | ssize_t got = read(sock, &len, sizeof(len)); | |
66 | ||
67 | if (got == 0) { | |
68 | break; | |
69 | } | |
70 | ||
71 | if (got != sizeof(len)) | |
72 | unixDie("read 1"); | |
73 | ||
74 | len = ntohs(len); | |
75 | ||
76 | if (len < sizeof(dnsheader)) | |
77 | unixDie("too small"); | |
78 | ||
79 | if (len > sizeof(buffer)) | |
80 | unixDie("too large"); | |
81 | ||
82 | got = read(sock, buffer, len); | |
83 | if (got != len) | |
84 | unixDie("read 2: " + std::to_string(got) + " / " + std::to_string(len)); | |
85 | ||
86 | if (dh->qr) | |
87 | continue; | |
88 | ||
89 | turnQueryIntoResponse(dh); | |
90 | ||
91 | uint16_t wirelen = htons(len); | |
92 | if (write(sock, &wirelen, sizeof(wirelen)) != sizeof(wirelen)) | |
93 | unixDie("send 1"); | |
94 | ||
95 | if (write(sock, buffer, len) < 0) | |
96 | unixDie("send 2"); | |
97 | } | |
98 | ||
99 | close(sock); | |
100 | } | |
101 | catch(const std::exception& e) { | |
102 | cerr<<"TCP connection handler got an exception: "<<e.what()<<endl; | |
103 | } | |
104 | ||
105 | static void tcpAcceptor(const ComboAddress local) | |
106 | { | |
107 | Socket tcpSocket(local.sin4.sin_family, SOCK_STREAM); | |
108 | #ifdef SO_REUSEPORT | |
109 | int one=1; | |
110 | if(setsockopt(tcpSocket.getHandle(), SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0) | |
111 | unixDie("setsockopt for REUSEPORT"); | |
112 | #endif | |
113 | ||
114 | tcpSocket.bind(local); | |
115 | tcpSocket.listen(1024); | |
116 | ||
117 | ComboAddress rem("::1"); | |
118 | auto socklen = rem.getSocklen(); | |
119 | ||
120 | for (;;) { | |
121 | int sock = accept(tcpSocket.getHandle(), reinterpret_cast<struct sockaddr*>(&rem), &socklen); | |
122 | if (sock == -1) { | |
123 | continue; | |
124 | } | |
125 | ||
126 | std::thread connectionHandler(tcpConnectionHandler, sock); | |
127 | connectionHandler.detach(); | |
128 | } | |
e06df890 PL |
129 | } |
130 | ||
c1e527e3 | 131 | int main(int argc, char** argv) |
132 | try | |
133 | { | |
65ae9609 RG |
134 | bool tcp = false; |
135 | ||
e06df890 | 136 | for(int i = 1; i < argc; i++) { |
65ae9609 | 137 | if(std::string(argv[i]) == "--help"){ |
e06df890 PL |
138 | usage(); |
139 | return(EXIT_SUCCESS); | |
140 | } | |
141 | ||
65ae9609 | 142 | if(std::string(argv[i]) == "--version"){ |
e06df890 PL |
143 | cerr<<"dumresp "<<VERSION<<endl; |
144 | return(EXIT_SUCCESS); | |
145 | } | |
146 | } | |
147 | ||
65ae9609 RG |
148 | if(argc == 5) { |
149 | if (std::string(argv[4]) == "tcp") { | |
150 | tcp = true; | |
151 | } | |
152 | else { | |
153 | usage(); | |
154 | exit(EXIT_FAILURE); | |
155 | } | |
156 | } | |
157 | else if(argc != 4) { | |
e06df890 | 158 | usage(); |
c1e527e3 | 159 | exit(EXIT_FAILURE); |
160 | } | |
161 | ||
65ae9609 | 162 | auto ptr = mmap(nullptr, sizeof(std::atomic<uint64_t>), PROT_READ | PROT_WRITE, |
7b85069a | 163 | MAP_SHARED | MAP_ANONYMOUS, -1, 0); |
164 | ||
165 | g_counter = new(ptr) std::atomic<uint64_t>(); | |
65ae9609 RG |
166 | |
167 | int numberOfListeners = atoi(argv[3]); | |
168 | ComboAddress local(argv[1], atoi(argv[2])); | |
169 | ||
7b85069a | 170 | int i=1; |
65ae9609 | 171 | for(; i < numberOfListeners; ++i) { |
c1e527e3 | 172 | if(!fork()) |
173 | break; | |
174 | } | |
65ae9609 RG |
175 | |
176 | if (i==1) { | |
7b85069a | 177 | std::thread t(printStatus); |
178 | t.detach(); | |
65ae9609 RG |
179 | |
180 | if (tcp) { | |
181 | for (int j = 0; j < numberOfListeners; j++) { | |
182 | cout<<"Listening to TCP "<<local.toStringWithPort()<<endl; | |
183 | std::thread tcpAcceptorThread(tcpAcceptor, local); | |
184 | tcpAcceptorThread.detach(); | |
185 | } | |
186 | } | |
7b85069a | 187 | } |
65ae9609 RG |
188 | |
189 | Socket s(local.sin4.sin_family, SOCK_DGRAM); | |
c648bdce | 190 | #ifdef SO_REUSEPORT |
c1e527e3 | 191 | int one=1; |
192 | if(setsockopt(s.getHandle(), SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0) | |
193 | unixDie("setsockopt for REUSEPORT"); | |
c648bdce | 194 | #endif |
c1e527e3 | 195 | |
196 | s.bind(local); | |
65ae9609 RG |
197 | cout<<"Bound to UDP "<<local.toStringWithPort()<<endl; |
198 | ||
199 | ComboAddress rem = local; | |
c1e527e3 | 200 | socklen_t socklen = rem.getSocklen(); |
65ae9609 RG |
201 | char buffer[1500]; |
202 | auto dh = reinterpret_cast<struct dnsheader*>(buffer); | |
203 | ||
c1e527e3 | 204 | for(;;) { |
0d8cd83c | 205 | ssize_t len = recvfrom(s.getHandle(), buffer, sizeof(buffer), 0, reinterpret_cast<struct sockaddr*>(&rem), &socklen); |
65ae9609 | 206 | |
c1e527e3 | 207 | if(len < 0) |
208 | unixDie("recvfrom"); | |
786d6f33 | 209 | |
0d8cd83c | 210 | if (static_cast<size_t>(len) < sizeof(dnsheader)) |
65ae9609 RG |
211 | unixDie("too small " + std::to_string(len)); |
212 | ||
c1e527e3 | 213 | if(dh->qr) |
214 | continue; | |
c1e527e3 | 215 | |
65ae9609 RG |
216 | turnQueryIntoResponse(dh); |
217 | ||
218 | if(sendto(s.getHandle(), buffer, len, 0, reinterpret_cast<const struct sockaddr*>(&rem), socklen) < 0) | |
219 | unixDie("sendto"); | |
c1e527e3 | 220 | } |
221 | } | |
65ae9609 | 222 | catch(const std::exception& e) |
c1e527e3 | 223 | { |
224 | cerr<<"Fatal error: "<<e.what()<<endl; | |
225 | exit(EXIT_FAILURE); | |
226 | } |