diff --git a/src/auth.c b/src/auth.c index 050fe16..a59a1b5 100644 --- a/src/auth.c +++ b/src/auth.c @@ -72,7 +72,7 @@ static int in_zone(struct auth_zone *zone, char *name, char **cut) } -size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now) +size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr) { char *name = daemon->namebuff; unsigned char *p, *ansp; @@ -357,6 +357,35 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n } else if (qtype == T_AXFR) { + if (daemon->auth_peers) + { + struct iname *peers; + + if (peer_addr->sa.sa_family == AF_INET) + peer_addr->in.sin_port = 0; +#ifdef HAVE_IPV6 + else + peer_addr->in6.sin6_port = 0; +#endif + + for (peers = daemon->auth_peers; peers; peers = peers->next) + if (sockaddr_isequal(peer_addr, &peers->addr)) + break; + + if (!peers) + { + if (peer_addr->sa.sa_family == AF_INET) + inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN); +#ifdef HAVE_IPV6 + else + inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN); +#endif + + my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff); + return 0; + } + } + soa = 1; /* inhibits auth section */ ns = 1; /* ensure we include NS records! */ axfr = 1; diff --git a/src/dnsmasq.h b/src/dnsmasq.h index 0d9ab7e..4fd9e56 100644 --- a/src/dnsmasq.h +++ b/src/dnsmasq.h @@ -762,7 +762,7 @@ extern struct daemon { struct cond_domain *cond_domain; char *runfile; char *lease_change_command; - struct iname *if_names, *if_addrs, *if_except, *dhcp_except; + struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers; struct bogus_addr *bogus_addr; struct server *servers; int log_fac; /* log facility */ @@ -909,7 +909,7 @@ int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, int in_arpa_name_2_addr(char *namein, struct all_addr *addrp); /* auth.c */ -size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now); +size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr); /* util.c */ void rand_init(void); diff --git a/src/forward.c b/src/forward.c index e93aada..95807f8 100644 --- a/src/forward.c +++ b/src/forward.c @@ -814,7 +814,7 @@ void receive_query(struct listener *listen, time_t now) if (auth_dns) { - m = answer_auth(header, ((char *) header) + PACKETSZ, (size_t)n, now); + m = answer_auth(header, ((char *) header) + PACKETSZ, (size_t)n, now, &source_addr); if (m >= 1) send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND), (char *)header, m, &source_addr, &dst_addr, if_index); @@ -904,7 +904,7 @@ unsigned char *tcp_request(int confd, time_t now, dst_addr_4.s_addr = 0; if (auth_dns) - m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now); + m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr); else { /* m > 0 if answered from cache */ @@ -1043,7 +1043,8 @@ unsigned char *tcp_request(int confd, time_t now, c1 = m>>8; c2 = m; - if (!read_write(confd, &c1, 1, 0) || + if (m == 0 || + !read_write(confd, &c1, 1, 0) || !read_write(confd, &c2, 1, 0) || !read_write(confd, packet, m, 0)) return packet; diff --git a/src/option.c b/src/option.c index d32f264..c1643a1 100644 --- a/src/option.c +++ b/src/option.c @@ -126,6 +126,7 @@ struct myoption { #define LOPT_AUTHTTL 315 #define LOPT_AUTHSOA 316 #define LOPT_AUTHSFS 317 +#define LOPT_AUTHPEER 318 #ifdef HAVE_GETOPT_LONG static const struct option opts[] = @@ -257,6 +258,7 @@ static const struct myoption opts[] = { "auth-ttl", 1, 0, LOPT_AUTHTTL }, { "auth-soa", 1, 0, LOPT_AUTHSOA }, { "auth-sec-servers", 1, 0, LOPT_AUTHSFS }, + { "auth-peer", 1, 0, LOPT_AUTHPEER }, { NULL, 0, 0, 0 } }; @@ -393,7 +395,8 @@ static struct { { LOPT_AUTHZONE, ARG_DUP, ",[,]", gettext_noop("Domain to export to global DNS"), NULL }, { LOPT_AUTHTTL, ARG_ONE, "", gettext_noop("Set TTL for authoritative replies"), NULL }, { LOPT_AUTHSOA, ARG_ONE, "[,...]", gettext_noop("Set authoritive zone information"), NULL }, - { LOPT_AUTHSFS, ARG_ONE, "[,...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL }, + { LOPT_AUTHSFS, ARG_DUP, "[,...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL }, + { LOPT_AUTHPEER, ARG_DUP, "[,...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL }, { 0, 0, NULL, NULL, NULL } }; @@ -1871,14 +1874,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma } case 'a': /* --listen-address */ + case LOPT_AUTHPEER: /* --auth-peer */ do { struct iname *new = opt_malloc(sizeof(struct iname)); comma = split(arg); unhide_metas(arg); - new->next = daemon->if_addrs; if (arg && (new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1) { new->addr.sa.sa_family = AF_INET; + new->addr.in.sin_port = 0; #ifdef HAVE_SOCKADDR_SA_LEN new->addr.in.sin_len = sizeof(new->addr.in); #endif @@ -1889,6 +1893,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma new->addr.sa.sa_family = AF_INET6; new->addr.in6.sin6_flowinfo = 0; new->addr.in6.sin6_scope_id = 0; + new->addr.in6.sin6_port = 0; #ifdef HAVE_SOCKADDR_SA_LEN new->addr.in6.sin6_len = sizeof(new->addr.in6); #endif @@ -1898,7 +1903,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma ret_err(gen_err); new->used = 0; - daemon->if_addrs = new; + if (option == 'a') + { + new->next = daemon->if_addrs; + daemon->if_addrs = new; + } + else + { + new->next = daemon->auth_peers; + daemon->auth_peers = new; + } arg = comma; } while (arg); break;