host.cc 6.46 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// Copyright (C) 2010  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.

15
// host rewritten in C++ using BIND 10 DNS library
Jeremy C. Reed's avatar
Jeremy C. Reed committed
16 17

#include <arpa/inet.h>
18
#include <netdb.h>          // for getaddrinfo
19
#include <sys/time.h>       // for gettimeofday
20
#include <sys/socket.h>     // networking functions and definitions on FreeBSD
Jeremy C. Reed's avatar
Jeremy C. Reed committed
21

22 23
#include <unistd.h>

24
#include <string>
Jeremy C. Reed's avatar
Jeremy C. Reed committed
25 26
#include <iostream>

27 28 29 30 31 32 33 34
#include <dns/buffer.h>
#include <dns/name.h>
#include <dns/message.h>
#include <dns/messagerenderer.h>
#include <dns/rrclass.h>
#include <dns/rrtype.h>
#include <dns/rrset.h>
#include <dns/message.h>
Jeremy C. Reed's avatar
Jeremy C. Reed committed
35

36
using namespace std;
Jeremy C. Reed's avatar
Jeremy C. Reed committed
37 38
using namespace isc::dns;

39
namespace {
40
char* dns_type = NULL;    // not set, so A, AAAA, MX
41 42
const char* server = "127.0.0.1";
const char* server_port = "53";
Jeremy C. Reed's avatar
Jeremy C. Reed committed
43
int   verbose = 0;
44
int   first_time = 1;
Jeremy C. Reed's avatar
Jeremy C. Reed committed
45
bool  recursive_bit = true;
46
struct timeval before_time, after_time;
Jeremy C. Reed's avatar
Jeremy C. Reed committed
47 48

int
49
host_lookup(const char* const name, const char* const type) {
50

51
    Message msg(Message::RENDER);
Jeremy C. Reed's avatar
Jeremy C. Reed committed
52

53
    msg.setQid(0); // does this matter?
Jeremy C. Reed's avatar
Jeremy C. Reed committed
54

55
    // TODO: add switch for this
56 57 58 59 60
    msg.setOpcode(Opcode::QUERY());
    msg.setRcode(Rcode::NOERROR());
    if (recursive_bit) {
        msg.setHeaderFlag(MessageFlag::RD());    // set recursive bit
    }
61

62 63 64
    msg.addQuestion(Question(Name(name),
                             RRClass::IN(),    // IN class only for now
                             RRType(type)));  // if NULL then:
65

66 67 68
    OutputBuffer obuffer(512);
    MessageRenderer renderer(obuffer);
    msg.toWire(renderer);
69

70 71 72 73 74 75
    struct addrinfo hints, *res;
    int e;
    memset(&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM;
    hints.ai_flags = 0; // not using AI_NUMERICHOST in case to bootstrap
76
    e = getaddrinfo(server, server_port, &hints, &res);
77

78 79 80
    if (verbose) {
        cout << "Trying \"" << name << "\"\n";
    }
81

82 83 84 85 86
    if (verbose && first_time) {
        // this is only output the first time
        first_time = 0;
        cout << "Using domain server:\n";
        cout << "Name: " << server << "\n";
87 88 89 90
        // TODO: I guess I have to do a lookup to get that address and aliases
        // too
        //cout << "Address: " << address << "\n" ; // "#" << port << "\n";
        //cout << "Aliases: " << server << "\n";
91
    }
Jeremy C. Reed's avatar
Jeremy C. Reed committed
92

93 94 95 96 97 98
    int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

    if (s < 0) {
        cerr << "failed to open socket" << endl;
        return (1);
    }
99

100 101 102 103
    if (verbose) {
        gettimeofday(&before_time, NULL);
    }

104 105
    sendto(s, obuffer.getData(), obuffer.getLength(), 0, res->ai_addr,
           res->ai_addrlen);
106

107 108 109 110 111 112
    struct sockaddr_storage ss;
    struct sockaddr* sa;
    socklen_t sa_len;

    sa_len = sizeof(ss);
    sa = static_cast<struct sockaddr*>((void*)&ss);
113

114 115 116 117
    char recvbuf[4096];
    int cc;
    if ((cc = recvfrom(s, recvbuf, sizeof(recvbuf), 0, sa, &sa_len)) > 0) {
        try {
118
            Message rmsg(Message::PARSE);
119 120
            InputBuffer ibuffer(recvbuf, cc);

121
            rmsg.fromWire(ibuffer);
122
            if (!verbose) {
123 124 125 126
                  for (RRsetIterator it = rmsg.beginSection(Section::ANSWER());
                       it != rmsg.endSection(Section::ANSWER());
                       ++it) {
                      if ((*it)->getType() != RRType::A()) {
127 128
                          continue;
                      }
129 130 131

                      RdataIteratorPtr rit = (*it)->getRdataIterator();
                      for (rit->first(); !rit->isLast(); rit->next()) {
132 133
                          // instead of using my name, maybe use returned label?
                          cout << name << " has address " <<
134
                              (*rit).getCurrent().toText() << endl;
JINMEI Tatuya's avatar
JINMEI Tatuya committed
135
                      }
136 137
                  }
            } else {
138
                gettimeofday(&after_time, NULL);
Jeremy C. Reed's avatar
Jeremy C. Reed committed
139 140 141 142 143 144 145 146 147 148 149 150

                // HEADER and QUESTION, ANSWER, AUTHORITY, and ADDITIONAL
                std::cout << rmsg.toText() << std::endl;

                if (before_time.tv_usec > after_time.tv_usec) {
                    after_time.tv_usec += 1000000;
                    --after_time.tv_sec;
                }

                int elapsed_time =
                    (after_time.tv_sec - before_time.tv_sec)
                    + ((after_time.tv_usec - before_time.tv_usec))/1000;
151

152 153 154
                // TODO: if NXDOMAIN, host(1) doesn't show HEADER
                // Host hsdjkfhksjhdfkj not found: 3(NXDOMAIN)
                // TODO: figure out the new libdns way to test if NXDOMAIN
155

156
                std::cout << "Received " << cc <<
Jeremy C. Reed's avatar
Jeremy C. Reed committed
157 158 159 160
                    " bytes in " << elapsed_time << " ms\n";
                // TODO: " bytes from 127.0.0.1#53 in 0 ms

            } //verbose
161 162 163
        } catch (const exception& ex) {
            std::cerr << "parse failed for " <<
                string(name) << "/" << type << ": " << ex.what() << std::endl;
164
        } catch (...) {
165
            std::cerr << "parse failed for " << string(name) << "/" << type;
166 167 168 169 170
        }
    }

    freeaddrinfo(res);

171
    return (0);
172
} // host_lookup()
173
}
174 175

int
176
main(int argc, char* argv[]) {
Jeremy C. Reed's avatar
Jeremy C. Reed committed
177
    int c;
178

179
    while ((c = getopt(argc, argv, "p:rt:v")) != -1)
Jeremy C. Reed's avatar
Jeremy C. Reed committed
180 181 182 183 184 185 186
        switch (c) {
        case 'r':
            recursive_bit = false;
            break;
        case 't':
            dns_type = optarg;
            break;
187 188 189
        case 'p':
            server_port = optarg;
            break;
Jeremy C. Reed's avatar
Jeremy C. Reed committed
190 191 192 193 194 195
        case 'v':
            verbose = 1;
            break;
    }
    argc -= optind;
    argv += optind;
Jeremy C. Reed's avatar
Jeremy C. Reed committed
196

Jeremy C. Reed's avatar
Jeremy C. Reed committed
197 198 199
    if (argc < 1) {
        cout << "Usage: host [-vr] [-t type] hostname [server]\n";
        exit(1);
Jeremy C. Reed's avatar
Jeremy C. Reed committed
200
    }
201

Jeremy C. Reed's avatar
Jeremy C. Reed committed
202 203 204 205
    if (argc >= 2) {
      server = argv[1];
    }

206
    if (dns_type == NULL) {
Jeremy C. Reed's avatar
Jeremy C. Reed committed
207
        host_lookup(argv[0], "A");
208
        // TODO: don't do next if A doesn't exist
Jeremy C. Reed's avatar
Jeremy C. Reed committed
209 210 211 212 213
        host_lookup(argv[0], "AAAA");
        host_lookup(argv[0], "MX");
    } else {
        host_lookup(argv[0], dns_type); 
    }
214
    return (0);
Jeremy C. Reed's avatar
Jeremy C. Reed committed
215
}