diff options
author | Reyk Floeter <reyk@cvs.openbsd.org> | 2008-12-08 10:59:45 +0000 |
---|---|---|
committer | Reyk Floeter <reyk@cvs.openbsd.org> | 2008-12-08 10:59:45 +0000 |
commit | bfc97caf3472bc8f39ea1da77fd452a8dfc90b94 (patch) | |
tree | 3f992d88b2277d11b181d312bcc4c39f9942d331 | |
parent | 4582047c3e51ef6fc1039bfab301990a82065ca1 (diff) |
change the handling of redirections with the sticky-address option set:
instead of flushing the complete source tracking table (sticky
addresses) in pf on host state changes, just flush the entries for
hosts that have been marked as down in the relayd table. this fixes
ugly problems with users loosing their sessions if another host or
redirection was going down.
ok cloder@
-rw-r--r-- | usr.sbin/relayd/pfe_filter.c | 66 |
1 files changed, 56 insertions, 10 deletions
diff --git a/usr.sbin/relayd/pfe_filter.c b/usr.sbin/relayd/pfe_filter.c index 6039cff47fb..27af721c2a4 100644 --- a/usr.sbin/relayd/pfe_filter.c +++ b/usr.sbin/relayd/pfe_filter.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pfe_filter.c,v 1.35 2008/12/04 17:13:20 reyk Exp $ */ +/* $OpenBSD: pfe_filter.c,v 1.36 2008/12/08 10:59:44 reyk Exp $ */ /* * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -49,6 +49,7 @@ struct pfdata { int transaction_init(struct relayd *, const char *); int transaction_commit(struct relayd *); void kill_tables(struct relayd *); +int kill_srcnodes(struct relayd *, struct table *); void init_filter(struct relayd *env) @@ -156,7 +157,7 @@ kill_tables(struct relayd *env) { void sync_table(struct relayd *env, struct rdr *rdr, struct table *table) { - int i; + int i, cnt = 0; struct pfioc_table io; struct pfr_addr *addlist; struct sockaddr_in *sain; @@ -224,24 +225,69 @@ sync_table(struct relayd *env, struct rdr *rdr, struct table *table) if (ioctl(env->sc_pf->dev, DIOCRSETADDRS, &io) == -1) fatal("sync_table: cannot set address list"); - if (rdr->conf.flags & F_STICKY) { - if (ioctl(env->sc_pf->dev, DIOCCLRSRCNODES, 0) == -1) - fatal("sync_table: cannot clear the tree of " - "source tracking nodes"); - } + if (rdr->conf.flags & F_STICKY) + cnt = kill_srcnodes(env, table); free(addlist); if (env->sc_opts & RELAYD_OPT_LOGUPDATE) log_info("table %s: %d added, %d deleted, " - "%d changed", - io.pfrio_table.pfrt_name, - io.pfrio_nadd, io.pfrio_ndel, io.pfrio_nchange); + "%d changed, %d killed", io.pfrio_table.pfrt_name, + io.pfrio_nadd, io.pfrio_ndel, io.pfrio_nchange, cnt); return; toolong: fatal("sync_table: name too long"); } +int +kill_srcnodes(struct relayd *env, struct table *table) +{ + struct host *host; + struct pfioc_src_node_kill psnk; + int cnt = 0; + struct sockaddr_in *sain; + struct sockaddr_in6 *sain6; + + bzero(&psnk, sizeof(psnk)); + + /* Only match the destination address, source mask will be zero */ + memset(&psnk.psnk_dst.addr.v.a.mask, 0xff, + sizeof(psnk.psnk_dst.addr.v.a.mask)); + + TAILQ_FOREACH(host, &table->hosts, entry) { + if (host->up != HOST_DOWN) + continue; + + switch (host->conf.ss.ss_family) { + case AF_INET: + sain = (struct sockaddr_in *)&host->conf.ss; + bcopy(&sain->sin_addr, + &psnk.psnk_dst.addr.v.a.addr.v4, + sizeof(psnk.psnk_dst.addr.v.a.addr.v4)); + break; + case AF_INET6: + sain6 = (struct sockaddr_in6 *)&host->conf.ss; + bcopy(&sain6->sin6_addr, + &psnk.psnk_dst.addr.v.a.addr.v6, + sizeof(psnk.psnk_dst.addr.v.a.addr.v6)); + break; + default: + fatalx("kill_srcnodes: unknown address family"); + break; + } + + psnk.psnk_af = host->conf.ss.ss_family; + psnk.psnk_killed = 0; + + if (ioctl(env->sc_pf->dev, + DIOCKILLSRCNODES, &psnk) == -1) + fatal("kill_srcnodes: cannot kill src nodes"); + cnt += psnk.psnk_killed; + } + + return (cnt); +} + void flush_table(struct relayd *env, struct rdr *rdr) { |