1 | #include <machine/rtems-bsd-user-space.h> |
---|
2 | |
---|
3 | /* $OpenBSD: pfctl_parser.c,v 1.240 2008/06/10 20:55:02 mcbride Exp $ */ |
---|
4 | |
---|
5 | /* |
---|
6 | * Copyright (c) 2001 Daniel Hartmeier |
---|
7 | * Copyright (c) 2002,2003 Henning Brauer |
---|
8 | * All rights reserved. |
---|
9 | * |
---|
10 | * Redistribution and use in source and binary forms, with or without |
---|
11 | * modification, are permitted provided that the following conditions |
---|
12 | * are met: |
---|
13 | * |
---|
14 | * - Redistributions of source code must retain the above copyright |
---|
15 | * notice, this list of conditions and the following disclaimer. |
---|
16 | * - Redistributions in binary form must reproduce the above |
---|
17 | * copyright notice, this list of conditions and the following |
---|
18 | * disclaimer in the documentation and/or other materials provided |
---|
19 | * with the distribution. |
---|
20 | * |
---|
21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
---|
22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
---|
23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
---|
24 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
---|
25 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
---|
26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
---|
27 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
---|
28 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
---|
29 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
30 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN |
---|
31 | * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
---|
32 | * POSSIBILITY OF SUCH DAMAGE. |
---|
33 | * |
---|
34 | */ |
---|
35 | |
---|
36 | #include <sys/cdefs.h> |
---|
37 | __FBSDID("$FreeBSD$"); |
---|
38 | |
---|
39 | #include <rtems/bsd/sys/types.h> |
---|
40 | #include <sys/ioctl.h> |
---|
41 | #include <sys/socket.h> |
---|
42 | #include <rtems/bsd/sys/param.h> |
---|
43 | #include <sys/proc.h> |
---|
44 | #include <net/if.h> |
---|
45 | #include <netinet/in.h> |
---|
46 | #include <netinet/in_systm.h> |
---|
47 | #include <netinet/ip.h> |
---|
48 | #include <netinet/ip_icmp.h> |
---|
49 | #include <netinet/icmp6.h> |
---|
50 | #include <net/pfvar.h> |
---|
51 | #include <arpa/inet.h> |
---|
52 | |
---|
53 | #include <stdio.h> |
---|
54 | #include <stdlib.h> |
---|
55 | #include <string.h> |
---|
56 | #include <ctype.h> |
---|
57 | #include <netdb.h> |
---|
58 | #include <stdarg.h> |
---|
59 | #include <errno.h> |
---|
60 | #include <err.h> |
---|
61 | #include <ifaddrs.h> |
---|
62 | #include <unistd.h> |
---|
63 | |
---|
64 | #include "pfctl_parser.h" |
---|
65 | #include "pfctl.h" |
---|
66 | |
---|
67 | void print_op (u_int8_t, const char *, const char *); |
---|
68 | void print_port (u_int8_t, u_int16_t, u_int16_t, const char *, int); |
---|
69 | void print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned); |
---|
70 | void print_flags (u_int8_t); |
---|
71 | void print_fromto(struct pf_rule_addr *, pf_osfp_t, |
---|
72 | struct pf_rule_addr *, u_int8_t, u_int8_t, int, int); |
---|
73 | int ifa_skip_if(const char *filter, struct node_host *p); |
---|
74 | |
---|
75 | struct node_host *ifa_grouplookup(const char *, int); |
---|
76 | struct node_host *host_if(const char *, int); |
---|
77 | struct node_host *host_v4(const char *, int); |
---|
78 | struct node_host *host_v6(const char *, int); |
---|
79 | struct node_host *host_dns(const char *, int, int); |
---|
80 | |
---|
81 | const char *tcpflags = "FSRPAUEW"; |
---|
82 | |
---|
83 | static const struct icmptypeent icmp_type[] = { |
---|
84 | { "echoreq", ICMP_ECHO }, |
---|
85 | { "echorep", ICMP_ECHOREPLY }, |
---|
86 | { "unreach", ICMP_UNREACH }, |
---|
87 | { "squench", ICMP_SOURCEQUENCH }, |
---|
88 | { "redir", ICMP_REDIRECT }, |
---|
89 | { "althost", ICMP_ALTHOSTADDR }, |
---|
90 | { "routeradv", ICMP_ROUTERADVERT }, |
---|
91 | { "routersol", ICMP_ROUTERSOLICIT }, |
---|
92 | { "timex", ICMP_TIMXCEED }, |
---|
93 | { "paramprob", ICMP_PARAMPROB }, |
---|
94 | { "timereq", ICMP_TSTAMP }, |
---|
95 | { "timerep", ICMP_TSTAMPREPLY }, |
---|
96 | { "inforeq", ICMP_IREQ }, |
---|
97 | { "inforep", ICMP_IREQREPLY }, |
---|
98 | { "maskreq", ICMP_MASKREQ }, |
---|
99 | { "maskrep", ICMP_MASKREPLY }, |
---|
100 | { "trace", ICMP_TRACEROUTE }, |
---|
101 | { "dataconv", ICMP_DATACONVERR }, |
---|
102 | { "mobredir", ICMP_MOBILE_REDIRECT }, |
---|
103 | { "ipv6-where", ICMP_IPV6_WHEREAREYOU }, |
---|
104 | { "ipv6-here", ICMP_IPV6_IAMHERE }, |
---|
105 | { "mobregreq", ICMP_MOBILE_REGREQUEST }, |
---|
106 | { "mobregrep", ICMP_MOBILE_REGREPLY }, |
---|
107 | { "skip", ICMP_SKIP }, |
---|
108 | { "photuris", ICMP_PHOTURIS } |
---|
109 | }; |
---|
110 | |
---|
111 | static const struct icmptypeent icmp6_type[] = { |
---|
112 | { "unreach", ICMP6_DST_UNREACH }, |
---|
113 | { "toobig", ICMP6_PACKET_TOO_BIG }, |
---|
114 | { "timex", ICMP6_TIME_EXCEEDED }, |
---|
115 | { "paramprob", ICMP6_PARAM_PROB }, |
---|
116 | { "echoreq", ICMP6_ECHO_REQUEST }, |
---|
117 | { "echorep", ICMP6_ECHO_REPLY }, |
---|
118 | { "groupqry", ICMP6_MEMBERSHIP_QUERY }, |
---|
119 | { "listqry", MLD_LISTENER_QUERY }, |
---|
120 | { "grouprep", ICMP6_MEMBERSHIP_REPORT }, |
---|
121 | { "listenrep", MLD_LISTENER_REPORT }, |
---|
122 | { "groupterm", ICMP6_MEMBERSHIP_REDUCTION }, |
---|
123 | { "listendone", MLD_LISTENER_DONE }, |
---|
124 | { "routersol", ND_ROUTER_SOLICIT }, |
---|
125 | { "routeradv", ND_ROUTER_ADVERT }, |
---|
126 | { "neighbrsol", ND_NEIGHBOR_SOLICIT }, |
---|
127 | { "neighbradv", ND_NEIGHBOR_ADVERT }, |
---|
128 | { "redir", ND_REDIRECT }, |
---|
129 | { "routrrenum", ICMP6_ROUTER_RENUMBERING }, |
---|
130 | { "wrureq", ICMP6_WRUREQUEST }, |
---|
131 | { "wrurep", ICMP6_WRUREPLY }, |
---|
132 | { "fqdnreq", ICMP6_FQDN_QUERY }, |
---|
133 | { "fqdnrep", ICMP6_FQDN_REPLY }, |
---|
134 | { "niqry", ICMP6_NI_QUERY }, |
---|
135 | { "nirep", ICMP6_NI_REPLY }, |
---|
136 | { "mtraceresp", MLD_MTRACE_RESP }, |
---|
137 | { "mtrace", MLD_MTRACE } |
---|
138 | }; |
---|
139 | |
---|
140 | static const struct icmpcodeent icmp_code[] = { |
---|
141 | { "net-unr", ICMP_UNREACH, ICMP_UNREACH_NET }, |
---|
142 | { "host-unr", ICMP_UNREACH, ICMP_UNREACH_HOST }, |
---|
143 | { "proto-unr", ICMP_UNREACH, ICMP_UNREACH_PROTOCOL }, |
---|
144 | { "port-unr", ICMP_UNREACH, ICMP_UNREACH_PORT }, |
---|
145 | { "needfrag", ICMP_UNREACH, ICMP_UNREACH_NEEDFRAG }, |
---|
146 | { "srcfail", ICMP_UNREACH, ICMP_UNREACH_SRCFAIL }, |
---|
147 | { "net-unk", ICMP_UNREACH, ICMP_UNREACH_NET_UNKNOWN }, |
---|
148 | { "host-unk", ICMP_UNREACH, ICMP_UNREACH_HOST_UNKNOWN }, |
---|
149 | { "isolate", ICMP_UNREACH, ICMP_UNREACH_ISOLATED }, |
---|
150 | { "net-prohib", ICMP_UNREACH, ICMP_UNREACH_NET_PROHIB }, |
---|
151 | { "host-prohib", ICMP_UNREACH, ICMP_UNREACH_HOST_PROHIB }, |
---|
152 | { "net-tos", ICMP_UNREACH, ICMP_UNREACH_TOSNET }, |
---|
153 | { "host-tos", ICMP_UNREACH, ICMP_UNREACH_TOSHOST }, |
---|
154 | { "filter-prohib", ICMP_UNREACH, ICMP_UNREACH_FILTER_PROHIB }, |
---|
155 | { "host-preced", ICMP_UNREACH, ICMP_UNREACH_HOST_PRECEDENCE }, |
---|
156 | { "cutoff-preced", ICMP_UNREACH, ICMP_UNREACH_PRECEDENCE_CUTOFF }, |
---|
157 | { "redir-net", ICMP_REDIRECT, ICMP_REDIRECT_NET }, |
---|
158 | { "redir-host", ICMP_REDIRECT, ICMP_REDIRECT_HOST }, |
---|
159 | { "redir-tos-net", ICMP_REDIRECT, ICMP_REDIRECT_TOSNET }, |
---|
160 | { "redir-tos-host", ICMP_REDIRECT, ICMP_REDIRECT_TOSHOST }, |
---|
161 | { "normal-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL }, |
---|
162 | { "common-adv", ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON }, |
---|
163 | { "transit", ICMP_TIMXCEED, ICMP_TIMXCEED_INTRANS }, |
---|
164 | { "reassemb", ICMP_TIMXCEED, ICMP_TIMXCEED_REASS }, |
---|
165 | { "badhead", ICMP_PARAMPROB, ICMP_PARAMPROB_ERRATPTR }, |
---|
166 | { "optmiss", ICMP_PARAMPROB, ICMP_PARAMPROB_OPTABSENT }, |
---|
167 | { "badlen", ICMP_PARAMPROB, ICMP_PARAMPROB_LENGTH }, |
---|
168 | { "unknown-ind", ICMP_PHOTURIS, ICMP_PHOTURIS_UNKNOWN_INDEX }, |
---|
169 | { "auth-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_AUTH_FAILED }, |
---|
170 | { "decrypt-fail", ICMP_PHOTURIS, ICMP_PHOTURIS_DECRYPT_FAILED } |
---|
171 | }; |
---|
172 | |
---|
173 | static const struct icmpcodeent icmp6_code[] = { |
---|
174 | { "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN }, |
---|
175 | { "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE }, |
---|
176 | { "notnbr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR }, |
---|
177 | { "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE }, |
---|
178 | { "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR }, |
---|
179 | { "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT }, |
---|
180 | { "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT }, |
---|
181 | { "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY }, |
---|
182 | { "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER }, |
---|
183 | { "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER }, |
---|
184 | { "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK }, |
---|
185 | { "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER } |
---|
186 | }; |
---|
187 | |
---|
188 | const struct pf_timeout pf_timeouts[] = { |
---|
189 | { "tcp.first", PFTM_TCP_FIRST_PACKET }, |
---|
190 | { "tcp.opening", PFTM_TCP_OPENING }, |
---|
191 | { "tcp.established", PFTM_TCP_ESTABLISHED }, |
---|
192 | { "tcp.closing", PFTM_TCP_CLOSING }, |
---|
193 | { "tcp.finwait", PFTM_TCP_FIN_WAIT }, |
---|
194 | { "tcp.closed", PFTM_TCP_CLOSED }, |
---|
195 | { "tcp.tsdiff", PFTM_TS_DIFF }, |
---|
196 | { "udp.first", PFTM_UDP_FIRST_PACKET }, |
---|
197 | { "udp.single", PFTM_UDP_SINGLE }, |
---|
198 | { "udp.multiple", PFTM_UDP_MULTIPLE }, |
---|
199 | { "icmp.first", PFTM_ICMP_FIRST_PACKET }, |
---|
200 | { "icmp.error", PFTM_ICMP_ERROR_REPLY }, |
---|
201 | { "other.first", PFTM_OTHER_FIRST_PACKET }, |
---|
202 | { "other.single", PFTM_OTHER_SINGLE }, |
---|
203 | { "other.multiple", PFTM_OTHER_MULTIPLE }, |
---|
204 | { "frag", PFTM_FRAG }, |
---|
205 | { "interval", PFTM_INTERVAL }, |
---|
206 | { "adaptive.start", PFTM_ADAPTIVE_START }, |
---|
207 | { "adaptive.end", PFTM_ADAPTIVE_END }, |
---|
208 | { "src.track", PFTM_SRC_NODE }, |
---|
209 | { NULL, 0 } |
---|
210 | }; |
---|
211 | |
---|
212 | const struct icmptypeent * |
---|
213 | geticmptypebynumber(u_int8_t type, sa_family_t af) |
---|
214 | { |
---|
215 | unsigned int i; |
---|
216 | |
---|
217 | if (af != AF_INET6) { |
---|
218 | for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); |
---|
219 | i++) { |
---|
220 | if (type == icmp_type[i].type) |
---|
221 | return (&icmp_type[i]); |
---|
222 | } |
---|
223 | } else { |
---|
224 | for (i=0; i < (sizeof (icmp6_type) / |
---|
225 | sizeof(icmp6_type[0])); i++) { |
---|
226 | if (type == icmp6_type[i].type) |
---|
227 | return (&icmp6_type[i]); |
---|
228 | } |
---|
229 | } |
---|
230 | return (NULL); |
---|
231 | } |
---|
232 | |
---|
233 | const struct icmptypeent * |
---|
234 | geticmptypebyname(char *w, sa_family_t af) |
---|
235 | { |
---|
236 | unsigned int i; |
---|
237 | |
---|
238 | if (af != AF_INET6) { |
---|
239 | for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0])); |
---|
240 | i++) { |
---|
241 | if (!strcmp(w, icmp_type[i].name)) |
---|
242 | return (&icmp_type[i]); |
---|
243 | } |
---|
244 | } else { |
---|
245 | for (i=0; i < (sizeof (icmp6_type) / |
---|
246 | sizeof(icmp6_type[0])); i++) { |
---|
247 | if (!strcmp(w, icmp6_type[i].name)) |
---|
248 | return (&icmp6_type[i]); |
---|
249 | } |
---|
250 | } |
---|
251 | return (NULL); |
---|
252 | } |
---|
253 | |
---|
254 | const struct icmpcodeent * |
---|
255 | geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af) |
---|
256 | { |
---|
257 | unsigned int i; |
---|
258 | |
---|
259 | if (af != AF_INET6) { |
---|
260 | for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); |
---|
261 | i++) { |
---|
262 | if (type == icmp_code[i].type && |
---|
263 | code == icmp_code[i].code) |
---|
264 | return (&icmp_code[i]); |
---|
265 | } |
---|
266 | } else { |
---|
267 | for (i=0; i < (sizeof (icmp6_code) / |
---|
268 | sizeof(icmp6_code[0])); i++) { |
---|
269 | if (type == icmp6_code[i].type && |
---|
270 | code == icmp6_code[i].code) |
---|
271 | return (&icmp6_code[i]); |
---|
272 | } |
---|
273 | } |
---|
274 | return (NULL); |
---|
275 | } |
---|
276 | |
---|
277 | const struct icmpcodeent * |
---|
278 | geticmpcodebyname(u_long type, char *w, sa_family_t af) |
---|
279 | { |
---|
280 | unsigned int i; |
---|
281 | |
---|
282 | if (af != AF_INET6) { |
---|
283 | for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0])); |
---|
284 | i++) { |
---|
285 | if (type == icmp_code[i].type && |
---|
286 | !strcmp(w, icmp_code[i].name)) |
---|
287 | return (&icmp_code[i]); |
---|
288 | } |
---|
289 | } else { |
---|
290 | for (i=0; i < (sizeof (icmp6_code) / |
---|
291 | sizeof(icmp6_code[0])); i++) { |
---|
292 | if (type == icmp6_code[i].type && |
---|
293 | !strcmp(w, icmp6_code[i].name)) |
---|
294 | return (&icmp6_code[i]); |
---|
295 | } |
---|
296 | } |
---|
297 | return (NULL); |
---|
298 | } |
---|
299 | |
---|
300 | void |
---|
301 | print_op(u_int8_t op, const char *a1, const char *a2) |
---|
302 | { |
---|
303 | if (op == PF_OP_IRG) |
---|
304 | printf(" %s >< %s", a1, a2); |
---|
305 | else if (op == PF_OP_XRG) |
---|
306 | printf(" %s <> %s", a1, a2); |
---|
307 | else if (op == PF_OP_EQ) |
---|
308 | printf(" = %s", a1); |
---|
309 | else if (op == PF_OP_NE) |
---|
310 | printf(" != %s", a1); |
---|
311 | else if (op == PF_OP_LT) |
---|
312 | printf(" < %s", a1); |
---|
313 | else if (op == PF_OP_LE) |
---|
314 | printf(" <= %s", a1); |
---|
315 | else if (op == PF_OP_GT) |
---|
316 | printf(" > %s", a1); |
---|
317 | else if (op == PF_OP_GE) |
---|
318 | printf(" >= %s", a1); |
---|
319 | else if (op == PF_OP_RRG) |
---|
320 | printf(" %s:%s", a1, a2); |
---|
321 | } |
---|
322 | |
---|
323 | void |
---|
324 | print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto, int numeric) |
---|
325 | { |
---|
326 | char a1[6], a2[6]; |
---|
327 | struct servent *s; |
---|
328 | |
---|
329 | if (!numeric) |
---|
330 | s = getservbyport(p1, proto); |
---|
331 | else |
---|
332 | s = NULL; |
---|
333 | p1 = ntohs(p1); |
---|
334 | p2 = ntohs(p2); |
---|
335 | snprintf(a1, sizeof(a1), "%u", p1); |
---|
336 | snprintf(a2, sizeof(a2), "%u", p2); |
---|
337 | printf(" port"); |
---|
338 | if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE)) |
---|
339 | print_op(op, s->s_name, a2); |
---|
340 | else |
---|
341 | print_op(op, a1, a2); |
---|
342 | } |
---|
343 | |
---|
344 | void |
---|
345 | print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax) |
---|
346 | { |
---|
347 | char a1[11], a2[11]; |
---|
348 | |
---|
349 | snprintf(a1, sizeof(a1), "%u", u1); |
---|
350 | snprintf(a2, sizeof(a2), "%u", u2); |
---|
351 | printf(" %s", t); |
---|
352 | if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE)) |
---|
353 | print_op(op, "unknown", a2); |
---|
354 | else |
---|
355 | print_op(op, a1, a2); |
---|
356 | } |
---|
357 | |
---|
358 | void |
---|
359 | print_flags(u_int8_t f) |
---|
360 | { |
---|
361 | int i; |
---|
362 | |
---|
363 | for (i = 0; tcpflags[i]; ++i) |
---|
364 | if (f & (1 << i)) |
---|
365 | printf("%c", tcpflags[i]); |
---|
366 | } |
---|
367 | |
---|
368 | void |
---|
369 | print_fromto(struct pf_rule_addr *src, pf_osfp_t osfp, struct pf_rule_addr *dst, |
---|
370 | sa_family_t af, u_int8_t proto, int verbose, int numeric) |
---|
371 | { |
---|
372 | char buf[PF_OSFP_LEN*3]; |
---|
373 | if (src->addr.type == PF_ADDR_ADDRMASK && |
---|
374 | dst->addr.type == PF_ADDR_ADDRMASK && |
---|
375 | PF_AZERO(&src->addr.v.a.addr, AF_INET6) && |
---|
376 | PF_AZERO(&src->addr.v.a.mask, AF_INET6) && |
---|
377 | PF_AZERO(&dst->addr.v.a.addr, AF_INET6) && |
---|
378 | PF_AZERO(&dst->addr.v.a.mask, AF_INET6) && |
---|
379 | !src->neg && !dst->neg && |
---|
380 | !src->port_op && !dst->port_op && |
---|
381 | osfp == PF_OSFP_ANY) |
---|
382 | printf(" all"); |
---|
383 | else { |
---|
384 | printf(" from "); |
---|
385 | if (src->neg) |
---|
386 | printf("! "); |
---|
387 | print_addr(&src->addr, af, verbose); |
---|
388 | if (src->port_op) |
---|
389 | print_port(src->port_op, src->port[0], |
---|
390 | src->port[1], |
---|
391 | proto == IPPROTO_TCP ? "tcp" : "udp", |
---|
392 | numeric); |
---|
393 | if (osfp != PF_OSFP_ANY) |
---|
394 | printf(" os \"%s\"", pfctl_lookup_fingerprint(osfp, buf, |
---|
395 | sizeof(buf))); |
---|
396 | |
---|
397 | printf(" to "); |
---|
398 | if (dst->neg) |
---|
399 | printf("! "); |
---|
400 | print_addr(&dst->addr, af, verbose); |
---|
401 | if (dst->port_op) |
---|
402 | print_port(dst->port_op, dst->port[0], |
---|
403 | dst->port[1], |
---|
404 | proto == IPPROTO_TCP ? "tcp" : "udp", |
---|
405 | numeric); |
---|
406 | } |
---|
407 | } |
---|
408 | |
---|
409 | void |
---|
410 | print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2, |
---|
411 | sa_family_t af, int id) |
---|
412 | { |
---|
413 | struct pf_pooladdr *pooladdr; |
---|
414 | |
---|
415 | if ((TAILQ_FIRST(&pool->list) != NULL) && |
---|
416 | TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) |
---|
417 | printf("{ "); |
---|
418 | TAILQ_FOREACH(pooladdr, &pool->list, entries){ |
---|
419 | switch (id) { |
---|
420 | case PF_NAT: |
---|
421 | case PF_RDR: |
---|
422 | case PF_BINAT: |
---|
423 | print_addr(&pooladdr->addr, af, 0); |
---|
424 | break; |
---|
425 | case PF_PASS: |
---|
426 | if (PF_AZERO(&pooladdr->addr.v.a.addr, af)) |
---|
427 | printf("%s", pooladdr->ifname); |
---|
428 | else { |
---|
429 | printf("(%s ", pooladdr->ifname); |
---|
430 | print_addr(&pooladdr->addr, af, 0); |
---|
431 | printf(")"); |
---|
432 | } |
---|
433 | break; |
---|
434 | default: |
---|
435 | break; |
---|
436 | } |
---|
437 | if (TAILQ_NEXT(pooladdr, entries) != NULL) |
---|
438 | printf(", "); |
---|
439 | else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL) |
---|
440 | printf(" }"); |
---|
441 | } |
---|
442 | switch (id) { |
---|
443 | case PF_NAT: |
---|
444 | if ((p1 != PF_NAT_PROXY_PORT_LOW || |
---|
445 | p2 != PF_NAT_PROXY_PORT_HIGH) && (p1 != 0 || p2 != 0)) { |
---|
446 | if (p1 == p2) |
---|
447 | printf(" port %u", p1); |
---|
448 | else |
---|
449 | printf(" port %u:%u", p1, p2); |
---|
450 | } |
---|
451 | break; |
---|
452 | case PF_RDR: |
---|
453 | if (p1) { |
---|
454 | printf(" port %u", p1); |
---|
455 | if (p2 && (p2 != p1)) |
---|
456 | printf(":%u", p2); |
---|
457 | } |
---|
458 | break; |
---|
459 | default: |
---|
460 | break; |
---|
461 | } |
---|
462 | switch (pool->opts & PF_POOL_TYPEMASK) { |
---|
463 | case PF_POOL_NONE: |
---|
464 | break; |
---|
465 | case PF_POOL_BITMASK: |
---|
466 | printf(" bitmask"); |
---|
467 | break; |
---|
468 | case PF_POOL_RANDOM: |
---|
469 | printf(" random"); |
---|
470 | break; |
---|
471 | case PF_POOL_SRCHASH: |
---|
472 | printf(" source-hash 0x%08x%08x%08x%08x", |
---|
473 | pool->key.key32[0], pool->key.key32[1], |
---|
474 | pool->key.key32[2], pool->key.key32[3]); |
---|
475 | break; |
---|
476 | case PF_POOL_ROUNDROBIN: |
---|
477 | printf(" round-robin"); |
---|
478 | break; |
---|
479 | } |
---|
480 | if (pool->opts & PF_POOL_STICKYADDR) |
---|
481 | printf(" sticky-address"); |
---|
482 | if (id == PF_NAT && p1 == 0 && p2 == 0) |
---|
483 | printf(" static-port"); |
---|
484 | } |
---|
485 | |
---|
486 | const char *pf_reasons[PFRES_MAX+1] = PFRES_NAMES; |
---|
487 | const char *pf_lcounters[LCNT_MAX+1] = LCNT_NAMES; |
---|
488 | const char *pf_fcounters[FCNT_MAX+1] = FCNT_NAMES; |
---|
489 | const char *pf_scounters[FCNT_MAX+1] = FCNT_NAMES; |
---|
490 | |
---|
491 | void |
---|
492 | print_status(struct pf_status *s, int opts) |
---|
493 | { |
---|
494 | char statline[80], *running; |
---|
495 | time_t runtime; |
---|
496 | int i; |
---|
497 | char buf[PF_MD5_DIGEST_LENGTH * 2 + 1]; |
---|
498 | static const char hex[] = "0123456789abcdef"; |
---|
499 | |
---|
500 | runtime = time(NULL) - s->since; |
---|
501 | running = s->running ? "Enabled" : "Disabled"; |
---|
502 | |
---|
503 | if (s->since) { |
---|
504 | unsigned int sec, min, hrs, day = runtime; |
---|
505 | |
---|
506 | sec = day % 60; |
---|
507 | day /= 60; |
---|
508 | min = day % 60; |
---|
509 | day /= 60; |
---|
510 | hrs = day % 24; |
---|
511 | day /= 24; |
---|
512 | snprintf(statline, sizeof(statline), |
---|
513 | "Status: %s for %u days %.2u:%.2u:%.2u", |
---|
514 | running, day, hrs, min, sec); |
---|
515 | } else |
---|
516 | snprintf(statline, sizeof(statline), "Status: %s", running); |
---|
517 | printf("%-44s", statline); |
---|
518 | switch (s->debug) { |
---|
519 | case PF_DEBUG_NONE: |
---|
520 | printf("%15s\n\n", "Debug: None"); |
---|
521 | break; |
---|
522 | case PF_DEBUG_URGENT: |
---|
523 | printf("%15s\n\n", "Debug: Urgent"); |
---|
524 | break; |
---|
525 | case PF_DEBUG_MISC: |
---|
526 | printf("%15s\n\n", "Debug: Misc"); |
---|
527 | break; |
---|
528 | case PF_DEBUG_NOISY: |
---|
529 | printf("%15s\n\n", "Debug: Loud"); |
---|
530 | break; |
---|
531 | } |
---|
532 | |
---|
533 | if (opts & PF_OPT_VERBOSE) { |
---|
534 | printf("Hostid: 0x%08x\n", ntohl(s->hostid)); |
---|
535 | |
---|
536 | for (i = 0; i < PF_MD5_DIGEST_LENGTH; i++) { |
---|
537 | buf[i + i] = hex[s->pf_chksum[i] >> 4]; |
---|
538 | buf[i + i + 1] = hex[s->pf_chksum[i] & 0x0f]; |
---|
539 | } |
---|
540 | buf[i + i] = '\0'; |
---|
541 | printf("Checksum: 0x%s\n\n", buf); |
---|
542 | } |
---|
543 | |
---|
544 | if (s->ifname[0] != 0) { |
---|
545 | printf("Interface Stats for %-16s %5s %16s\n", |
---|
546 | s->ifname, "IPv4", "IPv6"); |
---|
547 | printf(" %-25s %14llu %16llu\n", "Bytes In", |
---|
548 | (unsigned long long)s->bcounters[0][0], |
---|
549 | (unsigned long long)s->bcounters[1][0]); |
---|
550 | printf(" %-25s %14llu %16llu\n", "Bytes Out", |
---|
551 | (unsigned long long)s->bcounters[0][1], |
---|
552 | (unsigned long long)s->bcounters[1][1]); |
---|
553 | printf(" Packets In\n"); |
---|
554 | printf(" %-23s %14llu %16llu\n", "Passed", |
---|
555 | (unsigned long long)s->pcounters[0][0][PF_PASS], |
---|
556 | (unsigned long long)s->pcounters[1][0][PF_PASS]); |
---|
557 | printf(" %-23s %14llu %16llu\n", "Blocked", |
---|
558 | (unsigned long long)s->pcounters[0][0][PF_DROP], |
---|
559 | (unsigned long long)s->pcounters[1][0][PF_DROP]); |
---|
560 | printf(" Packets Out\n"); |
---|
561 | printf(" %-23s %14llu %16llu\n", "Passed", |
---|
562 | (unsigned long long)s->pcounters[0][1][PF_PASS], |
---|
563 | (unsigned long long)s->pcounters[1][1][PF_PASS]); |
---|
564 | printf(" %-23s %14llu %16llu\n\n", "Blocked", |
---|
565 | (unsigned long long)s->pcounters[0][1][PF_DROP], |
---|
566 | (unsigned long long)s->pcounters[1][1][PF_DROP]); |
---|
567 | } |
---|
568 | printf("%-27s %14s %16s\n", "State Table", "Total", "Rate"); |
---|
569 | printf(" %-25s %14u %14s\n", "current entries", s->states, ""); |
---|
570 | for (i = 0; i < FCNT_MAX; i++) { |
---|
571 | printf(" %-25s %14llu ", pf_fcounters[i], |
---|
572 | (unsigned long long)s->fcounters[i]); |
---|
573 | if (runtime > 0) |
---|
574 | printf("%14.1f/s\n", |
---|
575 | (double)s->fcounters[i] / (double)runtime); |
---|
576 | else |
---|
577 | printf("%14s\n", ""); |
---|
578 | } |
---|
579 | if (opts & PF_OPT_VERBOSE) { |
---|
580 | printf("Source Tracking Table\n"); |
---|
581 | printf(" %-25s %14u %14s\n", "current entries", |
---|
582 | s->src_nodes, ""); |
---|
583 | for (i = 0; i < SCNT_MAX; i++) { |
---|
584 | printf(" %-25s %14lld ", pf_scounters[i], |
---|
585 | #ifdef __FreeBSD__ |
---|
586 | (long long)s->scounters[i]); |
---|
587 | #else |
---|
588 | s->scounters[i]); |
---|
589 | #endif |
---|
590 | if (runtime > 0) |
---|
591 | printf("%14.1f/s\n", |
---|
592 | (double)s->scounters[i] / (double)runtime); |
---|
593 | else |
---|
594 | printf("%14s\n", ""); |
---|
595 | } |
---|
596 | } |
---|
597 | printf("Counters\n"); |
---|
598 | for (i = 0; i < PFRES_MAX; i++) { |
---|
599 | printf(" %-25s %14llu ", pf_reasons[i], |
---|
600 | (unsigned long long)s->counters[i]); |
---|
601 | if (runtime > 0) |
---|
602 | printf("%14.1f/s\n", |
---|
603 | (double)s->counters[i] / (double)runtime); |
---|
604 | else |
---|
605 | printf("%14s\n", ""); |
---|
606 | } |
---|
607 | if (opts & PF_OPT_VERBOSE) { |
---|
608 | printf("Limit Counters\n"); |
---|
609 | for (i = 0; i < LCNT_MAX; i++) { |
---|
610 | printf(" %-25s %14lld ", pf_lcounters[i], |
---|
611 | #ifdef __FreeBSD__ |
---|
612 | (unsigned long long)s->lcounters[i]); |
---|
613 | #else |
---|
614 | s->lcounters[i]); |
---|
615 | #endif |
---|
616 | if (runtime > 0) |
---|
617 | printf("%14.1f/s\n", |
---|
618 | (double)s->lcounters[i] / (double)runtime); |
---|
619 | else |
---|
620 | printf("%14s\n", ""); |
---|
621 | } |
---|
622 | } |
---|
623 | } |
---|
624 | |
---|
625 | void |
---|
626 | print_src_node(struct pf_src_node *sn, int opts) |
---|
627 | { |
---|
628 | struct pf_addr_wrap aw; |
---|
629 | int min, sec; |
---|
630 | |
---|
631 | memset(&aw, 0, sizeof(aw)); |
---|
632 | if (sn->af == AF_INET) |
---|
633 | aw.v.a.mask.addr32[0] = 0xffffffff; |
---|
634 | else |
---|
635 | memset(&aw.v.a.mask, 0xff, sizeof(aw.v.a.mask)); |
---|
636 | |
---|
637 | aw.v.a.addr = sn->addr; |
---|
638 | print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); |
---|
639 | printf(" -> "); |
---|
640 | aw.v.a.addr = sn->raddr; |
---|
641 | print_addr(&aw, sn->af, opts & PF_OPT_VERBOSE2); |
---|
642 | printf(" ( states %u, connections %u, rate %u.%u/%us )\n", sn->states, |
---|
643 | sn->conn, sn->conn_rate.count / 1000, |
---|
644 | (sn->conn_rate.count % 1000) / 100, sn->conn_rate.seconds); |
---|
645 | if (opts & PF_OPT_VERBOSE) { |
---|
646 | sec = sn->creation % 60; |
---|
647 | sn->creation /= 60; |
---|
648 | min = sn->creation % 60; |
---|
649 | sn->creation /= 60; |
---|
650 | printf(" age %.2u:%.2u:%.2u", sn->creation, min, sec); |
---|
651 | if (sn->states == 0) { |
---|
652 | sec = sn->expire % 60; |
---|
653 | sn->expire /= 60; |
---|
654 | min = sn->expire % 60; |
---|
655 | sn->expire /= 60; |
---|
656 | printf(", expires in %.2u:%.2u:%.2u", |
---|
657 | sn->expire, min, sec); |
---|
658 | } |
---|
659 | printf(", %llu pkts, %llu bytes", |
---|
660 | #ifdef __FreeBSD__ |
---|
661 | (unsigned long long)(sn->packets[0] + sn->packets[1]), |
---|
662 | (unsigned long long)(sn->bytes[0] + sn->bytes[1])); |
---|
663 | #else |
---|
664 | sn->packets[0] + sn->packets[1], |
---|
665 | sn->bytes[0] + sn->bytes[1]); |
---|
666 | #endif |
---|
667 | switch (sn->ruletype) { |
---|
668 | case PF_NAT: |
---|
669 | if (sn->rule.nr != -1) |
---|
670 | printf(", nat rule %u", sn->rule.nr); |
---|
671 | break; |
---|
672 | case PF_RDR: |
---|
673 | if (sn->rule.nr != -1) |
---|
674 | printf(", rdr rule %u", sn->rule.nr); |
---|
675 | break; |
---|
676 | case PF_PASS: |
---|
677 | if (sn->rule.nr != -1) |
---|
678 | printf(", filter rule %u", sn->rule.nr); |
---|
679 | break; |
---|
680 | } |
---|
681 | printf("\n"); |
---|
682 | } |
---|
683 | } |
---|
684 | |
---|
685 | void |
---|
686 | print_rule(struct pf_rule *r, const char *anchor_call, int verbose, int numeric) |
---|
687 | { |
---|
688 | static const char *actiontypes[] = { "pass", "block", "scrub", |
---|
689 | "no scrub", "nat", "no nat", "binat", "no binat", "rdr", "no rdr" }; |
---|
690 | static const char *anchortypes[] = { "anchor", "anchor", "anchor", |
---|
691 | "anchor", "nat-anchor", "nat-anchor", "binat-anchor", |
---|
692 | "binat-anchor", "rdr-anchor", "rdr-anchor" }; |
---|
693 | int i, opts; |
---|
694 | |
---|
695 | if (verbose) |
---|
696 | printf("@%d ", r->nr); |
---|
697 | if (r->action > PF_NORDR) |
---|
698 | printf("action(%d)", r->action); |
---|
699 | else if (anchor_call[0]) { |
---|
700 | if (anchor_call[0] == '_') { |
---|
701 | printf("%s", anchortypes[r->action]); |
---|
702 | } else |
---|
703 | printf("%s \"%s\"", anchortypes[r->action], |
---|
704 | anchor_call); |
---|
705 | } else { |
---|
706 | printf("%s", actiontypes[r->action]); |
---|
707 | if (r->natpass) |
---|
708 | printf(" pass"); |
---|
709 | } |
---|
710 | if (r->action == PF_DROP) { |
---|
711 | if (r->rule_flag & PFRULE_RETURN) |
---|
712 | printf(" return"); |
---|
713 | else if (r->rule_flag & PFRULE_RETURNRST) { |
---|
714 | if (!r->return_ttl) |
---|
715 | printf(" return-rst"); |
---|
716 | else |
---|
717 | printf(" return-rst(ttl %d)", r->return_ttl); |
---|
718 | } else if (r->rule_flag & PFRULE_RETURNICMP) { |
---|
719 | const struct icmpcodeent *ic, *ic6; |
---|
720 | |
---|
721 | ic = geticmpcodebynumber(r->return_icmp >> 8, |
---|
722 | r->return_icmp & 255, AF_INET); |
---|
723 | ic6 = geticmpcodebynumber(r->return_icmp6 >> 8, |
---|
724 | r->return_icmp6 & 255, AF_INET6); |
---|
725 | |
---|
726 | switch (r->af) { |
---|
727 | case AF_INET: |
---|
728 | printf(" return-icmp"); |
---|
729 | if (ic == NULL) |
---|
730 | printf("(%u)", r->return_icmp & 255); |
---|
731 | else |
---|
732 | printf("(%s)", ic->name); |
---|
733 | break; |
---|
734 | case AF_INET6: |
---|
735 | printf(" return-icmp6"); |
---|
736 | if (ic6 == NULL) |
---|
737 | printf("(%u)", r->return_icmp6 & 255); |
---|
738 | else |
---|
739 | printf("(%s)", ic6->name); |
---|
740 | break; |
---|
741 | default: |
---|
742 | printf(" return-icmp"); |
---|
743 | if (ic == NULL) |
---|
744 | printf("(%u, ", r->return_icmp & 255); |
---|
745 | else |
---|
746 | printf("(%s, ", ic->name); |
---|
747 | if (ic6 == NULL) |
---|
748 | printf("%u)", r->return_icmp6 & 255); |
---|
749 | else |
---|
750 | printf("%s)", ic6->name); |
---|
751 | break; |
---|
752 | } |
---|
753 | } else |
---|
754 | printf(" drop"); |
---|
755 | } |
---|
756 | if (r->direction == PF_IN) |
---|
757 | printf(" in"); |
---|
758 | else if (r->direction == PF_OUT) |
---|
759 | printf(" out"); |
---|
760 | if (r->log) { |
---|
761 | printf(" log"); |
---|
762 | if (r->log & ~PF_LOG || r->logif) { |
---|
763 | int count = 0; |
---|
764 | |
---|
765 | printf(" ("); |
---|
766 | if (r->log & PF_LOG_ALL) |
---|
767 | printf("%sall", count++ ? ", " : ""); |
---|
768 | if (r->log & PF_LOG_SOCKET_LOOKUP) |
---|
769 | printf("%suser", count++ ? ", " : ""); |
---|
770 | if (r->logif) |
---|
771 | printf("%sto pflog%u", count++ ? ", " : "", |
---|
772 | r->logif); |
---|
773 | printf(")"); |
---|
774 | } |
---|
775 | } |
---|
776 | if (r->quick) |
---|
777 | printf(" quick"); |
---|
778 | if (r->ifname[0]) { |
---|
779 | if (r->ifnot) |
---|
780 | printf(" on ! %s", r->ifname); |
---|
781 | else |
---|
782 | printf(" on %s", r->ifname); |
---|
783 | } |
---|
784 | if (r->rt) { |
---|
785 | if (r->rt == PF_ROUTETO) |
---|
786 | printf(" route-to"); |
---|
787 | else if (r->rt == PF_REPLYTO) |
---|
788 | printf(" reply-to"); |
---|
789 | else if (r->rt == PF_DUPTO) |
---|
790 | printf(" dup-to"); |
---|
791 | else if (r->rt == PF_FASTROUTE) |
---|
792 | printf(" fastroute"); |
---|
793 | if (r->rt != PF_FASTROUTE) { |
---|
794 | printf(" "); |
---|
795 | print_pool(&r->rpool, 0, 0, r->af, PF_PASS); |
---|
796 | } |
---|
797 | } |
---|
798 | if (r->af) { |
---|
799 | if (r->af == AF_INET) |
---|
800 | printf(" inet"); |
---|
801 | else |
---|
802 | printf(" inet6"); |
---|
803 | } |
---|
804 | if (r->proto) { |
---|
805 | struct protoent *p; |
---|
806 | |
---|
807 | if ((p = getprotobynumber(r->proto)) != NULL) |
---|
808 | printf(" proto %s", p->p_name); |
---|
809 | else |
---|
810 | printf(" proto %u", r->proto); |
---|
811 | } |
---|
812 | print_fromto(&r->src, r->os_fingerprint, &r->dst, r->af, r->proto, |
---|
813 | verbose, numeric); |
---|
814 | if (r->uid.op) |
---|
815 | print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user", |
---|
816 | UID_MAX); |
---|
817 | if (r->gid.op) |
---|
818 | print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group", |
---|
819 | GID_MAX); |
---|
820 | if (r->flags || r->flagset) { |
---|
821 | printf(" flags "); |
---|
822 | print_flags(r->flags); |
---|
823 | printf("/"); |
---|
824 | print_flags(r->flagset); |
---|
825 | } else if (r->action == PF_PASS && |
---|
826 | (!r->proto || r->proto == IPPROTO_TCP) && |
---|
827 | !(r->rule_flag & PFRULE_FRAGMENT) && |
---|
828 | !anchor_call[0] && r->keep_state) |
---|
829 | printf(" flags any"); |
---|
830 | if (r->type) { |
---|
831 | const struct icmptypeent *it; |
---|
832 | |
---|
833 | it = geticmptypebynumber(r->type-1, r->af); |
---|
834 | if (r->af != AF_INET6) |
---|
835 | printf(" icmp-type"); |
---|
836 | else |
---|
837 | printf(" icmp6-type"); |
---|
838 | if (it != NULL) |
---|
839 | printf(" %s", it->name); |
---|
840 | else |
---|
841 | printf(" %u", r->type-1); |
---|
842 | if (r->code) { |
---|
843 | const struct icmpcodeent *ic; |
---|
844 | |
---|
845 | ic = geticmpcodebynumber(r->type-1, r->code-1, r->af); |
---|
846 | if (ic != NULL) |
---|
847 | printf(" code %s", ic->name); |
---|
848 | else |
---|
849 | printf(" code %u", r->code-1); |
---|
850 | } |
---|
851 | } |
---|
852 | if (r->tos) |
---|
853 | printf(" tos 0x%2.2x", r->tos); |
---|
854 | if (!r->keep_state && r->action == PF_PASS && !anchor_call[0]) |
---|
855 | printf(" no state"); |
---|
856 | else if (r->keep_state == PF_STATE_NORMAL) |
---|
857 | printf(" keep state"); |
---|
858 | else if (r->keep_state == PF_STATE_MODULATE) |
---|
859 | printf(" modulate state"); |
---|
860 | else if (r->keep_state == PF_STATE_SYNPROXY) |
---|
861 | printf(" synproxy state"); |
---|
862 | if (r->prob) { |
---|
863 | char buf[20]; |
---|
864 | |
---|
865 | snprintf(buf, sizeof(buf), "%f", r->prob*100.0/(UINT_MAX+1.0)); |
---|
866 | for (i = strlen(buf)-1; i > 0; i--) { |
---|
867 | if (buf[i] == '0') |
---|
868 | buf[i] = '\0'; |
---|
869 | else { |
---|
870 | if (buf[i] == '.') |
---|
871 | buf[i] = '\0'; |
---|
872 | break; |
---|
873 | } |
---|
874 | } |
---|
875 | printf(" probability %s%%", buf); |
---|
876 | } |
---|
877 | opts = 0; |
---|
878 | if (r->max_states || r->max_src_nodes || r->max_src_states) |
---|
879 | opts = 1; |
---|
880 | if (r->rule_flag & PFRULE_NOSYNC) |
---|
881 | opts = 1; |
---|
882 | if (r->rule_flag & PFRULE_SRCTRACK) |
---|
883 | opts = 1; |
---|
884 | if (r->rule_flag & PFRULE_IFBOUND) |
---|
885 | opts = 1; |
---|
886 | if (r->rule_flag & PFRULE_STATESLOPPY) |
---|
887 | opts = 1; |
---|
888 | for (i = 0; !opts && i < PFTM_MAX; ++i) |
---|
889 | if (r->timeout[i]) |
---|
890 | opts = 1; |
---|
891 | if (opts) { |
---|
892 | printf(" ("); |
---|
893 | if (r->max_states) { |
---|
894 | printf("max %u", r->max_states); |
---|
895 | opts = 0; |
---|
896 | } |
---|
897 | if (r->rule_flag & PFRULE_NOSYNC) { |
---|
898 | if (!opts) |
---|
899 | printf(", "); |
---|
900 | printf("no-sync"); |
---|
901 | opts = 0; |
---|
902 | } |
---|
903 | if (r->rule_flag & PFRULE_SRCTRACK) { |
---|
904 | if (!opts) |
---|
905 | printf(", "); |
---|
906 | printf("source-track"); |
---|
907 | if (r->rule_flag & PFRULE_RULESRCTRACK) |
---|
908 | printf(" rule"); |
---|
909 | else |
---|
910 | printf(" global"); |
---|
911 | opts = 0; |
---|
912 | } |
---|
913 | if (r->max_src_states) { |
---|
914 | if (!opts) |
---|
915 | printf(", "); |
---|
916 | printf("max-src-states %u", r->max_src_states); |
---|
917 | opts = 0; |
---|
918 | } |
---|
919 | if (r->max_src_conn) { |
---|
920 | if (!opts) |
---|
921 | printf(", "); |
---|
922 | printf("max-src-conn %u", r->max_src_conn); |
---|
923 | opts = 0; |
---|
924 | } |
---|
925 | if (r->max_src_conn_rate.limit) { |
---|
926 | if (!opts) |
---|
927 | printf(", "); |
---|
928 | printf("max-src-conn-rate %u/%u", |
---|
929 | r->max_src_conn_rate.limit, |
---|
930 | r->max_src_conn_rate.seconds); |
---|
931 | opts = 0; |
---|
932 | } |
---|
933 | if (r->max_src_nodes) { |
---|
934 | if (!opts) |
---|
935 | printf(", "); |
---|
936 | printf("max-src-nodes %u", r->max_src_nodes); |
---|
937 | opts = 0; |
---|
938 | } |
---|
939 | if (r->overload_tblname[0]) { |
---|
940 | if (!opts) |
---|
941 | printf(", "); |
---|
942 | printf("overload <%s>", r->overload_tblname); |
---|
943 | if (r->flush) |
---|
944 | printf(" flush"); |
---|
945 | if (r->flush & PF_FLUSH_GLOBAL) |
---|
946 | printf(" global"); |
---|
947 | } |
---|
948 | if (r->rule_flag & PFRULE_IFBOUND) { |
---|
949 | if (!opts) |
---|
950 | printf(", "); |
---|
951 | printf("if-bound"); |
---|
952 | opts = 0; |
---|
953 | } |
---|
954 | if (r->rule_flag & PFRULE_STATESLOPPY) { |
---|
955 | if (!opts) |
---|
956 | printf(", "); |
---|
957 | printf("sloppy"); |
---|
958 | opts = 0; |
---|
959 | } |
---|
960 | if (r->rule_flag & PFRULE_PFLOW) { |
---|
961 | if (!opts) |
---|
962 | printf(", "); |
---|
963 | printf("pflow"); |
---|
964 | opts = 0; |
---|
965 | } |
---|
966 | for (i = 0; i < PFTM_MAX; ++i) |
---|
967 | if (r->timeout[i]) { |
---|
968 | int j; |
---|
969 | |
---|
970 | if (!opts) |
---|
971 | printf(", "); |
---|
972 | opts = 0; |
---|
973 | for (j = 0; pf_timeouts[j].name != NULL; |
---|
974 | ++j) |
---|
975 | if (pf_timeouts[j].timeout == i) |
---|
976 | break; |
---|
977 | printf("%s %u", pf_timeouts[j].name == NULL ? |
---|
978 | "inv.timeout" : pf_timeouts[j].name, |
---|
979 | r->timeout[i]); |
---|
980 | } |
---|
981 | printf(")"); |
---|
982 | } |
---|
983 | if (r->rule_flag & PFRULE_FRAGMENT) |
---|
984 | printf(" fragment"); |
---|
985 | if (r->rule_flag & PFRULE_NODF) |
---|
986 | printf(" no-df"); |
---|
987 | if (r->rule_flag & PFRULE_RANDOMID) |
---|
988 | printf(" random-id"); |
---|
989 | if (r->min_ttl) |
---|
990 | printf(" min-ttl %d", r->min_ttl); |
---|
991 | if (r->max_mss) |
---|
992 | printf(" max-mss %d", r->max_mss); |
---|
993 | if (r->rule_flag & PFRULE_SET_TOS) |
---|
994 | printf(" set-tos 0x%2.2x", r->set_tos); |
---|
995 | if (r->allow_opts) |
---|
996 | printf(" allow-opts"); |
---|
997 | if (r->action == PF_SCRUB) { |
---|
998 | if (r->rule_flag & PFRULE_REASSEMBLE_TCP) |
---|
999 | printf(" reassemble tcp"); |
---|
1000 | |
---|
1001 | if (r->rule_flag & PFRULE_FRAGDROP) |
---|
1002 | printf(" fragment drop-ovl"); |
---|
1003 | else if (r->rule_flag & PFRULE_FRAGCROP) |
---|
1004 | printf(" fragment crop"); |
---|
1005 | else |
---|
1006 | printf(" fragment reassemble"); |
---|
1007 | } |
---|
1008 | if (r->label[0]) |
---|
1009 | printf(" label \"%s\"", r->label); |
---|
1010 | if (r->qname[0] && r->pqname[0]) |
---|
1011 | printf(" queue(%s, %s)", r->qname, r->pqname); |
---|
1012 | else if (r->qname[0]) |
---|
1013 | printf(" queue %s", r->qname); |
---|
1014 | if (r->tagname[0]) |
---|
1015 | printf(" tag %s", r->tagname); |
---|
1016 | if (r->match_tagname[0]) { |
---|
1017 | if (r->match_tag_not) |
---|
1018 | printf(" !"); |
---|
1019 | printf(" tagged %s", r->match_tagname); |
---|
1020 | } |
---|
1021 | if (r->rtableid != -1) |
---|
1022 | printf(" rtable %u", r->rtableid); |
---|
1023 | if (r->divert.port) { |
---|
1024 | #ifdef __FreeBSD__ |
---|
1025 | printf(" divert-to %u", ntohs(r->divert.port)); |
---|
1026 | #else |
---|
1027 | if (PF_AZERO(&r->divert.addr, r->af)) { |
---|
1028 | printf(" divert-reply"); |
---|
1029 | } else { |
---|
1030 | /* XXX cut&paste from print_addr */ |
---|
1031 | char buf[48]; |
---|
1032 | |
---|
1033 | printf(" divert-to "); |
---|
1034 | if (inet_ntop(r->af, &r->divert.addr, buf, |
---|
1035 | sizeof(buf)) == NULL) |
---|
1036 | printf("?"); |
---|
1037 | else |
---|
1038 | printf("%s", buf); |
---|
1039 | printf(" port %u", ntohs(r->divert.port)); |
---|
1040 | } |
---|
1041 | #endif |
---|
1042 | } |
---|
1043 | if (!anchor_call[0] && (r->action == PF_NAT || |
---|
1044 | r->action == PF_BINAT || r->action == PF_RDR)) { |
---|
1045 | printf(" -> "); |
---|
1046 | print_pool(&r->rpool, r->rpool.proxy_port[0], |
---|
1047 | r->rpool.proxy_port[1], r->af, r->action); |
---|
1048 | } |
---|
1049 | } |
---|
1050 | |
---|
1051 | void |
---|
1052 | print_tabledef(const char *name, int flags, int addrs, |
---|
1053 | struct node_tinithead *nodes) |
---|
1054 | { |
---|
1055 | struct node_tinit *ti, *nti; |
---|
1056 | struct node_host *h; |
---|
1057 | |
---|
1058 | printf("table <%s>", name); |
---|
1059 | if (flags & PFR_TFLAG_CONST) |
---|
1060 | printf(" const"); |
---|
1061 | if (flags & PFR_TFLAG_PERSIST) |
---|
1062 | printf(" persist"); |
---|
1063 | if (flags & PFR_TFLAG_COUNTERS) |
---|
1064 | printf(" counters"); |
---|
1065 | SIMPLEQ_FOREACH(ti, nodes, entries) { |
---|
1066 | if (ti->file) { |
---|
1067 | printf(" file \"%s\"", ti->file); |
---|
1068 | continue; |
---|
1069 | } |
---|
1070 | printf(" {"); |
---|
1071 | for (;;) { |
---|
1072 | for (h = ti->host; h != NULL; h = h->next) { |
---|
1073 | printf(h->not ? " !" : " "); |
---|
1074 | print_addr(&h->addr, h->af, 0); |
---|
1075 | } |
---|
1076 | nti = SIMPLEQ_NEXT(ti, entries); |
---|
1077 | if (nti != NULL && nti->file == NULL) |
---|
1078 | ti = nti; /* merge lists */ |
---|
1079 | else |
---|
1080 | break; |
---|
1081 | } |
---|
1082 | printf(" }"); |
---|
1083 | } |
---|
1084 | if (addrs && SIMPLEQ_EMPTY(nodes)) |
---|
1085 | printf(" { }"); |
---|
1086 | printf("\n"); |
---|
1087 | } |
---|
1088 | |
---|
1089 | int |
---|
1090 | parse_flags(char *s) |
---|
1091 | { |
---|
1092 | char *p, *q; |
---|
1093 | u_int8_t f = 0; |
---|
1094 | |
---|
1095 | for (p = s; *p; p++) { |
---|
1096 | if ((q = strchr(tcpflags, *p)) == NULL) |
---|
1097 | return -1; |
---|
1098 | else |
---|
1099 | f |= 1 << (q - tcpflags); |
---|
1100 | } |
---|
1101 | return (f ? f : PF_TH_ALL); |
---|
1102 | } |
---|
1103 | |
---|
1104 | void |
---|
1105 | set_ipmask(struct node_host *h, u_int8_t b) |
---|
1106 | { |
---|
1107 | struct pf_addr *m, *n; |
---|
1108 | int i, j = 0; |
---|
1109 | |
---|
1110 | m = &h->addr.v.a.mask; |
---|
1111 | memset(m, 0, sizeof(*m)); |
---|
1112 | |
---|
1113 | while (b >= 32) { |
---|
1114 | m->addr32[j++] = 0xffffffff; |
---|
1115 | b -= 32; |
---|
1116 | } |
---|
1117 | for (i = 31; i > 31-b; --i) |
---|
1118 | m->addr32[j] |= (1 << i); |
---|
1119 | if (b) |
---|
1120 | m->addr32[j] = htonl(m->addr32[j]); |
---|
1121 | |
---|
1122 | /* Mask off bits of the address that will never be used. */ |
---|
1123 | n = &h->addr.v.a.addr; |
---|
1124 | if (h->addr.type == PF_ADDR_ADDRMASK) |
---|
1125 | for (i = 0; i < 4; i++) |
---|
1126 | n->addr32[i] = n->addr32[i] & m->addr32[i]; |
---|
1127 | } |
---|
1128 | |
---|
1129 | int |
---|
1130 | check_netmask(struct node_host *h, sa_family_t af) |
---|
1131 | { |
---|
1132 | struct node_host *n = NULL; |
---|
1133 | struct pf_addr *m; |
---|
1134 | |
---|
1135 | for (n = h; n != NULL; n = n->next) { |
---|
1136 | if (h->addr.type == PF_ADDR_TABLE) |
---|
1137 | continue; |
---|
1138 | m = &h->addr.v.a.mask; |
---|
1139 | /* fix up netmask for dynaddr */ |
---|
1140 | if (af == AF_INET && h->addr.type == PF_ADDR_DYNIFTL && |
---|
1141 | unmask(m, AF_INET6) > 32) |
---|
1142 | set_ipmask(n, 32); |
---|
1143 | /* netmasks > 32 bit are invalid on v4 */ |
---|
1144 | if (af == AF_INET && |
---|
1145 | (m->addr32[1] || m->addr32[2] || m->addr32[3])) { |
---|
1146 | fprintf(stderr, "netmask %u invalid for IPv4 address\n", |
---|
1147 | unmask(m, AF_INET6)); |
---|
1148 | return (1); |
---|
1149 | } |
---|
1150 | } |
---|
1151 | return (0); |
---|
1152 | } |
---|
1153 | |
---|
1154 | /* interface lookup routines */ |
---|
1155 | |
---|
1156 | struct node_host *iftab; |
---|
1157 | |
---|
1158 | void |
---|
1159 | ifa_load(void) |
---|
1160 | { |
---|
1161 | struct ifaddrs *ifap, *ifa; |
---|
1162 | struct node_host *n = NULL, *h = NULL; |
---|
1163 | |
---|
1164 | if (getifaddrs(&ifap) < 0) |
---|
1165 | err(1, "getifaddrs"); |
---|
1166 | |
---|
1167 | for (ifa = ifap; ifa; ifa = ifa->ifa_next) { |
---|
1168 | if (!(ifa->ifa_addr->sa_family == AF_INET || |
---|
1169 | ifa->ifa_addr->sa_family == AF_INET6 || |
---|
1170 | ifa->ifa_addr->sa_family == AF_LINK)) |
---|
1171 | continue; |
---|
1172 | n = calloc(1, sizeof(struct node_host)); |
---|
1173 | if (n == NULL) |
---|
1174 | err(1, "address: calloc"); |
---|
1175 | n->af = ifa->ifa_addr->sa_family; |
---|
1176 | n->ifa_flags = ifa->ifa_flags; |
---|
1177 | #ifdef __KAME__ |
---|
1178 | if (n->af == AF_INET6 && |
---|
1179 | IN6_IS_ADDR_LINKLOCAL(&((struct sockaddr_in6 *) |
---|
1180 | ifa->ifa_addr)->sin6_addr) && |
---|
1181 | ((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_scope_id == |
---|
1182 | 0) { |
---|
1183 | struct sockaddr_in6 *sin6; |
---|
1184 | |
---|
1185 | sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; |
---|
1186 | sin6->sin6_scope_id = sin6->sin6_addr.s6_addr[2] << 8 | |
---|
1187 | sin6->sin6_addr.s6_addr[3]; |
---|
1188 | sin6->sin6_addr.s6_addr[2] = 0; |
---|
1189 | sin6->sin6_addr.s6_addr[3] = 0; |
---|
1190 | } |
---|
1191 | #endif |
---|
1192 | n->ifindex = 0; |
---|
1193 | if (n->af == AF_INET) { |
---|
1194 | memcpy(&n->addr.v.a.addr, &((struct sockaddr_in *) |
---|
1195 | ifa->ifa_addr)->sin_addr.s_addr, |
---|
1196 | sizeof(struct in_addr)); |
---|
1197 | memcpy(&n->addr.v.a.mask, &((struct sockaddr_in *) |
---|
1198 | ifa->ifa_netmask)->sin_addr.s_addr, |
---|
1199 | sizeof(struct in_addr)); |
---|
1200 | if (ifa->ifa_broadaddr != NULL) |
---|
1201 | memcpy(&n->bcast, &((struct sockaddr_in *) |
---|
1202 | ifa->ifa_broadaddr)->sin_addr.s_addr, |
---|
1203 | sizeof(struct in_addr)); |
---|
1204 | if (ifa->ifa_dstaddr != NULL) |
---|
1205 | memcpy(&n->peer, &((struct sockaddr_in *) |
---|
1206 | ifa->ifa_dstaddr)->sin_addr.s_addr, |
---|
1207 | sizeof(struct in_addr)); |
---|
1208 | } else if (n->af == AF_INET6) { |
---|
1209 | memcpy(&n->addr.v.a.addr, &((struct sockaddr_in6 *) |
---|
1210 | ifa->ifa_addr)->sin6_addr.s6_addr, |
---|
1211 | sizeof(struct in6_addr)); |
---|
1212 | memcpy(&n->addr.v.a.mask, &((struct sockaddr_in6 *) |
---|
1213 | ifa->ifa_netmask)->sin6_addr.s6_addr, |
---|
1214 | sizeof(struct in6_addr)); |
---|
1215 | if (ifa->ifa_broadaddr != NULL) |
---|
1216 | memcpy(&n->bcast, &((struct sockaddr_in6 *) |
---|
1217 | ifa->ifa_broadaddr)->sin6_addr.s6_addr, |
---|
1218 | sizeof(struct in6_addr)); |
---|
1219 | if (ifa->ifa_dstaddr != NULL) |
---|
1220 | memcpy(&n->peer, &((struct sockaddr_in6 *) |
---|
1221 | ifa->ifa_dstaddr)->sin6_addr.s6_addr, |
---|
1222 | sizeof(struct in6_addr)); |
---|
1223 | n->ifindex = ((struct sockaddr_in6 *) |
---|
1224 | ifa->ifa_addr)->sin6_scope_id; |
---|
1225 | } |
---|
1226 | if ((n->ifname = strdup(ifa->ifa_name)) == NULL) |
---|
1227 | err(1, "ifa_load: strdup"); |
---|
1228 | n->next = NULL; |
---|
1229 | n->tail = n; |
---|
1230 | if (h == NULL) |
---|
1231 | h = n; |
---|
1232 | else { |
---|
1233 | h->tail->next = n; |
---|
1234 | h->tail = n; |
---|
1235 | } |
---|
1236 | } |
---|
1237 | |
---|
1238 | iftab = h; |
---|
1239 | freeifaddrs(ifap); |
---|
1240 | } |
---|
1241 | |
---|
1242 | struct node_host * |
---|
1243 | ifa_exists(const char *ifa_name) |
---|
1244 | { |
---|
1245 | struct node_host *n; |
---|
1246 | struct ifgroupreq ifgr; |
---|
1247 | int s; |
---|
1248 | |
---|
1249 | if (iftab == NULL) |
---|
1250 | ifa_load(); |
---|
1251 | |
---|
1252 | /* check wether this is a group */ |
---|
1253 | if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) |
---|
1254 | err(1, "socket"); |
---|
1255 | bzero(&ifgr, sizeof(ifgr)); |
---|
1256 | strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name)); |
---|
1257 | if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == 0) { |
---|
1258 | /* fake a node_host */ |
---|
1259 | if ((n = calloc(1, sizeof(*n))) == NULL) |
---|
1260 | err(1, "calloc"); |
---|
1261 | if ((n->ifname = strdup(ifa_name)) == NULL) |
---|
1262 | err(1, "strdup"); |
---|
1263 | close(s); |
---|
1264 | return (n); |
---|
1265 | } |
---|
1266 | close(s); |
---|
1267 | |
---|
1268 | for (n = iftab; n; n = n->next) { |
---|
1269 | if (n->af == AF_LINK && !strncmp(n->ifname, ifa_name, IFNAMSIZ)) |
---|
1270 | return (n); |
---|
1271 | } |
---|
1272 | |
---|
1273 | return (NULL); |
---|
1274 | } |
---|
1275 | |
---|
1276 | struct node_host * |
---|
1277 | ifa_grouplookup(const char *ifa_name, int flags) |
---|
1278 | { |
---|
1279 | struct ifg_req *ifg; |
---|
1280 | struct ifgroupreq ifgr; |
---|
1281 | int s, len; |
---|
1282 | struct node_host *n, *h = NULL; |
---|
1283 | |
---|
1284 | if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1) |
---|
1285 | err(1, "socket"); |
---|
1286 | bzero(&ifgr, sizeof(ifgr)); |
---|
1287 | strlcpy(ifgr.ifgr_name, ifa_name, sizeof(ifgr.ifgr_name)); |
---|
1288 | if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) { |
---|
1289 | close(s); |
---|
1290 | return (NULL); |
---|
1291 | } |
---|
1292 | |
---|
1293 | len = ifgr.ifgr_len; |
---|
1294 | if ((ifgr.ifgr_groups = calloc(1, len)) == NULL) |
---|
1295 | err(1, "calloc"); |
---|
1296 | if (ioctl(s, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1) |
---|
1297 | err(1, "SIOCGIFGMEMB"); |
---|
1298 | |
---|
1299 | for (ifg = ifgr.ifgr_groups; ifg && len >= sizeof(struct ifg_req); |
---|
1300 | ifg++) { |
---|
1301 | len -= sizeof(struct ifg_req); |
---|
1302 | if ((n = ifa_lookup(ifg->ifgrq_member, flags)) == NULL) |
---|
1303 | continue; |
---|
1304 | if (h == NULL) |
---|
1305 | h = n; |
---|
1306 | else { |
---|
1307 | h->tail->next = n; |
---|
1308 | h->tail = n->tail; |
---|
1309 | } |
---|
1310 | } |
---|
1311 | free(ifgr.ifgr_groups); |
---|
1312 | close(s); |
---|
1313 | |
---|
1314 | return (h); |
---|
1315 | } |
---|
1316 | |
---|
1317 | struct node_host * |
---|
1318 | ifa_lookup(const char *ifa_name, int flags) |
---|
1319 | { |
---|
1320 | struct node_host *p = NULL, *h = NULL, *n = NULL; |
---|
1321 | int got4 = 0, got6 = 0; |
---|
1322 | const char *last_if = NULL; |
---|
1323 | |
---|
1324 | if ((h = ifa_grouplookup(ifa_name, flags)) != NULL) |
---|
1325 | return (h); |
---|
1326 | |
---|
1327 | if (!strncmp(ifa_name, "self", IFNAMSIZ)) |
---|
1328 | ifa_name = NULL; |
---|
1329 | |
---|
1330 | if (iftab == NULL) |
---|
1331 | ifa_load(); |
---|
1332 | |
---|
1333 | for (p = iftab; p; p = p->next) { |
---|
1334 | if (ifa_skip_if(ifa_name, p)) |
---|
1335 | continue; |
---|
1336 | if ((flags & PFI_AFLAG_BROADCAST) && p->af != AF_INET) |
---|
1337 | continue; |
---|
1338 | if ((flags & PFI_AFLAG_BROADCAST) && |
---|
1339 | !(p->ifa_flags & IFF_BROADCAST)) |
---|
1340 | continue; |
---|
1341 | if ((flags & PFI_AFLAG_PEER) && |
---|
1342 | !(p->ifa_flags & IFF_POINTOPOINT)) |
---|
1343 | continue; |
---|
1344 | if ((flags & PFI_AFLAG_NETWORK) && p->ifindex > 0) |
---|
1345 | continue; |
---|
1346 | if (last_if == NULL || strcmp(last_if, p->ifname)) |
---|
1347 | got4 = got6 = 0; |
---|
1348 | last_if = p->ifname; |
---|
1349 | if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET && got4) |
---|
1350 | continue; |
---|
1351 | if ((flags & PFI_AFLAG_NOALIAS) && p->af == AF_INET6 && got6) |
---|
1352 | continue; |
---|
1353 | if (p->af == AF_INET) |
---|
1354 | got4 = 1; |
---|
1355 | else |
---|
1356 | got6 = 1; |
---|
1357 | n = calloc(1, sizeof(struct node_host)); |
---|
1358 | if (n == NULL) |
---|
1359 | err(1, "address: calloc"); |
---|
1360 | n->af = p->af; |
---|
1361 | if (flags & PFI_AFLAG_BROADCAST) |
---|
1362 | memcpy(&n->addr.v.a.addr, &p->bcast, |
---|
1363 | sizeof(struct pf_addr)); |
---|
1364 | else if (flags & PFI_AFLAG_PEER) |
---|
1365 | memcpy(&n->addr.v.a.addr, &p->peer, |
---|
1366 | sizeof(struct pf_addr)); |
---|
1367 | else |
---|
1368 | memcpy(&n->addr.v.a.addr, &p->addr.v.a.addr, |
---|
1369 | sizeof(struct pf_addr)); |
---|
1370 | if (flags & PFI_AFLAG_NETWORK) |
---|
1371 | set_ipmask(n, unmask(&p->addr.v.a.mask, n->af)); |
---|
1372 | else { |
---|
1373 | if (n->af == AF_INET) { |
---|
1374 | if (p->ifa_flags & IFF_LOOPBACK && |
---|
1375 | p->ifa_flags & IFF_LINK1) |
---|
1376 | memcpy(&n->addr.v.a.mask, |
---|
1377 | &p->addr.v.a.mask, |
---|
1378 | sizeof(struct pf_addr)); |
---|
1379 | else |
---|
1380 | set_ipmask(n, 32); |
---|
1381 | } else |
---|
1382 | set_ipmask(n, 128); |
---|
1383 | } |
---|
1384 | n->ifindex = p->ifindex; |
---|
1385 | |
---|
1386 | n->next = NULL; |
---|
1387 | n->tail = n; |
---|
1388 | if (h == NULL) |
---|
1389 | h = n; |
---|
1390 | else { |
---|
1391 | h->tail->next = n; |
---|
1392 | h->tail = n; |
---|
1393 | } |
---|
1394 | } |
---|
1395 | return (h); |
---|
1396 | } |
---|
1397 | |
---|
1398 | int |
---|
1399 | ifa_skip_if(const char *filter, struct node_host *p) |
---|
1400 | { |
---|
1401 | int n; |
---|
1402 | |
---|
1403 | if (p->af != AF_INET && p->af != AF_INET6) |
---|
1404 | return (1); |
---|
1405 | if (filter == NULL || !*filter) |
---|
1406 | return (0); |
---|
1407 | if (!strcmp(p->ifname, filter)) |
---|
1408 | return (0); /* exact match */ |
---|
1409 | n = strlen(filter); |
---|
1410 | if (n < 1 || n >= IFNAMSIZ) |
---|
1411 | return (1); /* sanity check */ |
---|
1412 | if (filter[n-1] >= '0' && filter[n-1] <= '9') |
---|
1413 | return (1); /* only do exact match in that case */ |
---|
1414 | if (strncmp(p->ifname, filter, n)) |
---|
1415 | return (1); /* prefix doesn't match */ |
---|
1416 | return (p->ifname[n] < '0' || p->ifname[n] > '9'); |
---|
1417 | } |
---|
1418 | |
---|
1419 | |
---|
1420 | struct node_host * |
---|
1421 | host(const char *s) |
---|
1422 | { |
---|
1423 | struct node_host *h = NULL; |
---|
1424 | int mask, v4mask, v6mask, cont = 1; |
---|
1425 | char *p, *q, *ps; |
---|
1426 | |
---|
1427 | if ((p = strrchr(s, '/')) != NULL) { |
---|
1428 | mask = strtol(p+1, &q, 0); |
---|
1429 | if (!q || *q || mask > 128 || q == (p+1)) { |
---|
1430 | fprintf(stderr, "invalid netmask '%s'\n", p); |
---|
1431 | return (NULL); |
---|
1432 | } |
---|
1433 | if ((ps = malloc(strlen(s) - strlen(p) + 1)) == NULL) |
---|
1434 | err(1, "host: malloc"); |
---|
1435 | strlcpy(ps, s, strlen(s) - strlen(p) + 1); |
---|
1436 | v4mask = v6mask = mask; |
---|
1437 | } else { |
---|
1438 | if ((ps = strdup(s)) == NULL) |
---|
1439 | err(1, "host: strdup"); |
---|
1440 | v4mask = 32; |
---|
1441 | v6mask = 128; |
---|
1442 | mask = -1; |
---|
1443 | } |
---|
1444 | |
---|
1445 | /* interface with this name exists? */ |
---|
1446 | if (cont && (h = host_if(ps, mask)) != NULL) |
---|
1447 | cont = 0; |
---|
1448 | |
---|
1449 | /* IPv4 address? */ |
---|
1450 | if (cont && (h = host_v4(s, mask)) != NULL) |
---|
1451 | cont = 0; |
---|
1452 | |
---|
1453 | /* IPv6 address? */ |
---|
1454 | if (cont && (h = host_v6(ps, v6mask)) != NULL) |
---|
1455 | cont = 0; |
---|
1456 | |
---|
1457 | /* dns lookup */ |
---|
1458 | if (cont && (h = host_dns(ps, v4mask, v6mask)) != NULL) |
---|
1459 | cont = 0; |
---|
1460 | free(ps); |
---|
1461 | |
---|
1462 | if (h == NULL || cont == 1) { |
---|
1463 | fprintf(stderr, "no IP address found for %s\n", s); |
---|
1464 | return (NULL); |
---|
1465 | } |
---|
1466 | return (h); |
---|
1467 | } |
---|
1468 | |
---|
1469 | struct node_host * |
---|
1470 | host_if(const char *s, int mask) |
---|
1471 | { |
---|
1472 | struct node_host *n, *h = NULL; |
---|
1473 | char *p, *ps; |
---|
1474 | int flags = 0; |
---|
1475 | |
---|
1476 | if ((ps = strdup(s)) == NULL) |
---|
1477 | err(1, "host_if: strdup"); |
---|
1478 | while ((p = strrchr(ps, ':')) != NULL) { |
---|
1479 | if (!strcmp(p+1, "network")) |
---|
1480 | flags |= PFI_AFLAG_NETWORK; |
---|
1481 | else if (!strcmp(p+1, "broadcast")) |
---|
1482 | flags |= PFI_AFLAG_BROADCAST; |
---|
1483 | else if (!strcmp(p+1, "peer")) |
---|
1484 | flags |= PFI_AFLAG_PEER; |
---|
1485 | else if (!strcmp(p+1, "0")) |
---|
1486 | flags |= PFI_AFLAG_NOALIAS; |
---|
1487 | else { |
---|
1488 | free(ps); |
---|
1489 | return (NULL); |
---|
1490 | } |
---|
1491 | *p = '\0'; |
---|
1492 | } |
---|
1493 | if (flags & (flags - 1) & PFI_AFLAG_MODEMASK) { /* Yep! */ |
---|
1494 | fprintf(stderr, "illegal combination of interface modifiers\n"); |
---|
1495 | free(ps); |
---|
1496 | return (NULL); |
---|
1497 | } |
---|
1498 | if ((flags & (PFI_AFLAG_NETWORK|PFI_AFLAG_BROADCAST)) && mask > -1) { |
---|
1499 | fprintf(stderr, "network or broadcast lookup, but " |
---|
1500 | "extra netmask given\n"); |
---|
1501 | free(ps); |
---|
1502 | return (NULL); |
---|
1503 | } |
---|
1504 | if (ifa_exists(ps) || !strncmp(ps, "self", IFNAMSIZ)) { |
---|
1505 | /* interface with this name exists */ |
---|
1506 | h = ifa_lookup(ps, flags); |
---|
1507 | for (n = h; n != NULL && mask > -1; n = n->next) |
---|
1508 | set_ipmask(n, mask); |
---|
1509 | } |
---|
1510 | |
---|
1511 | free(ps); |
---|
1512 | return (h); |
---|
1513 | } |
---|
1514 | |
---|
1515 | struct node_host * |
---|
1516 | host_v4(const char *s, int mask) |
---|
1517 | { |
---|
1518 | struct node_host *h = NULL; |
---|
1519 | struct in_addr ina; |
---|
1520 | int bits = 32; |
---|
1521 | |
---|
1522 | memset(&ina, 0, sizeof(struct in_addr)); |
---|
1523 | if (strrchr(s, '/') != NULL) { |
---|
1524 | if ((bits = inet_net_pton(AF_INET, s, &ina, sizeof(ina))) == -1) |
---|
1525 | return (NULL); |
---|
1526 | } else { |
---|
1527 | if (inet_pton(AF_INET, s, &ina) != 1) |
---|
1528 | return (NULL); |
---|
1529 | } |
---|
1530 | |
---|
1531 | h = calloc(1, sizeof(struct node_host)); |
---|
1532 | if (h == NULL) |
---|
1533 | err(1, "address: calloc"); |
---|
1534 | h->ifname = NULL; |
---|
1535 | h->af = AF_INET; |
---|
1536 | h->addr.v.a.addr.addr32[0] = ina.s_addr; |
---|
1537 | set_ipmask(h, bits); |
---|
1538 | h->next = NULL; |
---|
1539 | h->tail = h; |
---|
1540 | |
---|
1541 | return (h); |
---|
1542 | } |
---|
1543 | |
---|
1544 | struct node_host * |
---|
1545 | host_v6(const char *s, int mask) |
---|
1546 | { |
---|
1547 | struct addrinfo hints, *res; |
---|
1548 | struct node_host *h = NULL; |
---|
1549 | |
---|
1550 | memset(&hints, 0, sizeof(hints)); |
---|
1551 | hints.ai_family = AF_INET6; |
---|
1552 | hints.ai_socktype = SOCK_DGRAM; /*dummy*/ |
---|
1553 | hints.ai_flags = AI_NUMERICHOST; |
---|
1554 | if (getaddrinfo(s, "0", &hints, &res) == 0) { |
---|
1555 | h = calloc(1, sizeof(struct node_host)); |
---|
1556 | if (h == NULL) |
---|
1557 | err(1, "address: calloc"); |
---|
1558 | h->ifname = NULL; |
---|
1559 | h->af = AF_INET6; |
---|
1560 | memcpy(&h->addr.v.a.addr, |
---|
1561 | &((struct sockaddr_in6 *)res->ai_addr)->sin6_addr, |
---|
1562 | sizeof(h->addr.v.a.addr)); |
---|
1563 | h->ifindex = |
---|
1564 | ((struct sockaddr_in6 *)res->ai_addr)->sin6_scope_id; |
---|
1565 | set_ipmask(h, mask); |
---|
1566 | freeaddrinfo(res); |
---|
1567 | h->next = NULL; |
---|
1568 | h->tail = h; |
---|
1569 | } |
---|
1570 | |
---|
1571 | return (h); |
---|
1572 | } |
---|
1573 | |
---|
1574 | struct node_host * |
---|
1575 | host_dns(const char *s, int v4mask, int v6mask) |
---|
1576 | { |
---|
1577 | struct addrinfo hints, *res0, *res; |
---|
1578 | struct node_host *n, *h = NULL; |
---|
1579 | int error, noalias = 0; |
---|
1580 | int got4 = 0, got6 = 0; |
---|
1581 | char *p, *ps; |
---|
1582 | |
---|
1583 | if ((ps = strdup(s)) == NULL) |
---|
1584 | err(1, "host_dns: strdup"); |
---|
1585 | if ((p = strrchr(ps, ':')) != NULL && !strcmp(p, ":0")) { |
---|
1586 | noalias = 1; |
---|
1587 | *p = '\0'; |
---|
1588 | } |
---|
1589 | memset(&hints, 0, sizeof(hints)); |
---|
1590 | hints.ai_family = PF_UNSPEC; |
---|
1591 | hints.ai_socktype = SOCK_STREAM; /* DUMMY */ |
---|
1592 | error = getaddrinfo(ps, NULL, &hints, &res0); |
---|
1593 | if (error) { |
---|
1594 | free(ps); |
---|
1595 | return (h); |
---|
1596 | } |
---|
1597 | |
---|
1598 | for (res = res0; res; res = res->ai_next) { |
---|
1599 | if (res->ai_family != AF_INET && |
---|
1600 | res->ai_family != AF_INET6) |
---|
1601 | continue; |
---|
1602 | if (noalias) { |
---|
1603 | if (res->ai_family == AF_INET) { |
---|
1604 | if (got4) |
---|
1605 | continue; |
---|
1606 | got4 = 1; |
---|
1607 | } else { |
---|
1608 | if (got6) |
---|
1609 | continue; |
---|
1610 | got6 = 1; |
---|
1611 | } |
---|
1612 | } |
---|
1613 | n = calloc(1, sizeof(struct node_host)); |
---|
1614 | if (n == NULL) |
---|
1615 | err(1, "host_dns: calloc"); |
---|
1616 | n->ifname = NULL; |
---|
1617 | n->af = res->ai_family; |
---|
1618 | if (res->ai_family == AF_INET) { |
---|
1619 | memcpy(&n->addr.v.a.addr, |
---|
1620 | &((struct sockaddr_in *) |
---|
1621 | res->ai_addr)->sin_addr.s_addr, |
---|
1622 | sizeof(struct in_addr)); |
---|
1623 | set_ipmask(n, v4mask); |
---|
1624 | } else { |
---|
1625 | memcpy(&n->addr.v.a.addr, |
---|
1626 | &((struct sockaddr_in6 *) |
---|
1627 | res->ai_addr)->sin6_addr.s6_addr, |
---|
1628 | sizeof(struct in6_addr)); |
---|
1629 | n->ifindex = |
---|
1630 | ((struct sockaddr_in6 *) |
---|
1631 | res->ai_addr)->sin6_scope_id; |
---|
1632 | set_ipmask(n, v6mask); |
---|
1633 | } |
---|
1634 | n->next = NULL; |
---|
1635 | n->tail = n; |
---|
1636 | if (h == NULL) |
---|
1637 | h = n; |
---|
1638 | else { |
---|
1639 | h->tail->next = n; |
---|
1640 | h->tail = n; |
---|
1641 | } |
---|
1642 | } |
---|
1643 | freeaddrinfo(res0); |
---|
1644 | free(ps); |
---|
1645 | |
---|
1646 | return (h); |
---|
1647 | } |
---|
1648 | |
---|
1649 | /* |
---|
1650 | * convert a hostname to a list of addresses and put them in the given buffer. |
---|
1651 | * test: |
---|
1652 | * if set to 1, only simple addresses are accepted (no netblock, no "!"). |
---|
1653 | */ |
---|
1654 | int |
---|
1655 | append_addr(struct pfr_buffer *b, char *s, int test) |
---|
1656 | { |
---|
1657 | char *r; |
---|
1658 | struct node_host *h, *n; |
---|
1659 | int rv, not = 0; |
---|
1660 | |
---|
1661 | for (r = s; *r == '!'; r++) |
---|
1662 | not = !not; |
---|
1663 | if ((n = host(r)) == NULL) { |
---|
1664 | errno = 0; |
---|
1665 | return (-1); |
---|
1666 | } |
---|
1667 | rv = append_addr_host(b, n, test, not); |
---|
1668 | do { |
---|
1669 | h = n; |
---|
1670 | n = n->next; |
---|
1671 | free(h); |
---|
1672 | } while (n != NULL); |
---|
1673 | return (rv); |
---|
1674 | } |
---|
1675 | |
---|
1676 | /* |
---|
1677 | * same as previous function, but with a pre-parsed input and the ability |
---|
1678 | * to "negate" the result. Does not free the node_host list. |
---|
1679 | * not: |
---|
1680 | * setting it to 1 is equivalent to adding "!" in front of parameter s. |
---|
1681 | */ |
---|
1682 | int |
---|
1683 | append_addr_host(struct pfr_buffer *b, struct node_host *n, int test, int not) |
---|
1684 | { |
---|
1685 | int bits; |
---|
1686 | struct pfr_addr addr; |
---|
1687 | |
---|
1688 | do { |
---|
1689 | bzero(&addr, sizeof(addr)); |
---|
1690 | addr.pfra_not = n->not ^ not; |
---|
1691 | addr.pfra_af = n->af; |
---|
1692 | addr.pfra_net = unmask(&n->addr.v.a.mask, n->af); |
---|
1693 | switch (n->af) { |
---|
1694 | case AF_INET: |
---|
1695 | addr.pfra_ip4addr.s_addr = n->addr.v.a.addr.addr32[0]; |
---|
1696 | bits = 32; |
---|
1697 | break; |
---|
1698 | case AF_INET6: |
---|
1699 | memcpy(&addr.pfra_ip6addr, &n->addr.v.a.addr.v6, |
---|
1700 | sizeof(struct in6_addr)); |
---|
1701 | bits = 128; |
---|
1702 | break; |
---|
1703 | default: |
---|
1704 | errno = EINVAL; |
---|
1705 | return (-1); |
---|
1706 | } |
---|
1707 | if ((test && (not || addr.pfra_net != bits)) || |
---|
1708 | addr.pfra_net > bits) { |
---|
1709 | errno = EINVAL; |
---|
1710 | return (-1); |
---|
1711 | } |
---|
1712 | if (pfr_buf_add(b, &addr)) |
---|
1713 | return (-1); |
---|
1714 | } while ((n = n->next) != NULL); |
---|
1715 | |
---|
1716 | return (0); |
---|
1717 | } |
---|
1718 | |
---|
1719 | int |
---|
1720 | pfctl_add_trans(struct pfr_buffer *buf, int rs_num, const char *anchor) |
---|
1721 | { |
---|
1722 | struct pfioc_trans_e trans; |
---|
1723 | |
---|
1724 | bzero(&trans, sizeof(trans)); |
---|
1725 | trans.rs_num = rs_num; |
---|
1726 | if (strlcpy(trans.anchor, anchor, |
---|
1727 | sizeof(trans.anchor)) >= sizeof(trans.anchor)) |
---|
1728 | errx(1, "pfctl_add_trans: strlcpy"); |
---|
1729 | |
---|
1730 | return pfr_buf_add(buf, &trans); |
---|
1731 | } |
---|
1732 | |
---|
1733 | u_int32_t |
---|
1734 | pfctl_get_ticket(struct pfr_buffer *buf, int rs_num, const char *anchor) |
---|
1735 | { |
---|
1736 | struct pfioc_trans_e *p; |
---|
1737 | |
---|
1738 | PFRB_FOREACH(p, buf) |
---|
1739 | if (rs_num == p->rs_num && !strcmp(anchor, p->anchor)) |
---|
1740 | return (p->ticket); |
---|
1741 | errx(1, "pfctl_get_ticket: assertion failed"); |
---|
1742 | } |
---|
1743 | |
---|
1744 | int |
---|
1745 | pfctl_trans(int dev, struct pfr_buffer *buf, u_long cmd, int from) |
---|
1746 | { |
---|
1747 | struct pfioc_trans trans; |
---|
1748 | |
---|
1749 | bzero(&trans, sizeof(trans)); |
---|
1750 | trans.size = buf->pfrb_size - from; |
---|
1751 | trans.esize = sizeof(struct pfioc_trans_e); |
---|
1752 | trans.array = ((struct pfioc_trans_e *)buf->pfrb_caddr) + from; |
---|
1753 | return ioctl(dev, cmd, &trans); |
---|
1754 | } |
---|