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