mirror of
http://thekelleys.org.uk/git/dnsmasq.git
synced 2026-11-06 15:51:41 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26128d2747 | ||
|
|
fd9fa4811d | ||
|
|
36717eeefc |
No files matched your search
@@ -1190,3 +1190,107 @@ version 2.14
|
|||||||
|
|
||||||
Added "keep-in-foreground" option. Thanks to Sean
|
Added "keep-in-foreground" option. Thanks to Sean
|
||||||
MacLennan for the patch.
|
MacLennan for the patch.
|
||||||
|
|
||||||
|
version 2.15
|
||||||
|
Fixed NXDOMAIN/NODATA confusion for locally known
|
||||||
|
names. We now return a NODATA reponse for names which are
|
||||||
|
locally known. Now a query for (eg AAAA or MX) for a name
|
||||||
|
with an IPv4 address in /etc/hosts which fails upstream
|
||||||
|
will generate a NODATA response. Note that the query
|
||||||
|
is still tried upstream, but a NXDOMAIN reply gets
|
||||||
|
converted to NODATA. Thanks to Eric de Thouars, Eric
|
||||||
|
Spakman and Mike Mestnik for bug reports/testing.
|
||||||
|
|
||||||
|
Allow multiple dhcp-ranges within the same network. The
|
||||||
|
original intention was that there would be a dhcp-range
|
||||||
|
option for each network served, but there's no real reason
|
||||||
|
not to allow discontinuous ranges within a network so this
|
||||||
|
release adds support for that.
|
||||||
|
|
||||||
|
Check for dhcp-ranges which are inconsistent with their
|
||||||
|
netmask, and generate errors or warnings.
|
||||||
|
|
||||||
|
Improve error messages when there are problems with
|
||||||
|
configuration.
|
||||||
|
|
||||||
|
version 2.16
|
||||||
|
Fixed typo in OpenBSD-only code which stopped compilation
|
||||||
|
under that OS. Chris Weinhaupl gets credit for reporting
|
||||||
|
this.
|
||||||
|
|
||||||
|
Added dhcp-authoritative option which restores non-RFC
|
||||||
|
compliant but desirable behaviour of pre-2.14 versions and
|
||||||
|
avoids long timeouts while DHCP clients try to renew leases
|
||||||
|
which are unknown to dnsmasq. Thanks to John Mastwijk for
|
||||||
|
help with this.
|
||||||
|
|
||||||
|
Added support to the DHCP option code to allow RFC-3397
|
||||||
|
domain search DHCP option (119) to be sent.
|
||||||
|
|
||||||
|
Set NONBLOCK on all listening sockets to workaround non-POSIX
|
||||||
|
compliance in Linux 2.4 and 2.6. This fixes rare hangs which
|
||||||
|
occured when corrupted packets were received. Thanks to
|
||||||
|
Joris van Rantwijk for chasing that down.
|
||||||
|
|
||||||
|
Updated config.h for NetBSD. Thanks to Martin Lambers.
|
||||||
|
|
||||||
|
Do a better job of distinguishing between retransmissions
|
||||||
|
and new queries when forwarding. This fixes a bug
|
||||||
|
triggered by the polipo web cache which sends A and AAAA
|
||||||
|
queries both with the same transaction-ID. Thanks to
|
||||||
|
Joachim Berdal Haga and Juliusz Chroboczek for help with this.
|
||||||
|
|
||||||
|
Rewrote cache code to store CNAMES, rather then chasing
|
||||||
|
them before storage. This eliminates bad situations when
|
||||||
|
clients get inconsistent views depending on if data comes
|
||||||
|
from the cache.
|
||||||
|
|
||||||
|
Allow for more than one --addn-hosts flag.
|
||||||
|
|
||||||
|
Clarify logged message when a DHCP lease clashes with an
|
||||||
|
/etc/hosts entry. Thanks to Mat Swift for the suggestion.
|
||||||
|
|
||||||
|
Added dynamic-dnsmasq from Peter Willis to the contrib
|
||||||
|
section.
|
||||||
|
|
||||||
|
version 2.17
|
||||||
|
Correctly deduce the size of numeric dhcp-options, rather
|
||||||
|
than making wild guesses. Also cope with negative values.
|
||||||
|
|
||||||
|
Fixed use of C library reserved symbol "index" which broke
|
||||||
|
under certain combinations of library and compiler.
|
||||||
|
|
||||||
|
Make bind-interfaces work for IPv6 interfaces too.
|
||||||
|
|
||||||
|
Warn if an interface is given for listening which doesn't
|
||||||
|
currently exist when not in bind-interfaces mode. (This is
|
||||||
|
already a fatal error when bind-interfaces is set.)
|
||||||
|
|
||||||
|
Allow the --interface and --except-interface options to
|
||||||
|
take a comma-seperated list of interfaces.
|
||||||
|
|
||||||
|
Tweak --dhcp-userclass matching code to work with the
|
||||||
|
ISC dhclient which violates RFC3004 unless its
|
||||||
|
configuration is very warped. Thanks to Cedric Duval for
|
||||||
|
the bug report.
|
||||||
|
|
||||||
|
Allow more than one network-id tag in a dhcp-option. All
|
||||||
|
the tags must match to enable the option.
|
||||||
|
|
||||||
|
Added dhcp-ignore option to disable classes of hosts based
|
||||||
|
on network-id tags. Also allow BOOTP options to be
|
||||||
|
controlled by network tags.
|
||||||
|
|
||||||
|
Fill in sname, file and siaddr fields in replies to
|
||||||
|
DHCPINFORM messages.
|
||||||
|
|
||||||
|
Don't send NAK replies to DHCPREQUEST packets for disabled
|
||||||
|
clients. Credit to Cedric Duval for spotting this.
|
||||||
|
|
||||||
|
Fix rare crash associated with long DNS names and CNAME
|
||||||
|
records. Thanks to Holger_Hoffstatte and especially Steve
|
||||||
|
Grecni for help chasing that one down.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -284,6 +284,22 @@ A: Yes, new releases of dnsmasq are always announced through
|
|||||||
freshmeat.net, and they allow you to subcribe to email alerts when
|
freshmeat.net, and they allow you to subcribe to email alerts when
|
||||||
new versions of particular projects are released.
|
new versions of particular projects are released.
|
||||||
|
|
||||||
|
Q: What does the dhcp-authoritative option do?
|
||||||
|
|
||||||
|
A: See http://www.isc.org/index.pl?/sw/dhcp/authoritative.php - that's
|
||||||
|
for the ISC daemon, but the same applies to dnsmasq.
|
||||||
|
|
||||||
|
Q: Why does my Gentoo box pause for a minute before getting a new
|
||||||
|
lease?
|
||||||
|
|
||||||
|
A: Because when a Gentoo box shuts down, it releases its lease with
|
||||||
|
the server but remembers it on the client; this seems to be a
|
||||||
|
Gentoo-specific patch to dhcpcd. On restart it tries to renew
|
||||||
|
a lease which is long gone, as far as dnsmasq is concerned, and
|
||||||
|
dnsmasq ignores it until is times out and restarts the process.
|
||||||
|
To fix this, set the dhcp-authoritative flag in dnsmasq.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Executable
+249
@@ -0,0 +1,249 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
# dynamic-dnsmasq.pl - update dnsmasq's internal dns entries dynamically
|
||||||
|
# Copyright (C) 2004 Peter Willis
|
||||||
|
#
|
||||||
|
# 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
|
||||||
|
#
|
||||||
|
# the purpose of this script is to be able to update dnsmasq's dns
|
||||||
|
# records from a remote dynamic dns client.
|
||||||
|
#
|
||||||
|
# basic use of this script:
|
||||||
|
# dynamic-dnsmasq.pl add testaccount 1234 testaccount.mydomain.com
|
||||||
|
# dynamic-dnsmasq.pl listen &
|
||||||
|
#
|
||||||
|
# this script tries to emulate DynDNS.org's dynamic dns service, so
|
||||||
|
# technically you should be able to use any DynDNS.org client to
|
||||||
|
# update the records here. tested and confirmed to work with ddnsu
|
||||||
|
# 1.3.1. just point the client's host to the IP of this machine,
|
||||||
|
# port 9020, and include the hostname, user and pass, and it should
|
||||||
|
# work.
|
||||||
|
#
|
||||||
|
# make sure "addn-hosts=/etc/dyndns-hosts" is in your /etc/dnsmasq.conf
|
||||||
|
# file and "nopoll" is commented out.
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use IO::Socket;
|
||||||
|
use MIME::Base64;
|
||||||
|
use DB_File;
|
||||||
|
use Fcntl;
|
||||||
|
|
||||||
|
my $accountdb = "accounts.db";
|
||||||
|
my $recordfile = "/etc/dyndns-hosts";
|
||||||
|
my $dnsmasqpidfile = "/var/run/dnsmasq.pid"; # if this doesn't exist, will look for process in /proc
|
||||||
|
my $listenaddress = "0.0.0.0";
|
||||||
|
my $listenport = 9020;
|
||||||
|
|
||||||
|
# no editing past this point should be necessary
|
||||||
|
|
||||||
|
if ( @ARGV < 1 ) {
|
||||||
|
die "Usage: $0 ADD|DEL|LISTUSERS|WRITEHOSTSFILE|LISTEN\n";
|
||||||
|
} elsif ( lc $ARGV[0] eq "add" ) {
|
||||||
|
die "Usage: $0 ADD USER PASS HOSTNAME\n" unless @ARGV == 4;
|
||||||
|
add_acct($ARGV[1], $ARGV[2], $ARGV[3]);
|
||||||
|
} elsif ( lc $ARGV[0] eq "del" ) {
|
||||||
|
die "Usage: $0 DEL USER\n" unless @ARGV == 2;
|
||||||
|
print "Are you sure you want to delete user \"$ARGV[1]\"? [N/y] ";
|
||||||
|
my $resp = <STDIN>;
|
||||||
|
chomp $resp;
|
||||||
|
if ( lc substr($resp,0,1) eq "y" ) {
|
||||||
|
del_acct($ARGV[1]);
|
||||||
|
}
|
||||||
|
} elsif ( lc $ARGV[0] eq "listusers" or lc $ARGV[0] eq "writehostsfile" ) {
|
||||||
|
my $X = tie my %h, "DB_File", $accountdb, O_RDWR|O_CREAT, 0600, $DB_HASH;
|
||||||
|
my $fh;
|
||||||
|
if ( lc $ARGV[0] eq "writehostsfile" ) {
|
||||||
|
open($fh, ">$recordfile") || die "Couldn't open recordfile \"$recordfile\": $!\n";
|
||||||
|
flock($fh, 2);
|
||||||
|
seek($fh, 0, 0);
|
||||||
|
truncate($fh, 0);
|
||||||
|
}
|
||||||
|
while ( my ($key, $val) = each %h ) {
|
||||||
|
my ($pass, $domain, $ip) = split("\t",$val);
|
||||||
|
if ( lc $ARGV[0] eq "listusers" ) {
|
||||||
|
print "user $key, hostname $domain, ip $ip\n";
|
||||||
|
} else {
|
||||||
|
if ( defined $ip ) {
|
||||||
|
print $fh "$ip\t$domain\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ( lc $ARGV[0] eq "writehostsfile" ) {
|
||||||
|
flock($fh, 8);
|
||||||
|
close($fh);
|
||||||
|
dnsmasq_rescan_configs();
|
||||||
|
}
|
||||||
|
undef $X;
|
||||||
|
untie %h;
|
||||||
|
} elsif ( lc $ARGV[0] eq "listen" ) {
|
||||||
|
listen_for_updates();
|
||||||
|
}
|
||||||
|
|
||||||
|
sub listen_for_updates {
|
||||||
|
my $sock = IO::Socket::INET->new(Listen => 5,
|
||||||
|
LocalAddr => $listenaddress, LocalPort => $listenport,
|
||||||
|
Proto => 'tcp', ReuseAddr => 1,
|
||||||
|
MultiHomed => 1) || die "Could not open listening socket: $!\n";
|
||||||
|
$SIG{'CHLD'} = 'IGNORE';
|
||||||
|
while ( my $client = $sock->accept() ) {
|
||||||
|
my $p = fork();
|
||||||
|
if ( $p != 0 ) {
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
$SIG{'CHLD'} = 'DEFAULT';
|
||||||
|
my @headers;
|
||||||
|
my %cgi;
|
||||||
|
while ( <$client> ) {
|
||||||
|
s/(\r|\n)//g;
|
||||||
|
last if $_ eq "";
|
||||||
|
push @headers, $_;
|
||||||
|
}
|
||||||
|
foreach my $header (@headers) {
|
||||||
|
if ( $header =~ /^GET \/nic\/update\?([^\s].+) HTTP\/1\.[01]$/ ) {
|
||||||
|
foreach my $element (split('&', $1)) {
|
||||||
|
$cgi{(split '=', $element)[0]} = (split '=', $element)[1];
|
||||||
|
}
|
||||||
|
} elsif ( $header =~ /^Authorization: basic (.+)$/ ) {
|
||||||
|
unless ( defined $cgi{'hostname'} ) {
|
||||||
|
print_http_response($client, undef, "badsys");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
if ( !exists $cgi{'myip'} ) {
|
||||||
|
$cgi{'myip'} = $client->peerhost();
|
||||||
|
}
|
||||||
|
my ($user,$pass) = split ":", MIME::Base64::decode($1);
|
||||||
|
if ( authorize($user, $pass, $cgi{'hostname'}, $cgi{'myip'}) == 0 ) {
|
||||||
|
print_http_response($client, $cgi{'myip'}, "good");
|
||||||
|
update_dns(\%cgi);
|
||||||
|
} else {
|
||||||
|
print_http_response($client, undef, "badauth");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub add_acct {
|
||||||
|
my ($user, $pass, $hostname) = @_;
|
||||||
|
my $X = tie my %h, "DB_File", $accountdb, O_RDWR|O_CREAT, 0600, $DB_HASH;
|
||||||
|
$X->put($user, join("\t", ($pass, $hostname)));
|
||||||
|
undef $X;
|
||||||
|
untie %h;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub del_acct {
|
||||||
|
my ($user, $pass, $hostname) = @_;
|
||||||
|
my $X = tie my %h, "DB_File", $accountdb, O_RDWR|O_CREAT, 0600, $DB_HASH;
|
||||||
|
$X->del($user);
|
||||||
|
undef $X;
|
||||||
|
untie %h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub authorize {
|
||||||
|
my $user = shift;
|
||||||
|
my $pass = shift;
|
||||||
|
my $hostname = shift;
|
||||||
|
my $ip = shift;;
|
||||||
|
my $X = tie my %h, "DB_File", $accountdb, O_RDWR|O_CREAT, 0600, $DB_HASH;
|
||||||
|
my ($spass, $shost) = split("\t", $h{$user});
|
||||||
|
if ( defined $h{$user} and ($spass eq $pass) and ($shost eq $hostname) ) {
|
||||||
|
$X->put($user, join("\t", $spass, $shost, $ip));
|
||||||
|
undef $X;
|
||||||
|
untie %h;
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
undef $X;
|
||||||
|
untie %h;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub print_http_response {
|
||||||
|
my $sock = shift;
|
||||||
|
my $ip = shift;
|
||||||
|
my $response = shift;
|
||||||
|
print $sock "HTTP/1.0 200 OK\n";
|
||||||
|
my @tmp = split /\s+/, scalar gmtime();
|
||||||
|
print $sock "Date: $tmp[0], $tmp[2] $tmp[1] $tmp[4] $tmp[3] GMT\n";
|
||||||
|
print $sock "Server: Peter's Fake DynDNS.org Server/1.0\n";
|
||||||
|
print $sock "Content-Type: text/plain; charset=ISO-8859-1\n";
|
||||||
|
print $sock "Connection: close\n";
|
||||||
|
print $sock "Transfer-Encoding: chunked\n";
|
||||||
|
print $sock "\n";
|
||||||
|
#print $sock "12\n"; # this was part of the dyndns response but i'm not sure what it is
|
||||||
|
print $sock "$response", defined($ip)? " $ip" : "" . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
sub update_dns {
|
||||||
|
my $hashref = shift;
|
||||||
|
my @records;
|
||||||
|
my $found = 0;
|
||||||
|
# update the addn-hosts file
|
||||||
|
open(FILE, "+<$recordfile") || die "Couldn't open recordfile \"$recordfile\": $!\n";
|
||||||
|
flock(FILE, 2);
|
||||||
|
while ( <FILE> ) {
|
||||||
|
if ( /^(\d+\.\d+\.\d+\.\d+)\s+$$hashref{'hostname'}\n$/si ) {
|
||||||
|
if ( $1 ne $$hashref{'myip'} ) {
|
||||||
|
push @records, "$$hashref{'myip'}\t$$hashref{'hostname'}\n";
|
||||||
|
$found = 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
push @records, $_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unless ( $found ) {
|
||||||
|
push @records, "$$hashref{'myip'}\t$$hashref{'hostname'}\n";
|
||||||
|
}
|
||||||
|
sysseek(FILE, 0, 0);
|
||||||
|
truncate(FILE, 0);
|
||||||
|
syswrite(FILE, join("", @records));
|
||||||
|
flock(FILE, 8);
|
||||||
|
close(FILE);
|
||||||
|
dnsmasq_rescan_configs();
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub dnsmasq_rescan_configs {
|
||||||
|
# send the HUP signal to dnsmasq
|
||||||
|
if ( -r $dnsmasqpidfile ) {
|
||||||
|
open(PID,"<$dnsmasqpidfile") || die "Could not open PID file \"$dnsmasqpidfile\": $!\n";
|
||||||
|
my $pid = <PID>;
|
||||||
|
close(PID);
|
||||||
|
chomp $pid;
|
||||||
|
if ( kill(0, $pid) ) {
|
||||||
|
kill(1, $pid);
|
||||||
|
} else {
|
||||||
|
goto LOOKFORDNSMASQ;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOOKFORDNSMASQ:
|
||||||
|
opendir(DIR,"/proc") || die "Couldn't opendir /proc: $!\n";
|
||||||
|
my @dirs = grep(/^\d+$/, readdir(DIR));
|
||||||
|
closedir(DIR);
|
||||||
|
foreach my $process (@dirs) {
|
||||||
|
if ( open(FILE,"</proc/$process/cmdline") ) {
|
||||||
|
my $cmdline = <FILE>;
|
||||||
|
close(FILE);
|
||||||
|
if ( (split(/\0/,$cmdline))[0] =~ /dnsmasq/ ) {
|
||||||
|
kill(1, $process);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
Name: dnsmasq
|
Name: dnsmasq
|
||||||
Version: 2.14
|
Version: 2.17
|
||||||
Release: 1
|
Release: 1
|
||||||
Copyright: GPL
|
Copyright: GPL
|
||||||
Group: System Environment/Daemons
|
Group: System Environment/Daemons
|
||||||
|
|||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
###############################################################################
|
###############################################################################
|
||||||
|
|
||||||
Name: dnsmasq
|
Name: dnsmasq
|
||||||
Version: 2.14
|
Version: 2.17
|
||||||
Release: 1
|
Release: 1
|
||||||
Copyright: GPL
|
Copyright: GPL
|
||||||
Group: Productivity/Networking/DNS/Servers
|
Group: Productivity/Networking/DNS/Servers
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ Don't read the hostnames in /etc/hosts.
|
|||||||
.TP
|
.TP
|
||||||
.B \-H, --addn-hosts=<file>
|
.B \-H, --addn-hosts=<file>
|
||||||
Additional hosts file. Read the specified file as well as /etc/hosts. If -h is given, read
|
Additional hosts file. Read the specified file as well as /etc/hosts. If -h is given, read
|
||||||
only the specified file. At most one additional hosts file may be
|
only the specified file. This option may be repeated for more than one
|
||||||
given.
|
additional hosts file.
|
||||||
.TP
|
.TP
|
||||||
.B \-T, --local-ttl=<time>
|
.B \-T, --local-ttl=<time>
|
||||||
When replying with information from /etc/hosts or the DHCP leases
|
When replying with information from /etc/hosts or the DHCP leases
|
||||||
@@ -366,7 +366,7 @@ have exactly the same effect as
|
|||||||
.B --dhcp-host
|
.B --dhcp-host
|
||||||
options containing the same information.
|
options containing the same information.
|
||||||
.TP
|
.TP
|
||||||
.B \-O, --dhcp-option=[network-id,]<opt>,[<value>[,<value>]]
|
.B \-O, --dhcp-option=[<network-id>,[<network-id>,]]<opt>,[<value>[,<value>]]
|
||||||
Specfify different or extra options to DHCP clients. By default,
|
Specfify different or extra options to DHCP clients. By default,
|
||||||
dnsmasq sends some standard options to DHCP clients, the netmask and
|
dnsmasq sends some standard options to DHCP clients, the netmask and
|
||||||
broadcast address are set to the same as the host running dnsmasq, and
|
broadcast address are set to the same as the host running dnsmasq, and
|
||||||
@@ -382,12 +382,10 @@ and to set the time-server address to 192.168.0.4, do
|
|||||||
The special address 0.0.0.0 is taken to mean "the address of the
|
The special address 0.0.0.0 is taken to mean "the address of the
|
||||||
machine running dnsmasq". Data types allowed are comma seperated
|
machine running dnsmasq". Data types allowed are comma seperated
|
||||||
dotted-quad IP addresses, a decimal number, colon-seperated hex digits
|
dotted-quad IP addresses, a decimal number, colon-seperated hex digits
|
||||||
and a text string. If the optional network-id is given then
|
and a text string. If the optional network-ids are given then
|
||||||
this option is only sent to machines on the network whose dhcp-range
|
this option is only sent when all the network-ids are matched.
|
||||||
contains a matching network-id.
|
|
||||||
Be careful: no checking is done that the correct type of data for the
|
Be careful: no checking is done that the correct type of data for the
|
||||||
option number is sent, and there are option numbers for which it is not
|
option number is sent, it is quite possible to
|
||||||
possible to generate the correct data type; it is quite possible to
|
|
||||||
persuade dnsmasq to generate illegal DHCP packets with injudicious use
|
persuade dnsmasq to generate illegal DHCP packets with injudicious use
|
||||||
of this flag.
|
of this flag.
|
||||||
.TP
|
.TP
|
||||||
@@ -412,10 +410,17 @@ to different classes of hosts. It is possible, for instance to use
|
|||||||
this to set a different printer server for hosts in the class
|
this to set a different printer server for hosts in the class
|
||||||
"accounts" than for hosts in the class "engineering".
|
"accounts" than for hosts in the class "engineering".
|
||||||
.TP
|
.TP
|
||||||
.B \-M, --dhcp-boot=<filename>,[<servername>[,<server address>]]
|
.B \ -J, --dhcp-ignore=<network-id>[,<network-id>]
|
||||||
|
When all the given network-ids match the set of network-ids derived
|
||||||
|
from the net, host, vendor and user classes, ignore the host and do
|
||||||
|
not allocate it a DHCP lease.
|
||||||
|
.TP
|
||||||
|
.B \-M, --dhcp-boot=[net:<network-id>,]<filename>,[<servername>[,<server address>]]
|
||||||
Set BOOTP options to be returned by the DHCP server. These are needed
|
Set BOOTP options to be returned by the DHCP server. These are needed
|
||||||
for machines which network boot, and tell the machine where to collect
|
for machines which network boot, and tell the machine where to collect
|
||||||
its initial configuration.
|
its initial configuration. If the optional network-id(s) are given,
|
||||||
|
they must match for this configuration to be sent. Note that
|
||||||
|
network-ids are prefixed by "net:" to distinguish them.
|
||||||
.TP
|
.TP
|
||||||
.B \-X, --dhcp-lease-max=<number>
|
.B \-X, --dhcp-lease-max=<number>
|
||||||
Limits dnsmasq to the specified maximum number of DHCP leases. The
|
Limits dnsmasq to the specified maximum number of DHCP leases. The
|
||||||
@@ -423,6 +428,12 @@ default is 150. This limit is to prevent DoS attacks from hosts which
|
|||||||
create thousands of leases and use lots of memory in the dnsmasq
|
create thousands of leases and use lots of memory in the dnsmasq
|
||||||
process.
|
process.
|
||||||
.TP
|
.TP
|
||||||
|
.B \-K, --dhcp-authoritative
|
||||||
|
Should be set when dnsmasq is definatively the only DHCP server on a network.
|
||||||
|
It changes the behaviour from strict RFC compliance so that DHCP requests on
|
||||||
|
unknown leases from unknown hosts are not ignored. This allows new hosts
|
||||||
|
to get a lease without a tedious timeout under all circumstances.
|
||||||
|
.TP
|
||||||
.B \-l, --dhcp-leasefile=<path>
|
.B \-l, --dhcp-leasefile=<path>
|
||||||
Use the specified file to store DHCP lease information. If this option
|
Use the specified file to store DHCP lease information. If this option
|
||||||
is given but no dhcp-range option is given then dnsmasq version 1
|
is given but no dhcp-range option is given then dnsmasq version 1
|
||||||
@@ -534,6 +545,21 @@ and run dnsmasq with the
|
|||||||
option. This second technique allows for dynamic update of the server
|
option. This second technique allows for dynamic update of the server
|
||||||
addresses by PPP or DHCP.
|
addresses by PPP or DHCP.
|
||||||
.PP
|
.PP
|
||||||
|
The network-id system works as follows: For each DHCP request, dnsmasq
|
||||||
|
collects a set of valid network-id tags, one from the
|
||||||
|
.B dhcp-range
|
||||||
|
used to allocate the address, one from any matching
|
||||||
|
.B dhcp-host
|
||||||
|
and possibly many from matching vendor classes and user
|
||||||
|
classes sent by the DHCP client. Any
|
||||||
|
.B dhcp-option
|
||||||
|
which has network-id tags will be used in preference to an untagged
|
||||||
|
.B dhcp-option,
|
||||||
|
provided that _all_ the tags match somewhere in the
|
||||||
|
set collected as described above. The prefix '#' on a tag means 'not'
|
||||||
|
so --dhcp=option=#purple,3,1.2.3.4 sends the option when the
|
||||||
|
network-id tag purple is not in the set of valid tags.
|
||||||
|
.PP
|
||||||
The DHCP server in dnsmasq will function as a BOOTP server also,
|
The DHCP server in dnsmasq will function as a BOOTP server also,
|
||||||
provided that the MAC address and IP address for clients are given,
|
provided that the MAC address and IP address for clients are given,
|
||||||
either using
|
either using
|
||||||
|
|||||||
+14
-1
@@ -237,7 +237,10 @@ bogus-priv
|
|||||||
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server
|
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server
|
||||||
#dhcp-option=46,8 # netbios node type
|
#dhcp-option=46,8 # netbios node type
|
||||||
#dhcp-option=47 # empty netbios scope.
|
#dhcp-option=47 # empty netbios scope.
|
||||||
|
|
||||||
|
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client
|
||||||
|
# probably doesn't support this......
|
||||||
|
#dhcp-option=119,eng.apple.com,marketing.apple.com
|
||||||
|
|
||||||
# Set the boot filename and tftpd server name and address
|
# Set the boot filename and tftpd server name and address
|
||||||
# for BOOTP. You will only need this is you want to
|
# for BOOTP. You will only need this is you want to
|
||||||
@@ -252,6 +255,16 @@ bogus-priv
|
|||||||
# the line below.
|
# the line below.
|
||||||
#dhcp-leasefile=/var/lib/misc/dnsmasq.leases
|
#dhcp-leasefile=/var/lib/misc/dnsmasq.leases
|
||||||
|
|
||||||
|
# Set the DHCP server to authoritative mode. In this mode it will barge in
|
||||||
|
# and take over the lease for any client which broadcasts on the network,
|
||||||
|
# whether it has a record of the lease or not. This avoids long timeouts
|
||||||
|
# when a machine wakes up on a new network. DO NOT enable this if there's
|
||||||
|
# the slighest chance that you might end up accidentally configuring a DHCP
|
||||||
|
# server for your campus/company accidentally. The ISC server uses the same
|
||||||
|
# the same option, and this URL provides more information:
|
||||||
|
# http://www.isc.org/index.pl?/sw/dhcp/authoritative.php
|
||||||
|
#dhcp-authoritative
|
||||||
|
|
||||||
# Set the cachesize here.
|
# Set the cachesize here.
|
||||||
#cache-size=150
|
#cache-size=150
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ 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, LEAF, 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 and the m0n0wall project.
|
||||||
<P>
|
<P>
|
||||||
Dnsmasq provides the following features:
|
Dnsmasq provides the following features:
|
||||||
<DIR>
|
<DIR>
|
||||||
@@ -41,22 +42,18 @@ machine: If the names of local machines are there, then they can all
|
|||||||
be addressed without having to maintain /etc/hosts on each machine.
|
be addressed without having to maintain /etc/hosts on each machine.
|
||||||
</LI>
|
</LI>
|
||||||
<LI>
|
<LI>
|
||||||
Dnsmasq will serve names from the DHCP leases file on the firewall machine:
|
The integrated DHCP server supports static and dynamic DHCP leases and
|
||||||
If machines specify a hostname when they take out a DHCP lease, then they are
|
multiple networks and IP ranges. It works across BOOTP relays and
|
||||||
addressable in the local DNS. <B>UPDATE</B> Dnsmasq version 2 now offers an integrated DHCP server
|
supports DHCP options including RFC3397 DNS search lists.
|
||||||
instead of the lease file reader. This gives better control of the
|
Machines which are configured by DHCP have their names automatically
|
||||||
interaction with new functions (for example fixed IP leasess and
|
included in the DNS and the names can specified by each machine or
|
||||||
attaching names to ethernet addresses centrally) it's also much
|
centrally by associating a name with a MAC address in the dnsmasq
|
||||||
smaller than dnsmasq and ISC dhcpd which is important for router distros.
|
config file.
|
||||||
</LI>
|
</LI>
|
||||||
<LI>
|
<LI>
|
||||||
Dnsmasq caches internet addresses (A records and AAAA records) and address-to-name
|
Dnsmasq caches internet addresses (A records and AAAA records) and address-to-name
|
||||||
mappings (PTR records), reducing the load on upstream servers and
|
mappings (PTR records), reducing the load on upstream servers and
|
||||||
improving performance (especially on modem connections). From version
|
improving performance (especially on modem connections).
|
||||||
0.95 the cache honours time-to-live information and removes old
|
|
||||||
records as they expire. From version 0.996 dnsmasq does negative
|
|
||||||
caching. From version 1.2 dnsmasq supports IPv6 addresses, both
|
|
||||||
in its cache and in /etc/hosts.
|
|
||||||
</LI>
|
</LI>
|
||||||
<LI>
|
<LI>
|
||||||
Dnsmasq can be configured to automatically pick up the addresses of
|
Dnsmasq can be configured to automatically pick up the addresses of
|
||||||
@@ -76,14 +73,8 @@ upstream servers handling only those domains. This makes integration
|
|||||||
with private DNS systems easy.
|
with private DNS systems easy.
|
||||||
</LI>
|
</LI>
|
||||||
<LI>
|
<LI>
|
||||||
Dnsmasq can be configured to return an MX record
|
Dnsmasq supports MX records and can be configured to return MX records
|
||||||
for the firewall host. This makes it easy to configure the mailer on the local
|
for any or all local machines.
|
||||||
machines to forward all mail to the central mailer on the firewall host. Never
|
|
||||||
lose root messages from your machines again!
|
|
||||||
</LI>
|
|
||||||
<LI>
|
|
||||||
For version 1.15 dnsmasq has a facility to work around Verisign's infamous wildcard A record
|
|
||||||
in the .com and .net TLDs
|
|
||||||
</LI>
|
</LI>
|
||||||
</DIR>
|
</DIR>
|
||||||
|
|
||||||
@@ -115,12 +106,19 @@ bzip2 dnsmasq-zzz.tar
|
|||||||
Ulrich Ivens has a nice HOWTO in German on installing dnsmasq at <A
|
Ulrich Ivens has a nice HOWTO in German on installing dnsmasq at <A
|
||||||
HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardware-shop.de/dnsmasq.html</A>
|
HREF="http://howto.linux-hardware-shop.de/dnsmasq.html">http://howto.linux-hardware-shop.de/dnsmasq.html</A>
|
||||||
and Damien Raude-Morvan has one in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A>
|
and Damien Raude-Morvan has one in French at <A HREF="http://www.drazzib.com/docs-dnsmasq.html">http://www.drazzib.com/docs-dnsmasq.html</A>
|
||||||
|
There is a good article about dnsmasq at <A
|
||||||
|
HREF="http://www.enterprisenetworkingplanet.com/netos/article.php/3377351">http://www.enterprisenetworkingplanet.com/netos/article.php/3377351</A>
|
||||||
|
|
||||||
<H2>License.</H2>
|
<H2>License.</H2>
|
||||||
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
|
Dnsmasq is distributed under the GPL. See the file COPYING in the distribution
|
||||||
for details.
|
for details.
|
||||||
|
|
||||||
<H2>Contact.</H2>
|
<H2>Contact.</H2>
|
||||||
Dnsmasq was written by Simon Kelley. You can contact me at <A HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>. Bugreports, patches, and suggestions for improvements gratefully accepted.
|
There is a dnsmasq mailing list at <A
|
||||||
|
HREF="http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss">
|
||||||
|
http://lists.thekelleys.org.uk/mailman/listinfo/dnsmasq-discuss</A> which should be the
|
||||||
|
first location for queries, bugreports, suggestions etc.
|
||||||
|
Dnsmasq was written by Simon Kelley. You can contact me at <A
|
||||||
|
HREF="mailto:simon@thekelleys.org.uk">simon@thekelleys.org.uk</A>.
|
||||||
</BODY>
|
</BODY>
|
||||||
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
--- dnsmasq.8 2004-08-08 20:57:56.000000000 +0200
|
--- dnsmasq.8 2004-08-08 20:57:56.000000000 +0200
|
||||||
+++ dnsmasq.8 2004-08-12 00:40:01.000000000 +0200
|
+++ dnsmasq.8 2004-08-12 00:40:01.000000000 +0200
|
||||||
@@ -63,7 +63,7 @@
|
@@ -69,7 +69,7 @@
|
||||||
.TP
|
.TP
|
||||||
.B \-g, --group=<groupname>
|
.B \-g, --group=<groupname>
|
||||||
Specify the group which dnsmasq will run
|
Specify the group which dnsmasq will run
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
#define IP6INTERFACES "/proc/net/if_inet6"
|
#define IP6INTERFACES "/proc/net/if_inet6"
|
||||||
#define UPTIME "/proc/uptime"
|
#define UPTIME "/proc/uptime"
|
||||||
#define DHCP_SERVER_PORT 67
|
#define DHCP_SERVER_PORT 67
|
||||||
@@ -176,7 +176,7 @@
|
@@ -187,7 +187,7 @@
|
||||||
|
|
||||||
/* platform independent options. */
|
/* platform independent options. */
|
||||||
#undef HAVE_BROKEN_RTC
|
#undef HAVE_BROKEN_RTC
|
||||||
|
|||||||
+120
-71
@@ -17,11 +17,12 @@ static struct crec *dhcp_inuse, *dhcp_spare, *new_chain;
|
|||||||
static int cache_inserted, cache_live_freed, insert_error;
|
static int cache_inserted, cache_live_freed, insert_error;
|
||||||
static union bigname *big_free;
|
static union bigname *big_free;
|
||||||
static int bignames_left, log_queries, cache_size, hash_size;
|
static int bignames_left, log_queries, cache_size, hash_size;
|
||||||
static char *addn_file;
|
static int uid;
|
||||||
|
|
||||||
static void cache_free(struct crec *crecp);
|
static void cache_free(struct crec *crecp);
|
||||||
static void cache_unlink(struct crec *crecp);
|
static void cache_unlink(struct crec *crecp);
|
||||||
static void cache_link(struct crec *crecp);
|
static void cache_link(struct crec *crecp);
|
||||||
|
static char *record_source(struct hostsfile *add_hosts, int index);
|
||||||
|
|
||||||
void cache_init(int size, int logq)
|
void cache_init(int size, int logq)
|
||||||
{
|
{
|
||||||
@@ -35,7 +36,7 @@ void cache_init(int size, int logq)
|
|||||||
cache_size = size;
|
cache_size = size;
|
||||||
big_free = NULL;
|
big_free = NULL;
|
||||||
bignames_left = size/10;
|
bignames_left = size/10;
|
||||||
addn_file = NULL;
|
uid = 0;
|
||||||
|
|
||||||
cache_inserted = cache_live_freed = 0;
|
cache_inserted = cache_live_freed = 0;
|
||||||
|
|
||||||
@@ -47,6 +48,7 @@ void cache_init(int size, int logq)
|
|||||||
{
|
{
|
||||||
cache_link(crecp);
|
cache_link(crecp);
|
||||||
crecp->flags = 0;
|
crecp->flags = 0;
|
||||||
|
crecp->uid = uid++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +85,8 @@ static void cache_free(struct crec *crecp)
|
|||||||
{
|
{
|
||||||
crecp->flags &= ~F_FORWARD;
|
crecp->flags &= ~F_FORWARD;
|
||||||
crecp->flags &= ~F_REVERSE;
|
crecp->flags &= ~F_REVERSE;
|
||||||
|
crecp->uid = uid++; /* invalidate CNAMES pointing to this. */
|
||||||
|
|
||||||
if (cache_tail)
|
if (cache_tail)
|
||||||
cache_tail->next = crecp;
|
cache_tail->next = crecp;
|
||||||
else
|
else
|
||||||
@@ -137,6 +140,22 @@ char *cache_get_name(struct crec *crecp)
|
|||||||
return crecp->name.sname;
|
return crecp->name.sname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int is_outdated_cname_pointer(struct crec *crecp)
|
||||||
|
{
|
||||||
|
struct crec *target = crecp->addr.cname.cache;
|
||||||
|
|
||||||
|
if (!(crecp->flags & F_CNAME))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!target)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (crecp->addr.cname.uid == target->uid)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
|
static void cache_scan_free(char *name, struct all_addr *addr, time_t now, unsigned short flags)
|
||||||
{
|
{
|
||||||
/* Scan and remove old entries.
|
/* Scan and remove old entries.
|
||||||
@@ -146,14 +165,15 @@ static void cache_scan_free(char *name, struct all_addr *addr, time_t now, unsig
|
|||||||
entries in the whole cache.
|
entries in the whole cache.
|
||||||
If (flags == 0) remove any expired entries in the whole cache. */
|
If (flags == 0) remove any expired entries in the whole cache. */
|
||||||
|
|
||||||
#define F_CACHESTATUS (F_HOSTS | F_DHCP | F_FORWARD | F_REVERSE | F_IPV4 | F_IPV6)
|
#define F_CACHESTATUS (F_HOSTS | F_DHCP | F_FORWARD | F_REVERSE | F_IPV4 | F_IPV6 | F_CNAME)
|
||||||
struct crec *crecp, **up;
|
struct crec *crecp, **up;
|
||||||
flags &= (F_FORWARD | F_REVERSE | F_IPV6 | F_IPV4);
|
flags &= (F_FORWARD | F_REVERSE | F_IPV6 | F_IPV4 | F_CNAME);
|
||||||
|
|
||||||
if (flags & F_FORWARD)
|
if (flags & F_FORWARD)
|
||||||
{
|
{
|
||||||
for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
|
for (up = hash_bucket(name), crecp = *up; crecp; crecp = crecp->hash_next)
|
||||||
if ((!(crecp->flags & F_IMMORTAL) && difftime(now, crecp->ttd) > 0) ||
|
if ((!(crecp->flags & F_IMMORTAL) && difftime(now, crecp->ttd) > 0) ||
|
||||||
|
is_outdated_cname_pointer(crecp) ||
|
||||||
((flags == (crecp->flags & F_CACHESTATUS)) && hostname_isequal(cache_get_name(crecp), name)))
|
((flags == (crecp->flags & F_CACHESTATUS)) && hostname_isequal(cache_get_name(crecp), name)))
|
||||||
{
|
{
|
||||||
*up = crecp->hash_next;
|
*up = crecp->hash_next;
|
||||||
@@ -177,7 +197,7 @@ static void cache_scan_free(char *name, struct all_addr *addr, time_t now, unsig
|
|||||||
for (i = 0; i < hash_size; i++)
|
for (i = 0; i < hash_size; i++)
|
||||||
for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
|
for (crecp = hash_table[i], up = &hash_table[i]; crecp; crecp = crecp->hash_next)
|
||||||
if ((!(crecp->flags & F_IMMORTAL) && difftime(now, crecp->ttd) > 0) ||
|
if ((!(crecp->flags & F_IMMORTAL) && difftime(now, crecp->ttd) > 0) ||
|
||||||
((flags == (crecp->flags & F_CACHESTATUS)) && memcmp(&crecp->addr, addr, addrlen) == 0))
|
((flags == (crecp->flags & F_CACHESTATUS)) && memcmp(&crecp->addr.addr, addr, addrlen) == 0))
|
||||||
{
|
{
|
||||||
*up = crecp->hash_next;
|
*up = crecp->hash_next;
|
||||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||||
@@ -214,8 +234,8 @@ void cache_start_insert(void)
|
|||||||
insert_error = 0;
|
insert_error = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cache_insert(char *name, struct all_addr *addr,
|
struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||||
time_t now, unsigned long ttl, unsigned short flags)
|
time_t now, unsigned long ttl, unsigned short flags)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
|
int addrlen = (flags & F_IPV6) ? IN6ADDRSZ : INADDRSZ;
|
||||||
@@ -226,7 +246,7 @@ void cache_insert(char *name, struct all_addr *addr,
|
|||||||
union bigname *big_name = NULL;
|
union bigname *big_name = NULL;
|
||||||
int freed_all = flags & F_REVERSE;
|
int freed_all = flags & F_REVERSE;
|
||||||
|
|
||||||
log_query(flags | F_UPSTREAM, name, addr, 0);
|
log_query(flags | F_UPSTREAM, name, addr, 0, NULL, 0);
|
||||||
|
|
||||||
/* name is needed as workspace by log_query in this case */
|
/* name is needed as workspace by log_query in this case */
|
||||||
if ((flags & F_NEG) && (flags & F_REVERSE))
|
if ((flags & F_NEG) && (flags & F_REVERSE))
|
||||||
@@ -237,7 +257,7 @@ void cache_insert(char *name, struct all_addr *addr,
|
|||||||
|
|
||||||
/* if previous insertion failed give up now. */
|
/* if previous insertion failed give up now. */
|
||||||
if (insert_error)
|
if (insert_error)
|
||||||
return;
|
return NULL;
|
||||||
|
|
||||||
/* First remove any expired entries and entries for the name/address we
|
/* First remove any expired entries and entries for the name/address we
|
||||||
are currently inserting. */
|
are currently inserting. */
|
||||||
@@ -248,7 +268,7 @@ void cache_insert(char *name, struct all_addr *addr,
|
|||||||
if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
|
if (!(new = cache_tail)) /* no entries left - cache is too small, bail */
|
||||||
{
|
{
|
||||||
insert_error = 1;
|
insert_error = 1;
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* End of LRU list is still in use: if we didn't scan all the hash
|
/* End of LRU list is still in use: if we didn't scan all the hash
|
||||||
@@ -259,7 +279,7 @@ void cache_insert(char *name, struct all_addr *addr,
|
|||||||
{
|
{
|
||||||
if (freed_all)
|
if (freed_all)
|
||||||
{
|
{
|
||||||
cache_scan_free(cache_get_name(new), &new->addr, now, new->flags);
|
cache_scan_free(cache_get_name(new), &new->addr.addr, now, new->flags);
|
||||||
cache_live_freed++;
|
cache_live_freed++;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -283,7 +303,7 @@ void cache_insert(char *name, struct all_addr *addr,
|
|||||||
!(big_name = (union bigname *)malloc(sizeof(union bigname))))
|
!(big_name = (union bigname *)malloc(sizeof(union bigname))))
|
||||||
{
|
{
|
||||||
insert_error = 1;
|
insert_error = 1;
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
bignames_left--;
|
bignames_left--;
|
||||||
@@ -306,10 +326,15 @@ void cache_insert(char *name, struct all_addr *addr,
|
|||||||
else
|
else
|
||||||
*cache_get_name(new) = 0;
|
*cache_get_name(new) = 0;
|
||||||
if (addr)
|
if (addr)
|
||||||
memcpy(&new->addr, addr, addrlen);
|
memcpy(&new->addr.addr, addr, addrlen);
|
||||||
|
else
|
||||||
|
new->addr.cname.cache = NULL;
|
||||||
|
|
||||||
new->ttd = now + (time_t)ttl;
|
new->ttd = now + (time_t)ttl;
|
||||||
new->next = new_chain;
|
new->next = new_chain;
|
||||||
new_chain = new;
|
new_chain = new;
|
||||||
|
|
||||||
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* after end of insertion, commit the new entries */
|
/* after end of insertion, commit the new entries */
|
||||||
@@ -321,10 +346,16 @@ void cache_end_insert(void)
|
|||||||
while (new_chain)
|
while (new_chain)
|
||||||
{
|
{
|
||||||
struct crec *tmp = new_chain->next;
|
struct crec *tmp = new_chain->next;
|
||||||
cache_hash(new_chain);
|
/* drop CNAMEs which didn't find a target. */
|
||||||
cache_link(new_chain);
|
if (is_outdated_cname_pointer(new_chain))
|
||||||
|
cache_free(new_chain);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cache_hash(new_chain);
|
||||||
|
cache_link(new_chain);
|
||||||
|
cache_inserted++;
|
||||||
|
}
|
||||||
new_chain = tmp;
|
new_chain = tmp;
|
||||||
cache_inserted++;
|
|
||||||
}
|
}
|
||||||
new_chain = NULL;
|
new_chain = NULL;
|
||||||
}
|
}
|
||||||
@@ -345,7 +376,8 @@ struct crec *cache_find_by_name(struct crec *crecp, char *name, time_t now, unsi
|
|||||||
{
|
{
|
||||||
next = crecp->hash_next;
|
next = crecp->hash_next;
|
||||||
|
|
||||||
if ((crecp->flags & F_IMMORTAL) || difftime(now, crecp->ttd) < 0)
|
if (!is_outdated_cname_pointer(crecp) &&
|
||||||
|
((crecp->flags & F_IMMORTAL) || difftime(now, crecp->ttd) < 0))
|
||||||
{
|
{
|
||||||
if ((crecp->flags & F_FORWARD) &&
|
if ((crecp->flags & F_FORWARD) &&
|
||||||
(crecp->flags & prot) &&
|
(crecp->flags & prot) &&
|
||||||
@@ -430,7 +462,7 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
|
|||||||
{
|
{
|
||||||
if ((crecp->flags & F_REVERSE) &&
|
if ((crecp->flags & F_REVERSE) &&
|
||||||
(crecp->flags & prot) &&
|
(crecp->flags & prot) &&
|
||||||
memcmp(&crecp->addr, addr, addrlen) == 0)
|
memcmp(&crecp->addr.addr, addr, addrlen) == 0)
|
||||||
{
|
{
|
||||||
if (crecp->flags & (F_HOSTS | F_DHCP))
|
if (crecp->flags & (F_HOSTS | F_DHCP))
|
||||||
{
|
{
|
||||||
@@ -461,19 +493,20 @@ struct crec *cache_find_by_addr(struct crec *crecp, struct all_addr *addr,
|
|||||||
if (ans &&
|
if (ans &&
|
||||||
(ans->flags & F_REVERSE) &&
|
(ans->flags & F_REVERSE) &&
|
||||||
(ans->flags & prot) &&
|
(ans->flags & prot) &&
|
||||||
memcmp(&ans->addr, addr, addrlen) == 0)
|
memcmp(&ans->addr.addr, addr, addrlen) == 0)
|
||||||
return ans;
|
return ans;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen, unsigned short flags)
|
static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrlen,
|
||||||
|
unsigned short flags, int index)
|
||||||
{
|
{
|
||||||
struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
|
struct crec *lookup = cache_find_by_name(NULL, cache->name.sname, 0, flags & (F_IPV4 | F_IPV6));
|
||||||
|
|
||||||
/* Remove duplicates in hosts files. */
|
/* Remove duplicates in hosts files. */
|
||||||
if (lookup && (lookup->flags & F_HOSTS) &&
|
if (lookup && (lookup->flags & F_HOSTS) &&
|
||||||
memcmp(&lookup->addr, addr, addrlen) == 0)
|
memcmp(&lookup->addr.addr, addr, addrlen) == 0)
|
||||||
free(cache);
|
free(cache);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -481,12 +514,13 @@ static void add_hosts_entry(struct crec *cache, struct all_addr *addr, int addrl
|
|||||||
if (cache_find_by_addr(NULL, addr, 0, flags & (F_IPV4 | F_IPV6)))
|
if (cache_find_by_addr(NULL, addr, 0, flags & (F_IPV4 | F_IPV6)))
|
||||||
flags &= ~F_REVERSE;
|
flags &= ~F_REVERSE;
|
||||||
cache->flags = flags;
|
cache->flags = flags;
|
||||||
memcpy(&cache->addr, addr, addrlen);
|
cache->uid = index;
|
||||||
|
memcpy(&cache->addr.addr, addr, addrlen);
|
||||||
cache_hash(cache);
|
cache_hash(cache);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void read_hostsfile(char *filename, int opts, char *buff, char *domain_suffix, int is_addn)
|
static void read_hostsfile(char *filename, int opts, char *buff, char *domain_suffix, int index)
|
||||||
{
|
{
|
||||||
FILE *f = fopen(filename, "r");
|
FILE *f = fopen(filename, "r");
|
||||||
char *line;
|
char *line;
|
||||||
@@ -531,9 +565,6 @@ static void read_hostsfile(char *filename, int opts, char *buff, char *domain_su
|
|||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (is_addn)
|
|
||||||
flags |= F_ADDN;
|
|
||||||
|
|
||||||
while ((token = strtok(NULL, " \t\n\r")) && (*token != '#'))
|
while ((token = strtok(NULL, " \t\n\r")) && (*token != '#'))
|
||||||
{
|
{
|
||||||
struct crec *cache;
|
struct crec *cache;
|
||||||
@@ -548,12 +579,12 @@ static void read_hostsfile(char *filename, int opts, char *buff, char *domain_su
|
|||||||
strcpy(cache->name.sname, token);
|
strcpy(cache->name.sname, token);
|
||||||
strcat(cache->name.sname, ".");
|
strcat(cache->name.sname, ".");
|
||||||
strcat(cache->name.sname, domain_suffix);
|
strcat(cache->name.sname, domain_suffix);
|
||||||
add_hosts_entry(cache, &addr, addrlen, flags);
|
add_hosts_entry(cache, &addr, addrlen, flags, index);
|
||||||
}
|
}
|
||||||
if ((cache = malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
|
if ((cache = malloc(sizeof(struct crec) + strlen(token)+1-SMALLDNAME)))
|
||||||
{
|
{
|
||||||
strcpy(cache->name.sname, token);
|
strcpy(cache->name.sname, token);
|
||||||
add_hosts_entry(cache, &addr, addrlen, flags);
|
add_hosts_entry(cache, &addr, addrlen, flags, index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -566,7 +597,7 @@ static void read_hostsfile(char *filename, int opts, char *buff, char *domain_su
|
|||||||
syslog(LOG_INFO, "read %s - %d addresses", filename, count);
|
syslog(LOG_INFO, "read %s - %d addresses", filename, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void cache_reload(int opts, char *buff, char *domain_suffix, char *addn_hosts)
|
void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts)
|
||||||
{
|
{
|
||||||
struct crec *cache, **up, *tmp;
|
struct crec *cache, **up, *tmp;
|
||||||
int i;
|
int i;
|
||||||
@@ -603,11 +634,11 @@ void cache_reload(int opts, char *buff, char *domain_suffix, char *addn_hosts)
|
|||||||
|
|
||||||
if (!(opts & OPT_NO_HOSTS))
|
if (!(opts & OPT_NO_HOSTS))
|
||||||
read_hostsfile(HOSTSFILE, opts, buff, domain_suffix, 0);
|
read_hostsfile(HOSTSFILE, opts, buff, domain_suffix, 0);
|
||||||
if (addn_hosts)
|
while (addn_hosts)
|
||||||
{
|
{
|
||||||
read_hostsfile(addn_hosts, opts, buff, domain_suffix, 1);
|
read_hostsfile(addn_hosts->fname, opts, buff, domain_suffix, addn_hosts->index);
|
||||||
addn_file = addn_hosts;
|
addn_hosts = addn_hosts->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cache_unhash_dhcp(void)
|
void cache_unhash_dhcp(void)
|
||||||
@@ -633,7 +664,8 @@ void cache_unhash_dhcp(void)
|
|||||||
dhcp_inuse = NULL;
|
dhcp_inuse = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd)
|
void cache_add_dhcp_entry(struct daemon *daemon, char *host_name,
|
||||||
|
struct in_addr *host_address, time_t ttd)
|
||||||
{
|
{
|
||||||
struct crec *crec;
|
struct crec *crec;
|
||||||
unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
|
unsigned short flags = F_DHCP | F_FORWARD | F_IPV4 | F_REVERSE;
|
||||||
@@ -641,26 +673,23 @@ void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t
|
|||||||
if (!host_name)
|
if (!host_name)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4)))
|
if ((crec = cache_find_by_name(NULL, host_name, 0, F_IPV4 | F_CNAME)))
|
||||||
{
|
{
|
||||||
if (crec->flags & F_HOSTS)
|
if (crec->flags & F_HOSTS)
|
||||||
{
|
{
|
||||||
if (crec->addr.addr.addr4.s_addr != host_address->s_addr)
|
if (crec->addr.addr.addr.addr4.s_addr != host_address->s_addr)
|
||||||
syslog(LOG_WARNING, "not naming DHCP lease for %s because it clashes with an /etc/hosts entry.", host_name);
|
{
|
||||||
|
strcpy(daemon->namebuff, inet_ntoa(crec->addr.addr.addr.addr4));
|
||||||
|
syslog(LOG_WARNING,
|
||||||
|
"not giving name %s to the DHCP lease of %s because "
|
||||||
|
"the name exists in %s with address %s",
|
||||||
|
host_name, inet_ntoa(*host_address),
|
||||||
|
record_source(daemon->addn_hosts, crec->uid), daemon->namebuff);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else if (!(crec->flags & F_DHCP))
|
else if (!(crec->flags & F_DHCP))
|
||||||
{
|
cache_scan_free(host_name, NULL, 0, crec->flags & (F_IPV4 | F_CNAME | F_FORWARD));
|
||||||
if (!(crec->flags & F_NEG))
|
|
||||||
{
|
|
||||||
syslog(LOG_WARNING, "not naming DHCP lease for %s because it clashes with a cached name.", host_name);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* name may have been searched for before being allocated to DHCP and
|
|
||||||
therefore got a negative cache entry. If so delete it and continue. */
|
|
||||||
cache_scan_free(host_name, NULL, 0, F_IPV4 | F_FORWARD);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)))
|
if ((crec = cache_find_by_addr(NULL, (struct all_addr *)host_address, 0, F_IPV4)))
|
||||||
@@ -684,7 +713,7 @@ void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t
|
|||||||
crec->flags |= F_IMMORTAL;
|
crec->flags |= F_IMMORTAL;
|
||||||
else
|
else
|
||||||
crec->ttd = ttd;
|
crec->ttd = ttd;
|
||||||
crec->addr.addr.addr4 = *host_address;
|
crec->addr.addr.addr.addr4 = *host_address;
|
||||||
crec->name.namep = host_name;
|
crec->name.namep = host_name;
|
||||||
crec->prev = dhcp_inuse;
|
crec->prev = dhcp_inuse;
|
||||||
dhcp_inuse = crec;
|
dhcp_inuse = crec;
|
||||||
@@ -694,12 +723,12 @@ void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void dump_cache(int debug, int cache_size)
|
void dump_cache(struct daemon *daemon)
|
||||||
{
|
{
|
||||||
syslog(LOG_INFO, "cache size %d, %d/%d cache insertions re-used unexpired cache entries.",
|
syslog(LOG_INFO, "cache size %d, %d/%d cache insertions re-used unexpired cache entries.",
|
||||||
cache_size, cache_live_freed, cache_inserted);
|
daemon->cachesize, cache_live_freed, cache_inserted);
|
||||||
|
|
||||||
if (debug)
|
if (daemon->options & (OPT_DEBUG | OPT_LOG))
|
||||||
{
|
{
|
||||||
struct crec *cache ;
|
struct crec *cache ;
|
||||||
char addrbuff[ADDRSTRLEN];
|
char addrbuff[ADDRSTRLEN];
|
||||||
@@ -711,14 +740,21 @@ void dump_cache(int debug, int cache_size)
|
|||||||
{
|
{
|
||||||
if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
|
if ((cache->flags & F_NEG) && (cache->flags & F_FORWARD))
|
||||||
addrbuff[0] = 0;
|
addrbuff[0] = 0;
|
||||||
|
else if (cache->flags & F_CNAME)
|
||||||
|
{
|
||||||
|
addrbuff[0] = 0;
|
||||||
|
addrbuff[ADDRSTRLEN-1] = 0;
|
||||||
|
if (!is_outdated_cname_pointer(cache))
|
||||||
|
strncpy(addrbuff, cache_get_name(cache->addr.cname.cache), ADDRSTRLEN);
|
||||||
|
}
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else if (cache->flags & F_IPV4)
|
else if (cache->flags & F_IPV4)
|
||||||
inet_ntop(AF_INET, &cache->addr, addrbuff, ADDRSTRLEN);
|
inet_ntop(AF_INET, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
||||||
else if (cache->flags & F_IPV6)
|
else if (cache->flags & F_IPV6)
|
||||||
inet_ntop(AF_INET6, &cache->addr, addrbuff, ADDRSTRLEN);
|
inet_ntop(AF_INET6, &cache->addr.addr, addrbuff, ADDRSTRLEN);
|
||||||
#else
|
#else
|
||||||
else
|
else
|
||||||
strcpy(addrbuff, inet_ntoa(cache->addr.addr.addr4));
|
strcpy(addrbuff, inet_ntoa(cache->addr.addr.addr.addr4));
|
||||||
#endif
|
#endif
|
||||||
syslog(LOG_DEBUG,
|
syslog(LOG_DEBUG,
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
@@ -729,6 +765,7 @@ void dump_cache(int debug, int cache_size)
|
|||||||
cache_get_name(cache), addrbuff,
|
cache_get_name(cache), addrbuff,
|
||||||
cache->flags & F_IPV4 ? "4" : "",
|
cache->flags & F_IPV4 ? "4" : "",
|
||||||
cache->flags & F_IPV6 ? "6" : "",
|
cache->flags & F_IPV6 ? "6" : "",
|
||||||
|
cache->flags & F_CNAME ? "C" : "",
|
||||||
cache->flags & F_FORWARD ? "F" : " ",
|
cache->flags & F_FORWARD ? "F" : " ",
|
||||||
cache->flags & F_REVERSE ? "R" : " ",
|
cache->flags & F_REVERSE ? "R" : " ",
|
||||||
cache->flags & F_IMMORTAL ? "I" : " ",
|
cache->flags & F_IMMORTAL ? "I" : " ",
|
||||||
@@ -736,19 +773,34 @@ void dump_cache(int debug, int cache_size)
|
|||||||
cache->flags & F_NEG ? "N" : " ",
|
cache->flags & F_NEG ? "N" : " ",
|
||||||
cache->flags & F_NXDOMAIN ? "X" : " ",
|
cache->flags & F_NXDOMAIN ? "X" : " ",
|
||||||
cache->flags & F_HOSTS ? "H" : " ",
|
cache->flags & F_HOSTS ? "H" : " ",
|
||||||
cache->flags & F_ADDN ? "A" : " ",
|
|
||||||
#ifdef HAVE_BROKEN_RTC
|
#ifdef HAVE_BROKEN_RTC
|
||||||
cache->flags & F_IMMORTAL ? 0: (unsigned long)cache->ttd) ;
|
cache->flags & F_IMMORTAL ? 0: (unsigned long)cache->ttd
|
||||||
#else
|
#else
|
||||||
cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd))) ;
|
cache->flags & F_IMMORTAL ? "\n" : ctime(&(cache->ttd))
|
||||||
#endif
|
#endif
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *record_source(struct hostsfile *addn_hosts, int index)
|
||||||
|
{
|
||||||
|
char *source = HOSTSFILE;
|
||||||
|
while (addn_hosts)
|
||||||
|
{
|
||||||
|
if (addn_hosts->index == index)
|
||||||
|
{
|
||||||
|
source = addn_hosts->fname;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
addn_hosts = addn_hosts->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
void log_query(unsigned short flags, char *name, struct all_addr *addr, unsigned short type)
|
void log_query(unsigned short flags, char *name, struct all_addr *addr,
|
||||||
|
unsigned short type, struct hostsfile *addn_hosts, int index)
|
||||||
{
|
{
|
||||||
char *source;
|
char *source;
|
||||||
char *verb = "is";
|
char *verb = "is";
|
||||||
@@ -759,7 +811,7 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, unsigned
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
strcpy(types, " ");
|
strcpy(types, " ");
|
||||||
|
|
||||||
if (flags & F_NEG)
|
if (flags & F_NEG)
|
||||||
{
|
{
|
||||||
if (flags & F_REVERSE)
|
if (flags & F_REVERSE)
|
||||||
@@ -780,6 +832,8 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, unsigned
|
|||||||
else if (flags & F_IPV6)
|
else if (flags & F_IPV6)
|
||||||
strcat(addrbuff, "-IPv6");
|
strcat(addrbuff, "-IPv6");
|
||||||
}
|
}
|
||||||
|
else if (flags & F_CNAME)
|
||||||
|
strcpy(addrbuff, "<CNAME>");
|
||||||
else
|
else
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||||
@@ -787,17 +841,12 @@ void log_query(unsigned short flags, char *name, struct all_addr *addr, unsigned
|
|||||||
#else
|
#else
|
||||||
strcpy(addrbuff, inet_ntoa(addr->addr.addr4));
|
strcpy(addrbuff, inet_ntoa(addr->addr.addr4));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (flags & F_DHCP)
|
if (flags & F_DHCP)
|
||||||
source = "DHCP";
|
source = "DHCP";
|
||||||
else if (flags & F_HOSTS)
|
else if (flags & F_HOSTS)
|
||||||
{
|
source = record_source(addn_hosts, index);
|
||||||
if (flags & F_ADDN)
|
else if (flags & F_CONFIG)
|
||||||
source = addn_file;
|
|
||||||
else
|
|
||||||
source = HOSTSFILE;
|
|
||||||
}
|
|
||||||
else if (flags & F_CONFIG)
|
|
||||||
source = "config";
|
source = "config";
|
||||||
else if (flags & F_UPSTREAM)
|
else if (flags & F_UPSTREAM)
|
||||||
source = "reply";
|
source = "reply";
|
||||||
|
|||||||
+12
-13
@@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
/* Author's email: simon@thekelleys.org.uk */
|
/* Author's email: simon@thekelleys.org.uk */
|
||||||
|
|
||||||
#define VERSION "2.14"
|
#define VERSION "2.17"
|
||||||
|
|
||||||
#define FTABSIZ 150 /* max number of outstanding requests */
|
#define FTABSIZ 150 /* max number of outstanding requests */
|
||||||
#define MAX_PROCS 20 /* max no children for TCP requests */
|
#define MAX_PROCS 20 /* max no children for TCP requests */
|
||||||
@@ -156,7 +156,7 @@ HAVE_PSELECT
|
|||||||
If your C library implements pselect, define this.
|
If your C library implements pselect, define this.
|
||||||
|
|
||||||
HAVE_BPF
|
HAVE_BPF
|
||||||
If your OS implements Berkeley PAcket filter, define this.
|
If your OS implements Berkeley Packet filter, define this.
|
||||||
|
|
||||||
NOTES:
|
NOTES:
|
||||||
For Linux you should define
|
For Linux you should define
|
||||||
@@ -176,10 +176,12 @@ NOTES:
|
|||||||
you should NOT define
|
you should NOT define
|
||||||
HAVE_LINUX_IPV6_PROC
|
HAVE_LINUX_IPV6_PROC
|
||||||
and you MAY define
|
and you MAY define
|
||||||
HAVE_ARC4RANDOM - OpenBSD and FreeBSD
|
HAVE_ARC4RANDOM - OpenBSD and FreeBSD and NetBSD version 2.0 or later
|
||||||
HAVE_DEV_URANDOM - OpenBSD and FreeBSD
|
HAVE_DEV_URANDOM - OpenBSD and FreeBSD and NetBSD
|
||||||
HAVE_DEV_RANDOM - FreeBSD (OpenBSD with hardware random number generator)
|
HAVE_DEV_RANDOM - FreeBSD and NetBSD
|
||||||
HAVE_GETOPT_LONG - only if you link GNU getopt.
|
(OpenBSD with hardware random number generator)
|
||||||
|
HAVE_GETOPT_LONG - NetBSD
|
||||||
|
(FreeBSD and OpenBSD only if you link GNU getopt)
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -250,9 +252,6 @@ typedef unsigned long in_addr_t;
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* #elif defined(__OpenBSD__)
|
|
||||||
#error The sockets API in OpenBSD does not provide facilities required by dnsmasq
|
|
||||||
*/
|
|
||||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
#elif defined(__FreeBSD__) || defined(__OpenBSD__)
|
||||||
#undef HAVE_LINUX_IPV6_PROC
|
#undef HAVE_LINUX_IPV6_PROC
|
||||||
#undef HAVE_GETOPT_LONG
|
#undef HAVE_GETOPT_LONG
|
||||||
@@ -275,16 +274,16 @@ typedef unsigned long in_addr_t;
|
|||||||
#define BIND_8_COMPAT
|
#define BIND_8_COMPAT
|
||||||
/* Define before sys/socket.h is included so we get socklen_t */
|
/* Define before sys/socket.h is included so we get socklen_t */
|
||||||
#define _BSD_SOCKLEN_T_
|
#define _BSD_SOCKLEN_T_
|
||||||
/* The three below are not defined in Mac OS X arpa/nameserv.h */
|
/* This is not defined in Mac OS X arpa/nameserv.h */
|
||||||
#define IN6ADDRSZ 16
|
#define IN6ADDRSZ 16
|
||||||
|
|
||||||
#elif defined(__NetBSD__)
|
#elif defined(__NetBSD__)
|
||||||
#undef HAVE_LINUX_IPV6_PROC
|
#undef HAVE_LINUX_IPV6_PROC
|
||||||
#undef HAVE_GETOPT_LONG
|
#define HAVE_GETOPT_LONG
|
||||||
#undef HAVE_ARC4RANDOM
|
#undef HAVE_ARC4RANDOM
|
||||||
#define HAVE_RANDOM
|
#define HAVE_RANDOM
|
||||||
#undef HAVE_DEV_URANDOM
|
#define HAVE_DEV_URANDOM
|
||||||
#undef HAVE_DEV_RANDOM
|
#define HAVE_DEV_RANDOM
|
||||||
#define HAVE_SOCKADDR_SA_LEN
|
#define HAVE_SOCKADDR_SA_LEN
|
||||||
#undef HAVE_PSELECT
|
#undef HAVE_PSELECT
|
||||||
#define HAVE_BPF
|
#define HAVE_BPF
|
||||||
|
|||||||
+74
-62
@@ -18,13 +18,14 @@ void dhcp_init(struct daemon *daemon)
|
|||||||
{
|
{
|
||||||
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
int fd = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
struct sockaddr_in saddr;
|
struct sockaddr_in saddr;
|
||||||
int oneopt = 1, zeroopt = 0;
|
int flags, oneopt = 1, zeroopt = 0;
|
||||||
struct dhcp_config *configs, *cp;
|
struct dhcp_config *configs, *cp;
|
||||||
|
|
||||||
if (fd == -1)
|
if (fd == -1)
|
||||||
die ("cannot create DHCP socket : %s", NULL);
|
die ("cannot create DHCP socket : %s", NULL);
|
||||||
|
|
||||||
if (
|
if ((flags = fcntl(fd, F_GETFL, 0)) == -1 ||
|
||||||
|
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||||
#if defined(IP_PKTINFO)
|
#if defined(IP_PKTINFO)
|
||||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
|
setsockopt(fd, SOL_IP, IP_PKTINFO, &oneopt, sizeof(oneopt)) == -1 ||
|
||||||
#elif defined(IP_RECVIF)
|
#elif defined(IP_RECVIF)
|
||||||
@@ -46,6 +47,8 @@ void dhcp_init(struct daemon *daemon)
|
|||||||
daemon->dhcpfd = fd;
|
daemon->dhcpfd = fd;
|
||||||
|
|
||||||
if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1 ||
|
if ((fd = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP)) == -1 ||
|
||||||
|
(flags = fcntl(fd, F_GETFL, 0)) == -1 ||
|
||||||
|
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||||
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) ||
|
setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &oneopt, sizeof(oneopt)) ||
|
||||||
setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
|
setsockopt(fd, SOL_SOCKET, SO_DONTROUTE, &zeroopt, sizeof(zeroopt)) == -1)
|
||||||
die("cannot create ICMP raw socket: %s.", NULL);
|
die("cannot create ICMP raw socket: %s.", NULL);
|
||||||
@@ -160,7 +163,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
|||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
struct iname *name;
|
struct iname *name;
|
||||||
for (name = daemon->if_names; names->isloop; names = names->next);
|
for (name = daemon->if_names; name->isloop; name = name->next);
|
||||||
strcpy(ifr.ifr_name, name->name);
|
strcpy(ifr.ifr_name, name->name);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -209,9 +212,19 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
|||||||
iface_netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
iface_netmask = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||||
|
|
||||||
if (iface_netmask.s_addr &&
|
if (iface_netmask.s_addr &&
|
||||||
is_same_net(iface_addr, context->start, iface_netmask) &&
|
(is_same_net(iface_addr, context->start, iface_netmask) ||
|
||||||
is_same_net(iface_addr, context->end, iface_netmask))
|
is_same_net(iface_addr, context->end, iface_netmask)))
|
||||||
context->netmask = iface_netmask;
|
{
|
||||||
|
context->netmask = iface_netmask;
|
||||||
|
if (!(is_same_net(iface_addr, context->start, iface_netmask) &&
|
||||||
|
is_same_net(iface_addr, context->end, iface_netmask)))
|
||||||
|
{
|
||||||
|
strcpy(daemon->dhcp_buff, inet_ntoa(context->start));
|
||||||
|
strcpy(daemon->dhcp_buff2, inet_ntoa(context->end));
|
||||||
|
syslog(LOG_WARNING, "DHCP range %s -- %s is not consistent with netmask %s",
|
||||||
|
daemon->dhcp_buff, daemon->dhcp_buff2, inet_ntoa(iface_netmask));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine "default" default routes. These are to this server or the relay agent.
|
/* Determine "default" default routes. These are to this server or the relay agent.
|
||||||
@@ -226,7 +239,8 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
|||||||
{
|
{
|
||||||
if (!iface_broadcast.s_addr && ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) != -1)
|
if (!iface_broadcast.s_addr && ioctl(daemon->dhcpfd, SIOCGIFBRDADDR, &ifr) != -1)
|
||||||
iface_broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
iface_broadcast = ((struct sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||||
if (iface_broadcast.s_addr)
|
if (iface_broadcast.s_addr &&
|
||||||
|
is_same_net(iface_broadcast, context->start, context->netmask))
|
||||||
context->broadcast = iface_broadcast;
|
context->broadcast = iface_broadcast;
|
||||||
else
|
else
|
||||||
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
context->broadcast.s_addr = context->start.s_addr | ~context->netmask.s_addr;
|
||||||
@@ -246,7 +260,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
|||||||
lease_prune(NULL, now); /* lose any expired leases */
|
lease_prune(NULL, now); /* lose any expired leases */
|
||||||
newlen = dhcp_reply(daemon, iface_addr, ifr.ifr_name, sz, now);
|
newlen = dhcp_reply(daemon, iface_addr, ifr.ifr_name, sz, now);
|
||||||
lease_update_file(0, now);
|
lease_update_file(0, now);
|
||||||
lease_update_dns();
|
lease_update_dns(daemon);
|
||||||
|
|
||||||
if (newlen == 0)
|
if (newlen == 0)
|
||||||
return;
|
return;
|
||||||
@@ -272,7 +286,9 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
|||||||
dest.sin_addr = mess->ciaddr;
|
dest.sin_addr = mess->ciaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
sendto(daemon->dhcpfd, mess, newlen, 0, (struct sockaddr *)&dest, sizeof(dest));
|
while(sendto(daemon->dhcpfd, mess, newlen, 0,
|
||||||
|
(struct sockaddr *)&dest, sizeof(dest)) == -1 &&
|
||||||
|
retry_send());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -342,7 +358,7 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
|||||||
iov[0].iov_len = sizeof(struct ether_header);
|
iov[0].iov_len = sizeof(struct ether_header);
|
||||||
iov[1].iov_base = (char *)rawpacket;
|
iov[1].iov_base = (char *)rawpacket;
|
||||||
iov[1].iov_len = ntohs(rawpacket->ip.ip_len);
|
iov[1].iov_len = ntohs(rawpacket->ip.ip_len);
|
||||||
writev(daemon->dhcp_raw_fd, iov, 2);
|
while (writev(daemon->dhcp_raw_fd, iov, 2) == -1 && retry_send());
|
||||||
#else
|
#else
|
||||||
struct sockaddr_ll dest;
|
struct sockaddr_ll dest;
|
||||||
|
|
||||||
@@ -351,9 +367,9 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
|||||||
dest.sll_ifindex = iface_index;
|
dest.sll_ifindex = iface_index;
|
||||||
dest.sll_protocol = htons(ETHERTYPE_IP);
|
dest.sll_protocol = htons(ETHERTYPE_IP);
|
||||||
memcpy(dest.sll_addr, hwdest, ETHER_ADDR_LEN);
|
memcpy(dest.sll_addr, hwdest, ETHER_ADDR_LEN);
|
||||||
sendto(daemon->dhcp_raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len),
|
while (sendto(daemon->dhcp_raw_fd, rawpacket, ntohs(rawpacket->ip.ip_len),
|
||||||
0, (struct sockaddr *)&dest, sizeof(dest));
|
0, (struct sockaddr *)&dest, sizeof(dest)) == -1 &&
|
||||||
|
retry_send());
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,26 +377,23 @@ void dhcp_packet(struct daemon *daemon, time_t now)
|
|||||||
|
|
||||||
int address_available(struct dhcp_context *context, struct in_addr taddr)
|
int address_available(struct dhcp_context *context, struct in_addr taddr)
|
||||||
{
|
{
|
||||||
/* Check is an address is OK for this network, ie
|
/* Check is an address is OK for this network, check all
|
||||||
within allowable range and not in an existing lease */
|
possible ranges. */
|
||||||
|
|
||||||
unsigned int addr, start, end;
|
unsigned int start, end, addr = ntohl(taddr.s_addr);
|
||||||
|
|
||||||
/* static leases only. */
|
for (; context; context = context->current)
|
||||||
if (context->static_only)
|
{
|
||||||
return 0;
|
start = ntohl(context->start.s_addr);
|
||||||
|
end = ntohl(context->end.s_addr);
|
||||||
|
|
||||||
addr = ntohl(taddr.s_addr);
|
if (!context->static_only &&
|
||||||
start = ntohl(context->start.s_addr);
|
addr >= start &&
|
||||||
end = ntohl(context->end.s_addr);
|
addr <= end)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (addr < start)
|
return 0;
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (addr > end)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
|
struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct in_addr addr)
|
||||||
@@ -402,41 +415,40 @@ int address_allocate(struct dhcp_context *context, struct daemon *daemon,
|
|||||||
|
|
||||||
struct in_addr start, addr ;
|
struct in_addr start, addr ;
|
||||||
unsigned int i, j;
|
unsigned int i, j;
|
||||||
|
|
||||||
/* check if no dynamic leases. */
|
|
||||||
if (context->static_only)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
for (; context; context = context->current)
|
||||||
for (j = context->addr_epoch, i = 0; i < ETHER_ADDR_LEN; i++)
|
if (!context->static_only)
|
||||||
j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
|
|
||||||
|
|
||||||
start.s_addr = addr.s_addr =
|
|
||||||
htonl(ntohl(context->start.s_addr) +
|
|
||||||
(j % (1 + ntohl(context->end.s_addr) - ntohl(context->start.s_addr))));
|
|
||||||
|
|
||||||
do {
|
|
||||||
if (!lease_find_by_addr(addr) &&
|
|
||||||
!config_find_by_address(daemon->dhcp_conf, addr))
|
|
||||||
{
|
{
|
||||||
if (icmp_ping(daemon, addr))
|
/* pick a seed based on hwaddr then iterate until we find a free address. */
|
||||||
/* perturb address selection so that we are
|
for (j = context->addr_epoch, i = 0; i < ETHER_ADDR_LEN; i++)
|
||||||
less likely to try this address again. */
|
j += hwaddr[i] + (hwaddr[i] << 8) + (hwaddr[i] << 16);
|
||||||
context->addr_epoch++;
|
|
||||||
else
|
start.s_addr = addr.s_addr =
|
||||||
{
|
htonl(ntohl(context->start.s_addr) +
|
||||||
*addrp = addr;
|
(j % (1 + ntohl(context->end.s_addr) - ntohl(context->start.s_addr))));
|
||||||
return 1;
|
|
||||||
}
|
do {
|
||||||
}
|
if (!lease_find_by_addr(addr) &&
|
||||||
|
!config_find_by_address(daemon->dhcp_conf, addr))
|
||||||
|
{
|
||||||
|
if (icmp_ping(daemon, addr))
|
||||||
|
/* perturb address selection so that we are
|
||||||
|
less likely to try this address again. */
|
||||||
|
context->addr_epoch++;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*addrp = addr;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
|
addr.s_addr = htonl(ntohl(addr.s_addr) + 1);
|
||||||
|
|
||||||
if (addr.s_addr == htonl(ntohl(context->end.s_addr) + 1))
|
if (addr.s_addr == htonl(ntohl(context->end.s_addr) + 1))
|
||||||
addr = context->start;
|
addr = context->start;
|
||||||
|
|
||||||
} while (addr.s_addr != start.s_addr);
|
} while (addr.s_addr != start.s_addr);
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -617,7 +629,7 @@ void dhcp_update_configs(struct dhcp_config *configs)
|
|||||||
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
|
(crec = cache_find_by_name(NULL, config->hostname, 0, F_IPV4)) &&
|
||||||
(crec->flags & F_HOSTS))
|
(crec->flags & F_HOSTS))
|
||||||
{
|
{
|
||||||
config->addr = crec->addr.addr.addr4;
|
config->addr = crec->addr.addr.addr.addr4;
|
||||||
config->flags |= CONFIG_ADDR;
|
config->flags |= CONFIG_ADDR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+50
-44
@@ -30,6 +30,7 @@ int main (int argc, char **argv)
|
|||||||
struct irec *interfaces;
|
struct irec *interfaces;
|
||||||
struct sigaction sigact;
|
struct sigaction sigact;
|
||||||
sigset_t sigmask;
|
sigset_t sigmask;
|
||||||
|
struct iname *if_tmp;
|
||||||
|
|
||||||
sighup = 1; /* init cache the first time through */
|
sighup = 1; /* init cache the first time through */
|
||||||
sigusr1 = 0; /* but don't dump */
|
sigusr1 = 0; /* but don't dump */
|
||||||
@@ -92,7 +93,6 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
if (daemon->options & OPT_NOWILD)
|
if (daemon->options & OPT_NOWILD)
|
||||||
{
|
{
|
||||||
struct iname *if_tmp;
|
|
||||||
daemon->listeners = create_bound_listeners(interfaces, daemon->port);
|
daemon->listeners = create_bound_listeners(interfaces, daemon->port);
|
||||||
|
|
||||||
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||||
@@ -263,6 +263,11 @@ int main (int argc, char **argv)
|
|||||||
if (bind_fallback)
|
if (bind_fallback)
|
||||||
syslog(LOG_WARNING, "setting --bind-interfaces option because of OS limitations");
|
syslog(LOG_WARNING, "setting --bind-interfaces option because of OS limitations");
|
||||||
|
|
||||||
|
if (!(daemon->options & OPT_NOWILD))
|
||||||
|
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
|
||||||
|
if (if_tmp->name && !if_tmp->used)
|
||||||
|
syslog(LOG_WARNING, "warning: interface %s does not currently exist", if_tmp->name);
|
||||||
|
|
||||||
if (daemon->dhcp)
|
if (daemon->dhcp)
|
||||||
{
|
{
|
||||||
struct dhcp_context *dhcp_tmp;
|
struct dhcp_context *dhcp_tmp;
|
||||||
@@ -288,13 +293,12 @@ int main (int argc, char **argv)
|
|||||||
"DHCP, IP range %s -- %s, lease time %s",
|
"DHCP, IP range %s -- %s, lease time %s",
|
||||||
daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), time);
|
daemon->dhcp_buff, inet_ntoa(dhcp_tmp->end), time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_BROKEN_RTC
|
||||||
|
syslog(LOG_INFO, "DHCP, %s will be written every %ds", daemon->lease_file, daemon->min_leasetime/3);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_BROKEN_RTC
|
|
||||||
if (daemon->dhcp)
|
|
||||||
syslog(LOG_INFO, "DHCP, %s will be written every %ds", daemon->lease_file, daemon->min_leasetime/3);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
|
if (!(daemon->options & OPT_DEBUG) && (getuid() == 0 || geteuid() == 0))
|
||||||
syslog(LOG_WARNING, "running as root");
|
syslog(LOG_WARNING, "running as root");
|
||||||
|
|
||||||
@@ -314,7 +318,7 @@ int main (int argc, char **argv)
|
|||||||
dhcp_update_configs(daemon->dhcp_conf);
|
dhcp_update_configs(daemon->dhcp_conf);
|
||||||
lease_update_from_configs(daemon->dhcp_conf, daemon->domain_suffix);
|
lease_update_from_configs(daemon->dhcp_conf, daemon->domain_suffix);
|
||||||
lease_update_file(0, now);
|
lease_update_file(0, now);
|
||||||
lease_update_dns();
|
lease_update_dns(daemon);
|
||||||
}
|
}
|
||||||
if (daemon->resolv_files && (daemon->options & OPT_NO_POLL))
|
if (daemon->resolv_files && (daemon->options & OPT_NO_POLL))
|
||||||
{
|
{
|
||||||
@@ -326,7 +330,7 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
if (sigusr1)
|
if (sigusr1)
|
||||||
{
|
{
|
||||||
dump_cache(daemon->options & (OPT_DEBUG | OPT_LOG), daemon->cachesize);
|
dump_cache(daemon);
|
||||||
sigusr1 = 0;
|
sigusr1 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -379,7 +383,7 @@ int main (int argc, char **argv)
|
|||||||
|
|
||||||
#ifdef HAVE_ISC_READER
|
#ifdef HAVE_ISC_READER
|
||||||
if (daemon->lease_file && !daemon->dhcp)
|
if (daemon->lease_file && !daemon->dhcp)
|
||||||
load_dhcp(daemon->lease_file, daemon->domain_suffix, now, daemon->namebuff);
|
load_dhcp(daemon, now);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!(daemon->options & OPT_NO_POLL))
|
if (!(daemon->options & OPT_NO_POLL))
|
||||||
@@ -638,43 +642,45 @@ int icmp_ping(struct daemon *daemon, struct in_addr addr)
|
|||||||
|
|
||||||
setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
|
setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
|
||||||
|
|
||||||
if (sendto(daemon->dhcp_icmp_fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
|
while (sendto(daemon->dhcp_icmp_fd, (char *)&packet.icmp, sizeof(struct icmp), 0,
|
||||||
(struct sockaddr *)&saddr, sizeof(saddr)) == sizeof(struct icmp))
|
(struct sockaddr *)&saddr, sizeof(saddr)) == -1 &&
|
||||||
for (now = start = dnsmasq_time(daemon->uptime_fd); difftime(now, start) < 3.0;)
|
retry_send());
|
||||||
{
|
|
||||||
struct timeval tv;
|
for (now = start = dnsmasq_time(daemon->uptime_fd); difftime(now, start) < 3.0;)
|
||||||
fd_set rset;
|
{
|
||||||
struct sockaddr_in faddr;
|
struct timeval tv;
|
||||||
int maxfd, len = sizeof(faddr);
|
fd_set rset;
|
||||||
|
struct sockaddr_in faddr;
|
||||||
tv.tv_usec = 250000;
|
int maxfd, len = sizeof(faddr);
|
||||||
tv.tv_sec = 0;
|
|
||||||
|
tv.tv_usec = 250000;
|
||||||
FD_ZERO(&rset);
|
tv.tv_sec = 0;
|
||||||
FD_SET(daemon->dhcp_icmp_fd, &rset);
|
|
||||||
maxfd = set_dns_listeners(daemon, &rset, daemon->dhcp_icmp_fd);
|
FD_ZERO(&rset);
|
||||||
|
FD_SET(daemon->dhcp_icmp_fd, &rset);
|
||||||
|
maxfd = set_dns_listeners(daemon, &rset, daemon->dhcp_icmp_fd);
|
||||||
|
|
||||||
if (select(maxfd+1, &rset, NULL, NULL, &tv) < 0)
|
if (select(maxfd+1, &rset, NULL, NULL, &tv) < 0)
|
||||||
FD_ZERO(&rset);
|
FD_ZERO(&rset);
|
||||||
|
|
||||||
now = dnsmasq_time(daemon->uptime_fd);
|
now = dnsmasq_time(daemon->uptime_fd);
|
||||||
check_dns_listeners(daemon, &rset, now);
|
check_dns_listeners(daemon, &rset, now);
|
||||||
|
|
||||||
if (FD_ISSET(daemon->dhcp_icmp_fd, &rset) &&
|
if (FD_ISSET(daemon->dhcp_icmp_fd, &rset) &&
|
||||||
recvfrom(daemon->dhcp_icmp_fd, &packet, sizeof(packet), 0,
|
recvfrom(daemon->dhcp_icmp_fd, &packet, sizeof(packet), 0,
|
||||||
(struct sockaddr *)&faddr, &len) == sizeof(packet) &&
|
(struct sockaddr *)&faddr, &len) == sizeof(packet) &&
|
||||||
saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
|
saddr.sin_addr.s_addr == faddr.sin_addr.s_addr &&
|
||||||
packet.icmp.icmp_type == ICMP_ECHOREPLY &&
|
packet.icmp.icmp_type == ICMP_ECHOREPLY &&
|
||||||
packet.icmp.icmp_seq == 0 &&
|
packet.icmp.icmp_seq == 0 &&
|
||||||
packet.icmp.icmp_id == id)
|
packet.icmp.icmp_id == id)
|
||||||
{
|
{
|
||||||
gotreply = 1;
|
gotreply = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
opt = 1;
|
opt = 1;
|
||||||
setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
|
setsockopt(daemon->dhcp_icmp_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt));
|
||||||
|
|
||||||
return gotreply;
|
return gotreply;
|
||||||
}
|
}
|
||||||
+53
-21
@@ -95,6 +95,7 @@
|
|||||||
#define OPT_ETHERS 16384
|
#define OPT_ETHERS 16384
|
||||||
#define OPT_RESOLV_DOMAIN 32768
|
#define OPT_RESOLV_DOMAIN 32768
|
||||||
#define OPT_NO_FORK 65536
|
#define OPT_NO_FORK 65536
|
||||||
|
#define OPT_AUTHORITATIVE 131072
|
||||||
|
|
||||||
struct all_addr {
|
struct all_addr {
|
||||||
union {
|
union {
|
||||||
@@ -129,7 +130,14 @@ union bigname {
|
|||||||
struct crec {
|
struct crec {
|
||||||
struct crec *next, *prev, *hash_next;
|
struct crec *next, *prev, *hash_next;
|
||||||
time_t ttd; /* time to die */
|
time_t ttd; /* time to die */
|
||||||
struct all_addr addr;
|
int uid;
|
||||||
|
union {
|
||||||
|
struct all_addr addr;
|
||||||
|
struct {
|
||||||
|
struct crec *cache;
|
||||||
|
int uid;
|
||||||
|
} cname;
|
||||||
|
} addr;
|
||||||
unsigned short flags;
|
unsigned short flags;
|
||||||
union {
|
union {
|
||||||
char sname[SMALLDNAME];
|
char sname[SMALLDNAME];
|
||||||
@@ -139,7 +147,7 @@ struct crec {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define F_IMMORTAL 1
|
#define F_IMMORTAL 1
|
||||||
#define F_CONFIG 2
|
#define F_CONFIG 2
|
||||||
#define F_REVERSE 4
|
#define F_REVERSE 4
|
||||||
#define F_FORWARD 8
|
#define F_FORWARD 8
|
||||||
#define F_DHCP 16
|
#define F_DHCP 16
|
||||||
@@ -152,7 +160,7 @@ struct crec {
|
|||||||
#define F_SERVER 2048
|
#define F_SERVER 2048
|
||||||
#define F_NXDOMAIN 4096
|
#define F_NXDOMAIN 4096
|
||||||
#define F_QUERY 8192
|
#define F_QUERY 8192
|
||||||
#define F_ADDN 16384
|
#define F_CNAME 16384
|
||||||
#define F_NOERR 32768
|
#define F_NOERR 32768
|
||||||
|
|
||||||
/* struct sockaddr is not large enough to hold any address,
|
/* struct sockaddr is not large enough to hold any address,
|
||||||
@@ -227,6 +235,13 @@ struct resolvc {
|
|||||||
char *name;
|
char *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* adn-hosts parms from command-line */
|
||||||
|
struct hostsfile {
|
||||||
|
struct hostsfile *next;
|
||||||
|
char *fname;
|
||||||
|
int index; /* matches to cache entries fro logging */
|
||||||
|
};
|
||||||
|
|
||||||
struct frec {
|
struct frec {
|
||||||
union mysockaddr source;
|
union mysockaddr source;
|
||||||
struct all_addr dest;
|
struct all_addr dest;
|
||||||
@@ -234,6 +249,7 @@ struct frec {
|
|||||||
unsigned int iface;
|
unsigned int iface;
|
||||||
unsigned short orig_id, new_id;
|
unsigned short orig_id, new_id;
|
||||||
int fd;
|
int fd;
|
||||||
|
unsigned int crc;
|
||||||
time_t time;
|
time_t time;
|
||||||
struct frec *next;
|
struct frec *next;
|
||||||
};
|
};
|
||||||
@@ -253,6 +269,10 @@ struct dhcp_netid {
|
|||||||
struct dhcp_netid *next;
|
struct dhcp_netid *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dhcp_netid_list {
|
||||||
|
struct dhcp_netid *list;
|
||||||
|
struct dhcp_netid_list *next;
|
||||||
|
};
|
||||||
struct dhcp_config {
|
struct dhcp_config {
|
||||||
unsigned int flags;
|
unsigned int flags;
|
||||||
int clid_len; /* length of client identifier */
|
int clid_len; /* length of client identifier */
|
||||||
@@ -277,12 +297,19 @@ struct dhcp_config {
|
|||||||
struct dhcp_opt {
|
struct dhcp_opt {
|
||||||
int opt, len, is_addr;
|
int opt, len, is_addr;
|
||||||
unsigned char *val;
|
unsigned char *val;
|
||||||
char *netid;
|
struct dhcp_netid *netid;
|
||||||
struct dhcp_opt *next;
|
struct dhcp_opt *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct dhcp_boot {
|
||||||
|
char *file, *sname;
|
||||||
|
struct in_addr next_server;
|
||||||
|
struct dhcp_netid *netid;
|
||||||
|
struct dhcp_boot *next;
|
||||||
|
};
|
||||||
|
|
||||||
struct dhcp_vendor {
|
struct dhcp_vendor {
|
||||||
int len, is_vendor, used;
|
int len, is_vendor;
|
||||||
char *data;
|
char *data;
|
||||||
struct dhcp_netid netid;
|
struct dhcp_netid netid;
|
||||||
struct dhcp_vendor *next;
|
struct dhcp_vendor *next;
|
||||||
@@ -294,7 +321,7 @@ struct dhcp_context {
|
|||||||
struct in_addr start, end; /* range of available addresses */
|
struct in_addr start, end; /* range of available addresses */
|
||||||
int static_only;
|
int static_only;
|
||||||
struct dhcp_netid netid;
|
struct dhcp_netid netid;
|
||||||
struct dhcp_context *next;
|
struct dhcp_context *next, *current;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef unsigned char u8;
|
typedef unsigned char u8;
|
||||||
@@ -340,14 +367,13 @@ struct daemon {
|
|||||||
int cachesize;
|
int cachesize;
|
||||||
int port, query_port;
|
int port, query_port;
|
||||||
unsigned long local_ttl;
|
unsigned long local_ttl;
|
||||||
char *addn_hosts;
|
struct hostsfile *addn_hosts;
|
||||||
struct dhcp_context *dhcp;
|
struct dhcp_context *dhcp;
|
||||||
struct dhcp_config *dhcp_conf;
|
struct dhcp_config *dhcp_conf;
|
||||||
struct dhcp_opt *dhcp_opts;
|
struct dhcp_opt *dhcp_opts;
|
||||||
struct dhcp_vendor *dhcp_vendors;
|
struct dhcp_vendor *dhcp_vendors;
|
||||||
char *dhcp_file;
|
struct dhcp_boot *boot_config;
|
||||||
char *dhcp_sname;
|
struct dhcp_netid_list *dhcp_ignore;
|
||||||
struct in_addr dhcp_next_server;
|
|
||||||
int dhcp_max;
|
int dhcp_max;
|
||||||
unsigned int min_leasetime;
|
unsigned int min_leasetime;
|
||||||
struct doctor *doctors;
|
struct doctor *doctors;
|
||||||
@@ -369,7 +395,8 @@ struct daemon {
|
|||||||
|
|
||||||
/* cache.c */
|
/* cache.c */
|
||||||
void cache_init(int cachesize, int log);
|
void cache_init(int cachesize, int log);
|
||||||
void log_query(unsigned short flags, char *name, struct all_addr *addr, unsigned short type);
|
void log_query(unsigned short flags, char *name, struct all_addr *addr,
|
||||||
|
unsigned short type, struct hostsfile *addn_hosts, int index);
|
||||||
struct crec *cache_find_by_addr(struct crec *crecp,
|
struct crec *cache_find_by_addr(struct crec *crecp,
|
||||||
struct all_addr *addr, time_t now,
|
struct all_addr *addr, time_t now,
|
||||||
unsigned short prot);
|
unsigned short prot);
|
||||||
@@ -377,12 +404,12 @@ struct crec *cache_find_by_name(struct crec *crecp,
|
|||||||
char *name, time_t now, unsigned short prot);
|
char *name, time_t now, unsigned short prot);
|
||||||
void cache_end_insert(void);
|
void cache_end_insert(void);
|
||||||
void cache_start_insert(void);
|
void cache_start_insert(void);
|
||||||
void cache_insert(char *name, struct all_addr *addr,
|
struct crec *cache_insert(char *name, struct all_addr *addr,
|
||||||
time_t now, unsigned long ttl, unsigned short flags);
|
time_t now, unsigned long ttl, unsigned short flags);
|
||||||
void cache_reload(int opts, char *buff, char *domain_suffix, char *addn_hosts);
|
void cache_reload(int opts, char *buff, char *domain_suffix, struct hostsfile *addn_hosts);
|
||||||
void cache_add_dhcp_entry(char *host_name, struct in_addr *host_address, time_t ttd);
|
void cache_add_dhcp_entry(struct daemon *daemon, char *host_name, struct in_addr *host_address, time_t ttd);
|
||||||
void cache_unhash_dhcp(void);
|
void cache_unhash_dhcp(void);
|
||||||
void dump_cache(int debug, int size);
|
void dump_cache(struct daemon *daemon);
|
||||||
char *cache_get_name(struct crec *crecp);
|
char *cache_get_name(struct crec *crecp);
|
||||||
|
|
||||||
/* rfc1035.c */
|
/* rfc1035.c */
|
||||||
@@ -392,12 +419,16 @@ int setup_reply(HEADER *header, unsigned int qlen,
|
|||||||
struct all_addr *addrp, unsigned short flags,
|
struct all_addr *addrp, unsigned short flags,
|
||||||
unsigned long local_ttl);
|
unsigned long local_ttl);
|
||||||
void extract_addresses(HEADER *header, unsigned int qlen, char *namebuff,
|
void extract_addresses(HEADER *header, unsigned int qlen, char *namebuff,
|
||||||
time_t now, struct doctor *doctors);
|
time_t now, struct daemon *daemon);
|
||||||
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 daemon *daemon, time_t now);
|
int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon *daemon, time_t now);
|
||||||
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);
|
unsigned char *find_pseudoheader(HEADER *header, unsigned int plen,
|
||||||
|
unsigned int *len, unsigned char **p);
|
||||||
|
int check_for_local_domain(char *name, time_t now, struct mx_record *mx);
|
||||||
|
unsigned int questions_crc(HEADER *header, unsigned int plen);
|
||||||
|
int resize_packet(HEADER *header, unsigned int plen,
|
||||||
|
unsigned char *pheader, unsigned int hlen);
|
||||||
|
|
||||||
/* util.c */
|
/* util.c */
|
||||||
unsigned short rand16(void);
|
unsigned short rand16(void);
|
||||||
@@ -413,6 +444,7 @@ int sockaddr_isequal(union mysockaddr *s1, union mysockaddr *s2);
|
|||||||
int hostname_isequal(unsigned char *a, unsigned char *b);
|
int hostname_isequal(unsigned char *a, unsigned char *b);
|
||||||
time_t dnsmasq_time(int fd);
|
time_t dnsmasq_time(int fd);
|
||||||
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
|
||||||
|
int retry_send(void);
|
||||||
|
|
||||||
/* option.c */
|
/* option.c */
|
||||||
struct daemon *read_opts (int argc, char **argv);
|
struct daemon *read_opts (int argc, char **argv);
|
||||||
@@ -448,7 +480,7 @@ struct dhcp_config *config_find_by_address(struct dhcp_config *configs, struct i
|
|||||||
|
|
||||||
/* lease.c */
|
/* lease.c */
|
||||||
void lease_update_file(int force, time_t now);
|
void lease_update_file(int force, time_t now);
|
||||||
void lease_update_dns(void);
|
void lease_update_dns(struct daemon *daemon);
|
||||||
void lease_init(struct daemon *daemon, time_t now);
|
void lease_init(struct daemon *daemon, time_t now);
|
||||||
struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_addr addr);
|
struct dhcp_lease *lease_allocate(unsigned char *clid, int clid_len, struct in_addr addr);
|
||||||
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr);
|
void lease_set_hwaddr(struct dhcp_lease *lease, unsigned char *hwaddr);
|
||||||
@@ -467,6 +499,6 @@ int icmp_ping(struct daemon *daemon, struct in_addr addr);
|
|||||||
|
|
||||||
/* isc.c */
|
/* isc.c */
|
||||||
#ifdef HAVE_ISC_READER
|
#ifdef HAVE_ISC_READER
|
||||||
void load_dhcp(char *file, char *suffix, time_t now, char *hostname);
|
void load_dhcp(struct daemon *daemon, time_t now);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
+201
-154
@@ -19,7 +19,8 @@ static struct frec *frec_list;
|
|||||||
static struct frec *get_new_frec(time_t now);
|
static struct frec *get_new_frec(time_t now);
|
||||||
static struct frec *lookup_frec(unsigned short id);
|
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,
|
||||||
|
unsigned int crc);
|
||||||
static unsigned short get_id(void);
|
static unsigned short get_id(void);
|
||||||
|
|
||||||
/* May be called more than once. */
|
/* May be called more than once. */
|
||||||
@@ -64,58 +65,62 @@ static void send_from(int fd, int nowild, char *packet, int len,
|
|||||||
msg.msg_iov = iov;
|
msg.msg_iov = iov;
|
||||||
msg.msg_iovlen = 1;
|
msg.msg_iovlen = 1;
|
||||||
|
|
||||||
if (!nowild && to->sa.sa_family == AF_INET)
|
if (!nowild)
|
||||||
{
|
{
|
||||||
|
struct cmsghdr *cmptr;
|
||||||
msg.msg_control = &control_u;
|
msg.msg_control = &control_u;
|
||||||
msg.msg_controllen = sizeof(control_u);
|
msg.msg_controllen = sizeof(control_u);
|
||||||
{
|
cmptr = CMSG_FIRSTHDR(&msg);
|
||||||
struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
|
|
||||||
#if defined(IP_PKTINFO)
|
|
||||||
struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
|
|
||||||
pkt->ipi_ifindex = 0;
|
|
||||||
pkt->ipi_spec_dst = source->addr.addr4;
|
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
|
||||||
cmptr->cmsg_level = SOL_IP;
|
|
||||||
cmptr->cmsg_type = IP_PKTINFO;
|
|
||||||
#elif defined(IP_SENDSRCADDR)
|
|
||||||
struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
|
|
||||||
*a = source->addr.addr4;
|
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
|
|
||||||
cmptr->cmsg_level = IPPROTO_IP;
|
|
||||||
cmptr->cmsg_type = IP_SENDSRCADDR;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
if (to->sa.sa_family == AF_INET)
|
||||||
if (to->sa.sa_family == AF_INET6)
|
{
|
||||||
{
|
#if defined(IP_PKTINFO)
|
||||||
msg.msg_control = &control_u;
|
struct in_pktinfo *pkt = (struct in_pktinfo *)CMSG_DATA(cmptr);
|
||||||
msg.msg_controllen = sizeof(control_u);
|
pkt->ipi_ifindex = 0;
|
||||||
{
|
pkt->ipi_spec_dst = source->addr.addr4;
|
||||||
struct cmsghdr *cmptr = CMSG_FIRSTHDR(&msg);
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
|
||||||
struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
|
cmptr->cmsg_level = SOL_IP;
|
||||||
pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
|
cmptr->cmsg_type = IP_PKTINFO;
|
||||||
pkt->ipi6_addr = source->addr.addr6;
|
#elif defined(IP_SENDSRCADDR)
|
||||||
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
|
struct in_addr *a = (struct in_addr *)CMSG_DATA(cmptr);
|
||||||
cmptr->cmsg_type = IPV6_PKTINFO;
|
*a = source->addr.addr4;
|
||||||
cmptr->cmsg_level = IPV6_LEVEL;
|
msg.msg_controllen = cmptr->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
|
||||||
}
|
cmptr->cmsg_level = IPPROTO_IP;
|
||||||
}
|
cmptr->cmsg_type = IP_SENDSRCADDR;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct in6_pktinfo *pkt = (struct in6_pktinfo *)CMSG_DATA(cmptr);
|
||||||
|
pkt->ipi6_ifindex = iface; /* Need iface for IPv6 to handle link-local addrs */
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
/* certain Linux kernels seem to object to setting the source address in the IPv6 stack
|
retry:
|
||||||
by returning EINVAL from sendmsg. In that case, try again without setting the
|
if (sendmsg(fd, &msg, 0) == -1)
|
||||||
source address, since it will nearly alway be correct anyway. IPv6 stinks. */
|
|
||||||
if (sendmsg(fd, &msg, 0) == -1 && errno == EINVAL)
|
|
||||||
{
|
{
|
||||||
msg.msg_controllen = 0;
|
/* certain Linux kernels seem to object to setting the source address in the IPv6 stack
|
||||||
sendmsg(fd, &msg, 0);
|
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 (errno == EINVAL && msg.msg_controllen)
|
||||||
|
{
|
||||||
|
msg.msg_controllen = 0;
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
if (retry_send())
|
||||||
|
goto retry;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned short search_servers(struct daemon *daemon, struct all_addr **addrpp,
|
static unsigned short search_servers(struct daemon *daemon, time_t now, struct all_addr **addrpp,
|
||||||
unsigned short qtype, char *qdomain, int *type, char **domain)
|
unsigned short qtype, char *qdomain, int *type, char **domain)
|
||||||
|
|
||||||
{
|
{
|
||||||
/* If the query ends in the domain in one of our servers, set
|
/* If the query ends in the domain in one of our servers, set
|
||||||
@@ -133,19 +138,23 @@ unsigned short search_servers(struct daemon *daemon, struct all_addr **addrpp,
|
|||||||
{
|
{
|
||||||
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
unsigned short sflag = serv->addr.sa.sa_family == AF_INET ? F_IPV4 : F_IPV6;
|
||||||
*type = SERV_FOR_NODOTS;
|
*type = SERV_FOR_NODOTS;
|
||||||
flags = 0;
|
|
||||||
if (serv->flags & SERV_NO_ADDR)
|
if (serv->flags & SERV_NO_ADDR)
|
||||||
flags = F_NXDOMAIN;
|
flags = F_NXDOMAIN;
|
||||||
else if ((serv->flags & SERV_LITERAL_ADDRESS) && (sflag & qtype))
|
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||||
{
|
{
|
||||||
flags = sflag;
|
if (sflag & qtype)
|
||||||
if (serv->addr.sa.sa_family == AF_INET)
|
{
|
||||||
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
flags = sflag;
|
||||||
|
if (serv->addr.sa.sa_family == AF_INET)
|
||||||
|
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
else if (!flags)
|
||||||
|
flags = F_NOERR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (serv->flags & SERV_HAS_DOMAIN)
|
else if (serv->flags & SERV_HAS_DOMAIN)
|
||||||
{
|
{
|
||||||
@@ -158,34 +167,41 @@ unsigned short search_servers(struct daemon *daemon, struct all_addr **addrpp,
|
|||||||
*type = SERV_HAS_DOMAIN;
|
*type = SERV_HAS_DOMAIN;
|
||||||
*domain = serv->domain;
|
*domain = serv->domain;
|
||||||
matchlen = domainlen;
|
matchlen = domainlen;
|
||||||
flags = 0;
|
|
||||||
if (serv->flags & SERV_NO_ADDR)
|
if (serv->flags & SERV_NO_ADDR)
|
||||||
flags = F_NXDOMAIN;
|
flags = F_NXDOMAIN;
|
||||||
else if ((serv->flags & SERV_LITERAL_ADDRESS) && ((sflag | F_QUERY ) & qtype))
|
else if (serv->flags & SERV_LITERAL_ADDRESS)
|
||||||
{
|
{
|
||||||
flags = qtype;
|
if ((sflag | F_QUERY ) & qtype)
|
||||||
if (serv->addr.sa.sa_family == AF_INET)
|
{
|
||||||
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
flags = qtype;
|
||||||
|
if (serv->addr.sa.sa_family == AF_INET)
|
||||||
|
*addrpp = (struct all_addr *)&serv->addr.in.sin_addr;
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
*addrpp = (struct all_addr *)&serv->addr.in6.sin6_addr;
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
|
else if (!flags)
|
||||||
|
flags = F_NOERR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (flags & ~F_NXDOMAIN) /* flags set here means a literal found */
|
if (flags & ~(F_NOERR | F_NXDOMAIN)) /* flags set here means a literal found */
|
||||||
{
|
{
|
||||||
if (flags & F_QUERY)
|
if (flags & F_QUERY)
|
||||||
log_query(F_CONFIG | F_FORWARD | F_NEG, qdomain, NULL, 0);
|
log_query(F_CONFIG | F_FORWARD | F_NEG, qdomain, NULL, 0, NULL, 0);
|
||||||
else
|
else
|
||||||
log_query(F_CONFIG | F_FORWARD | flags, qdomain, *addrpp, 0);
|
log_query(F_CONFIG | F_FORWARD | flags, qdomain, *addrpp, 0, NULL, 0);
|
||||||
}
|
}
|
||||||
else if (qtype && (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.'))
|
else if (qtype && (daemon->options & OPT_NODOTS_LOCAL) && !strchr(qdomain, '.'))
|
||||||
|
flags = F_NXDOMAIN;
|
||||||
|
|
||||||
|
if (flags == F_NXDOMAIN && check_for_local_domain(qdomain, now, daemon->mxnames))
|
||||||
flags = F_NOERR;
|
flags = F_NOERR;
|
||||||
|
|
||||||
if (flags & (F_NOERR | F_NXDOMAIN))
|
if (flags == F_NXDOMAIN || flags == F_NOERR)
|
||||||
log_query(F_CONFIG | F_FORWARD | F_NEG | qtype | (flags & F_NXDOMAIN), qdomain, NULL, 0);
|
log_query(F_CONFIG | F_FORWARD | F_NEG | qtype | (flags & F_NXDOMAIN), qdomain, NULL, 0, NULL, 0);
|
||||||
|
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
@@ -202,11 +218,12 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
|
|||||||
unsigned short flags = 0;
|
unsigned short flags = 0;
|
||||||
unsigned short gotname = extract_request(header, (unsigned int)plen, daemon->namebuff, NULL);
|
unsigned short gotname = extract_request(header, (unsigned int)plen, daemon->namebuff, NULL);
|
||||||
struct server *start = NULL;
|
struct server *start = NULL;
|
||||||
|
unsigned int crc = questions_crc(header,(unsigned int)plen);
|
||||||
|
|
||||||
/* may be recursion not speced or no servers available. */
|
/* may be recursion not speced or no servers available. */
|
||||||
if (!header->rd || !daemon->servers)
|
if (!header->rd || !daemon->servers)
|
||||||
forward = NULL;
|
forward = NULL;
|
||||||
else if ((forward = lookup_frec_by_sender(ntohs(header->id), udpaddr)))
|
else if ((forward = lookup_frec_by_sender(ntohs(header->id), udpaddr, crc)))
|
||||||
{
|
{
|
||||||
/* retry on existing query, send to all available servers */
|
/* retry on existing query, send to all available servers */
|
||||||
domain = forward->sentto->domain;
|
domain = forward->sentto->domain;
|
||||||
@@ -223,7 +240,7 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (gotname)
|
if (gotname)
|
||||||
flags = search_servers(daemon, &addrp, gotname, daemon->namebuff, &type, &domain);
|
flags = search_servers(daemon, now, &addrp, gotname, daemon->namebuff, &type, &domain);
|
||||||
|
|
||||||
if (!flags && !(forward = get_new_frec(now)))
|
if (!flags && !(forward = get_new_frec(now)))
|
||||||
/* table full - server failure. */
|
/* table full - server failure. */
|
||||||
@@ -249,6 +266,7 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
|
|||||||
forward->new_id = get_id();
|
forward->new_id = get_id();
|
||||||
forward->fd = udpfd;
|
forward->fd = udpfd;
|
||||||
forward->orig_id = ntohs(header->id);
|
forward->orig_id = ntohs(header->id);
|
||||||
|
forward->crc = crc;
|
||||||
header->id = htons(forward->new_id);
|
header->id = htons(forward->new_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -269,22 +287,29 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
|
|||||||
must be NULL also. */
|
must be NULL also. */
|
||||||
|
|
||||||
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)) &&
|
||||||
|
!(start->flags & SERV_LITERAL_ADDRESS))
|
||||||
{
|
{
|
||||||
if (!(start->flags & SERV_LITERAL_ADDRESS) &&
|
if (sendto(start->sfd->fd, (char *)header, plen, 0,
|
||||||
sendto(start->sfd->fd, (char *)header, plen, 0,
|
|
||||||
&start->addr.sa,
|
&start->addr.sa,
|
||||||
sa_len(&start->addr)) != -1)
|
sa_len(&start->addr)) == -1)
|
||||||
|
{
|
||||||
|
if (retry_send())
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if (!gotname)
|
if (!gotname)
|
||||||
strcpy(daemon->namebuff, "query");
|
strcpy(daemon->namebuff, "query");
|
||||||
if (start->addr.sa.sa_family == AF_INET)
|
if (start->addr.sa.sa_family == AF_INET)
|
||||||
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
|
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||||
(struct all_addr *)&start->addr.in.sin_addr, 0);
|
(struct all_addr *)&start->addr.in.sin_addr, 0,
|
||||||
|
NULL, 0);
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
|
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||||
(struct all_addr *)&start->addr.in6.sin6_addr, 0);
|
(struct all_addr *)&start->addr.in6.sin6_addr, 0,
|
||||||
|
NULL, 0);
|
||||||
#endif
|
#endif
|
||||||
forwarded = 1;
|
forwarded = 1;
|
||||||
forward->sentto = start;
|
forward->sentto = start;
|
||||||
@@ -316,20 +341,21 @@ static void forward_query(struct daemon *daemon, int udpfd, union mysockaddr *ud
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
||||||
union mysockaddr *serveraddr, int n)
|
union mysockaddr *serveraddr, unsigned int n)
|
||||||
{
|
{
|
||||||
unsigned char *pheader;
|
unsigned char *pheader, *sizep;
|
||||||
|
unsigned int plen, munged = 0;
|
||||||
|
|
||||||
/* If upstream is advertising a larger UDP packet size
|
/* If upstream is advertising a larger UDP packet size
|
||||||
than we allow, trim it so that we don't get overlarge
|
than we allow, trim it so that we don't get overlarge
|
||||||
requests for the client. */
|
requests for the client. */
|
||||||
|
|
||||||
if ((pheader = find_pseudoheader(header, n)))
|
if ((pheader = find_pseudoheader(header, n, &plen, &sizep)))
|
||||||
{
|
{
|
||||||
unsigned short udpsz;
|
unsigned short udpsz;
|
||||||
unsigned char *psave = pheader;
|
unsigned char *psave = sizep;
|
||||||
|
|
||||||
GETSHORT(udpsz, pheader);
|
GETSHORT(udpsz, sizep);
|
||||||
if (udpsz > daemon->edns_pktsz)
|
if (udpsz > daemon->edns_pktsz)
|
||||||
PUTSHORT(daemon->edns_pktsz, psave);
|
PUTSHORT(daemon->edns_pktsz, psave);
|
||||||
}
|
}
|
||||||
@@ -350,20 +376,47 @@ static int process_reply(struct daemon *daemon, HEADER *header, time_t now,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((header->rcode == NOERROR || header->rcode == NXDOMAIN) && header->opcode == QUERY)
|
if (header->opcode != QUERY || (header->rcode != NOERROR && header->rcode != NXDOMAIN))
|
||||||
|
return n;
|
||||||
|
|
||||||
|
if (daemon->bogus_addr && header->rcode != NXDOMAIN &&
|
||||||
|
check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
|
||||||
{
|
{
|
||||||
if (!(daemon->bogus_addr &&
|
munged = 1;
|
||||||
header->rcode == NOERROR &&
|
header->rcode = NXDOMAIN;
|
||||||
check_for_bogus_wildcard(header, (unsigned int)n, daemon->namebuff, daemon->bogus_addr, now)))
|
header->aa = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (header->rcode == NXDOMAIN &&
|
||||||
|
extract_request(header, n, daemon->namebuff, NULL) &&
|
||||||
|
check_for_local_domain(daemon->namebuff, now, daemon->mxnames))
|
||||||
{
|
{
|
||||||
if (header->rcode == NOERROR && ntohs(header->ancount) != 0)
|
/* if we forwarded a query for a locally known name (because it was for
|
||||||
extract_addresses(header, (unsigned int)n, daemon->namebuff, now, daemon->doctors);
|
an unknown type) and the answer is NXDOMAIN, convert that to NODATA,
|
||||||
else if (!(daemon->options & OPT_NO_NEG))
|
since we know that the domain exists, even if upstream doesn't */
|
||||||
extract_neg_addrs(header, (unsigned int)n, daemon->namebuff, now);
|
munged = 1;
|
||||||
|
header->aa = 1;
|
||||||
|
header->rcode = NOERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extract_addresses(header, n, daemon->namebuff, now, daemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 1;
|
/* do this after extract_addresses. Ensure NODATA reply and remove
|
||||||
|
nameserver info. */
|
||||||
|
|
||||||
|
if (munged)
|
||||||
|
{
|
||||||
|
header->ancount = htons(0);
|
||||||
|
header->nscount = htons(0);
|
||||||
|
header->arcount = htons(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the bogus-nxdomain stuff, doctor and NXDOMAIN->NODATA munging can all elide
|
||||||
|
sections of the packet. Find the new length here and put back pseudoheader
|
||||||
|
if it was removed. */
|
||||||
|
return resize_packet(header, n, pheader, plen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* sets new last_server */
|
/* sets new last_server */
|
||||||
@@ -385,7 +438,9 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
header = (HEADER *)daemon->packet;
|
header = (HEADER *)daemon->packet;
|
||||||
if (n >= (int)sizeof(HEADER) && header->qr && (forward = lookup_frec(ntohs(header->id))))
|
forward = lookup_frec(ntohs(header->id));
|
||||||
|
|
||||||
|
if (n >= (int)sizeof(HEADER) && header->qr && forward)
|
||||||
{
|
{
|
||||||
/* find good server by address if possible, otherwise assume the last one we sent to */
|
/* find good server by address if possible, otherwise assume the last one we sent to */
|
||||||
if ((forward->sentto->flags & SERV_TYPE) == 0)
|
if ((forward->sentto->flags & SERV_TYPE) == 0)
|
||||||
@@ -401,9 +456,10 @@ void reply_query(struct serverfd *sfd, struct daemon *daemon, time_t now)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (process_reply(daemon, header, now, &serveraddr, n))
|
if ((n = process_reply(daemon, header, now, &serveraddr, (unsigned int)n)))
|
||||||
{
|
{
|
||||||
header->id = htons(forward->orig_id);
|
header->id = htons(forward->orig_id);
|
||||||
|
header->ra = 1; /* recursion if available */
|
||||||
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, n,
|
send_from(forward->fd, daemon->options & OPT_NOWILD, daemon->packet, n,
|
||||||
&forward->source, &forward->dest, forward->iface);
|
&forward->source, &forward->dest, forward->iface);
|
||||||
forward->new_id = 0; /* cancel */
|
forward->new_id = 0; /* cancel */
|
||||||
@@ -418,7 +474,6 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
|||||||
unsigned short type;
|
unsigned short type;
|
||||||
struct iname *tmp;
|
struct iname *tmp;
|
||||||
struct all_addr dst_addr;
|
struct all_addr dst_addr;
|
||||||
int check_dst = !(daemon->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;
|
||||||
@@ -450,57 +505,55 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
|||||||
if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
|
if ((n = recvmsg(listen->fd, &msg, 0)) == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
source_addr.sa.sa_family = listen->family;
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
if (listen->family == AF_INET6)
|
|
||||||
{
|
|
||||||
check_dst = 1;
|
|
||||||
source_addr.in6.sin6_flowinfo = htonl(0);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (check_dst && msg.msg_controllen < sizeof(struct cmsghdr))
|
|
||||||
return;
|
|
||||||
|
|
||||||
#if defined(IP_PKTINFO)
|
|
||||||
if (check_dst && listen->family == AF_INET)
|
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
|
||||||
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
|
||||||
{
|
|
||||||
dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
|
|
||||||
if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
|
|
||||||
}
|
|
||||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
|
||||||
if (check_dst && listen->family == AF_INET)
|
|
||||||
{
|
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
|
||||||
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
|
||||||
dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
|
|
||||||
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
|
||||||
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
if (listen->family == AF_INET6)
|
|
||||||
{
|
|
||||||
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
|
||||||
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
|
|
||||||
{
|
|
||||||
dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
|
|
||||||
if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (n < (int)sizeof(HEADER) || header->qr)
|
if (n < (int)sizeof(HEADER) || header->qr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* enforce available interface configuration */
|
source_addr.sa.sa_family = listen->family;
|
||||||
if (check_dst)
|
#ifdef HAVE_IPV6
|
||||||
|
if (listen->family == AF_INET6)
|
||||||
|
source_addr.in6.sin6_flowinfo = htonl(0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!(daemon->options & OPT_NOWILD))
|
||||||
{
|
{
|
||||||
struct ifreq ifr;
|
struct ifreq ifr;
|
||||||
|
|
||||||
|
if (msg.msg_controllen < sizeof(struct cmsghdr))
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if defined(IP_PKTINFO)
|
||||||
|
if (listen->family == AF_INET)
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
|
if (cmptr->cmsg_level == SOL_IP && cmptr->cmsg_type == IP_PKTINFO)
|
||||||
|
{
|
||||||
|
dst_addr.addr.addr4 = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_spec_dst;
|
||||||
|
if_index = ((struct in_pktinfo *)CMSG_DATA(cmptr))->ipi_ifindex;
|
||||||
|
}
|
||||||
|
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||||
|
if (listen->family == AF_INET)
|
||||||
|
{
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
|
if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR)
|
||||||
|
dst_addr.addr.addr4 = *((struct in_addr *)CMSG_DATA(cmptr));
|
||||||
|
else if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVIF)
|
||||||
|
if_index = ((struct sockaddr_dl *)CMSG_DATA(cmptr))->sdl_index;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_IPV6
|
||||||
|
if (listen->family == AF_INET6)
|
||||||
|
{
|
||||||
|
for (cmptr = CMSG_FIRSTHDR(&msg); cmptr; cmptr = CMSG_NXTHDR(&msg, cmptr))
|
||||||
|
if (cmptr->cmsg_level == IPV6_LEVEL && cmptr->cmsg_type == IPV6_PKTINFO)
|
||||||
|
{
|
||||||
|
dst_addr.addr.addr6 = ((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_addr;
|
||||||
|
if_index =((struct in6_pktinfo *)CMSG_DATA(cmptr))->ipi6_ifindex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* enforce available interface configuration */
|
||||||
|
|
||||||
if (if_index == 0)
|
if (if_index == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -549,11 +602,11 @@ void receive_query(struct listener *listen, struct daemon *daemon, time_t now)
|
|||||||
{
|
{
|
||||||
if (listen->family == AF_INET)
|
if (listen->family == AF_INET)
|
||||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||||
(struct all_addr *)&source_addr.in.sin_addr, type);
|
(struct all_addr *)&source_addr.in.sin_addr, type, NULL, 0);
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||||
(struct all_addr *)&source_addr.in6.sin6_addr, type);
|
(struct all_addr *)&source_addr.in6.sin6_addr, type, NULL, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -581,16 +634,8 @@ static int read_write(int fd, char *packet, int size, int rw)
|
|||||||
return 0;
|
return 0;
|
||||||
else if (n == -1)
|
else if (n == -1)
|
||||||
{
|
{
|
||||||
if (errno == EINTR)
|
if (retry_send())
|
||||||
goto retry;
|
goto retry;
|
||||||
else if (errno == EAGAIN)
|
|
||||||
{
|
|
||||||
struct timespec waiter;
|
|
||||||
waiter.tv_sec = 0;
|
|
||||||
waiter.tv_nsec = 10000;
|
|
||||||
nanosleep(&waiter, NULL);
|
|
||||||
goto retry;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -634,11 +679,11 @@ char *tcp_request(struct daemon *daemon, int confd, time_t now)
|
|||||||
{
|
{
|
||||||
if (peer_addr.sa.sa_family == AF_INET)
|
if (peer_addr.sa.sa_family == AF_INET)
|
||||||
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||||
(struct all_addr *)&peer_addr.in.sin_addr, qtype);
|
(struct all_addr *)&peer_addr.in.sin_addr, qtype, NULL, 0);
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
log_query(F_QUERY | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||||
(struct all_addr *)&peer_addr.in6.sin6_addr, qtype);
|
(struct all_addr *)&peer_addr.in6.sin6_addr, qtype, NULL, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -654,7 +699,7 @@ char *tcp_request(struct daemon *daemon, int confd, time_t now)
|
|||||||
char *domain = NULL;
|
char *domain = NULL;
|
||||||
|
|
||||||
if (gotname)
|
if (gotname)
|
||||||
flags = search_servers(daemon, &addrp, gotname, daemon->namebuff, &type, &domain);
|
flags = search_servers(daemon, now, &addrp, gotname, daemon->namebuff, &type, &domain);
|
||||||
|
|
||||||
if (type != 0 || (daemon->options & OPT_ORDER) || !daemon->last_server)
|
if (type != 0 || (daemon->options & OPT_ORDER) || !daemon->last_server)
|
||||||
last_server = daemon->servers;
|
last_server = daemon->servers;
|
||||||
@@ -719,17 +764,17 @@ char *tcp_request(struct daemon *daemon, int confd, time_t now)
|
|||||||
strcpy(daemon->namebuff, "query");
|
strcpy(daemon->namebuff, "query");
|
||||||
if (last_server->addr.sa.sa_family == AF_INET)
|
if (last_server->addr.sa.sa_family == AF_INET)
|
||||||
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
|
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
|
||||||
(struct all_addr *)&last_server->addr.in.sin_addr, 0);
|
(struct all_addr *)&last_server->addr.in.sin_addr, 0, NULL, 0);
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else
|
else
|
||||||
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
|
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
|
||||||
(struct all_addr *)&last_server->addr.in6.sin6_addr, 0);
|
(struct all_addr *)&last_server->addr.in6.sin6_addr, 0, NULL, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* There's no point in updating the cache, since this process will exit and
|
/* 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
|
lose the information after one query. We make this call for the alias and
|
||||||
bogus-nxdomain side-effects. */
|
bogus-nxdomain side-effects. */
|
||||||
process_reply(daemon, header, now, &last_server->addr, m);
|
m = process_reply(daemon, header, now, &last_server->addr, (unsigned int)m);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -813,13 +858,15 @@ 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,
|
||||||
|
unsigned int crc)
|
||||||
{
|
{
|
||||||
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 &&
|
||||||
f->orig_id == id &&
|
f->orig_id == id &&
|
||||||
|
f->crc == crc &&
|
||||||
sockaddr_isequal(&f->source, addr))
|
sockaddr_isequal(&f->source, addr))
|
||||||
return f;
|
return f;
|
||||||
|
|
||||||
|
|||||||
@@ -55,8 +55,9 @@ static int next_token (char *token, int buffsize, FILE * fp)
|
|||||||
return count ? 1 : 0;
|
return count ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
void load_dhcp(struct daemon *daemon, time_t now)
|
||||||
{
|
{
|
||||||
|
char *hostname = daemon->namebuff;
|
||||||
char token[MAXTOK], *dot;
|
char token[MAXTOK], *dot;
|
||||||
struct in_addr host_address;
|
struct in_addr host_address;
|
||||||
time_t ttd, tts;
|
time_t ttd, tts;
|
||||||
@@ -64,10 +65,10 @@ void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
|||||||
struct isc_lease *lease, *tmp, **up;
|
struct isc_lease *lease, *tmp, **up;
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
|
|
||||||
if (stat(file, &statbuf) == -1)
|
if (stat(daemon->lease_file, &statbuf) == -1)
|
||||||
{
|
{
|
||||||
if (!logged_lease)
|
if (!logged_lease)
|
||||||
syslog(LOG_WARNING, "failed to access %s: %m", file);
|
syslog(LOG_WARNING, "failed to access %s: %m", daemon->lease_file);
|
||||||
logged_lease = 1;
|
logged_lease = 1;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -81,13 +82,13 @@ void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
|||||||
lease_file_size = statbuf.st_size;
|
lease_file_size = statbuf.st_size;
|
||||||
lease_file_inode = statbuf.st_ino;
|
lease_file_inode = statbuf.st_ino;
|
||||||
|
|
||||||
if (!(fp = fopen (file, "r")))
|
if (!(fp = fopen (daemon->lease_file, "r")))
|
||||||
{
|
{
|
||||||
syslog (LOG_ERR, "failed to load %s: %m", file);
|
syslog (LOG_ERR, "failed to load %s: %m", daemon->lease_file);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
syslog (LOG_INFO, "reading %s", file);
|
syslog (LOG_INFO, "reading %s", daemon->lease_file);
|
||||||
|
|
||||||
while ((next_token(token, MAXTOK, fp)))
|
while ((next_token(token, MAXTOK, fp)))
|
||||||
{
|
{
|
||||||
@@ -109,7 +110,7 @@ void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
|||||||
if (!canonicalise(hostname))
|
if (!canonicalise(hostname))
|
||||||
{
|
{
|
||||||
*hostname = 0;
|
*hostname = 0;
|
||||||
syslog(LOG_ERR, "bad name in %s", file);
|
syslog(LOG_ERR, "bad name in %s", daemon->lease_file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((strcmp(token, "ends") == 0) ||
|
else if ((strcmp(token, "ends") == 0) ||
|
||||||
@@ -168,7 +169,7 @@ void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
|||||||
|
|
||||||
if ((dot = strchr(hostname, '.')))
|
if ((dot = strchr(hostname, '.')))
|
||||||
{
|
{
|
||||||
if (!suffix || hostname_isequal(dot+1, suffix))
|
if (!daemon->domain_suffix || hostname_isequal(dot+1, daemon->domain_suffix))
|
||||||
{
|
{
|
||||||
syslog(LOG_WARNING,
|
syslog(LOG_WARNING,
|
||||||
"Ignoring DHCP lease for %s because it has an illegal domain part",
|
"Ignoring DHCP lease for %s because it has an illegal domain part",
|
||||||
@@ -198,11 +199,12 @@ void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
|||||||
{
|
{
|
||||||
leases = lease;
|
leases = lease;
|
||||||
strcpy(lease->name, hostname);
|
strcpy(lease->name, hostname);
|
||||||
if (suffix && (lease->fqdn = malloc(strlen(hostname) + strlen(suffix) + 2)))
|
if (daemon->domain_suffix &&
|
||||||
|
(lease->fqdn = malloc(strlen(hostname) + strlen(daemon->domain_suffix) + 2)))
|
||||||
{
|
{
|
||||||
strcpy(lease->fqdn, hostname);
|
strcpy(lease->fqdn, hostname);
|
||||||
strcat(lease->fqdn, ".");
|
strcat(lease->fqdn, ".");
|
||||||
strcat(lease->fqdn, suffix);
|
strcat(lease->fqdn, daemon->domain_suffix);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -235,8 +237,8 @@ void load_dhcp(char *file, char *suffix, time_t now, char *hostname)
|
|||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
{
|
{
|
||||||
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
|
cache_add_dhcp_entry(daemon, lease->fqdn, &lease->addr, lease->expires);
|
||||||
cache_add_dhcp_entry(lease->name, &lease->addr, lease->expires);
|
cache_add_dhcp_entry(daemon, lease->name, &lease->addr, lease->expires);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-3
@@ -167,7 +167,7 @@ void lease_update_file(int force, time_t now)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void lease_update_dns(void)
|
void lease_update_dns(struct daemon *daemon)
|
||||||
{
|
{
|
||||||
struct dhcp_lease *lease;
|
struct dhcp_lease *lease;
|
||||||
|
|
||||||
@@ -177,8 +177,8 @@ void lease_update_dns(void)
|
|||||||
|
|
||||||
for (lease = leases; lease; lease = lease->next)
|
for (lease = leases; lease; lease = lease->next)
|
||||||
{
|
{
|
||||||
cache_add_dhcp_entry(lease->fqdn, &lease->addr, lease->expires);
|
cache_add_dhcp_entry(daemon, lease->fqdn, &lease->addr, lease->expires);
|
||||||
cache_add_dhcp_entry(lease->hostname, &lease->addr, lease->expires);
|
cache_add_dhcp_entry(daemon, lease->hostname, &lease->addr, lease->expires);
|
||||||
}
|
}
|
||||||
|
|
||||||
dns_dirty = 0;
|
dns_dirty = 0;
|
||||||
|
|||||||
+39
-27
@@ -256,6 +256,8 @@ static int create_ipv6_listener(struct listener **link, int port)
|
|||||||
setsockopt(tcpfd, 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(fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||||
setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
setsockopt(tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||||
|
(flags = fcntl(fd, F_GETFL, 0)) == -1 ||
|
||||||
|
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||||
(flags = fcntl(tcpfd, F_GETFL, 0)) == -1 ||
|
(flags = fcntl(tcpfd, F_GETFL, 0)) == -1 ||
|
||||||
fcntl(tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
fcntl(tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||||
#ifdef IPV6_RECVPKTINFO
|
#ifdef IPV6_RECVPKTINFO
|
||||||
@@ -321,6 +323,8 @@ struct listener *create_wildcard_listeners(int port)
|
|||||||
!create_ipv6_listener(&l6, port) ||
|
!create_ipv6_listener(&l6, port) ||
|
||||||
#endif
|
#endif
|
||||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
|
(flags = fcntl(fd, F_GETFL, 0)) == -1 ||
|
||||||
|
fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||||
#if defined(IP_PKTINFO)
|
#if defined(IP_PKTINFO)
|
||||||
setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
setsockopt(fd, SOL_IP, IP_PKTINFO, &opt, sizeof(opt)) == -1 ||
|
||||||
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
#elif defined(IP_RECVDSTADDR) && defined(IP_RECVIF)
|
||||||
@@ -352,32 +356,37 @@ struct listener *create_bound_listeners(struct irec *interfaces, int port)
|
|||||||
struct irec *iface;
|
struct irec *iface;
|
||||||
int flags = port, 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));
|
||||||
struct listener *new = safe_malloc(sizeof(struct listener));
|
new->family = iface->addr.sa.sa_family;
|
||||||
new->family = iface->addr.sa.sa_family;
|
new->next = listeners;
|
||||||
new->next = listeners;
|
listeners = new;
|
||||||
listeners = new;
|
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
|
||||||
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
|
(new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
|
||||||
(new->fd = socket(iface->addr.sa.sa_family, SOCK_DGRAM, 0)) == -1 ||
|
setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
setsockopt(new->fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
||||||
setsockopt(new->tcpfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1 ||
|
/* See Stevens 16.6 */
|
||||||
/* See Stevens 16.6 */
|
(flags = fcntl(new->tcpfd, F_GETFL, 0)) == -1 ||
|
||||||
(flags = fcntl(new->tcpfd, F_GETFL, 0)) == -1 ||
|
fcntl(new->tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
||||||
fcntl(new->tcpfd, F_SETFL, flags | O_NONBLOCK) == -1 ||
|
(flags = fcntl(new->fd, F_GETFL, 0)) == -1 ||
|
||||||
bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
|
fcntl(new->fd, F_SETFL, flags | O_NONBLOCK) == -1)
|
||||||
bind(new->fd, &iface->addr.sa, sa_len(&iface->addr)) == -1 ||
|
die("failed to create listening socket: %s", NULL);
|
||||||
listen(new->tcpfd, 5) == -1)
|
|
||||||
die("failed to to create listening socket: %s", NULL);
|
#ifdef HAVE_IPV6
|
||||||
}
|
if (iface->addr.sa.sa_family == AF_INET6)
|
||||||
|
{
|
||||||
|
if (setsockopt(new->fd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1 ||
|
||||||
|
setsockopt(new->tcpfd, IPV6_LEVEL, IPV6_V6ONLY, &opt, sizeof(opt)) == -1)
|
||||||
|
die("failed to set IPV6 options on listening socket: %s", NULL);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (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 bind listening socket: %s", NULL);
|
||||||
|
}
|
||||||
|
|
||||||
return listeners;
|
return listeners;
|
||||||
}
|
}
|
||||||
@@ -385,7 +394,8 @@ struct listener *create_bound_listeners(struct irec *interfaces, int port)
|
|||||||
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;
|
||||||
|
int flags;
|
||||||
|
|
||||||
/* may have a suitable one already */
|
/* may have a suitable one already */
|
||||||
for (sfd = *sfds; sfd; sfd = sfd->next )
|
for (sfd = *sfds; sfd; sfd = sfd->next )
|
||||||
if (sockaddr_isequal(&sfd->source_addr, addr))
|
if (sockaddr_isequal(&sfd->source_addr, addr))
|
||||||
@@ -402,7 +412,9 @@ struct serverfd *allocate_sfd(union mysockaddr *addr, struct serverfd **sfds)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bind(sfd->fd, (struct sockaddr *)addr, sa_len(addr)) == -1)
|
if (bind(sfd->fd, (struct sockaddr *)addr, sa_len(addr)) == -1 ||
|
||||||
|
(flags = fcntl(sfd->fd, F_GETFL, 0)) == -1 ||
|
||||||
|
fcntl(sfd->fd, F_SETFL, flags | O_NONBLOCK) == -1)
|
||||||
{
|
{
|
||||||
int errsave = errno; /* save error from bind. */
|
int errsave = errno; /* save error from bind. */
|
||||||
close(sfd->fd);
|
close(sfd->fd);
|
||||||
|
|||||||
+329
-159
@@ -21,7 +21,7 @@ struct myoption {
|
|||||||
int val;
|
int val;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define OPTSTRING "ZDNLERzowefnbvhdkqr: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:"
|
#define OPTSTRING "ZDNLERKzowefnbvhdkqr: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:J:"
|
||||||
|
|
||||||
static struct myoption opts[] = {
|
static struct myoption opts[] = {
|
||||||
{"version", 0, 0, 'v'},
|
{"version", 0, 0, 'v'},
|
||||||
@@ -72,8 +72,10 @@ 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'},
|
||||||
|
{"dhcp-ignore", 1, 0, 'J'},
|
||||||
{"edns-packet-max", 1, 0, 'P'},
|
{"edns-packet-max", 1, 0, 'P'},
|
||||||
{"keep-in-foreground", 0, 0, 'k'},
|
{"keep-in-foreground", 0, 0, 'k'},
|
||||||
|
{"dhcp-authoritative", 0, 0, 'K'},
|
||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -91,6 +93,7 @@ static struct optflags optmap[] = {
|
|||||||
{ 'n', OPT_NO_POLL },
|
{ 'n', OPT_NO_POLL },
|
||||||
{ 'd', OPT_DEBUG },
|
{ 'd', OPT_DEBUG },
|
||||||
{ 'k', OPT_NO_FORK },
|
{ 'k', OPT_NO_FORK },
|
||||||
|
{ 'K', OPT_AUTHORITATIVE },
|
||||||
{ 'o', OPT_ORDER },
|
{ 'o', OPT_ORDER },
|
||||||
{ 'R', OPT_NO_RESOLV },
|
{ 'R', OPT_NO_RESOLV },
|
||||||
{ 'E', OPT_EXPAND },
|
{ 'E', OPT_EXPAND },
|
||||||
@@ -105,8 +108,11 @@ static struct optflags optmap[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static char *usage =
|
static char *usage =
|
||||||
"Usage: dnsmasq [options]\n"
|
"Usage: dnsmasq [options]\n\n"
|
||||||
"\nValid options are :\n"
|
#ifndef HAVE_GETOPT_LONG
|
||||||
|
"Use short options only on the command line.\n"
|
||||||
|
#endif
|
||||||
|
"Valid options are :\n"
|
||||||
"-a, --listen-address=ipaddr Specify local address(es) to listen on.\n"
|
"-a, --listen-address=ipaddr Specify local address(es) to listen on.\n"
|
||||||
"-A, --address=/domain/ipaddr Return ipaddr for all hosts in specified domains.\n"
|
"-A, --address=/domain/ipaddr Return ipaddr for all hosts in specified domains.\n"
|
||||||
"-b, --bogus-priv Fake reverse lookups for RFC1918 private address ranges.\n"
|
"-b, --bogus-priv Fake reverse lookups for RFC1918 private address ranges.\n"
|
||||||
@@ -126,7 +132,9 @@ static char *usage =
|
|||||||
"-i, --interface=interface Specify interface(s) to listen on.\n"
|
"-i, --interface=interface Specify interface(s) to listen on.\n"
|
||||||
"-I, --except-interface=int Specify interface(s) NOT to listen on.\n"
|
"-I, --except-interface=int Specify interface(s) NOT to listen on.\n"
|
||||||
"-j, --dhcp-userclass=<id>,<class> Map DHCP user class to option set.\n"
|
"-j, --dhcp-userclass=<id>,<class> Map DHCP user class to option set.\n"
|
||||||
|
"-J, --dhcp-ignore=<id> Don't do DHCP for hosts in option set.\n"
|
||||||
"-k, --keep-in-foreground Do NOT fork into the background, do NOT run in debug mode.\n"
|
"-k, --keep-in-foreground Do NOT fork into the background, do NOT run in debug mode.\n"
|
||||||
|
"-K, --dhcp-authoritative Assume we are the only DHCP server on the local network.\n"
|
||||||
"-l, --dhcp-leasefile=path Specify where to store DHCP leases (defaults to " LEASEFILE ").\n"
|
"-l, --dhcp-leasefile=path Specify where to store DHCP leases (defaults to " LEASEFILE ").\n"
|
||||||
"-L, --localmx Return MX records for local hosts.\n"
|
"-L, --localmx Return MX records for local hosts.\n"
|
||||||
"-m, --mx-host=host_name Specify the MX name to reply to.\n"
|
"-m, --mx-host=host_name Specify the MX name to reply to.\n"
|
||||||
@@ -161,11 +169,11 @@ static char *usage =
|
|||||||
struct daemon *read_opts (int argc, char **argv)
|
struct daemon *read_opts (int argc, char **argv)
|
||||||
{
|
{
|
||||||
struct daemon *daemon = safe_malloc(sizeof(struct daemon));
|
struct daemon *daemon = safe_malloc(sizeof(struct daemon));
|
||||||
char *buff = safe_malloc(MAXDNAME);
|
char *problem = NULL, *buff = safe_malloc(MAXDNAME);
|
||||||
int option = 0, i;
|
int option = 0, i;
|
||||||
FILE *file_save = NULL, *f = NULL;
|
FILE *file_save = NULL, *f = NULL;
|
||||||
char *file_name_save = NULL, *conffile = CONFFILE;
|
char *comma, *file_name_save = NULL, *conffile = CONFFILE;
|
||||||
int conffile_set = 0;
|
int hosts_index = 1, conffile_set = 0;
|
||||||
int line_save = 0, lineno = 0;
|
int line_save = 0, lineno = 0;
|
||||||
opterr = 0;
|
opterr = 0;
|
||||||
|
|
||||||
@@ -187,6 +195,8 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
problem = NULL;
|
||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
#ifdef HAVE_GETOPT_LONG
|
#ifdef HAVE_GETOPT_LONG
|
||||||
option = getopt_long(argc, argv, OPTSTRING, (struct option *)opts, NULL);
|
option = getopt_long(argc, argv, OPTSTRING, (struct option *)opts, NULL);
|
||||||
@@ -302,7 +312,7 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
complain(buff, NULL);
|
complain(buff, NULL);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (option)
|
switch (option)
|
||||||
{
|
{
|
||||||
case 'C':
|
case 'C':
|
||||||
@@ -362,11 +372,13 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
{
|
{
|
||||||
char *comma = strchr(optarg, ',');
|
if ((comma = strchr(optarg, ',')))
|
||||||
if (comma)
|
|
||||||
*(comma++) = 0;
|
*(comma++) = 0;
|
||||||
if (!canonicalise(optarg) || (comma && !canonicalise(comma)))
|
if (!canonicalise(optarg) || (comma && !canonicalise(comma)))
|
||||||
option = '?';
|
{
|
||||||
|
option = '?';
|
||||||
|
problem = "bad MX name";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
struct mx_record *new = safe_malloc(sizeof(struct mx_record));
|
struct mx_record *new = safe_malloc(sizeof(struct mx_record));
|
||||||
@@ -380,7 +392,10 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
|
|
||||||
case 't':
|
case 't':
|
||||||
if (!canonicalise(optarg))
|
if (!canonicalise(optarg))
|
||||||
option = '?';
|
{
|
||||||
|
option = '?';
|
||||||
|
problem = "bad MX target";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
daemon->mxtarget = safe_string_alloc(optarg);
|
daemon->mxtarget = safe_string_alloc(optarg);
|
||||||
break;
|
break;
|
||||||
@@ -390,12 +405,15 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'H':
|
case 'H':
|
||||||
if (daemon->addn_hosts)
|
{
|
||||||
option = '?';
|
struct hostsfile *new = safe_malloc(sizeof(struct hostsfile));
|
||||||
else
|
new->fname = safe_string_alloc(optarg);
|
||||||
daemon->addn_hosts = safe_string_alloc(optarg);
|
new->index = hosts_index++;
|
||||||
break;
|
new->next = daemon->addn_hosts;
|
||||||
|
daemon->addn_hosts = new;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
if (strcmp (optarg, "#") == 0)
|
if (strcmp (optarg, "#") == 0)
|
||||||
daemon->options |= OPT_RESOLV_DOMAIN;
|
daemon->options |= OPT_RESOLV_DOMAIN;
|
||||||
@@ -414,8 +432,10 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
{
|
do {
|
||||||
struct iname *new = safe_malloc(sizeof(struct iname));
|
struct iname *new = safe_malloc(sizeof(struct iname));
|
||||||
|
if ((comma = strchr(optarg, ',')))
|
||||||
|
*comma++ = 0;
|
||||||
new->next = daemon->if_names;
|
new->next = daemon->if_names;
|
||||||
daemon->if_names = new;
|
daemon->if_names = new;
|
||||||
/* new->name may be NULL if someone does
|
/* new->name may be NULL if someone does
|
||||||
@@ -424,20 +444,24 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
new->isloop = new->used = 0;
|
new->isloop = new->used = 0;
|
||||||
if (strchr(optarg, ':'))
|
if (strchr(optarg, ':'))
|
||||||
daemon->options |= OPT_NOWILD;
|
daemon->options |= OPT_NOWILD;
|
||||||
break;
|
optarg = comma;
|
||||||
}
|
} while (optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'I':
|
case 'I':
|
||||||
{
|
do {
|
||||||
struct iname *new = safe_malloc(sizeof(struct iname));
|
struct iname *new = safe_malloc(sizeof(struct iname));
|
||||||
|
if ((comma = strchr(optarg, ',')))
|
||||||
|
*comma++ = 0;
|
||||||
new->next = daemon->if_except;
|
new->next = daemon->if_except;
|
||||||
daemon->if_except = new;
|
daemon->if_except = new;
|
||||||
new->name = safe_string_alloc(optarg);
|
new->name = safe_string_alloc(optarg);
|
||||||
if (strchr(optarg, ':'))
|
if (strchr(optarg, ':'))
|
||||||
daemon->options |= OPT_NOWILD;
|
daemon->options |= OPT_NOWILD;
|
||||||
break;
|
optarg = comma;
|
||||||
}
|
} while (optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'B':
|
case 'B':
|
||||||
{
|
{
|
||||||
struct in_addr addr;
|
struct in_addr addr;
|
||||||
@@ -563,7 +587,10 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
{
|
{
|
||||||
*portno = 0;
|
*portno = 0;
|
||||||
if (!atoi_check(portno+1, &source_port))
|
if (!atoi_check(portno+1, &source_port))
|
||||||
option = '?';
|
{
|
||||||
|
option = '?';
|
||||||
|
problem = "bad port";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -571,7 +598,10 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
{
|
{
|
||||||
*portno = 0;
|
*portno = 0;
|
||||||
if (!atoi_check(portno+1, &serv_port))
|
if (!atoi_check(portno+1, &serv_port))
|
||||||
option = '?';
|
{
|
||||||
|
option = '?';
|
||||||
|
problem = "bad port";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
@@ -705,7 +735,7 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
case 'F':
|
case 'F':
|
||||||
{
|
{
|
||||||
int k, leasepos = 2;
|
int k, leasepos = 2;
|
||||||
char *cp, *comma, *a[5] = { NULL, NULL, NULL, NULL, NULL };
|
char *cp, *a[5] = { NULL, NULL, NULL, NULL, NULL };
|
||||||
struct dhcp_context *new = safe_malloc(sizeof(struct dhcp_context));
|
struct dhcp_context *new = safe_malloc(sizeof(struct dhcp_context));
|
||||||
|
|
||||||
new->next = daemon->dhcp;
|
new->next = daemon->dhcp;
|
||||||
@@ -717,6 +747,8 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
new->netid.net = NULL;
|
new->netid.net = NULL;
|
||||||
new->static_only = 0;
|
new->static_only = 0;
|
||||||
|
|
||||||
|
problem = "bad dhcp-range";
|
||||||
|
|
||||||
for (cp = optarg; *cp; cp++)
|
for (cp = optarg; *cp; cp++)
|
||||||
if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
|
if (!(*cp == ' ' || *cp == '.' || (*cp >='0' && *cp <= '9')))
|
||||||
break;
|
break;
|
||||||
@@ -755,6 +787,17 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
new->end = tmp;
|
new->end = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (option != '?' && k >= 3 && strchr(a[2], '.') &&
|
||||||
|
((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
|
||||||
|
{
|
||||||
|
leasepos = 3;
|
||||||
|
if (!is_same_net(new->start, new->end, new->netmask))
|
||||||
|
{
|
||||||
|
problem = "inconsistent DHCP range";
|
||||||
|
option = '?';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (option == '?')
|
if (option == '?')
|
||||||
{
|
{
|
||||||
free(new);
|
free(new);
|
||||||
@@ -762,11 +805,7 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
daemon->dhcp = new;
|
daemon->dhcp = new;
|
||||||
|
|
||||||
if (k >= 3 && strchr(a[2], '.') &&
|
|
||||||
((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
|
|
||||||
leasepos = 3;
|
|
||||||
|
|
||||||
if (k >= 4 && strchr(a[3], '.') &&
|
if (k >= 4 && strchr(a[3], '.') &&
|
||||||
((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
|
((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
|
||||||
leasepos = 4;
|
leasepos = 4;
|
||||||
@@ -873,10 +912,7 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
memcpy(new->clid, arg, len);
|
memcpy(new->clid, arg, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if ((arg[0] == 'n' || arg[0] == 'N') &&
|
else if (strstr(arg, "net:") == arg)
|
||||||
(arg[1] == 'e' || arg[1] == 'E') &&
|
|
||||||
(arg[2] == 't' || arg[3] == 'T') &&
|
|
||||||
arg[3] == ':')
|
|
||||||
{
|
{
|
||||||
new->flags |= CONFIG_NETID;
|
new->flags |= CONFIG_NETID;
|
||||||
new->netid.net = safe_string_alloc(arg+4);
|
new->netid.net = safe_string_alloc(arg+4);
|
||||||
@@ -955,6 +991,7 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
|
|
||||||
if (option == '?')
|
if (option == '?')
|
||||||
{
|
{
|
||||||
|
problem = "bad dhcp-host";
|
||||||
if (new->flags & CONFIG_NAME)
|
if (new->flags & CONFIG_NAME)
|
||||||
free(new->hostname);
|
free(new->hostname);
|
||||||
if (new->flags & CONFIG_CLID)
|
if (new->flags & CONFIG_CLID)
|
||||||
@@ -975,164 +1012,274 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
case 'O':
|
case 'O':
|
||||||
{
|
{
|
||||||
struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
|
struct dhcp_opt *new = safe_malloc(sizeof(struct dhcp_opt));
|
||||||
char *cp, *comma;
|
char *cp;
|
||||||
int addrs, digs, is_addr, is_hex, is_dec;
|
int addrs, digs, is_addr, is_hex, is_dec;
|
||||||
|
|
||||||
new->next = daemon->dhcp_opts;
|
new->next = daemon->dhcp_opts;
|
||||||
new->len = 0;
|
new->len = 0;
|
||||||
new->is_addr = 0;
|
new->is_addr = 0;
|
||||||
new->netid = NULL;
|
new->netid = NULL;
|
||||||
|
new->val = NULL;
|
||||||
|
|
||||||
if ((comma = strchr(optarg, ',')))
|
if ((comma = strchr(optarg, ',')))
|
||||||
{
|
{
|
||||||
*comma = 0;
|
struct dhcp_netid *np = NULL;
|
||||||
|
*comma++ = 0;
|
||||||
|
|
||||||
for (cp = optarg; *cp; cp++)
|
do {
|
||||||
if (!(*cp == ' ' || (*cp >='0' && *cp <= '9')))
|
for (cp = optarg; *cp; cp++)
|
||||||
|
if (!(*cp == ' ' || (*cp >='0' && *cp <= '9')))
|
||||||
|
break;
|
||||||
|
if (!*cp)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (*cp)
|
new->netid = safe_malloc(sizeof (struct dhcp_netid));
|
||||||
{
|
new->netid->net = safe_string_alloc(optarg);
|
||||||
new->netid = safe_string_alloc(optarg);
|
new->netid->next = np;
|
||||||
optarg = comma + 1;
|
np = new->netid;
|
||||||
if ((comma = strchr(optarg, ',')))
|
optarg = comma;
|
||||||
*comma = 0;
|
if ((comma = strchr(optarg, ',')))
|
||||||
}
|
*comma++ = 0;
|
||||||
|
} while (optarg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((new->opt = atoi(optarg)) == 0)
|
if (!optarg || (new->opt = atoi(optarg)) == 0)
|
||||||
{
|
{
|
||||||
option = '?';
|
option = '?';
|
||||||
if (new->netid)
|
problem = "bad dhcp-option";
|
||||||
free(new->netid);
|
|
||||||
free(new);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else if (comma && new->opt == 119)
|
||||||
daemon->dhcp_opts = new;
|
|
||||||
|
|
||||||
if (!comma)
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* characterise the value */
|
|
||||||
is_addr = is_hex = is_dec = 1;
|
|
||||||
addrs = digs = 1;
|
|
||||||
for (cp = comma+1; *cp; cp++)
|
|
||||||
if (*cp == ',')
|
|
||||||
{
|
|
||||||
addrs++;
|
|
||||||
is_dec = is_hex = 0;
|
|
||||||
}
|
|
||||||
else if (*cp == ':')
|
|
||||||
{
|
|
||||||
digs++;
|
|
||||||
is_dec = is_addr = 0;
|
|
||||||
}
|
|
||||||
else if (*cp == '.')
|
|
||||||
is_dec = is_hex = 0;
|
|
||||||
else if (!(*cp >='0' && *cp <= '9'))
|
|
||||||
{
|
|
||||||
is_dec = is_addr = 0;
|
|
||||||
if (!((*cp >='A' && *cp <= 'F') ||
|
|
||||||
(*cp >='a' && *cp <= 'f')))
|
|
||||||
is_hex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_hex && digs > 1)
|
|
||||||
{
|
{
|
||||||
char *p = comma+1, *q, *r;
|
/* dns search, RFC 3397 */
|
||||||
new->len = digs;
|
unsigned char *q, *r, *tail;
|
||||||
q = new->val = safe_malloc(new->len);
|
unsigned char *p = NULL;
|
||||||
while (*p)
|
int newlen, len = 0;
|
||||||
|
|
||||||
|
optarg = comma;
|
||||||
|
if ((comma = strchr(optarg, ',')))
|
||||||
|
*(comma++) = 0;
|
||||||
|
|
||||||
|
while (optarg && *optarg)
|
||||||
{
|
{
|
||||||
for (r = p; *r && *r != ':'; r++);
|
if (!canonicalise(optarg))
|
||||||
if (*r)
|
|
||||||
{
|
{
|
||||||
if (r != p)
|
option = '?';
|
||||||
{
|
problem = "bad domain in dhcp-option";
|
||||||
*r = 0;
|
|
||||||
*(q++) = strtol(p, NULL, 16);
|
|
||||||
}
|
|
||||||
p = r+1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (*p)
|
|
||||||
*(q++) = strtol(p, NULL, 16);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(r = realloc(p, len + strlen(optarg) + 2)))
|
||||||
|
die("could not get memory", NULL);
|
||||||
|
p = memmove(r, p, len);
|
||||||
|
|
||||||
|
q = p + len;
|
||||||
|
|
||||||
|
/* add string on the end in RFC1035 format */
|
||||||
|
while (*optarg)
|
||||||
|
{
|
||||||
|
char *cp = q++;
|
||||||
|
int j;
|
||||||
|
for (j = 0; *optarg && (*optarg != '.'); optarg++, j++)
|
||||||
|
*q++ = *optarg;
|
||||||
|
*cp = j;
|
||||||
|
if (*optarg)
|
||||||
|
optarg++;
|
||||||
|
}
|
||||||
|
*q++ = 0;
|
||||||
|
|
||||||
|
/* Now tail-compress using earlier names. */
|
||||||
|
newlen = q - p;
|
||||||
|
for (tail = p + len; *tail; tail += (*tail) + 1)
|
||||||
|
for (r = p; r - p < len; r += (*r) + 1)
|
||||||
|
if (strcmp(r, tail) == 0)
|
||||||
|
{
|
||||||
|
PUTSHORT((r - p) | 0xc000, tail);
|
||||||
|
newlen = tail - p;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
len = newlen;
|
||||||
|
|
||||||
|
optarg = comma;
|
||||||
|
if (optarg && (comma = strchr(optarg, ',')))
|
||||||
|
*(comma++) = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
new->len = len;
|
||||||
|
new->val = p;
|
||||||
}
|
}
|
||||||
else if (is_dec)
|
else if (comma)
|
||||||
{
|
{
|
||||||
/* Given that we don't know the length,
|
/* not option 119 */
|
||||||
this appaling hack is the best available */
|
/* characterise the value */
|
||||||
unsigned int val = atoi(comma+1);
|
is_addr = is_hex = is_dec = 1;
|
||||||
if (val < 256)
|
addrs = digs = 1;
|
||||||
|
for (cp = comma; *cp; cp++)
|
||||||
|
if (*cp == ',')
|
||||||
|
{
|
||||||
|
addrs++;
|
||||||
|
is_dec = is_hex = 0;
|
||||||
|
}
|
||||||
|
else if (*cp == ':')
|
||||||
|
{
|
||||||
|
digs++;
|
||||||
|
is_dec = is_addr = 0;
|
||||||
|
}
|
||||||
|
else if (*cp == '.')
|
||||||
|
is_dec = is_hex = 0;
|
||||||
|
else if (!((*cp >='0' && *cp <= '9') || *cp == '-'))
|
||||||
|
{
|
||||||
|
is_dec = is_addr = 0;
|
||||||
|
if (!((*cp >='A' && *cp <= 'F') ||
|
||||||
|
(*cp >='a' && *cp <= 'f')))
|
||||||
|
is_hex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_hex && digs > 1)
|
||||||
{
|
{
|
||||||
new->len = 1;
|
char *p = comma, *q, *r;
|
||||||
new->val = safe_malloc(1);
|
new->len = digs;
|
||||||
*(new->val) = val;
|
q = new->val = safe_malloc(new->len);
|
||||||
|
while (*p)
|
||||||
|
{
|
||||||
|
for (r = p; *r && *r != ':'; r++);
|
||||||
|
if (*r)
|
||||||
|
{
|
||||||
|
if (r != p)
|
||||||
|
{
|
||||||
|
*r = 0;
|
||||||
|
*(q++) = strtol(p, NULL, 16);
|
||||||
|
}
|
||||||
|
p = r+1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (*p)
|
||||||
|
*(q++) = strtol(p, NULL, 16);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (val < 65536)
|
else if (is_dec)
|
||||||
{
|
{
|
||||||
new->len = 2;
|
int i, val = atoi(comma);
|
||||||
new->val = safe_malloc(2);
|
/* assume numeric arg is 1 byte except for
|
||||||
*(new->val) = val>>8;
|
options where it is known otherwise. */
|
||||||
*(new->val+1) = val;
|
switch (new->opt)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
new->len = 1;
|
||||||
|
break;
|
||||||
|
case 13: case 22: case 25: case 26:
|
||||||
|
new->len = 2;
|
||||||
|
break;
|
||||||
|
case 2: case 24: case 35: case 38:
|
||||||
|
new->len = 4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
new->val = safe_malloc(new->len);
|
||||||
|
for (i=0; i<new->len; i++)
|
||||||
|
new->val[i] = val>>((new->len - i - 1)*8);
|
||||||
|
}
|
||||||
|
else if (is_addr)
|
||||||
|
{
|
||||||
|
struct in_addr in;
|
||||||
|
unsigned char *op;
|
||||||
|
new->len = INADDRSZ * addrs;
|
||||||
|
new->val = op = safe_malloc(new->len);
|
||||||
|
new->is_addr = 1;
|
||||||
|
while (addrs--)
|
||||||
|
{
|
||||||
|
cp = comma;
|
||||||
|
if ((comma = strchr(cp, ',')))
|
||||||
|
*comma++ = 0;
|
||||||
|
in.s_addr = inet_addr(cp);
|
||||||
|
memcpy(op, &in, INADDRSZ);
|
||||||
|
op += INADDRSZ;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
new->len = 4;
|
/* text arg */
|
||||||
new->val = safe_malloc(4);
|
new->len = strlen(comma);
|
||||||
*(new->val) = val>>24;
|
new->val = safe_malloc(new->len);
|
||||||
*(new->val+1) = val>>16;
|
memcpy(new->val, comma, new->len);
|
||||||
*(new->val+2) = val>>8;
|
|
||||||
*(new->val+3) = val;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (is_addr)
|
|
||||||
|
if (new->len > 256)
|
||||||
{
|
{
|
||||||
struct in_addr in;
|
option = '?';
|
||||||
unsigned char *op;
|
problem = "dhcp-option too long";
|
||||||
new->len = INADDRSZ * addrs;
|
}
|
||||||
new->val = op = safe_malloc(new->len);
|
|
||||||
new->is_addr = 1;
|
if (option == '?')
|
||||||
while (addrs--)
|
{
|
||||||
{
|
if (new->netid)
|
||||||
cp = comma;
|
free(new->netid);
|
||||||
if ((comma = strchr(cp+1, ',')))
|
if (new->val)
|
||||||
*comma = 0;
|
free(new->val);
|
||||||
in.s_addr = inet_addr(cp+1);
|
free(new);
|
||||||
memcpy(op, &in, INADDRSZ);
|
|
||||||
op += INADDRSZ;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
daemon->dhcp_opts = new;
|
||||||
/* text arg */
|
|
||||||
new->len = strlen(comma+1);
|
|
||||||
new->val = safe_malloc(new->len);
|
|
||||||
memcpy(new->val, comma+1, new->len);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'M':
|
case 'M':
|
||||||
{
|
{
|
||||||
char *comma;
|
struct dhcp_netid *id = NULL;
|
||||||
|
while (optarg && strstr(optarg, "net:") == optarg)
|
||||||
if ((comma = strchr(optarg, ',')))
|
|
||||||
*comma = 0;
|
|
||||||
daemon->dhcp_file = safe_string_alloc(optarg);
|
|
||||||
if (comma)
|
|
||||||
{
|
{
|
||||||
optarg = comma+1;
|
struct dhcp_netid *newid = safe_malloc(sizeof(struct dhcp_netid));
|
||||||
|
newid->next = id;
|
||||||
|
id = newid;
|
||||||
if ((comma = strchr(optarg, ',')))
|
if ((comma = strchr(optarg, ',')))
|
||||||
*comma = 0;
|
*comma++ = 0;
|
||||||
daemon->dhcp_sname = safe_string_alloc(optarg);
|
newid->net = safe_string_alloc(optarg+4);
|
||||||
if (comma && (daemon->dhcp_next_server.s_addr = inet_addr(comma+1)) == (in_addr_t)-1)
|
optarg = comma;
|
||||||
option = '?';
|
};
|
||||||
|
|
||||||
|
if (!optarg)
|
||||||
|
option = '?';
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *dhcp_file, *dhcp_sname = NULL;
|
||||||
|
struct in_addr dhcp_next_server;
|
||||||
|
if ((comma = strchr(optarg, ',')))
|
||||||
|
*comma++ = 0;
|
||||||
|
dhcp_file = safe_string_alloc(optarg);
|
||||||
|
dhcp_next_server.s_addr = 0;
|
||||||
|
if (comma)
|
||||||
|
{
|
||||||
|
optarg = comma;
|
||||||
|
if ((comma = strchr(optarg, ',')))
|
||||||
|
*comma++ = 0;
|
||||||
|
dhcp_sname = safe_string_alloc(optarg);
|
||||||
|
if (comma && (dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1)
|
||||||
|
option = '?';
|
||||||
|
}
|
||||||
|
if (option != '?')
|
||||||
|
{
|
||||||
|
struct dhcp_boot *new = safe_malloc(sizeof(struct dhcp_boot));
|
||||||
|
new->file = dhcp_file;
|
||||||
|
new->sname = dhcp_sname;
|
||||||
|
new->next_server = dhcp_next_server;
|
||||||
|
new->netid = id;
|
||||||
|
new->next = daemon->boot_config;
|
||||||
|
daemon->boot_config = new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (option == '?')
|
||||||
|
{
|
||||||
|
struct dhcp_netid *tmp;
|
||||||
|
for (; id; id = tmp)
|
||||||
|
{
|
||||||
|
tmp = id->next;
|
||||||
|
free(id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1140,8 +1287,6 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
case 'U':
|
case 'U':
|
||||||
case 'j':
|
case 'j':
|
||||||
{
|
{
|
||||||
char *comma;
|
|
||||||
|
|
||||||
if (!(comma = strchr(optarg, ',')))
|
if (!(comma = strchr(optarg, ',')))
|
||||||
option = '?';
|
option = '?';
|
||||||
else
|
else
|
||||||
@@ -1158,7 +1303,27 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'J':
|
||||||
|
{
|
||||||
|
struct dhcp_netid_list *new = safe_malloc(sizeof(struct dhcp_netid_list));
|
||||||
|
struct dhcp_netid *list = NULL;
|
||||||
|
new->next = daemon->dhcp_ignore;
|
||||||
|
daemon->dhcp_ignore = new;
|
||||||
|
do {
|
||||||
|
struct dhcp_netid *member = safe_malloc(sizeof(struct dhcp_netid));
|
||||||
|
if ((comma = strchr(optarg, ',')))
|
||||||
|
*comma++ = 0;
|
||||||
|
member->next = list;
|
||||||
|
list = member;
|
||||||
|
member->net = safe_string_alloc(optarg);
|
||||||
|
optarg = comma;
|
||||||
|
} while (optarg);
|
||||||
|
|
||||||
|
new->list = list;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case 'V':
|
case 'V':
|
||||||
{
|
{
|
||||||
char *a[3] = { NULL, NULL, NULL };
|
char *a[3] = { NULL, NULL, NULL };
|
||||||
@@ -1203,11 +1368,16 @@ struct daemon *read_opts (int argc, char **argv)
|
|||||||
{
|
{
|
||||||
if (f)
|
if (f)
|
||||||
{
|
{
|
||||||
sprintf(buff, "error at line %d of %s ", lineno, conffile);
|
sprintf(buff, "%s at line %d of %s ",
|
||||||
|
problem ? problem : "error", lineno, conffile);
|
||||||
complain(buff, NULL);
|
complain(buff, NULL);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
die("bad command line options: try --help.", NULL);
|
#ifdef HAVE_GETOPT_LONG
|
||||||
|
die("bad command line options: %s.", problem ? problem : "try --help");
|
||||||
|
#else
|
||||||
|
die("bad command line options: %s.", problem ? problem : "try -w");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+345
-253
@@ -306,18 +306,11 @@ static unsigned char *skip_questions(HEADER *header, unsigned int plen)
|
|||||||
return ansp;
|
return ansp;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char *find_pseudoheader(HEADER *header, unsigned int plen)
|
static unsigned char *skip_section(unsigned char *ansp, int count, HEADER *header, unsigned int plen)
|
||||||
{
|
{
|
||||||
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it. */
|
int i, rdlen;
|
||||||
|
|
||||||
int i, arcount = ntohs(header->arcount);
|
for (i = 0; i < count; i++)
|
||||||
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)))
|
if (!(ansp = skip_name(ansp, header, plen)))
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -328,9 +321,69 @@ unsigned char *find_pseudoheader(HEADER *header, unsigned int plen)
|
|||||||
ansp += rdlen;
|
ansp += rdlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ansp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* CRC all the bytes of the question section. This is used to
|
||||||
|
safely detect query retransmision. */
|
||||||
|
unsigned int questions_crc(HEADER *header, unsigned int plen)
|
||||||
|
{
|
||||||
|
unsigned char *start, *end = skip_questions(header, plen);
|
||||||
|
unsigned int crc = 0xffffffff;
|
||||||
|
|
||||||
|
if (end)
|
||||||
|
for (start = (unsigned char *)(header+1); start < end; start++)
|
||||||
|
{
|
||||||
|
int i = 8;
|
||||||
|
crc ^= *start << 24;
|
||||||
|
while (i--)
|
||||||
|
crc = crc & 0x80000000 ? (crc << 1) ^ 0x04c11db7 : crc << 1;
|
||||||
|
}
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int resize_packet(HEADER *header, unsigned int plen, unsigned char *pheader, unsigned int hlen)
|
||||||
|
{
|
||||||
|
unsigned char *ansp = skip_questions(header, plen);
|
||||||
|
|
||||||
|
if (!ansp)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
|
||||||
|
header, plen)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* restore pseudoheader */
|
||||||
|
if (pheader && ntohs(header->arcount) == 0)
|
||||||
|
{
|
||||||
|
/* must use memmove, may overlap */
|
||||||
|
memmove(ansp, pheader, hlen);
|
||||||
|
header->arcount = htons(1);
|
||||||
|
ansp += hlen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ansp - (unsigned char *)header;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *find_pseudoheader(HEADER *header, unsigned int plen, unsigned int *len, unsigned char **p)
|
||||||
|
{
|
||||||
|
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
|
||||||
|
also return length of pseudoheader in *len and pointer to the UDP size in *p */
|
||||||
|
|
||||||
|
int i, arcount = ntohs(header->arcount);
|
||||||
|
unsigned char *ansp;
|
||||||
|
unsigned short rdlen, type;
|
||||||
|
|
||||||
|
if (arcount == 0 || !(ansp = skip_questions(header, plen)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (!(ansp = skip_section(ansp, ntohs(header->ancount) + ntohs(header->nscount), header, plen)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
for (i = 0; i < arcount; i++)
|
for (i = 0; i < arcount; i++)
|
||||||
{
|
{
|
||||||
unsigned char *save;
|
unsigned char *save, *start = ansp;
|
||||||
if (!(ansp = skip_name(ansp, header, plen)))
|
if (!(ansp = skip_name(ansp, header, plen)))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
@@ -340,9 +393,15 @@ unsigned char *find_pseudoheader(HEADER *header, unsigned int plen)
|
|||||||
GETSHORT(rdlen, ansp);
|
GETSHORT(rdlen, ansp);
|
||||||
if ((unsigned int)(ansp + rdlen - (unsigned char *)header) > plen)
|
if ((unsigned int)(ansp + rdlen - (unsigned char *)header) > plen)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (type == T_OPT)
|
ansp += rdlen;
|
||||||
return save;
|
if (type == T_OPT)
|
||||||
ansp += rdlen;
|
{
|
||||||
|
if (len)
|
||||||
|
*len = ansp - start;
|
||||||
|
if (p)
|
||||||
|
*p = save;
|
||||||
|
return start;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -361,9 +420,9 @@ static int private_net(struct all_addr *addrp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char *add_text_record(unsigned int nameoffset, unsigned char *p,
|
static unsigned char *add_text_record(HEADER *header, unsigned int nameoffset, unsigned char *p,
|
||||||
unsigned long ttl, unsigned short pref,
|
unsigned long ttl, unsigned short pref,
|
||||||
unsigned short type, char *name)
|
unsigned short type, char *name, int *offset)
|
||||||
{
|
{
|
||||||
unsigned char *sav, *cp;
|
unsigned char *sav, *cp;
|
||||||
int j;
|
int j;
|
||||||
@@ -392,105 +451,12 @@ static unsigned char *add_text_record(unsigned int nameoffset, unsigned char *p,
|
|||||||
j = p - sav - 2;
|
j = p - sav - 2;
|
||||||
PUTSHORT(j, sav); /* Real RDLENGTH */
|
PUTSHORT(j, sav); /* Real RDLENGTH */
|
||||||
|
|
||||||
|
if (offset)
|
||||||
|
*offset = sav - (unsigned char *)header;
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On receiving an NXDOMAIN or NODATA reply, determine which names are known
|
|
||||||
not to exist for negative caching. name if a working buffer passed in. */
|
|
||||||
void extract_neg_addrs(HEADER *header, unsigned int qlen, char *name, time_t now)
|
|
||||||
{
|
|
||||||
unsigned char *p;
|
|
||||||
int i, found_soa = 0;
|
|
||||||
int qtype, qclass, rdlen;
|
|
||||||
unsigned long ttl, minttl = 0;
|
|
||||||
unsigned short flags = F_NEG;
|
|
||||||
|
|
||||||
if (header->rcode == NXDOMAIN)
|
|
||||||
flags |= F_NXDOMAIN;
|
|
||||||
|
|
||||||
/* there may be more than one question with some questions
|
|
||||||
answered. We don't generate negative entries from those. */
|
|
||||||
if (ntohs(header->ancount) != 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!(p = skip_questions(header, qlen)))
|
|
||||||
return; /* bad packet */
|
|
||||||
|
|
||||||
/* we first need to find SOA records, to get min TTL, then we
|
|
||||||
add a NEG cache entry for each question. */
|
|
||||||
|
|
||||||
for (i=0; i<ntohs(header->nscount); i++)
|
|
||||||
{
|
|
||||||
if (!extract_name(header, qlen, &p, name, 1))
|
|
||||||
return; /* bad packet */
|
|
||||||
|
|
||||||
GETSHORT(qtype, p);
|
|
||||||
GETSHORT(qclass, p);
|
|
||||||
GETLONG(ttl, p);
|
|
||||||
GETSHORT(rdlen, p);
|
|
||||||
|
|
||||||
if ((qclass == C_IN) && (qtype == T_SOA))
|
|
||||||
{
|
|
||||||
int dummy;
|
|
||||||
/* MNAME */
|
|
||||||
if (!extract_name(header, qlen, &p, name, 1))
|
|
||||||
return;
|
|
||||||
/* RNAME */
|
|
||||||
if (!extract_name(header, qlen, &p, name, 1))
|
|
||||||
return;
|
|
||||||
GETLONG(dummy, p); /* SERIAL */
|
|
||||||
GETLONG(dummy, p); /* REFRESH */
|
|
||||||
GETLONG(dummy, p); /* RETRY */
|
|
||||||
GETLONG(dummy, p); /* EXPIRE */
|
|
||||||
if (!found_soa)
|
|
||||||
{
|
|
||||||
found_soa = 1;
|
|
||||||
minttl = ttl;
|
|
||||||
}
|
|
||||||
else if (ttl < minttl)
|
|
||||||
minttl = ttl;
|
|
||||||
GETLONG(ttl, p); /* minTTL */
|
|
||||||
if (ttl < minttl)
|
|
||||||
minttl = ttl;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
p += rdlen;
|
|
||||||
|
|
||||||
if ((unsigned int)(p - (unsigned char *)header) > qlen)
|
|
||||||
return; /* bad packet */
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found_soa)
|
|
||||||
return; /* failed to find SOA */
|
|
||||||
|
|
||||||
cache_start_insert();
|
|
||||||
|
|
||||||
p = (unsigned char *)(header+1);
|
|
||||||
|
|
||||||
for (i=0; i<ntohs(header->qdcount); i++)
|
|
||||||
{
|
|
||||||
struct all_addr addr;
|
|
||||||
int is_arpa;
|
|
||||||
|
|
||||||
if (!extract_name(header, qlen, &p, name, 1))
|
|
||||||
return; /* bad packet */
|
|
||||||
|
|
||||||
GETSHORT(qtype, p);
|
|
||||||
GETSHORT(qclass, p);
|
|
||||||
|
|
||||||
if (qclass == C_IN && qtype == T_PTR && (is_arpa = in_arpa_name_2_addr(name, &addr)))
|
|
||||||
cache_insert(name, &addr, now, minttl , is_arpa | F_REVERSE | flags);
|
|
||||||
else if (qclass == C_IN && qtype == T_A)
|
|
||||||
cache_insert(name, NULL, now, minttl, F_IPV4 | F_FORWARD | flags);
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
else if (qclass == C_IN && qtype == T_AAAA)
|
|
||||||
cache_insert(name, NULL, now, minttl, F_IPV6 | F_FORWARD | flags);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
cache_end_insert();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dns_doctor(HEADER *header, 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)
|
||||||
@@ -501,149 +467,249 @@ static void dns_doctor(HEADER *header, struct doctor *doctor, struct in_addr *ad
|
|||||||
/* Since we munged the data, the server it came from is no longer authoritative */
|
/* Since we munged the data, the server it came from is no longer authoritative */
|
||||||
header->nscount = htons(0);
|
header->nscount = htons(0);
|
||||||
header->arcount = htons(0);
|
header->arcount = htons(0);
|
||||||
|
header->aa = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void extract_addresses(HEADER *header, unsigned int qlen, char *name,
|
static int find_soa(HEADER *header, unsigned int qlen)
|
||||||
time_t now, struct doctor *doctors)
|
|
||||||
{
|
{
|
||||||
unsigned char *p, *psave, *endrr;
|
unsigned char *p;
|
||||||
int qtype, qclass, rdlen;
|
int qtype, qclass, rdlen;
|
||||||
unsigned long ttl;
|
unsigned long ttl, minttl = ULONG_MAX;
|
||||||
int i;
|
int i, found_soa = 0;
|
||||||
|
|
||||||
/* skip over questions */
|
/* first move to NS section and find TTL from any SOA section */
|
||||||
if (!(p = skip_questions(header, qlen)))
|
if (!(p = skip_questions(header, qlen)) ||
|
||||||
return; /* bad packet */
|
!(p = skip_section(p, ntohs(header->ancount), header, qlen)))
|
||||||
|
return 0; /* bad packet */
|
||||||
|
|
||||||
cache_start_insert();
|
for (i=0; i<ntohs(header->nscount); i++)
|
||||||
|
|
||||||
psave = p;
|
|
||||||
|
|
||||||
for (i=0; i<ntohs(header->ancount); i++)
|
|
||||||
{
|
{
|
||||||
unsigned char *origname = p;
|
if (!(p = skip_name(p, header, qlen)))
|
||||||
if (!extract_name(header, qlen, &p, name, 1))
|
return 0; /* bad packet */
|
||||||
return; /* bad packet */
|
|
||||||
|
|
||||||
GETSHORT(qtype, p);
|
GETSHORT(qtype, p);
|
||||||
GETSHORT(qclass, p);
|
GETSHORT(qclass, p);
|
||||||
GETLONG(ttl, p);
|
GETLONG(ttl, p);
|
||||||
GETSHORT(rdlen, p);
|
GETSHORT(rdlen, p);
|
||||||
|
|
||||||
endrr = p + rdlen;
|
if ((qclass == C_IN) && (qtype == T_SOA))
|
||||||
if ((unsigned int)(endrr - (unsigned char *)header) > qlen)
|
{
|
||||||
|
found_soa = 1;
|
||||||
|
if (ttl < minttl)
|
||||||
|
minttl = ttl;
|
||||||
|
|
||||||
|
/* MNAME */
|
||||||
|
if (!(p = skip_name(p, header, qlen)))
|
||||||
|
return 0;
|
||||||
|
/* RNAME */
|
||||||
|
if (!(p = skip_name(p, header, qlen)))
|
||||||
|
return 0;
|
||||||
|
p += 16; /* SERIAL REFRESH RETRY EXPIRE */
|
||||||
|
|
||||||
|
GETLONG(ttl, p); /* minTTL */
|
||||||
|
if (ttl < minttl)
|
||||||
|
minttl = ttl;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
p += rdlen;
|
||||||
|
|
||||||
|
if ((unsigned int)(p - (unsigned char *)header) > qlen)
|
||||||
|
return 0; /* bad packet */
|
||||||
|
}
|
||||||
|
|
||||||
|
return found_soa ? minttl : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Note that the following code can create CNAME chains that don't point to a real record,
|
||||||
|
either because of lack of memory, or lack of SOA records. These are treated by the cache code as
|
||||||
|
expired and cleaned out that way. */
|
||||||
|
void extract_addresses(HEADER *header, unsigned int qlen, char *name, time_t now, struct daemon *daemon)
|
||||||
|
{
|
||||||
|
unsigned char *p, *p1, *endrr;
|
||||||
|
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||||
|
|
||||||
|
cache_start_insert();
|
||||||
|
|
||||||
|
/* go through the questions. */
|
||||||
|
p = (unsigned char *)(header+1);
|
||||||
|
|
||||||
|
for (i = 0; i<ntohs(header->qdcount); i++)
|
||||||
|
{
|
||||||
|
int found = 0, cname_count = 5;
|
||||||
|
struct crec *cpp = NULL;
|
||||||
|
int flags = header->rcode == NXDOMAIN ? F_NXDOMAIN : 0;
|
||||||
|
unsigned long cttl = ULONG_MAX, attl, ttl = 0;
|
||||||
|
|
||||||
|
if (!extract_name(header, qlen, &p, name, 1))
|
||||||
return; /* bad packet */
|
return; /* bad packet */
|
||||||
|
|
||||||
|
GETSHORT(qtype, p);
|
||||||
|
GETSHORT(qclass, p);
|
||||||
|
|
||||||
if (qclass != C_IN)
|
if (qclass != C_IN)
|
||||||
{
|
continue;
|
||||||
p = endrr;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qtype == T_A) /* A record. */
|
/* PTRs: we chase CNAMEs here, since we have no way to
|
||||||
{
|
represent them in the cache. */
|
||||||
dns_doctor(header, doctors, (struct in_addr *)p);
|
if (qtype == T_PTR)
|
||||||
cache_insert(name, (struct all_addr *)p, now,
|
{
|
||||||
ttl, F_IPV4 | F_FORWARD);
|
|
||||||
}
|
|
||||||
#ifdef HAVE_IPV6
|
|
||||||
else if (qtype == T_AAAA) /* IPV6 address record. */
|
|
||||||
cache_insert(name, (struct all_addr *)p, now,
|
|
||||||
ttl, F_IPV6 | F_FORWARD);
|
|
||||||
#endif
|
|
||||||
else if (qtype == T_PTR)
|
|
||||||
{
|
|
||||||
/* PTR record */
|
|
||||||
struct all_addr addr;
|
struct all_addr addr;
|
||||||
int name_encoding = in_arpa_name_2_addr(name, &addr);
|
int name_encoding = in_arpa_name_2_addr(name, &addr);
|
||||||
if (name_encoding)
|
|
||||||
|
if (!name_encoding)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(flags & F_NXDOMAIN))
|
||||||
{
|
{
|
||||||
if (!extract_name(header, qlen, &p, name, 1))
|
cname_loop:
|
||||||
return; /* bad packet */
|
if (!(p1 = skip_questions(header, qlen)))
|
||||||
cache_insert(name, &addr, now,
|
return;
|
||||||
ttl, name_encoding | F_REVERSE);
|
|
||||||
|
for (j = 0; j<ntohs(header->ancount); j++)
|
||||||
|
{
|
||||||
|
if (!(res = extract_name(header, qlen, &p1, name, 0)))
|
||||||
|
return; /* bad packet */
|
||||||
|
|
||||||
|
GETSHORT(aqtype, p1);
|
||||||
|
GETSHORT(aqclass, p1);
|
||||||
|
GETLONG(attl, p1);
|
||||||
|
GETSHORT(ardlen, p1);
|
||||||
|
endrr = p1+ardlen;
|
||||||
|
|
||||||
|
/* TTL of record is minimum of CNAMES and PTR */
|
||||||
|
if (attl < cttl)
|
||||||
|
cttl = attl;
|
||||||
|
|
||||||
|
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == T_PTR))
|
||||||
|
{
|
||||||
|
if (!extract_name(header, qlen, &p1, name, 1))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (aqtype == T_CNAME)
|
||||||
|
{
|
||||||
|
if (!cname_count--)
|
||||||
|
return; /* looped CNAMES */
|
||||||
|
goto cname_loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
cache_insert(name, &addr, now, cttl, name_encoding | F_REVERSE);
|
||||||
|
found = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 = endrr;
|
||||||
|
if ((unsigned int)(p1 - (unsigned char *)header) > qlen)
|
||||||
|
return; /* bad packet */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found && !(daemon->options & OPT_NO_NEG))
|
||||||
|
{
|
||||||
|
if (!searched_soa)
|
||||||
|
{
|
||||||
|
searched_soa = 1;
|
||||||
|
ttl = find_soa(header, qlen);
|
||||||
|
}
|
||||||
|
if (ttl)
|
||||||
|
cache_insert(name, &addr, now, ttl, name_encoding | F_REVERSE | F_NEG | flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (qtype == T_CNAME)
|
else
|
||||||
{
|
{
|
||||||
/* CNAME, search whole answer section again */
|
/* everything other than PTR */
|
||||||
unsigned char *endrr1;
|
struct crec *newc;
|
||||||
unsigned long cttl;
|
|
||||||
int j;
|
if (qtype == T_A)
|
||||||
unsigned char *targp = p;
|
flags |= F_IPV4;
|
||||||
|
|
||||||
p = psave; /* rewind p */
|
|
||||||
for (j=0; j<ntohs(header->ancount); j++)
|
|
||||||
{
|
|
||||||
int res;
|
|
||||||
unsigned char *tmp = targp;
|
|
||||||
/* copy since it gets altered by extract_name */
|
|
||||||
/* get CNAME target each time round */
|
|
||||||
if (!extract_name(header, qlen, &tmp, name, 1))
|
|
||||||
return; /* bad packet */
|
|
||||||
/* compare this name with target of CNAME in name buffer */
|
|
||||||
if (!(res = extract_name(header, qlen, &p, name, 0)))
|
|
||||||
return; /* bad packet */
|
|
||||||
|
|
||||||
GETSHORT(qtype, p);
|
|
||||||
GETSHORT(qclass, p);
|
|
||||||
GETLONG(cttl, p);
|
|
||||||
GETSHORT(rdlen, p);
|
|
||||||
|
|
||||||
endrr1 = p+rdlen;
|
|
||||||
if ((unsigned int)(endrr1 - (unsigned char *)header) > qlen)
|
|
||||||
return; /* bad packet */
|
|
||||||
|
|
||||||
/* is this RR name same as target of CNAME */
|
|
||||||
if ((qclass != C_IN) || (res == 2))
|
|
||||||
{
|
|
||||||
p = endrr1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* match, use name of CNAME, data from this RR
|
|
||||||
use min TTL of two */
|
|
||||||
|
|
||||||
if (ttl < cttl)
|
|
||||||
cttl = ttl;
|
|
||||||
|
|
||||||
/* get orig. name back again */
|
|
||||||
tmp = origname;
|
|
||||||
if (!extract_name(header, qlen, &tmp, name, 1))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (qtype == T_A) /* A record. */
|
|
||||||
{
|
|
||||||
dns_doctor(header, doctors, (struct in_addr *)p);
|
|
||||||
cache_insert(name, (struct all_addr *)p, now,
|
|
||||||
cttl, F_IPV4 | F_FORWARD);
|
|
||||||
}
|
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
else if (qtype == T_AAAA) /* IPV6 address record. */
|
else if (qtype == T_AAAA)
|
||||||
cache_insert(name, (struct all_addr *)p, now,
|
flags |= F_IPV6;
|
||||||
cttl, F_IPV6 | F_FORWARD);
|
|
||||||
#endif
|
#endif
|
||||||
else if (qtype == T_PTR)
|
else
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!(flags & F_NXDOMAIN))
|
||||||
|
{
|
||||||
|
cname_loop1:
|
||||||
|
if (!(p1 = skip_questions(header, qlen)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (j = 0; j<ntohs(header->ancount); j++)
|
||||||
{
|
{
|
||||||
/* PTR record extract address from CNAME name */
|
if (!(res = extract_name(header, qlen, &p1, name, 0)))
|
||||||
struct all_addr addr;
|
return; /* bad packet */
|
||||||
int name_encoding = in_arpa_name_2_addr(name, &addr);
|
|
||||||
if (name_encoding)
|
GETSHORT(aqtype, p1);
|
||||||
|
GETSHORT(aqclass, p1);
|
||||||
|
GETLONG(attl, p1);
|
||||||
|
GETSHORT(ardlen, p1);
|
||||||
|
endrr = p1+ardlen;
|
||||||
|
|
||||||
|
if (aqclass == C_IN && res != 2 && (aqtype == T_CNAME || aqtype == qtype))
|
||||||
{
|
{
|
||||||
if (!extract_name(header, qlen, &p, name, 1))
|
if (aqtype == T_CNAME)
|
||||||
return; /* bad packet */
|
{
|
||||||
cache_insert(name, &addr, now, cttl,
|
if (!cname_count--)
|
||||||
name_encoding | F_REVERSE);
|
return; /* looped CNAMES */
|
||||||
}
|
newc = cache_insert(name, NULL, now, attl, F_CNAME | F_FORWARD);
|
||||||
}
|
if (newc && cpp)
|
||||||
p = endrr1;
|
{
|
||||||
}
|
cpp->addr.cname.cache = newc;
|
||||||
}
|
cpp->addr.cname.uid = newc->uid;
|
||||||
p = endrr;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
cpp = newc;
|
||||||
|
if (attl < cttl)
|
||||||
|
cttl = attl;
|
||||||
|
|
||||||
|
if (!extract_name(header, qlen, &p1, name, 1))
|
||||||
|
return;
|
||||||
|
goto cname_loop1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
found = 1;
|
||||||
|
if (aqtype == T_A)
|
||||||
|
dns_doctor(header, daemon->doctors, (struct in_addr *)p1);
|
||||||
|
newc = cache_insert(name, (struct all_addr *)p1, now, attl, flags | F_FORWARD);
|
||||||
|
if (newc && cpp)
|
||||||
|
{
|
||||||
|
cpp->addr.cname.cache = newc;
|
||||||
|
cpp->addr.cname.uid = newc->uid;
|
||||||
|
}
|
||||||
|
cpp = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p1 = endrr;
|
||||||
|
if ((unsigned int)(p1 - (unsigned char *)header) > qlen)
|
||||||
|
return; /* bad packet */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found && !(daemon->options & OPT_NO_NEG))
|
||||||
|
{
|
||||||
|
if (!searched_soa)
|
||||||
|
{
|
||||||
|
searched_soa = 1;
|
||||||
|
ttl = find_soa(header, qlen);
|
||||||
|
}
|
||||||
|
/* If there's no SOA to get the TTL from, but there is a CNAME
|
||||||
|
pointing at this, inherit it's TTL */
|
||||||
|
if (ttl || cpp)
|
||||||
|
{
|
||||||
|
newc = cache_insert(name, (struct all_addr *)p, now, ttl ? ttl : cttl, F_FORWARD | F_NEG | flags);
|
||||||
|
if (newc && cpp)
|
||||||
|
{
|
||||||
|
cpp->addr.cname.cache = newc;
|
||||||
|
cpp->addr.cname.uid = newc->uid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
cache_end_insert();
|
cache_end_insert();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -735,7 +801,22 @@ int setup_reply(HEADER *header, unsigned int qlen,
|
|||||||
|
|
||||||
return p - (unsigned char *)header;
|
return p - (unsigned char *)header;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* check if name matches local names ie from /etc/hosts or DHCP or local mx names. */
|
||||||
|
int check_for_local_domain(char *name, time_t now, struct mx_record *mx)
|
||||||
|
{
|
||||||
|
struct crec *crecp;
|
||||||
|
|
||||||
|
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)) &&
|
||||||
|
(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (; mx; mx = mx->next)
|
||||||
|
if (hostname_isequal(name, mx->mxname))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Is the packet a reply with the answer address equal to addr?
|
/* Is the packet a reply with the answer address equal to addr?
|
||||||
If so mung is into an NXDOMAIN reply and also put that information
|
If so mung is into an NXDOMAIN reply and also put that information
|
||||||
@@ -766,14 +847,8 @@ int check_for_bogus_wildcard(HEADER *header, unsigned int qlen, char *name,
|
|||||||
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
|
for (baddrp = baddr; baddrp; baddrp = baddrp->next)
|
||||||
if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
|
if (memcmp(&baddrp->addr, p, INADDRSZ) == 0)
|
||||||
{
|
{
|
||||||
/* Found a bogus address. Mangle the packet into an NXDOMAIN reply */
|
/* Found a bogus address. Insert that info here, since there no SOA record
|
||||||
header->aa = 0;
|
to get the ttl from in the normal processing */
|
||||||
header->ra = 1; /* recursion if available */
|
|
||||||
header->nscount = htons(0);
|
|
||||||
header->arcount = htons(0);
|
|
||||||
header->ancount = htons(0);
|
|
||||||
header->rcode = NXDOMAIN;
|
|
||||||
|
|
||||||
cache_start_insert();
|
cache_start_insert();
|
||||||
cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);
|
cache_insert(name, NULL, now, ttl, F_IPV4 | F_FORWARD | F_NEG | F_NXDOMAIN | F_CONFIG);
|
||||||
cache_end_insert();
|
cache_end_insert();
|
||||||
@@ -811,7 +886,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
|||||||
forward rather than answering from the cache, which doesn't include
|
forward rather than answering from the cache, which doesn't include
|
||||||
security information. */
|
security information. */
|
||||||
|
|
||||||
if ((pheader = find_pseudoheader(header, qlen)))
|
if (find_pseudoheader(header, qlen, NULL, &pheader))
|
||||||
{
|
{
|
||||||
unsigned short udpsz, ext_rcode, flags;
|
unsigned short udpsz, ext_rcode, flags;
|
||||||
unsigned char *psave = pheader;
|
unsigned char *psave = pheader;
|
||||||
@@ -892,7 +967,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
|||||||
(qtype == T_SOA || qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
(qtype == T_SOA || qtype == T_SRV || (qtype == T_ANY && strchr(name, '_'))))
|
||||||
{
|
{
|
||||||
ans = 1;
|
ans = 1;
|
||||||
log_query(F_CONFIG | F_NEG, name, &addr, 0);
|
log_query(F_CONFIG | F_NEG, name, &addr, 0, NULL, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -906,7 +981,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
|||||||
ans = 1;
|
ans = 1;
|
||||||
if (!dryrun)
|
if (!dryrun)
|
||||||
{
|
{
|
||||||
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN, name, &addr, 0);
|
log_query(F_CONFIG | F_REVERSE | F_IPV4 | F_NEG | F_NXDOMAIN, name, &addr, 0, NULL, 0);
|
||||||
nxdomain = 1;
|
nxdomain = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -922,7 +997,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
|||||||
ans = 1;
|
ans = 1;
|
||||||
if (!dryrun)
|
if (!dryrun)
|
||||||
{
|
{
|
||||||
log_query(crecp->flags & ~F_FORWARD, name, &addr, 0);
|
log_query(crecp->flags & ~F_FORWARD, name, &addr, 0, NULL, 0);
|
||||||
auth = 0;
|
auth = 0;
|
||||||
if (crecp->flags & F_NXDOMAIN)
|
if (crecp->flags & F_NXDOMAIN)
|
||||||
nxdomain = 1;
|
nxdomain = 1;
|
||||||
@@ -944,10 +1019,11 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
|||||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||||
auth = 0;
|
auth = 0;
|
||||||
|
|
||||||
ansp = add_text_record(nameoffset, ansp, ttl, 0, T_PTR,
|
ansp = add_text_record(header, nameoffset, ansp, ttl, 0, T_PTR,
|
||||||
cache_get_name(crecp));
|
cache_get_name(crecp), NULL);
|
||||||
|
|
||||||
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr, 0);
|
log_query(crecp->flags & ~F_FORWARD, cache_get_name(crecp), &addr,
|
||||||
|
0, daemon->addn_hosts, crecp->uid);
|
||||||
anscount++;
|
anscount++;
|
||||||
|
|
||||||
/* if last answer exceeded packet size, give up */
|
/* if last answer exceeded packet size, give up */
|
||||||
@@ -962,7 +1038,7 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
|||||||
{
|
{
|
||||||
unsigned short type = T_A;
|
unsigned short type = T_A;
|
||||||
int addrsz = INADDRSZ;
|
int addrsz = INADDRSZ;
|
||||||
|
|
||||||
if (flag == F_IPV6)
|
if (flag == F_IPV6)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_IPV6
|
#ifdef HAVE_IPV6
|
||||||
@@ -975,21 +1051,36 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
|||||||
|
|
||||||
if (qtype != type && qtype != T_ANY)
|
if (qtype != type && qtype != T_ANY)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
cname_restart:
|
||||||
crecp = NULL;
|
crecp = NULL;
|
||||||
while ((crecp = cache_find_by_name(crecp, name, now, flag)))
|
while ((crecp = cache_find_by_name(crecp, name, now, flag | F_CNAME)))
|
||||||
{
|
{
|
||||||
/* 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)))
|
||||||
continue;
|
break;
|
||||||
|
|
||||||
|
if (crecp->flags & F_CNAME)
|
||||||
|
{
|
||||||
|
if (!dryrun)
|
||||||
|
{
|
||||||
|
ansp = add_text_record(header, nameoffset, ansp, crecp->ttd - now, 0, T_CNAME,
|
||||||
|
cache_get_name(crecp->addr.cname.cache), &nameoffset);
|
||||||
|
anscount++;
|
||||||
|
log_query(crecp->flags, name, NULL, 0, daemon->addn_hosts, crecp->uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(name, cache_get_name(crecp->addr.cname.cache));
|
||||||
|
goto cname_restart;
|
||||||
|
}
|
||||||
|
|
||||||
if (crecp->flags & F_NEG)
|
if (crecp->flags & F_NEG)
|
||||||
{
|
{
|
||||||
ans = 1;
|
ans = 1;
|
||||||
if (!dryrun)
|
if (!dryrun)
|
||||||
{
|
{
|
||||||
log_query(crecp->flags, name, NULL, 0);
|
log_query(crecp->flags, name, NULL, 0, NULL, 0);
|
||||||
auth = 0;
|
auth = 0;
|
||||||
if (crecp->flags & F_NXDOMAIN)
|
if (crecp->flags & F_NXDOMAIN)
|
||||||
nxdomain = 1;
|
nxdomain = 1;
|
||||||
@@ -1009,7 +1100,8 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
|||||||
|
|
||||||
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
if (!(crecp->flags & (F_HOSTS | F_DHCP)))
|
||||||
auth = 0;
|
auth = 0;
|
||||||
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr, 0);
|
log_query(crecp->flags & ~F_REVERSE, name, &crecp->addr.addr,
|
||||||
|
0, daemon->addn_hosts, crecp->uid);
|
||||||
|
|
||||||
/* copy question as first part of answer (use compression) */
|
/* copy question as first part of answer (use compression) */
|
||||||
PUTSHORT(nameoffset | 0xc000, ansp);
|
PUTSHORT(nameoffset | 0xc000, ansp);
|
||||||
@@ -1040,8 +1132,8 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
|||||||
ans = 1;
|
ans = 1;
|
||||||
if (!dryrun)
|
if (!dryrun)
|
||||||
{
|
{
|
||||||
ansp = add_text_record(nameoffset, ansp, daemon->local_ttl, 1, T_MX,
|
ansp = add_text_record(header, nameoffset, ansp, daemon->local_ttl, 1, T_MX,
|
||||||
mx->mxtarget ? mx->mxtarget : daemon->mxtarget);
|
mx->mxtarget ? mx->mxtarget : daemon->mxtarget, NULL);
|
||||||
anscount++;
|
anscount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1051,8 +1143,8 @@ int answer_request(HEADER *header, char *limit, unsigned int qlen, struct daemon
|
|||||||
ans = 1;
|
ans = 1;
|
||||||
if (!dryrun)
|
if (!dryrun)
|
||||||
{
|
{
|
||||||
ansp = add_text_record(nameoffset, ansp, daemon->local_ttl, 1, T_MX,
|
ansp = add_text_record(header, nameoffset, ansp, daemon->local_ttl, 1, T_MX,
|
||||||
(daemon->options & OPT_SELFMX) ? name : daemon->mxtarget);
|
(daemon->options & OPT_SELFMX) ? name : daemon->mxtarget, NULL);
|
||||||
anscount++;
|
anscount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+234
-159
@@ -57,12 +57,14 @@
|
|||||||
static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt, int len, unsigned int val);
|
static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt, int len, unsigned int val);
|
||||||
static unsigned char *option_end(unsigned char *p, unsigned char *end, struct dhcp_packet *start);
|
static unsigned char *option_end(unsigned char *p, unsigned char *end, struct dhcp_packet *start);
|
||||||
static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string);
|
static unsigned char *option_put_string(unsigned char *p, unsigned char *end, int opt, char *string);
|
||||||
static void bootp_option_put(struct dhcp_packet *mess, char *filename, char *sname);
|
static void bootp_option_put(struct dhcp_packet *mess,
|
||||||
|
struct dhcp_boot *boot_opts, struct dhcp_netid *netids);
|
||||||
static int option_len(unsigned char *opt);
|
static int option_len(unsigned char *opt);
|
||||||
static void *option_ptr(unsigned char *opt);
|
static void *option_ptr(unsigned char *opt);
|
||||||
static struct in_addr option_addr(unsigned char *opt);
|
static struct in_addr option_addr(unsigned char *opt);
|
||||||
static unsigned int option_uint(unsigned char *opt, int size);
|
static unsigned int option_uint(unsigned char *opt, int size);
|
||||||
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string);
|
static void log_packet(char *type, struct in_addr *addr, unsigned char *hwaddr, char *interface, char *string);
|
||||||
|
static int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool);
|
||||||
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type);
|
static unsigned char *option_find(struct dhcp_packet *mess, int size, int opt_type);
|
||||||
static unsigned char *do_req_options(struct dhcp_context *context,
|
static unsigned char *do_req_options(struct dhcp_context *context,
|
||||||
unsigned char *p, unsigned char *end,
|
unsigned char *p, unsigned char *end,
|
||||||
@@ -80,11 +82,12 @@ static int have_config(struct dhcp_config *config, unsigned int mask)
|
|||||||
|
|
||||||
int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_name, unsigned int sz, time_t now)
|
int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_name, unsigned int sz, time_t now)
|
||||||
{
|
{
|
||||||
struct dhcp_context *context;
|
struct dhcp_context *context, *context_tmp;
|
||||||
unsigned char *opt, *clid;
|
unsigned char *opt, *clid = NULL;
|
||||||
struct dhcp_lease *lease, *ltmp;
|
struct dhcp_lease *lease, *ltmp;
|
||||||
struct dhcp_vendor *vendor;
|
struct dhcp_vendor *vendor;
|
||||||
int clid_len;
|
struct dhcp_netid_list *id_list;
|
||||||
|
int clid_len = 0, ignore = 0;
|
||||||
struct dhcp_packet *mess = &daemon->dhcp_packet->data;
|
struct dhcp_packet *mess = &daemon->dhcp_packet->data;
|
||||||
unsigned char *p = mess->options + sizeof(u32); /* skip cookie */
|
unsigned char *p = mess->options + sizeof(u32); /* skip cookie */
|
||||||
unsigned char *end = (unsigned char *)(daemon->dhcp_packet + 1);
|
unsigned char *end = (unsigned char *)(daemon->dhcp_packet + 1);
|
||||||
@@ -139,6 +142,15 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
|||||||
/* Check for RFC3011 subnet selector */
|
/* Check for RFC3011 subnet selector */
|
||||||
if ((opt = option_find(mess, sz, OPTION_SUBNET_SELECT)))
|
if ((opt = option_find(mess, sz, OPTION_SUBNET_SELECT)))
|
||||||
subnet_addr = option_addr(opt);
|
subnet_addr = option_addr(opt);
|
||||||
|
|
||||||
|
/* If there is no client identifier option, use the hardware address */
|
||||||
|
if ((opt = option_find(mess, sz, OPTION_CLIENT_ID)))
|
||||||
|
{
|
||||||
|
clid = option_ptr(opt);
|
||||||
|
clid_len = option_len(opt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
clid = mess->chaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Determine network for this packet. If the machine has an address already, and we don't have
|
/* Determine network for this packet. If the machine has an address already, and we don't have
|
||||||
@@ -148,12 +160,25 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
|||||||
subnet_addr.s_addr ? subnet_addr :
|
subnet_addr.s_addr ? subnet_addr :
|
||||||
(mess->giaddr.s_addr ? mess->giaddr :
|
(mess->giaddr.s_addr ? mess->giaddr :
|
||||||
(mess->ciaddr.s_addr ? mess->ciaddr : iface_addr));
|
(mess->ciaddr.s_addr ? mess->ciaddr : iface_addr));
|
||||||
|
|
||||||
for (context = daemon->dhcp; context; context = context->next)
|
/* More than one context may match, we build a chain of them all on ->current
|
||||||
if (context->netmask.s_addr &&
|
Note that if netmasks, netid or lease times don't match, odd things may happen. */
|
||||||
is_same_net(addr, context->start, context->netmask) &&
|
|
||||||
is_same_net(addr, context->end, context->netmask))
|
for (context = NULL, context_tmp = daemon->dhcp; context_tmp; context_tmp = context_tmp->next)
|
||||||
break;
|
if (context_tmp->netmask.s_addr &&
|
||||||
|
is_same_net(addr, context_tmp->start, context_tmp->netmask) &&
|
||||||
|
is_same_net(addr, context_tmp->end, context_tmp->netmask))
|
||||||
|
{
|
||||||
|
context_tmp->current = context;
|
||||||
|
context = context_tmp;
|
||||||
|
|
||||||
|
/* start to build netid chain */
|
||||||
|
if (context_tmp->netid.net)
|
||||||
|
{
|
||||||
|
context_tmp->netid.next = netid;
|
||||||
|
netid = &context_tmp->netid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!context)
|
if (!context)
|
||||||
{
|
{
|
||||||
@@ -164,68 +189,68 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
|||||||
}
|
}
|
||||||
|
|
||||||
mess->op = BOOTREPLY;
|
mess->op = BOOTREPLY;
|
||||||
|
|
||||||
/* start to build netid chain */
|
config = find_config(daemon->dhcp_conf, context, clid, clid_len, mess->chaddr, NULL);
|
||||||
if (context->netid.net)
|
|
||||||
{
|
|
||||||
context->netid.next = netid;
|
|
||||||
netid = &context->netid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mess_type == 0)
|
if (mess_type == 0)
|
||||||
{
|
{
|
||||||
/* BOOTP request */
|
/* BOOTP request */
|
||||||
config = find_config(daemon->dhcp_conf, context, NULL, 0, mess->chaddr, NULL);
|
struct dhcp_netid id;
|
||||||
if (have_config(config, CONFIG_ADDR) &&
|
char save = mess->file[128];
|
||||||
!have_config(config, CONFIG_DISABLE) &&
|
struct in_addr *logaddr = NULL;
|
||||||
!lease_find_by_addr(config->addr))
|
|
||||||
|
if (have_config(config, CONFIG_ADDR))
|
||||||
{
|
{
|
||||||
struct dhcp_netid id;
|
logaddr = &config->addr;
|
||||||
char save = mess->file[128];
|
|
||||||
end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
|
|
||||||
mess->yiaddr = config->addr;
|
mess->yiaddr = config->addr;
|
||||||
mess->siaddr = daemon->dhcp_next_server.s_addr ? daemon->dhcp_next_server : iface_addr;
|
if (lease_find_by_addr(config->addr))
|
||||||
if (have_config(config, CONFIG_NAME))
|
message = "address in use";
|
||||||
hostname = config->hostname;
|
|
||||||
if (have_config(config, CONFIG_NETID))
|
|
||||||
{
|
|
||||||
config->netid.next = netid;
|
|
||||||
netid = &config->netid;
|
|
||||||
}
|
|
||||||
/* Match incoming filename field as a netid. */
|
|
||||||
if (mess->file[0])
|
|
||||||
{
|
|
||||||
mess->file[128] = 0; /* ensure zero term. */
|
|
||||||
id.net = mess->file;
|
|
||||||
id.next = netid;
|
|
||||||
netid = &id;
|
|
||||||
}
|
|
||||||
p = do_req_options(context, p, end, NULL, daemon,
|
|
||||||
hostname, iface_addr, netid, subnet_addr);
|
|
||||||
/* must do this after do_req_options since it overwrites filename field. */
|
|
||||||
bootp_option_put(mess, daemon->dhcp_file, daemon->dhcp_sname);
|
|
||||||
p = option_end(p, end, mess);
|
|
||||||
log_packet(NULL, &config->addr, mess->chaddr, iface_name, NULL);
|
|
||||||
mess->file[128] = save;
|
|
||||||
return p - (unsigned char *)mess;
|
|
||||||
}
|
}
|
||||||
return 0;
|
else
|
||||||
|
message = "no address configured";
|
||||||
|
|
||||||
|
if (have_config(config, CONFIG_DISABLE))
|
||||||
|
message = "disabled";
|
||||||
|
|
||||||
|
end = mess->options + 64; /* BOOTP vend area is only 64 bytes */
|
||||||
|
|
||||||
|
if (have_config(config, CONFIG_NAME))
|
||||||
|
hostname = config->hostname;
|
||||||
|
|
||||||
|
if (have_config(config, CONFIG_NETID))
|
||||||
|
{
|
||||||
|
config->netid.next = netid;
|
||||||
|
netid = &config->netid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Match incoming filename field as a netid. */
|
||||||
|
if (mess->file[0])
|
||||||
|
{
|
||||||
|
mess->file[128] = 0; /* ensure zero term. */
|
||||||
|
id.net = mess->file;
|
||||||
|
id.next = netid;
|
||||||
|
netid = &id;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
|
||||||
|
if (match_netid(id_list->list, netid))
|
||||||
|
message = "disabled";
|
||||||
|
|
||||||
|
p = do_req_options(context, p, end, NULL, daemon,
|
||||||
|
hostname, iface_addr, netid, subnet_addr);
|
||||||
|
/* must do this after do_req_options since it overwrites filename field. */
|
||||||
|
mess->siaddr = iface_addr;
|
||||||
|
bootp_option_put(mess, daemon->boot_config, netid);
|
||||||
|
p = option_end(p, end, mess);
|
||||||
|
log_packet(NULL, logaddr, mess->chaddr, iface_name, message);
|
||||||
|
mess->file[128] = save;
|
||||||
|
|
||||||
|
if (message)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return p - (unsigned char *)mess;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If there is no client identifier option, use the hardware address */
|
|
||||||
if ((opt = option_find(mess, sz, OPTION_CLIENT_ID)))
|
|
||||||
{
|
|
||||||
clid = option_ptr(opt);
|
|
||||||
clid_len = option_len(opt);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
clid = mess->chaddr;
|
|
||||||
clid_len = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
config = find_config(daemon->dhcp_conf, context, clid, clid_len, mess->chaddr, NULL);
|
|
||||||
|
|
||||||
if (have_config(config, CONFIG_NAME))
|
if (have_config(config, CONFIG_NAME))
|
||||||
hostname = config->hostname;
|
hostname = config->hostname;
|
||||||
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME)))
|
else if ((opt = option_find(mess, sz, OPTION_HOSTNAME)))
|
||||||
@@ -268,54 +293,51 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
def_time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
|
|
||||||
|
|
||||||
if (have_config(config, CONFIG_NETID))
|
if (have_config(config, CONFIG_NETID))
|
||||||
{
|
{
|
||||||
config->netid.next = netid;
|
config->netid.next = netid;
|
||||||
netid = &config->netid;
|
netid = &config->netid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Theres a chance that carefully chosen data could match the same
|
|
||||||
vendor/user option twice and make a loop in the netid chain. */
|
|
||||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
|
||||||
vendor->used = 0;
|
|
||||||
|
|
||||||
if ((opt = option_find(mess, sz, OPTION_VENDOR_ID)))
|
|
||||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
|
||||||
if (vendor->is_vendor && !vendor->used)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
|
||||||
if (memcmp(vendor->data, option_ptr(opt)+i, vendor->len) == 0)
|
|
||||||
{
|
|
||||||
vendor->used = 1;
|
|
||||||
vendor->netid.next = netid;
|
|
||||||
netid = &vendor->netid;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* user-class options are, according to RFC3004, supposed to contain
|
||||||
|
a set of counted strings. Here we check that this is so (by seeing
|
||||||
|
if the counts are consistent with the overall option length) and if
|
||||||
|
so zero the counts so that we don't get spurious matches between
|
||||||
|
the vendor string and the counts. If the lengths don't add up, we
|
||||||
|
assume that the option is a single string and non RFC3004 compliant
|
||||||
|
and just do the substring match. dhclient provides these broken options. */
|
||||||
|
|
||||||
if ((opt = option_find(mess, sz, OPTION_USER_CLASS)))
|
if ((opt = option_find(mess, sz, OPTION_USER_CLASS)))
|
||||||
{
|
{
|
||||||
unsigned char *ucp = option_ptr(opt);
|
unsigned char *ucp = option_ptr(opt);
|
||||||
int j;
|
int tmp, j;
|
||||||
for (j = 0; j < option_len(opt); j += ucp[j] + 1)
|
for (j = 0; j < option_len(opt); j += ucp[j] + 1);
|
||||||
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
if (j == option_len(opt))
|
||||||
if (!vendor->is_vendor && !vendor->used)
|
for (j = 0; j < option_len(opt); j = tmp)
|
||||||
{
|
{
|
||||||
int i;
|
tmp = j + ucp[j] + 1;
|
||||||
for (i = 0; i <= (ucp[j] - vendor->len); i++)
|
ucp[j] = 0;
|
||||||
if (memcmp(vendor->data, &ucp[j+i+1], vendor->len) == 0)
|
}
|
||||||
{
|
|
||||||
vendor->used = 1;
|
|
||||||
vendor->netid.next = netid;
|
|
||||||
netid = &vendor->netid;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (vendor = daemon->dhcp_vendors; vendor; vendor = vendor->next)
|
||||||
|
if ((opt = option_find(mess, sz, vendor->is_vendor ? OPTION_VENDOR_ID : OPTION_USER_CLASS)))
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for (i = 0; i <= (option_len(opt) - vendor->len); i++)
|
||||||
|
if (memcmp(vendor->data, option_ptr(opt)+i, vendor->len) == 0)
|
||||||
|
{
|
||||||
|
vendor->netid.next = netid;
|
||||||
|
netid = &vendor->netid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if all the netids in the ignore list are present, ignore this client */
|
||||||
|
for (id_list = daemon->dhcp_ignore; id_list; id_list = id_list->next)
|
||||||
|
if (match_netid(id_list->list, netid))
|
||||||
|
ignore = 1;
|
||||||
|
|
||||||
/* Can have setting to ignore the client ID for a particular MAC address or hostname */
|
/* Can have setting to ignore the client ID for a particular MAC address or hostname */
|
||||||
if (have_config(config, CONFIG_NOCLID))
|
if (have_config(config, CONFIG_NOCLID))
|
||||||
{
|
{
|
||||||
@@ -326,10 +348,12 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
|||||||
/* do we have a lease in store? */
|
/* do we have a lease in store? */
|
||||||
lease = lease_find_by_client(clid, clid_len);
|
lease = lease_find_by_client(clid, clid_len);
|
||||||
|
|
||||||
|
def_time = have_config(config, CONFIG_TIME) ? config->lease_time : context->lease_time;
|
||||||
|
|
||||||
if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
|
if ((opt = option_find(mess, sz, OPTION_LEASE_TIME)))
|
||||||
{
|
{
|
||||||
unsigned int req_time = option_uint(opt, 4);
|
unsigned int req_time = option_uint(opt, 4);
|
||||||
|
|
||||||
if (def_time == 0xffffffff ||
|
if (def_time == 0xffffffff ||
|
||||||
(req_time != 0xffffffff && req_time < def_time))
|
(req_time != 0xffffffff && req_time < def_time))
|
||||||
expires_time = renewal_time = req_time;
|
expires_time = renewal_time = req_time;
|
||||||
@@ -392,7 +416,8 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
/* make sure this host gets a different address next time. */
|
/* make sure this host gets a different address next time. */
|
||||||
context->addr_epoch++;
|
for (; context; context = context->current)
|
||||||
|
context->addr_epoch++;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -401,17 +426,19 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
|||||||
(iface_addr.s_addr != option_addr(opt).s_addr))
|
(iface_addr.s_addr != option_addr(opt).s_addr))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
log_packet("RELEASE", &mess->ciaddr, mess->chaddr, iface_name, NULL);
|
|
||||||
|
|
||||||
if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
|
if (lease && lease->addr.s_addr == mess->ciaddr.s_addr)
|
||||||
lease_prune(lease, now);
|
lease_prune(lease, now);
|
||||||
|
else
|
||||||
|
message = "unknown lease";
|
||||||
|
|
||||||
|
log_packet("RELEASE", &mess->ciaddr, mess->chaddr, iface_name, message);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
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 (ignore || have_config(config, CONFIG_DISABLE))
|
||||||
message = "ignored";
|
message = "ignored";
|
||||||
else if (have_config(config, CONFIG_ADDR) &&
|
else if (have_config(config, CONFIG_ADDR) &&
|
||||||
(!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
|
(!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
|
||||||
@@ -428,8 +455,8 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
|||||||
if (message)
|
if (message)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
bootp_option_put(mess, daemon->dhcp_file, daemon->dhcp_sname);
|
mess->siaddr = iface_addr;
|
||||||
mess->siaddr = daemon->dhcp_next_server.s_addr ? daemon->dhcp_next_server : iface_addr;
|
bootp_option_put(mess, daemon->boot_config, netid);
|
||||||
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
|
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPOFFER);
|
||||||
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
|
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
|
||||||
p = option_put(p, end, OPTION_LEASE_TIME, 4, expires_time);
|
p = option_put(p, end, OPTION_LEASE_TIME, 4, expires_time);
|
||||||
@@ -447,9 +474,9 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
|||||||
return p - (unsigned char *)mess;
|
return p - (unsigned char *)mess;
|
||||||
|
|
||||||
case DHCPREQUEST:
|
case DHCPREQUEST:
|
||||||
if (have_config(config, CONFIG_DISABLE))
|
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||||
message = "disabled";
|
return 0;
|
||||||
else if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
|
if ((opt = option_find(mess, sz, OPTION_REQUESTED_IP)))
|
||||||
{
|
{
|
||||||
/* SELECTING or INIT_REBOOT */
|
/* SELECTING or INIT_REBOOT */
|
||||||
mess->yiaddr = option_addr(opt);
|
mess->yiaddr = option_addr(opt);
|
||||||
@@ -466,22 +493,14 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
|||||||
lease_prune(lease, now);
|
lease_prune(lease, now);
|
||||||
lease = NULL;
|
lease = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lease)
|
|
||||||
{
|
|
||||||
if (lease_find_by_addr(mess->yiaddr))
|
|
||||||
message = "address in use";
|
|
||||||
else if (!(lease = lease_allocate(clid, clid_len, mess->yiaddr)))
|
|
||||||
message = "no leases left";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* INIT-REBOOT */
|
/* INIT-REBOOT */
|
||||||
if (!lease)
|
if (!lease && !(daemon->options & OPT_AUTHORITATIVE))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (lease->addr.s_addr != mess->yiaddr.s_addr)
|
if (lease && lease->addr.s_addr != mess->yiaddr.s_addr)
|
||||||
message = "wrong address";
|
message = "wrong address";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -500,31 +519,40 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
|||||||
mess->yiaddr = mess->ciaddr;
|
mess->yiaddr = mess->ciaddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
|
||||||
|
|
||||||
if (!message)
|
if (!message)
|
||||||
{
|
{
|
||||||
struct dhcp_config *addr_config;
|
struct dhcp_config *addr_config;
|
||||||
|
|
||||||
/* If a machine moves networks whilst it has a lease, we catch that here. */
|
/* If a machine moves networks whilst it has a lease, we catch that here. */
|
||||||
if (!is_same_net(mess->yiaddr, context->start, context->netmask))
|
if (!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. */
|
/* Check for renewal of a lease which is outside the allowed range. */
|
||||||
else if (!address_available(context, mess->yiaddr) &&
|
else if (!address_available(context, 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 no longer available";
|
message = "address not available";
|
||||||
|
|
||||||
/* Check if a new static address has been configured. Be very sure that
|
/* 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
|
when the client does DISCOVER, it will get the static address, otherwise
|
||||||
an endless protocol loop will ensue. */
|
an endless protocol loop will ensue. */
|
||||||
|
|
||||||
else if (have_config(config, CONFIG_ADDR) && !lease_find_by_addr(config->addr))
|
else if (have_config(config, CONFIG_ADDR) &&
|
||||||
|
config->addr.s_addr != mess->yiaddr.s_addr &&
|
||||||
|
(!(ltmp = lease_find_by_addr(config->addr)) || ltmp == lease))
|
||||||
message = "static lease available";
|
message = "static lease available";
|
||||||
|
|
||||||
/* Check to see if the address is reserved as a static address for another host */
|
/* Check to see if the address is reserved as a static address for another host */
|
||||||
else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
|
else if ((addr_config = config_find_by_address(daemon->dhcp_conf, mess->yiaddr)) && addr_config != config)
|
||||||
message ="address reserved";
|
message ="address reserved";
|
||||||
}
|
|
||||||
|
|
||||||
log_packet("REQUEST", &mess->yiaddr, mess->chaddr, iface_name, NULL);
|
else if ((ltmp = lease_find_by_addr(mess->yiaddr)) && ltmp != lease)
|
||||||
|
message = "address in use";
|
||||||
|
|
||||||
|
else if (!lease && !(lease = lease_allocate(clid, clid_len, mess->yiaddr)))
|
||||||
|
message = "no leases left";
|
||||||
|
}
|
||||||
|
|
||||||
if (message)
|
if (message)
|
||||||
{
|
{
|
||||||
@@ -534,35 +562,36 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
|||||||
bootp_option_put(mess, NULL, NULL);
|
bootp_option_put(mess, NULL, NULL);
|
||||||
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
|
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPNAK);
|
||||||
p = option_put_string(p, end, OPTION_MESSAGE, message);
|
p = option_put_string(p, end, OPTION_MESSAGE, message);
|
||||||
p = option_end(p, end, mess);
|
|
||||||
mess->flags |= htons(0x8000); /* broadcast */
|
mess->flags |= htons(0x8000); /* broadcast */
|
||||||
return p - (unsigned char *)mess;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
log_packet("ACK", &mess->yiaddr, mess->chaddr, iface_name, hostname);
|
|
||||||
|
|
||||||
lease_set_hwaddr(lease, mess->chaddr);
|
|
||||||
if (hostname)
|
|
||||||
lease_set_hostname(lease, hostname, daemon->domain_suffix);
|
|
||||||
lease_set_expires(lease, renewal_time == 0xffffffff ? 0 : now + (time_t)renewal_time);
|
|
||||||
|
|
||||||
bootp_option_put(mess, daemon->dhcp_file, daemon->dhcp_sname);
|
|
||||||
mess->siaddr = daemon->dhcp_next_server.s_addr ? daemon->dhcp_next_server : iface_addr;
|
|
||||||
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
|
||||||
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
|
|
||||||
p = option_put(p, end, OPTION_LEASE_TIME, 4, renewal_time);
|
|
||||||
if (renewal_time != 0xffffffff)
|
|
||||||
{
|
{
|
||||||
p = option_put(p, end, OPTION_T1, 4, (renewal_time/2) - fuzz);
|
log_packet("ACK", &mess->yiaddr, mess->chaddr, iface_name, hostname);
|
||||||
p = option_put(p, end, OPTION_T2, 4, ((renewal_time * 7)/8) - fuzz);
|
|
||||||
|
lease_set_hwaddr(lease, mess->chaddr);
|
||||||
|
if (hostname)
|
||||||
|
lease_set_hostname(lease, hostname, daemon->domain_suffix);
|
||||||
|
lease_set_expires(lease, renewal_time == 0xffffffff ? 0 : now + (time_t)renewal_time);
|
||||||
|
|
||||||
|
mess->siaddr = iface_addr;
|
||||||
|
bootp_option_put(mess, daemon->boot_config, netid);
|
||||||
|
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||||
|
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
|
||||||
|
p = option_put(p, end, OPTION_LEASE_TIME, 4, renewal_time);
|
||||||
|
if (renewal_time != 0xffffffff)
|
||||||
|
{
|
||||||
|
p = option_put(p, end, OPTION_T1, 4, (renewal_time/2) - fuzz);
|
||||||
|
p = option_put(p, end, OPTION_T2, 4, ((renewal_time * 7)/8) - fuzz);
|
||||||
|
}
|
||||||
|
p = do_req_options(context, p, end, req_options, daemon,
|
||||||
|
hostname, iface_addr, netid, subnet_addr);
|
||||||
}
|
}
|
||||||
p = do_req_options(context, p, end, req_options, daemon,
|
|
||||||
hostname, iface_addr, netid, subnet_addr);
|
|
||||||
p = option_end(p, end, mess);
|
p = option_end(p, end, mess);
|
||||||
return p - (unsigned char *)mess;
|
return p - (unsigned char *)mess;
|
||||||
|
|
||||||
case DHCPINFORM:
|
case DHCPINFORM:
|
||||||
if (have_config(config, CONFIG_DISABLE))
|
if (ignore || have_config(config, CONFIG_DISABLE))
|
||||||
message = "ignored";
|
message = "ignored";
|
||||||
|
|
||||||
log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, message);
|
log_packet("INFORM", &mess->ciaddr, mess->chaddr, iface_name, message);
|
||||||
@@ -570,6 +599,8 @@ int dhcp_reply(struct daemon *daemon, struct in_addr iface_addr, char *iface_nam
|
|||||||
if (message || mess->ciaddr.s_addr == 0)
|
if (message || mess->ciaddr.s_addr == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
mess->siaddr = iface_addr;
|
||||||
|
bootp_option_put(mess, daemon->boot_config, netid);
|
||||||
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
p = option_put(p, end, OPTION_MESSAGE_TYPE, 1, DHCPACK);
|
||||||
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
|
p = option_put(p, end, OPTION_SERVER_IDENTIFIER, INADDRSZ, ntohl(iface_addr.s_addr));
|
||||||
p = do_req_options(context, p, end, req_options, daemon,
|
p = do_req_options(context, p, end, req_options, daemon,
|
||||||
@@ -630,14 +661,35 @@ static unsigned int option_uint(unsigned char *opt, int size)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bootp_option_put(struct dhcp_packet *mess, char *filename, char *sname)
|
static void bootp_option_put(struct dhcp_packet *mess,
|
||||||
|
struct dhcp_boot *boot_opts, struct dhcp_netid *netids)
|
||||||
{
|
{
|
||||||
|
struct dhcp_boot *tmp;
|
||||||
|
|
||||||
|
for (tmp = boot_opts; tmp; tmp = tmp->next)
|
||||||
|
if (match_netid(tmp->netid, netids))
|
||||||
|
break;
|
||||||
|
if (!tmp)
|
||||||
|
/* No match, look for one without a netid */
|
||||||
|
for (tmp = boot_opts; tmp; tmp = tmp->next)
|
||||||
|
if (!tmp->netid)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Do this _after_ the matching above, since in
|
||||||
|
BOOTP mode, one if the things we match is the filename. */
|
||||||
|
|
||||||
memset(mess->sname, 0, sizeof(mess->sname));
|
memset(mess->sname, 0, sizeof(mess->sname));
|
||||||
memset(mess->file, 0, sizeof(mess->file));
|
memset(mess->file, 0, sizeof(mess->file));
|
||||||
if (sname)
|
|
||||||
strncpy(mess->sname, sname, sizeof(mess->sname)-1);
|
if (tmp)
|
||||||
if (filename)
|
{
|
||||||
strncpy(mess->file, filename, sizeof(mess->file)-1);
|
if (tmp->sname)
|
||||||
|
strncpy(mess->sname, tmp->sname, sizeof(mess->sname)-1);
|
||||||
|
if (tmp->file)
|
||||||
|
strncpy(mess->file, tmp->file, sizeof(mess->file)-1);
|
||||||
|
if (tmp->next_server.s_addr)
|
||||||
|
mess->siaddr = tmp->next_server;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt, int len, unsigned int val)
|
static unsigned char *option_put(unsigned char *p, unsigned char *end, int opt, int len, unsigned int val)
|
||||||
@@ -748,20 +800,43 @@ static int in_list(unsigned char *list, int opt)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Is every member of check matched by a member of pool? */
|
||||||
|
static int match_netid(struct dhcp_netid *check, struct dhcp_netid *pool)
|
||||||
|
{
|
||||||
|
struct dhcp_netid *tmp1;
|
||||||
|
|
||||||
|
if (!check)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for (; check; check = check->next)
|
||||||
|
{
|
||||||
|
if (check->net[0] != '#')
|
||||||
|
{
|
||||||
|
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||||
|
if (strcmp(check->net, tmp1->net) == 0)
|
||||||
|
break;
|
||||||
|
if (!tmp1)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
for (tmp1 = pool; tmp1; tmp1 = tmp1->next)
|
||||||
|
if (strcmp((check->net)+1, tmp1->net) == 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
|
static struct dhcp_opt *option_find2(struct dhcp_netid *netid, struct dhcp_opt *opts, int opt)
|
||||||
{
|
{
|
||||||
struct dhcp_opt *tmp;
|
struct dhcp_opt *tmp;
|
||||||
struct dhcp_netid *tmp1;
|
|
||||||
|
|
||||||
for (tmp = opts; tmp; tmp = tmp->next)
|
for (tmp = opts; tmp; tmp = tmp->next)
|
||||||
if (tmp->opt == opt)
|
if (tmp->opt == opt)
|
||||||
{
|
{
|
||||||
if (netid)
|
if (netid)
|
||||||
{
|
{
|
||||||
if (tmp->netid)
|
if (match_netid(tmp->netid, netid))
|
||||||
for (tmp1 = netid; tmp1; tmp1 = tmp1->next)
|
return tmp;
|
||||||
if (strcmp(tmp->netid, tmp1->net) == 0)
|
|
||||||
return tmp;
|
|
||||||
}
|
}
|
||||||
else if (!tmp->netid)
|
else if (!tmp->netid)
|
||||||
return tmp;
|
return tmp;
|
||||||
|
|||||||
+17
@@ -251,3 +251,20 @@ int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask)
|
|||||||
{
|
{
|
||||||
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
return (a.s_addr & mask.s_addr) == (b.s_addr & mask.s_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int retry_send(void)
|
||||||
|
{
|
||||||
|
struct timespec waiter;
|
||||||
|
if (errno == EAGAIN)
|
||||||
|
{
|
||||||
|
waiter.tv_sec = 0;
|
||||||
|
waiter.tv_nsec = 10000;
|
||||||
|
nanosleep(&waiter, NULL);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errno == EINTR)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in new issue
Block a user