]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/net/pf_ruleset.c
xnu-7195.81.3.tar.gz
[apple/xnu.git] / bsd / net / pf_ruleset.c
index 27121f77902d87ec041ca6ad1e164c80a41b9c1a..b802c11bbdfcc0059a29d3120f961166f1e9d473 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2007-2016 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  *
@@ -32,6 +32,7 @@
 /*
  * Copyright (c) 2001 Daniel Hartmeier
  * Copyright (c) 2002,2003 Henning Brauer
+ * NAT64 - Copyright (c) 2010 Viagenie Inc. (http://www.viagenie.ca)
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -73,6 +74,7 @@
 #endif /* KERNEL */
 #include <sys/mbuf.h>
 
+#include <netinet/ip_dummynet.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
 #include <netinet/ip.h>
 #include <net/if.h>
 #include <net/pfvar.h>
 
-#if INET6
 #include <netinet/ip6.h>
-#endif /* INET6 */
 
 
 #ifdef KERNEL
-#define DPFPRINTF(format, x...)                \
-       if (pf_status.debug >= PF_DEBUG_NOISY)  \
-               printf(format, ##x)
-#define rs_malloc(x)           _MALLOC(x, M_TEMP, M_WAITOK)
-#define rs_free(x)             _FREE(x, M_TEMP)
-#define        strrchr                 _strrchr
-
-static char *
-_strrchr(const char *c, int ch)
-{
-       char *p = (char *)(size_t)c, *save;
-
-       for (save = NULL; ; ++p) {
-               if (*p == ch)
-                       save = (char *)p;
-               if (*p == '\0')
-                       return (save);
-       }
-       /* NOTREACHED */
-}
+#define DPFPRINTF(format, x ...)         \
+       if (pf_status.debug >= PF_DEBUG_NOISY)  \
+               printf(format, ##x)
+#define rs_malloc(x)            _MALLOC(x, M_TEMP, M_WAITOK)
+#define rs_free(x)              _FREE(x, M_TEMP)
 
 #else
 /* Userland equivalents so we can lend code to pfctl et al. */
@@ -116,20 +101,20 @@ _strrchr(const char *c, int ch)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#define rs_malloc(x)            malloc(x)
-#define rs_free(x)              free(x)
+#define rs_malloc(x)             malloc(x)
+#define rs_free(x)               free(x)
 
 #ifdef PFDEBUG
 #include <sys/stdarg.h>
-#define DPFPRINTF(format, x...)        fprintf(stderr, format, ##x)
+#define DPFPRINTF(format, x...) fprintf(stderr, format, ##x)
 #else
-#define DPFPRINTF(format, x...)        ((void)0)
+#define DPFPRINTF(format, x...) ((void)0)
 #endif /* PFDEBUG */
 #endif /* KERNEL */
 
 
-struct pf_anchor_global         pf_anchors;
-struct pf_anchor        pf_main_anchor;
+struct pf_anchor_global  pf_anchors;
+struct pf_anchor         pf_main_anchor;
 
 static __inline int pf_anchor_compare(struct pf_anchor *, struct pf_anchor *);
 
@@ -141,7 +126,7 @@ pf_anchor_compare(struct pf_anchor *a, struct pf_anchor *b)
 {
        int c = strcmp(a->path, b->path);
 
-       return (c ? (c < 0 ? -1 : 1) : 0);
+       return c ? (c < 0 ? -1 : 1) : 0;
 }
 
 int
@@ -150,41 +135,37 @@ pf_get_ruleset_number(u_int8_t action)
        switch (action) {
        case PF_SCRUB:
        case PF_NOSCRUB:
-               return (PF_RULESET_SCRUB);
-               break;
+               return PF_RULESET_SCRUB;
        case PF_PASS:
        case PF_DROP:
-               return (PF_RULESET_FILTER);
-               break;
+               return PF_RULESET_FILTER;
        case PF_NAT:
        case PF_NONAT:
-               return (PF_RULESET_NAT);
-               break;
+               return PF_RULESET_NAT;
        case PF_BINAT:
        case PF_NOBINAT:
-               return (PF_RULESET_BINAT);
-               break;
+               return PF_RULESET_BINAT;
        case PF_RDR:
        case PF_NORDR:
-               return (PF_RULESET_RDR);
-               break;
+       case PF_NAT64:
+       case PF_NONAT64:
+               return PF_RULESET_RDR;
 #if DUMMYNET
        case PF_DUMMYNET:
        case PF_NODUMMYNET:
-               return (PF_RULESET_DUMMYNET);
+               return PF_RULESET_DUMMYNET;
 #endif /* DUMMYNET */
        default:
-               return (PF_RULESET_MAX);
-               break;
+               return PF_RULESET_MAX;
        }
 }
 
 void
 pf_init_ruleset(struct pf_ruleset *ruleset)
 {
-       int     i;
+       int     i;
 
-       memset(ruleset, 0, sizeof (struct pf_ruleset));
+       memset(ruleset, 0, sizeof(struct pf_ruleset));
        for (i = 0; i < PF_RULESET_MAX; i++) {
                TAILQ_INIT(&ruleset->rules[i].queues[0]);
                TAILQ_INIT(&ruleset->rules[i].queues[1]);
@@ -196,50 +177,56 @@ pf_init_ruleset(struct pf_ruleset *ruleset)
 struct pf_anchor *
 pf_find_anchor(const char *path)
 {
-       struct pf_anchor        *key, *found;
+       struct pf_anchor        *key, *found;
 
-       key = (struct pf_anchor *)rs_malloc(sizeof (*key));
-       memset(key, 0, sizeof (*key));
-       strlcpy(key->path, path, sizeof (key->path));
+       key = (struct pf_anchor *)rs_malloc(sizeof(*key));
+       memset(key, 0, sizeof(*key));
+       strlcpy(key->path, path, sizeof(key->path));
        found = RB_FIND(pf_anchor_global, &pf_anchors, key);
        rs_free(key);
-       return (found);
+       return found;
 }
 
 struct pf_ruleset *
 pf_find_ruleset(const char *path)
 {
-       struct pf_anchor        *anchor;
+       struct pf_anchor        *anchor;
 
-       while (*path == '/')
+       while (*path == '/') {
                path++;
-       if (!*path)
-               return (&pf_main_ruleset);
+       }
+       if (!*path) {
+               return &pf_main_ruleset;
+       }
        anchor = pf_find_anchor(path);
-       if (anchor == NULL)
-               return (NULL);
-       else
-               return (&anchor->ruleset);
+       if (anchor == NULL) {
+               return NULL;
+       } else {
+               return &anchor->ruleset;
+       }
 }
 
 struct pf_ruleset *
 pf_find_ruleset_with_owner(const char *path, const char *owner, int is_anchor,
     int *error)
 {
-       struct pf_anchor        *anchor;
+       struct pf_anchor        *anchor;
 
-       while (*path == '/')
+       while (*path == '/') {
                path++;
-       if (!*path)
-               return (&pf_main_ruleset);
+       }
+       if (!*path) {
+               return &pf_main_ruleset;
+       }
        anchor = pf_find_anchor(path);
        if (anchor == NULL) {
                *error = EINVAL;
-               return (NULL);
+               return NULL;
        } else {
-               if ((owner && anchor->owner && (!strcmp(owner, anchor->owner)))
-                   || (is_anchor && !strcmp(anchor->owner, "")))
-                       return (&anchor->ruleset);
+               if ((owner && (!strcmp(owner, anchor->owner)))
+                   || (is_anchor && !strcmp(anchor->owner, ""))) {
+                       return &anchor->ruleset;
+               }
                *error = EPERM;
                return NULL;
        }
@@ -248,17 +235,20 @@ pf_find_ruleset_with_owner(const char *path, const char *owner, int is_anchor,
 struct pf_ruleset *
 pf_find_or_create_ruleset(const char *path)
 {
-       char                    *p, *q, *r;
-       struct pf_ruleset       *ruleset;
-       struct pf_anchor        *anchor = 0, *dup, *parent = NULL;
+       char                    *p, *q = NULL, *r;
+       struct pf_ruleset       *ruleset;
+       struct pf_anchor        *anchor = 0, *dup, *parent = NULL;
 
-       if (path[0] == 0)
-               return (&pf_main_ruleset);
-       while (*path == '/')
+       if (path[0] == 0) {
+               return &pf_main_ruleset;
+       }
+       while (*path == '/') {
                path++;
+       }
        ruleset = pf_find_ruleset(path);
-       if (ruleset != NULL)
-               return (ruleset);
+       if (ruleset != NULL) {
+               return ruleset;
+       }
        p = (char *)rs_malloc(MAXPATHLEN);
        bzero(p, MAXPATHLEN);
        strlcpy(p, path, MAXPATHLEN);
@@ -269,38 +259,40 @@ pf_find_or_create_ruleset(const char *path)
                        break;
                }
        }
-       if (q == NULL)
+       if (q == NULL) {
                q = p;
-       else
+       } else {
                q++;
+       }
        strlcpy(p, path, MAXPATHLEN);
        if (!*q) {
                rs_free(p);
-               return (NULL);
+               return NULL;
        }
        while ((r = strchr(q, '/')) != NULL || *q) {
-               if (r != NULL)
+               if (r != NULL) {
                        *r = 0;
+               }
                if (!*q || strlen(q) >= PF_ANCHOR_NAME_SIZE ||
                    (parent != NULL && strlen(parent->path) >=
                    MAXPATHLEN - PF_ANCHOR_NAME_SIZE - 1)) {
                        rs_free(p);
-                       return (NULL);
+                       return NULL;
                }
-               anchor = (struct pf_anchor *)rs_malloc(sizeof (*anchor));
+               anchor = (struct pf_anchor *)rs_malloc(sizeof(*anchor));
                if (anchor == NULL) {
                        rs_free(p);
-                       return (NULL);
+                       return NULL;
                }
-               memset(anchor, 0, sizeof (*anchor));
+               memset(anchor, 0, sizeof(*anchor));
                RB_INIT(&anchor->children);
-               strlcpy(anchor->name, q, sizeof (anchor->name));
+               strlcpy(anchor->name, q, sizeof(anchor->name));
                if (parent != NULL) {
                        strlcpy(anchor->path, parent->path,
-                           sizeof (anchor->path));
-                       strlcat(anchor->path, "/", sizeof (anchor->path));
+                           sizeof(anchor->path));
+                       strlcat(anchor->path, "/", sizeof(anchor->path));
                }
-               strlcat(anchor->path, anchor->name, sizeof (anchor->path));
+               strlcat(anchor->path, anchor->name, sizeof(anchor->path));
                if ((dup = RB_INSERT(pf_anchor_global, &pf_anchors, anchor)) !=
                    NULL) {
                        printf("pf_find_or_create_ruleset: RB_INSERT1 "
@@ -308,7 +300,7 @@ pf_find_or_create_ruleset(const char *path)
                            anchor->path, anchor->name, dup->path, dup->name);
                        rs_free(anchor);
                        rs_free(p);
-                       return (NULL);
+                       return NULL;
                }
                if (parent != NULL) {
                        anchor->parent = parent;
@@ -322,45 +314,67 @@ pf_find_or_create_ruleset(const char *path)
                                    anchor);
                                rs_free(anchor);
                                rs_free(p);
-                               return (NULL);
+                               return NULL;
                        }
                }
                pf_init_ruleset(&anchor->ruleset);
                anchor->ruleset.anchor = anchor;
                parent = anchor;
-               if (r != NULL)
+               if (r != NULL) {
                        q = r + 1;
-               else
+               } else {
                        *q = 0;
+               }
+#if DUMMYNET
+               if (strncmp("com.apple.nlc", anchor->name,
+                   sizeof("com.apple.nlc")) == 0) {
+                       is_nlc_enabled_glb = TRUE;
+               }
+#endif
        }
        rs_free(p);
-       return (anchor ? &anchor->ruleset : 0);
+       return anchor ? &anchor->ruleset : 0;
 }
 
 void
 pf_remove_if_empty_ruleset(struct pf_ruleset *ruleset)
 {
-       struct pf_anchor        *parent;
-       int                      i;
+       struct pf_anchor        *parent;
+       int                      i;
 
        while (ruleset != NULL) {
                if (ruleset == &pf_main_ruleset || ruleset->anchor == NULL ||
                    !RB_EMPTY(&ruleset->anchor->children) ||
                    ruleset->anchor->refcnt > 0 || ruleset->tables > 0 ||
-                   ruleset->topen)
+                   ruleset->topen) {
                        return;
-               for (i = 0; i < PF_RULESET_MAX; ++i)
+               }
+               for (i = 0; i < PF_RULESET_MAX; ++i) {
                        if (!TAILQ_EMPTY(ruleset->rules[i].active.ptr) ||
                            !TAILQ_EMPTY(ruleset->rules[i].inactive.ptr) ||
-                           ruleset->rules[i].inactive.open)
+                           ruleset->rules[i].inactive.open) {
                                return;
+                       }
+               }
                RB_REMOVE(pf_anchor_global, &pf_anchors, ruleset->anchor);
-               if ((parent = ruleset->anchor->parent) != NULL)
+#if DUMMYNET
+               if (strncmp("com.apple.nlc", ruleset->anchor->name,
+                   sizeof("com.apple.nlc")) == 0) {
+                       struct dummynet_event dn_event;
+                       bzero(&dn_event, sizeof(dn_event));
+                       dn_event.dn_event_code = DUMMYNET_NLC_DISABLED;
+                       dummynet_event_enqueue_nwk_wq_entry(&dn_event);
+                       is_nlc_enabled_glb = FALSE;
+               }
+#endif
+               if ((parent = ruleset->anchor->parent) != NULL) {
                        RB_REMOVE(pf_anchor_node, &parent->children,
                            ruleset->anchor);
+               }
                rs_free(ruleset->anchor);
-               if (parent == NULL)
+               if (parent == NULL) {
                        return;
+               }
                ruleset = &parent->ruleset;
        }
 }
@@ -369,40 +383,44 @@ int
 pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s,
     const char *name)
 {
-       char                    *p, *path;
-       struct pf_ruleset       *ruleset;
+       char                    *p, *path;
+       struct pf_ruleset       *ruleset;
 
        r->anchor = NULL;
        r->anchor_relative = 0;
        r->anchor_wildcard = 0;
-       if (!name[0])
-               return (0);
+       if (!name[0]) {
+               return 0;
+       }
        path = (char *)rs_malloc(MAXPATHLEN);
        bzero(path, MAXPATHLEN);
-       if (name[0] == '/')
+       if (name[0] == '/') {
                strlcpy(path, name + 1, MAXPATHLEN);
-       else {
+       else {
                /* relative path */
                r->anchor_relative = 1;
-               if (s->anchor == NULL || !s->anchor->path[0])
+               if (s->anchor == NULL || !s->anchor->path[0]) {
                        path[0] = 0;
-               else
+               } else {
                        strlcpy(path, s->anchor->path, MAXPATHLEN);
+               }
                while (name[0] == '.' && name[1] == '.' && name[2] == '/') {
                        if (!path[0]) {
                                printf("pf_anchor_setup: .. beyond root\n");
                                rs_free(path);
-                               return (1);
+                               return 1;
                        }
-                       if ((p = strrchr(path, '/')) != NULL)
+                       if ((p = strrchr(path, '/')) != NULL) {
                                *p = 0;
-                       else
+                       } else {
                                path[0] = 0;
+                       }
                        r->anchor_relative++;
                        name += 3;
                }
-               if (path[0])
+               if (path[0]) {
                        strlcat(path, "/", MAXPATHLEN);
+               }
                strlcat(path, name, MAXPATHLEN);
        }
        if ((p = strrchr(path, '/')) != NULL && strcmp(p, "/*") == 0) {
@@ -413,11 +431,11 @@ pf_anchor_setup(struct pf_rule *r, const struct pf_ruleset *s,
        rs_free(path);
        if (ruleset == NULL || ruleset->anchor == NULL) {
                printf("pf_anchor_setup: ruleset\n");
-               return (1);
+               return 1;
        }
        r->anchor = ruleset->anchor;
        r->anchor->refcnt++;
-       return (0);
+       return 0;
 }
 
 int
@@ -425,57 +443,64 @@ pf_anchor_copyout(const struct pf_ruleset *rs, const struct pf_rule *r,
     struct pfioc_rule *pr)
 {
        pr->anchor_call[0] = 0;
-       if (r->anchor == NULL)
-               return (0);
+       if (r->anchor == NULL) {
+               return 0;
+       }
        if (!r->anchor_relative) {
-               strlcpy(pr->anchor_call, "/", sizeof (pr->anchor_call));
+               strlcpy(pr->anchor_call, "/", sizeof(pr->anchor_call));
                strlcat(pr->anchor_call, r->anchor->path,
-                   sizeof (pr->anchor_call));
+                   sizeof(pr->anchor_call));
        } else {
-               char    *a, *p;
-               int      i;
+               char    *a, *p;
+               int      i;
 
                a = (char *)rs_malloc(MAXPATHLEN);
                bzero(a, MAXPATHLEN);
-               if (rs->anchor == NULL)
+               if (rs->anchor == NULL) {
                        a[0] = 0;
-               else
+               } else {
                        strlcpy(a, rs->anchor->path, MAXPATHLEN);
+               }
                for (i = 1; i < r->anchor_relative; ++i) {
-                       if ((p = strrchr(a, '/')) == NULL)
+                       if ((p = strrchr(a, '/')) == NULL) {
                                p = a;
+                       }
                        *p = 0;
                        strlcat(pr->anchor_call, "../",
-                           sizeof (pr->anchor_call));
+                           sizeof(pr->anchor_call));
                }
                if (strncmp(a, r->anchor->path, strlen(a))) {
                        printf("pf_anchor_copyout: '%s' '%s'\n", a,
                            r->anchor->path);
                        rs_free(a);
-                       return (1);
+                       return 1;
                }
-               if (strlen(r->anchor->path) > strlen(a))
+               if (strlen(r->anchor->path) > strlen(a)) {
                        strlcat(pr->anchor_call, r->anchor->path + (a[0] ?
-                           strlen(a) + 1 : 0), sizeof (pr->anchor_call));
+                           strlen(a) + 1 : 0), sizeof(pr->anchor_call));
+               }
                rs_free(a);
        }
-       if (r->anchor_wildcard)
+       if (r->anchor_wildcard) {
                strlcat(pr->anchor_call, pr->anchor_call[0] ? "/*" : "*",
-                   sizeof (pr->anchor_call));
-       return (0);
+                   sizeof(pr->anchor_call));
+       }
+       return 0;
 }
 
 void
 pf_anchor_remove(struct pf_rule *r)
 {
-       if (r->anchor == NULL)
+       if (r->anchor == NULL) {
                return;
+       }
        if (r->anchor->refcnt <= 0) {
                printf("pf_anchor_remove: broken refcount\n");
                r->anchor = NULL;
                return;
        }
-       if (!--r->anchor->refcnt)
+       if (!--r->anchor->refcnt) {
                pf_remove_if_empty_ruleset(&r->anchor->ruleset);
+       }
        r->anchor = NULL;
 }