GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/relayd/pfe_filter.c Lines: 0 321 0.0 %
Date: 2017-11-07 Branches: 0 177 0.0 %

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