diff --git a/CHANGELOG b/CHANGELOG index e4304ff..26cfcf6 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1213,4 +1213,43 @@ version 2.15 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. + diff --git a/FAQ b/FAQ index 67d3889..dceb8d1 100644 --- a/FAQ +++ b/FAQ @@ -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 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. + + diff --git a/contrib/dynamic-dnsmasq/dynamic-dnsmasq.pl b/contrib/dynamic-dnsmasq/dynamic-dnsmasq.pl new file mode 100755 index 0000000..3c4a1f1 --- /dev/null +++ b/contrib/dynamic-dnsmasq/dynamic-dnsmasq.pl @@ -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 = ; + 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 ( ) { + 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 = ; + 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,"; + close(FILE); + if ( (split(/\0/,$cmdline))[0] =~ /dnsmasq/ ) { + kill(1, $process); + } + } + } + } + return(0); +} diff --git a/dnsmasq-rh.spec b/dnsmasq-rh.spec index 3594e3f..3652a24 100644 --- a/dnsmasq-rh.spec +++ b/dnsmasq-rh.spec @@ -5,7 +5,7 @@ ############################################################################### Name: dnsmasq -Version: 2.15 +Version: 2.16 Release: 1 Copyright: GPL Group: System Environment/Daemons diff --git a/dnsmasq-suse.spec b/dnsmasq-suse.spec index b379e0a..c1ca8a0 100644 --- a/dnsmasq-suse.spec +++ b/dnsmasq-suse.spec @@ -5,7 +5,7 @@ ############################################################################### Name: dnsmasq -Version: 2.15 +Version: 2.16 Release: 1 Copyright: GPL Group: Productivity/Networking/DNS/Servers diff --git a/dnsmasq.8 b/dnsmasq.8 index 907b3ff..b2bec2e 100644 --- a/dnsmasq.8 +++ b/dnsmasq.8 @@ -34,8 +34,8 @@ Don't read the hostnames in /etc/hosts. .TP .B \-H, --addn-hosts= 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 -given. +only the specified file. This option may be repeated for more than one +additional hosts file. .TP .B \-T, --local-ttl=