On Fri, Apr 27, 2012 at 12:45:01PM +0100, Stuart Henderson wrote:
> On 2012/04/27 00:51, Lawrence Teo wrote:
> > The diff below fixes pfctl so that it will show the 'authpf/*' anchor
> > as intended:
> 
> This is extremely useful for relayd/ftp-proxy too.

I agree.  I bumped into this bug while writing a custom proxy that uses
'foo/*' anchors, so I think the fix will also help future proxies that
use these anchors.

> > Note that since this diff changes the behavior of
> > "pfctl -a 'foo/*' -sr", it will also change the pfload* regression
> > tests since those tests execute this command:
> > pfctl -o none -a 'regress/*' -gvvsr
> > 
> > If this diff is correct, I would appreciate some guidance from the
> > developers on how to address the pfload* regression tests.
> 
> First problem: -a 'regress/*' used to print anchor "regress",
> and now it _only_ prints sub-anchors. Following diff changes it
> to print the named anchor itself as well as sub-anchors, which
> is how I would expect recursive printing to work.

Thank you for catching this!  I agree that the behavior shown by your
revised diff is much closer to what users expect.

> If '-s l' and maybe also '-s a' get the same treatment then I think
> I'll be OK with this going in.

Here's a revised diff that makes it work with '-s l'.

Index: pfctl.c
===================================================================
RCS file: /cvs/src/sbin/pfctl/pfctl.c,v
retrieving revision 1.310
diff -u -p pfctl.c
--- pfctl.c     18 Apr 2012 14:42:17 -0000      1.310
+++ pfctl.c     28 Apr 2012 02:18:05 -0000
@@ -864,6 +864,7 @@ pfctl_show_rules(int dev, char *path, int opts, enum p
                switch (format) {
                case PFCTL_SHOW_LABELS:
                        if (pr.rule.label[0]) {
+                               INDENT(depth, !(opts & PF_OPT_VERBOSE));
                                printf("%s %llu %llu %llu %llu"
                                    " %llu %llu %llu %llu\n",
                                    pr.rule.label,
@@ -1937,6 +1938,7 @@ main(int argc, char *argv[])
        int      optimize = PF_OPTIMIZE_BASIC;
        int      level;
        char     anchorname[MAXPATHLEN];
+       int      anchor_wildcard = 0;
        char    *path;
        char    *lfile = NULL, *sfile = NULL;
        const char *errstr;
@@ -2097,9 +2099,10 @@ main(int argc, char *argv[])
                int len = strlen(anchoropt);
 
                if (anchoropt[len - 1] == '*') {
-                       if (len >= 2 && anchoropt[len - 2] == '/')
+                       if (len >= 2 && anchoropt[len - 2] == '/') {
                                anchoropt[len - 2] = '\0';
-                       else
+                               anchor_wildcard = 1;
+                       } else
                                anchoropt[len - 1] = '\0';
                        opts |= PF_OPT_RECURSE;
                }
@@ -2137,11 +2140,19 @@ main(int argc, char *argv[])
                        pfctl_load_fingerprints(dev, opts);
                        pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES,
                            anchorname, 0, 0, shownr);
+                       if (anchor_wildcard)
+                               pfctl_show_rules(dev, path, opts,
+                                   PFCTL_SHOW_RULES, anchorname, 0,
+                                   anchor_wildcard, shownr);
                        break;
                case 'l':
                        pfctl_load_fingerprints(dev, opts);
                        pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS,
                            anchorname, 0, 0, shownr);
+                       if (anchor_wildcard)
+                               pfctl_show_rules(dev, path, opts,
+                                   PFCTL_SHOW_LABELS, anchorname, 0,
+                                   anchor_wildcard, shownr);
                        break;
                case 'q':
                        pfctl_show_altq(dev, ifaceopt, opts,

I'm not sure what's the best way to handle '-s a' yet, since I think
users typically run 'pfctl -s a' to find out everything about their
full ruleset instead of specific anchors.  Applying a recursive
behavior on '-s a' also seems complex.  Do you have any thoughts on
what a command like "pfctl -a 'foo/*' -s a" should show?

> Next problem, and this is not directly relating to the above diff
> to fix printing, but it is highlighted by it: the anchors added by
> pfload regression tests are never emptied. Running 'make pfload-update'
> results in the same crap being added to lots of the files it produces.
> So it seems the -Fr / -Fa flush commands also need teaching how to work
> recursively and the regress Makefile changing to use this.
> 
> If I bypass this problem by temporarily adjusting pfload${n}-update
> to use individual anchor names per rule (rather than '-a regress'
> I used '-a foo$n') I see that with the above diff an additional
> summary is printed each time, each rule-printing gets these additional
> lines:
> 
>    [ Skip steps: i=end d=end r=end f=end p=end sa=end da=end sp=end dp=end ]
>    [ queue: qname= qid=0 pqname= pqid=0 ]
>    [ Evaluations: 0         Packets: 0         Bytes: 0           States: 0   
>   ]
> +  [ Skip steps: i=0 d=0 r=0 f=0 p=0 sa=0 da=0 sp=0 dp=0 ]
> +  [ queue: qname= qid=0 pqname= pqid=0 ]
> +  [ Evaluations: 0         Packets: 0         Bytes: 0           States: 0   
>   ]
> 
> This is slightly ugly but I don't think it's a major problem.
> 
> also spotted, though I don't know if it's a problem, I don't see
> a way to remove an anchor once created. But then again, I don't see
> why you don't end up with hundreds of old ftp-proxy anchors showing
> up...so not sure what's going on here.

I think ftp-proxy removes its sub-anchors by committing empty rulesets
into them.  The code is in end_session() in
src/usr.sbin/ftp-proxy/ftp-proxy.c.

I tried to replicate that behavior on the shell by telling pfctl to
load /dev/null into the sub-anchor.  It seems to work, though I have
not tested it thoroughly.  Here's how my test session looks like when
I created a simple testanchor/xyz sub-anchor and then removed it
completely:

# pfctl -sr
anchor "testanchor/*" all
# pfctl -a 'testanchor/*' -sr
# echo pass | pfctl -a 'testanchor/xyz' -f -
# pfctl -a '*' -sr                         
anchor "testanchor/*" all {
  anchor "xyz" all {
    pass all flags S/SA
  }
}
# pfctl -a 'testanchor/xyz' -f /dev/null
# pfctl -a '*' -sr                    
anchor "testanchor/*" all {
}

Lawrence

Reply via email to