1145519Sdarrenr/* $FreeBSD$ */ 2145510Sdarrenr 3145510Sdarrenr/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 5145510Sdarrenr * 6145510Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 7145510Sdarrenr * 8255332Scy * $Id$ 9145510Sdarrenr */ 10145510Sdarrenr 11145510Sdarrenr#include "ipf.h" 12145510Sdarrenr 13145510Sdarrenr 14145510Sdarrenr/* 15145510Sdarrenr * print the filter structure in a useful way 16145510Sdarrenr */ 17255332Scyvoid 18255332Scyprintfr(fp, iocfunc) 19255332Scy struct frentry *fp; 20255332Scy ioctlfunc_t iocfunc; 21145510Sdarrenr{ 22145510Sdarrenr struct protoent *p; 23145510Sdarrenr u_short sec[2]; 24145510Sdarrenr u_32_t type; 25255332Scy int pr, af; 26145510Sdarrenr char *s; 27255332Scy int hash; 28145510Sdarrenr 29145510Sdarrenr pr = -2; 30145510Sdarrenr type = fp->fr_type & ~FR_T_BUILTIN; 31145510Sdarrenr 32145510Sdarrenr if ((fp->fr_type & FR_T_BUILTIN) != 0) 33255332Scy PRINTF("# Builtin: "); 34145510Sdarrenr 35153881Sguido if (fp->fr_collect != 0) 36255332Scy PRINTF("%u ", fp->fr_collect); 37153881Sguido 38145510Sdarrenr if (fp->fr_type == FR_T_CALLFUNC) { 39145510Sdarrenr ; 40145510Sdarrenr } else if (fp->fr_func != NULL) { 41255332Scy PRINTF("call"); 42145510Sdarrenr if ((fp->fr_flags & FR_CALLNOW) != 0) 43255332Scy PRINTF(" now"); 44145510Sdarrenr s = kvatoname(fp->fr_func, iocfunc); 45255332Scy PRINTF(" %s/%u", s ? s : "?", fp->fr_arg); 46145510Sdarrenr } else if (FR_ISPASS(fp->fr_flags)) 47255332Scy PRINTF("pass"); 48145510Sdarrenr else if (FR_ISBLOCK(fp->fr_flags)) { 49255332Scy PRINTF("block"); 50145510Sdarrenr } else if ((fp->fr_flags & FR_LOGMASK) == FR_LOG) { 51145510Sdarrenr printlog(fp); 52145510Sdarrenr } else if (FR_ISACCOUNT(fp->fr_flags)) 53255332Scy PRINTF("count"); 54145510Sdarrenr else if (FR_ISAUTH(fp->fr_flags)) 55255332Scy PRINTF("auth"); 56145510Sdarrenr else if (FR_ISPREAUTH(fp->fr_flags)) 57255332Scy PRINTF("preauth"); 58145510Sdarrenr else if (FR_ISNOMATCH(fp->fr_flags)) 59255332Scy PRINTF("nomatch"); 60255332Scy else if (FR_ISDECAPS(fp->fr_flags)) 61255332Scy PRINTF("decapsulate"); 62145510Sdarrenr else if (FR_ISSKIP(fp->fr_flags)) 63255332Scy PRINTF("skip %u", fp->fr_arg); 64145510Sdarrenr else { 65255332Scy PRINTF("%x", fp->fr_flags); 66145510Sdarrenr } 67161357Sguido if (fp->fr_flags & FR_RETICMP) { 68161357Sguido if ((fp->fr_flags & FR_RETMASK) == FR_FAKEICMP) 69255332Scy PRINTF(" return-icmp-as-dest"); 70161357Sguido else if ((fp->fr_flags & FR_RETMASK) == FR_RETICMP) 71255332Scy PRINTF(" return-icmp"); 72161357Sguido if (fp->fr_icode) { 73161357Sguido if (fp->fr_icode <= MAX_ICMPCODE) 74255332Scy PRINTF("(%s)", 75161357Sguido icmpcodes[(int)fp->fr_icode]); 76161357Sguido else 77255332Scy PRINTF("(%d)", fp->fr_icode); 78161357Sguido } 79161357Sguido } else if ((fp->fr_flags & FR_RETMASK) == FR_RETRST) 80255332Scy PRINTF(" return-rst"); 81145510Sdarrenr 82145510Sdarrenr if (fp->fr_flags & FR_OUTQUE) 83255332Scy PRINTF(" out "); 84255332Scy else if (fp->fr_flags & FR_INQUE) 85255332Scy PRINTF(" in "); 86145510Sdarrenr 87145510Sdarrenr if (((fp->fr_flags & FR_LOGB) == FR_LOGB) || 88145510Sdarrenr ((fp->fr_flags & FR_LOGP) == FR_LOGP)) { 89145510Sdarrenr printlog(fp); 90145510Sdarrenr putchar(' '); 91145510Sdarrenr } 92145510Sdarrenr 93145510Sdarrenr if (fp->fr_flags & FR_QUICK) 94255332Scy PRINTF("quick "); 95145510Sdarrenr 96255332Scy if (fp->fr_ifnames[0] != -1) { 97255332Scy printifname("on ", fp->fr_names + fp->fr_ifnames[0], 98255332Scy fp->fr_ifa); 99255332Scy if (fp->fr_ifnames[1] != -1 && 100255332Scy strcmp(fp->fr_names + fp->fr_ifnames[1], "*")) 101255332Scy printifname(",", fp->fr_names + fp->fr_ifnames[1], 102255332Scy fp->fr_ifas[1]); 103145510Sdarrenr putchar(' '); 104145510Sdarrenr } 105145510Sdarrenr 106255332Scy if (fp->fr_tif.fd_name != -1) 107255332Scy print_toif(fp->fr_family, "to", fp->fr_names, &fp->fr_tif); 108255332Scy if (fp->fr_dif.fd_name != -1) 109255332Scy print_toif(fp->fr_family, "dup-to", fp->fr_names, 110255332Scy &fp->fr_dif); 111255332Scy if (fp->fr_rif.fd_name != -1) 112255332Scy print_toif(fp->fr_family, "reply-to", fp->fr_names, 113255332Scy &fp->fr_rif); 114145510Sdarrenr if (fp->fr_flags & FR_FASTROUTE) 115255332Scy PRINTF("fastroute "); 116145510Sdarrenr 117255332Scy if ((fp->fr_ifnames[2] != -1 && 118255332Scy strcmp(fp->fr_names + fp->fr_ifnames[2], "*")) || 119255332Scy (fp->fr_ifnames[3] != -1 && 120255332Scy strcmp(fp->fr_names + fp->fr_ifnames[3], "*"))) { 121145510Sdarrenr if (fp->fr_flags & FR_OUTQUE) 122255332Scy PRINTF("in-via "); 123145510Sdarrenr else 124255332Scy PRINTF("out-via "); 125145510Sdarrenr 126255332Scy if (fp->fr_ifnames[2] != -1) { 127255332Scy printifname("", fp->fr_names + fp->fr_ifnames[2], 128145510Sdarrenr fp->fr_ifas[2]); 129255332Scy if (fp->fr_ifnames[3] != -1) { 130255332Scy printifname(",", 131255332Scy fp->fr_names + fp->fr_ifnames[3], 132145510Sdarrenr fp->fr_ifas[3]); 133145510Sdarrenr } 134153881Sguido putchar(' '); 135145510Sdarrenr } 136145510Sdarrenr } 137145510Sdarrenr 138255332Scy if (fp->fr_family == AF_INET) { 139255332Scy PRINTF("inet "); 140255332Scy af = AF_INET; 141255332Scy#ifdef USE_INET6 142255332Scy } else if (fp->fr_family == AF_INET6) { 143255332Scy PRINTF("inet6 "); 144255332Scy af = AF_INET6; 145255332Scy#endif 146255332Scy } else { 147255332Scy af = -1; 148255332Scy } 149255332Scy 150145510Sdarrenr if (type == FR_T_IPF) { 151145510Sdarrenr if (fp->fr_mip.fi_tos) 152255332Scy PRINTF("tos %#x ", fp->fr_tos); 153145510Sdarrenr if (fp->fr_mip.fi_ttl) 154255332Scy PRINTF("ttl %d ", fp->fr_ttl); 155145510Sdarrenr if (fp->fr_flx & FI_TCPUDP) { 156255332Scy PRINTF("proto tcp/udp "); 157145510Sdarrenr pr = -1; 158145510Sdarrenr } else if (fp->fr_mip.fi_p) { 159145510Sdarrenr pr = fp->fr_ip.fi_p; 160153881Sguido p = getprotobynumber(pr); 161255332Scy PRINTF("proto "); 162153881Sguido printproto(p, pr, NULL); 163153881Sguido putchar(' '); 164145510Sdarrenr } 165145510Sdarrenr } 166145510Sdarrenr 167255332Scy switch (type) 168255332Scy { 169255332Scy case FR_T_NONE : 170255332Scy PRINTF("all"); 171255332Scy break; 172255332Scy 173255332Scy case FR_T_IPF : 174255332Scy PRINTF("from %s", fp->fr_flags & FR_NOTSRCIP ? "!" : ""); 175255332Scy printaddr(af, fp->fr_satype, fp->fr_names, fp->fr_ifnames[0], 176145510Sdarrenr &fp->fr_src.s_addr, &fp->fr_smsk.s_addr); 177145510Sdarrenr if (fp->fr_scmp) 178145510Sdarrenr printportcmp(pr, &fp->fr_tuc.ftu_src); 179145510Sdarrenr 180255332Scy PRINTF(" to %s", fp->fr_flags & FR_NOTDSTIP ? "!" : ""); 181255332Scy printaddr(af, fp->fr_datype, fp->fr_names, fp->fr_ifnames[0], 182145510Sdarrenr &fp->fr_dst.s_addr, &fp->fr_dmsk.s_addr); 183145510Sdarrenr if (fp->fr_dcmp) 184145510Sdarrenr printportcmp(pr, &fp->fr_tuc.ftu_dst); 185145510Sdarrenr 186255332Scy if (((fp->fr_proto == IPPROTO_ICMP) || 187255332Scy (fp->fr_proto == IPPROTO_ICMPV6)) && fp->fr_icmpm) { 188145510Sdarrenr int type = fp->fr_icmp, code; 189255332Scy char *name; 190145510Sdarrenr 191145510Sdarrenr type = ntohs(fp->fr_icmp); 192145510Sdarrenr code = type & 0xff; 193145510Sdarrenr type /= 256; 194255332Scy name = icmptypename(fp->fr_family, type); 195255332Scy if (name == NULL) 196255332Scy PRINTF(" icmp-type %d", type); 197145510Sdarrenr else 198255332Scy PRINTF(" icmp-type %s", name); 199145510Sdarrenr if (ntohs(fp->fr_icmpm) & 0xff) 200255332Scy PRINTF(" code %d", code); 201145510Sdarrenr } 202145510Sdarrenr if ((fp->fr_proto == IPPROTO_TCP) && 203145510Sdarrenr (fp->fr_tcpf || fp->fr_tcpfm)) { 204255332Scy PRINTF(" flags "); 205255332Scy printtcpflags(fp->fr_tcpf, fp->fr_tcpfm); 206145510Sdarrenr } 207255332Scy break; 208255332Scy 209255332Scy case FR_T_BPFOPC : 210255332Scy { 211145510Sdarrenr fakebpf_t *fb; 212145510Sdarrenr int i; 213145510Sdarrenr 214255332Scy PRINTF("bpf-v%d { \"", fp->fr_family); 215145510Sdarrenr i = fp->fr_dsize / sizeof(*fb); 216145510Sdarrenr 217145510Sdarrenr for (fb = fp->fr_data, s = ""; i; i--, fb++, s = " ") 218255332Scy PRINTF("%s%#x %#x %#x %#x", s, fb->fb_c, fb->fb_t, 219145510Sdarrenr fb->fb_f, fb->fb_k); 220145510Sdarrenr 221255332Scy PRINTF("\" }"); 222255332Scy break; 223255332Scy } 224255332Scy 225255332Scy case FR_T_COMPIPF : 226255332Scy break; 227255332Scy 228255332Scy case FR_T_CALLFUNC : 229255332Scy PRINTF("call function at %p", fp->fr_data); 230255332Scy break; 231255332Scy 232255332Scy case FR_T_IPFEXPR : 233255332Scy PRINTF("exp { \""); 234255332Scy printipfexpr(fp->fr_data); 235255332Scy PRINTF("\" } "); 236255332Scy break; 237255332Scy 238255332Scy default : 239255332Scy PRINTF("[unknown filter type %#x]", fp->fr_type); 240255332Scy break; 241145510Sdarrenr } 242145510Sdarrenr 243145510Sdarrenr if ((type == FR_T_IPF) && 244145510Sdarrenr ((fp->fr_flx & FI_WITH) || (fp->fr_mflx & FI_WITH) || 245145510Sdarrenr fp->fr_optbits || fp->fr_optmask || 246145510Sdarrenr fp->fr_secbits || fp->fr_secmask)) { 247145510Sdarrenr char *comma = " "; 248145510Sdarrenr 249255332Scy PRINTF(" with"); 250145510Sdarrenr if (fp->fr_optbits || fp->fr_optmask || 251145510Sdarrenr fp->fr_secbits || fp->fr_secmask) { 252145510Sdarrenr sec[0] = fp->fr_secmask; 253145510Sdarrenr sec[1] = fp->fr_secbits; 254255332Scy if (fp->fr_family == AF_INET) 255145510Sdarrenr optprint(sec, fp->fr_optmask, fp->fr_optbits); 256145510Sdarrenr#ifdef USE_INET6 257145510Sdarrenr else 258145510Sdarrenr optprintv6(sec, fp->fr_optmask, 259145510Sdarrenr fp->fr_optbits); 260145510Sdarrenr#endif 261145510Sdarrenr } else if (fp->fr_mflx & FI_OPTIONS) { 262145510Sdarrenr fputs(comma, stdout); 263145510Sdarrenr if (!(fp->fr_flx & FI_OPTIONS)) 264255332Scy PRINTF("not "); 265255332Scy PRINTF("ipopts"); 266145510Sdarrenr comma = ","; 267145510Sdarrenr } 268145510Sdarrenr if (fp->fr_mflx & FI_SHORT) { 269145510Sdarrenr fputs(comma, stdout); 270145510Sdarrenr if (!(fp->fr_flx & FI_SHORT)) 271255332Scy PRINTF("not "); 272255332Scy PRINTF("short"); 273145510Sdarrenr comma = ","; 274145510Sdarrenr } 275145510Sdarrenr if (fp->fr_mflx & FI_FRAG) { 276145510Sdarrenr fputs(comma, stdout); 277145510Sdarrenr if (!(fp->fr_flx & FI_FRAG)) 278255332Scy PRINTF("not "); 279255332Scy PRINTF("frag"); 280145510Sdarrenr comma = ","; 281145510Sdarrenr } 282145510Sdarrenr if (fp->fr_mflx & FI_FRAGBODY) { 283145510Sdarrenr fputs(comma, stdout); 284145510Sdarrenr if (!(fp->fr_flx & FI_FRAGBODY)) 285255332Scy PRINTF("not "); 286255332Scy PRINTF("frag-body"); 287145510Sdarrenr comma = ","; 288145510Sdarrenr } 289145510Sdarrenr if (fp->fr_mflx & FI_NATED) { 290145510Sdarrenr fputs(comma, stdout); 291145510Sdarrenr if (!(fp->fr_flx & FI_NATED)) 292255332Scy PRINTF("not "); 293255332Scy PRINTF("nat"); 294145510Sdarrenr comma = ","; 295145510Sdarrenr } 296145510Sdarrenr if (fp->fr_mflx & FI_LOWTTL) { 297145510Sdarrenr fputs(comma, stdout); 298145510Sdarrenr if (!(fp->fr_flx & FI_LOWTTL)) 299255332Scy PRINTF("not "); 300255332Scy PRINTF("lowttl"); 301145510Sdarrenr comma = ","; 302145510Sdarrenr } 303145510Sdarrenr if (fp->fr_mflx & FI_BAD) { 304145510Sdarrenr fputs(comma, stdout); 305145510Sdarrenr if (!(fp->fr_flx & FI_BAD)) 306255332Scy PRINTF("not "); 307255332Scy PRINTF("bad"); 308145510Sdarrenr comma = ","; 309145510Sdarrenr } 310145510Sdarrenr if (fp->fr_mflx & FI_BADSRC) { 311145510Sdarrenr fputs(comma, stdout); 312145510Sdarrenr if (!(fp->fr_flx & FI_BADSRC)) 313255332Scy PRINTF("not "); 314255332Scy PRINTF("bad-src"); 315145510Sdarrenr comma = ","; 316145510Sdarrenr } 317145510Sdarrenr if (fp->fr_mflx & FI_BADNAT) { 318145510Sdarrenr fputs(comma, stdout); 319145510Sdarrenr if (!(fp->fr_flx & FI_BADNAT)) 320255332Scy PRINTF("not "); 321255332Scy PRINTF("bad-nat"); 322145510Sdarrenr comma = ","; 323145510Sdarrenr } 324145510Sdarrenr if (fp->fr_mflx & FI_OOW) { 325145510Sdarrenr fputs(comma, stdout); 326145510Sdarrenr if (!(fp->fr_flx & FI_OOW)) 327255332Scy PRINTF("not "); 328255332Scy PRINTF("oow"); 329153881Sguido comma = ","; 330145510Sdarrenr } 331153881Sguido if (fp->fr_mflx & FI_MBCAST) { 332153881Sguido fputs(comma, stdout); 333153881Sguido if (!(fp->fr_flx & FI_MBCAST)) 334255332Scy PRINTF("not "); 335255332Scy PRINTF("mbcast"); 336153881Sguido comma = ","; 337153881Sguido } 338153881Sguido if (fp->fr_mflx & FI_BROADCAST) { 339153881Sguido fputs(comma, stdout); 340153881Sguido if (!(fp->fr_flx & FI_BROADCAST)) 341255332Scy PRINTF("not "); 342255332Scy PRINTF("bcast"); 343153881Sguido comma = ","; 344153881Sguido } 345153881Sguido if (fp->fr_mflx & FI_MULTICAST) { 346153881Sguido fputs(comma, stdout); 347153881Sguido if (!(fp->fr_flx & FI_MULTICAST)) 348255332Scy PRINTF("not "); 349255332Scy PRINTF("mcast"); 350153881Sguido comma = ","; 351153881Sguido } 352153881Sguido if (fp->fr_mflx & FI_STATE) { 353153881Sguido fputs(comma, stdout); 354153881Sguido if (!(fp->fr_flx & FI_STATE)) 355255332Scy PRINTF("not "); 356255332Scy PRINTF("state"); 357153881Sguido comma = ","; 358153881Sguido } 359255332Scy if (fp->fr_mflx & FI_V6EXTHDR) { 360255332Scy fputs(comma, stdout); 361255332Scy if (!(fp->fr_flx & FI_V6EXTHDR)) 362255332Scy PRINTF("not "); 363255332Scy PRINTF("v6hdrs"); 364255332Scy comma = ","; 365255332Scy } 366145510Sdarrenr } 367145510Sdarrenr 368145510Sdarrenr if (fp->fr_flags & FR_KEEPSTATE) { 369255332Scy host_track_t *src = &fp->fr_srctrack; 370255332Scy PRINTF(" keep state"); 371255332Scy if ((fp->fr_flags & (FR_STSTRICT|FR_NEWISN| 372255332Scy FR_NOICMPERR|FR_STATESYNC)) || 373255332Scy (fp->fr_statemax != 0) || (fp->fr_age[0] != 0) || 374255332Scy (src->ht_max_nodes != 0)) { 375145510Sdarrenr char *comma = ""; 376255332Scy PRINTF(" ("); 377145510Sdarrenr if (fp->fr_statemax != 0) { 378255332Scy PRINTF("limit %u", fp->fr_statemax); 379145510Sdarrenr comma = ","; 380145510Sdarrenr } 381255332Scy if (src->ht_max_nodes != 0) { 382255332Scy PRINTF("%smax-nodes %d", comma, 383255332Scy src->ht_max_nodes); 384255332Scy if (src->ht_max_per_node) 385255332Scy PRINTF(", max-per-src %d/%d", 386255332Scy src->ht_max_per_node, 387255332Scy src->ht_netmask); 388255332Scy comma = ","; 389255332Scy } 390145510Sdarrenr if (fp->fr_flags & FR_STSTRICT) { 391255332Scy PRINTF("%sstrict", comma); 392145510Sdarrenr comma = ","; 393145510Sdarrenr } 394255332Scy if (fp->fr_flags & FR_STLOOSE) { 395255332Scy PRINTF("%sloose", comma); 396255332Scy comma = ","; 397255332Scy } 398145510Sdarrenr if (fp->fr_flags & FR_NEWISN) { 399255332Scy PRINTF("%snewisn", comma); 400145510Sdarrenr comma = ","; 401145510Sdarrenr } 402145510Sdarrenr if (fp->fr_flags & FR_NOICMPERR) { 403255332Scy PRINTF("%sno-icmp-err", comma); 404145510Sdarrenr comma = ","; 405145510Sdarrenr } 406145510Sdarrenr if (fp->fr_flags & FR_STATESYNC) { 407255332Scy PRINTF("%ssync", comma); 408145510Sdarrenr comma = ","; 409145510Sdarrenr } 410145510Sdarrenr if (fp->fr_age[0] || fp->fr_age[1]) 411255332Scy PRINTF("%sage %d/%d", comma, fp->fr_age[0], 412145510Sdarrenr fp->fr_age[1]); 413255332Scy PRINTF(")"); 414145510Sdarrenr } 415145510Sdarrenr } 416145510Sdarrenr if (fp->fr_flags & FR_KEEPFRAG) { 417255332Scy PRINTF(" keep frags"); 418145510Sdarrenr if (fp->fr_flags & (FR_FRSTRICT)) { 419255332Scy PRINTF(" ("); 420145510Sdarrenr if (fp->fr_flags & FR_FRSTRICT) 421255332Scy PRINTF("strict"); 422255332Scy PRINTF(")"); 423255332Scy 424145510Sdarrenr } 425145510Sdarrenr } 426145510Sdarrenr if (fp->fr_isc != (struct ipscan *)-1) { 427255332Scy if (fp->fr_isctag != -1) 428255332Scy PRINTF(" scan %s", fp->fr_isctag + fp->fr_names); 429145510Sdarrenr else 430255332Scy PRINTF(" scan *"); 431145510Sdarrenr } 432255332Scy if (fp->fr_grhead != -1) 433255332Scy PRINTF(" head %s", fp->fr_names + fp->fr_grhead); 434255332Scy if (fp->fr_group != -1) 435255332Scy PRINTF(" group %s", fp->fr_names + fp->fr_group); 436145510Sdarrenr if (fp->fr_logtag != FR_NOLOGTAG || *fp->fr_nattag.ipt_tag) { 437145510Sdarrenr char *s = ""; 438145510Sdarrenr 439255332Scy PRINTF(" set-tag("); 440145510Sdarrenr if (fp->fr_logtag != FR_NOLOGTAG) { 441255332Scy PRINTF("log=%u", fp->fr_logtag); 442145510Sdarrenr s = ", "; 443145510Sdarrenr } 444145510Sdarrenr if (*fp->fr_nattag.ipt_tag) { 445255332Scy PRINTF("%snat=%-.*s", s, IPFTAG_LEN, 446145510Sdarrenr fp->fr_nattag.ipt_tag); 447145510Sdarrenr } 448255332Scy PRINTF(")"); 449145510Sdarrenr } 450170268Sdarrenr 451145510Sdarrenr if (fp->fr_pps) 452255332Scy PRINTF(" pps %d", fp->fr_pps); 453170268Sdarrenr 454255332Scy if (fp->fr_comment != -1) 455255332Scy PRINTF(" comment \"%s\"", fp->fr_names + fp->fr_comment); 456255332Scy 457255332Scy hash = 0; 458170268Sdarrenr if ((fp->fr_flags & FR_KEEPSTATE) && (opts & OPT_VERBOSE)) { 459255332Scy PRINTF(" # count %d", fp->fr_statecnt); 460255332Scy if (fp->fr_die != 0) 461255332Scy PRINTF(" rule-ttl %u", fp->fr_die); 462255332Scy hash = 1; 463255332Scy } else if (fp->fr_die != 0) { 464255332Scy PRINTF(" # rule-ttl %u", fp->fr_die); 465255332Scy hash = 1; 466170268Sdarrenr } 467255332Scy if (opts & OPT_DEBUG) { 468255332Scy if (hash == 0) 469255332Scy putchar('#'); 470255332Scy PRINTF(" ref %d", fp->fr_ref); 471255332Scy } 472145510Sdarrenr (void)putchar('\n'); 473145510Sdarrenr} 474