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