Hi,

I wrote a patch to program a very simple steganographic buffer into the pf
firewalling system.  However I'm running into a problem.  It turns out at
least to me, that pf's scrub gets called twice on output.  Why is this?

I'm making my patch available and the program to program the buffer into
pf.  It's ugly but I don't see a need to commit this ever, it's a small
personal project of mine...

When you see the code you'll see that when ip_stegid() gets called it 
increments the buffer offset by two, I'm missing data.  When I program
the buffer with '11223344556677889900AABBCCDDEEFF', in a tcpdump I see this:

20:33:13.120728 192.168.65.2 > 192.168.179.1: icmp: echo request (id:7195 
seq:7) [icmp cksum ok] (ttl 255, id 12593, len 84)
  0000: 4500 0054 3131 0000 ff01 1523 c0a8 4102  E..T11.....#..A.
  0010: c0a8 b301 0800 a4e7 7195 0007 2994 298a  ........q...).).
20:33:14.120730 192.168.65.2 > 192.168.179.1: icmp: echo request (id:7195 
seq:8) [icmp cksum ok] (ttl 255, id 13107, len 84)
  0000: 4500 0054 3333 0000 ff01 1321 c0a8 4102  E..T33.....!..A.
  0010: c0a8 b301 0800 7b05 7195 0008 2994 298a  ......{.q...).).
20:33:15.120732 192.168.65.2 > 192.168.179.1: icmp: echo request (id:7195 
seq:9) [icmp cksum ok] (ttl 255, id 13621, len 84)
  0000: 4500 0054 3535 0000 ff01 111f c0a8 4102  E..T55........A.
  0010: c0a8 b301 0800 c128 7195 0009 2994 298a  .......(q...).).
20:33:16.120737 192.168.65.2 > 192.168.179.1: icmp: echo request (id:7195 
seq:10) [icmp cksum ok] (ttl 255, id 14135, len 84)
  0000: 4500 0054 3737 0000 ff01 0f1d c0a8 4102  E..T77........A.
  0010: c0a8 b301 0800 9580 7195 000a 2994 298a  ........q...).).
20:33:17.120736 192.168.65.2 > 192.168.179.1: icmp: echo request (id:7195 
seq:11) [icmp cksum ok] (ttl 255, id 14649, len 84)
  0000: 4500 0054 3939 0000 ff01 0d1b c0a8 4102  E..T99........A.
  0010: c0a8 b301 0800 0a73 7195 000b 2994 298a  .......sq...).).

So 11, 33, 55, 77, 99... exactly every 2nd value gets skipped.

For steganography this would suck as I'm trying to relay a message from one
computer to another and if only half arrives and it can't reassemble it it's
no good.  I'm not saying it has to be like TCP but some reliability would be
nice.  I'm guessing it's because ip_stegid() gets called twice per packet that
is outgoing.  Here is my rule btw for this:

beta# pfctl -srules|grep steg
pass out on vxlan0 inet proto icmp from any to 192.168.179.1 scrub (steg-id)

There was only 1 pinger on 192.168.179.1, I'm the only user on this box and
I should have seen this in the tcpdump.

Anyhow before I confuse everyone I'll just dump the code.  The patches to the
OS first and then the small program to ioctl the buffer into the kernel.

Regards,
-peter


Index: sbin/pfctl/parse.y
===================================================================
RCS file: /cvs/src/sbin/pfctl/parse.y,v
retrieving revision 1.670
diff -u -p -u -r1.670 parse.y
--- sbin/pfctl/parse.y  8 Feb 2018 09:15:46 -0000       1.670
+++ sbin/pfctl/parse.y  17 Mar 2018 19:45:13 -0000
@@ -273,6 +273,7 @@ struct filter_opts {
        int                      settos;
        int                      randomid;
        int                      max_mss;
+       int                      stegid;
 
        /* route opts */
        struct {
@@ -302,6 +303,7 @@ struct scrub_opts {
        int                     settos;
        int                     randomid;
        int                     reassemble_tcp;
+       int                     stegid;
 } scrub_opts;
 
 struct node_sc {
@@ -472,7 +474,7 @@ int parseport(char *, struct range *r, i
 %token NOROUTE URPFFAILED FRAGMENT USER GROUP MAXMSS MAXIMUM TTL TOS DROP TABLE
 %token REASSEMBLE ANCHOR SYNCOOKIES
 %token SET OPTIMIZATION TIMEOUT LIMIT LOGINTERFACE BLOCKPOLICY RANDOMID
-%token SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID
+%token SYNPROXY FINGERPRINTS NOSYNC DEBUG SKIP HOSTID 
 %token ANTISPOOF FOR INCLUDE MATCHES
 %token BITMASK RANDOM SOURCEHASH ROUNDROBIN LEASTSTATES STATICPORT PROBABILITY
 %token WEIGHT BANDWIDTH FLOWS QUANTUM
@@ -482,6 +484,7 @@ int parseport(char *, struct range *r, i
 %token MAXSRCCONN MAXSRCCONNRATE OVERLOAD FLUSH SLOPPY PFLOW MAXPKTRATE
 %token TAGGED TAG IFBOUND FLOATING STATEPOLICY STATEDEFAULTS ROUTE
 %token DIVERTTO DIVERTREPLY DIVERTPACKET NATTO AFTO RDRTO RECEIVEDON NE LE GE
+%token STEGID
 %token <v.string>              STRING
 %token <v.number>              NUMBER
 %token <v.i>                   PORTBINARY
@@ -1085,6 +1088,13 @@ scrub_opt        : NODF  {
                        }
                        scrub_opts.randomid = 1;
                }
+               | STEGID {
+                       if (scrub_opts.stegid) {
+                               yyerror("steg-id cannot be respecified");
+                               YYERROR;
+                       }
+                       scrub_opts.stegid = 1;
+               }
                ;
 
 antispoof      : ANTISPOOF logquick antispoof_ifspc af antispoof_opts {
@@ -1588,6 +1598,8 @@ pfrule            : action dir logquick interface 
                                r.scrub_flags |= PFSTATE_NODF;
                        if ($8.randomid)
                                r.scrub_flags |= PFSTATE_RANDOMID;
+                       if ($8.stegid)
+                               r.scrub_flags |= PFSTATE_STEG;
                        if ($8.minttl)
                                r.min_ttl = $8.minttl;
                        if ($8.max_mss)
@@ -2147,6 +2159,7 @@ filter_opt        : USER uids {
                        filter_opts.minttl = $3.minttl;
                        filter_opts.randomid = $3.randomid;
                        filter_opts.max_mss = $3.maxmss;
+                       filter_opts.stegid = $3.stegid;
                        if ($3.reassemble_tcp)
                                filter_opts.marker |= FOM_SCRUB_TCP;
                        filter_opts.marker |= $3.marker;
@@ -4130,7 +4143,7 @@ rule_consistent(struct pf_rule *r, int a
                problems++;
        }
        if (r->af == AF_INET6 && (r->scrub_flags &
-           (PFSTATE_NODF|PFSTATE_RANDOMID))) {
+           (PFSTATE_NODF|PFSTATE_RANDOMID|PFSTATE_STEG))) {
                yyerror("address family inet6 does not support scrub options "
                    "no-df, random-id");
                problems++;
@@ -5202,6 +5215,7 @@ lookup(char *s)
                { "state-defaults",     STATEDEFAULTS},
                { "state-policy",       STATEPOLICY},
                { "static-port",        STATICPORT},
+               { "steg-id",            STEGID},
                { "sticky-address",     STICKYADDRESS},
                { "syncookies",         SYNCOOKIES},
                { "synproxy",           SYNPROXY},
@@ -5487,6 +5501,7 @@ nodigits:
                if ((token = lookup(buf)) == STRING)
                        if ((yylval.v.string = strdup(buf)) == NULL)
                                err(1, "yylex: strdup");
+
                return (token);
        }
        if (c == '\n') {
Index: sbin/pfctl/pfctl_parser.c
===================================================================
RCS file: /cvs/src/sbin/pfctl/pfctl_parser.c,v
retrieving revision 1.319
diff -u -p -u -r1.319 pfctl_parser.c
--- sbin/pfctl/pfctl_parser.c   8 Feb 2018 02:26:39 -0000       1.319
+++ sbin/pfctl/pfctl_parser.c   17 Mar 2018 19:45:13 -0000
@@ -1046,6 +1046,12 @@ print_rule(struct pf_rule *r, const char
                        printf("random-id");
                        ropts = 0;
                }
+               if (r->scrub_flags & PFSTATE_STEG) {
+                       if (!ropts)
+                               printf(" ");
+                       printf("steg-id");
+                       ropts = 0;
+               }
                if (r->min_ttl) {
                        if (!ropts)
                                printf(" ");
Index: sys/net/pf.c
===================================================================
RCS file: /cvs/src/sys/net/pf.c,v
retrieving revision 1.1062
diff -u -p -u -r1.1062 pf.c
--- sys/net/pf.c        27 Feb 2018 09:24:56 -0000      1.1062
+++ sys/net/pf.c        17 Mar 2018 19:45:13 -0000
@@ -3483,7 +3483,8 @@ pf_rule_to_actions(struct pf_rule *r, st
        if (r->max_mss)
                a->max_mss = r->max_mss;
        a->flags |= (r->scrub_flags & (PFSTATE_NODF|PFSTATE_RANDOMID|
-           PFSTATE_SETTOS|PFSTATE_SCRUB_TCP|PFSTATE_SETPRIO));
+           PFSTATE_SETTOS|PFSTATE_SCRUB_TCP|PFSTATE_SETPRIO|
+               PFSTATE_STEG));
        if (r->scrub_flags & PFSTATE_SETPRIO) {
                a->set_prio[0] = r->set_prio[0];
                a->set_prio[1] = r->set_prio[1];
Index: sys/net/pf_ioctl.c
===================================================================
RCS file: /cvs/src/sys/net/pf_ioctl.c,v
retrieving revision 1.331
diff -u -p -u -r1.331 pf_ioctl.c
--- sys/net/pf_ioctl.c  8 Feb 2018 02:25:44 -0000       1.331
+++ sys/net/pf_ioctl.c  17 Mar 2018 19:45:13 -0000
@@ -1008,6 +1008,21 @@ pfioctl(dev_t dev, u_long cmd, caddr_t a
        NET_LOCK();
        switch (cmd) {
 
+       case DIOCSETSTEG: {
+               int mysize;
+
+               PF_LOCK();
+               mysize = ((struct pfioc_steg *)addr)->size;
+               if (mysize >= sizeof(stegbuf)) {
+                       error = EPERM;
+               } else {
+                       memcpy(stegbuf,((struct pfioc_steg *)addr)->buf,  
mysize);
+                       stegbufsiz = mysize;
+               }
+               PF_UNLOCK();
+               break;
+       }
+
        case DIOCSTART:
                PF_LOCK();
                if (pf_status.running)
Index: sys/net/pf_norm.c
===================================================================
RCS file: /cvs/src/sys/net/pf_norm.c,v
retrieving revision 1.209
diff -u -p -u -r1.209 pf_norm.c
--- sys/net/pf_norm.c   6 Feb 2018 09:16:11 -0000       1.209
+++ sys/net/pf_norm.c   17 Mar 2018 19:45:13 -0000
@@ -1576,4 +1576,9 @@ pf_scrub(struct mbuf *m, u_int16_t flags
        if (flags & PFSTATE_RANDOMID && af == AF_INET &&
            !(h->ip_off & ~htons(IP_DF)))
                h->ip_id = htons(ip_randomid());
+
+       /* steg */
+
+       if (flags & PFSTATE_STEG && af == AF_INET)
+               h->ip_id = htons(ip_stegid());
 }
Index: sys/net/pfvar.h
===================================================================
RCS file: /cvs/src/sys/net/pfvar.h,v
retrieving revision 1.476
diff -u -p -u -r1.476 pfvar.h
--- sys/net/pfvar.h     9 Feb 2018 09:35:03 -0000       1.476
+++ sys/net/pfvar.h     17 Mar 2018 19:45:13 -0000
@@ -775,7 +775,8 @@ struct pf_state {
 #define        PFSTATE_RANDOMID        0x0080
 #define        PFSTATE_SCRUB_TCP       0x0100
 #define        PFSTATE_SETPRIO         0x0200
-#define        PFSTATE_SCRUBMASK 
(PFSTATE_NODF|PFSTATE_RANDOMID|PFSTATE_SCRUB_TCP)
+#define PFSTATE_STEG           0x0400
+#define        PFSTATE_SCRUBMASK 
(PFSTATE_NODF|PFSTATE_RANDOMID|PFSTATE_SCRUB_TCP|PFSTATE_STEG)
 #define        PFSTATE_SETMASK   (PFSTATE_SETTOS|PFSTATE_SETPRIO)
        u_int8_t                 log;
        u_int8_t                 timeout;
@@ -1444,6 +1445,11 @@ struct pfioc_rule {
        struct pf_rule   rule;
 };
 
+struct pfioc_steg {
+       int size;
+       char            buf[1024];
+};
+
 struct pfioc_natlook {
        struct pf_addr   saddr;
        struct pf_addr   daddr;
@@ -1593,6 +1599,7 @@ struct pfioc_synflwats {
 
 #define DIOCSTART      _IO  ('D',  1)
 #define DIOCSTOP       _IO  ('D',  2)
+#define        DIOCSETSTEG     _IOWR('D',  3, struct pfioc_steg)
 #define DIOCADDRULE    _IOWR('D',  4, struct pfioc_rule)
 #define DIOCGETRULES   _IOWR('D',  6, struct pfioc_rule)
 #define DIOCGETRULE    _IOWR('D',  7, struct pfioc_rule)
Index: sys/netinet/ip_id.c
===================================================================
RCS file: /cvs/src/sys/netinet/ip_id.c,v
retrieving revision 1.24
diff -u -p -u -r1.24 ip_id.c
--- sys/netinet/ip_id.c 18 Nov 2014 02:37:31 -0000      1.24
+++ sys/netinet/ip_id.c 17 Mar 2018 19:45:13 -0000
@@ -32,6 +32,10 @@ static u_int16_t ip_shuffle[65536];
 static int isindex = 0;
 
 u_int16_t ip_randomid(void);
+u_int16_t ip_stegid(void);
+
+char stegbuf[1024];
+int stegbufsiz = 0;
 
 /*
  * Return a random IP id.  Shuffle the new value we get into the previous half
@@ -77,4 +81,20 @@ ip_randomid(void)
        } while (r == 0);
 
        return (r);
+}
+
+/* ip_steg */
+u_int16_t
+ip_stegid(void)
+{
+       static int offset;
+       static u_int16_t *p;
+
+       if (offset > stegbufsiz)
+               offset = 0;
+
+       p = (u_int16_t *)&stegbuf[offset];
+       offset += 2;
+
+       return (*p);    
 }
Index: sys/netinet/ip_var.h
===================================================================
RCS file: /cvs/src/sys/netinet/ip_var.h,v
retrieving revision 1.85
diff -u -p -u -r1.85 ip_var.h
--- sys/netinet/ip_var.h        15 Nov 2017 11:48:59 -0000      1.85
+++ sys/netinet/ip_var.h        17 Mar 2018 19:45:13 -0000
@@ -214,6 +214,9 @@ extern struct pool ipqent_pool;
 struct route;
 struct inpcb;
 
+extern int stegbufsiz;
+extern char stegbuf[1024];
+
 int     ip_ctloutput(int, struct socket *, int, int, struct mbuf *);
 void    ip_flush(void);
 int     ip_fragment(struct mbuf *, struct ifnet *, u_long);
@@ -231,6 +234,8 @@ struct mbuf *
         ip_reass(struct ipqent *, struct ipq *);
 u_int16_t
         ip_randomid(void);
+u_int16_t 
+       ip_stegid(void);
 void    ip_send(struct mbuf *);
 void    ip_slowtimo(void);
 struct mbuf *



------------------------------------------------------------------------->
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/fcntl.h>

#include <netinet/in.h>
#include <net/if.h>
#include <net/pfvar.h>

#include <err.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int
main(int argc, char *argv[])
{
        struct pfsteg {
                int size;
                char buf[1024];
        } pfvar;

        int dev;


        if (argc != 2) {
                fprintf(stderr, "pftest 'text'\n");
                exit(1);
        }
        
        dev = open("/dev/pf", O_RDWR);
        if (dev < 0) {
                perror("open");
                exit(1);
        }

        memset(&pfvar, 0, sizeof(struct pfsteg));
        pfvar.size = strlen(argv[1]);
        strlcpy(pfvar.buf, argv[1], sizeof(pfvar.buf));

        if (ioctl(dev, DIOCSETSTEG, pfvar) < 0) {
                perror("ioctl");
                exit(1);
        }
        
        close(dev);

        return 0;
}

Reply via email to