]>
git.proxmox.com Git - pve-network.git/blob - src/PVE/Network/SDN/Dhcp/Dnsmasq.pm
1 package PVE
::Network
::SDN
::Dhcp
::Dnsmasq
;
6 use base
qw(PVE::Network::SDN::Dhcp::Plugin);
9 use PVE
::Tools
qw(file_set_contents run_command lock_file);
14 use PVE
::RESTEnvironment
qw(log_warn);
16 my $DNSMASQ_CONFIG_ROOT = '/etc/dnsmasq.d';
17 my $DNSMASQ_DEFAULT_ROOT = '/etc/default';
18 my $DNSMASQ_LEASE_ROOT = '/var/lib/misc';
25 my ($class, $dhcpid, $macdb, $mac, $ip4, $ip6) = @_;
27 my $ethers_file = "$DNSMASQ_CONFIG_ROOT/$dhcpid/ethers";
28 my $ethers_tmp_file = "$ethers_file.tmp";
33 open(my $in, '<', $ethers_file) or die "Could not open file '$ethers_file' $!\n";
34 open(my $out, '>', $ethers_tmp_file) or die "Could not open file '$ethers_tmp_file' $!\n";
38 while (my $line = <$in>) {
40 my $parsed_ip4 = undef;
41 my $parsed_ip6 = undef;
42 my ($parsed_mac, $parsed_ip1, $parsed_ip2) = split(/,/, $line);
45 $parsed_ip4 = $parsed_ip1;
46 $parsed_ip6 = $parsed_ip2;
47 } elsif (Net
::IP
::ip_is_ipv4
($parsed_ip1)) {
48 $parsed_ip4 = $parsed_ip1;
50 $parsed_ip6 = $parsed_ip1;
52 $parsed_ip6 = $1 if $parsed_ip6 && $parsed_ip6 =~ m/\[(\S+)\]/;
55 if (!defined($macdb->{macs
}->{$parsed_mac}) ||
56 ($parsed_ip4 && $macdb->{macs
}->{$parsed_mac}->{'ip4'} && $macdb->{macs
}->{$parsed_mac}->{'ip4'} ne $parsed_ip4) ||
57 ($parsed_ip6 && $macdb->{macs
}->{$parsed_mac}->{'ip6'} && $macdb->{macs
}->{$parsed_mac}->{'ip6'} ne $parsed_ip6)) {
62 if ($parsed_mac eq $mac) {
63 $match = 1 if $ip4 && $parsed_ip4 && $ip4;
64 $match = 1 if $ip6 && $parsed_ip6 && $ip6;
71 my $reservation = $mac;
72 $reservation .= ",$ip4" if $ip4;
73 $reservation .= ",[$ip6]" if $ip6;
74 print $out "$reservation\n";
80 move
$ethers_tmp_file, $ethers_file;
81 chmod 0644, $ethers_file;
84 PVE
::Tools
::lock_file
($ethers_file, 10, $appendFn);
87 warn "Unable to add $mac to the dnsmasq configuration: $@\n";
91 my $service_name = "dnsmasq\@$dhcpid";
92 PVE
::Tools
::run_command
(['systemctl', 'reload', $service_name]) if $reload;
94 #update lease as ip could still be associated to an old removed mac
95 my $bus = Net
::DBus-
>system();
96 my $dnsmasq = $bus->get_service("uk.org.thekelleys.dnsmasq.$dhcpid");
97 my $manager = $dnsmasq->get_object("/uk/org/thekelleys/dnsmasq","uk.org.thekelleys.dnsmasq.$dhcpid");
99 my @hostname = unpack("C*", "*");
100 $manager->AddDhcpLease($ip4, $mac, \
@hostname, undef, 0, 0, 0) if $ip4;
101 # $manager->AddDhcpLease($ip6, $mac, \@hostname, undef, 0, 0, 0) if $ip6;
105 sub configure_subnet
{
106 my ($class, $config, $dhcpid, $vnetid, $subnet_config) = @_;
108 die "No gateway defined for subnet $subnet_config->{id}"
109 if !$subnet_config->{gateway
};
111 my $tag = $subnet_config->{id
};
114 if (ip_is_ipv6
($subnet_config->{network
})) {
115 $option_string = 'option6';
117 $option_string = 'option';
118 push @{$config}, "dhcp-option=tag:$tag,$option_string:router,$subnet_config->{gateway}";
121 push @{$config}, "dhcp-option=tag:$tag,$option_string:dns-server,$subnet_config->{'dhcp-dns-server'}"
122 if $subnet_config->{'dhcp-dns-server'};
126 sub configure_range
{
127 my ($class, $config, $dhcpid, $vnetid, $subnet_config, $range_config) = @_;
129 my $tag = $subnet_config->{id
};
131 my ($zone, $network, $mask) = split(/-/, $tag);
133 if (Net
::IP
::ip_is_ipv4
($network)) {
134 $mask = (2 ** $mask - 1) << (32 - $mask);
135 $mask = join( '.', unpack( "C4", pack( "N", $mask ) ) );
138 push @{$config}, "dhcp-range=set:$tag,$network,static,$mask,infinite";
142 my ($class, $config, $dhcpid, $vnetid, $vnet_config) = @_;
144 return if @{$config} < 1;
146 push @{$config}, "interface=$vnetid";
148 PVE
::Tools
::file_set_contents
(
149 "$DNSMASQ_CONFIG_ROOT/$dhcpid/10-$vnetid.conf",
150 join("\n", @{$config}) . "\n"
154 sub before_configure
{
155 my ($class, $dhcpid) = @_;
157 my $dbus_config = <<DBUSCFG;
158 <!DOCTYPE busconfig PUBLIC
159 "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
160 "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
163 <allow own="uk.org.thekelleys.dnsmasq.$dhcpid"/>
164 <allow send_destination="uk.org.thekelleys.dnsmasq.$dhcpid"/>
166 <policy user="dnsmasq">
167 <allow own="uk.org.thekelleys.dnsmasq.$dhcpid"/>
168 <allow send_destination="uk.org.thekelleys.dnsmasq.$dhcpid"/>
170 <policy context="default">
171 <deny own="uk.org.thekelleys.dnsmasq.$dhcpid"/>
172 <deny send_destination="uk.org.thekelleys.dnsmasq.$dhcpid"/>
177 PVE
::Tools
::file_set_contents
(
178 "/etc/dbus-1/system.d/dnsmasq.$dhcpid.conf",
182 my $config_directory = "$DNSMASQ_CONFIG_ROOT/$dhcpid";
184 mkdir($config_directory, 0755) if !-d
$config_directory;
186 my $default_config = <<CFG;
187 CONFIG_DIR='$config_directory,\*.conf'
188 DNSMASQ_OPTS="--conf-file=/dev/null --enable-dbus=uk.org.thekelleys.dnsmasq.$dhcpid"
191 PVE
::Tools
::file_set_contents
(
192 "$DNSMASQ_DEFAULT_ROOT/dnsmasq.$dhcpid",
196 my $default_dnsmasq_config = <<CFG;
202 dhcp-leasefile=$DNSMASQ_LEASE_ROOT/dnsmasq.$dhcpid.leases
203 dhcp-hostsfile=$config_directory/ethers
204 dhcp-ignore=tag:!known
206 # Send an empty WPAD option. This may be REQUIRED to get windows 7 to behave.
207 dhcp-option=252,"\\n"
209 # Send microsoft-specific option to tell windows to release the DHCP lease
210 # when it shuts down. Note the "i" flag, to tell dnsmasq to send the
211 # value as a four-byte integer - that's what microsoft wants.
212 dhcp-option=vendor:MSFT,2,1i
214 # If a DHCP client claims that its name is "wpad", ignore that.
215 # This fixes a security hole. see CERT Vulnerability VU#598349
216 dhcp-name-match=set:wpad-ignore,wpad
217 dhcp-ignore-names=tag:wpad-ignore
220 PVE
::Tools
::file_set_contents
(
221 "$config_directory/00-default.conf",
222 $default_dnsmasq_config
225 unlink glob "$config_directory/10-*.conf";
228 sub after_configure
{
229 my ($class, $dhcpid) = @_;
231 my $service_name = "dnsmasq\@$dhcpid";
233 PVE
::Tools
::run_command
(['systemctl', 'reload', 'dbus']);
234 PVE
::Tools
::run_command
(['systemctl', 'enable', $service_name]);
235 PVE
::Tools
::run_command
(['systemctl', 'restart', $service_name]);
238 sub before_regenerate
{
241 my $bin_path = "/usr/sbin/dnsmasq";
243 log_warn
("Please install dnsmasq in order to use the DHCP feature!");
247 PVE
::Tools
::run_command
(['systemctl', 'stop', "dnsmasq@*"]);
248 PVE
::Tools
::run_command
(['systemctl', 'disable', 'dnsmasq@']);
251 sub after_regenerate
{