]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/ws-api.cc
Recursor: restore correct syslog name
[thirdparty/pdns.git] / pdns / ws-api.cc
CommitLineData
6ec5e728
CH
1/*
2 Copyright (C) 2002 - 2014 PowerDNS.COM BV
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License version 2
6 as published by the Free Software Foundation
7
8 Additionally, the license of this program contains a special
9 exception which allows to distribute the program in binary form when
10 it is linked against OpenSSL.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20*/
21#include <boost/foreach.hpp>
22#include <boost/tokenizer.hpp>
23#include <boost/circular_buffer.hpp>
24#include "namespaces.hh"
25#include "ws-api.hh"
26#include "json.hh"
27#include "config.h"
28#include "version.hh"
29#include "arguments.hh"
30#include <stdio.h>
31#include <string.h>
32#include <ctype.h>
33#include <sys/types.h>
3c3c006b 34#include <iomanip>
6ec5e728
CH
35
36#ifndef HAVE_STRCASESTR
37
38/*
39 * strcasestr() locates the first occurrence in the string s1 of the
40 * sequence of characters (excluding the terminating null character)
41 * in the string s2, ignoring case. strcasestr() returns a pointer
42 * to the located string, or a null pointer if the string is not found.
43 * If s2 is empty, the function returns s1.
44 */
45
46static char *
47strcasestr(const char *s1, const char *s2)
48{
49 int *cm = __trans_lower;
50 const uchar_t *us1 = (const uchar_t *)s1;
51 const uchar_t *us2 = (const uchar_t *)s2;
52 const uchar_t *tptr;
53 int c;
54
55 if (us2 == NULL || *us2 == '\0')
56 return ((char *)us1);
57
58 c = cm[*us2];
59 while (*us1 != '\0') {
60 if (c == cm[*us1++]) {
61 tptr = us1;
62 while (cm[c = *++us2] == cm[*us1++] && c != '\0')
63 continue;
64 if (c == '\0')
65 return ((char *)tptr - 1);
66 us1 = tptr;
67 us2 = (const uchar_t *)s2;
68 c = cm[*us2];
69 }
70 }
71
72 return (NULL);
73}
74
75#endif // HAVE_STRCASESTR
76
77using namespace rapidjson;
78
79static void fillServerDetail(Value& out, Value::AllocatorType& allocator)
80{
81 Value jdaemonType(productTypeApiType().c_str(), allocator);
82 out.SetObject();
83 out.AddMember("type", "Server", allocator);
84 out.AddMember("id", "localhost", allocator);
85 out.AddMember("url", "/servers/localhost", allocator);
86 out.AddMember("daemon_type", jdaemonType, allocator);
87 out.AddMember("version", VERSION, allocator);
88 out.AddMember("config_url", "/servers/localhost/config{/config_setting}", allocator);
89 out.AddMember("zones_url", "/servers/localhost/zones{/zone}", allocator);
90}
91
92void apiServer(HttpRequest* req, HttpResponse* resp) {
93 if(req->method != "GET")
94 throw HttpMethodNotAllowedException();
95
96 Document doc;
97 doc.SetArray();
98 Value server;
99 fillServerDetail(server, doc.GetAllocator());
100 doc.PushBack(server, doc.GetAllocator());
669822d0 101 resp->setBody(doc);
6ec5e728
CH
102}
103
104void apiServerDetail(HttpRequest* req, HttpResponse* resp) {
105 if(req->method != "GET")
106 throw HttpMethodNotAllowedException();
107
108 Document doc;
109 fillServerDetail(doc, doc.GetAllocator());
669822d0 110 resp->setBody(doc);
6ec5e728
CH
111}
112
113void apiServerConfig(HttpRequest* req, HttpResponse* resp) {
114 if(req->method != "GET")
115 throw HttpMethodNotAllowedException();
116
117 vector<string> items = ::arg().list();
118 string value;
119 Document doc;
120 doc.SetArray();
121 BOOST_FOREACH(const string& item, items) {
122 Value jitem;
123 jitem.SetObject();
124 jitem.AddMember("type", "ConfigSetting", doc.GetAllocator());
125
126 Value jname(item.c_str(), doc.GetAllocator());
127 jitem.AddMember("name", jname, doc.GetAllocator());
128
129 if(item.find("password") != string::npos)
130 value = "***";
131 else
132 value = ::arg()[item];
133
134 Value jvalue(value.c_str(), doc.GetAllocator());
135 jitem.AddMember("value", jvalue, doc.GetAllocator());
136
137 doc.PushBack(jitem, doc.GetAllocator());
138 }
669822d0 139 resp->setBody(doc);
6ec5e728
CH
140}
141
142static string logGrep(const string& q, const string& fname, const string& prefix)
143{
144 FILE* ptr = fopen(fname.c_str(), "r");
145 if(!ptr) {
146 return "[]";
147 }
148 boost::shared_ptr<FILE> fp(ptr, fclose);
149
150 string line;
151 string needle = q;
152 trim_right(needle);
153
154 boost::replace_all(needle, "%20", " ");
155 boost::replace_all(needle, "%22", "\"");
156
157 boost::tokenizer<boost::escaped_list_separator<char> > t(needle, boost::escaped_list_separator<char>("\\", " ", "\""));
158 vector<string> matches(t.begin(), t.end());
159 matches.push_back(prefix);
160
161 boost::circular_buffer<string> lines(200);
162 while(stringfgets(fp.get(), line)) {
163 vector<string>::const_iterator iter;
164 for(iter = matches.begin(); iter != matches.end(); ++iter) {
165 if(!strcasestr(line.c_str(), iter->c_str()))
166 break;
167 }
168 if(iter == matches.end()) {
169 trim_right(line);
170 lines.push_front(line);
171 }
172 }
173
174 Document doc;
175 doc.SetArray();
176 if(!lines.empty()) {
177 BOOST_FOREACH(const string& line, lines) {
178 doc.PushBack(line.c_str(), doc.GetAllocator());
179 }
180 }
181 return makeStringFromDocument(doc);
182}
183
184void apiServerSearchLog(HttpRequest* req, HttpResponse* resp) {
185 if(req->method != "GET")
186 throw HttpMethodNotAllowedException();
187
188 string prefix;
189 switch (versionGetProduct()) {
190 case ProductAuthoritative:
191 prefix = " pdns[";
192 break;
193 case ProductRecursor:
194 prefix = " pdns_recursor[";
195 break;
196 }
197 resp->body = logGrep(req->parameters["q"], ::arg()["experimental-logfile"], prefix);
198}
199
200void apiServerStatistics(HttpRequest* req, HttpResponse* resp) {
201 if(req->method != "GET")
202 throw HttpMethodNotAllowedException();
203
204 map<string,string> items;
205 productServerStatisticsFetch(items);
206
207 Document doc;
208 doc.SetArray();
209 typedef map<string, string> items_t;
f29b72dc 210 BOOST_FOREACH(const items_t::value_type& item, items) {
6ec5e728
CH
211 Value jitem;
212 jitem.SetObject();
213 jitem.AddMember("type", "StatisticItem", doc.GetAllocator());
214
215 Value jname(item.first.c_str(), doc.GetAllocator());
216 jitem.AddMember("name", jname, doc.GetAllocator());
217
218 Value jvalue(item.second.c_str(), doc.GetAllocator());
219 jitem.AddMember("value", jvalue, doc.GetAllocator());
220
221 doc.PushBack(jitem, doc.GetAllocator());
222 }
223
669822d0 224 resp->setBody(doc);
6ec5e728 225}
3c3c006b
CH
226
227string apiZoneIdToName(const string& id) {
228 string zonename;
229 ostringstream ss;
230
231 if(id.empty())
232 throw HttpBadRequestException();
233
234 std::size_t lastpos = 0, pos = 0;
235 while ((pos = id.find('=', lastpos)) != string::npos) {
236 ss << id.substr(lastpos, pos-lastpos);
237 if ((id[pos+1] >= '0' && id[pos+1] <= '9') &&
238 (id[pos+2] >= '0' && id[pos+2] <= '9')) {
239 char c = ((id[pos+1] - '0')*10) + (id[pos+2] - '0');
240 ss << c;
241 } else {
242 throw HttpBadRequestException();
243 }
244
245 lastpos = pos+3;
246 }
247 if (lastpos < pos) {
248 ss << id.substr(lastpos, pos-lastpos);
249 }
250
251 zonename = ss.str();
252
253 // strip trailing dot
254 if (zonename.substr(zonename.size()-1) == ".") {
161a8b69 255 zonename.resize(zonename.size()-1);
3c3c006b
CH
256 }
257 return zonename;
258}
259
260string apiZoneNameToId(const string& name) {
261 ostringstream ss;
262
263 for(string::const_iterator iter = name.begin(); iter != name.end(); ++iter) {
264 if ((*iter >= 'A' && *iter <= 'Z') ||
265 (*iter >= 'a' && *iter <= 'z') ||
266 (*iter >= '0' && *iter <= '9') ||
267 (*iter == '.') || (*iter == '-')) {
268 ss << *iter;
269 } else {
270 ss << "=" << std::setfill('0') << std::setw(2) << (int)(*iter);
271 }
272 }
273
161a8b69
CH
274 string id = ss.str();
275
3c3c006b 276 // add trailing dot
161a8b69
CH
277 if (id.substr(id.size()-1) != ".") {
278 id += ".";
279 }
3c3c006b
CH
280
281 // special handling for the root zone, as a dot on it's own doesn't work
282 // everywhere.
283 if (id == ".") {
284 id = (boost::format("=%d") % (int)('.')).str();
285 }
286 return id;
287}