parkinglot.cc 8.51 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.

// $Id$

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/select.h>
20
#include <netinet/in.h>
21
22
23
#include <netdb.h>
#include <stdlib.h>

24
#include <algorithm>
25
26
27
#include <set>
#include <iostream>

28
29
30
31
32
33
34
#include <dns/cpp/buffer.h>
#include <dns/cpp/messagerenderer.h>
#include <dns/cpp/name.h>
#include <dns/cpp/question.h>
#include <dns/cpp/rrset.h>
#include <dns/cpp/rrttl.h>
#include <dns/cpp/message.h>
35

36
37
#include <cc/cpp/data.h>

38
#include "common.h"
39
#include "builtin.h"
40
41
#include "parkinglot.h"

42
#include <boost/lexical_cast.hpp>
43
44
#include <boost/foreach.hpp>

45
46
47
using namespace std;

using namespace isc::dns;
48
using namespace isc::dns::rdata;
Jelte Jansen's avatar
Jelte Jansen committed
49
using namespace isc::data;
50
51

ParkingLot::ParkingLot(int port) {
52
    /*ns1 = Rdata::RdataPtr(new NS("ns1.parking.example"));
53
54
    ns2 = Rdata::RdataPtr(new NS("ns2.parking.example"));
    ns3 = Rdata::RdataPtr(new NS("ns3.parking.example"));
55
56
    a = Rdata::RdataPtr(new A("127.0.0.1"));
    aaaa = Rdata::RdataPtr(new AAAA("::1"));
57
    */
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

    int s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    if (s < 0)
        throw FatalError("failed to open socket");

    struct sockaddr_in sin;
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;
    sin.sin_port = htons(port);

    socklen_t sa_len = sizeof(sin);
#ifdef HAVE_SIN_LEN
    sin.sin_len = sa_len;
#endif

    if (bind(s, (struct sockaddr *)&sin, sa_len) < 0)
        throw FatalError("could not bind socket");

    sock = s;
}

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
namespace {
struct GlueInserter {
    GlueInserter(const DataSourceParkingLot& data_source,
                 const Name& zname, const RRClass& qclass,
                 Message& msg) :
        data_source_(&data_source), zname_(&zname), qclass_(&qclass),
        msg_(&msg)
    {}
    void operator()(const RRsetPtr rrset)
    {
        if (rrset->getType() == RRType::NS()) {
            RdataIteratorPtr it = rrset->getRdataIterator();
            for (it->first(); !it->isLast(); it->next()) {
                const generic::NS& nsrdata =
                    dynamic_cast<const generic::NS&>(it->getCurrent());
                data_source_->addToMessage(*msg_, Section::ADDITIONAL(),
                                           *zname_, nsrdata.getNSName(),
                                           *qclass_, RRType::A());
                data_source_->addToMessage(*msg_, Section::ADDITIONAL(),
                                           *zname_, nsrdata.getNSName(),
                                           *qclass_, RRType::AAAA());
            }
        }
    }
    const DataSourceParkingLot* data_source_;
    const Name* zname_;
    const RRClass* qclass_;
    Message* msg_;
};
}

110
111
112
113
114
namespace {
const Name authors_name("authors.bind");
const Name version_name("version.bind");
}

115
116
void
ParkingLot::processMessage() {
117
118
119
120
121
    struct sockaddr_storage ss;
    socklen_t sa_len = sizeof(ss);
    struct sockaddr* sa = static_cast<struct sockaddr*>((void*)&ss);
    int s = sock;
    Message msg;
122
123
    char recvbuf[4096];
    int cc;
124

125
126
    if ((cc = recvfrom(s, recvbuf, sizeof(recvbuf), 0, sa, &sa_len)) > 0) {
        InputBuffer buffer(recvbuf, cc);
127
        try {
128
            msg.fromWire(buffer);
129
130
131
132
133
134
135
        } catch (...) {
            cerr << "parse failed" << endl;
            return;
        }

        cout << "received a message:\n" << msg.toText() << endl;

136
        if (msg.getRRCount(Section::QUESTION()) != 1) {
137
            return;
138
        }
139

140
        QuestionPtr query = *msg.beginQuestion();
141
142

        msg.makeResponse();
143
144
        msg.setHeaderFlag(MessageFlag::AA());
        Name zname(".");        // ugly, but should work for now
145
        msg.setRcode(Rcode::NOERROR());
146
147
148
        if (query->getType() == RRType::TXT() &&
            query->getClass() == RRClass::CH() &&
            query->getName() == authors_name) {
149
150
151
            msg.addRRset(Section::ANSWER(), getBuiltinAuthors().getAnswer());
            msg.addRRset(Section::AUTHORITY(),
                         getBuiltinAuthors().getAuthority());
152
153
154
        } else if (query->getType() == RRType::TXT() &&
                   query->getClass() == RRClass::CH() &&
            query->getName() == version_name) {
155
156
157
158
            msg.addRRset(Section::ANSWER(), getBuiltinVersion().getAnswer());
            msg.addRRset(Section::AUTHORITY(),
                         getBuiltinVersion().getAuthority());
        } else if (data_source.hasZoneFor(query->getName(), zname)) {
159
160
161
162
163
164
            SearchResult::status_type status =
                data_source.addToMessage(msg, Section::ANSWER(), zname,
                                         query->getName(), query->getClass(),
                                         query->getType());
            bool included_ns = false;

165
166
            // rcode is based on this result?
            if (status == SearchResult::name_not_found) {
167
                msg.setRcode(Rcode::NXDOMAIN());
168
                if (query->getType() != RRType::NS()) {
169
                    status = data_source.addToMessage(msg, Section::AUTHORITY(),
170
171
                                                      zname, zname,
                                                      query->getClass(),
172
                                                      RRType::SOA());
173
174
                }
            } else {
175
                if (query->getType() != RRType::NS()) {
176
                    status = data_source.addToMessage(msg, Section::AUTHORITY(),
177
178
                                                      zname, zname,
                                                      query->getClass(),
179
                                                      RRType::NS());
180
181
                }
                included_ns = true;
182
            }
183
184
            // If we included NS records, and their target falls below the zone, add glue
            if (included_ns) {
185
186
                for_each(msg.beginSection(Section::ANSWER()),
                         msg.endSection(Section::ANSWER()),
187
188
                         GlueInserter(data_source, zname, query->getClass(),
                                      msg));
189
190
                for_each(msg.beginSection(Section::AUTHORITY()),
                         msg.endSection(Section::AUTHORITY()),
191
192
                         GlueInserter(data_source, zname, query->getClass(),
                                      msg));
193
194
            }
        } else {
195
            msg.setRcode(Rcode::SERVFAIL());
196
        }
197
198
199
200

        OutputBuffer obuffer(4096);
        MessageRenderer renderer(obuffer);
        msg.toWire(renderer);
201
        cout << "sending a response (" <<
202
            boost::lexical_cast<string>(obuffer.getLength())
203
                  << " bytes):\n" << msg.toText() << endl;
204
        sendto(s, obuffer.getData(), obuffer.getLength(), 0, sa, sa_len);
205
    }
206
}
207

208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
ElementPtr
ParkingLot::updateConfig(isc::data::ElementPtr config) {
    if (config->contains("zones")) {
        data_source.clear_zones();
        BOOST_FOREACH(isc::data::ElementPtr zone_el, config->get("zones")->listValue()) {
            data_source.serve(zone_el->stringValue());
        }
    }
    if (config->contains("port")) {
        // todo: what to do with port change. restart automatically?
        // ignore atm
    }
    if (config->contains("a_records")) {
        data_source.clearARecords();
        BOOST_FOREACH(isc::data::ElementPtr rel, config->get("a_records")->listValue()) {
            data_source.addARecord(rel->stringValue());
        }
    }
    if (config->contains("aaaa_records")) {
        data_source.clearAAAARecords();
        BOOST_FOREACH(isc::data::ElementPtr rel, config->get("aaaa_records")->listValue()) {
            data_source.addAAAARecord(rel->stringValue());
        }
    }
    if (config->contains("ns_records")) {
        data_source.clearNSRecords();
        BOOST_FOREACH(isc::data::ElementPtr rel, config->get("ns_records")->listValue()) {
            data_source.addNSRecord(rel->stringValue());
        }
    }
    return isc::data::Element::createFromString("{ \"result\": [0] }");
239
}