aboutsummaryrefslogtreecommitdiff
path: root/pf.c
diff options
context:
space:
mode:
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2008-06-11 08:45:09 +0000
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2008-06-11 08:45:09 +0000
commit90efcacba6378a4e29275cd6e9914d73d836a4a4 (patch)
treeda032ba71582994f9e1f2ed7162ba14f152cb7d7 /pf.c
parentAdded support for building and linking with (diff)
downloadopenvpn-90efcacba6378a4e29275cd6e9914d73d836a4a4.tar.xz
Updated version to 2.1_rc7e.
Added client authentication and packet filtering capability to management interface. Extended packet filtering capability to work on both --dev tun and --dev tap tunnels. Updated valgrind-suppress file. Made "Linux ip addr del failed" error nonfatal. Amplified --client-cert-not-required warning. Added #pragma pack to proto.h. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@2991 e7ae566f-a301-0410-adde-c780ea21d3b5
Diffstat (limited to 'pf.c')
-rw-r--r--pf.c272
1 files changed, 175 insertions, 97 deletions
diff --git a/pf.c b/pf.c
index 87d7c3b..b7ed4c8 100644
--- a/pf.c
+++ b/pf.c
@@ -32,6 +32,8 @@
#include "memdbg.h"
+#include "pf-inline.h"
+
static void
pf_destroy (struct pf_set *pfs)
{
@@ -64,7 +66,7 @@ pf_destroy (struct pf_set *pfs)
}
static bool
-add_client (const char *line, const char *fn, const int line_num, struct pf_cn_elem ***next, const bool exclude)
+add_client (const char *line, const char *prefix, const int line_num, struct pf_cn_elem ***next, const bool exclude)
{
struct pf_cn_elem *e;
ALLOC_OBJ_CLEAR (e, struct pf_cn_elem);
@@ -76,34 +78,44 @@ add_client (const char *line, const char *fn, const int line_num, struct pf_cn_e
}
static bool
-add_subnet (const char *line, const char *fn, const int line_num, struct pf_subnet ***next, const bool exclude)
+add_subnet (const char *line, const char *prefix, const int line_num, struct pf_subnet ***next, const bool exclude)
{
struct in_addr network;
in_addr_t netmask = 0;
- int netbits = 32;
- char *div = strchr (line, '/');
- if (div)
+ if (strcmp (line, "unknown"))
{
- *div++ = '\0';
- if (sscanf (div, "%d", &netbits) != 1)
+ int netbits = 32;
+ char *div = strchr (line, '/');
+
+ if (div)
{
- msg (D_PF, "PF: %s/%d: bad '/n' subnet specifier: '%s'", fn, line_num, div);
- return false;
+ *div++ = '\0';
+ if (sscanf (div, "%d", &netbits) != 1)
+ {
+ msg (D_PF_INFO, "PF: %s/%d: bad '/n' subnet specifier: '%s'", prefix, line_num, div);
+ return false;
+ }
+ if (netbits < 0 || netbits > 32)
+ {
+ msg (D_PF_INFO, "PF: %s/%d: bad '/n' subnet specifier: must be between 0 and 32: '%s'", prefix, line_num, div);
+ return false;
+ }
}
- if (netbits < 0 || netbits > 32)
+
+ if (openvpn_inet_aton (line, &network) != OIA_IP)
{
- msg (D_PF, "PF: %s/%d: bad '/n' subnet specifier: must be between 0 and 32: '%s'", fn, line_num, div);
+ msg (D_PF_INFO, "PF: %s/%d: bad network address: '%s'", prefix, line_num, line);
return false;
}
+ netmask = netbits_to_netmask (netbits);
}
-
- if (openvpn_inet_aton (line, &network) != OIA_IP)
+ else
{
- msg (D_PF, "PF: %s/%d: bad network address: '%s'", fn, line_num, line);
- return false;
+ /* match special "unknown" tag for addresses unrecognized by mroute */
+ network.s_addr = htonl(0);
+ netmask = ~0;
}
- netmask = netbits_to_netmask (netbits);
{
struct pf_subnet *e;
@@ -130,7 +142,7 @@ cn_compare_function (const void *key1, const void *key2)
}
static bool
-genhash (struct pf_cn_set *cns, const char *fn, const int n_clients)
+genhash (struct pf_cn_set *cns, const char *prefix, const int n_clients)
{
struct pf_cn_elem *e;
bool status = true;
@@ -143,7 +155,7 @@ genhash (struct pf_cn_set *cns, const char *fn, const int n_clients)
{
if (!hash_add (cns->hash_table, e->rule.cn, &e->rule, false))
{
- msg (D_PF, "PF: %s: duplicate common name in [clients] section: '%s'", fn, e->rule.cn);
+ msg (D_PF_INFO, "PF: %s: duplicate common name in [clients] section: '%s'", prefix, e->rule.cn);
status = false;
}
}
@@ -152,7 +164,7 @@ genhash (struct pf_cn_set *cns, const char *fn, const int n_clients)
}
static struct pf_set *
-pf_init (const char *fn)
+pf_init (const struct buffer_list *bl, const char *prefix, const bool allow_kill)
{
# define MODE_UNDEF 0
# define MODE_CLIENTS 1
@@ -163,18 +175,19 @@ pf_init (const char *fn)
int n_subnets = 0;
int n_errors = 0;
struct pf_set *pfs = NULL;
- char line[256];
+ char line[PF_MAX_LINE_LEN];
ALLOC_OBJ_CLEAR (pfs, struct pf_set);
- FILE *fp = fopen (fn, "r");
- if (fp)
+ if (bl)
{
struct pf_cn_elem **cl = &pfs->cns.list;
struct pf_subnet **sl = &pfs->sns.list;
+ struct buffer_entry *be;
- while (fgets (line, sizeof (line), fp) != NULL)
+ for (be = bl->head; be != NULL; be = be->next)
{
++line_num;
+ strncpynt (line, BSTR(&be->buf), sizeof(line));
rm_trailing_chars (line, "\r\n\t ");
if (line[0] == '\0' || line[0] == '#')
;
@@ -184,19 +197,19 @@ pf_init (const char *fn)
if (line[1] =='\0')
{
- msg (D_PF, "PF: %s/%d: no data after +/-: '%s'", fn, line_num, line);
+ msg (D_PF_INFO, "PF: %s/%d: no data after +/-: '%s'", prefix, line_num, line);
++n_errors;
}
else if (mode == MODE_CLIENTS)
{
- if (add_client (&line[1], fn, line_num, &cl, exclude))
+ if (add_client (&line[1], prefix, line_num, &cl, exclude))
++n_clients;
else
++n_errors;
}
else if (mode == MODE_SUBNETS)
{
- if (add_subnet (&line[1], fn, line_num, &sl, exclude))
+ if (add_subnet (&line[1], prefix, line_num, &sl, exclude))
++n_subnets;
else
++n_errors;
@@ -232,41 +245,40 @@ pf_init (const char *fn)
}
else if (!strcasecmp (line, "[end]"))
goto done;
- else if (!strcasecmp (line, "[kill]"))
+ else if (allow_kill && !strcasecmp (line, "[kill]"))
goto kill;
else
{
mode = MODE_UNDEF;
- msg (D_PF, "PF: %s/%d unknown tag: '%s'", fn, line_num, line);
+ msg (D_PF_INFO, "PF: %s/%d unknown tag: '%s'", prefix, line_num, line);
++n_errors;
}
}
else
{
- msg (D_PF, "PF: %s/%d line must begin with '+', '-', or '[' : '%s'", fn, line_num, line);
+ msg (D_PF_INFO, "PF: %s/%d line must begin with '+', '-', or '[' : '%s'", prefix, line_num, line);
++n_errors;
}
}
++n_errors;
- msg (D_PF, "PF: %s: missing [end]", fn);
+ msg (D_PF_INFO, "PF: %s: missing [end]", prefix);
}
else
{
- msg (D_PF|M_ERRNO, "PF: %s: cannot open", fn);
+ msg (D_PF_INFO, "PF: %s: cannot open", prefix);
++n_errors;
}
done:
- if (fp)
+ if (bl)
{
- fclose (fp);
if (!n_errors)
{
- if (!genhash (&pfs->cns, fn, n_clients))
+ if (!genhash (&pfs->cns, prefix, n_clients))
++n_errors;
}
if (n_errors)
- msg (D_PF, "PF: %s rejected due to %d error(s)", fn, n_errors);
+ msg (D_PF_INFO, "PF: %s rejected due to %d error(s)", prefix, n_errors);
}
if (n_errors)
{
@@ -276,15 +288,32 @@ pf_init (const char *fn)
return pfs;
kill:
- if (fp)
- fclose (fp);
pf_destroy (pfs);
ALLOC_OBJ_CLEAR (pfs, struct pf_set);
pfs->kill = true;
return pfs;
}
-#if PF_DEBUG >= 1
+#ifdef PLUGIN_PF
+static struct pf_set *
+pf_init_from_file (const char *fn)
+{
+ struct buffer_list *bl = buffer_list_file (fn, PF_MAX_LINE_LEN);
+ if (bl)
+ {
+ struct pf_set *pfs = pf_init (bl, fn, true);
+ buffer_list_free (bl);
+ return pfs;
+ }
+ else
+ {
+ msg (D_PF_INFO|M_ERRNO, "PF: %s: cannot open", fn);
+ return NULL;
+ }
+}
+#endif
+
+#ifdef ENABLE_DEBUG
static const char *
drop_accept (const bool accept)
@@ -292,31 +321,46 @@ drop_accept (const bool accept)
return accept ? "ACCEPT" : "DROP";
}
-#endif
-
-#if PF_DEBUG >= 2
+static const char *
+pct_name (const int type)
+{
+ switch (type)
+ {
+ case PCT_SRC:
+ return "SRC";
+ case PCT_DEST:
+ return "DEST";
+ default:
+ return "???";
+ }
+}
static void
pf_cn_test_print (const char *prefix,
+ const int type,
+ const char *prefix2,
const char *cn,
const bool allow,
const struct pf_cn *rule)
{
if (rule)
{
- msg (D_PF, "PF: %s %s %s rule=[%s %s]",
- prefix, cn, drop_accept (allow),
+ dmsg (D_PF_DEBUG, "PF: %s/%s/%s %s %s rule=[%s %s]",
+ prefix, prefix2, pct_name (type),
+ cn, drop_accept (allow),
rule->cn, drop_accept (!rule->exclude));
}
else
{
- msg (D_PF, "PF: %s %s %s",
- prefix, cn, drop_accept (allow));
+ dmsg (D_PF_DEBUG, "PF: %s/%s/%s %s %s",
+ prefix, prefix2, pct_name (type),
+ cn, drop_accept (allow));
}
}
static void
pf_addr_test_print (const char *prefix,
+ const char *prefix2,
const struct context *src,
const struct mroute_addr *dest,
const bool allow,
@@ -325,10 +369,11 @@ pf_addr_test_print (const char *prefix,
struct gc_arena gc = gc_new ();
if (rule)
{
- msg (D_PF, "PF: %s %s %s %s rule=[%s/%s %s]",
+ dmsg (D_PF_DEBUG, "PF: %s/%s %s %s %s rule=[%s/%s %s]",
prefix,
+ prefix2,
tls_common_name (src->c2.tls_multi, false),
- mroute_addr_print (dest, &gc),
+ mroute_addr_print_ex (dest, MAPF_SHOW_ARP, &gc),
drop_accept (allow),
print_in_addr_t (rule->network, 0, &gc),
print_in_addr_t (rule->netmask, 0, &gc),
@@ -336,10 +381,11 @@ pf_addr_test_print (const char *prefix,
}
else
{
- msg (D_PF, "PF: %s %s %s %s",
+ dmsg (D_PF_DEBUG, "PF: %s/%s %s %s %s",
prefix,
+ prefix2,
tls_common_name (src->c2.tls_multi, false),
- mroute_addr_print (dest, &gc),
+ mroute_addr_print_ex (dest, MAPF_SHOW_ARP, &gc),
drop_accept (allow));
}
gc_free (&gc);
@@ -357,8 +403,8 @@ lookup_cn_rule (struct hash *h, const char *cn, const uint32_t cn_hash)
return NULL;
}
-static inline bool
-cn_test (struct pf_set *pfs, const struct tls_multi *tm)
+bool
+pf_cn_test (struct pf_set *pfs, const struct tls_multi *tm, const int type, const char *prefix)
{
if (!pfs->kill)
{
@@ -369,8 +415,9 @@ cn_test (struct pf_set *pfs, const struct tls_multi *tm)
const struct pf_cn *rule = lookup_cn_rule (pfs->cns.hash_table, cn, cn_hash);
if (rule)
{
-#if PF_DEBUG >= 2
- pf_cn_test_print ("PF_CN_MATCH", cn, !rule->exclude, rule);
+#ifdef ENABLE_DEBUG
+ if (check_debug_level (D_PF_DEBUG))
+ pf_cn_test_print ("PF_CN_MATCH", type, prefix, cn, !rule->exclude, rule);
#endif
if (!rule->exclude)
return true;
@@ -379,8 +426,9 @@ cn_test (struct pf_set *pfs, const struct tls_multi *tm)
}
else
{
-#if PF_DEBUG >= 2
- pf_cn_test_print ("PF_CN_DEFAULT", cn, pfs->cns.default_allow, NULL);
+#ifdef ENABLE_DEBUG
+ if (check_debug_level (D_PF_DEBUG))
+ pf_cn_test_print ("PF_CN_DEFAULT", type, prefix, cn, pfs->cns.default_allow, NULL);
#endif
if (pfs->cns.default_allow)
return true;
@@ -389,59 +437,50 @@ cn_test (struct pf_set *pfs, const struct tls_multi *tm)
}
}
}
-#if PF_DEBUG >= 2
- pf_cn_test_print ("PF_CN_FAULT", tls_common_name (tm, false), false, NULL);
+#ifdef ENABLE_DEBUG
+ if (check_debug_level (D_PF_DEBUG))
+ pf_cn_test_print ("PF_CN_FAULT", type, prefix, tls_common_name (tm, false), false, NULL);
#endif
return false;
}
bool
-pf_c2c_test (const struct context *src, const struct context *dest)
+pf_addr_test_dowork (const struct context *src, const struct mroute_addr *dest, const char *prefix)
{
- return (!src->c2.pf.filename || cn_test (src->c2.pf.pfs, dest->c2.tls_multi))
- && (!dest->c2.pf.filename || cn_test (dest->c2.pf.pfs, src->c2.tls_multi));
-}
-
-bool
-pf_addr_test (const struct context *src, const struct mroute_addr *dest)
-{
- if (src->c2.pf.filename)
+ struct pf_set *pfs = src->c2.pf.pfs;
+ if (pfs && !pfs->kill)
{
- struct pf_set *pfs = src->c2.pf.pfs;
- if (pfs && !pfs->kill)
+ const in_addr_t addr = in_addr_t_from_mroute_addr (dest);
+ const struct pf_subnet *se = pfs->sns.list;
+ while (se)
{
- const in_addr_t addr = in_addr_t_from_mroute_addr (dest);
- const struct pf_subnet *se = pfs->sns.list;
- while (se)
+ if ((addr & se->rule.netmask) == se->rule.network)
{
- if ((addr & se->rule.netmask) == se->rule.network)
- {
-#if PF_DEBUG >= 2
- pf_addr_test_print ("PF_ADDR_MATCH", src, dest, !se->rule.exclude, &se->rule);
+#ifdef ENABLE_DEBUG
+ if (check_debug_level (D_PF_DEBUG))
+ pf_addr_test_print ("PF_ADDR_MATCH", prefix, src, dest, !se->rule.exclude, &se->rule);
#endif
- return !se->rule.exclude;
- }
- se = se->next;
+ return !se->rule.exclude;
}
-#if PF_DEBUG >= 2
- pf_addr_test_print ("PF_ADDR_DEFAULT", src, dest, pfs->sns.default_allow, NULL);
-#endif
- return pfs->sns.default_allow;
+ se = se->next;
}
- else
- {
-#if PF_DEBUG >= 2
- pf_addr_test_print ("PF_ADDR_FAULT", src, dest, false, NULL);
+#ifdef ENABLE_DEBUG
+ if (check_debug_level (D_PF_DEBUG))
+ pf_addr_test_print ("PF_ADDR_DEFAULT", prefix, src, dest, pfs->sns.default_allow, NULL);
#endif
- return false;
- }
+ return pfs->sns.default_allow;
}
else
{
- return true;
+#ifdef ENABLE_DEBUG
+ if (check_debug_level (D_PF_DEBUG))
+ pf_addr_test_print ("PF_ADDR_FAULT", prefix, src, dest, false, NULL);
+#endif
+ return false;
}
}
+#ifdef PLUGIN_PF
void
pf_check_reload (struct context *c)
{
@@ -450,14 +489,16 @@ pf_check_reload (struct context *c)
const int wakeup_transition = 60;
bool reloaded = false;
- if (c->c2.pf.filename && event_timeout_trigger (&c->c2.pf.reload, &c->c2.timeval, ETT_DEFAULT))
+ if (c->c2.pf.enabled
+ && c->c2.pf.filename
+ && event_timeout_trigger (&c->c2.pf.reload, &c->c2.timeval, ETT_DEFAULT))
{
struct stat s;
if (!stat (c->c2.pf.filename, &s))
{
if (s.st_mtime > c->c2.pf.file_last_mod)
{
- struct pf_set *pfs = pf_init (c->c2.pf.filename);
+ struct pf_set *pfs = pf_init_from_file (c->c2.pf.filename);
if (pfs)
{
if (c->c2.pf.pfs)
@@ -482,16 +523,35 @@ pf_check_reload (struct context *c)
c->c2.pf.n_check_reload++;
}
}
-#if PF_DEBUG >= 1
- if (reloaded)
- pf_context_print (&c->c2.pf, "pf_check_reload", M_INFO);
+#ifdef ENABLE_DEBUG
+ if (reloaded && check_debug_level (D_PF_DEBUG))
+ pf_context_print (&c->c2.pf, "pf_check_reload", D_PF_DEBUG);
#endif
}
+#endif
+
+#ifdef MANAGEMENT_PF
+bool
+pf_load_from_buffer_list (struct context *c, const struct buffer_list *config)
+{
+ struct pf_set *pfs = pf_init (config, "[SERVER-PF]", false);
+ if (pfs)
+ {
+ if (c->c2.pf.pfs)
+ pf_destroy (c->c2.pf.pfs);
+ c->c2.pf.pfs = pfs;
+ return true;
+ }
+ else
+ return false;
+}
+#endif
void
pf_init_context (struct context *c)
{
struct gc_arena gc = gc_new ();
+#ifdef PLUGIN_PF
if (plugin_defined (c->plugins, OPENVPN_PLUGIN_ENABLE_PF))
{
const char *pf_file = create_temp_filename (c->options.tmp_dir, "pf", &gc);
@@ -502,8 +562,10 @@ pf_init_context (struct context *c)
{
event_timeout_init (&c->c2.pf.reload, 1, now);
c->c2.pf.filename = string_alloc (pf_file, NULL);
-#if PF_DEBUG >= 1
- pf_context_print (&c->c2.pf, "pf_init_context", M_INFO);
+ c->c2.pf.enabled = true;
+#ifdef ENABLE_DEBUG
+ if (check_debug_level (D_PF_DEBUG))
+ pf_context_print (&c->c2.pf, "pf_init_context#1", D_PF_DEBUG);
#endif
}
else
@@ -511,22 +573,35 @@ pf_init_context (struct context *c)
msg (M_WARN, "WARNING: OPENVPN_PLUGIN_ENABLE_PF disabled");
}
}
+#endif
+#ifdef MANAGEMENT_PF
+ if (!c->c2.pf.enabled && management_enable_pf (management))
+ {
+ c->c2.pf.enabled = true;
+#ifdef ENABLE_DEBUG
+ if (check_debug_level (D_PF_DEBUG))
+ pf_context_print (&c->c2.pf, "pf_init_context#2", D_PF_DEBUG);
+#endif
+ }
+#endif
gc_free (&gc);
}
void
pf_destroy_context (struct pf_context *pfc)
{
+#ifdef PLUGIN_PF
if (pfc->filename)
{
delete_file (pfc->filename);
free (pfc->filename);
}
+#endif
if (pfc->pfs)
pf_destroy (pfc->pfs);
}
-#if PF_DEBUG >= 1
+#ifdef ENABLE_DEBUG
static void
pf_subnet_set_print (const struct pf_subnet_set *s, const int lev)
@@ -613,10 +688,13 @@ pf_context_print (const struct pf_context *pfc, const char *prefix, const int le
msg (lev, "----- %s : struct pf_context -----", prefix);
if (pfc)
{
+ msg (lev, "enabled=%d", pfc->enabled);
+#ifdef PLUGIN_PF
msg (lev, "filename='%s'", np(pfc->filename));
msg (lev, "file_last_mod=%u", (unsigned int)pfc->file_last_mod);
msg (lev, "n_check_reload=%u", pfc->n_check_reload);
msg (lev, "reload=[%d,%u,%u]", pfc->reload.defined, pfc->reload.n, (unsigned int)pfc->reload.last);
+#endif
pf_set_print (pfc->pfs, lev);
}
msg (lev, "--------------------");