c7efb396f618aa82e8a792de23479eee3af6a693
[collectd.git] / pfutils45.c
1 #include <sys/types.h>
2 #include <sys/ioctl.h>
3 #include <sys/socket.h>
4 #include <sys/param.h>
5 #include <sys/proc.h>
6 #include <net/if.h>
7 #include <netinet/in.h>
8 #include <netinet/in_systm.h>
9 #include <netinet/ip.h>
10 #include <netinet/ip_icmp.h>
11 #include <netinet/icmp6.h>
12 #include <net/pfvar.h>
13 #include <arpa/inet.h>
14
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <netdb.h>
20 #include <stdarg.h>
21 #include <errno.h>
22 #include <err.h>
23 #include <ifaddrs.h>
24 #include <unistd.h>
25
26 #include "pfutils45.h"
27
28 void             print_fromto(struct pf_rule_addr *, pf_osfp_t,
29                     struct pf_rule_addr *, u_int8_t, u_int8_t, int);
30 void             print_ugid (u_int8_t, unsigned, unsigned, const char *, unsigned);
31 void             print_flags (u_int8_t);
32 void             print_addr(struct pf_addr_wrap *, sa_family_t, int);
33 void             print_port (u_int8_t, u_int16_t, u_int16_t, const char *);
34 char            *pfctl_lookup_fingerprint(pf_osfp_t, char *, size_t);
35 void             print_op (u_int8_t, const char *, const char *);
36 int              unmask(struct pf_addr *, sa_family_t);
37
38 struct name_entry;
39 LIST_HEAD(name_list, name_entry);
40 struct name_entry {
41         LIST_ENTRY(name_entry)  nm_entry;
42         int                     nm_num;
43         char                    nm_name[PF_OSFP_LEN];
44
45         struct name_list        nm_sublist;
46         int                     nm_sublist_num;
47 };
48
49 struct name_list classes = LIST_HEAD_INITIALIZER(&classes);
50
51 struct icmptypeent {
52         const char *name;
53         u_int8_t type;
54 };
55
56 struct icmpcodeent {
57         const char *name;
58         u_int8_t type;
59         u_int8_t code;
60 };
61
62 struct pf_timeout {
63         const char      *name;
64         int              timeout;
65 };
66
67
68 const struct icmptypeent *geticmptypebynumber(u_int8_t, u_int8_t);
69 const struct icmptypeent *geticmptypebyname(char *, u_int8_t);
70 const struct icmpcodeent *geticmpcodebynumber(u_int8_t, u_int8_t, u_int8_t);
71 const struct icmpcodeent *geticmpcodebyname(u_long, char *, u_int8_t);
72
73 static const struct icmptypeent icmp_type[] = {
74         { "echoreq",    ICMP_ECHO },
75         { "echorep",    ICMP_ECHOREPLY },
76         { "unreach",    ICMP_UNREACH },
77         { "squench",    ICMP_SOURCEQUENCH },
78         { "redir",      ICMP_REDIRECT },
79         { "althost",    ICMP_ALTHOSTADDR },
80         { "routeradv",  ICMP_ROUTERADVERT },
81         { "routersol",  ICMP_ROUTERSOLICIT },
82         { "timex",      ICMP_TIMXCEED },
83         { "paramprob",  ICMP_PARAMPROB },
84         { "timereq",    ICMP_TSTAMP },
85         { "timerep",    ICMP_TSTAMPREPLY },
86         { "inforeq",    ICMP_IREQ },
87         { "inforep",    ICMP_IREQREPLY },
88         { "maskreq",    ICMP_MASKREQ },
89         { "maskrep",    ICMP_MASKREPLY },
90         { "trace",      ICMP_TRACEROUTE },
91         { "dataconv",   ICMP_DATACONVERR },
92         { "mobredir",   ICMP_MOBILE_REDIRECT },
93         { "ipv6-where", ICMP_IPV6_WHEREAREYOU },
94         { "ipv6-here",  ICMP_IPV6_IAMHERE },
95         { "mobregreq",  ICMP_MOBILE_REGREQUEST },
96         { "mobregrep",  ICMP_MOBILE_REGREPLY },
97         { "skip",       ICMP_SKIP },
98         { "photuris",   ICMP_PHOTURIS }
99 };
100
101 static const struct icmptypeent icmp6_type[] = {
102         { "unreach",    ICMP6_DST_UNREACH },
103         { "toobig",     ICMP6_PACKET_TOO_BIG },
104         { "timex",      ICMP6_TIME_EXCEEDED },
105         { "paramprob",  ICMP6_PARAM_PROB },
106         { "echoreq",    ICMP6_ECHO_REQUEST },
107         { "echorep",    ICMP6_ECHO_REPLY },
108         { "groupqry",   ICMP6_MEMBERSHIP_QUERY },
109         { "listqry",    MLD_LISTENER_QUERY },
110         { "grouprep",   ICMP6_MEMBERSHIP_REPORT },
111         { "listenrep",  MLD_LISTENER_REPORT },
112         { "groupterm",  ICMP6_MEMBERSHIP_REDUCTION },
113         { "listendone", MLD_LISTENER_DONE },
114         { "routersol",  ND_ROUTER_SOLICIT },
115         { "routeradv",  ND_ROUTER_ADVERT },
116         { "neighbrsol", ND_NEIGHBOR_SOLICIT },
117         { "neighbradv", ND_NEIGHBOR_ADVERT },
118         { "redir",      ND_REDIRECT },
119         { "routrrenum", ICMP6_ROUTER_RENUMBERING },
120         { "wrureq",     ICMP6_WRUREQUEST },
121         { "wrurep",     ICMP6_WRUREPLY },
122         { "fqdnreq",    ICMP6_FQDN_QUERY },
123         { "fqdnrep",    ICMP6_FQDN_REPLY },
124         { "niqry",      ICMP6_NI_QUERY },
125         { "nirep",      ICMP6_NI_REPLY },
126         { "mtraceresp", MLD_MTRACE_RESP },
127         { "mtrace",     MLD_MTRACE }
128 };
129
130
131 const struct pf_timeout pf_timeouts[] = {
132         { "tcp.first",          PFTM_TCP_FIRST_PACKET },
133         { "tcp.opening",        PFTM_TCP_OPENING },
134         { "tcp.established",    PFTM_TCP_ESTABLISHED },
135         { "tcp.closing",        PFTM_TCP_CLOSING },
136         { "tcp.finwait",        PFTM_TCP_FIN_WAIT },
137         { "tcp.closed",         PFTM_TCP_CLOSED },
138         { "tcp.tsdiff",         PFTM_TS_DIFF },
139         { "udp.first",          PFTM_UDP_FIRST_PACKET },
140         { "udp.single",         PFTM_UDP_SINGLE },
141         { "udp.multiple",       PFTM_UDP_MULTIPLE },
142         { "icmp.first",         PFTM_ICMP_FIRST_PACKET },
143         { "icmp.error",         PFTM_ICMP_ERROR_REPLY },
144         { "other.first",        PFTM_OTHER_FIRST_PACKET },
145         { "other.single",       PFTM_OTHER_SINGLE },
146         { "other.multiple",     PFTM_OTHER_MULTIPLE },
147         { "frag",               PFTM_FRAG },
148         { "interval",           PFTM_INTERVAL },
149         { "adaptive.start",     PFTM_ADAPTIVE_START },
150         { "adaptive.end",       PFTM_ADAPTIVE_END },
151         { "src.track",          PFTM_SRC_NODE },
152         { NULL,                 0 }
153 };
154
155 static const struct icmpcodeent icmp_code[] = {
156         { "net-unr",            ICMP_UNREACH,   ICMP_UNREACH_NET },
157         { "host-unr",           ICMP_UNREACH,   ICMP_UNREACH_HOST },
158         { "proto-unr",          ICMP_UNREACH,   ICMP_UNREACH_PROTOCOL },
159         { "port-unr",           ICMP_UNREACH,   ICMP_UNREACH_PORT },
160         { "needfrag",           ICMP_UNREACH,   ICMP_UNREACH_NEEDFRAG },
161         { "srcfail",            ICMP_UNREACH,   ICMP_UNREACH_SRCFAIL },
162         { "net-unk",            ICMP_UNREACH,   ICMP_UNREACH_NET_UNKNOWN },
163         { "host-unk",           ICMP_UNREACH,   ICMP_UNREACH_HOST_UNKNOWN },
164         { "isolate",            ICMP_UNREACH,   ICMP_UNREACH_ISOLATED },
165         { "net-prohib",         ICMP_UNREACH,   ICMP_UNREACH_NET_PROHIB },
166         { "host-prohib",        ICMP_UNREACH,   ICMP_UNREACH_HOST_PROHIB },
167         { "net-tos",            ICMP_UNREACH,   ICMP_UNREACH_TOSNET },
168         { "host-tos",           ICMP_UNREACH,   ICMP_UNREACH_TOSHOST },
169         { "filter-prohib",      ICMP_UNREACH,   ICMP_UNREACH_FILTER_PROHIB },
170         { "host-preced",        ICMP_UNREACH,   ICMP_UNREACH_HOST_PRECEDENCE },
171         { "cutoff-preced",      ICMP_UNREACH,   ICMP_UNREACH_PRECEDENCE_CUTOFF },
172         { "redir-net",          ICMP_REDIRECT,  ICMP_REDIRECT_NET },
173         { "redir-host",         ICMP_REDIRECT,  ICMP_REDIRECT_HOST },
174         { "redir-tos-net",      ICMP_REDIRECT,  ICMP_REDIRECT_TOSNET },
175         { "redir-tos-host",     ICMP_REDIRECT,  ICMP_REDIRECT_TOSHOST },
176         { "normal-adv",         ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NORMAL },
177         { "common-adv",         ICMP_ROUTERADVERT, ICMP_ROUTERADVERT_NOROUTE_COMMON },
178         { "transit",            ICMP_TIMXCEED,  ICMP_TIMXCEED_INTRANS },
179         { "reassemb",           ICMP_TIMXCEED,  ICMP_TIMXCEED_REASS },
180         { "badhead",            ICMP_PARAMPROB, ICMP_PARAMPROB_ERRATPTR },
181         { "optmiss",            ICMP_PARAMPROB, ICMP_PARAMPROB_OPTABSENT },
182         { "badlen",             ICMP_PARAMPROB, ICMP_PARAMPROB_LENGTH },
183         { "unknown-ind",        ICMP_PHOTURIS,  ICMP_PHOTURIS_UNKNOWN_INDEX },
184         { "auth-fail",          ICMP_PHOTURIS,  ICMP_PHOTURIS_AUTH_FAILED },
185         { "decrypt-fail",       ICMP_PHOTURIS,  ICMP_PHOTURIS_DECRYPT_FAILED }
186 };
187
188 static const struct icmpcodeent icmp6_code[] = {
189         { "admin-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADMIN },
190         { "noroute-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOROUTE },
191         { "notnbr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOTNEIGHBOR },
192         { "beyond-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_BEYONDSCOPE },
193         { "addr-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_ADDR },
194         { "port-unr", ICMP6_DST_UNREACH, ICMP6_DST_UNREACH_NOPORT },
195         { "transit", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_TRANSIT },
196         { "reassemb", ICMP6_TIME_EXCEEDED, ICMP6_TIME_EXCEED_REASSEMBLY },
197         { "badhead", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_HEADER },
198         { "nxthdr", ICMP6_PARAM_PROB, ICMP6_PARAMPROB_NEXTHEADER },
199         { "redironlink", ND_REDIRECT, ND_REDIRECT_ONLINK },
200         { "redirrouter", ND_REDIRECT, ND_REDIRECT_ROUTER }
201 };
202
203 const char *tcpflags = "FSRPAUEW";
204
205 void
206 print_rule(struct pf_rule *r, const char *anchor_call, int verbose)
207 {
208         static const char *actiontypes[] = { "pass", "block", "scrub",
209             "no scrub", "nat", "no nat", "binat", "no binat", "rdr", "no rdr" };
210         static const char *anchortypes[] = { "anchor", "anchor", "anchor",
211             "anchor", "nat-anchor", "nat-anchor", "binat-anchor",
212             "binat-anchor", "rdr-anchor", "rdr-anchor" };
213         int     i, opts;
214
215         if (verbose)
216                 printf("@%d ", r->nr);
217         if (r->action > PF_NORDR)
218                 printf("action(%d)", r->action);
219         else if (anchor_call[0]) {
220                 if (anchor_call[0] == '_') {
221                         printf("%s", anchortypes[r->action]);
222                 } else
223                         printf("%s \"%s\"", anchortypes[r->action],
224                             anchor_call);
225         } else {
226                 printf("%s", actiontypes[r->action]);
227                 if (r->natpass)
228                         printf(" pass");
229         }
230         if (r->action == PF_DROP) {
231                 if (r->rule_flag & PFRULE_RETURN)
232                         printf(" return");
233                 else if (r->rule_flag & PFRULE_RETURNRST) {
234                         if (!r->return_ttl)
235                                 printf(" return-rst");
236                         else
237                                 printf(" return-rst(ttl %d)", r->return_ttl);
238                 } else if (r->rule_flag & PFRULE_RETURNICMP) {
239                         const struct icmpcodeent        *ic, *ic6;
240
241                         ic = geticmpcodebynumber(r->return_icmp >> 8,
242                             r->return_icmp & 255, AF_INET);
243                         ic6 = geticmpcodebynumber(r->return_icmp6 >> 8,
244                             r->return_icmp6 & 255, AF_INET6);
245
246                         switch (r->af) {
247                         case AF_INET:
248                                 printf(" return-icmp");
249                                 if (ic == NULL)
250                                         printf("(%u)", r->return_icmp & 255);
251                                 else
252                                         printf("(%s)", ic->name);
253                                 break;
254                         case AF_INET6:
255                                 printf(" return-icmp6");
256                                 if (ic6 == NULL)
257                                         printf("(%u)", r->return_icmp6 & 255);
258                                 else
259                                         printf("(%s)", ic6->name);
260                                 break;
261                         default:
262                                 printf(" return-icmp");
263                                 if (ic == NULL)
264                                         printf("(%u, ", r->return_icmp & 255);
265                                 else
266                                         printf("(%s, ", ic->name);
267                                 if (ic6 == NULL)
268                                         printf("%u)", r->return_icmp6 & 255);
269                                 else
270                                         printf("%s)", ic6->name);
271                                 break;
272                         }
273                 } else
274                         printf(" drop");
275         }
276         if (r->direction == PF_IN)
277                 printf(" in");
278         else if (r->direction == PF_OUT)
279                 printf(" out");
280         if (r->log) {
281                 printf(" log");
282                 if (r->log & ~PF_LOG || r->logif) {
283                         int count = 0;
284
285                         printf(" (");
286                         if (r->log & PF_LOG_ALL)
287                                 printf("%sall", count++ ? ", " : "");
288                         if (r->log & PF_LOG_SOCKET_LOOKUP)
289                                 printf("%suser", count++ ? ", " : "");
290                         if (r->logif)
291                                 printf("%sto pflog%u", count++ ? ", " : "",
292                                     r->logif);
293                         printf(")");
294                 }
295         }
296         if (r->quick)
297                 printf(" quick");
298         if (r->ifname[0]) {
299                 if (r->ifnot)
300                         printf(" on ! %s", r->ifname);
301                 else
302                         printf(" on %s", r->ifname);
303         }
304         if (r->rt) {
305                 if (r->rt == PF_ROUTETO)
306                         printf(" route-to");
307                 else if (r->rt == PF_REPLYTO)
308                         printf(" reply-to");
309                 else if (r->rt == PF_DUPTO)
310                         printf(" dup-to");
311                 else if (r->rt == PF_FASTROUTE)
312                         printf(" fastroute");
313                 if (r->rt != PF_FASTROUTE) {
314                         printf(" ");
315                         print_pool(&r->rpool, 0, 0, r->af, PF_PASS);
316                 }
317         }
318         if (r->af) {
319                 if (r->af == AF_INET)
320                         printf(" inet");
321                 else
322                         printf(" inet6");
323         }
324         if (r->proto) {
325                 struct protoent *p;
326
327                 if ((p = getprotobynumber(r->proto)) != NULL)
328                         printf(" proto %s", p->p_name);
329                 else
330                         printf(" proto %u", r->proto);
331         }
332         print_fromto(&r->src, r->os_fingerprint, &r->dst, r->af, r->proto,
333             verbose);
334         if (r->uid.op)
335                 print_ugid(r->uid.op, r->uid.uid[0], r->uid.uid[1], "user",
336                     UID_MAX);
337         if (r->gid.op)
338                 print_ugid(r->gid.op, r->gid.gid[0], r->gid.gid[1], "group",
339                     GID_MAX);
340         if (r->flags || r->flagset) {
341                 printf(" flags ");
342                 print_flags(r->flags);
343                 printf("/");
344                 print_flags(r->flagset);
345         } else if (r->action == PF_PASS &&
346             (!r->proto || r->proto == IPPROTO_TCP) &&
347             !(r->rule_flag & PFRULE_FRAGMENT) &&
348             !anchor_call[0] && r->keep_state)
349                 printf(" flags any");
350         if (r->type) {
351                 const struct icmptypeent        *it;
352
353                 it = geticmptypebynumber(r->type-1, r->af);
354                 if (r->af != AF_INET6)
355                         printf(" icmp-type");
356                 else
357                         printf(" icmp6-type");
358                 if (it != NULL)
359                         printf(" %s", it->name);
360                 else
361                         printf(" %u", r->type-1);
362                 if (r->code) {
363                         const struct icmpcodeent        *ic;
364
365                         ic = geticmpcodebynumber(r->type-1, r->code-1, r->af);
366                         if (ic != NULL)
367                                 printf(" code %s", ic->name);
368                         else
369                                 printf(" code %u", r->code-1);
370                 }
371         }
372         if (r->tos)
373                 printf(" tos 0x%2.2x", r->tos);
374         if (!r->keep_state && r->action == PF_PASS && !anchor_call[0])
375                 printf(" no state");
376         else if (r->keep_state == PF_STATE_NORMAL)
377                 printf(" keep state");
378         else if (r->keep_state == PF_STATE_MODULATE)
379                 printf(" modulate state");
380         else if (r->keep_state == PF_STATE_SYNPROXY)
381                 printf(" synproxy state");
382         if (r->prob) {
383                 char    buf[20];
384
385                 snprintf(buf, sizeof(buf), "%f", r->prob*100.0/(UINT_MAX+1.0));
386                 for (i = strlen(buf)-1; i > 0; i--) {
387                         if (buf[i] == '0')
388                                 buf[i] = '\0';
389                         else {
390                                 if (buf[i] == '.')
391                                         buf[i] = '\0';
392                                 break;
393                         }
394                 }
395                 printf(" probability %s%%", buf);
396         }
397         opts = 0;
398         if (r->max_states || r->max_src_nodes || r->max_src_states)
399                 opts = 1;
400         if (r->rule_flag & PFRULE_NOSYNC)
401                 opts = 1;
402         if (r->rule_flag & PFRULE_SRCTRACK)
403                 opts = 1;
404         if (r->rule_flag & PFRULE_IFBOUND)
405                 opts = 1;
406         if (r->rule_flag & PFRULE_STATESLOPPY)
407                 opts = 1;
408         for (i = 0; !opts && i < PFTM_MAX; ++i)
409                 if (r->timeout[i])
410                         opts = 1;
411         if (opts) {
412                 printf(" (");
413                 if (r->max_states) {
414                         printf("max %u", r->max_states);
415                         opts = 0;
416                 }
417                 if (r->rule_flag & PFRULE_NOSYNC) {
418                         if (!opts)
419                                 printf(", ");
420                         printf("no-sync");
421                         opts = 0;
422                 }
423                 if (r->rule_flag & PFRULE_SRCTRACK) {
424                         if (!opts)
425                                 printf(", ");
426                         printf("source-track");
427                         if (r->rule_flag & PFRULE_RULESRCTRACK)
428                                 printf(" rule");
429                         else
430                                 printf(" global");
431                         opts = 0;
432                 }
433                 if (r->max_src_states) {
434                         if (!opts)
435                                 printf(", ");
436                         printf("max-src-states %u", r->max_src_states);
437                         opts = 0;
438                 }
439                 if (r->max_src_conn) {
440                         if (!opts)
441                                 printf(", ");
442                         printf("max-src-conn %u", r->max_src_conn);
443                         opts = 0;
444                 }
445                 if (r->max_src_conn_rate.limit) {
446                         if (!opts)
447                                 printf(", ");
448                         printf("max-src-conn-rate %u/%u",
449                             r->max_src_conn_rate.limit,
450                             r->max_src_conn_rate.seconds);
451                         opts = 0;
452                 }
453                 if (r->max_src_nodes) {
454                         if (!opts)
455                                 printf(", ");
456                         printf("max-src-nodes %u", r->max_src_nodes);
457                         opts = 0;
458                 }
459                 if (r->overload_tblname[0]) {
460                         if (!opts)
461                                 printf(", ");
462                         printf("overload <%s>", r->overload_tblname);
463                         if (r->flush)
464                                 printf(" flush");
465                         if (r->flush & PF_FLUSH_GLOBAL)
466                                 printf(" global");
467                 }
468                 if (r->rule_flag & PFRULE_IFBOUND) {
469                         if (!opts)
470                                 printf(", ");
471                         printf("if-bound");
472                         opts = 0;
473                 }
474                 if (r->rule_flag & PFRULE_STATESLOPPY) {
475                         if (!opts)
476                                 printf(", ");
477                         printf("sloppy");
478                         opts = 0;
479                 }
480                 if (r->rule_flag & PFRULE_PFLOW) {
481                         if (!opts)
482                                 printf(", ");
483                         printf("pflow");
484                         opts = 0;
485                 }
486                 for (i = 0; i < PFTM_MAX; ++i)
487                         if (r->timeout[i]) {
488                                 int j;
489
490                                 if (!opts)
491                                         printf(", ");
492                                 opts = 0;
493                                 for (j = 0; pf_timeouts[j].name != NULL;
494                                     ++j)
495                                         if (pf_timeouts[j].timeout == i)
496                                                 break;
497                                 printf("%s %u", pf_timeouts[j].name == NULL ?
498                                     "inv.timeout" : pf_timeouts[j].name,
499                                     r->timeout[i]);
500                         }
501                 printf(")");
502         }
503         if (r->rule_flag & PFRULE_FRAGMENT)
504                 printf(" fragment");
505         if (r->rule_flag & PFRULE_NODF)
506                 printf(" no-df");
507         if (r->rule_flag & PFRULE_RANDOMID)
508                 printf(" random-id");
509         if (r->min_ttl)
510                 printf(" min-ttl %d", r->min_ttl);
511         if (r->max_mss)
512                 printf(" max-mss %d", r->max_mss);
513         if (r->rule_flag & PFRULE_SET_TOS)
514                 printf(" set-tos 0x%2.2x", r->set_tos);
515         if (r->allow_opts)
516                 printf(" allow-opts");
517         if (r->action == PF_SCRUB) {
518                 if (r->rule_flag & PFRULE_REASSEMBLE_TCP)
519                         printf(" reassemble tcp");
520
521                 if (r->rule_flag & PFRULE_FRAGDROP)
522                         printf(" fragment drop-ovl");
523                 else if (r->rule_flag & PFRULE_FRAGCROP)
524                         printf(" fragment crop");
525                 else
526                         printf(" fragment reassemble");
527         }
528         if (r->label[0])
529                 printf(" label \"%s\"", r->label);
530         if (r->qname[0] && r->pqname[0])
531                 printf(" queue(%s, %s)", r->qname, r->pqname);
532         else if (r->qname[0])
533                 printf(" queue %s", r->qname);
534         if (r->tagname[0])
535                 printf(" tag %s", r->tagname);
536         if (r->match_tagname[0]) {
537                 if (r->match_tag_not)
538                         printf(" !");
539                 printf(" tagged %s", r->match_tagname);
540         }
541         if (r->rtableid != -1)
542                 printf(" rtable %u", r->rtableid);
543         if (r->divert.port) {
544                 if (PF_AZERO(&r->divert.addr, r->af)) {
545                         printf(" divert-reply");
546                 } else {
547                         /* XXX cut&paste from print_addr */
548                         char buf[48];
549
550                         printf(" divert-to ");
551                         if (inet_ntop(r->af, &r->divert.addr, buf,
552                             sizeof(buf)) == NULL)
553                                 printf("?");
554                         else
555                                 printf("%s", buf);
556                         printf(" port %u", ntohs(r->divert.port));
557                 }
558         }
559         if (!anchor_call[0] && (r->action == PF_NAT ||
560             r->action == PF_BINAT || r->action == PF_RDR)) {
561                 printf(" -> ");
562                 print_pool(&r->rpool, r->rpool.proxy_port[0],
563                     r->rpool.proxy_port[1], r->af, r->action);
564         }
565 }
566
567 const struct icmptypeent *
568 geticmptypebynumber(u_int8_t type, sa_family_t af)
569 {
570         unsigned int    i;
571
572         if (af != AF_INET6) {
573                 for (i=0; i < (sizeof (icmp_type) / sizeof(icmp_type[0]));
574                     i++) {
575                         if (type == icmp_type[i].type)
576                                 return (&icmp_type[i]);
577                 }
578         } else {
579                 for (i=0; i < (sizeof (icmp6_type) /
580                     sizeof(icmp6_type[0])); i++) {
581                         if (type == icmp6_type[i].type)
582                                  return (&icmp6_type[i]);
583                 }
584         }
585         return (NULL);
586 }
587
588 const struct icmpcodeent *
589 geticmpcodebynumber(u_int8_t type, u_int8_t code, sa_family_t af)
590 {
591         unsigned int    i;
592
593         if (af != AF_INET6) {
594                 for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0]));
595                     i++) {
596                         if (type == icmp_code[i].type &&
597                             code == icmp_code[i].code)
598                                 return (&icmp_code[i]);
599                 }
600         } else {
601                 for (i=0; i < (sizeof (icmp6_code) /
602                     sizeof(icmp6_code[0])); i++) {
603                         if (type == icmp6_code[i].type &&
604                             code == icmp6_code[i].code)
605                                 return (&icmp6_code[i]);
606                 }
607         }
608         return (NULL);
609 }
610
611 const struct icmpcodeent *
612 geticmpcodebyname(u_long type, char *w, sa_family_t af)
613 {
614         unsigned int    i;
615
616         if (af != AF_INET6) {
617                 for (i=0; i < (sizeof (icmp_code) / sizeof(icmp_code[0]));
618                     i++) {
619                         if (type == icmp_code[i].type &&
620                             !strcmp(w, icmp_code[i].name))
621                                 return (&icmp_code[i]);
622                 }
623         } else {
624                 for (i=0; i < (sizeof (icmp6_code) /
625                     sizeof(icmp6_code[0])); i++) {
626                         if (type == icmp6_code[i].type &&
627                             !strcmp(w, icmp6_code[i].name))
628                                 return (&icmp6_code[i]);
629                 }
630         }
631         return (NULL);
632 }
633
634 void
635 print_pool(struct pf_pool *pool, u_int16_t p1, u_int16_t p2,
636     sa_family_t af, int id)
637 {
638         struct pf_pooladdr      *pooladdr;
639
640         if ((TAILQ_FIRST(&pool->list) != NULL) &&
641             TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
642                 printf("{ ");
643         TAILQ_FOREACH(pooladdr, &pool->list, entries){
644                 switch (id) {
645                 case PF_NAT:
646                 case PF_RDR:
647                 case PF_BINAT:
648                         print_addr(&pooladdr->addr, af, 0);
649                         break;
650                 case PF_PASS:
651                         if (PF_AZERO(&pooladdr->addr.v.a.addr, af))
652                                 printf("%s", pooladdr->ifname);
653                         else {
654                                 printf("(%s ", pooladdr->ifname);
655                                 print_addr(&pooladdr->addr, af, 0);
656                                 printf(")");
657                         }
658                         break;
659                 default:
660                         break;
661                 }
662                 if (TAILQ_NEXT(pooladdr, entries) != NULL)
663                         printf(", ");
664                 else if (TAILQ_NEXT(TAILQ_FIRST(&pool->list), entries) != NULL)
665                         printf(" }");
666         }
667         switch (id) {
668         case PF_NAT:
669                 if ((p1 != PF_NAT_PROXY_PORT_LOW ||
670                     p2 != PF_NAT_PROXY_PORT_HIGH) && (p1 != 0 || p2 != 0)) {
671                         if (p1 == p2)
672                                 printf(" port %u", p1);
673                         else
674                                 printf(" port %u:%u", p1, p2);
675                 }
676                 break;
677         case PF_RDR:
678                 if (p1) {
679                         printf(" port %u", p1);
680                         if (p2 && (p2 != p1))
681                                 printf(":%u", p2);
682                 }
683                 break;
684         default:
685                 break;
686         }
687         switch (pool->opts & PF_POOL_TYPEMASK) {
688         case PF_POOL_NONE:
689                 break;
690         case PF_POOL_BITMASK:
691                 printf(" bitmask");
692                 break;
693         case PF_POOL_RANDOM:
694                 printf(" random");
695                 break;
696         case PF_POOL_SRCHASH:
697                 printf(" source-hash 0x%08x%08x%08x%08x",
698                     pool->key.key32[0], pool->key.key32[1],
699                     pool->key.key32[2], pool->key.key32[3]);
700                 break;
701         case PF_POOL_ROUNDROBIN:
702                 printf(" round-robin");
703                 break;
704         }
705         if (pool->opts & PF_POOL_STICKYADDR)
706                 printf(" sticky-address");
707         if (id == PF_NAT && p1 == 0 && p2 == 0)
708                 printf(" static-port");
709 }
710
711 void
712 print_fromto(struct pf_rule_addr *src, pf_osfp_t osfp, struct pf_rule_addr *dst,
713     sa_family_t af, u_int8_t proto, int verbose)
714 {
715         char buf[PF_OSFP_LEN*3];
716         if (src->addr.type == PF_ADDR_ADDRMASK &&
717             dst->addr.type == PF_ADDR_ADDRMASK &&
718             PF_AZERO(&src->addr.v.a.addr, AF_INET6) &&
719             PF_AZERO(&src->addr.v.a.mask, AF_INET6) &&
720             PF_AZERO(&dst->addr.v.a.addr, AF_INET6) &&
721             PF_AZERO(&dst->addr.v.a.mask, AF_INET6) &&
722             !src->neg && !dst->neg &&
723             !src->port_op && !dst->port_op &&
724             osfp == PF_OSFP_ANY)
725                 printf(" all");
726         else {
727                 printf(" from ");
728                 if (src->neg)
729                         printf("! ");
730                 print_addr(&src->addr, af, verbose);
731                 if (src->port_op)
732                         print_port(src->port_op, src->port[0],
733                             src->port[1],
734                             proto == IPPROTO_TCP ? "tcp" : "udp");
735                 if (osfp != PF_OSFP_ANY)
736                         printf(" os \"%s\"", pfctl_lookup_fingerprint(osfp, buf,
737                             sizeof(buf)));
738
739                 printf(" to ");
740                 if (dst->neg)
741                         printf("! ");
742                 print_addr(&dst->addr, af, verbose);
743                 if (dst->port_op)
744                         print_port(dst->port_op, dst->port[0],
745                             dst->port[1],
746                             proto == IPPROTO_TCP ? "tcp" : "udp");
747         }
748 }
749
750 void
751 print_ugid(u_int8_t op, unsigned u1, unsigned u2, const char *t, unsigned umax)
752 {
753         char    a1[11], a2[11];
754
755         snprintf(a1, sizeof(a1), "%u", u1);
756         snprintf(a2, sizeof(a2), "%u", u2);
757         printf(" %s", t);
758         if (u1 == umax && (op == PF_OP_EQ || op == PF_OP_NE))
759                 print_op(op, "unknown", a2);
760         else
761                 print_op(op, a1, a2);
762 }
763
764 void
765 print_flags(u_int8_t f)
766 {
767         int     i;
768
769         for (i = 0; tcpflags[i]; ++i)
770                 if (f & (1 << i))
771                         printf("%c", tcpflags[i]);
772 }
773
774 void
775 print_addr(struct pf_addr_wrap *addr, sa_family_t af, int verbose)
776 {
777         switch (addr->type) {
778         case PF_ADDR_DYNIFTL:
779                 printf("(%s", addr->v.ifname);
780                 if (addr->iflags & PFI_AFLAG_NETWORK)
781                         printf(":network");
782                 if (addr->iflags & PFI_AFLAG_BROADCAST)
783                         printf(":broadcast");
784                 if (addr->iflags & PFI_AFLAG_PEER)
785                         printf(":peer");
786                 if (addr->iflags & PFI_AFLAG_NOALIAS)
787                         printf(":0");
788                 if (verbose) {
789                         if (addr->p.dyncnt <= 0)
790                                 printf(":*");
791                         else
792                                 printf(":%d", addr->p.dyncnt);
793                 }
794                 printf(")");
795                 break;
796         case PF_ADDR_TABLE:
797                 if (verbose)
798                         if (addr->p.tblcnt == -1)
799                                 printf("<%s:*>", addr->v.tblname);
800                         else
801                                 printf("<%s:%d>", addr->v.tblname,
802                                     addr->p.tblcnt);
803                 else
804                         printf("<%s>", addr->v.tblname);
805                 return;
806         case PF_ADDR_RANGE: {
807                 char buf[48];
808
809                 if (inet_ntop(af, &addr->v.a.addr, buf, sizeof(buf)) == NULL)
810                         printf("?");
811                 else
812                         printf("%s", buf);
813                 if (inet_ntop(af, &addr->v.a.mask, buf, sizeof(buf)) == NULL)
814                         printf(" - ?");
815                 else
816                         printf(" - %s", buf);
817                 break;
818         }
819         case PF_ADDR_ADDRMASK:
820                 if (PF_AZERO(&addr->v.a.addr, AF_INET6) &&
821                     PF_AZERO(&addr->v.a.mask, AF_INET6))
822                         printf("any");
823                 else {
824                         char buf[48];
825
826                         if (inet_ntop(af, &addr->v.a.addr, buf,
827                             sizeof(buf)) == NULL)
828                                 printf("?");
829                         else
830                                 printf("%s", buf);
831                 }
832                 break;
833         case PF_ADDR_NOROUTE:
834                 printf("no-route");
835                 return;
836         case PF_ADDR_URPFFAILED:
837                 printf("urpf-failed");
838                 return;
839         case PF_ADDR_RTLABEL:
840                 printf("route \"%s\"", addr->v.rtlabelname);
841                 return;
842         default:
843                 printf("?");
844                 return;
845         }
846
847         /* mask if not _both_ address and mask are zero */
848         if (addr->type != PF_ADDR_RANGE &&
849             !(PF_AZERO(&addr->v.a.addr, AF_INET6) &&
850             PF_AZERO(&addr->v.a.mask, AF_INET6))) {
851                 int bits = unmask(&addr->v.a.mask, af);
852
853                 if (bits != (af == AF_INET ? 32 : 128))
854                         printf("/%d", bits);
855         }
856 }
857
858 void
859 print_op(u_int8_t op, const char *a1, const char *a2)
860 {
861         if (op == PF_OP_IRG)
862                 printf(" %s >< %s", a1, a2);
863         else if (op == PF_OP_XRG)
864                 printf(" %s <> %s", a1, a2);
865         else if (op == PF_OP_EQ)
866                 printf(" = %s", a1);
867         else if (op == PF_OP_NE)
868                 printf(" != %s", a1);
869         else if (op == PF_OP_LT)
870                 printf(" < %s", a1);
871         else if (op == PF_OP_LE)
872                 printf(" <= %s", a1);
873         else if (op == PF_OP_GT)
874                 printf(" > %s", a1);
875         else if (op == PF_OP_GE)
876                 printf(" >= %s", a1);
877         else if (op == PF_OP_RRG)
878                 printf(" %s:%s", a1, a2);
879 }
880
881 int
882 unmask(struct pf_addr *m, sa_family_t af)
883 {
884         int i = 31, j = 0, b = 0;
885         u_int32_t tmp;
886
887         while (j < 4 && m->addr32[j] == 0xffffffff) {
888                 b += 32;
889                 j++;
890         }
891         if (j < 4) {
892                 tmp = ntohl(m->addr32[j]);
893                 for (i = 31; tmp & (1 << i); --i)
894                         b++;
895         }
896         return (b);
897 }
898 void
899 print_port(u_int8_t op, u_int16_t p1, u_int16_t p2, const char *proto)
900 {
901         char             a1[6], a2[6];
902         struct servent  *s;
903
904         s = getservbyport(p1, proto);
905         p1 = ntohs(p1);
906         p2 = ntohs(p2);
907         snprintf(a1, sizeof(a1), "%u", p1);
908         snprintf(a2, sizeof(a2), "%u", p2);
909         printf(" port");
910         if (s != NULL && (op == PF_OP_EQ || op == PF_OP_NE))
911                 print_op(op, s->s_name, a2);
912         else
913                 print_op(op, a1, a2);
914 }
915
916 /* Lookup a fingerprint name by ID */
917 char *
918 pfctl_lookup_fingerprint(pf_osfp_t fp, char *buf, size_t len)
919 {
920         int class, version, subtype;
921         struct name_list *list;
922         struct name_entry *nm;
923
924         char *class_name, *version_name, *subtype_name;
925         class_name = version_name = subtype_name = NULL;
926
927         if (fp == PF_OSFP_UNKNOWN) {
928                 strlcpy(buf, "unknown", len);
929                 return (buf);
930         }
931         if (fp == PF_OSFP_ANY) {
932                 strlcpy(buf, "any", len);
933                 return (buf);
934         }
935
936         PF_OSFP_UNPACK(fp, class, version, subtype);
937         if (class >= (1 << _FP_CLASS_BITS) ||
938             version >= (1 << _FP_VERSION_BITS) ||
939             subtype >= (1 << _FP_SUBTYPE_BITS)) {
940                 warnx("PF_OSFP_UNPACK(0x%x) failed!!", fp);
941                 strlcpy(buf, "nomatch", len);
942                 return (buf);
943         }
944
945         LIST_FOREACH(nm, &classes, nm_entry) {
946                 if (nm->nm_num == class) {
947                         class_name = nm->nm_name;
948                         if (version == PF_OSFP_ANY)
949                                 goto found;
950                         list = &nm->nm_sublist;
951                         LIST_FOREACH(nm, list, nm_entry) {
952                                 if (nm->nm_num == version) {
953                                         version_name = nm->nm_name;
954                                         if (subtype == PF_OSFP_ANY)
955                                                 goto found;
956                                         list = &nm->nm_sublist;
957                                         LIST_FOREACH(nm, list, nm_entry) {
958                                                 if (nm->nm_num == subtype) {
959                                                         subtype_name =
960                                                             nm->nm_name;
961                                                         goto found;
962                                                 }
963                                         } /* foreach subtype */
964                                         strlcpy(buf, "nomatch", len);
965                                         return (buf);
966                                 }
967                         } /* foreach version */
968                         strlcpy(buf, "nomatch", len);
969                         return (buf);
970                 }
971         } /* foreach class */
972
973         strlcpy(buf, "nomatch", len);
974         return (buf);
975
976 found:
977         snprintf(buf, len, "%s", class_name);
978         if (version_name) {
979                 strlcat(buf, " ", len);
980                 strlcat(buf, version_name, len);
981                 if (subtype_name) {
982                         if (strchr(version_name, ' '))
983                                 strlcat(buf, " ", len);
984                         else if (strchr(version_name, '.') &&
985                             isdigit(*subtype_name))
986                                 strlcat(buf, ".", len);
987                         else
988                                 strlcat(buf, " ", len);
989                         strlcat(buf, subtype_name, len);
990                 }
991         }
992         return (buf);
993 }
994
995