aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xacmeman77
-rw-r--r--lib/App/Acmeman/Source/Pound.pm73
2 files changed, 118 insertions, 32 deletions
diff --git a/acmeman b/acmeman
index 1520dcc..5225751 100755
--- a/acmeman
+++ b/acmeman
@@ -292,22 +292,22 @@ matching algorithm. If serving several host names, use the B<Match OR> block.
=back
After these two steps, your listener section will look like:
ListenHTTP
- Address 0.0.0.0
- Port 80
- ACME "/var/lib/pound/acme/.well-known/acme-challenge"
+ Address 0.0.0.0
+ Port 80
+ ACME "/var/lib/pound/acme/.well-known/acme-challenge"
Service
Match OR
Host "www.example.org"
Host "example.org"
End
- ...
- End
+ ...
+ End
End
=over 4
=item 3. Configure B<acmeman>. Use the B<pound> source and make sure
B<rootdir> is synchronized with the B<ACME> statement in F<pound.cfg>, as
@@ -820,13 +820,14 @@ issued. The I<HOST> will be used as its B<CN>. All the domain names read
from the input files will form the list of its alternative names.
=head2 pound
[core]
source = pound [--config=FILE] [--host=HOST] \
- [--type=http|https] [--listener=NAME]
+ [--type=http|https] [--listener=NAME] \
+ [--comment=TEXT]
Domain names will be read from I<FILE> or, if it is not supplied, from
the default B<pound> configuration file F</etc/pound.cfg>. By default,
the module will scan B<ListenHTTP> sections that have B<ACME> directive
set and will extract domain names from B<Host> statements in its services.
@@ -838,12 +839,68 @@ enable scanning both types of listeners, use B<--type=http --type=https>.
When scanning B<ListenHTTPS>, the module collects all domain names that
appear as arguments to B<Host> statements.
If B<--listener> option is used, module will scan only the named listener.
To select multiple listeners, use several B<--listener> options.
+The B<--comment> option defines a text, which, when appearing at the
+start of a comment line, enables host name collection. Such I<pragmatical>
+comments may appear anywhere within listener and service sections and their
+scope is limited by the corresponding section. When this option is used,
+host collection is disabled by default. For example, assuming
+B<--comment=acme>, the following configuration snippet (with irrelevant
+statements replaced by ellipses) will result in issuing certificate for
+C<example.org> and C<www.example.org>:
+
+ ListenerHTTP
+ # acme
+ Service
+ Host -exact "example.org"
+ ...
+ End
+
+ Service
+ Host -exact "www.example.org"
+ ...
+ End
+ End
+
+In contrast, when processing the following snippet, B<acmeman> will issue
+certificate for C<example.org> only:
+
+ ListenerHTTP
+ Service
+ # acme
+ Host -exact "example.org"
+ ...
+ End
+
+ Service
+ Host -exact "www.example.org"
+ ...
+ End
+ End
+
+Furthermore, using B<no-I<TEXT>> at the start of a comment cancels
+the effect of the previous pragmatic comment. This can be used for
+better control of host selection:
+
+ ListenerHTTP
+ Service
+ Match OR
+ # acme
+ Host -exact "example.org"
+ Host -exact "www.example.org"
+ # no-acme
+ Host -exact "test.example.org"
+ End
+ ...
+ End
+ End
+
+
If the B<--host> (B<-h>) option is used, only one certificate will be
issued. The I<HOST> will be used as its B<CN>. All the domain names read
from the input files will form the list of its alternative names.
Notice the limitations of this module:
@@ -853,15 +910,15 @@ Notice the limitations of this module:
When declaring multiple hosts it might be tempting to use regular expression
matching instead. Due to obvious reasons, the module won't be able to
cope with it. When declaring multiple hosts, always use the B<Match OR>
section, like this:
Match OR
- Host "host1"
- Host "host2"
- Host "host3"
+ Host -exact "host1"
+ Host -exact "host2"
+ Host -exact "host3"
End
=item 2. These B<Host> statements (or the enclosing B<Match OR> section)
must be declared in the B<Service> sections located under the B<ListenHTTP>
or B<ListenHTTPS> sections. Global B<Service> sections are not scanned.
@@ -964,8 +1021,8 @@ Sergey Poznyakoff <gray@gnu.org>
=head1 LICENSE
GPLv3+: GNU GPL version 3 or later, see L<http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
-
+
=cut
diff --git a/lib/App/Acmeman/Source/Pound.pm b/lib/App/Acmeman/Source/Pound.pm
index f02d128..daf5373 100644
--- a/lib/App/Acmeman/Source/Pound.pm
+++ b/lib/App/Acmeman/Source/Pound.pm
@@ -8,22 +8,27 @@ use App::Acmeman::Log qw(:all);
sub new {
my $class = shift;
my $cfgname = '/etc/pound.cfg';
my $host;
my @listener;
my @types;
+ my $comment;
GetOptionsFromArray(\@_,
'config|f=s' => \$cfgname,
'host|h=s' => \$host,
'listener=s@' => \@listener,
- 'type=s@' => \@types
+ 'type=s@' => \@types,
+ 'comment=s' => \$comment
);
my $self = bless {
cfgname => $cfgname,
host => $host,
}, $class;
+ if ($comment) {
+ $self->{comment} = qr($comment)
+ }
if (@listener) {
$self->{listener} = { map { $_ => 1 } @listener };
}
if (!@types) {
@types = qw(http)
}
@@ -86,61 +91,72 @@ sub scan {
ST_SERVICE => 2,
ST_EXPEND => 3,
ST_MATCH => 4,
ST_IGNORE => 5
};
my $state = ST_INIT;
- my $acme = 0;
- my $coalesce = 0;
+ my $acme;
+ my @collect_state;
my @lsthosts;
my @srvhosts;
my $endcnt;
while (<$fh>) {
chomp;
- s/#.*//;
+
s/^\s+//;
+ if ($self->{comment} && m{#\s*(no-)?$self->{comment}}) {
+ if (@collect_state) {
+ my $hint = 1;
+ if ($1) {
+ $hint = 0;
+ }
+ debug(4, "$self->{cfgname}:$.: hint=$hint");
+ $collect_state[$#collect_state] = $hint;
+ }
+ }
+
+ s/#.*//;
next if (/^$/);
+
if ($state == ST_INIT) {
if (/^ListenHTTP(?:(?<s>S)?\s+"(?<name>.*)"\s*)?$/i) {
if ($self->lstn_ok($+{s}, $+{name})) {
debug(4, "$self->{cfgname}:$.: listener");
$state = ST_LISTENER;
+ $acme = 0;
if (defined($+{s}) && uc($+{s}) eq 'S') {
$acme = 1;
- $coalesce = 1;
}
+ push @collect_state, !defined($self->{comment});
@lsthosts = ();
} else {
$state = ST_IGNORE;
}
}
} elsif ($state == ST_LISTENER) {
- debug(4, "$self->{cfgname}:$.: service");
if (/^Service(?:\s+".*"\s*)?$/i) {
+ debug(4, "$self->{cfgname}:$.: service");
+ push @collect_state, $collect_state[$#collect_state];
$state = ST_SERVICE;
@srvhosts = ();
} elsif (/^ACME\s/i) {
$acme = 1;
} elsif (/^End$/i) {
- if ($acme) {
+ debug(4, "$self->{cfgname}:$.: listener ends");
+ pop @collect_state;
+ if ($acme && @lsthosts) {
if ($self->{host}) {
$self->define_alias($self->{host}, map { @$_ } @lsthosts);
- } elsif ($coalesce) {
- my @hosts = (map {@$_} @lsthosts);
- my $cn = shift @hosts;
- $self->define_domain($cn);
- $self->define_alias($cn, @hosts) if @hosts;
} else {
foreach my $hosts (@lsthosts) {
my $cn = shift @{$hosts};
$self->define_domain($cn);
$self->define_alias($cn, @{$hosts}) if @{$hosts};
}
}
}
-
$state = ST_INIT;
}
} elsif ($state == ST_IGNORE) {
if (/^Service(?:\s+".*"\s*)?$/i || /^Match/i || /^Rewrite/i) {
$endcnt++;
} elsif (/^End$/i) {
@@ -149,42 +165,55 @@ sub scan {
} else {
$endcnt--;
}
}
} elsif ($state == ST_SERVICE) {
if (s/^Host\s+//i) {
- if (my @hosts = $self->host($_)) {
- debug(3, "$self->{cfgname}:$.: hosts ".join(',', @hosts));
- push @srvhosts, @hosts;
+ if ($collect_state[$#collect_state]) {
+ if (my @hosts = $self->host($_)) {
+ debug(3, "$self->{cfgname}:$.: hosts ".join(',', @hosts));
+ push @srvhosts, @hosts;
+ }
}
} elsif (/^Backend/i) {
$state = ST_EXPEND;
} elsif (/^Match/i) {
$state = ST_MATCH;
} elsif (/^End$/i) {
$state = ST_LISTENER;
- push @lsthosts, [ @srvhosts ] if (@srvhosts);
+ if (@srvhosts) {
+ push @lsthosts, [ @srvhosts ];
+ }
+ pop @collect_state;
+ debug(4, "$self->{cfgname}:$.: service ends");
}
} elsif ($state == ST_MATCH) {
if (s/^Host\s+//i) {
- if (my @hosts = $self->host($_)) {
- debug(3, "$self->{cfgname}:$.: hosts ".join(',', @hosts));
- push @srvhosts, @hosts;
+ if ($collect_state[$#collect_state]) {
+ if (my @hosts = $self->host($_)) {
+ debug(3, "$self->{cfgname}:$.: hosts ".join(',', @hosts));
+ push @srvhosts, @hosts;
+ }
}
} elsif (/^End$/i) {
$state = ST_SERVICE;
}
} elsif ($state == ST_EXPEND) {
if (/^End$/i) {
$state = ST_SERVICE;
}
}
}
close $fh;
- # FIXME: check state
- #debug(1, "$.: end state $state");
+
+ if (@collect_state) {
+ error("$self->{cfgname}: parsing failed, " . (0+@collect_state) .
+ " states remained on stack");
+ return 0
+ }
+
return 1;
}
sub dequote {
my ($self, $arg) = @_;
if (defined($arg) && $arg =~ s{^\s*"(.*?)"\s*$}{$1}) {

Return to:

Send suggestions and report system problems to the System administrator.