xref: /openbsd-src/usr.sbin/relayd/pfe_filter.c (revision a28daedfc357b214be5c701aa8ba8adb29a7f1c2)
1 /*	$OpenBSD: pfe_filter.c,v 1.38 2009/04/24 14:20:24 reyk Exp $	*/
2 
3 /*
4  * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <sys/socket.h>
22 #include <sys/ioctl.h>
23 
24 #include <net/if.h>
25 #include <net/pfvar.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 
29 #include <limits.h>
30 #include <fcntl.h>
31 #include <event.h>
32 #include <string.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <errno.h>
36 
37 #include <openssl/ssl.h>
38 
39 #include "relayd.h"
40 
41 struct pfdata {
42 	int			 dev;
43 	struct pf_anchor	*anchor;
44 	struct pfioc_trans	 pft[PF_RULESET_MAX];
45 	struct pfioc_trans_e	 pfte[PF_RULESET_MAX];
46 	u_int8_t		 pfused;
47 };
48 
49 int	 transaction_init(struct relayd *, const char *);
50 int	 transaction_commit(struct relayd *);
51 void	 kill_tables(struct relayd *);
52 int	 kill_srcnodes(struct relayd *, struct table *);
53 
54 void
55 init_filter(struct relayd *env)
56 {
57 	struct pf_status	status;
58 
59 	if (!(env->sc_flags & F_NEEDPF))
60 		return;
61 
62 	if ((env->sc_pf = calloc(1, sizeof(*(env->sc_pf)))) == NULL)
63 		fatal("calloc");
64 	if ((env->sc_pf->dev = open(PF_SOCKET, O_RDWR)) == -1)
65 		fatal("init_filter: cannot open pf socket");
66 	if (ioctl(env->sc_pf->dev, DIOCGETSTATUS, &status) == -1)
67 		fatal("init_filter: DIOCGETSTATUS");
68 	if (!status.running)
69 		fatalx("init_filter: pf is disabled");
70 	log_debug("init_filter: filter init done");
71 }
72 
73 void
74 init_tables(struct relayd *env)
75 {
76 	int			 i;
77 	struct rdr		*rdr;
78 	struct pfr_table	*tables;
79 	struct pfioc_table	 io;
80 
81 	if (!(env->sc_flags & F_NEEDPF))
82 		return;
83 
84 	if ((tables = calloc(env->sc_rdrcount, sizeof(*tables))) == NULL)
85 		fatal("calloc");
86 	i = 0;
87 
88 	TAILQ_FOREACH(rdr, env->sc_rdrs, entry) {
89 		if (strlcpy(tables[i].pfrt_anchor, RELAYD_ANCHOR "/",
90 		    sizeof(tables[i].pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE)
91 			goto toolong;
92 		if (strlcat(tables[i].pfrt_anchor, rdr->conf.name,
93 		    sizeof(tables[i].pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE)
94 			goto toolong;
95 		if (strlcpy(tables[i].pfrt_name, rdr->conf.name,
96 		    sizeof(tables[i].pfrt_name)) >=
97 		    sizeof(tables[i].pfrt_name))
98 			goto toolong;
99 		tables[i].pfrt_flags |= PFR_TFLAG_PERSIST;
100 		i++;
101 	}
102 	if (i != env->sc_rdrcount)
103 		fatalx("init_tables: table count modified");
104 
105 	memset(&io, 0, sizeof(io));
106 	io.pfrio_size = env->sc_rdrcount;
107 	io.pfrio_esize = sizeof(*tables);
108 	io.pfrio_buffer = tables;
109 
110 	if (ioctl(env->sc_pf->dev, DIOCRADDTABLES, &io) == -1)
111 		fatal("init_tables: cannot create tables");
112 	log_debug("init_tables: created %d tables", io.pfrio_nadd);
113 
114 	free(tables);
115 
116 	if (io.pfrio_nadd == env->sc_rdrcount)
117 		return;
118 
119 	/*
120 	 * clear all tables, since some already existed
121 	 */
122 	TAILQ_FOREACH(rdr, env->sc_rdrs, entry)
123 		flush_table(env, rdr);
124 
125 	return;
126 
127  toolong:
128 	fatal("init_tables: name too long");
129 }
130 
131 void
132 kill_tables(struct relayd *env)
133 {
134 	struct pfioc_table	 io;
135 	struct rdr		*rdr;
136 	int			 cnt = 0;
137 
138 	if (!(env->sc_flags & F_NEEDPF))
139 		return;
140 
141 	TAILQ_FOREACH(rdr, env->sc_rdrs, entry) {
142 		memset(&io, 0, sizeof(io));
143 		if (strlcpy(io.pfrio_table.pfrt_anchor, RELAYD_ANCHOR "/",
144 		    sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE)
145 			goto toolong;
146 		if (strlcat(io.pfrio_table.pfrt_anchor, rdr->conf.name,
147 		    sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE)
148 			goto toolong;
149 		if (ioctl(env->sc_pf->dev, DIOCRCLRTABLES, &io) == -1)
150 			fatal("kill_tables: ioctl failed");
151 		cnt += io.pfrio_ndel;
152 	}
153 	log_debug("kill_tables: deleted %d tables", cnt);
154 	return;
155 
156  toolong:
157 	fatal("kill_tables: name too long");
158 }
159 
160 void
161 sync_table(struct relayd *env, struct rdr *rdr, struct table *table)
162 {
163 	int			 i, cnt = 0;
164 	struct pfioc_table	 io;
165 	struct pfr_addr		*addlist;
166 	struct sockaddr_in	*sain;
167 	struct sockaddr_in6	*sain6;
168 	struct host		*host;
169 
170 	if (!(env->sc_flags & F_NEEDPF))
171 		return;
172 
173 	if (table == NULL)
174 		return;
175 
176 	if (table->up == 0) {
177 		flush_table(env, rdr);
178 		return;
179 	}
180 
181 	if ((addlist = calloc(table->up, sizeof(*addlist))) == NULL)
182 		fatal("calloc");
183 
184 	memset(&io, 0, sizeof(io));
185 	io.pfrio_esize = sizeof(struct pfr_addr);
186 	io.pfrio_size = table->up;
187 	io.pfrio_size2 = 0;
188 	io.pfrio_buffer = addlist;
189 	if (strlcpy(io.pfrio_table.pfrt_anchor, RELAYD_ANCHOR "/",
190 	    sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE)
191 		goto toolong;
192 	if (strlcat(io.pfrio_table.pfrt_anchor, rdr->conf.name,
193 	    sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE)
194 		goto toolong;
195 	if (strlcpy(io.pfrio_table.pfrt_name, rdr->conf.name,
196 	    sizeof(io.pfrio_table.pfrt_name)) >=
197 	    sizeof(io.pfrio_table.pfrt_name))
198 		goto toolong;
199 
200 	i = 0;
201 	TAILQ_FOREACH(host, &table->hosts, entry) {
202 		if (host->up != HOST_UP)
203 			continue;
204 		memset(&(addlist[i]), 0, sizeof(addlist[i]));
205 		switch (host->conf.ss.ss_family) {
206 		case AF_INET:
207 			sain = (struct sockaddr_in *)&host->conf.ss;
208 			addlist[i].pfra_af = AF_INET;
209 			memcpy(&(addlist[i].pfra_ip4addr), &sain->sin_addr,
210 			    sizeof(sain->sin_addr));
211 			addlist[i].pfra_net = 32;
212 			break;
213 		case AF_INET6:
214 			sain6 = (struct sockaddr_in6 *)&host->conf.ss;
215 			addlist[i].pfra_af = AF_INET6;
216 			memcpy(&(addlist[i].pfra_ip6addr), &sain6->sin6_addr,
217 			    sizeof(sain6->sin6_addr));
218 			addlist[i].pfra_net = 128;
219 			break;
220 		default:
221 			fatalx("sync_table: unknown address family");
222 			break;
223 		}
224 		i++;
225 	}
226 	if (i != table->up)
227 		fatalx("sync_table: desynchronized");
228 
229 	if (ioctl(env->sc_pf->dev, DIOCRSETADDRS, &io) == -1)
230 		fatal("sync_table: cannot set address list");
231 	if (rdr->conf.flags & F_STICKY)
232 		cnt = kill_srcnodes(env, table);
233 	free(addlist);
234 
235 	if (env->sc_opts & RELAYD_OPT_LOGUPDATE)
236 		log_info("table %s: %d added, %d deleted, "
237 		    "%d changed, %d killed", io.pfrio_table.pfrt_name,
238 		    io.pfrio_nadd, io.pfrio_ndel, io.pfrio_nchange, cnt);
239 	return;
240 
241  toolong:
242 	fatal("sync_table: name too long");
243 }
244 
245 int
246 kill_srcnodes(struct relayd *env, struct table *table)
247 {
248 	struct host			*host;
249 	struct pfioc_src_node_kill	 psnk;
250 	int				 cnt = 0;
251 	struct sockaddr_in		*sain;
252 	struct sockaddr_in6		*sain6;
253 
254 	bzero(&psnk, sizeof(psnk));
255 
256 	/* Only match the destination address, source mask will be zero */
257 	memset(&psnk.psnk_dst.addr.v.a.mask, 0xff,
258 	    sizeof(psnk.psnk_dst.addr.v.a.mask));
259 
260 	TAILQ_FOREACH(host, &table->hosts, entry) {
261 		if (host->up != HOST_DOWN)
262 			continue;
263 
264 		switch (host->conf.ss.ss_family) {
265 		case AF_INET:
266 		sain = (struct sockaddr_in *)&host->conf.ss;
267 			bcopy(&sain->sin_addr,
268 			    &psnk.psnk_dst.addr.v.a.addr.v4,
269 			    sizeof(psnk.psnk_dst.addr.v.a.addr.v4));
270 			break;
271 		case AF_INET6:
272 			sain6 = (struct sockaddr_in6 *)&host->conf.ss;
273 			bcopy(&sain6->sin6_addr,
274 			    &psnk.psnk_dst.addr.v.a.addr.v6,
275 			    sizeof(psnk.psnk_dst.addr.v.a.addr.v6));
276 			break;
277 		default:
278 			fatalx("kill_srcnodes: unknown address family");
279 			break;
280 		}
281 
282 		psnk.psnk_af = host->conf.ss.ss_family;
283 		psnk.psnk_killed = 0;
284 
285 		if (ioctl(env->sc_pf->dev,
286 		    DIOCKILLSRCNODES, &psnk) == -1)
287 			fatal("kill_srcnodes: cannot kill src nodes");
288 		cnt += psnk.psnk_killed;
289 	}
290 
291 	return (cnt);
292 }
293 
294 void
295 flush_table(struct relayd *env, struct rdr *rdr)
296 {
297 	struct pfioc_table	io;
298 
299 	if (!(env->sc_flags & F_NEEDPF))
300 		return;
301 
302 	memset(&io, 0, sizeof(io));
303 	if (strlcpy(io.pfrio_table.pfrt_anchor, RELAYD_ANCHOR "/",
304 	    sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE)
305 		goto toolong;
306 	if (strlcat(io.pfrio_table.pfrt_anchor, rdr->conf.name,
307 	    sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE)
308 		goto toolong;
309 	if (strlcpy(io.pfrio_table.pfrt_name, rdr->conf.name,
310 	    sizeof(io.pfrio_table.pfrt_name)) >=
311 	    sizeof(io.pfrio_table.pfrt_name))
312 		goto toolong;
313 	if (ioctl(env->sc_pf->dev, DIOCRCLRADDRS, &io) == -1)
314 		fatal("flush_table: cannot flush table addresses");
315 
316 	io.pfrio_esize = sizeof(io.pfrio_table);
317 	io.pfrio_size = 1;
318 	io.pfrio_buffer = &io.pfrio_table;
319 	if (ioctl(env->sc_pf->dev, DIOCRCLRTSTATS, &io) == -1)
320 		fatal("flush_table: cannot flush table stats");
321 
322 	log_debug("flush_table: flushed table %s", rdr->conf.name);
323 	return;
324 
325  toolong:
326 	fatal("flush_table: name too long");
327 }
328 
329 int
330 transaction_init(struct relayd *env, const char *anchor)
331 {
332 	int i;
333 
334 	for (i = 0; i < PF_RULESET_MAX; i++) {
335 		env->sc_pf->pft[i].size = 1;
336 		env->sc_pf->pft[i].esize = sizeof(env->sc_pf->pfte[i]);
337 		env->sc_pf->pft[i].array = &env->sc_pf->pfte[i];
338 
339 		bzero(&env->sc_pf->pfte[i], sizeof(env->sc_pf->pfte[i]));
340 		(void)strlcpy(env->sc_pf->pfte[i].anchor,
341 		    anchor, PF_ANCHOR_NAME_SIZE);
342 		env->sc_pf->pfte[i].rs_num = i;
343 
344 		if (ioctl(env->sc_pf->dev, DIOCXBEGIN,
345 		    &env->sc_pf->pft[i]) == -1)
346 			return (-1);
347 	}
348 	return (0);
349 }
350 
351 int
352 transaction_commit(struct relayd *env)
353 {
354 	int i;
355 
356 	for (i = 0; i < PF_RULESET_MAX; i++) {
357 		if (ioctl(env->sc_pf->dev, DIOCXCOMMIT,
358 		    &env->sc_pf->pft[i]) == -1)
359 			return (-1);
360 	}
361 	return (0);
362 }
363 
364 void
365 sync_ruleset(struct relayd *env, struct rdr *rdr, int enable)
366 {
367 	struct pfioc_rule	 rio;
368 	struct pfioc_pooladdr	 pio;
369 	struct sockaddr_in	*sain;
370 	struct sockaddr_in6	*sain6;
371 	struct address		*address;
372 	char			 anchor[PF_ANCHOR_NAME_SIZE];
373 	int			 rs;
374 	struct table		*t = rdr->table;
375 
376 	if (!(env->sc_flags & F_NEEDPF))
377 		return;
378 
379 	bzero(anchor, sizeof(anchor));
380 	if (strlcpy(anchor, RELAYD_ANCHOR "/", sizeof(anchor)) >=
381 	    PF_ANCHOR_NAME_SIZE)
382 		goto toolong;
383 	if (strlcat(anchor, rdr->conf.name, sizeof(anchor)) >=
384 	    PF_ANCHOR_NAME_SIZE)
385 		goto toolong;
386 	if (transaction_init(env, anchor) == -1) {
387 		log_warn("sync_ruleset: transaction init failed");
388 		return;
389 	}
390 
391 	if (!enable) {
392 		if (transaction_commit(env) == -1)
393 			log_warn("sync_ruleset: "
394 			    "remove rules transaction failed");
395 		else
396 			log_debug("sync_ruleset: rules removed");
397 		return;
398 	}
399 
400 	TAILQ_FOREACH(address, &rdr->virts, entry) {
401 		memset(&rio, 0, sizeof(rio));
402 		memset(&pio, 0, sizeof(pio));
403 		(void)strlcpy(rio.anchor, anchor, sizeof(rio.anchor));
404 
405 		switch (t->conf.fwdmode) {
406 		case FWD_NORMAL:
407 			/* traditional redirection in the rdr-anchor */
408 			rs = PF_RULESET_RDR;
409 			rio.rule.action = PF_RDR;
410 			break;
411 		case FWD_ROUTE:
412 			/* re-route with pf for DSR (direct server return) */
413 			rs = PF_RULESET_FILTER;
414 			rio.rule.action = PF_PASS;
415 			rio.rule.rt = PF_ROUTETO;
416 			rio.rule.direction = PF_IN;
417 			rio.rule.quick = 1; /* force first match */
418 
419 			/* Use sloppy state handling for half connections */
420 			rio.rule.keep_state = PF_STATE_NORMAL;
421 			rio.rule.rule_flag = PFRULE_STATESLOPPY;
422 			break;
423 		default:
424 			fatalx("sync_ruleset: invalid forward mode");
425 			/* NOTREACHED */
426 		}
427 
428 		rio.ticket = env->sc_pf->pfte[rs].ticket;
429 		if (ioctl(env->sc_pf->dev, DIOCBEGINADDRS, &pio) == -1)
430 			fatal("sync_ruleset: cannot initialise address pool");
431 
432 		rio.pool_ticket = pio.ticket;
433 		rio.rule.af = address->ss.ss_family;
434 		rio.rule.proto = address->ipproto;
435 		rio.rule.src.addr.type = PF_ADDR_ADDRMASK;
436 		rio.rule.dst.addr.type = PF_ADDR_ADDRMASK;
437 		rio.rule.dst.port_op = address->port.op;
438 		rio.rule.dst.port[0] = address->port.val[0];
439 		rio.rule.dst.port[1] = address->port.val[1];
440 		rio.rule.rtableid = -1; /* stay in the main routing table */
441 
442 		if (rio.rule.proto == IPPROTO_TCP)
443 			rio.rule.timeout[PFTM_TCP_ESTABLISHED] =
444 			    rdr->conf.timeout.tv_sec;
445 
446 		if (strlen(rdr->conf.tag))
447 			(void)strlcpy(rio.rule.tagname, rdr->conf.tag,
448 			    sizeof(rio.rule.tagname));
449 		if (strlen(address->ifname))
450 			(void)strlcpy(rio.rule.ifname, address->ifname,
451 			    sizeof(rio.rule.ifname));
452 
453 		if (address->ss.ss_family == AF_INET) {
454 			sain = (struct sockaddr_in *)&address->ss;
455 
456 			rio.rule.dst.addr.v.a.addr.addr32[0] =
457 			    sain->sin_addr.s_addr;
458 			rio.rule.dst.addr.v.a.mask.addr32[0] = 0xffffffff;
459 		} else {
460 			sain6 = (struct sockaddr_in6 *)&address->ss;
461 
462 			memcpy(&rio.rule.dst.addr.v.a.addr.v6,
463 			    &sain6->sin6_addr.s6_addr,
464 			    sizeof(sain6->sin6_addr.s6_addr));
465 			memset(&rio.rule.dst.addr.v.a.mask.addr8, 0xff, 16);
466 		}
467 
468 		pio.addr.addr.type = PF_ADDR_TABLE;
469 		if (strlen(t->conf.ifname))
470 			(void)strlcpy(pio.addr.ifname, t->conf.ifname,
471 			    sizeof(pio.addr.ifname));
472 		if (strlcpy(pio.addr.addr.v.tblname, rdr->conf.name,
473 		    sizeof(pio.addr.addr.v.tblname)) >=
474 		    sizeof(pio.addr.addr.v.tblname))
475 			fatal("sync_ruleset: table name too long");
476 		if (ioctl(env->sc_pf->dev, DIOCADDADDR, &pio) == -1)
477 			fatal("sync_ruleset: cannot add address to pool");
478 
479 		if (address->port.op == PF_OP_EQ ||
480 		    rdr->table->conf.flags & F_PORT) {
481 			rio.rule.rpool.proxy_port[0] =
482 			    ntohs(rdr->table->conf.port);
483 			rio.rule.rpool.port_op = PF_OP_EQ;
484 		}
485 		rio.rule.rpool.opts = PF_POOL_ROUNDROBIN;
486 		if (rdr->conf.flags & F_STICKY)
487 			rio.rule.rpool.opts |= PF_POOL_STICKYADDR;
488 
489 		if (ioctl(env->sc_pf->dev, DIOCADDRULE, &rio) == -1)
490 			fatal("cannot add rule");
491 		log_debug("sync_ruleset: rule added to %sanchor \"%s\"",
492 		    rdr->table->conf.fwdmode == FWD_ROUTE ?
493 		    "" : "rdr-", anchor);
494 	}
495 	if (transaction_commit(env) == -1)
496 		log_warn("sync_ruleset: add rules transaction failed");
497 	return;
498 
499  toolong:
500 	fatal("sync_ruleset: name too long");
501 }
502 
503 void
504 flush_rulesets(struct relayd *env)
505 {
506 	struct rdr	*rdr;
507 	char		 anchor[PF_ANCHOR_NAME_SIZE];
508 
509 	if (!(env->sc_flags & F_NEEDPF))
510 		return;
511 
512 	kill_tables(env);
513 	TAILQ_FOREACH(rdr, env->sc_rdrs, entry) {
514 		if (strlcpy(anchor, RELAYD_ANCHOR "/", sizeof(anchor)) >=
515 		    PF_ANCHOR_NAME_SIZE)
516 			goto toolong;
517 		if (strlcat(anchor, rdr->conf.name, sizeof(anchor)) >=
518 		    PF_ANCHOR_NAME_SIZE)
519 			goto toolong;
520 		if (transaction_init(env, anchor) == -1 ||
521 		    transaction_commit(env) == -1)
522 			log_warn("flush_rulesets: transaction for %s/ failed",
523 			    RELAYD_ANCHOR);
524 	}
525 	if (strlcpy(anchor, RELAYD_ANCHOR, sizeof(anchor)) >=
526 	    PF_ANCHOR_NAME_SIZE)
527 		goto toolong;
528 	if (transaction_init(env, anchor) == -1 ||
529 	    transaction_commit(env) == -1)
530 		log_warn("flush_rulesets: transaction for %s failed",
531 		    RELAYD_ANCHOR);
532 	log_debug("flush_rulesets: flushed rules");
533 	return;
534 
535  toolong:
536 	fatal("flush_rulesets: name too long");
537 }
538 
539 int
540 natlook(struct relayd *env, struct ctl_natlook *cnl)
541 {
542 	struct pfioc_natlook	 pnl;
543 	struct sockaddr_in	*in, *out;
544 	struct sockaddr_in6	*in6, *out6;
545 	char			 ibuf[BUFSIZ], obuf[BUFSIZ];
546 
547 	if (!(env->sc_flags & F_NEEDPF))
548 		return (0);
549 
550 	bzero(&pnl, sizeof(pnl));
551 
552 	if ((pnl.af = cnl->src.ss_family) != cnl->dst.ss_family)
553 		fatalx("natlook: illegal address families");
554 	switch (pnl.af) {
555 	case AF_INET:
556 		in = (struct sockaddr_in *)&cnl->src;
557 		out = (struct sockaddr_in *)&cnl->dst;
558 		bcopy(&in->sin_addr, &pnl.saddr.v4, sizeof(pnl.saddr.v4));
559 		pnl.sport = in->sin_port;
560 		bcopy(&out->sin_addr, &pnl.daddr.v4, sizeof(pnl.daddr.v4));
561 		pnl.dport = out->sin_port;
562 		break;
563 	case AF_INET6:
564 		in6 = (struct sockaddr_in6 *)&cnl->src;
565 		out6 = (struct sockaddr_in6 *)&cnl->dst;
566 		bcopy(&in6->sin6_addr, &pnl.saddr.v6, sizeof(pnl.saddr.v6));
567 		pnl.sport = in6->sin6_port;
568 		bcopy(&out6->sin6_addr, &pnl.daddr.v6, sizeof(pnl.daddr.v6));
569 		pnl.dport = out6->sin6_port;
570 	}
571 	pnl.proto = cnl->proto;
572 	pnl.direction = PF_IN;
573 	cnl->in = 1;
574 
575 	if (ioctl(env->sc_pf->dev, DIOCNATLOOK, &pnl) == -1) {
576 		pnl.direction = PF_OUT;
577 		cnl->in = 0;
578 		if (ioctl(env->sc_pf->dev, DIOCNATLOOK, &pnl) == -1) {
579 			log_debug("natlook: error: %s", strerror(errno));
580 			return (-1);
581 		}
582 	}
583 
584 	inet_ntop(pnl.af, &pnl.rsaddr, ibuf, sizeof(ibuf));
585 	inet_ntop(pnl.af, &pnl.rdaddr, obuf, sizeof(obuf));
586 	log_debug("natlook: %s %s:%d -> %s:%d",
587 	    pnl.direction == PF_IN ? "in" : "out",
588 	    ibuf, ntohs(pnl.rsport), obuf, ntohs(pnl.rdport));
589 
590 	switch (pnl.af) {
591 	case AF_INET:
592 		in = (struct sockaddr_in *)&cnl->rsrc;
593 		out = (struct sockaddr_in *)&cnl->rdst;
594 		bcopy(&pnl.rsaddr.v4, &in->sin_addr, sizeof(in->sin_addr));
595 		in->sin_port = pnl.rsport;
596 		bcopy(&pnl.rdaddr.v4, &out->sin_addr, sizeof(out->sin_addr));
597 		out->sin_port = pnl.rdport;
598 		break;
599 	case AF_INET6:
600 		in6 = (struct sockaddr_in6 *)&cnl->rsrc;
601 		out6 = (struct sockaddr_in6 *)&cnl->rdst;
602 		bcopy(&pnl.rsaddr.v6, &in6->sin6_addr, sizeof(in6->sin6_addr));
603 		bcopy(&pnl.rdaddr.v6, &out6->sin6_addr,
604 		    sizeof(out6->sin6_addr));
605 		break;
606 	}
607 	cnl->rsrc.ss_family = pnl.af;
608 	cnl->rdst.ss_family = pnl.af;
609 	cnl->rsport = pnl.rsport;
610 	cnl->rdport = pnl.rdport;
611 
612 	return (0);
613 }
614 
615 u_int64_t
616 check_table(struct relayd *env, struct rdr *rdr, struct table *table)
617 {
618 	struct pfioc_table	 io;
619 	struct pfr_tstats	 tstats;
620 
621 	if (table == NULL)
622 		return (0);
623 
624 	bzero(&io, sizeof(io));
625 	io.pfrio_esize = sizeof(struct pfr_tstats);
626 	io.pfrio_size = 1;
627 	io.pfrio_buffer = &tstats;
628 	if (strlcpy(io.pfrio_table.pfrt_anchor, RELAYD_ANCHOR "/",
629 	    sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE)
630 		goto toolong;
631 	if (strlcat(io.pfrio_table.pfrt_anchor, rdr->conf.name,
632 	    sizeof(io.pfrio_table.pfrt_anchor)) >= PF_ANCHOR_NAME_SIZE)
633 		goto toolong;
634 	if (strlcpy(io.pfrio_table.pfrt_name, rdr->conf.name,
635 	    sizeof(io.pfrio_table.pfrt_name)) >=
636 	    sizeof(io.pfrio_table.pfrt_name))
637 		goto toolong;
638 
639 	if (ioctl(env->sc_pf->dev, DIOCRGETTSTATS, &io) == -1)
640 		fatal("check_table: cannot get table stats");
641 
642 	return (tstats.pfrts_match);
643 
644  toolong:
645 	fatal("check_table: name too long");
646 	return (0);
647 }
648