X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/316670eb35587141e969394ae8537d66b9211e80..a991bd8d3e7fe02dbca0644054bab73c5b75324a:/bsd/net/pf_ruleset.c diff --git a/bsd/net/pf_ruleset.c b/bsd/net/pf_ruleset.c index 27121f779..b802c11bb 100644 --- a/bsd/net/pf_ruleset.c +++ b/bsd/net/pf_ruleset.c @@ -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 +#include #include #include #include @@ -81,32 +83,15 @@ #include #include -#if INET6 #include -#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 #include #include -#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 -#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; }