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  */
22 #include "query-local-address.hh"
23 #include "iputils.hh"
24 #include "dns_random.hh"
25 
26 namespace pdns {
27   static const ComboAddress local4("0.0.0.0");
28   static const ComboAddress local6("::");
29 
30   static vector<ComboAddress> g_localQueryAddresses4;
31   static vector<ComboAddress> g_localQueryAddresses6;
32 
getQueryLocalAddress(const sa_family_t family,const in_port_t port)33   ComboAddress getQueryLocalAddress(const sa_family_t family, const in_port_t port) {
34     ComboAddress ret;
35     if (family==AF_INET) {
36       if (g_localQueryAddresses4.empty()) {
37         ret = local4;
38       } else if (g_localQueryAddresses4.size() == 1) {
39         ret = g_localQueryAddresses4.at(0);
40       } else {
41         ret = g_localQueryAddresses4[dns_random(g_localQueryAddresses4.size())];
42       }
43       ret.sin4.sin_port = htons(port);
44     }
45     else {
46       if (g_localQueryAddresses6.empty()) {
47         ret = local6;
48       } else if (g_localQueryAddresses6.size() == 1) {
49         ret = g_localQueryAddresses6.at(0);
50       } else {
51         ret = g_localQueryAddresses6[dns_random(g_localQueryAddresses6.size())];
52       }
53       ret.sin6.sin6_port = htons(port);
54     }
55     return ret;
56   }
57 
getNonAnyQueryLocalAddress(const sa_family_t family)58   ComboAddress getNonAnyQueryLocalAddress(const sa_family_t family) {
59     if (family == AF_INET) {
60       for (const auto& addr : pdns::g_localQueryAddresses4) {
61         if (!IsAnyAddress(addr)) {
62           return addr;
63         }
64       }
65     }
66     if (family == AF_INET6) {
67       for (const auto& addr : pdns::g_localQueryAddresses6) {
68         if (!IsAnyAddress(addr)) {
69           return addr;
70         }
71       }
72     }
73     ComboAddress ret("0.0.0.0");
74     ret.reset(); // Ensure all is zero, even the addr family
75     return ret;
76   }
77 
parseQueryLocalAddress(const std::string & qla)78   void parseQueryLocalAddress(const std::string &qla) {
79     vector<string> addrs;
80     stringtok(addrs, qla, ", ;");
81     for(const string& addr : addrs) {
82       ComboAddress tmp(addr);
83       if (tmp.isIPv4()) {
84         g_localQueryAddresses4.push_back(tmp);
85         continue;
86       }
87       g_localQueryAddresses6.push_back(tmp);
88     }
89   }
90 
isQueryLocalAddressFamilyEnabled(const sa_family_t family)91   bool isQueryLocalAddressFamilyEnabled(const sa_family_t family) {
92     if (family == AF_INET) {
93       return !g_localQueryAddresses4.empty();
94     }
95     if (family == AF_INET6) {
96       return !g_localQueryAddresses6.empty();
97     }
98     return false;
99   }
100 } // namespace pdns
101