mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
import of dnsmasq-2.10.tar.gz
This commit is contained in:
68
CHANGELOG
68
CHANGELOG
@@ -1056,3 +1056,71 @@ release 2.9
|
|||||||
Allow # as the argument to --domain, meaning "read the
|
Allow # as the argument to --domain, meaning "read the
|
||||||
domain from the first search directive in
|
domain from the first search directive in
|
||||||
/etc.resolv.conf". Feature suggested by Evan Jones.
|
/etc.resolv.conf". Feature suggested by Evan Jones.
|
||||||
|
|
||||||
|
release 2.10
|
||||||
|
Allow --query-port to be set to a low port by creating and
|
||||||
|
binding the socket before dropping root. (Suggestion from
|
||||||
|
Jamie Lokier)
|
||||||
|
|
||||||
|
Support TCP queries. It turned out to be possible to do
|
||||||
|
this with a couple of hundred lines of code, once I knew
|
||||||
|
how. The executable size went up by a few K on i386.
|
||||||
|
There are a few limitations: data obtained via TCP is not
|
||||||
|
cached, and dynamically-created interfaces may break under
|
||||||
|
certain circumstances. Source-address or query-port
|
||||||
|
specifications are ignored for TCP.
|
||||||
|
|
||||||
|
NAK attempts to renew a DHCP lease where the DHCP range
|
||||||
|
has changed and the lease is no longer in the allowed
|
||||||
|
range. Jamie Lokier pointed out this bug.
|
||||||
|
|
||||||
|
NAK attempts to renew a pool DHCP lease when a statically
|
||||||
|
allocated address has become available, forcing a host to
|
||||||
|
move to it's allocated address. Lots of people have
|
||||||
|
suggested this change and been rebuffed (they know who
|
||||||
|
they are) the straws that broke the camel's back were Tim
|
||||||
|
Cutts and Jamie Lokier.
|
||||||
|
|
||||||
|
Remove any nameserver records from answers which are
|
||||||
|
modified by --alias flags. If the answer is modified, it
|
||||||
|
cannot any longer be authoritative.
|
||||||
|
|
||||||
|
Change behaviour of "bogus-priv" option to return NXDOMAIN
|
||||||
|
rather than a PTR record with the dotted-quad address as
|
||||||
|
name. The new behaviour doesn't provoke tcpwrappers like
|
||||||
|
the old behavior did.
|
||||||
|
|
||||||
|
Added a patch for the Suse rpm. That changes the default
|
||||||
|
group to one suitable for Suse and disables inclusion of
|
||||||
|
the ISC lease-file reader code. Thanks to Andy Cambeis for
|
||||||
|
his ongoing work on Suse packaging.
|
||||||
|
|
||||||
|
Support forwarding of EDNS.0 The maximum UDP packet size
|
||||||
|
defaults to 1280, but may be changed with the
|
||||||
|
--edns-packet-max option. Detect queries with the do bit
|
||||||
|
set and always forward them, since DNSSEC records are
|
||||||
|
not cached. This behaviour is required to make
|
||||||
|
DNSSECbis work properly though dnsmasq. Thanks to Simon
|
||||||
|
Josefsson for help with this.
|
||||||
|
|
||||||
|
Move default config file location under OpenBSD from
|
||||||
|
/usr/local/etc/dnsmasq.conf to /etc/dnsmasq.conf. Bug
|
||||||
|
report from Jonathan Weiss.
|
||||||
|
|
||||||
|
Use a lease with matching MAC address for a host which
|
||||||
|
doesn't present a client-id, even if there was a client ID
|
||||||
|
at some point in the past. This reduces surprises when
|
||||||
|
changing DHCP clients, adding id:* to a host, and from the
|
||||||
|
semantics change of /etc/ethers in 2.9. Thanks to Bernard
|
||||||
|
Sammer for finding that.
|
||||||
|
|
||||||
|
Added a "contrib" directory and in it the dnslist utility,
|
||||||
|
from Thomas Tuttle.
|
||||||
|
|
||||||
|
Fixed "fail to start up" problems under Linux with IPv6
|
||||||
|
enabled. It's not clear that these were an issue in
|
||||||
|
released versions, but they manifested themselves when TCP
|
||||||
|
support was added. Thanks to Michael Hamilton for
|
||||||
|
assistance with this.
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
12
FAQ
12
FAQ
@@ -20,12 +20,10 @@ A: The high ports that dnsmasq opens is for replies from the upstream
|
|||||||
Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify
|
Q: Why doesn't dnsmasq support DNS queries over TCP? Don't the RFC's specify
|
||||||
that?
|
that?
|
||||||
|
|
||||||
A: Yes, they do, so technically dnsmasq is not RFC-compliant. In practice, the
|
A: Update: from version 2.10, it does. There are a few limitations:
|
||||||
sorts of queries which dnsmasq is used for are always sent via UDP. Adding
|
data obtained via TCP is not cached, and dynamically-created
|
||||||
TCP support would make dnsmasq much more heavyweight for no practical
|
interfaces may break under certain circumstances. Source-address
|
||||||
benefit. If you really want to do zone transfers, forward port 53 TCP
|
or query-port specifications are ignored for TCP.
|
||||||
using in-kernel port-forwarding or a port-fowarder like rinetd.
|
|
||||||
|
|
||||||
|
|
||||||
Q: When I send SIGUSR1 to dump the contents of the cache, some entries have
|
Q: When I send SIGUSR1 to dump the contents of the cache, some entries have
|
||||||
no IP address and are for names like mymachine.mydomain.com.mydomain.com.
|
no IP address and are for names like mymachine.mydomain.com.mydomain.com.
|
||||||
@@ -74,6 +72,8 @@ A: Use the standard DNS convention of <reversed address>.in-addr.arpa.
|
|||||||
For instance to send reverse queries on the range 192.168.0.0 to
|
For instance to send reverse queries on the range 192.168.0.0 to
|
||||||
192.168.0.255 to a nameserver at 10.0.0.1 do
|
192.168.0.255 to a nameserver at 10.0.0.1 do
|
||||||
server=/0.168.192.in-addr.arpa/10.0.0.1
|
server=/0.168.192.in-addr.arpa/10.0.0.1
|
||||||
|
Note that the "bogus-priv" option take priority over this option,
|
||||||
|
so the above will not work when the bogus-priv option is set.
|
||||||
|
|
||||||
Q: Dnsmasq fails to start with an error like this: "dnsmasq: bind
|
Q: Dnsmasq fails to start with an error like this: "dnsmasq: bind
|
||||||
failed: Cannot assign requested address". What's the problem?
|
failed: Cannot assign requested address". What's the problem?
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -10,7 +10,7 @@ all :
|
|||||||
@cd $(SRC); $(MAKE) dnsmasq
|
@cd $(SRC); $(MAKE) dnsmasq
|
||||||
|
|
||||||
clean :
|
clean :
|
||||||
rm -f *~ */*~ $(SRC)/*.o $(SRC)/dnsmasq core build
|
rm -f *~ contrib/*/*~ */*~ $(SRC)/*.o $(SRC)/dnsmasq core build
|
||||||
|
|
||||||
install : all
|
install : all
|
||||||
install -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
|
install -d $(DESTDIR)$(BINDIR) -d $(DESTDIR)$(MANDIR)/man8
|
||||||
|
|||||||
57
contrib/dnslist/dhcp.css
Normal file
57
contrib/dnslist/dhcp.css
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
body
|
||||||
|
{
|
||||||
|
font-family: sans-serif;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1
|
||||||
|
{
|
||||||
|
font-size: medium;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 .updated
|
||||||
|
{
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
table
|
||||||
|
{
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-bottom: 2px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
th
|
||||||
|
{
|
||||||
|
background: #DDD;
|
||||||
|
border-top: 2px solid #000;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Any row */
|
||||||
|
|
||||||
|
tr
|
||||||
|
{
|
||||||
|
border-top: 2px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Any row but the first or second (overrides above rule) */
|
||||||
|
|
||||||
|
tr + tr + tr
|
||||||
|
{
|
||||||
|
border-top: 2px solid #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
tr.offline td.hostname
|
||||||
|
{
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hostname { width: 10em; }
|
||||||
|
.ip_addr { width: 10em; background: #DDD; }
|
||||||
|
.ether_addr { width: 15em; }
|
||||||
|
.client_id { width: 15em; background: #DDD; }
|
||||||
|
.status { width: 5em; }
|
||||||
|
.since { width: 10em; background: #DDD; }
|
||||||
|
.lease { width: 10em; }
|
||||||
608
contrib/dnslist/dnslist.pl
Executable file
608
contrib/dnslist/dnslist.pl
Executable file
@@ -0,0 +1,608 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
# dnslist - Read state file from dnsmasq and create a nice web page to display
|
||||||
|
# a list of DHCP clients.
|
||||||
|
#
|
||||||
|
# Copyright (C) 2004 Thomas Tuttle
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTIBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program*; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
# * The license is in fact included at the end of this file, and can
|
||||||
|
# either be viewed by reading everything after "__DATA__" or by
|
||||||
|
# running dnslist with the '-l' option.
|
||||||
|
#
|
||||||
|
# Version: 0.2
|
||||||
|
# Author: Thomas Tuttle
|
||||||
|
# Email: dnslist.20.thinkinginbinary@spamgourmet.org
|
||||||
|
# License: GNU General Public License, version 2.0
|
||||||
|
#
|
||||||
|
# v. 0.0: Too ugly to publish, thrown out.
|
||||||
|
#
|
||||||
|
# v. 0.1: First rewrite.
|
||||||
|
# Added master host list so offline hosts can still be displayed.
|
||||||
|
# Fixed modification detection (a newer modification time is lower.)
|
||||||
|
#
|
||||||
|
# v. 0.2: Fixed Client ID = "*" => "None"
|
||||||
|
# Fixed HTML entities (a client ID of ????<? screwed it up)
|
||||||
|
# Fixed command-line argument processing (apparently, "shift @ARGV" !=
|
||||||
|
# "$_ = shift @ARGV"...)
|
||||||
|
# Added license information.
|
||||||
|
|
||||||
|
use Template;
|
||||||
|
|
||||||
|
# Location of state file. (This is the dnsmasq default.)
|
||||||
|
# Change with -s <file>
|
||||||
|
my $dnsmasq_state_file = '/var/lib/misc/dnsmasq.leases';
|
||||||
|
# Location of template. (Assumed to be in current directory.)
|
||||||
|
# Change with -t <file>
|
||||||
|
my $html_template_file = 'dnslist.tt2';
|
||||||
|
# File to write HTML page to. (This is where Slackware puts WWW pages. It may
|
||||||
|
# be different on other systems. Make sure the permissions are set correctly
|
||||||
|
# for it.)
|
||||||
|
my $html_output_file = '/var/www/htdocs/dhcp.html';
|
||||||
|
# Time to wait after each page update. (The state file is checked for changes
|
||||||
|
# before each update but is not read in each time, in case it is very big. The
|
||||||
|
# page is rewritten just so the "(updated __/__ __:__:__)" text changes ;-)
|
||||||
|
my $wait_time = 2;
|
||||||
|
|
||||||
|
# Read command-line arguments.
|
||||||
|
while ($_ = shift @ARGV) {
|
||||||
|
if (/-s/) { $dnsmasq_state_file = shift; next; }
|
||||||
|
if (/-t/) { $html_template_file = shift; next; }
|
||||||
|
if (/-o/) { $html_output_file = shift; next; }
|
||||||
|
if (/-d/) { $wait_time = shift; next; }
|
||||||
|
if (/-l/) { show_license(); exit; }
|
||||||
|
die "usage: dnslist [-s state_file] [-t template_file] [-o output_file] [-d delay_time]\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Master list of clients, offline and online.
|
||||||
|
my $list = {};
|
||||||
|
# Sorted host list. (It's actually sorted by IP--the sub &byip() compares two
|
||||||
|
# IP addresses, octet by octet, and figures out which is higher.)
|
||||||
|
my @hosts = ();
|
||||||
|
# Last time the state file was changed.
|
||||||
|
my $last_state_change;
|
||||||
|
|
||||||
|
# Check for a change to the state file.
|
||||||
|
sub check_state {
|
||||||
|
if (defined $last_state_change) {
|
||||||
|
if (-M $dnsmasq_state_file < $last_state_change) {
|
||||||
|
print "check_state: state file has been changed.\n";
|
||||||
|
$last_state_change = -M $dnsmasq_state_file;
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# Last change undefined, so we are running for the first time.
|
||||||
|
print "check_state: reading state file at startup.\n";
|
||||||
|
read_state();
|
||||||
|
$last_state_change = -M $dnsmasq_state_file;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Read data in state file.
|
||||||
|
sub read_state {
|
||||||
|
my $old;
|
||||||
|
my $new;
|
||||||
|
# Open file.
|
||||||
|
unless (open STATE, $dnsmasq_state_file) {
|
||||||
|
warn "read_state: can't open $dnsmasq_state_file!\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
# Mark all hosts as offline, saving old state.
|
||||||
|
foreach $ether (keys %{$list}) {
|
||||||
|
$list->{$ether}->{'old_online'} = $list->{$ether}->{'online'};
|
||||||
|
$list->{$ether}->{'online'} = 0;
|
||||||
|
}
|
||||||
|
# Read hosts.
|
||||||
|
while (<STATE>) {
|
||||||
|
chomp;
|
||||||
|
@host{qw/raw_lease ether_addr ip_addr hostname raw_client_id/} = split /\s+/;
|
||||||
|
$ether = $host{ether_addr};
|
||||||
|
# Mark each online host as online.
|
||||||
|
$list->{$ether}->{'online'} = 1;
|
||||||
|
# Copy data to master list.
|
||||||
|
foreach $key (keys %host) {
|
||||||
|
$list->{$ether}->{$key} = $host{$key};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close STATE;
|
||||||
|
# Handle changes in offline/online state. (The sub &do_host() handles
|
||||||
|
# all of the extra stuff to do with a host's data once it is read.
|
||||||
|
foreach $ether (keys %{$list}) {
|
||||||
|
$old = $list->{$ether}->{'old_online'};
|
||||||
|
$new = $list->{$ether}->{'online'};
|
||||||
|
if (not $old) {
|
||||||
|
if (not $new) {
|
||||||
|
do_host($ether, 'offline');
|
||||||
|
} else {
|
||||||
|
do_host($ether, 'join');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (not $new) {
|
||||||
|
do_host($ether, 'leave');
|
||||||
|
} else {
|
||||||
|
do_host($ether, 'online');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
# Sort hosts by IP ;-)
|
||||||
|
@hosts = sort byip values %{$list};
|
||||||
|
# Copy sorted list to template data store.
|
||||||
|
$data->{'hosts'} = [ @hosts ];
|
||||||
|
}
|
||||||
|
|
||||||
|
# Do stuff per host.
|
||||||
|
sub do_host {
|
||||||
|
my ($ether, $status) = @_;
|
||||||
|
|
||||||
|
# Find textual representation of DHCP client ID.
|
||||||
|
if ($list->{$ether}->{'raw_client_id'} eq '*') {
|
||||||
|
$list->{$ether}->{'text_client_id'} = 'None';
|
||||||
|
} else {
|
||||||
|
my $text = "";
|
||||||
|
foreach $char (split /:/, $list->{$ether}->{'raw_client_id'}) {
|
||||||
|
$char = pack('H2', $char);
|
||||||
|
if (ord($char) >= 32 and ord($char) <= 127) {
|
||||||
|
$text .= $char;
|
||||||
|
} else {
|
||||||
|
$text .= "?";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$list->{$ether}->{'text_client_id'} = $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert lease expiration date/time to text.
|
||||||
|
if ($list->{$ether}->{'raw_lease'} == 0) {
|
||||||
|
$list->{$ether}->{'text_lease'} = 'Never';
|
||||||
|
} else {
|
||||||
|
$list->{$ether}->{'text_lease'} = nice_time($list->{$ether}->{'raw_lease'});
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($status eq 'offline') {
|
||||||
|
# Nothing to do.
|
||||||
|
} elsif ($status eq 'online') {
|
||||||
|
# Nothing to do.
|
||||||
|
} elsif ($status eq 'join') {
|
||||||
|
# Update times for joining host.
|
||||||
|
print "do_host: $ether joined the network.\n";
|
||||||
|
$list->{$ether}->{'join_time'} = time;
|
||||||
|
$list->{$ether}->{'since'} = nice_time(time);
|
||||||
|
} elsif ($status eq 'leave') {
|
||||||
|
# Update times for leaving host.
|
||||||
|
print "do_host: $ether left the network.\n";
|
||||||
|
$list->{$ether}->{'leave_time'} = time;
|
||||||
|
$list->{$ether}->{'since'} = nice_time(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
# Convert time to a string representation.
|
||||||
|
sub nice_time {
|
||||||
|
my $time = shift;
|
||||||
|
my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $dst) = localtime($time);
|
||||||
|
$sec = pad($sec, '0', 2);
|
||||||
|
$min = pad($min, '0', 2);
|
||||||
|
$hour = pad($hour, '0', 2);
|
||||||
|
$mon = pad($mon, '0', 2);
|
||||||
|
$mday = pad($mday, '0', 2);
|
||||||
|
return "$mon/$mday $hour:$min:$sec";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Pad string to a certain length by repeatedly prepending another string.
|
||||||
|
sub pad {
|
||||||
|
my ($text, $pad, $length) = @_;
|
||||||
|
while (length($text) < $length) {
|
||||||
|
$text = "$pad$text";
|
||||||
|
}
|
||||||
|
return $text;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compare two IP addresses. (Uses $a and $b from sort.)
|
||||||
|
sub byip {
|
||||||
|
# Split into octets.
|
||||||
|
my @a = split /\./, $a->{ip_addr};
|
||||||
|
my @b = split /\./, $b->{ip_addr};
|
||||||
|
# Compare octets.
|
||||||
|
foreach $n (0..3) {
|
||||||
|
return $a[$n] <=> $b[$n] if ($a[$n] != $b[$n]);
|
||||||
|
}
|
||||||
|
# If we get here there is no difference.
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Output HTML file.
|
||||||
|
sub write_output {
|
||||||
|
# Create new template object.
|
||||||
|
my $template = Template->new(
|
||||||
|
{
|
||||||
|
ABSOLUTE => 1, # /var/www/... is an absolute path
|
||||||
|
OUTPUT => $html_output_file # put it here, not STDOUT
|
||||||
|
}
|
||||||
|
);
|
||||||
|
$data->{'updated'} = nice_time(time); # add "(updated ...)" to file
|
||||||
|
unless ($template->process($html_template_file, $data)) { # do it
|
||||||
|
warn "write_output: Template Toolkit error: " . $template->error() . "\n";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
print "write_output: page updated.\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub show_license {
|
||||||
|
while (<DATA>) {
|
||||||
|
print;
|
||||||
|
$line++;
|
||||||
|
if ($line == 24) { <>; $line = 1; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Main loop.
|
||||||
|
while (1) {
|
||||||
|
# Check for state change.
|
||||||
|
if (check_state()) {
|
||||||
|
read_state();
|
||||||
|
sleep 1; # Sleep for a second just so we don't wear anything
|
||||||
|
# out. (By not sleeping the whole time after a change
|
||||||
|
# we can detect rapid changes more easily--like if 300
|
||||||
|
# hosts all come back online, they show up quicker.)
|
||||||
|
} else {
|
||||||
|
sleep $wait_time; # Take a nap.
|
||||||
|
}
|
||||||
|
write_output(); # Write the file anyway.
|
||||||
|
}
|
||||||
|
__DATA__
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
Version 2, June 1991
|
||||||
|
|
||||||
|
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||||
|
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
Preamble
|
||||||
|
|
||||||
|
The licenses for most software are designed to take away your
|
||||||
|
freedom to share and change it. By contrast, the GNU General Public
|
||||||
|
License is intended to guarantee your freedom to share and change free
|
||||||
|
software--to make sure the software is free for all its users. This
|
||||||
|
General Public License applies to most of the Free Software
|
||||||
|
Foundation's software and to any other program whose authors commit to
|
||||||
|
using it. (Some other Free Software Foundation software is covered by
|
||||||
|
the GNU Library General Public License instead.) You can apply it to
|
||||||
|
your programs, too.
|
||||||
|
|
||||||
|
When we speak of free software, we are referring to freedom, not
|
||||||
|
price. Our General Public Licenses are designed to make sure that you
|
||||||
|
have the freedom to distribute copies of free software (and charge for
|
||||||
|
this service if you wish), that you receive source code or can get it
|
||||||
|
if you want it, that you can change the software or use pieces of it
|
||||||
|
in new free programs; and that you know you can do these things.
|
||||||
|
|
||||||
|
To protect your rights, we need to make restrictions that forbid
|
||||||
|
anyone to deny you these rights or to ask you to surrender the rights.
|
||||||
|
These restrictions translate to certain responsibilities for you if you
|
||||||
|
distribute copies of the software, or if you modify it.
|
||||||
|
|
||||||
|
For example, if you distribute copies of such a program, whether
|
||||||
|
gratis or for a fee, you must give the recipients all the rights that
|
||||||
|
you have. You must make sure that they, too, receive or can get the
|
||||||
|
source code. And you must show them these terms so they know their
|
||||||
|
rights.
|
||||||
|
|
||||||
|
We protect your rights with two steps: (1) copyright the software, and
|
||||||
|
(2) offer you this license which gives you legal permission to copy,
|
||||||
|
distribute and/or modify the software.
|
||||||
|
|
||||||
|
Also, for each author's protection and ours, we want to make certain
|
||||||
|
that everyone understands that there is no warranty for this free
|
||||||
|
software. If the software is modified by someone else and passed on, we
|
||||||
|
want its recipients to know that what they have is not the original, so
|
||||||
|
that any problems introduced by others will not reflect on the original
|
||||||
|
authors' reputations.
|
||||||
|
|
||||||
|
Finally, any free program is threatened constantly by software
|
||||||
|
patents. We wish to avoid the danger that redistributors of a free
|
||||||
|
program will individually obtain patent licenses, in effect making the
|
||||||
|
program proprietary. To prevent this, we have made it clear that any
|
||||||
|
patent must be licensed for everyone's free use or not licensed at all.
|
||||||
|
|
||||||
|
The precise terms and conditions for copying, distribution and
|
||||||
|
modification follow.
|
||||||
|
|
||||||
|
GNU GENERAL PUBLIC LICENSE
|
||||||
|
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||||
|
|
||||||
|
0. This License applies to any program or other work which contains
|
||||||
|
a notice placed by the copyright holder saying it may be distributed
|
||||||
|
under the terms of this General Public License. The "Program", below,
|
||||||
|
refers to any such program or work, and a "work based on the Program"
|
||||||
|
means either the Program or any derivative work under copyright law:
|
||||||
|
that is to say, a work containing the Program or a portion of it,
|
||||||
|
either verbatim or with modifications and/or translated into another
|
||||||
|
language. (Hereinafter, translation is included without limitation in
|
||||||
|
the term "modification".) Each licensee is addressed as "you".
|
||||||
|
|
||||||
|
Activities other than copying, distribution and modification are not
|
||||||
|
covered by this License; they are outside its scope. The act of
|
||||||
|
running the Program is not restricted, and the output from the Program
|
||||||
|
is covered only if its contents constitute a work based on the
|
||||||
|
Program (independent of having been made by running the Program).
|
||||||
|
Whether that is true depends on what the Program does.
|
||||||
|
|
||||||
|
1. You may copy and distribute verbatim copies of the Program's
|
||||||
|
source code as you receive it, in any medium, provided that you
|
||||||
|
conspicuously and appropriately publish on each copy an appropriate
|
||||||
|
copyright notice and disclaimer of warranty; keep intact all the
|
||||||
|
notices that refer to this License and to the absence of any warranty;
|
||||||
|
and give any other recipients of the Program a copy of this License
|
||||||
|
along with the Program.
|
||||||
|
|
||||||
|
You may charge a fee for the physical act of transferring a copy, and
|
||||||
|
you may at your option offer warranty protection in exchange for a fee.
|
||||||
|
|
||||||
|
2. You may modify your copy or copies of the Program or any portion
|
||||||
|
of it, thus forming a work based on the Program, and copy and
|
||||||
|
distribute such modifications or work under the terms of Section 1
|
||||||
|
above, provided that you also meet all of these conditions:
|
||||||
|
|
||||||
|
a) You must cause the modified files to carry prominent notices
|
||||||
|
stating that you changed the files and the date of any change.
|
||||||
|
|
||||||
|
b) You must cause any work that you distribute or publish, that in
|
||||||
|
whole or in part contains or is derived from the Program or any
|
||||||
|
part thereof, to be licensed as a whole at no charge to all third
|
||||||
|
parties under the terms of this License.
|
||||||
|
|
||||||
|
c) If the modified program normally reads commands interactively
|
||||||
|
when run, you must cause it, when started running for such
|
||||||
|
interactive use in the most ordinary way, to print or display an
|
||||||
|
announcement including an appropriate copyright notice and a
|
||||||
|
notice that there is no warranty (or else, saying that you provide
|
||||||
|
a warranty) and that users may redistribute the program under
|
||||||
|
these conditions, and telling the user how to view a copy of this
|
||||||
|
License. (Exception: if the Program itself is interactive but
|
||||||
|
does not normally print such an announcement, your work based on
|
||||||
|
the Program is not required to print an announcement.)
|
||||||
|
|
||||||
|
These requirements apply to the modified work as a whole. If
|
||||||
|
identifiable sections of that work are not derived from the Program,
|
||||||
|
and can be reasonably considered independent and separate works in
|
||||||
|
themselves, then this License, and its terms, do not apply to those
|
||||||
|
sections when you distribute them as separate works. But when you
|
||||||
|
distribute the same sections as part of a whole which is a work based
|
||||||
|
on the Program, the distribution of the whole must be on the terms of
|
||||||
|
this License, whose permissions for other licensees extend to the
|
||||||
|
entire whole, and thus to each and every part regardless of who wrote it.
|
||||||
|
|
||||||
|
Thus, it is not the intent of this section to claim rights or contest
|
||||||
|
your rights to work written entirely by you; rather, the intent is to
|
||||||
|
exercise the right to control the distribution of derivative or
|
||||||
|
collective works based on the Program.
|
||||||
|
|
||||||
|
In addition, mere aggregation of another work not based on the Program
|
||||||
|
with the Program (or with a work based on the Program) on a volume of
|
||||||
|
a storage or distribution medium does not bring the other work under
|
||||||
|
the scope of this License.
|
||||||
|
|
||||||
|
3. You may copy and distribute the Program (or a work based on it,
|
||||||
|
under Section 2) in object code or executable form under the terms of
|
||||||
|
Sections 1 and 2 above provided that you also do one of the following:
|
||||||
|
|
||||||
|
a) Accompany it with the complete corresponding machine-readable
|
||||||
|
source code, which must be distributed under the terms of Sections
|
||||||
|
1 and 2 above on a medium customarily used for software interchange; or,
|
||||||
|
|
||||||
|
b) Accompany it with a written offer, valid for at least three
|
||||||
|
years, to give any third party, for a charge no more than your
|
||||||
|
cost of physically performing source distribution, a complete
|
||||||
|
machine-readable copy of the corresponding source code, to be
|
||||||
|
distributed under the terms of Sections 1 and 2 above on a medium
|
||||||
|
customarily used for software interchange; or,
|
||||||
|
|
||||||
|
c) Accompany it with the information you received as to the offer
|
||||||
|
to distribute corresponding source code. (This alternative is
|
||||||
|
allowed only for noncommercial distribution and only if you
|
||||||
|
received the program in object code or executable form with such
|
||||||
|
an offer, in accord with Subsection b above.)
|
||||||
|
|
||||||
|
The source code for a work means the preferred form of the work for
|
||||||
|
making modifications to it. For an executable work, complete source
|
||||||
|
code means all the source code for all modules it contains, plus any
|
||||||
|
associated interface definition files, plus the scripts used to
|
||||||
|
control compilation and installation of the executable. However, as a
|
||||||
|
special exception, the source code distributed need not include
|
||||||
|
anything that is normally distributed (in either source or binary
|
||||||
|
form) with the major components (compiler, kernel, and so on) of the
|
||||||
|
operating system on which the executable runs, unless that component
|
||||||
|
itself accompanies the executable.
|
||||||
|
|
||||||
|
If distribution of executable or object code is made by offering
|
||||||
|
access to copy from a designated place, then offering equivalent
|
||||||
|
access to copy the source code from the same place counts as
|
||||||
|
distribution of the source code, even though third parties are not
|
||||||
|
compelled to copy the source along with the object code.
|
||||||
|
|
||||||
|
4. You may not copy, modify, sublicense, or distribute the Program
|
||||||
|
except as expressly provided under this License. Any attempt
|
||||||
|
otherwise to copy, modify, sublicense or distribute the Program is
|
||||||
|
void, and will automatically terminate your rights under this License.
|
||||||
|
However, parties who have received copies, or rights, from you under
|
||||||
|
this License will not have their licenses terminated so long as such
|
||||||
|
parties remain in full compliance.
|
||||||
|
|
||||||
|
5. You are not required to accept this License, since you have not
|
||||||
|
signed it. However, nothing else grants you permission to modify or
|
||||||
|
distribute the Program or its derivative works. These actions are
|
||||||
|
prohibited by law if you do not accept this License. Therefore, by
|
||||||
|
modifying or distributing the Program (or any work based on the
|
||||||
|
Program), you indicate your acceptance of this License to do so, and
|
||||||
|
all its terms and conditions for copying, distributing or modifying
|
||||||
|
the Program or works based on it.
|
||||||
|
|
||||||
|
6. Each time you redistribute the Program (or any work based on the
|
||||||
|
Program), the recipient automatically receives a license from the
|
||||||
|
original licensor to copy, distribute or modify the Program subject to
|
||||||
|
these terms and conditions. You may not impose any further
|
||||||
|
restrictions on the recipients' exercise of the rights granted herein.
|
||||||
|
You are not responsible for enforcing compliance by third parties to
|
||||||
|
this License.
|
||||||
|
|
||||||
|
7. If, as a consequence of a court judgment or allegation of patent
|
||||||
|
infringement or for any other reason (not limited to patent issues),
|
||||||
|
conditions are imposed on you (whether by court order, agreement or
|
||||||
|
otherwise) that contradict the conditions of this License, they do not
|
||||||
|
excuse you from the conditions of this License. If you cannot
|
||||||
|
distribute so as to satisfy simultaneously your obligations under this
|
||||||
|
License and any other pertinent obligations, then as a consequence you
|
||||||
|
may not distribute the Program at all. For example, if a patent
|
||||||
|
license would not permit royalty-free redistribution of the Program by
|
||||||
|
all those who receive copies directly or indirectly through you, then
|
||||||
|
the only way you could satisfy both it and this License would be to
|
||||||
|
refrain entirely from distribution of the Program.
|
||||||
|
|
||||||
|
If any portion of this section is held invalid or unenforceable under
|
||||||
|
any particular circumstance, the balance of the section is intended to
|
||||||
|
apply and the section as a whole is intended to apply in other
|
||||||
|
circumstances.
|
||||||
|
|
||||||
|
It is not the purpose of this section to induce you to infringe any
|
||||||
|
patents or other property right claims or to contest validity of any
|
||||||
|
such claims; this section has the sole purpose of protecting the
|
||||||
|
integrity of the free software distribution system, which is
|
||||||
|
implemented by public license practices. Many people have made
|
||||||
|
generous contributions to the wide range of software distributed
|
||||||
|
through that system in reliance on consistent application of that
|
||||||
|
system; it is up to the author/donor to decide if he or she is willing
|
||||||
|
to distribute software through any other system and a licensee cannot
|
||||||
|
impose that choice.
|
||||||
|
|
||||||
|
This section is intended to make thoroughly clear what is believed to
|
||||||
|
be a consequence of the rest of this License.
|
||||||
|
|
||||||
|
8. If the distribution and/or use of the Program is restricted in
|
||||||
|
certain countries either by patents or by copyrighted interfaces, the
|
||||||
|
original copyright holder who places the Program under this License
|
||||||
|
may add an explicit geographical distribution limitation excluding
|
||||||
|
those countries, so that distribution is permitted only in or among
|
||||||
|
countries not thus excluded. In such case, this License incorporates
|
||||||
|
the limitation as if written in the body of this License.
|
||||||
|
|
||||||
|
9. The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the General Public License from time to time. Such new versions will
|
||||||
|
be similar in spirit to the present version, but may differ in detail to
|
||||||
|
address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the Program
|
||||||
|
specifies a version number of this License which applies to it and "any
|
||||||
|
later version", you have the option of following the terms and conditions
|
||||||
|
either of that version or of any later version published by the Free
|
||||||
|
Software Foundation. If the Program does not specify a version number of
|
||||||
|
this License, you may choose any version ever published by the Free Software
|
||||||
|
Foundation.
|
||||||
|
|
||||||
|
10. If you wish to incorporate parts of the Program into other free
|
||||||
|
programs whose distribution conditions are different, write to the author
|
||||||
|
to ask for permission. For software which is copyrighted by the Free
|
||||||
|
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||||
|
make exceptions for this. Our decision will be guided by the two goals
|
||||||
|
of preserving the free status of all derivatives of our free software and
|
||||||
|
of promoting the sharing and reuse of software generally.
|
||||||
|
|
||||||
|
NO WARRANTY
|
||||||
|
|
||||||
|
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||||
|
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||||
|
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||||
|
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||||
|
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||||
|
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||||
|
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||||
|
REPAIR OR CORRECTION.
|
||||||
|
|
||||||
|
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||||
|
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||||
|
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||||
|
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||||
|
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||||
|
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||||
|
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
How to Apply These Terms to Your New Programs
|
||||||
|
|
||||||
|
If you develop a new program, and you want it to be of the greatest
|
||||||
|
possible use to the public, the best way to achieve this is to make it
|
||||||
|
free software which everyone can redistribute and change under these terms.
|
||||||
|
|
||||||
|
To do so, attach the following notices to the program. It is safest
|
||||||
|
to attach them to the start of each source file to most effectively
|
||||||
|
convey the exclusion of warranty; and each file should have at least
|
||||||
|
the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
|
<one line to give the program's name and a brief idea of what it does.>
|
||||||
|
Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
Also add information on how to contact you by electronic and paper mail.
|
||||||
|
|
||||||
|
If the program is interactive, make it output a short notice like this
|
||||||
|
when it starts in an interactive mode:
|
||||||
|
|
||||||
|
Gnomovision version 69, Copyright (C) year name of author
|
||||||
|
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||||
|
This is free software, and you are welcome to redistribute it
|
||||||
|
under certain conditions; type `show c' for details.
|
||||||
|
|
||||||
|
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||||
|
parts of the General Public License. Of course, the commands you use may
|
||||||
|
be called something other than `show w' and `show c'; they could even be
|
||||||
|
mouse-clicks or menu items--whatever suits your program.
|
||||||
|
|
||||||
|
You should also get your employer (if you work as a programmer) or your
|
||||||
|
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||||
|
necessary. Here is a sample; alter the names:
|
||||||
|
|
||||||
|
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||||
|
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||||
|
|
||||||
|
<signature of Ty Coon>, 1 April 1989
|
||||||
|
Ty Coon, President of Vice
|
||||||
|
|
||||||
|
This General Public License does not permit incorporating your program into
|
||||||
|
proprietary programs. If your program is a subroutine library, you may
|
||||||
|
consider it more useful to permit linking proprietary applications with the
|
||||||
|
library. If this is what you want to do, use the GNU Library General
|
||||||
|
Public License instead of this License.
|
||||||
32
contrib/dnslist/dnslist.tt2
Normal file
32
contrib/dnslist/dnslist.tt2
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>DHCP Clients</title>
|
||||||
|
<link rel="stylesheet" href="dhcp.css"/>
|
||||||
|
<meta http-equiv="Refresh" content="2"/>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>DHCP Clients <span class="updated">(updated [% updated %])</span></h1>
|
||||||
|
<table cols="7">
|
||||||
|
<tr>
|
||||||
|
<th class="hostname">Hostname</th>
|
||||||
|
<th class="ip_addr">IP Address</th>
|
||||||
|
<th class="ether_addr">Ethernet Address</th>
|
||||||
|
<th class="client_id">DHCP Client ID</th>
|
||||||
|
<th class="status">Status</th>
|
||||||
|
<th class="since">Since</th>
|
||||||
|
<th class="lease">Lease Expires</th>
|
||||||
|
</tr>
|
||||||
|
[% FOREACH host IN hosts %]
|
||||||
|
<tr class="[% IF host.online %]online[% ELSE %]offline[% END %]">
|
||||||
|
<td class="hostname">[% host.hostname %]</td>
|
||||||
|
<td class="ip_addr">[% host.ip_addr %]</td>
|
||||||
|
<td class="ether_addr">[% host.ether_addr %]</td>
|
||||||
|
<td class="client_id">[% host.text_client_id %] ([% host.raw_client_id %])</td>
|
||||||
|
<td class="status">[% IF host.online %]Online[% ELSE %]Offline[% END %]</td>
|
||||||
|
<td class="since">[% host.since %]</td>
|
||||||
|
<td class="lease">[% host.text_lease %]</td>
|
||||||
|
</tr>
|
||||||
|
[% END %]
|
||||||
|
</table>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
Name: dnsmasq
|
Name: dnsmasq
|
||||||
Version: 2.9
|
Version: 2.10
|
||||||
Release: 1
|
Release: 1
|
||||||
Copyright: GPL
|
Copyright: GPL
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
Name: dnsmasq
|
Name: dnsmasq
|
||||||
Version: 2.9
|
Version: 2.10
|
||||||
Release: 1
|
Release: 1
|
||||||
Copyright: GPL
|
Copyright: GPL
|
||||||
Group: Productivity/Networking/DNS/Servers
|
Group: Productivity/Networking/DNS/Servers
|
||||||
@@ -16,7 +16,7 @@ Provides: dns_daemon
|
|||||||
Conflicts: bind bind8 bind9
|
Conflicts: bind bind8 bind9
|
||||||
PreReq: %fillup_prereq %insserv_prereq
|
PreReq: %fillup_prereq %insserv_prereq
|
||||||
Autoreqprov: on
|
Autoreqprov: on
|
||||||
Source0: %{name}-%{version}.tar.gz
|
Source0: %{name}-%{version}.tar.bz2
|
||||||
BuildRoot: /var/tmp/%{name}-%{version}
|
BuildRoot: /var/tmp/%{name}-%{version}
|
||||||
Summary: A lightweight caching nameserver
|
Summary: A lightweight caching nameserver
|
||||||
|
|
||||||
@@ -39,6 +39,8 @@ leases and BOOTP for network booting of diskless machines.
|
|||||||
|
|
||||||
%prep
|
%prep
|
||||||
%setup -q
|
%setup -q
|
||||||
|
patch -p0 <rpm/%{name}-SuSE.patch
|
||||||
|
|
||||||
%build
|
%build
|
||||||
%{?suse_update_config:%{suse_update_config -f}}
|
%{?suse_update_config:%{suse_update_config -f}}
|
||||||
make
|
make
|
||||||
|
|||||||
60
dnsmasq.8
60
dnsmasq.8
@@ -73,19 +73,29 @@ Print the version number.
|
|||||||
Listen on <port> instead of the standard DNS port (53). Useful mainly for
|
Listen on <port> instead of the standard DNS port (53). Useful mainly for
|
||||||
debugging.
|
debugging.
|
||||||
.TP
|
.TP
|
||||||
|
.B \-P, --edns-packet-max=<size>
|
||||||
|
Specify the largest EDNS.0 UDP packet which is supported by the DNS
|
||||||
|
forwarder. Defaults to 1280, which is the RFC2671-recommended maximum
|
||||||
|
for ethernet.
|
||||||
|
.TP
|
||||||
.B \-Q, --query-port=<query_port>
|
.B \-Q, --query-port=<query_port>
|
||||||
Send outbound DNS queries from, and listen for their replies on, the specific UDP port <query_port> instead of using one chosen at runtime. Useful to simplify your
|
Send outbound DNS queries from, and listen for their replies on, the specific UDP port <query_port> instead of using one chosen at runtime. Useful to simplify your
|
||||||
firewall rules; without this, your firewall would have to allow connections from outside DNS servers to a range of UDP ports, or dynamically adapt to the
|
firewall rules; without this, your firewall would have to allow connections from outside DNS servers to a range of UDP ports, or dynamically adapt to the
|
||||||
port being used by the current dnsmasq instance.
|
port being used by the current dnsmasq instance.
|
||||||
.TP
|
.TP
|
||||||
.B \-i, --interface=<interface name>
|
.B \-i, --interface=<interface name>
|
||||||
Listen only on the specified interface. More than one interface may be specified. Dnsmasq always listens on the loopback (local) interface. If no
|
Listen only on the specified interface(s). Dnsmasq automatically adds
|
||||||
.B \-i
|
the loopback (local) interface to the list of interfaces to use when
|
||||||
flags are given, dnsmasq listens on all available interfaces unless overridden by
|
the
|
||||||
.B \-a
|
.B \--interface
|
||||||
|
option is used. If no
|
||||||
|
.B \--interface
|
||||||
or
|
or
|
||||||
.B \-I
|
.B \--listen-address
|
||||||
flags. If IP alias interfaces (eg "eth1:0") are used with
|
options are given dnsmasq listens on all available interfaces except any
|
||||||
|
given in
|
||||||
|
.B \--except-interface
|
||||||
|
options. If IP alias interfaces (eg "eth1:0") are used with
|
||||||
.B --interface
|
.B --interface
|
||||||
or
|
or
|
||||||
.B --except-interface
|
.B --except-interface
|
||||||
@@ -95,21 +105,30 @@ option will be automatically set. This is required for deeply boring
|
|||||||
sockets-API reasons.
|
sockets-API reasons.
|
||||||
.TP
|
.TP
|
||||||
.B \-I, --except-interface=<interface name>
|
.B \-I, --except-interface=<interface name>
|
||||||
Do not listen on the specified interface.
|
Do not listen on the specified interface. Note that the order of
|
||||||
|
.B \--listen-address
|
||||||
|
.B --interface
|
||||||
|
and
|
||||||
|
.B --except-interface
|
||||||
|
options does not matter and that
|
||||||
|
.B --except-interface
|
||||||
|
options always override the others.
|
||||||
.TP
|
.TP
|
||||||
.B \-a, --listen-address=<ipaddr>
|
.B \-a, --listen-address=<ipaddr>
|
||||||
Listen only on the given IP address. As with
|
Listen on the given IP address(es). Both
|
||||||
.B \-i
|
.B \--interface
|
||||||
more than one address may be specified. Unlike
|
and
|
||||||
.B \-i
|
.B \--listen-address
|
||||||
the loopback interface is not special: if dnsmasq is to listen on the loopback interface,
|
options may be given, in which case the set of both interfaces and
|
||||||
it's IP, 127.0.0.1, must be explicitly given. If no
|
addresses is used. Note that if no
|
||||||
.B \-a
|
.B \--interface
|
||||||
flags are given, dnsmasq listens on all available interfaces unless overridden by
|
option is given, but
|
||||||
.B \-i
|
.B \--listen-address
|
||||||
or
|
is, dnsmasq will not automatically listen on the loopback
|
||||||
.B \-I
|
interface. To achieve this, its IP address, 127.0.0.1, must be
|
||||||
flags.
|
explicitly given as a
|
||||||
|
.B \--listen-address
|
||||||
|
option.
|
||||||
.TP
|
.TP
|
||||||
.B \-z, --bind-interfaces
|
.B \-z, --bind-interfaces
|
||||||
On systems which support it, dnsmasq binds the wildcard address,
|
On systems which support it, dnsmasq binds the wildcard address,
|
||||||
@@ -126,7 +145,8 @@ broadcast packets.
|
|||||||
.TP
|
.TP
|
||||||
.B \-b, --bogus-priv
|
.B \-b, --bogus-priv
|
||||||
Bogus private reverse lookups. All reverse lookups for private IP ranges (ie 192.168.x.x, etc)
|
Bogus private reverse lookups. All reverse lookups for private IP ranges (ie 192.168.x.x, etc)
|
||||||
which are not found in /etc/hosts or the DHCP leases file are resolved to the IP address in dotted-quad form.
|
which are not found in /etc/hosts or the DHCP leases file are answered
|
||||||
|
with "no such domain" rather than being forwarded upstream.
|
||||||
.TP
|
.TP
|
||||||
.B \-V, --alias=<old-ip>,<new-ip>[,<mask>]
|
.B \-V, --alias=<old-ip>,<new-ip>[,<mask>]
|
||||||
Modify IPv4 addresses returned from upstream nameservers; old-ip is
|
Modify IPv4 addresses returned from upstream nameservers; old-ip is
|
||||||
|
|||||||
4
doc.html
4
doc.html
@@ -18,9 +18,11 @@ connected to the internet via a modem, cable-modem or ADSL
|
|||||||
connection but would be a good choice for any small network where low
|
connection but would be a good choice for any small network where low
|
||||||
resource use and ease of configuration are important.
|
resource use and ease of configuration are important.
|
||||||
<P>
|
<P>
|
||||||
|
Supported platforms include Linux (with glibc and uclibc), *BSD and
|
||||||
|
Mac OS X.
|
||||||
Dnsmasq is included in at least the following Linux distributions:
|
Dnsmasq is included in at least the following Linux distributions:
|
||||||
Gentoo, Debian, Slackware, Suse,
|
Gentoo, Debian, Slackware, Suse,
|
||||||
Smoothwall, IP-Cop, floppyfw, Firebox, Freesco, CoyoteLinux and
|
Smoothwall, IP-Cop, floppyfw, Firebox, LEAF, Freesco, CoyoteLinux and
|
||||||
Clarkconnect. It is also available as a FreeBSD port and is used in Linksys wireless routers.
|
Clarkconnect. It is also available as a FreeBSD port and is used in Linksys wireless routers.
|
||||||
<P>
|
<P>
|
||||||
Dnsmasq provides the following features:
|
Dnsmasq provides the following features:
|
||||||
|
|||||||
42
rpm/dnsmasq-SuSE.patch
Normal file
42
rpm/dnsmasq-SuSE.patch
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
--- dnsmasq.8 2004-06-21 21:55:47.000000000 +0200
|
||||||
|
+++ dnsmasq.8 2004-06-22 23:30:18.000000000 +0200
|
||||||
|
@@ -63,7 +63,7 @@
|
||||||
|
.TP
|
||||||
|
.B \-g, --group=<groupname>
|
||||||
|
Specify the group which dnsmasq will run
|
||||||
|
-as. The defaults to "dip", if available, to facilitate access to
|
||||||
|
+as. The defaults to "dialout", if available, to facilitate access to
|
||||||
|
/etc/ppp/resolv.conf which is not normally world readable.
|
||||||
|
.TP
|
||||||
|
.B \-v, --version
|
||||||
|
--- dnsmasq.conf.example 2004-05-26 12:59:56.000000000 +0200
|
||||||
|
+++ dnsmasq.conf.example 2004-06-22 23:32:36.000000000 +0200
|
||||||
|
@@ -62,7 +62,7 @@
|
||||||
|
|
||||||
|
# You no longer (as of version 1.7) need to set these to enable
|
||||||
|
# dnsmasq to read /etc/ppp/resolv.conf since dnsmasq now uses the
|
||||||
|
-# "dip" group to achieve this.
|
||||||
|
+# "dialout" group to achieve this.
|
||||||
|
#user=
|
||||||
|
#group=
|
||||||
|
|
||||||
|
--- src/config.h 2004-06-22 21:14:50.000000000 +0200
|
||||||
|
+++ src/config.h 2004-06-22 23:31:46.000000000 +0200
|
||||||
|
@@ -38,7 +38,7 @@
|
||||||
|
#endif
|
||||||
|
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||||
|
#define CHUSER "nobody"
|
||||||
|
-#define CHGRP "dip"
|
||||||
|
+#define CHGRP "dialout"
|
||||||
|
#define IP6INTERFACES "/proc/net/if_inet6"
|
||||||
|
#define UPTIME "/proc/uptime"
|
||||||
|
#define DHCP_SERVER_PORT 67
|
||||||
|
@@ -171,7 +171,7 @@
|
||||||
|
|
||||||
|
/* platform independent options. */
|
||||||
|
#undef HAVE_BROKEN_RTC
|
||||||
|
-#define HAVE_ISC_READER
|
||||||
|
+#undef HAVE_ISC_READER
|
||||||
|
|
||||||
|
#if defined(HAVE_BROKEN_RTC) && defined(HAVE_ISC_READER)
|
||||||
|
# error HAVE_ISC_READER is not compatible with HAVE_BROKEN_RTC
|
||||||
15
src/config.h
15
src/config.h
@@ -12,10 +12,13 @@
|
|||||||
|
|
||||||
/* Author's email: simon@thekelleys.org.uk */
|
/* Author's email: simon@thekelleys.org.uk */
|
||||||
|
|
||||||
#define VERSION "2.9"
|
#define VERSION "2.10"
|
||||||
|
|
||||||
#define FTABSIZ 150 /* max number of outstanding requests */
|
#define FTABSIZ 150 /* max number of outstanding requests */
|
||||||
#define TIMEOUT 20 /* drop queries after TIMEOUT seconds */
|
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||||
|
#define CHILD_LIFETIME 150 /* secs 'till terminated (RFC1035 suggests > 120s) */
|
||||||
|
#define EDNS_PKTSZ 1280 /* default max EDNS.0 UDP packet from RFC2671 */
|
||||||
|
#define TIMEOUT 20 /* drop UDP queries after TIMEOUT seconds */
|
||||||
#define LOGRATE 120 /* log table overflows every LOGRATE seconds */
|
#define LOGRATE 120 /* log table overflows every LOGRATE seconds */
|
||||||
#define CACHESIZ 150 /* default cache size */
|
#define CACHESIZ 150 /* default cache size */
|
||||||
#define MAXTOK 50 /* token in DHCP leases */
|
#define MAXTOK 50 /* token in DHCP leases */
|
||||||
@@ -31,9 +34,12 @@
|
|||||||
#define RUNFILE "/var/run/dnsmasq.pid"
|
#define RUNFILE "/var/run/dnsmasq.pid"
|
||||||
#if defined(__FreeBSD__) || defined (__OpenBSD__)
|
#if defined(__FreeBSD__) || defined (__OpenBSD__)
|
||||||
# define LEASEFILE "/var/db/dnsmasq.leases"
|
# define LEASEFILE "/var/db/dnsmasq.leases"
|
||||||
# define CONFFILE "/usr/local/etc/dnsmasq.conf"
|
|
||||||
#else
|
#else
|
||||||
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
|
# define LEASEFILE "/var/lib/misc/dnsmasq.leases"
|
||||||
|
#endif
|
||||||
|
#if defined(__FreeBSD__)
|
||||||
|
# define CONFFILE "/usr/local/etc/dnsmasq.conf"
|
||||||
|
#else
|
||||||
# define CONFFILE "/etc/dnsmasq.conf"
|
# define CONFFILE "/etc/dnsmasq.conf"
|
||||||
#endif
|
#endif
|
||||||
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
#define DEFLEASE 3600 /* default lease time, 1 hour */
|
||||||
@@ -63,7 +69,7 @@
|
|||||||
/* We assume that systems which don't have IPv6
|
/* We assume that systems which don't have IPv6
|
||||||
headers don't have ntop and pton either */
|
headers don't have ntop and pton either */
|
||||||
|
|
||||||
#if defined(INET6_ADDRSTRLEN) && !defined(NO_IPV6)
|
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY) && !defined(NO_IPV6)
|
||||||
# define HAVE_IPV6
|
# define HAVE_IPV6
|
||||||
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
# define ADDRSTRLEN INET6_ADDRSTRLEN
|
||||||
# if defined(SOL_IPV6)
|
# if defined(SOL_IPV6)
|
||||||
@@ -89,7 +95,6 @@
|
|||||||
new system, you may want to edit these.
|
new system, you may want to edit these.
|
||||||
May replace this with Autoconf one day.
|
May replace this with Autoconf one day.
|
||||||
|
|
||||||
|
|
||||||
HAVE_LINUX_IPV6_PROC
|
HAVE_LINUX_IPV6_PROC
|
||||||
define this to do IPv6 interface discovery using
|
define this to do IPv6 interface discovery using
|
||||||
proc/net/if_inet6 ala LINUX.
|
proc/net/if_inet6 ala LINUX.
|
||||||
|
|||||||
@@ -368,28 +368,25 @@ int address_available(struct dhcp_context *context, struct in_addr taddr)
|
|||||||
if (addr > end)
|
if (addr > end)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (lease_find_by_addr(taddr))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
|
int address_allocate(struct dhcp_context *context, struct dhcp_config *configs,
|
||||||
struct in_addr *addrp, unsigned char *hwaddr)
|
struct in_addr *addrp, unsigned char *hwaddr)
|
||||||
{
|
{
|
||||||
/* Find a free address: exlude anything in use and anything allocated to
|
/* Find a free address: exclude anything in use and anything allocated to
|
||||||
a particular hwaddr/clientid/hostname in our configuration */
|
a particular hwaddr/clientid/hostname in our configuration */
|
||||||
|
|
||||||
struct dhcp_config *config;
|
struct dhcp_config *config;
|
||||||
struct in_addr start, addr ;
|
struct in_addr start, addr ;
|
||||||
int i, j;
|
unsigned int i, j;
|
||||||
|
|
||||||
/* start == end means no dynamic leases. */
|
/* start == end means no dynamic leases. */
|
||||||
if (context->end.s_addr == context->start.s_addr)
|
if (context->end.s_addr == context->start.s_addr)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
||||||
for (j = 0, i = 0; i < ETHER_ADDR_LEN; i++)
|
for (j = context->addr_epoch, i = 0; i < ETHER_ADDR_LEN; i++)
|
||||||
j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
|
j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
|
||||||
|
|
||||||
start.s_addr = addr.s_addr =
|
start.s_addr = addr.s_addr =
|
||||||
|
|||||||
205
src/dnsmasq.c
205
src/dnsmasq.c
@@ -10,13 +10,11 @@
|
|||||||
GNU General Public License for more details.
|
GNU General Public License for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* See RFC1035 for details of the protocol this code talks. */
|
|
||||||
|
|
||||||
/* Author's email: simon@thekelleys.org.uk */
|
/* Author's email: simon@thekelleys.org.uk */
|
||||||
|
|
||||||
#include "dnsmasq.h"
|
#include "dnsmasq.h"
|
||||||
|
|
||||||
static int sigterm, sighup, sigusr1, sigalarm;
|
static int sigterm, sighup, sigusr1, sigalarm, num_kids, in_child;
|
||||||
|
|
||||||
static void sig_handler(int sig)
|
static void sig_handler(int sig)
|
||||||
{
|
{
|
||||||
@@ -27,7 +25,22 @@ static void sig_handler(int sig)
|
|||||||
else if (sig == SIGUSR1)
|
else if (sig == SIGUSR1)
|
||||||
sigusr1 = 1;
|
sigusr1 = 1;
|
||||||
else if (sig == SIGALRM)
|
else if (sig == SIGALRM)
|
||||||
sigalarm = 1;
|
{
|
||||||
|
/* alarm is used to kill children after a fixed time. */
|
||||||
|
if (in_child)
|
||||||
|
exit(0);
|
||||||
|
else
|
||||||
|
sigalarm = 1;
|
||||||
|
}
|
||||||
|
else if (sig == SIGCHLD)
|
||||||
|
{
|
||||||
|
/* See Stevens 5.10 */
|
||||||
|
pid_t pid;
|
||||||
|
int stat;
|
||||||
|
|
||||||
|
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
|
||||||
|
num_kids--;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
@@ -35,6 +48,7 @@ int main (int argc, char **argv)
|
|||||||
int cachesize = CACHESIZ;
|
int cachesize = CACHESIZ;
|
||||||
int port = NAMESERVER_PORT;
|
int port = NAMESERVER_PORT;
|
||||||
int maxleases = MAXLEASES;
|
int maxleases = MAXLEASES;
|
||||||
|
unsigned short edns_pktsz = EDNS_PKTSZ;
|
||||||
int query_port = 0;
|
int query_port = 0;
|
||||||
int first_loop = 1;
|
int first_loop = 1;
|
||||||
int bind_fallback = 0;
|
int bind_fallback = 0;
|
||||||
@@ -82,6 +96,8 @@ int main (int argc, char **argv)
|
|||||||
#else
|
#else
|
||||||
sigalarm = 0; /* or not */
|
sigalarm = 0; /* or not */
|
||||||
#endif
|
#endif
|
||||||
|
num_kids = 0;
|
||||||
|
in_child = 0;
|
||||||
|
|
||||||
sigact.sa_handler = sig_handler;
|
sigact.sa_handler = sig_handler;
|
||||||
sigact.sa_flags = 0;
|
sigact.sa_flags = 0;
|
||||||
@@ -90,6 +106,11 @@ int main (int argc, char **argv)
|
|||||||
sigaction(SIGHUP, &sigact, NULL);
|
sigaction(SIGHUP, &sigact, NULL);
|
||||||
sigaction(SIGTERM, &sigact, NULL);
|
sigaction(SIGTERM, &sigact, NULL);
|
||||||
sigaction(SIGALRM, &sigact, NULL);
|
sigaction(SIGALRM, &sigact, NULL);
|
||||||
|
sigaction(SIGCHLD, &sigact, NULL);
|
||||||
|
|
||||||
|
/* ignore SIGPIPE */
|
||||||
|
sigact.sa_handler = SIG_IGN;
|
||||||
|
sigaction(SIGPIPE, &sigact, NULL);
|
||||||
|
|
||||||
/* now block all the signals, they stay that way except
|
/* now block all the signals, they stay that way except
|
||||||
during the call to pselect */
|
during the call to pselect */
|
||||||
@@ -97,6 +118,7 @@ int main (int argc, char **argv)
|
|||||||
sigaddset(&sigact.sa_mask, SIGTERM);
|
sigaddset(&sigact.sa_mask, SIGTERM);
|
||||||
sigaddset(&sigact.sa_mask, SIGHUP);
|
sigaddset(&sigact.sa_mask, SIGHUP);
|
||||||
sigaddset(&sigact.sa_mask, SIGALRM);
|
sigaddset(&sigact.sa_mask, SIGALRM);
|
||||||
|
sigaddset(&sigact.sa_mask, SIGCHLD);
|
||||||
sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask);
|
sigprocmask(SIG_BLOCK, &sigact.sa_mask, &sigmask);
|
||||||
|
|
||||||
/* These get allocated here to avoid overflowing the small stack
|
/* These get allocated here to avoid overflowing the small stack
|
||||||
@@ -104,7 +126,6 @@ int main (int argc, char **argv)
|
|||||||
maximal sixed domain name and gets passed into all the processing
|
maximal sixed domain name and gets passed into all the processing
|
||||||
code. We manage to get away with one buffer. */
|
code. We manage to get away with one buffer. */
|
||||||
dnamebuff = safe_malloc(MAXDNAME);
|
dnamebuff = safe_malloc(MAXDNAME);
|
||||||
packet = safe_malloc(DNSMASQ_PACKETSZ);
|
|
||||||
|
|
||||||
dhcp_next_server.s_addr = 0;
|
dhcp_next_server.s_addr = 0;
|
||||||
options = read_opts(argc, argv, dnamebuff, &resolv, &mxnames, &mxtarget, &lease_file,
|
options = read_opts(argc, argv, dnamebuff, &resolv, &mxnames, &mxtarget, &lease_file,
|
||||||
@@ -113,7 +134,11 @@ int main (int argc, char **argv)
|
|||||||
&serv_addrs, &cachesize, &port, &query_port, &local_ttl, &addn_hosts,
|
&serv_addrs, &cachesize, &port, &query_port, &local_ttl, &addn_hosts,
|
||||||
&dhcp, &dhcp_configs, &dhcp_options, &dhcp_vendors,
|
&dhcp, &dhcp_configs, &dhcp_options, &dhcp_vendors,
|
||||||
&dhcp_file, &dhcp_sname, &dhcp_next_server, &maxleases, &min_leasetime,
|
&dhcp_file, &dhcp_sname, &dhcp_next_server, &maxleases, &min_leasetime,
|
||||||
&doctors);
|
&doctors, &edns_pktsz);
|
||||||
|
|
||||||
|
if (edns_pktsz < PACKETSZ)
|
||||||
|
edns_pktsz = PACKETSZ;
|
||||||
|
packet = safe_malloc(edns_pktsz > DNSMASQ_PACKETSZ ? edns_pktsz : DNSMASQ_PACKETSZ);
|
||||||
|
|
||||||
if (!lease_file)
|
if (!lease_file)
|
||||||
{
|
{
|
||||||
@@ -136,7 +161,7 @@ int main (int argc, char **argv)
|
|||||||
if (options & OPT_NOWILD)
|
if (options & OPT_NOWILD)
|
||||||
{
|
{
|
||||||
struct iname *if_tmp;
|
struct iname *if_tmp;
|
||||||
listeners = create_bound_listeners(interfaces);
|
listeners = create_bound_listeners(interfaces, port);
|
||||||
|
|
||||||
for (if_tmp = if_names; if_tmp; if_tmp = if_tmp->next)
|
for (if_tmp = if_names; if_tmp; if_tmp = if_tmp->next)
|
||||||
if (if_tmp->name && !if_tmp->used)
|
if (if_tmp->name && !if_tmp->used)
|
||||||
@@ -185,6 +210,31 @@ int main (int argc, char **argv)
|
|||||||
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
|
leasefd = lease_init(lease_file, domain_suffix, dnamebuff, packet, now, maxleases);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If query_port is set then create a socket now, before dumping root
|
||||||
|
for use to access nameservers without more specific source addresses.
|
||||||
|
This allows query_port to be a low port */
|
||||||
|
if (query_port)
|
||||||
|
{
|
||||||
|
union mysockaddr addr;
|
||||||
|
addr.in.sin_family = AF_INET;
|
||||||
|
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
addr.in.sin_port = htons(query_port);
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||||
|
#endif
|
||||||
|
allocate_sfd(&addr, &sfds);
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
addr.in6.sin6_family = AF_INET6;
|
||||||
|
addr.in6.sin6_addr = in6addr_any;
|
||||||
|
addr.in6.sin6_port = htons(query_port);
|
||||||
|
addr.in6.sin6_flowinfo = htonl(0);
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||||
|
#endif
|
||||||
|
allocate_sfd(&addr, &sfds);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
setbuf(stdout, NULL);
|
setbuf(stdout, NULL);
|
||||||
|
|
||||||
if (!(options & OPT_DEBUG))
|
if (!(options & OPT_DEBUG))
|
||||||
@@ -221,8 +271,12 @@ int main (int argc, char **argv)
|
|||||||
for (i=0; i<64; i++)
|
for (i=0; i<64; i++)
|
||||||
{
|
{
|
||||||
for (listener = listeners; listener; listener = listener->next)
|
for (listener = listeners; listener; listener = listener->next)
|
||||||
if (listener->fd == i)
|
{
|
||||||
break;
|
if (listener->fd == i)
|
||||||
|
break;
|
||||||
|
if (listener->tcpfd == i)
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (listener)
|
if (listener)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -232,6 +286,12 @@ int main (int argc, char **argv)
|
|||||||
i == dhcp_raw_fd)
|
i == dhcp_raw_fd)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
|
||||||
|
if (serverfdp->fd == i)
|
||||||
|
break;
|
||||||
|
if (serverfdp)
|
||||||
|
continue;
|
||||||
|
|
||||||
close(i);
|
close(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,13 +316,13 @@ int main (int argc, char **argv)
|
|||||||
DNSMASQ_LOG_OPT(options & OPT_DEBUG),
|
DNSMASQ_LOG_OPT(options & OPT_DEBUG),
|
||||||
DNSMASQ_LOG_FAC(options & OPT_DEBUG));
|
DNSMASQ_LOG_FAC(options & OPT_DEBUG));
|
||||||
|
|
||||||
if (cachesize)
|
if (cachesize != 0)
|
||||||
syslog(LOG_INFO, "started, version %s cachesize %d", VERSION, cachesize);
|
syslog(LOG_INFO, "started, version %s cachesize %d", VERSION, cachesize);
|
||||||
else
|
else
|
||||||
syslog(LOG_INFO, "started, version %s cache disabled", VERSION);
|
syslog(LOG_INFO, "started, version %s cache disabled", VERSION);
|
||||||
|
|
||||||
if (bind_fallback)
|
if (bind_fallback)
|
||||||
syslog(LOG_WARNING, "setting --bind-interfaces option because if OS limitations");
|
syslog(LOG_WARNING, "setting --bind-interfaces option because of OS limitations");
|
||||||
|
|
||||||
for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
for (dhcp_tmp = dhcp; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
|
||||||
{
|
{
|
||||||
@@ -270,7 +330,15 @@ int main (int argc, char **argv)
|
|||||||
if (dhcp_tmp->lease_time == 0)
|
if (dhcp_tmp->lease_time == 0)
|
||||||
sprintf(packet, "infinite");
|
sprintf(packet, "infinite");
|
||||||
else
|
else
|
||||||
sprintf(packet, "%ds", (int)dhcp_tmp->lease_time);
|
{
|
||||||
|
unsigned int x, p = 0, t = (unsigned int)dhcp_tmp->lease_time;
|
||||||
|
if ((x = t/3600))
|
||||||
|
p += sprintf(&packet[p], "%dh", x);
|
||||||
|
if ((x = (t/60)%60))
|
||||||
|
p += sprintf(&packet[p], "%dm", x);
|
||||||
|
if ((x = t%60))
|
||||||
|
p += sprintf(&packet[p], "%ds", x);
|
||||||
|
}
|
||||||
syslog(LOG_INFO,
|
syslog(LOG_INFO,
|
||||||
dhcp_tmp->start.s_addr == dhcp_tmp->end.s_addr ?
|
dhcp_tmp->start.s_addr == dhcp_tmp->end.s_addr ?
|
||||||
"DHCP, static leases only on %.0s%s, lease time %s" :
|
"DHCP, static leases only on %.0s%s, lease time %s" :
|
||||||
@@ -283,8 +351,8 @@ int main (int argc, char **argv)
|
|||||||
syslog(LOG_INFO, "DHCP, %s will be written every %ds", lease_file, min_leasetime/3);
|
syslog(LOG_INFO, "DHCP, %s will be written every %ds", lease_file, min_leasetime/3);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (getuid() == 0 || geteuid() == 0)
|
if (!(options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
|
||||||
syslog(LOG_WARNING, "failed to drop root privs");
|
syslog(LOG_WARNING, "running as root");
|
||||||
|
|
||||||
servers = check_servers(serv_addrs, interfaces, &sfds);
|
servers = check_servers(serv_addrs, interfaces, &sfds);
|
||||||
last_server = NULL;
|
last_server = NULL;
|
||||||
@@ -350,6 +418,9 @@ int main (int argc, char **argv)
|
|||||||
FD_SET(listener->fd, &rset);
|
FD_SET(listener->fd, &rset);
|
||||||
if (listener->fd > maxfd)
|
if (listener->fd > maxfd)
|
||||||
maxfd = listener->fd;
|
maxfd = listener->fd;
|
||||||
|
FD_SET(listener->tcpfd, &rset);
|
||||||
|
if (listener->tcpfd > maxfd)
|
||||||
|
maxfd = listener->tcpfd;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dhcp)
|
if (dhcp)
|
||||||
@@ -428,7 +499,8 @@ int main (int argc, char **argv)
|
|||||||
for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
|
for (serverfdp = sfds; serverfdp; serverfdp = serverfdp->next)
|
||||||
if (FD_ISSET(serverfdp->fd, &rset))
|
if (FD_ISSET(serverfdp->fd, &rset))
|
||||||
last_server = reply_query(serverfdp, options, packet, now,
|
last_server = reply_query(serverfdp, options, packet, now,
|
||||||
dnamebuff, servers, last_server, bogus_addr, doctors);
|
dnamebuff, servers, last_server,
|
||||||
|
bogus_addr, doctors, edns_pktsz);
|
||||||
|
|
||||||
if (dhcp && FD_ISSET(dhcpfd, &rset))
|
if (dhcp && FD_ISSET(dhcpfd, &rset))
|
||||||
dhcp_packet(dhcp, packet, dhcp_options, dhcp_configs, dhcp_vendors,
|
dhcp_packet(dhcp, packet, dhcp_options, dhcp_configs, dhcp_vendors,
|
||||||
@@ -437,10 +509,105 @@ int main (int argc, char **argv)
|
|||||||
if_names, if_addrs, if_except);
|
if_names, if_addrs, if_except);
|
||||||
|
|
||||||
for (listener = listeners; listener; listener = listener->next)
|
for (listener = listeners; listener; listener = listener->next)
|
||||||
if (FD_ISSET(listener->fd, &rset))
|
{
|
||||||
last_server = receive_query(listener, packet,
|
if (FD_ISSET(listener->fd, &rset))
|
||||||
mxnames, mxtarget, options, now, local_ttl, dnamebuff,
|
last_server = receive_query(listener, packet,
|
||||||
if_names, if_addrs, if_except, last_server, servers);
|
mxnames, mxtarget, options, now, local_ttl, dnamebuff,
|
||||||
|
if_names, if_addrs, if_except, last_server, servers, edns_pktsz);
|
||||||
|
|
||||||
|
if (FD_ISSET(listener->tcpfd, &rset))
|
||||||
|
{
|
||||||
|
int confd;
|
||||||
|
|
||||||
|
while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
if (confd != -1)
|
||||||
|
{
|
||||||
|
int match = 1;
|
||||||
|
if (!(options & OPT_NOWILD))
|
||||||
|
{
|
||||||
|
/* Check for allowed interfaces when binding the wildcard address */
|
||||||
|
/* Don't know how to get interface of a connection, so we have to
|
||||||
|
check by address. This will break when interfaces change address */
|
||||||
|
union mysockaddr tcp_addr;
|
||||||
|
socklen_t tcp_len = sizeof(union mysockaddr);
|
||||||
|
struct iname *tmp;
|
||||||
|
|
||||||
|
if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
|
||||||
|
{
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (tcp_addr.sa.sa_family == AF_INET6)
|
||||||
|
tcp_addr.in6.sin6_flowinfo = htonl(0);
|
||||||
|
#endif
|
||||||
|
for (match = 1, tmp = if_except; tmp; tmp = tmp->next)
|
||||||
|
if (sockaddr_isequal(&tmp->addr, &tcp_addr))
|
||||||
|
match = 0;
|
||||||
|
|
||||||
|
if (match && (if_names || if_addrs))
|
||||||
|
{
|
||||||
|
match = 0;
|
||||||
|
for (tmp = if_names; tmp; tmp = tmp->next)
|
||||||
|
if (sockaddr_isequal(&tmp->addr, &tcp_addr))
|
||||||
|
match = 1;
|
||||||
|
for (tmp = if_addrs; tmp; tmp = tmp->next)
|
||||||
|
if (sockaddr_isequal(&tmp->addr, &tcp_addr))
|
||||||
|
match = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!match || (num_kids >= MAX_PROCS))
|
||||||
|
close(confd);
|
||||||
|
else if (!(options & OPT_DEBUG) && fork())
|
||||||
|
{
|
||||||
|
num_kids++;
|
||||||
|
close(confd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *buff;
|
||||||
|
struct server *s;
|
||||||
|
int flags;
|
||||||
|
|
||||||
|
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
|
||||||
|
terminate the process. */
|
||||||
|
if (!(options & OPT_DEBUG))
|
||||||
|
{
|
||||||
|
sigemptyset(&sigact.sa_mask);
|
||||||
|
sigaddset(&sigact.sa_mask, SIGALRM);
|
||||||
|
sigprocmask(SIG_UNBLOCK, &sigact.sa_mask, NULL);
|
||||||
|
alarm(CHILD_LIFETIME);
|
||||||
|
in_child = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* start with no upstream connections. */
|
||||||
|
for (s = servers; s; s = s->next)
|
||||||
|
s->tcpfd = -1;
|
||||||
|
|
||||||
|
/* The connected socket inherits non-blocking
|
||||||
|
attribute from the listening socket.
|
||||||
|
Reset that here. */
|
||||||
|
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
|
||||||
|
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
|
||||||
|
|
||||||
|
buff = tcp_request(confd, mxnames, mxtarget, options, now,
|
||||||
|
local_ttl, dnamebuff, last_server, servers,
|
||||||
|
bogus_addr, doctors, edns_pktsz);
|
||||||
|
|
||||||
|
|
||||||
|
if (!(options & OPT_DEBUG))
|
||||||
|
exit(0);
|
||||||
|
|
||||||
|
close(confd);
|
||||||
|
if (buff)
|
||||||
|
free(buff);
|
||||||
|
for (s = servers; s; s = s->next)
|
||||||
|
if (s->tcpfd != -1)
|
||||||
|
close(s->tcpfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
syslog(LOG_INFO, "exiting on receipt of SIGTERM");
|
syslog(LOG_INFO, "exiting on receipt of SIGTERM");
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
/* Author's email: simon@thekelleys.org.uk */
|
/* Author's email: simon@thekelleys.org.uk */
|
||||||
|
|
||||||
|
#define COPYRIGHT "Copyright (C) 2000-2004 Simon Kelley"
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
/* for pselect.... */
|
/* for pselect.... */
|
||||||
@@ -36,6 +37,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/ioctl.h>
|
#include <sys/ioctl.h>
|
||||||
#include <sys/select.h>
|
#include <sys/select.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
#if defined(__sun) || defined(__sun__)
|
#if defined(__sun) || defined(__sun__)
|
||||||
# include <sys/sockio.h>
|
# include <sys/sockio.h>
|
||||||
#endif
|
#endif
|
||||||
@@ -194,7 +196,7 @@ struct server {
|
|||||||
struct serverfd *sfd; /* non-NULL if this server has its own fd bound to
|
struct serverfd *sfd; /* non-NULL if this server has its own fd bound to
|
||||||
a source port */
|
a source port */
|
||||||
char *domain; /* set if this server only handles a domain. */
|
char *domain; /* set if this server only handles a domain. */
|
||||||
int flags;
|
int flags, tcpfd;
|
||||||
struct server *next;
|
struct server *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -204,7 +206,7 @@ struct irec {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct listener {
|
struct listener {
|
||||||
int fd, family;
|
int fd, tcpfd, family;
|
||||||
struct listener *next;
|
struct listener *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -285,7 +287,7 @@ struct dhcp_vendor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct dhcp_context {
|
struct dhcp_context {
|
||||||
unsigned int lease_time;
|
unsigned int lease_time, addr_epoch;
|
||||||
struct in_addr netmask, broadcast;
|
struct in_addr netmask, broadcast;
|
||||||
struct in_addr start, end; /* range of available addresses */
|
struct in_addr start, end; /* range of available addresses */
|
||||||
struct dhcp_netid netid;
|
struct dhcp_netid netid;
|
||||||
@@ -346,9 +348,10 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *namebuff,
|
|||||||
void extract_neg_addrs(HEADER *header, unsigned int qlen, char *namebuff, time_t now);
|
void extract_neg_addrs(HEADER *header, unsigned int qlen, char *namebuff, time_t now);
|
||||||
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_record *mxnames,
|
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_record *mxnames,
|
||||||
char *mxtarget, unsigned int options, time_t now, unsigned long local_ttl,
|
char *mxtarget, unsigned int options, time_t now, unsigned long local_ttl,
|
||||||
char *namebuff);
|
char *namebuff, unsigned short edns_pcktsz);
|
||||||
int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
|
int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
|
||||||
struct bogus_addr *addr, time_t now);
|
struct bogus_addr *addr, time_t now);
|
||||||
|
unsigned char *find_pseudoheader(HEADER *header, unsigned int plen);
|
||||||
|
|
||||||
/* util.c */
|
/* util.c */
|
||||||
unsigned short rand16(void);
|
unsigned short rand16(void);
|
||||||
@@ -376,20 +379,30 @@ unsigned int read_opts(int argc, char **argv, char *buff, struct resolvc **resol
|
|||||||
struct dhcp_context **dhcp, struct dhcp_config **dhcp_conf,
|
struct dhcp_context **dhcp, struct dhcp_config **dhcp_conf,
|
||||||
struct dhcp_opt **opts, struct dhcp_vendor **dhcp_vendors,
|
struct dhcp_opt **opts, struct dhcp_vendor **dhcp_vendors,
|
||||||
char **dhcp_file, char **dhcp_sname, struct in_addr *dhcp_next_server,
|
char **dhcp_file, char **dhcp_sname, struct in_addr *dhcp_next_server,
|
||||||
int *maxleases, unsigned int *min_leasetime, struct doctor **doctors);
|
int *maxleases, unsigned int *min_leasetime, struct doctor **doctors,
|
||||||
|
unsigned short *edns_pktsz);
|
||||||
|
|
||||||
/* forward.c */
|
/* forward.c */
|
||||||
void forward_init(int first);
|
void forward_init(int first);
|
||||||
struct server *reply_query(struct serverfd *sfd, int options, char *packet, time_t now,
|
struct server *reply_query(struct serverfd *sfd, int options, char *packet, time_t now,
|
||||||
char *dnamebuff, struct server *servers, struct server *last_server,
|
char *dnamebuff, struct server *servers, struct server *last_server,
|
||||||
struct bogus_addr *bogus_nxdomain, struct doctor *doctors);
|
struct bogus_addr *bogus_nxdomain,
|
||||||
|
struct doctor *doctors, unsigned short edns_pcktsz);
|
||||||
|
|
||||||
struct server *receive_query(struct listener *listen, char *packet, struct mx_record *mxnames,
|
struct server *receive_query(struct listener *listen, char *packet, struct mx_record *mxnames,
|
||||||
char *mxtarget, unsigned int options, time_t now,
|
char *mxtarget, unsigned int options, time_t now,
|
||||||
unsigned long local_ttl, char *namebuff,
|
unsigned long local_ttl, char *namebuff,
|
||||||
struct iname *names, struct iname *addrs, struct iname *except,
|
struct iname *names, struct iname *addrs, struct iname *except,
|
||||||
struct server *last_server, struct server *servers);
|
struct server *last_server, struct server *servers, unsigned short edns_pcktsz);
|
||||||
|
|
||||||
|
char *tcp_request(int confd, struct mx_record *mxnames,
|
||||||
|
char *mxtarget, unsigned int options, time_t now,
|
||||||
|
unsigned long local_ttl, char *namebuff,
|
||||||
|
struct server *last_server, struct server *servers,
|
||||||
|
struct bogus_addr *bogus_nxdomain, struct doctor *doctors,
|
||||||
|
unsigned short edns_pcktsz);
|
||||||
/* network.c */
|
/* network.c */
|
||||||
|
struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds);
|
||||||
struct server *reload_servers(char *fname, char *buff, struct server *servers, int query_port);
|
struct server *reload_servers(char *fname, char *buff, struct server *servers, int query_port);
|
||||||
struct server *check_servers(struct server *new, struct irec *interfaces, struct serverfd **sfds);
|
struct server *check_servers(struct server *new, struct irec *interfaces, struct serverfd **sfds);
|
||||||
struct irec *enumerate_interfaces(struct iname **names,
|
struct irec *enumerate_interfaces(struct iname **names,
|
||||||
@@ -397,7 +410,7 @@ struct irec *enumerate_interfaces(struct iname **names,
|
|||||||
struct iname *except,
|
struct iname *except,
|
||||||
int port);
|
int port);
|
||||||
struct listener *create_wildcard_listeners(int port);
|
struct listener *create_wildcard_listeners(int port);
|
||||||
struct listener *create_bound_listeners(struct irec *interfaces);
|
struct listener *create_bound_listeners(struct irec *interfaces, int port);
|
||||||
/* dhcp.c */
|
/* dhcp.c */
|
||||||
void dhcp_init(int *fdp, int* rfdp);
|
void dhcp_init(int *fdp, int* rfdp);
|
||||||
void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
void dhcp_packet(struct dhcp_context *contexts, char *packet,
|
||||||
@@ -448,3 +461,4 @@ int dhcp_reply(struct dhcp_context *context,
|
|||||||
#ifdef HAVE_ISC_READER
|
#ifdef HAVE_ISC_READER
|
||||||
void load_dhcp(char *file, char *suffix, time_t now, char *hostname);
|
void load_dhcp(char *file, char *suffix, time_t now, char *hostname);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
543
src/forward.c
543
src/forward.c
@@ -40,7 +40,6 @@ static void send_from(int fd, int nowild, char *packet, int len,
|
|||||||
{
|
{
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
struct iovec iov[1];
|
struct iovec iov[1];
|
||||||
struct cmsghdr *cmptr;
|
|
||||||
union {
|
union {
|
||||||
struct cmsghdr align; /* this ensures alignment */
|
struct cmsghdr align; /* this ensures alignment */
|
||||||
#if defined(IP_PKTINFO)
|
#if defined(IP_PKTINFO)
|
||||||
@@ -56,60 +55,139 @@ static void send_from(int fd, int nowild, char *packet, int len,
|
|||||||
iov[0].iov_base = packet;
|
iov[0].iov_base = packet;
|
||||||
iov[0].iov_len = len;
|
iov[0].iov_len = len;
|
||||||
|
|
||||||
if (nowild)
|
msg.msg_control = NULL;
|
||||||
{
|
msg.msg_controllen = 0;
|
||||||
msg.msg_control = NULL;
|
|
||||||
msg.msg_controllen = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
msg.msg_control = &control_u;
|
|
||||||
msg.msg_controllen = sizeof(control_u);
|
|
||||||
}
|
|
||||||
msg.msg_flags = 0;
|
msg.msg_flags = 0;
|
||||||
msg.msg_name = to;
|
msg.msg_name = to;
|
||||||
msg.msg_namelen = sa_len(to);
|
msg.msg_namelen = sa_len(to);
|
||||||
msg.msg_iov = iov;
|
msg.msg_iov = iov;
|
||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
cmptr = CMSG_FIRSTHDR(&msg);
|
if (!nowild && to->sa.sa_family == AF_INET)
|
||||||
|
{
|
||||||
|
msg.msg_control = &control_u;
|
||||||
|
msg.msg_controllen = sizeof(control_u);
|
||||||
|
{
|
||||||
|
struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
|
||||||
#if defined(IP_PKTINFO)
|
#if defined(IP_PKTINFO)
|
||||||
if (!nowild && to->sa.sa_family == AF_INET)
|
struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
|
||||||
{
|
pkt->ipi_ifindex = 0;
|
||||||
struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
|
pkt->ipi_spec_dst = source->addr.addr4;
|
||||||
pkt->ipi_ifindex = 0;
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||||
pkt->ipi_spec_dst = source->addr.addr4;
|
cmptr->cmsg_level = SOL_IP;
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
cmptr->cmsg_type = IP_PKTINFO;
|
||||||
cmptr->cmsg_level = SOL_IP;
|
|
||||||
cmptr->cmsg_type = IP_PKTINFO;
|
|
||||||
}
|
|
||||||
#elif defined(IP_SENDSRCADDR)
|
#elif defined(IP_SENDSRCADDR)
|
||||||
if (!nowild && to->sa.sa_family == AF_INET)
|
struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
|
||||||
{
|
*a = source->addr.addr4;
|
||||||
struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
|
||||||
*a = source->addr.addr4;
|
cmptr->cmsg_level = IPPROTO_IP;
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
|
cmptr->cmsg_type = IP_SENDSRCADDR;
|
||||||
cmptr->cmsg_level = IPPROTO_IP;
|
|
||||||
cmptr->cmsg_type = IP_SENDSRCADDR;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (!nowild && to->sa.sa_family == AF_INET6)
|
if (to->sa.sa_family == AF_INET6)
|
||||||
{
|
{
|
||||||
struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
|
msg.msg_control = &control_u;
|
||||||
pkt->ipi6_ifindex = 0;
|
msg.msg_controllen = sizeof(control_u);
|
||||||
pkt->ipi6_addr = source->addr.addr6;
|
{
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
|
||||||
cmptr->cmsg_type = IPV6_PKTINFO;
|
struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
|
||||||
cmptr->cmsg_level = IPV6_LEVEL;
|
pkt->ipi6_ifindex = 0;
|
||||||
|
pkt->ipi6_addr = source->addr.addr6;
|
||||||
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
||||||
|
cmptr->cmsg_type = IPV6_PKTINFO;
|
||||||
|
cmptr->cmsg_level = IPV6_LEVEL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
sendmsg(fd, &msg, 0);
|
/* certain Linux kernels seem to object to setting the source address in the IPv6 stack
|
||||||
|
by returning EINVAL from sendmsg. In that case, try again without setting the
|
||||||
|
source address, since it will nearly alway be correct anyway. IPv6 stinks. */
|
||||||
|
if (sendmsg(fd, &msg, 0) == -1 && errno == EINVAL)
|
||||||
|
{
|
||||||
|
msg.msg_controllen = 0;
|
||||||
|
sendmsg(fd, &msg, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned short search_servers(struct server *servers, unsigned int options, struct all_addr **addrpp,
|
||||||
|
unsigned short qtype, char *qdomain, int *type, char **domain)
|
||||||
|
|
||||||
|
{
|
||||||
|
/* If the query ends in the domain in one of our servers, set
|
||||||
|
domain to point to that name. We find the largest match to allow both
|
||||||
|
domain.org and sub.domain.org to exist. */
|
||||||
|
|
||||||
|
unsigned int namelen = strlen(qdomain);
|
||||||
|
unsigned int matchlen = 0;
|
||||||
|
struct server *serv;
|
||||||
|
unsigned short flags = 0;
|
||||||
|
|
||||||
|
for (serv=servers; serv; serv=serv->next)
|
||||||
|
/* domain matches take priority over NODOTS matches */
|
||||||
|
if ((serv->flags & SERV_FOR_NODOTS) && *type != SERV_HAS_DOMAIN && !strchr(qdomain, '.'))
|
||||||
|
{
|
||||||
|
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||||
|
*type = SERV_FOR_NODOTS;
|
||||||
|
flags = 0;
|
||||||
|
if (serv->flags & SERV_NO_ADDR)
|
||||||
|
flags = F_NOERR;
|
||||||
|
else if ((serv->flags & SERV_LITERAL_ADDRESS) && (sflag & qtype))
|
||||||
|
{
|
||||||
|
flags = sflag;
|
||||||
|
if (serv->addr.sa.sa_family == AF_INET)
|
||||||
|
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else
|
||||||
|
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (serv->flags & SERV_HAS_DOMAIN)
|
||||||
|
{
|
||||||
|
unsigned int domainlen = strlen(serv->domain);
|
||||||
|
if (namelen >= domainlen &&
|
||||||
|
hostname_isequal(qdomain + namelen - domainlen, serv->domain) &&
|
||||||
|
domainlen >= matchlen)
|
||||||
|
{
|
||||||
|
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||||
|
*type = SERV_HAS_DOMAIN;
|
||||||
|
*domain = serv->domain;
|
||||||
|
matchlen = domainlen;
|
||||||
|
flags = 0;
|
||||||
|
if (serv->flags & SERV_NO_ADDR)
|
||||||
|
flags = F_NOERR;
|
||||||
|
else if ((serv->flags & SERV_LITERAL_ADDRESS) && ((sflag | F_QUERY ) & qtype))
|
||||||
|
{
|
||||||
|
flags = qtype;
|
||||||
|
if (serv->addr.sa.sa_family == AF_INET)
|
||||||
|
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else
|
||||||
|
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & ~F_NOERR) /* flags set here means a literal found */
|
||||||
|
{
|
||||||
|
if (flags & F_QUERY)
|
||||||
|
log_query(F_CONFIG | F_FORWARD | F_NEG, qdomain, NULL);
|
||||||
|
else
|
||||||
|
log_query(F_CONFIG | F_FORWARD | flags, qdomain, *addrpp);
|
||||||
|
}
|
||||||
|
else if (qtype && (options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.'))
|
||||||
|
flags = F_NXDOMAIN;
|
||||||
|
|
||||||
|
if (flags & (F_NOERR | F_NXDOMAIN))
|
||||||
|
log_query(F_CONFIG | F_FORWARD | F_NEG | qtype | (flags & F_NXDOMAIN), qdomain, NULL);
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
/* returns new last_server */
|
/* returns new last_server */
|
||||||
static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||||
@@ -146,75 +224,11 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (gotname)
|
if (gotname)
|
||||||
{
|
flags = search_servers(servers, options, &addrp, gotname, dnamebuff, &type, &domain);
|
||||||
/* If the query ends in the domain in one of our servers, set
|
|
||||||
domain to point to that name. We find the largest match to allow both
|
|
||||||
domain.org and sub.domain.org to exist. */
|
|
||||||
|
|
||||||
unsigned int namelen = strlen(dnamebuff);
|
if (!flags && !(forward = get_new_frec(now)))
|
||||||
unsigned int matchlen = 0;
|
/* table full - server failure. */
|
||||||
struct server *serv;
|
flags = F_NEG;
|
||||||
|
|
||||||
for (serv=servers; serv; serv=serv->next)
|
|
||||||
/* domain matches take priority over NODOTS matches */
|
|
||||||
if ((serv->flags & SERV_FOR_NODOTS) && type != SERV_HAS_DOMAIN && !strchr(dnamebuff, '.'))
|
|
||||||
{
|
|
||||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
|
||||||
type = SERV_FOR_NODOTS;
|
|
||||||
flags = 0;
|
|
||||||
if ((serv->flags & SERV_LITERAL_ADDRESS) && (sflag & gotname))
|
|
||||||
{
|
|
||||||
flags = sflag;
|
|
||||||
if (serv->addr.sa.sa_family == AF_INET)
|
|
||||||
addrp = (struct all_addr *)&serv->addr.in.sin_addr;
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
else
|
|
||||||
addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (serv->flags & SERV_HAS_DOMAIN)
|
|
||||||
{
|
|
||||||
unsigned int domainlen = strlen(serv->domain);
|
|
||||||
if (namelen >= domainlen &&
|
|
||||||
hostname_isequal(dnamebuff + namelen - domainlen, serv->domain) &&
|
|
||||||
domainlen >= matchlen)
|
|
||||||
{
|
|
||||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
|
||||||
type = SERV_HAS_DOMAIN;
|
|
||||||
domain = serv->domain;
|
|
||||||
matchlen = domainlen;
|
|
||||||
flags = 0;
|
|
||||||
if ((serv->flags & SERV_LITERAL_ADDRESS) && ((sflag | F_QUERY ) & gotname))
|
|
||||||
{
|
|
||||||
flags = gotname;
|
|
||||||
if (serv->addr.sa.sa_family == AF_INET)
|
|
||||||
addrp = (struct all_addr *)&serv->addr.in.sin_addr;
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
else
|
|
||||||
addrp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags) /* flags set here means a literal found */
|
|
||||||
{
|
|
||||||
if (flags & F_QUERY)
|
|
||||||
log_query(F_CONFIG | F_FORWARD | F_NEG, dnamebuff, NULL);
|
|
||||||
else
|
|
||||||
log_query(F_CONFIG | F_FORWARD | flags, dnamebuff, addrp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* we may by policy not forward names without a domain part */
|
|
||||||
if (gotname && (options & OPT_NODOTS_LOCAL) && !strchr(dnamebuff, '.'))
|
|
||||||
flags = F_NXDOMAIN;
|
|
||||||
else if (!(forward = get_new_frec(now)))
|
|
||||||
/* table full - server failure. */
|
|
||||||
flags = F_NEG;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (forward)
|
if (forward)
|
||||||
{
|
{
|
||||||
@@ -257,12 +271,10 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
if (type == (start->flags & SERV_TYPE) &&
|
if (type == (start->flags & SERV_TYPE) &&
|
||||||
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)))
|
(type != SERV_HAS_DOMAIN || hostname_isequal(domain, start->domain)))
|
||||||
{
|
{
|
||||||
if (start->flags & SERV_NO_ADDR)
|
if (!(start->flags & SERV_LITERAL_ADDRESS) &&
|
||||||
flags = F_NOERR; /* NULL servers are OK. */
|
sendto(start->sfd->fd, (char *)header, plen, 0,
|
||||||
else if (!(start->flags & SERV_LITERAL_ADDRESS) &&
|
&start->addr.sa,
|
||||||
sendto(start->sfd->fd, (char *)header, plen, 0,
|
sa_len(&start->addr)) != -1)
|
||||||
&start->addr.sa,
|
|
||||||
sa_len(&start->addr)) != -1)
|
|
||||||
{
|
{
|
||||||
if (!gotname)
|
if (!gotname)
|
||||||
strcpy(dnamebuff, "query");
|
strcpy(dnamebuff, "query");
|
||||||
@@ -282,7 +294,7 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!(start = start->next))
|
if (!(start = start->next))
|
||||||
start = servers;
|
start = servers;
|
||||||
|
|
||||||
if (start == firstsentto)
|
if (start == firstsentto)
|
||||||
break;
|
break;
|
||||||
@@ -300,16 +312,65 @@ static struct server *forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
plen = setup_reply(header, (unsigned int)plen, addrp, flags, local_ttl);
|
plen = setup_reply(header, (unsigned int)plen, addrp, flags, local_ttl);
|
||||||
send_from(udpfd, options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr);
|
send_from(udpfd, options & OPT_NOWILD, (char *)header, plen, udpaddr, dst_addr);
|
||||||
|
|
||||||
if (flags & (F_NOERR | F_NXDOMAIN))
|
|
||||||
log_query(F_CONFIG | F_FORWARD | F_NEG | gotname | (flags & F_NXDOMAIN), dnamebuff, NULL);
|
|
||||||
|
|
||||||
return last_server;
|
return last_server;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int process_reply(HEADER *header, time_t now, char *dnamebuff, struct bogus_addr *bogus_nxdomain,
|
||||||
|
struct doctor *doctors, union mysockaddr *serveraddr,
|
||||||
|
int n, int options, unsigned short edns_pcktsz)
|
||||||
|
{
|
||||||
|
unsigned char *pheader;
|
||||||
|
|
||||||
|
/* If upstream is advertising a larger UDP packet size
|
||||||
|
than we allow, trim it so that we don't get overlarge
|
||||||
|
requests for the client. */
|
||||||
|
|
||||||
|
if ((pheader = find_pseudoheader(header, n)))
|
||||||
|
{
|
||||||
|
unsigned short udpsz;
|
||||||
|
unsigned char *psave = pheader;
|
||||||
|
|
||||||
|
GETSHORT(udpsz, pheader);
|
||||||
|
if (udpsz > edns_pcktsz)
|
||||||
|
PUTSHORT(edns_pcktsz, psave);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Complain loudly if the upstream server is non-recursive. */
|
||||||
|
if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0)
|
||||||
|
{
|
||||||
|
char addrbuff[ADDRSTRLEN];
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (serveraddr->sa.sa_family == AF_INET)
|
||||||
|
inet_ntop(AF_INET, &serveraddr->in.sin_addr, addrbuff, ADDRSTRLEN);
|
||||||
|
else if (serveraddr->sa.sa_family == AF_INET6)
|
||||||
|
inet_ntop(AF_INET6, &serveraddr->in6.sin6_addr, addrbuff, ADDRSTRLEN);
|
||||||
|
#else
|
||||||
|
strcpy(addrbuff, inet_ntoa(serveraddr->in.sin_addr));
|
||||||
|
#endif
|
||||||
|
syslog(LOG_WARNING, "nameserver %s refused to do a recursive query", addrbuff);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((header->rcode == NOERROR || header->rcode == NXDOMAIN) && header->opcode == QUERY)
|
||||||
|
{
|
||||||
|
if (!(bogus_nxdomain &&
|
||||||
|
header->rcode == NOERROR &&
|
||||||
|
check_for_bogus_wildcard(header, (unsigned int)n, dnamebuff, bogus_nxdomain, now)))
|
||||||
|
{
|
||||||
|
if (header->rcode == NOERROR && ntohs(header->ancount) != 0)
|
||||||
|
extract_addresses(header, (unsigned int)n, dnamebuff, now, doctors);
|
||||||
|
else if (!(options & OPT_NO_NEG))
|
||||||
|
extract_neg_addrs(header, (unsigned int)n, dnamebuff, now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* returns new last_server */
|
/* returns new last_server */
|
||||||
struct server *reply_query(struct serverfd *sfd, int options, char *packet, time_t now,
|
struct server *reply_query(struct serverfd *sfd, int options, char *packet, time_t now,
|
||||||
char *dnamebuff, struct server *servers, struct server *last_server,
|
char *dnamebuff, struct server *servers, struct server *last_server,
|
||||||
struct bogus_addr *bogus_nxdomain, struct doctor *doctors)
|
struct bogus_addr *bogus_nxdomain, struct doctor *doctors, unsigned short edns_pcktsz)
|
||||||
{
|
{
|
||||||
/* packet from peer server, extract data for cache, and send to
|
/* packet from peer server, extract data for cache, and send to
|
||||||
original requester */
|
original requester */
|
||||||
@@ -317,7 +378,7 @@ struct server *reply_query(struct serverfd *sfd, int options, char *packet, time
|
|||||||
HEADER *header;
|
HEADER *header;
|
||||||
union mysockaddr serveraddr;
|
union mysockaddr serveraddr;
|
||||||
socklen_t addrlen = sizeof(serveraddr);
|
socklen_t addrlen = sizeof(serveraddr);
|
||||||
int n = recvfrom(sfd->fd, packet, PACKETSZ, 0, &serveraddr.sa, &addrlen);
|
int n = recvfrom(sfd->fd, packet, edns_pcktsz, 0, &serveraddr.sa, &addrlen);
|
||||||
|
|
||||||
/* Determine the address of the server replying so that we can mark that as good */
|
/* Determine the address of the server replying so that we can mark that as good */
|
||||||
serveraddr.sa.sa_family = sfd->source_addr.sa.sa_family;
|
serveraddr.sa.sa_family = sfd->source_addr.sa.sa_family;
|
||||||
@@ -340,40 +401,10 @@ struct server *reply_query(struct serverfd *sfd, int options, char *packet, time
|
|||||||
last_server = forward->sentto;
|
last_server = forward->sentto;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Complain loudly if the upstream server is non-recursive. */
|
if (!process_reply(header, now, dnamebuff, bogus_nxdomain, doctors, &serveraddr, n, options, edns_pcktsz))
|
||||||
if (!header->ra && header->rcode == NOERROR && ntohs(header->ancount) == 0)
|
return NULL;
|
||||||
{
|
|
||||||
char addrbuff[ADDRSTRLEN];
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
if (serveraddr.sa.sa_family == AF_INET)
|
|
||||||
inet_ntop(AF_INET, &serveraddr.in.sin_addr, addrbuff, ADDRSTRLEN);
|
|
||||||
else if (serveraddr.sa.sa_family == AF_INET6)
|
|
||||||
inet_ntop(AF_INET6, &serveraddr.in6.sin6_addr, addrbuff, ADDRSTRLEN);
|
|
||||||
#else
|
|
||||||
strcpy(addrbuff, inet_ntoa(serveraddr.in.sin_addr));
|
|
||||||
#endif
|
|
||||||
syslog(LOG_WARNING, "nameserver %s refused to do a recursive query", addrbuff);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((header->rcode == NOERROR || header->rcode == NXDOMAIN) && header->opcode == QUERY)
|
|
||||||
{
|
|
||||||
if (!(bogus_nxdomain &&
|
|
||||||
header->rcode == NOERROR &&
|
|
||||||
check_for_bogus_wildcard(header, (unsigned int)n, dnamebuff, bogus_nxdomain, now)))
|
|
||||||
{
|
|
||||||
if (header->rcode == NOERROR && ntohs(header->ancount) != 0)
|
|
||||||
extract_addresses(header, (unsigned int)n, dnamebuff, now, doctors);
|
|
||||||
else if (!(options & OPT_NO_NEG))
|
|
||||||
extract_neg_addrs(header, (unsigned int)n, dnamebuff, now);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
header->id = htons(forward->orig_id);
|
header->id = htons(forward->orig_id);
|
||||||
/* There's no point returning an upstream reply marked as truncated,
|
|
||||||
since that will prod the resolver into moving to TCP - which we
|
|
||||||
don't support. */
|
|
||||||
header->tc = 0; /* goodbye truncate */
|
|
||||||
send_from(forward->fd, options & OPT_NOWILD, packet, n, &forward->source, &forward->dest);
|
send_from(forward->fd, options & OPT_NOWILD, packet, n, &forward->source, &forward->dest);
|
||||||
forward->new_id = 0; /* cancel */
|
forward->new_id = 0; /* cancel */
|
||||||
}
|
}
|
||||||
@@ -385,12 +416,13 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
|||||||
char *mxtarget, unsigned int options, time_t now,
|
char *mxtarget, unsigned int options, time_t now,
|
||||||
unsigned long local_ttl, char *namebuff,
|
unsigned long local_ttl, char *namebuff,
|
||||||
struct iname *names, struct iname *addrs, struct iname *except,
|
struct iname *names, struct iname *addrs, struct iname *except,
|
||||||
struct server *last_server, struct server *servers)
|
struct server *last_server, struct server *servers, unsigned short edns_pcktsz)
|
||||||
{
|
{
|
||||||
HEADER *header = (HEADER *)packet;
|
HEADER *header = (HEADER *)packet;
|
||||||
union mysockaddr source_addr;
|
union mysockaddr source_addr;
|
||||||
struct iname *tmp;
|
struct iname *tmp;
|
||||||
struct all_addr dst_addr;
|
struct all_addr dst_addr;
|
||||||
|
int check_dst = !(options & OPT_NOWILD);
|
||||||
int m, n, if_index = 0;
|
int m, n, if_index = 0;
|
||||||
struct iovec iov[1];
|
struct iovec iov[1];
|
||||||
struct msghdr msg;
|
struct msghdr msg;
|
||||||
@@ -409,7 +441,7 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
|||||||
} control_u;
|
} control_u;
|
||||||
|
|
||||||
iov[0].iov_base = packet;
|
iov[0].iov_base = packet;
|
||||||
iov[0].iov_len = PACKETSZ;
|
iov[0].iov_len = edns_pcktsz;
|
||||||
|
|
||||||
msg.msg_control = control_u.control;
|
msg.msg_control = control_u.control;
|
||||||
msg.msg_controllen = sizeof(control_u);
|
msg.msg_controllen = sizeof(control_u);
|
||||||
@@ -425,14 +457,17 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
|||||||
source_addr.sa.sa_family = listen->family;
|
source_addr.sa.sa_family = listen->family;
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (listen->family == AF_INET6)
|
if (listen->family == AF_INET6)
|
||||||
source_addr.in6.sin6_flowinfo = htonl(0);
|
{
|
||||||
|
check_dst = 1;
|
||||||
|
source_addr.in6.sin6_flowinfo = htonl(0);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!(options & OPT_NOWILD) && msg.msg_controllen < sizeof(struct cmsghdr))
|
if (check_dst && msg.msg_controllen < sizeof(struct cmsghdr))
|
||||||
return last_server;
|
return last_server;
|
||||||
|
|
||||||
#if defined(IP_PKTINFO)
|
#if defined(IP_PKTINFO)
|
||||||
if (!(options & OPT_NOWILD) && listen->family == AF_INET)
|
if (check_dst && listen->family == AF_INET)
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
{
|
{
|
||||||
@@ -440,7 +475,7 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
|||||||
if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
|
if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
|
||||||
}
|
}
|
||||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||||
if (!(options & OPT_NOWILD) && listen->family == AF_INET)
|
if (check_dst && listen->family == AF_INET)
|
||||||
{
|
{
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||||
@@ -451,7 +486,7 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (!(options & OPT_NOWILD) && listen->family == AF_INET6)
|
if (listen->family == AF_INET6)
|
||||||
{
|
{
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
|
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
|
||||||
@@ -466,7 +501,7 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
|||||||
return last_server;
|
return last_server;
|
||||||
|
|
||||||
/* enforce available interface configuration */
|
/* enforce available interface configuration */
|
||||||
if (!(options & OPT_NOWILD))
|
if (check_dst)
|
||||||
{
|
{
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
|
|
||||||
@@ -527,7 +562,7 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
|||||||
}
|
}
|
||||||
|
|
||||||
m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n,
|
m = answer_request (header, ((char *) header) + PACKETSZ, (unsigned int)n,
|
||||||
mxnames, mxtarget, options, now, local_ttl, namebuff);
|
mxnames, mxtarget, options, now, local_ttl, namebuff, edns_pcktsz);
|
||||||
if (m >= 1)
|
if (m >= 1)
|
||||||
send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr);
|
send_from(listen->fd, options & OPT_NOWILD, (char *)header, m, &source_addr, &dst_addr);
|
||||||
else
|
else
|
||||||
@@ -537,6 +572,194 @@ struct server *receive_query(struct listener *listen, char *packet, struct mx_re
|
|||||||
return last_server;
|
return last_server;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int read_write(int fd, char *packet, int size, int rw)
|
||||||
|
{
|
||||||
|
int n, done;
|
||||||
|
|
||||||
|
for (done = 0; done < size; done += n)
|
||||||
|
{
|
||||||
|
retry:
|
||||||
|
if (rw)
|
||||||
|
n = read(fd, &packet[done], (size_t)(size - done));
|
||||||
|
else
|
||||||
|
n = write(fd, &packet[done], (size_t)(size - done));
|
||||||
|
|
||||||
|
if (n == 0)
|
||||||
|
return 0;
|
||||||
|
else if (n == -1)
|
||||||
|
{
|
||||||
|
if (errno == EINTR)
|
||||||
|
goto retry;
|
||||||
|
else if (errno == EAGAIN)
|
||||||
|
{
|
||||||
|
struct timespec waiter;
|
||||||
|
waiter.tv_sec = 0;
|
||||||
|
waiter.tv_nsec = 10000;
|
||||||
|
nanosleep(&waiter, NULL);
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The daemon forks before calling this: it should deal with one connection,
|
||||||
|
blocking as neccessary, and then return. Note, need to be a bit careful
|
||||||
|
about resources for debug mode, when the fork is suppressed: that's
|
||||||
|
done by the caller. */
|
||||||
|
char *tcp_request(int confd, struct mx_record *mxnames,
|
||||||
|
char *mxtarget, unsigned int options, time_t now,
|
||||||
|
unsigned long local_ttl, char *namebuff,
|
||||||
|
struct server *last_server, struct server *servers,
|
||||||
|
struct bogus_addr *bogus_nxdomain, struct doctor *doctors,
|
||||||
|
unsigned short edns_pktsz)
|
||||||
|
{
|
||||||
|
int size = 0, m;
|
||||||
|
unsigned char c1, c2;
|
||||||
|
/* Max TCP packet + slop */
|
||||||
|
char *packet = malloc(65536 + MAXDNAME + RRFIXEDSZ);
|
||||||
|
HEADER *header;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (!packet ||
|
||||||
|
!read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
|
||||||
|
!(size = c1 << 8 | c2) ||
|
||||||
|
!read_write(confd, packet, size, 1))
|
||||||
|
return packet;
|
||||||
|
|
||||||
|
if (size < (int)sizeof(HEADER))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
header = (HEADER *)packet;
|
||||||
|
|
||||||
|
if (extract_request(header, (unsigned int)size, namebuff))
|
||||||
|
{
|
||||||
|
union mysockaddr peer_addr;
|
||||||
|
socklen_t peer_len = sizeof(union mysockaddr);
|
||||||
|
|
||||||
|
if (getpeername(confd, (struct sockaddr *)&peer_addr, &peer_len) != -1)
|
||||||
|
{
|
||||||
|
if (peer_addr.sa.sa_family == AF_INET)
|
||||||
|
log_query(F_QUERY | F_IPV4 | F_FORWARD, namebuff,
|
||||||
|
(struct all_addr *)&peer_addr.in.sin_addr);
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else
|
||||||
|
log_query(F_QUERY | F_IPV6 | F_FORWARD, namebuff,
|
||||||
|
(struct all_addr *)&peer_addr.in6.sin6_addr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* m > 0 if answered from cache */
|
||||||
|
m = answer_request (header, ((char *) header) + 65536, (unsigned int)size,
|
||||||
|
mxnames, mxtarget, options, now, local_ttl, namebuff, edns_pktsz);
|
||||||
|
|
||||||
|
if (m == 0)
|
||||||
|
{
|
||||||
|
unsigned short flags = 0;
|
||||||
|
unsigned short gotname = extract_request(header, (unsigned int)size, namebuff);
|
||||||
|
struct all_addr *addrp = NULL;
|
||||||
|
int type = 0;
|
||||||
|
char *domain = NULL;
|
||||||
|
|
||||||
|
if (gotname)
|
||||||
|
flags = search_servers(servers, options, &addrp, gotname, namebuff, &type, &domain);
|
||||||
|
|
||||||
|
if (type != 0 || (options & OPT_ORDER) || !last_server)
|
||||||
|
last_server = servers;
|
||||||
|
|
||||||
|
if (!flags && last_server)
|
||||||
|
{
|
||||||
|
struct server *firstsendto = NULL;
|
||||||
|
|
||||||
|
/* Loop round available servers until we succeed in connecting to one.
|
||||||
|
Note that this code subtley ensures that consecutive queries on this connection
|
||||||
|
which can go to the same server, do so. */
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
if (!firstsendto)
|
||||||
|
firstsendto = last_server;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!(last_server = last_server->next))
|
||||||
|
last_server = servers;
|
||||||
|
|
||||||
|
if (last_server == firstsendto)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* server for wrong domain */
|
||||||
|
if (type != (last_server->flags & SERV_TYPE) ||
|
||||||
|
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if ((last_server->tcpfd == -1) &&
|
||||||
|
(last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) != -1 &&
|
||||||
|
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1)
|
||||||
|
{
|
||||||
|
close(last_server->tcpfd);
|
||||||
|
last_server->tcpfd = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (last_server->tcpfd == -1)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
c1 = size >> 8;
|
||||||
|
c2 = size;
|
||||||
|
|
||||||
|
if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
|
||||||
|
!read_write(last_server->tcpfd, &c2, 1, 0) ||
|
||||||
|
!read_write(last_server->tcpfd, packet, size, 0) ||
|
||||||
|
!read_write(last_server->tcpfd, &c1, 1, 1) ||
|
||||||
|
!read_write(last_server->tcpfd, &c2, 1, 1))
|
||||||
|
{
|
||||||
|
close(last_server->tcpfd);
|
||||||
|
last_server->tcpfd = -1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
m = (c1 << 8) | c2;
|
||||||
|
if (!read_write(last_server->tcpfd, packet, m, 1))
|
||||||
|
return packet;
|
||||||
|
|
||||||
|
if (!gotname)
|
||||||
|
strcpy(namebuff, "query");
|
||||||
|
if (last_server->addr.sa.sa_family == AF_INET)
|
||||||
|
log_query(F_SERVER | F_IPV4 | F_FORWARD, namebuff,
|
||||||
|
(struct all_addr *)&last_server->addr.in.sin_addr);
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else
|
||||||
|
log_query(F_SERVER | F_IPV6 | F_FORWARD, namebuff,
|
||||||
|
(struct all_addr *)&last_server->addr.in6.sin6_addr);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* There's no point in updating the cache, since this process will exit and
|
||||||
|
lose the information after one query. We make this call for the alias and
|
||||||
|
bogus-nxdomain side-effects. */
|
||||||
|
process_reply(header, now, namebuff, bogus_nxdomain, doctors,
|
||||||
|
&last_server->addr, m, options, edns_pktsz);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In case of local answer or no connections made. */
|
||||||
|
if (m == 0)
|
||||||
|
m = setup_reply(header, (unsigned int)size, addrp, flags, local_ttl);
|
||||||
|
}
|
||||||
|
|
||||||
|
c1 = m>>8;
|
||||||
|
c2 = m;
|
||||||
|
if (!read_write(confd, &c1, 1, 0) ||
|
||||||
|
!read_write(confd, &c2, 1, 0) ||
|
||||||
|
!read_write(confd, packet, m, 0))
|
||||||
|
return packet;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static struct frec *get_new_frec(time_t now)
|
static struct frec *get_new_frec(time_t now)
|
||||||
{
|
{
|
||||||
struct frec *f = frec_list, *oldest = NULL;
|
struct frec *f = frec_list, *oldest = NULL;
|
||||||
@@ -603,7 +826,7 @@ static struct frec *lookup_frec(unsigned short id)
|
|||||||
static struct frec *lookup_frec_by_sender(unsigned short id,
|
static struct frec *lookup_frec_by_sender(unsigned short id,
|
||||||
union mysockaddr *addr)
|
union mysockaddr *addr)
|
||||||
{
|
{
|
||||||
struct frec *f;
|
struct frec *f;
|
||||||
|
|
||||||
for(f = frec_list; f; f = f->next)
|
for(f = frec_list; f; f = f->next)
|
||||||
if (f->new_id &&
|
if (f->new_id &&
|
||||||
|
|||||||
@@ -220,9 +220,6 @@ void lease_prune(struct dhcp_lease *target, time_t now)
|
|||||||
|
|
||||||
struct dhcp_lease *lease_find_by_client(unsigned char *clid, int clid_len)
|
struct dhcp_lease *lease_find_by_client(unsigned char *clid, int clid_len)
|
||||||
{
|
{
|
||||||
/* zero length means clid from hwaddr: never match am option clid to
|
|
||||||
a hardware-address derived clid */
|
|
||||||
|
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
if (clid_len)
|
if (clid_len)
|
||||||
@@ -235,8 +232,7 @@ struct dhcp_lease *lease_find_by_client(unsigned char *clid, int clid_len)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
if (!lease->clid &&
|
if (memcmp(clid, lease->hwaddr, ETHER_ADDR_LEN) == 0)
|
||||||
memcmp(clid, lease->hwaddr, ETHER_ADDR_LEN) == 0)
|
|
||||||
return lease;
|
return lease;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
210
src/network.c
210
src/network.c
@@ -25,7 +25,11 @@ static struct irec *add_iface(struct irec *list, char *name, union mysockaddr *a
|
|||||||
if (except)
|
if (except)
|
||||||
for (tmp = except; tmp; tmp = tmp->next)
|
for (tmp = except; tmp; tmp = tmp->next)
|
||||||
if (tmp->name && strcmp(tmp->name, name) == 0)
|
if (tmp->name && strcmp(tmp->name, name) == 0)
|
||||||
return list;
|
{
|
||||||
|
/* record address of named interfaces, for TCP access control */
|
||||||
|
tmp->addr = *addr;
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
/* we may need to check the whitelist */
|
/* we may need to check the whitelist */
|
||||||
if (names || addrs)
|
if (names || addrs)
|
||||||
@@ -34,7 +38,10 @@ static struct irec *add_iface(struct irec *list, char *name, union mysockaddr *a
|
|||||||
|
|
||||||
for (tmp = names; tmp; tmp = tmp->next)
|
for (tmp = names; tmp; tmp = tmp->next)
|
||||||
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
if (tmp->name && (strcmp(tmp->name, name) == 0))
|
||||||
found = tmp->used = 1;
|
{
|
||||||
|
tmp->addr = *addr;
|
||||||
|
found = tmp->used = 1;
|
||||||
|
}
|
||||||
|
|
||||||
for (tmp = addrs; tmp; tmp = tmp->next)
|
for (tmp = addrs; tmp; tmp = tmp->next)
|
||||||
if (sockaddr_isequal(&tmp->addr, addr))
|
if (sockaddr_isequal(&tmp->addr, addr))
|
||||||
@@ -220,46 +227,14 @@ struct irec *enumerate_interfaces(struct iname **names,
|
|||||||
return iface;
|
return iface;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct listener *create_wildcard_listeners(int port)
|
#ifdef HAVE_IPV6
|
||||||
|
static int create_ipv6_listener(struct listener **link, int port)
|
||||||
{
|
{
|
||||||
#if !(defined(IP_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR)))
|
|
||||||
return NULL;
|
|
||||||
#else
|
|
||||||
union mysockaddr addr;
|
union mysockaddr addr;
|
||||||
|
int tcpfd, fd, flags, save;
|
||||||
|
struct listener *l;
|
||||||
int opt = 1;
|
int opt = 1;
|
||||||
struct listener *listen;
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
int fd;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
addr.in.sin_family = AF_INET;
|
|
||||||
addr.in.sin_addr.s_addr = INADDR_ANY;
|
|
||||||
addr.in.sin_port = htons(port);
|
|
||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
|
||||||
addr.in.sin_len = sizeof(struct sockaddr_in);
|
|
||||||
#endif
|
|
||||||
listen = safe_malloc(sizeof(struct listener));
|
|
||||||
if ((listen->fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
|
||||||
{
|
|
||||||
free(listen);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (setsockopt(listen->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
|
||||||
#if defined(IP_PKTINFO)
|
|
||||||
setsockopt(listen->fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
|
||||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
|
||||||
setsockopt(listen->fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
|
||||||
setsockopt(listen->fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
|
||||||
#endif
|
|
||||||
bind(listen->fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
|
||||||
{
|
|
||||||
close(listen->fd);
|
|
||||||
free(listen);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
listen->next = NULL;
|
|
||||||
listen->family = AF_INET;
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
addr.in6.sin6_family = AF_INET6;
|
addr.in6.sin6_family = AF_INET6;
|
||||||
addr.in6.sin6_addr = in6addr_any;
|
addr.in6.sin6_addr = in6addr_any;
|
||||||
addr.in6.sin6_port = htons(port);
|
addr.in6.sin6_port = htons(port);
|
||||||
@@ -267,65 +242,148 @@ struct listener *create_wildcard_listeners(int port)
|
|||||||
#ifdef HAVE_SOCKADDR_SA_LEN
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* No error of the kernel doesn't support IPv6 */
|
||||||
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
|
if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) == -1)
|
||||||
|
return (errno == EPROTONOSUPPORT ||
|
||||||
|
errno == EAFNOSUPPORT ||
|
||||||
|
errno == EINVAL);
|
||||||
|
|
||||||
|
if ((tcpfd = socket(AF_INET6, SOCK_STREAM, 0)) == -1)
|
||||||
{
|
{
|
||||||
if (errno != EPROTONOSUPPORT &&
|
save = errno;
|
||||||
errno != EAFNOSUPPORT &&
|
close(fd);
|
||||||
errno != EINVAL)
|
errno = save;
|
||||||
{
|
return 0;
|
||||||
close(listen->fd);
|
|
||||||
free(listen);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
|
setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
|
setsockopt(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||||
|
setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||||
|
(flags = fcntl(tcpfd, F_GETFL, 0)) == -1 ||
|
||||||
|
fcntl(tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||||
|
setsockopt(fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||||
|
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
|
||||||
|
listen(tcpfd, 5) == -1 ||
|
||||||
|
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||||
{
|
{
|
||||||
listen->next = safe_malloc(sizeof(struct listener));
|
save = errno;
|
||||||
listen->next->fd = fd;
|
close(fd);
|
||||||
listen->next->family = AF_INET6;
|
close(tcpfd);
|
||||||
listen->next->next = NULL;
|
errno = save;
|
||||||
if (setsockopt(listen->next->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
return 0;
|
||||||
setsockopt(listen->next->fd, IPV6_LEVEL, IPV6_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
|
||||||
bind(listen->next->fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
|
||||||
{
|
|
||||||
close(listen->next->fd);
|
|
||||||
free(listen->next);
|
|
||||||
close(listen->fd);
|
|
||||||
free(listen);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
l = safe_malloc(sizeof(struct listener));
|
||||||
|
l->fd = fd;
|
||||||
|
l->tcpfd = tcpfd;
|
||||||
|
l->family = AF_INET6;
|
||||||
|
l->next = NULL;
|
||||||
|
*link = l;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return listen;
|
struct listener *create_wildcard_listeners(int port)
|
||||||
|
{
|
||||||
|
#if !(defined(IP_PKTINFO) || (defined(IP_RECVDSTADDR) && defined(IP_RECVIF) && defined(IP_SENDSRCADDR)))
|
||||||
|
return NULL;
|
||||||
|
#else
|
||||||
|
union mysockaddr addr;
|
||||||
|
int opt = 1;
|
||||||
|
struct listener *l, *l6 = NULL;
|
||||||
|
int flags;
|
||||||
|
int tcpfd, fd;
|
||||||
|
|
||||||
|
addr.in.sin_family = AF_INET;
|
||||||
|
addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
addr.in.sin_port = htons(port);
|
||||||
|
#ifdef HAVE_SOCKADDR_SA_LEN
|
||||||
|
addr.in.sin_len = sizeof(struct sockaddr_in);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if ((tcpfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
|
||||||
|
{
|
||||||
|
close (fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setsockopt(tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
|
bind(tcpfd, (struct sockaddr *)&addr, sa_len(&addr)) == -1 ||
|
||||||
|
listen(tcpfd, 5) == -1 ||
|
||||||
|
(flags = fcntl(tcpfd, F_GETFL, 0)) == -1 ||
|
||||||
|
fcntl(tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
!create_ipv6_listener(&l6, port) ||
|
||||||
|
#endif
|
||||||
|
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
|
#if defined(IP_PKTINFO)
|
||||||
|
setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||||
|
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||||
|
setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
|
setsockopt(fd, IPPROTO_IP, IP_RECVIF, &opt, sizeof(opt)) == -1 ||
|
||||||
|
#endif
|
||||||
|
bind(fd, (struct sockaddr *)&addr, sa_len(&addr)) == -1)
|
||||||
|
{
|
||||||
|
close(fd);
|
||||||
|
close(tcpfd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
l = safe_malloc(sizeof(struct listener));
|
||||||
|
l->family = AF_INET;
|
||||||
|
l->fd = fd;
|
||||||
|
l->tcpfd = tcpfd;
|
||||||
|
l->next = l6;
|
||||||
|
|
||||||
|
return l;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct listener *create_bound_listeners(struct irec *interfaces)
|
struct listener *create_bound_listeners(struct irec *interfaces, int port)
|
||||||
{
|
{
|
||||||
|
|
||||||
struct listener *listeners = NULL;
|
struct listener *listeners = NULL;
|
||||||
struct irec *iface;
|
struct irec *iface;
|
||||||
int opt = 1;
|
int flags = port, opt = 1;
|
||||||
|
|
||||||
|
/* Create bound listeners only for IPv4, IPv6 always binds the wildcard */
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (!create_ipv6_listener(&listeners, port))
|
||||||
|
die("failed to to create listening socket: %s", NULL);
|
||||||
|
#endif
|
||||||
|
|
||||||
for (iface = interfaces ;iface; iface = iface->next)
|
for (iface = interfaces ;iface; iface = iface->next)
|
||||||
{
|
if (iface->addr.sa.sa_family == AF_INET)
|
||||||
struct listener *new = safe_malloc(sizeof(struct listener));
|
{
|
||||||
new->family = iface->addr.sa.sa_family;
|
struct listener *new = safe_malloc(sizeof(struct listener));
|
||||||
new->next = listeners;
|
new->family = iface->addr.sa.sa_family;
|
||||||
listeners = new;
|
new->next = listeners;
|
||||||
if ((new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1)
|
listeners = new;
|
||||||
die("failed to create socket: %s", NULL);
|
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
|
||||||
if (setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
(new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
|
||||||
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1)
|
setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
die("failed to bind socket: %s", NULL);
|
setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
}
|
/* See Stevens 16.6 */
|
||||||
|
(flags = fcntl(new->tcpfd, F_GETFL, 0)) == -1 ||
|
||||||
|
fcntl(new->tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||||
|
bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
|
||||||
|
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
|
||||||
|
listen(new->tcpfd, 5) == -1)
|
||||||
|
die("failed to to create listening socket: %s", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
return listeners;
|
return listeners;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
|
struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
|
||||||
{
|
{
|
||||||
struct serverfd *sfd;
|
struct serverfd *sfd;
|
||||||
|
|
||||||
|
|||||||
25
src/option.c
25
src/option.c
@@ -21,7 +21,7 @@ struct myoption {
|
|||||||
int val;
|
int val;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OPTSTRING "ZDNLERzowefnbvhdqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:"
|
#define OPTSTRING "ZDNLERzowefnbvhdqr:m:p:c:l:s:i:t:u:g:a:x:S:C:A:T:H:Q:I:B:F:G:O:M:X:V:U:j:P:"
|
||||||
|
|
||||||
static struct myoption opts[] = {
|
static struct myoption opts[] = {
|
||||||
{"version", 0, 0, 'v'},
|
{"version", 0, 0, 'v'},
|
||||||
@@ -72,6 +72,7 @@ static struct myoption opts[] = {
|
|||||||
{"alias", 1, 0, 'V' },
|
{"alias", 1, 0, 'V' },
|
||||||
{"dhcp-vendorclass", 1, 0, 'U'},
|
{"dhcp-vendorclass", 1, 0, 'U'},
|
||||||
{"dhcp-userclass", 1, 0, 'j'},
|
{"dhcp-userclass", 1, 0, 'j'},
|
||||||
|
{"edns-packet-max", 1, 0, 'P'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -132,6 +133,7 @@ static char *usage =
|
|||||||
"-o, --strict-order Use nameservers strictly in the order given in " RESOLVFILE ".\n"
|
"-o, --strict-order Use nameservers strictly in the order given in " RESOLVFILE ".\n"
|
||||||
"-O, --dhcp-option=<optspec> Set extra options to be set to DHCP clients.\n"
|
"-O, --dhcp-option=<optspec> Set extra options to be set to DHCP clients.\n"
|
||||||
"-p, --port=number Specify port to listen for DNS requests on (defaults to 53).\n"
|
"-p, --port=number Specify port to listen for DNS requests on (defaults to 53).\n"
|
||||||
|
"-P, --edns-packet-max=<size> Maximum supported UDP packet size for EDNS.0 (defaults to %d).\n"
|
||||||
"-q, --log-queries Log queries.\n"
|
"-q, --log-queries Log queries.\n"
|
||||||
"-Q, --query-port=number Force the originating port for upstream queries.\n"
|
"-Q, --query-port=number Force the originating port for upstream queries.\n"
|
||||||
"-R, --no-resolv Do NOT read resolv.conf.\n"
|
"-R, --no-resolv Do NOT read resolv.conf.\n"
|
||||||
@@ -143,7 +145,7 @@ static char *usage =
|
|||||||
"-T, --local-ttl=time Specify time-to-live in seconds for replies from /etc/hosts.\n"
|
"-T, --local-ttl=time Specify time-to-live in seconds for replies from /etc/hosts.\n"
|
||||||
"-u, --user=username Change to this user after startup. (defaults to " CHUSER ").\n"
|
"-u, --user=username Change to this user after startup. (defaults to " CHUSER ").\n"
|
||||||
"-U, --dhcp-vendorclass=<id>,<class> Map DHCP vendor class to option set.\n"
|
"-U, --dhcp-vendorclass=<id>,<class> Map DHCP vendor class to option set.\n"
|
||||||
"-v, --version Display dnsmasq version.\n"
|
"-v, --version Display dnsmasq version and copyright information.\n"
|
||||||
"-V, --alias=addr,addr,mask Translate IPv4 addresses from upstream servers.\n"
|
"-V, --alias=addr,addr,mask Translate IPv4 addresses from upstream servers.\n"
|
||||||
"-w, --help Display this message.\n"
|
"-w, --help Display this message.\n"
|
||||||
"-x, --pid-file=path Specify path of PID file. (defaults to " RUNFILE ").\n"
|
"-x, --pid-file=path Specify path of PID file. (defaults to " RUNFILE ").\n"
|
||||||
@@ -161,7 +163,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
int *query_port, unsigned long *local_ttl, char **addn_hosts, struct dhcp_context **dhcp,
|
int *query_port, unsigned long *local_ttl, char **addn_hosts, struct dhcp_context **dhcp,
|
||||||
struct dhcp_config **dhcp_conf, struct dhcp_opt **dhcp_opts, struct dhcp_vendor **dhcp_vendors, char **dhcp_file,
|
struct dhcp_config **dhcp_conf, struct dhcp_opt **dhcp_opts, struct dhcp_vendor **dhcp_vendors, char **dhcp_file,
|
||||||
char **dhcp_sname, struct in_addr *dhcp_next_server, int *dhcp_max,
|
char **dhcp_sname, struct in_addr *dhcp_next_server, int *dhcp_max,
|
||||||
unsigned int *min_leasetime, struct doctor **doctors)
|
unsigned int *min_leasetime, struct doctor **doctors, unsigned short *edns_pktsz)
|
||||||
{
|
{
|
||||||
int option = 0, i;
|
int option = 0, i;
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
@@ -256,13 +258,16 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
|
|
||||||
if (!f && option == 'w')
|
if (!f && option == 'w')
|
||||||
{
|
{
|
||||||
fprintf (stderr, usage, CACHESIZ, MAXLEASES);
|
fprintf (stderr, usage, CACHESIZ, EDNS_PKTSZ, MAXLEASES);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!f && option == 'v')
|
if (!f && option == 'v')
|
||||||
{
|
{
|
||||||
fprintf(stderr, "dnsmasq version %s\n", VERSION);
|
fprintf(stderr, "Dnsmasq version %s %s\n\n", VERSION, COPYRIGHT);
|
||||||
|
fprintf(stderr, "This software comes with ABSOLUTELY NO WARRANTY.\n");
|
||||||
|
fprintf(stderr, "Dnsmasq is free software, and you are welcome to redistribute it\n");
|
||||||
|
fprintf(stderr, "under the terms of the GNU General Public License, version 2.\n");
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -658,6 +663,15 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
option = '?';
|
option = '?';
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'P':
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (!atoi_check(optarg, &i))
|
||||||
|
option = '?';
|
||||||
|
*edns_pktsz = (unsigned short)i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'Q':
|
case 'Q':
|
||||||
if (!atoi_check(optarg, query_port))
|
if (!atoi_check(optarg, query_port))
|
||||||
option = '?';
|
option = '?';
|
||||||
@@ -686,6 +700,7 @@ unsigned int read_opts (int argc, char **argv, char *buff, struct resolvc **reso
|
|||||||
|
|
||||||
new->next = *dhcp;
|
new->next = *dhcp;
|
||||||
new->lease_time = DEFLEASE;
|
new->lease_time = DEFLEASE;
|
||||||
|
new->addr_epoch = 0;
|
||||||
new->netmask.s_addr = 0;
|
new->netmask.s_addr = 0;
|
||||||
new->broadcast.s_addr = 0;
|
new->broadcast.s_addr = 0;
|
||||||
new->netid.net = NULL;
|
new->netid.net = NULL;
|
||||||
|
|||||||
515
src/rfc1035.c
515
src/rfc1035.c
@@ -244,52 +244,60 @@ static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned char *skip_name(unsigned char *ansp, HEADER *header, unsigned int plen)
|
||||||
|
{
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
unsigned int label_type = (*ansp) & 0xc0;
|
||||||
|
|
||||||
|
if ((unsigned int)(ansp - (unsigned char *)header) >= plen)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (label_type == 0xc0)
|
||||||
|
{
|
||||||
|
/* pointer for compression. */
|
||||||
|
ansp += 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (label_type == 0x80)
|
||||||
|
return NULL; /* reserved */
|
||||||
|
else if (label_type == 0x40)
|
||||||
|
{
|
||||||
|
/* Extended label type */
|
||||||
|
unsigned int count;
|
||||||
|
|
||||||
|
if (((*ansp++) & 0x3f) != 1)
|
||||||
|
return NULL; /* we only understand bitstrings */
|
||||||
|
|
||||||
|
count = *(ansp++); /* Bits in bitstring */
|
||||||
|
|
||||||
|
if (count == 0) /* count == 0 means 256 bits */
|
||||||
|
ansp += 32;
|
||||||
|
else
|
||||||
|
ansp += ((count-1)>>3)+1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ /* label type == 0 Bottom six bits is length */
|
||||||
|
unsigned int len = (*ansp++) & 0x3f;
|
||||||
|
if (len == 0)
|
||||||
|
break; /* zero length label marks the end. */
|
||||||
|
|
||||||
|
ansp += len;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ansp;
|
||||||
|
}
|
||||||
|
|
||||||
static unsigned char *skip_questions(HEADER *header, unsigned int plen)
|
static unsigned char *skip_questions(HEADER *header, unsigned int plen)
|
||||||
{
|
{
|
||||||
int q, qdcount = ntohs(header->qdcount);
|
int q, qdcount = ntohs(header->qdcount);
|
||||||
unsigned char *ansp = (unsigned char *)(header+1);
|
unsigned char *ansp = (unsigned char *)(header+1);
|
||||||
|
|
||||||
for (q=0; q<qdcount; q++)
|
for (q = 0; q<qdcount; q++)
|
||||||
{
|
{
|
||||||
while (1)
|
if (!(ansp = skip_name(ansp, header, plen)))
|
||||||
{
|
return NULL;
|
||||||
unsigned int label_type = (*ansp) & 0xc0;
|
|
||||||
|
|
||||||
if ((unsigned int)(ansp - (unsigned char *)header) >= plen)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (label_type == 0xc0)
|
|
||||||
{
|
|
||||||
/* pointer for compression. */
|
|
||||||
ansp += 2;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (label_type == 0x80)
|
|
||||||
return NULL; /* reserved */
|
|
||||||
else if (label_type == 0x40)
|
|
||||||
{
|
|
||||||
/* Extended label type */
|
|
||||||
unsigned int count;
|
|
||||||
|
|
||||||
if (((*ansp++) & 0x3f) != 1)
|
|
||||||
return NULL; /* we only understand bitstrings */
|
|
||||||
|
|
||||||
count = *(ansp++); /* Bits in bitstring */
|
|
||||||
|
|
||||||
if (count == 0) /* count == 0 means 256 bits */
|
|
||||||
ansp += 32;
|
|
||||||
else
|
|
||||||
ansp += ((count-1)>>3)+1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ /* label type == 0 Bottom six bits is length */
|
|
||||||
unsigned int len = (*ansp++) & 0x3f;
|
|
||||||
if (len == 0)
|
|
||||||
break; /* zero length label marks the end. */
|
|
||||||
|
|
||||||
ansp += len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ansp += 4; /* class and type */
|
ansp += 4; /* class and type */
|
||||||
}
|
}
|
||||||
if ((unsigned int)(ansp - (unsigned char *)header) > plen)
|
if ((unsigned int)(ansp - (unsigned char *)header) > plen)
|
||||||
@@ -298,6 +306,49 @@ static unsigned char *skip_questions(HEADER *header, unsigned int plen)
|
|||||||
return ansp;
|
return ansp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned char *find_pseudoheader(HEADER *header, unsigned int plen)
|
||||||
|
{
|
||||||
|
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it. */
|
||||||
|
|
||||||
|
int i, arcount = ntohs(header->arcount);
|
||||||
|
unsigned char *ansp;
|
||||||
|
unsigned short rdlen, type;
|
||||||
|
|
||||||
|
if (arcount == 0 || !(ansp = skip_questions(header, plen)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
for (i = 0; i < (ntohs(header->ancount) + ntohs(header->nscount)); i++)
|
||||||
|
{
|
||||||
|
if (!(ansp = skip_name(ansp, header, plen)))
|
||||||
|
return NULL;
|
||||||
|
ansp += 8; /* type, class, TTL */
|
||||||
|
GETSHORT(rdlen, ansp);
|
||||||
|
if ((unsigned int)(ansp + rdlen - (unsigned char *)header) > plen)
|
||||||
|
return NULL;
|
||||||
|
ansp += rdlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < arcount; i++)
|
||||||
|
{
|
||||||
|
unsigned char *save;
|
||||||
|
if (!(ansp = skip_name(ansp, header, plen)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
GETSHORT(type, ansp);
|
||||||
|
save = ansp;
|
||||||
|
ansp += 6; /* class, TTL */
|
||||||
|
GETSHORT(rdlen, ansp);
|
||||||
|
if ((unsigned int)(ansp + rdlen - (unsigned char *)header) > plen)
|
||||||
|
return NULL;
|
||||||
|
if (type == ns_t_opt)
|
||||||
|
return save;
|
||||||
|
ansp += rdlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* is addr in the non-globally-routed IP space? */
|
/* is addr in the non-globally-routed IP space? */
|
||||||
static int private_net(struct all_addr *addrp)
|
static int private_net(struct all_addr *addrp)
|
||||||
{
|
{
|
||||||
@@ -440,13 +491,16 @@ void extract_neg_addrs(HEADER *header, unsigned int qlen, char *name, time_t now
|
|||||||
cache_end_insert();
|
cache_end_insert();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void dns_doctor(struct doctor *doctor, struct in_addr *addr)
|
static void dns_doctor(HEADER *header, struct doctor *doctor, struct in_addr *addr)
|
||||||
{
|
{
|
||||||
for (; doctor; doctor = doctor->next)
|
for (; doctor; doctor = doctor->next)
|
||||||
if (is_same_net(doctor->in, *addr, doctor->mask))
|
if (is_same_net(doctor->in, *addr, doctor->mask))
|
||||||
{
|
{
|
||||||
addr->s_addr &= ~doctor->mask.s_addr;
|
addr->s_addr &= ~doctor->mask.s_addr;
|
||||||
addr->s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
|
addr->s_addr |= (doctor->out.s_addr & doctor->mask.s_addr);
|
||||||
|
/* Since we munged the data, the server it came from is no longer authoritative */
|
||||||
|
header->nscount = htons(0);
|
||||||
|
header->arcount = htons(0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -490,7 +544,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name,
|
|||||||
|
|
||||||
if (qtype == T_A) /* A record. */
|
if (qtype == T_A) /* A record. */
|
||||||
{
|
{
|
||||||
dns_doctor(doctors, (struct in_addr *)p);
|
dns_doctor(header, doctors, (struct in_addr *)p);
|
||||||
cache_insert(name, (struct all_addr *)p, now,
|
cache_insert(name, (struct all_addr *)p, now,
|
||||||
ttl, F_IPV4 | F_FORWARD);
|
ttl, F_IPV4 | F_FORWARD);
|
||||||
}
|
}
|
||||||
@@ -562,7 +616,7 @@ void extract_addresses(HEADER *header, unsigned int qlen, char *name,
|
|||||||
|
|
||||||
if (qtype == T_A) /* A record. */
|
if (qtype == T_A) /* A record. */
|
||||||
{
|
{
|
||||||
dns_doctor(doctors, (struct in_addr *)p);
|
dns_doctor(header, doctors, (struct in_addr *)p);
|
||||||
cache_insert(name, (struct all_addr *)p, now,
|
cache_insert(name, (struct all_addr *)p, now,
|
||||||
cttl, F_IPV4 | F_FORWARD);
|
cttl, F_IPV4 | F_FORWARD);
|
||||||
}
|
}
|
||||||
@@ -635,7 +689,7 @@ int setup_reply(HEADER *header, unsigned int qlen,
|
|||||||
header->tc = 0; /* not truncated */
|
header->tc = 0; /* not truncated */
|
||||||
header->nscount = htons(0);
|
header->nscount = htons(0);
|
||||||
header->arcount = htons(0);
|
header->arcount = htons(0);
|
||||||
header->ancount = htons(0); /* no answers unless changed below*/
|
header->ancount = htons(0); /* no answers unless changed below */
|
||||||
if (flags == F_NEG)
|
if (flags == F_NEG)
|
||||||
header->rcode = SERVFAIL; /* couldn't get memory */
|
header->rcode = SERVFAIL; /* couldn't get memory */
|
||||||
else if (flags == F_NOERR || flags == F_QUERY)
|
else if (flags == F_NOERR || flags == F_QUERY)
|
||||||
@@ -730,26 +784,57 @@ int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
|
|||||||
/* return zero if we can't answer from cache, or packet size if we can */
|
/* return zero if we can't answer from cache, or packet size if we can */
|
||||||
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_record *mxnames,
|
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_record *mxnames,
|
||||||
char *mxtarget, unsigned int options, time_t now,
|
char *mxtarget, unsigned int options, time_t now,
|
||||||
unsigned long local_ttl, char *name)
|
unsigned long local_ttl, char *name, unsigned short edns_pcktsz)
|
||||||
{
|
{
|
||||||
unsigned char *p, *ansp;
|
unsigned char *p, *ansp, *pheader;
|
||||||
int qtype, qclass, is_arpa;
|
int qtype, qclass, is_arpa;
|
||||||
struct all_addr addr;
|
struct all_addr addr;
|
||||||
unsigned int nameoffset;
|
unsigned int nameoffset;
|
||||||
int q, qdcount = ntohs(header->qdcount);
|
unsigned short flag;
|
||||||
int ans, anscount = 0;
|
int qdcount = ntohs(header->qdcount);
|
||||||
|
int q, ans, anscount;
|
||||||
|
int dryrun = 0, sec_reqd = 0;
|
||||||
struct crec *crecp;
|
struct crec *crecp;
|
||||||
int nxdomain = 0, auth = 1;
|
int nxdomain, auth;
|
||||||
|
|
||||||
if (!qdcount || header->opcode != QUERY )
|
if (!qdcount || header->opcode != QUERY )
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* If there is an RFC2671 pseudoheader then it will be overwritten by
|
||||||
|
partial replies, so we have to do a dry run to see if we can answer
|
||||||
|
the query. We check to see if the do bit is set, if so we always
|
||||||
|
forward rather than answering from the cache, which doesn't include
|
||||||
|
security information. */
|
||||||
|
|
||||||
|
if ((pheader = find_pseudoheader(header, qlen)))
|
||||||
|
{
|
||||||
|
unsigned short udpsz, ext_rcode, flags;
|
||||||
|
unsigned char *psave = pheader;
|
||||||
|
|
||||||
|
GETSHORT(udpsz, pheader);
|
||||||
|
GETSHORT(ext_rcode, pheader);
|
||||||
|
GETSHORT(flags, pheader);
|
||||||
|
|
||||||
|
sec_reqd = flags & 0x8000; /* do bit */
|
||||||
|
|
||||||
|
/* If our client is advertising a larger UDP packet size
|
||||||
|
than we allow, trim it so that we don't get an overlarge
|
||||||
|
response from upstream */
|
||||||
|
|
||||||
|
if (udpsz > edns_pcktsz)
|
||||||
|
PUTSHORT(edns_pcktsz, psave);
|
||||||
|
|
||||||
|
dryrun = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rerun:
|
||||||
/* determine end of question section (we put answers there) */
|
/* determine end of question section (we put answers there) */
|
||||||
if (!(ansp = skip_questions(header, qlen)))
|
if (!(ansp = skip_questions(header, qlen)))
|
||||||
return 0; /* bad packet */
|
return 0; /* bad packet */
|
||||||
|
|
||||||
/* now process each question, answers go in RRs after the question */
|
/* now process each question, answers go in RRs after the question */
|
||||||
p = (unsigned char *)(header+1);
|
p = (unsigned char *)(header+1);
|
||||||
|
nxdomain = 0, auth = 1, anscount = 0;
|
||||||
|
|
||||||
for (q=0; q<qdcount; q++)
|
for (q=0; q<qdcount; q++)
|
||||||
{
|
{
|
||||||
@@ -769,16 +854,19 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec
|
|||||||
|
|
||||||
ans = 0; /* have we answered this question */
|
ans = 0; /* have we answered this question */
|
||||||
|
|
||||||
if (qclass == C_CHAOS)
|
if (qclass == C_CHAOS && qtype == T_TXT)
|
||||||
/* special query to get version. */
|
/* special query to get version. */
|
||||||
{
|
{
|
||||||
if (qtype == T_TXT)
|
ans = 1;
|
||||||
|
if (!dryrun)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
if (hostname_isequal(name, "version.bind"))
|
if (hostname_isequal(name, "version.bind"))
|
||||||
sprintf(name, "dnsmasq-%s", VERSION);
|
sprintf(name, "dnsmasq-%s", VERSION);
|
||||||
else if (hostname_isequal(name, "authors.bind"))
|
else if (hostname_isequal(name, "authors.bind"))
|
||||||
sprintf(name, "Simon Kelley");
|
sprintf(name, "Simon Kelley");
|
||||||
|
else if (hostname_isequal(name, "copyright.bind"))
|
||||||
|
sprintf(name, COPYRIGHT);
|
||||||
else
|
else
|
||||||
*name = 0;
|
*name = 0;
|
||||||
len = strlen(name);
|
len = strlen(name);
|
||||||
@@ -790,235 +878,192 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct mx_rec
|
|||||||
*ansp++ = len;
|
*ansp++ = len;
|
||||||
memcpy(ansp, name, len);
|
memcpy(ansp, name, len);
|
||||||
ansp += len;
|
ansp += len;
|
||||||
ans = 1;
|
|
||||||
anscount++;
|
anscount++;
|
||||||
|
|
||||||
if (((unsigned char *)limit - ansp) < 0)
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
return 0;
|
else if (qclass == C_IN)
|
||||||
}
|
|
||||||
else if (qclass != C_IN)
|
|
||||||
return 0; /* we can't answer non-inet queries */
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
|
if ((options & OPT_FILTER) &&
|
||||||
if ((options & OPT_FILTER) && (qtype == T_SOA || qtype == T_SRV))
|
(qtype == T_SOA || qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
||||||
ans = 1;
|
ans = 1;
|
||||||
|
else
|
||||||
if (qtype == T_PTR || qtype == T_ANY)
|
|
||||||
{
|
{
|
||||||
crecp = NULL;
|
if (qtype == T_PTR || qtype == T_ANY)
|
||||||
while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)))
|
|
||||||
{
|
{
|
||||||
unsigned long ttl;
|
if (!(crecp = cache_find_by_addr(NULL, &addr, now, is_arpa)))
|
||||||
/* Return 0 ttl for DHCP entries, which might change
|
|
||||||
before the lease expires. */
|
|
||||||
if (crecp->flags & (F_IMMORTAL | F_DHCP))
|
|
||||||
ttl = local_ttl;
|
|
||||||
else
|
|
||||||
ttl = crecp->ttd - now;
|
|
||||||
|
|
||||||
/* don't answer wildcard queries with data not from /etc/hosts
|
|
||||||
or dhcp leases */
|
|
||||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
ans = 1;
|
|
||||||
if (crecp->flags & F_NEG)
|
|
||||||
{
|
{
|
||||||
log_query(crecp->flags & ~F_FORWARD, name, &addr);
|
if (is_arpa == F_IPV4 && (options & OPT_BOGUSPRIV) && private_net(&addr))
|
||||||
auth = 0;
|
{
|
||||||
if (crecp->flags & F_NXDOMAIN)
|
/* if not in cache, enabled and private IPV4 address, return NXDOMAIN */
|
||||||
nxdomain = 1;
|
ans = 1;
|
||||||
|
if (!dryrun)
|
||||||
|
{
|
||||||
|
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN, name, &addr);
|
||||||
|
nxdomain = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else do
|
||||||
{
|
{
|
||||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
/* don't answer wildcard queries with data not from /etc/hosts or dhcp leases */
|
||||||
auth = 0;
|
|
||||||
ansp = add_text_record(nameoffset, ansp, ttl, 0, T_PTR,
|
|
||||||
cache_get_name(crecp));
|
|
||||||
|
|
||||||
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr);
|
|
||||||
anscount++;
|
|
||||||
|
|
||||||
/* if last answer exceeded packet size, give up */
|
|
||||||
if (((unsigned char *)limit - ansp) < 0)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if not in cache, enabled and private IPV4 address, fake up answer */
|
|
||||||
if (ans == 0 && is_arpa == F_IPV4 &&
|
|
||||||
(options & OPT_BOGUSPRIV) &&
|
|
||||||
private_net(&addr))
|
|
||||||
{
|
|
||||||
struct in_addr addr4 = *((struct in_addr *)&addr);
|
|
||||||
ansp = add_text_record(nameoffset, ansp, local_ttl, 0, T_PTR, inet_ntoa(addr4));
|
|
||||||
log_query(F_CONFIG | F_REVERSE | F_IPV4, inet_ntoa(addr4), &addr);
|
|
||||||
anscount++;
|
|
||||||
ans = 1;
|
|
||||||
|
|
||||||
if (((unsigned char *)limit - ansp) < 0)
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qtype == T_A || qtype == T_ANY)
|
|
||||||
{
|
|
||||||
/* T_ANY queries for hostnames with underscores are spam
|
|
||||||
from win2k - don't forward them. */
|
|
||||||
if ((options & OPT_FILTER) &&
|
|
||||||
qtype == T_ANY &&
|
|
||||||
(strchr(name, '_') != NULL))
|
|
||||||
ans = 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
crecp = NULL;
|
|
||||||
while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4)))
|
|
||||||
{
|
|
||||||
unsigned long ttl;
|
|
||||||
if (crecp->flags & (F_IMMORTAL | F_DHCP))
|
|
||||||
ttl = local_ttl;
|
|
||||||
else
|
|
||||||
ttl = crecp->ttd - now;
|
|
||||||
|
|
||||||
/* don't answer wildcard queries with data not from /etc/hosts
|
|
||||||
or DHCP leases */
|
|
||||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||||
return 0;
|
continue;
|
||||||
|
|
||||||
/* If we have negative cache entry, it's OK
|
|
||||||
to return no answer. */
|
|
||||||
ans = 1;
|
|
||||||
|
|
||||||
if (crecp->flags & F_NEG)
|
if (crecp->flags & F_NEG)
|
||||||
{
|
{
|
||||||
log_query(crecp->flags, name, NULL);
|
ans = 1;
|
||||||
auth = 0;
|
if (!dryrun)
|
||||||
if (crecp->flags & F_NXDOMAIN)
|
{
|
||||||
nxdomain = 1;
|
log_query(crecp->flags & ~F_FORWARD, name, &addr);
|
||||||
|
auth = 0;
|
||||||
|
if (crecp->flags & F_NXDOMAIN)
|
||||||
|
nxdomain = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
|
||||||
{
|
{
|
||||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
ans = 1;
|
||||||
auth = 0;
|
if (!dryrun)
|
||||||
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr);
|
{
|
||||||
|
unsigned long ttl;
|
||||||
|
/* Return 0 ttl for DHCP entries, which might change
|
||||||
|
before the lease expires. */
|
||||||
|
if (crecp->flags & (F_IMMORTAL | F_DHCP))
|
||||||
|
ttl = local_ttl;
|
||||||
|
else
|
||||||
|
ttl = crecp->ttd - now;
|
||||||
|
|
||||||
/* copy question as first part of answer (use compression) */
|
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||||
PUTSHORT(nameoffset | 0xc000, ansp);
|
auth = 0;
|
||||||
PUTSHORT(T_A, ansp);
|
|
||||||
PUTSHORT(C_IN, ansp);
|
|
||||||
PUTLONG(ttl, ansp); /* TTL */
|
|
||||||
|
|
||||||
PUTSHORT(INADDRSZ, ansp);
|
ansp = add_text_record(nameoffset, ansp, ttl, 0, T_PTR,
|
||||||
memcpy(ansp, &crecp->addr, INADDRSZ);
|
cache_get_name(crecp));
|
||||||
ansp += INADDRSZ;
|
|
||||||
anscount++;
|
|
||||||
|
|
||||||
if (((unsigned char *)limit - ansp) < 0)
|
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr);
|
||||||
return 0;
|
anscount++;
|
||||||
|
|
||||||
|
/* if last answer exceeded packet size, give up */
|
||||||
|
if (((unsigned char *)limit - ansp) < 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} while ((crecp = cache_find_by_addr(crecp, &addr, now, is_arpa)));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
|
||||||
|
{
|
||||||
|
unsigned short type = T_A;
|
||||||
|
int addrsz = INADDRSZ;
|
||||||
|
|
||||||
|
if (flag == F_IPV6)
|
||||||
|
{
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
if (qtype == T_AAAA || qtype == T_ANY)
|
type = T_AAAA;
|
||||||
{
|
addrsz = IN6ADDRSZ;
|
||||||
/* T_ANY queries for hostnames with underscores are spam
|
#else
|
||||||
from win2k - don't forward them. */
|
break;
|
||||||
if ((options & OPT_FILTER) &&
|
#endif
|
||||||
qtype == T_ANY
|
}
|
||||||
&& (strchr(name, '_') != NULL))
|
|
||||||
ans = 1;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
crecp = NULL;
|
|
||||||
while ((crecp = cache_find_by_name(crecp, name, now, F_IPV6)))
|
|
||||||
{
|
|
||||||
unsigned long ttl;
|
|
||||||
if (crecp->flags & (F_IMMORTAL | F_DHCP))
|
|
||||||
ttl = local_ttl;
|
|
||||||
else
|
|
||||||
ttl = crecp->ttd - now;
|
|
||||||
|
|
||||||
|
if (qtype != type && qtype != T_ANY)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
crecp = NULL;
|
||||||
|
while ((crecp = cache_find_by_name(crecp, name, now, flag)))
|
||||||
|
{
|
||||||
/* don't answer wildcard queries with data not from /etc/hosts
|
/* don't answer wildcard queries with data not from /etc/hosts
|
||||||
or DHCP leases */
|
or DHCP leases */
|
||||||
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
if (qtype == T_ANY && !(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||||
return 0;
|
continue;
|
||||||
|
|
||||||
/* If we have negative cache entry, it's OK
|
|
||||||
to return no answer. */
|
|
||||||
ans = 1;
|
|
||||||
|
|
||||||
if (crecp->flags & F_NEG)
|
if (crecp->flags & F_NEG)
|
||||||
{
|
{
|
||||||
log_query(crecp->flags, name, NULL);
|
ans = 1;
|
||||||
auth = 0;
|
if (!dryrun)
|
||||||
if (crecp->flags & F_NXDOMAIN)
|
{
|
||||||
nxdomain = 1;
|
log_query(crecp->flags, name, NULL);
|
||||||
|
auth = 0;
|
||||||
|
if (crecp->flags & F_NXDOMAIN)
|
||||||
|
nxdomain = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else if ((crecp->flags & (F_HOSTS | F_DHCP)) || !sec_reqd)
|
||||||
{
|
{
|
||||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
ans = 1;
|
||||||
auth = 0;
|
if (!dryrun)
|
||||||
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr);
|
{
|
||||||
|
unsigned long ttl;
|
||||||
|
|
||||||
/* copy question as first part of answer (use compression) */
|
if (crecp->flags & (F_IMMORTAL | F_DHCP))
|
||||||
PUTSHORT(nameoffset | 0xc000, ansp);
|
ttl = local_ttl;
|
||||||
PUTSHORT(T_AAAA, ansp);
|
else
|
||||||
PUTSHORT(C_IN, ansp);
|
ttl = crecp->ttd - now;
|
||||||
PUTLONG(ttl, ansp); /* TTL */
|
|
||||||
|
|
||||||
PUTSHORT(IN6ADDRSZ, ansp);
|
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||||
memcpy(ansp, &crecp->addr, IN6ADDRSZ);
|
auth = 0;
|
||||||
ansp += IN6ADDRSZ;
|
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr);
|
||||||
anscount++;
|
|
||||||
|
|
||||||
if (((unsigned char *)limit - ansp) < 0)
|
/* copy question as first part of answer (use compression) */
|
||||||
return 0;
|
PUTSHORT(nameoffset | 0xc000, ansp);
|
||||||
|
PUTSHORT(type, ansp);
|
||||||
|
PUTSHORT(C_IN, ansp);
|
||||||
|
PUTLONG(ttl, ansp); /* TTL */
|
||||||
|
|
||||||
|
PUTSHORT(addrsz, ansp);
|
||||||
|
memcpy(ansp, &crecp->addr, addrsz);
|
||||||
|
ansp += addrsz;
|
||||||
|
anscount++;
|
||||||
|
|
||||||
|
if (((unsigned char *)limit - ansp) < 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (qtype == T_MX || qtype == T_ANY)
|
if (qtype == T_MX || qtype == T_ANY)
|
||||||
{
|
|
||||||
struct mx_record *mx;
|
|
||||||
for (mx = mxnames; mx; mx = mx->next)
|
|
||||||
if (hostname_isequal(name, mx->mxname))
|
|
||||||
break;
|
|
||||||
if (mx)
|
|
||||||
{
|
{
|
||||||
ansp = add_text_record(nameoffset, ansp, local_ttl, 1, T_MX,
|
struct mx_record *mx;
|
||||||
mx->mxtarget ? mx->mxtarget : mxtarget);
|
for (mx = mxnames; mx; mx = mx->next)
|
||||||
anscount++;
|
if (hostname_isequal(name, mx->mxname))
|
||||||
ans = 1;
|
break;
|
||||||
|
if (mx)
|
||||||
|
{
|
||||||
|
ans = 1;
|
||||||
|
if (!dryrun)
|
||||||
|
{
|
||||||
|
ansp = add_text_record(nameoffset, ansp, local_ttl, 1, T_MX,
|
||||||
|
mx->mxtarget ? mx->mxtarget : mxtarget);
|
||||||
|
anscount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ((options & (OPT_SELFMX | OPT_LOCALMX)) &&
|
||||||
|
cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
|
||||||
|
{
|
||||||
|
ans = 1;
|
||||||
|
if (!dryrun)
|
||||||
|
{
|
||||||
|
ansp = add_text_record(nameoffset, ansp, local_ttl, 1, T_MX,
|
||||||
|
(options & OPT_SELFMX) ? name : mxtarget);
|
||||||
|
anscount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if ((options & (OPT_SELFMX | OPT_LOCALMX)) &&
|
|
||||||
cache_find_by_name(NULL, name, now, F_HOSTS | F_DHCP))
|
if (qtype == T_MAILB)
|
||||||
{
|
ans = 1, nxdomain = 1;
|
||||||
ansp = add_text_record(nameoffset, ansp, local_ttl, 1, T_MX,
|
|
||||||
(options & OPT_SELFMX) ? name : mxtarget);
|
|
||||||
anscount++;
|
|
||||||
ans = 1;
|
|
||||||
}
|
|
||||||
if (((unsigned char *)limit - ansp) < 0)
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (qtype == T_MAILB)
|
|
||||||
ans = 1, nxdomain = 1;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ans)
|
if (!ans || ((unsigned char *)limit - ansp) < 0)
|
||||||
return 0; /* failed to answer a question */
|
return 0; /* failed to answer a question */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dryrun)
|
||||||
|
{
|
||||||
|
dryrun = 0;
|
||||||
|
goto rerun;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* done all questions, set up header and return length of result */
|
/* done all questions, set up header and return length of result */
|
||||||
|
|||||||
@@ -105,9 +105,7 @@ int dhcp_reply(struct dhcp_context *context,
|
|||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
unsigned short fuzz = 0;
|
unsigned short fuzz = 0;
|
||||||
|
|
||||||
if (mess->op != BOOTREQUEST ||
|
if (mess->op != BOOTREQUEST || mess->cookie != htonl(DHCP_COOKIE))
|
||||||
mess->hlen != ETHER_ADDR_LEN ||
|
|
||||||
mess->cookie != htonl(DHCP_COOKIE))
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Token ring is supported when we have packet sockets
|
/* Token ring is supported when we have packet sockets
|
||||||
@@ -117,12 +115,17 @@ int dhcp_reply(struct dhcp_context *context,
|
|||||||
|
|
||||||
#ifdef HAVE_BPF
|
#ifdef HAVE_BPF
|
||||||
if (mess->htype != ARPHRD_ETHER)
|
if (mess->htype != ARPHRD_ETHER)
|
||||||
return 0;
|
|
||||||
#else
|
#else
|
||||||
if (mess->htype != ARPHRD_ETHER &&
|
if (mess->htype != ARPHRD_ETHER && mess->htype != ARPHRD_IEEE802)
|
||||||
mess->htype != ARPHRD_IEEE802)
|
|
||||||
return 0;
|
|
||||||
#endif
|
#endif
|
||||||
|
{
|
||||||
|
syslog(LOG_WARNING, "DHCP request for unsupported hardware type (%d) recieved on %s",
|
||||||
|
mess->htype, iface_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mess->hlen != ETHER_ADDR_LEN)
|
||||||
|
return 0;
|
||||||
|
|
||||||
mess->op = BOOTREPLY;
|
mess->op = BOOTREPLY;
|
||||||
|
|
||||||
@@ -317,6 +320,9 @@ int dhcp_reply(struct dhcp_context *context,
|
|||||||
syslog(LOG_WARNING, "disabling DHCP static address %s", inet_ntoa(config->addr));
|
syslog(LOG_WARNING, "disabling DHCP static address %s", inet_ntoa(config->addr));
|
||||||
config->flags &= ~CONFIG_ADDR ;
|
config->flags &= ~CONFIG_ADDR ;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
/* make sure this host gets a different address next time. */
|
||||||
|
context->addr_epoch++;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -335,18 +341,16 @@ int dhcp_reply(struct dhcp_context *context,
|
|||||||
case DHCPDISCOVER:
|
case DHCPDISCOVER:
|
||||||
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
|
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
|
||||||
addr = option_addr(opt);
|
addr = option_addr(opt);
|
||||||
|
|
||||||
if (have_config(config, CONFIG_DISABLE))
|
if (have_config(config, CONFIG_DISABLE))
|
||||||
message = "ignored";
|
message = "ignored";
|
||||||
else if (have_config(config, CONFIG_ADDR) && !lease_find_by_addr(config->addr))
|
else if (have_config(config, CONFIG_ADDR) && !lease_find_by_addr(config->addr))
|
||||||
mess->yiaddr = config->addr;
|
mess->yiaddr = config->addr;
|
||||||
else if (lease && is_same_net(lease->addr, context->start, context->netmask))
|
else if (lease && address_available(context, lease->addr))
|
||||||
mess->yiaddr = lease->addr;
|
mess->yiaddr = lease->addr;
|
||||||
else if (opt && address_available(context, addr))
|
else if (opt && address_available(context, addr) && !lease_find_by_addr(addr))
|
||||||
mess->yiaddr = addr;
|
mess->yiaddr = addr;
|
||||||
else if (!address_allocate(context, dhcp_configs, &mess->yiaddr, mess->chaddr))
|
else if (!address_allocate(context, dhcp_configs, &mess->yiaddr, mess->chaddr))
|
||||||
message = "no address available";
|
message = "no address available";
|
||||||
|
|
||||||
log_packet("DISCOVER", opt ? &addr : NULL, mess->chaddr, iface_name, message);
|
log_packet("DISCOVER", opt ? &addr : NULL, mess->chaddr, iface_name, message);
|
||||||
|
|
||||||
if (message)
|
if (message)
|
||||||
@@ -394,11 +398,9 @@ int dhcp_reply(struct dhcp_context *context,
|
|||||||
lease = NULL;
|
lease = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* accept addresses in the dynamic range or ones allocated statically to
|
|
||||||
particular hosts or an address which the host already has. */
|
|
||||||
if (!lease)
|
if (!lease)
|
||||||
{
|
{
|
||||||
if (!address_available(context, mess->yiaddr) &&
|
if ((!address_available(context, mess->yiaddr) || lease_find_by_addr(mess->yiaddr)) &&
|
||||||
(!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
|
(!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
|
||||||
message = "address unavailable";
|
message = "address unavailable";
|
||||||
else if (!(lease = lease_allocate(clid, clid_len, mess->yiaddr)))
|
else if (!(lease = lease_allocate(clid, clid_len, mess->yiaddr)))
|
||||||
@@ -426,6 +428,19 @@ int dhcp_reply(struct dhcp_context *context,
|
|||||||
if (!message && !is_same_net(mess->yiaddr, context->start, context->netmask))
|
if (!message && !is_same_net(mess->yiaddr, context->start, context->netmask))
|
||||||
message = "wrong network";
|
message = "wrong network";
|
||||||
|
|
||||||
|
/* Check for renewal of a lease which is now outside the allowed range. */
|
||||||
|
if (!message && !address_available(context, mess->yiaddr) &&
|
||||||
|
(!have_config(config, CONFIG_ADDR) || config->addr.s_addr != mess->yiaddr.s_addr))
|
||||||
|
message = "address no longer available";
|
||||||
|
|
||||||
|
/* Check if a new static address has been configured. Be very sure that
|
||||||
|
when the client does DISCOVER, it will get the static address, otherwise
|
||||||
|
an endless protocol loop will ensue. */
|
||||||
|
if (!message && have_config(config, CONFIG_ADDR) &&
|
||||||
|
!have_config(config, CONFIG_DISABLE) &&
|
||||||
|
!lease_find_by_addr(config->addr))
|
||||||
|
message = "static lease available";
|
||||||
|
|
||||||
log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
|
log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
|
||||||
|
|
||||||
if (message)
|
if (message)
|
||||||
|
|||||||
Reference in New Issue
Block a user