]>
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 | |
e483a610 BH |
25 | #include <bitset> |
26 | #include "dnsparser.hh" | |
df136790 | 27 | #include "dns_random.hh" |
e483a610 | 28 | #include "iputils.hh" |
e483a610 BH |
29 | #include <boost/program_options.hpp> |
30 | ||
31 | #include <boost/format.hpp> | |
32 | #include <boost/utility.hpp> | |
33 | #include <boost/multi_index_container.hpp> | |
34 | #include <boost/multi_index/ordered_index.hpp> | |
35 | #include <boost/multi_index/key_extractors.hpp> | |
36 | ||
37 | #include "mplexer.hh" | |
d89592cd | 38 | #include "statbag.hh" |
e4bca3a9 | 39 | #include "arguments.hh" |
43fd645d | 40 | #include "version.hh" |
61b26744 | 41 | #include "namespaces.hh" |
e483a610 | 42 | using namespace ::boost::multi_index; |
e483a610 BH |
43 | |
44 | namespace po = boost::program_options; | |
45 | po::variables_map g_vm; | |
46 | ||
d89592cd | 47 | StatBag S; |
e4bca3a9 PD |
48 | ArgvMap &arg() |
49 | { | |
50 | static ArgvMap arg; | |
51 | return arg; | |
52 | } | |
e483a610 | 53 | |
050e6877 | 54 | static void usage() { |
e929f5f7 | 55 | cerr<<"Syntax: pdns_notify IP_ADDRESS/HOSTNAME[:PORT] DOMAIN"<<endl; |
d09ce00c PL |
56 | } |
57 | ||
e483a610 BH |
58 | int main(int argc, char** argv) |
59 | try | |
60 | { | |
fc1f7fa9 | 61 | set<ComboAddress> addrs; |
cff2753d OM |
62 | ::arg().set("rng")="auto"; |
63 | ::arg().set("entropy-source")="/dev/urandom"; | |
d09ce00c PL |
64 | |
65 | for(int n=1 ; n < argc; ++n) { | |
66 | if ((string) argv[n] == "--help") { | |
67 | usage(); | |
68 | return EXIT_SUCCESS; | |
69 | } | |
70 | ||
71 | if ((string) argv[n] == "--version") { | |
72 | cerr<<"notify "<<VERSION<<endl; | |
73 | return EXIT_SUCCESS; | |
74 | } | |
75 | } | |
76 | ||
d89592cd | 77 | if(argc!=3) { |
d09ce00c | 78 | usage(); |
d89592cd BH |
79 | exit(1); |
80 | } | |
81 | ||
fc1f7fa9 | 82 | int sock = -1; |
d89592cd BH |
83 | |
84 | // ComboAddress local("127.0.0.1", (int)0); | |
85 | // if(::bind(sock, (struct sockaddr*) &local, local.getSocklen()) < 0) | |
86 | // throw runtime_error("Failed to bind local socket to address "+local.toString()+": "+stringerror()); | |
71e063fd | 87 | |
fc1f7fa9 AT |
88 | try { |
89 | addrs.emplace(ComboAddress{argv[1], 53}); | |
90 | } catch (PDNSException &ex) { | |
91 | /* needs resolving, maybe */ | |
92 | struct addrinfo *info; | |
93 | vector<string> parts; | |
94 | boost::split(parts, argv[1], [](char c){return c == ':';}); | |
95 | if (parts.size() == 1) | |
96 | parts.push_back("domain"); | |
97 | else if (parts.size() != 2) | |
98 | throw runtime_error("Invalid hostname:port syntax"); | |
9a4b58d4 | 99 | if (getaddrinfo(parts[0].c_str(), parts[1].c_str(), NULL, &info) != 0) |
fc1f7fa9 AT |
100 | throw runtime_error("Cannot resolve '" + string(argv[1]) +"'"); |
101 | for(auto ptr = info; ptr != NULL; ptr = ptr->ai_next) | |
102 | addrs.emplace(ComboAddress{ptr->ai_addr, ptr->ai_addrlen}); | |
103 | } | |
e483a610 | 104 | |
fc1f7fa9 AT |
105 | for(const auto &addr: addrs) { |
106 | if (sock > -1) | |
107 | (void)close(sock); | |
108 | sock = socket(addr.sin4.sin_family, SOCK_DGRAM, 0); | |
109 | if(sock < 0) | |
110 | throw runtime_error("Creating socket for incoming packets: "+stringerror()); | |
111 | if(connect(sock, (struct sockaddr*)&addr, addr.getSocklen()) < 0) { | |
f044453d | 112 | cerr<<"Failed to connect to address "+addr.toStringWithPort()+": "+stringerror()<<endl; |
fc1f7fa9 AT |
113 | continue; |
114 | } | |
115 | vector<uint8_t> outpacket; | |
116 | DNSPacketWriter pw(outpacket, DNSName(argv[2]), QType::SOA, 1, Opcode::Notify); | |
a410b176 | 117 | pw.getHeader()->id = dns_random_uint16(); |
e483a610 | 118 | |
fc1f7fa9 | 119 | if(send(sock, &outpacket[0], outpacket.size(), 0) < 0) { |
f044453d | 120 | cerr<<"Unable to send notify to "<<addr.toStringWithPort()<<": "+stringerror()<<endl; |
fc1f7fa9 AT |
121 | continue; |
122 | } | |
e483a610 | 123 | |
fc1f7fa9 | 124 | char buffer[1500]; |
5648c27c AT |
125 | fd_set rfds; |
126 | FD_ZERO(&rfds); | |
127 | FD_SET(sock, &rfds); | |
eace2c24 RG |
128 | fd_set errfds; |
129 | FD_ZERO(&errfds); | |
130 | FD_SET(sock, &errfds); | |
5648c27c AT |
131 | int len; |
132 | struct timeval tv; | |
133 | bool timeout = true; | |
134 | ||
135 | for(int tries=0; tries<60; tries++) { | |
136 | tv.tv_sec = 1; | |
137 | tv.tv_usec = 0; | |
eace2c24 | 138 | if ((len = select(sock+1, &rfds, nullptr, &errfds, &tv)) > 0) { |
5648c27c AT |
139 | len = recv(sock, buffer, sizeof(buffer), 0); |
140 | timeout = false; | |
141 | break; | |
142 | } | |
143 | } | |
e483a610 | 144 | |
fc1f7fa9 | 145 | if(len < 0) { |
f044453d | 146 | cerr<<"Unable to receive notification response from "<<addr.toStringWithPort()<<": "+stringerror()<<endl; |
fc1f7fa9 | 147 | continue; |
5648c27c | 148 | } else if (timeout) { |
f044453d | 149 | cerr<<"Unable to receive notification response from "<<addr.toStringWithPort()<<": Timed out"<<endl; |
5648c27c AT |
150 | continue; |
151 | } else if (len == 0) { | |
f044453d | 152 | cerr<<"Unable to receive notification response from "<<addr.toStringWithPort()<<": EOF"<<endl; |
5648c27c | 153 | continue; |
fc1f7fa9 AT |
154 | } |
155 | ||
156 | string packet(buffer, len); | |
157 | MOADNSParser mdp(false, packet); | |
158 | ||
f044453d AT |
159 | if (mdp.d_header.rcode == 0) |
160 | cerr<<"Successfully notified "<<addr.toStringWithPort()<<endl; | |
161 | else | |
162 | cerr<<"Received notification response with error from "<<addr.toStringWithPort()<<": "<<RCode::to_s(mdp.d_header.rcode)<<endl; | |
fc1f7fa9 AT |
163 | cerr<<"For: '"<<mdp.d_qname<<"'"<<endl; |
164 | } | |
e483a610 | 165 | } |
adc10f99 | 166 | catch(std::exception& e) |
e483a610 BH |
167 | { |
168 | cerr<<"Fatal: "<<e.what()<<endl; | |
169 | } | |
170 |