Hi,

This patch fix `pfctl` to be able to kill states within a rdomain.
Currently only states in rdomain 0 can be kill when using host or label
because check is done in ioctl DIOCKILLSTATES

sys/net/pf_ioctl.c:
   `psk->psk_rdomain == sk->rdomain`

I used -V like `arp`, `ping`... but it could be done too with
`route -T id exec` and `getrtable()` (don't know which one is the
best here since it related to rdomain and not rtable).

Also `const char *iface` arg was not used in `pfctl_id_kill_states`.

To reproduce the bug:

   # ifconfig pair1 rdomain 1 10.1.1.1/24 up
   # ifconfig pair2 rdomain 2 10.1.1.2/24 up
   # ifconfig pair1 patch pair2
   # route -T 1 exec ping 10.1.1.2

Then start a server

   # route -T2 exec nc -vl 10.1.1.2 4242

And connect to it

   # route -T1 exec nc 10.1.1.2 4242

Display states:

   # pfctl -v -ss
   all tcp (2) 10.1.1.2:4242 <- (2) 10.1.1.1:13194 ESTABLISHED:ESTABLISHED
      [4248582619 + 16384] wscale 3  [1432845864 + 17376] wscale 3
      age 00:00:58, expires in 23:59:05, 3:2 pkts, 174:116 bytes, rule 1

Kill it

   # pfctl -k 10.1.1.2
   killed 0 states from 1 sources and 0 destinations

or

   # pfctl -k 10.1.1.1
   killed 0 states from 1 sources and 0 destinations

But state is still here and connection is still established.

   # pfctl -v -ss
   all tcp (2) 10.1.1.2:4242 <- (2) 10.1.1.1:13194 ESTABLISHED:ESTABLISHED
      [4248582625 + 16384] wscale 3  [1432845864 + 17376] wscale 3
      age 00:04:49, expires in 23:56:29, 4:3 pkts, 226:174 bytes, rule 1

Regards,

--
Bertrand Provost

Index: pfctl.8
===================================================================
RCS file: /cvs/src/sbin/pfctl/pfctl.8,v
retrieving revision 1.165
diff -u -p -r1.165 pfctl.8
--- pfctl.8     15 Jun 2015 08:48:23 -0000      1.165
+++ pfctl.8     24 Jan 2017 21:38:56 -0000
@@ -47,6 +47,7 @@
  .Op Fl S Ar statefile
  .Op Fl s Ar modifier Op Fl R Ar id
  .Op Fl t Ar table Fl T Ar command Op Ar address ...
+.Op Fl V Ar rdomain
  .Op Fl x Ar level
  .Ek
  .Sh DESCRIPTION
@@ -275,6 +276,12 @@ from rules carrying the label
  .Dq foobar :
  .Pp
  .Dl # pfctl -k label -k foobar
+.Pp
+To kill states withing a rdomain (the rdomain of a state is displayed
+in parentheses before the host by pfctl -s states) use
+.Fl V Ar rdomain :
+.Pp
+.Dl # pfctl -V rdomain -k host
  .Pp
  To kill one specific state by its unique state ID
  (as shown by pfctl -s state -vv),
Index: pfctl.c
===================================================================
RCS file: /cvs/src/sbin/pfctl/pfctl.c,v
retrieving revision 1.334
diff -u -p -r1.334 pfctl.c
--- pfctl.c     14 Jan 2016 12:05:51 -0000      1.334
+++ pfctl.c     24 Jan 2017 21:38:56 -0000
@@ -69,9 +69,9 @@ int    pfctl_clear_src_nodes(int, int);
  int    pfctl_clear_states(int, const char *, int);
  void   pfctl_addrprefix(char *, struct pf_addr *);
  int    pfctl_kill_src_nodes(int, const char *, int);
-int     pfctl_net_kill_states(int, const char *, int);
-int     pfctl_label_kill_states(int, const char *, int);
-int     pfctl_id_kill_states(int, const char *, int);
+int     pfctl_net_kill_states(int, const char *, int, int);
+int     pfctl_label_kill_states(int, const char *, int, int);
+int     pfctl_id_kill_states(int, int);
  void   pfctl_init_options(struct pfctl *);
  int    pfctl_load_options(struct pfctl *);
  int    pfctl_load_limit(struct pfctl *, unsigned int, unsigned int);
@@ -512,7 +512,7 @@ pfctl_kill_src_nodes(int dev, const char
  }

  int
-pfctl_net_kill_states(int dev, const char *iface, int opts)
+pfctl_net_kill_states(int dev, const char *iface, int opts, int rdomain)
  {
        struct pfioc_state_kill psk;
        struct addrinfo *res[2], *resp[2];
@@ -531,6 +531,8 @@ pfctl_net_kill_states(int dev, const cha
            sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
                errx(1, "invalid interface: %s", iface);

+       psk.psk_rdomain = rdomain;
+
        pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask);

        if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
@@ -618,7 +620,7 @@ pfctl_net_kill_states(int dev, const cha
  }

  int
-pfctl_label_kill_states(int dev, const char *iface, int opts)
+pfctl_label_kill_states(int dev, const char *iface, int opts, int rdomain)
  {
        struct pfioc_state_kill psk;

@@ -635,6 +637,8 @@ pfctl_label_kill_states(int dev, const c
            sizeof(psk.psk_label))
                errx(1, "label too long: %s", state_kill[1]);

+       psk.psk_rdomain = rdomain;
+
        if (ioctl(dev, DIOCKILLSTATES, &psk))
                err(1, "DIOCKILLSTATES");

@@ -645,7 +649,7 @@ pfctl_label_kill_states(int dev, const c
  }

  int
-pfctl_id_kill_states(int dev, const char *iface, int opts)
+pfctl_id_kill_states(int dev, int opts)
  {
        struct pfioc_state_kill psk;

@@ -2098,6 +2102,7 @@ main(int argc, char *argv[])
        int      opts = 0;
        int      optimize = PF_OPTIMIZE_BASIC;
        int      level;
+       int      rdomain = 0;
        char     anchorname[PATH_MAX];
        int      anchor_wildcard = 0;
        char    *path;
@@ -2109,7 +2114,7 @@ main(int argc, char *argv[])
                usage();

        while ((ch = getopt(argc, argv,
-           "a:dD:eqf:F:ghi:k:K:L:no:Pp:R:rS:s:t:T:vx:z")) != -1) {
+           "a:dD:eqf:F:ghi:k:K:L:no:Pp:R:rS:s:t:T:vV:x:z")) != -1) {
                switch (ch) {
                case 'a':
                        anchoropt = optarg;
@@ -2215,6 +2220,13 @@ main(int argc, char *argv[])
                                opts |= PF_OPT_VERBOSE2;
                        opts |= PF_OPT_VERBOSE;
                        break;
+               case 'V':
+                       rdomain = strtonum(optarg, 0, RT_TABLEID_MAX, &errstr);
+                       if (errstr) {
+                               warnx("Invalid rdomain: %s", errstr);
+                               usage();
+                       }
+                       break;
                case 'x':
                        debugopt = pfctl_lookup_option(optarg, debugopt_list);
                        if (debugopt == NULL) {
@@ -2403,11 +2415,11 @@ main(int argc, char *argv[])
        }
        if (state_killers) {
                if (!strcmp(state_kill[0], "label"))
-                       pfctl_label_kill_states(dev, ifaceopt, opts);
+                       pfctl_label_kill_states(dev, ifaceopt, opts, rdomain);
                else if (!strcmp(state_kill[0], "id"))
-                       pfctl_id_kill_states(dev, ifaceopt, opts);
+                       pfctl_id_kill_states(dev, opts);
                else
-                       pfctl_net_kill_states(dev, ifaceopt, opts);
+                       pfctl_net_kill_states(dev, ifaceopt, opts, rdomain);
        }

        if (src_node_killers)

Reply via email to