1*3b3a8eb9SGleb Smirnoff /*- 2*3b3a8eb9SGleb Smirnoff * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa 3*3b3a8eb9SGleb Smirnoff * 4*3b3a8eb9SGleb Smirnoff * Redistribution and use in source and binary forms, with or without 5*3b3a8eb9SGleb Smirnoff * modification, are permitted provided that the following conditions 6*3b3a8eb9SGleb Smirnoff * are met: 7*3b3a8eb9SGleb Smirnoff * 1. Redistributions of source code must retain the above copyright 8*3b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer. 9*3b3a8eb9SGleb Smirnoff * 2. Redistributions in binary form must reproduce the above copyright 10*3b3a8eb9SGleb Smirnoff * notice, this list of conditions and the following disclaimer in the 11*3b3a8eb9SGleb Smirnoff * documentation and/or other materials provided with the distribution. 12*3b3a8eb9SGleb Smirnoff * 13*3b3a8eb9SGleb Smirnoff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14*3b3a8eb9SGleb Smirnoff * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15*3b3a8eb9SGleb Smirnoff * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16*3b3a8eb9SGleb Smirnoff * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17*3b3a8eb9SGleb Smirnoff * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18*3b3a8eb9SGleb Smirnoff * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19*3b3a8eb9SGleb Smirnoff * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20*3b3a8eb9SGleb Smirnoff * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21*3b3a8eb9SGleb Smirnoff * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22*3b3a8eb9SGleb Smirnoff * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23*3b3a8eb9SGleb Smirnoff * SUCH DAMAGE. 24*3b3a8eb9SGleb Smirnoff */ 25*3b3a8eb9SGleb Smirnoff 26*3b3a8eb9SGleb Smirnoff #include <sys/cdefs.h> 27*3b3a8eb9SGleb Smirnoff __FBSDID("$FreeBSD$"); 28*3b3a8eb9SGleb Smirnoff 29*3b3a8eb9SGleb Smirnoff /* 30*3b3a8eb9SGleb Smirnoff * Logging support for ipfw 31*3b3a8eb9SGleb Smirnoff */ 32*3b3a8eb9SGleb Smirnoff 33*3b3a8eb9SGleb Smirnoff #include "opt_ipfw.h" 34*3b3a8eb9SGleb Smirnoff #include "opt_inet.h" 35*3b3a8eb9SGleb Smirnoff #ifndef INET 36*3b3a8eb9SGleb Smirnoff #error IPFIREWALL requires INET. 37*3b3a8eb9SGleb Smirnoff #endif /* INET */ 38*3b3a8eb9SGleb Smirnoff #include "opt_inet6.h" 39*3b3a8eb9SGleb Smirnoff 40*3b3a8eb9SGleb Smirnoff #include <sys/param.h> 41*3b3a8eb9SGleb Smirnoff #include <sys/systm.h> 42*3b3a8eb9SGleb Smirnoff #include <sys/mbuf.h> 43*3b3a8eb9SGleb Smirnoff #include <sys/kernel.h> 44*3b3a8eb9SGleb Smirnoff #include <sys/socket.h> 45*3b3a8eb9SGleb Smirnoff #include <sys/sysctl.h> 46*3b3a8eb9SGleb Smirnoff #include <sys/syslog.h> 47*3b3a8eb9SGleb Smirnoff #include <sys/lock.h> 48*3b3a8eb9SGleb Smirnoff #include <sys/rwlock.h> 49*3b3a8eb9SGleb Smirnoff #include <net/ethernet.h> /* for ETHERTYPE_IP */ 50*3b3a8eb9SGleb Smirnoff #include <net/if.h> 51*3b3a8eb9SGleb Smirnoff #include <net/if_clone.h> 52*3b3a8eb9SGleb Smirnoff #include <net/vnet.h> 53*3b3a8eb9SGleb Smirnoff #include <net/if_types.h> /* for IFT_PFLOG */ 54*3b3a8eb9SGleb Smirnoff #include <net/bpf.h> /* for BPF */ 55*3b3a8eb9SGleb Smirnoff 56*3b3a8eb9SGleb Smirnoff #include <netinet/in.h> 57*3b3a8eb9SGleb Smirnoff #include <netinet/ip.h> 58*3b3a8eb9SGleb Smirnoff #include <netinet/ip_icmp.h> 59*3b3a8eb9SGleb Smirnoff #include <netinet/ip_var.h> 60*3b3a8eb9SGleb Smirnoff #include <netinet/ip_fw.h> 61*3b3a8eb9SGleb Smirnoff #include <netinet/tcp_var.h> 62*3b3a8eb9SGleb Smirnoff #include <netinet/udp.h> 63*3b3a8eb9SGleb Smirnoff 64*3b3a8eb9SGleb Smirnoff #include <netinet/ip6.h> 65*3b3a8eb9SGleb Smirnoff #include <netinet/icmp6.h> 66*3b3a8eb9SGleb Smirnoff #ifdef INET6 67*3b3a8eb9SGleb Smirnoff #include <netinet6/in6_var.h> /* ip6_sprintf() */ 68*3b3a8eb9SGleb Smirnoff #endif 69*3b3a8eb9SGleb Smirnoff 70*3b3a8eb9SGleb Smirnoff #include <netpfil/ipfw/ip_fw_private.h> 71*3b3a8eb9SGleb Smirnoff 72*3b3a8eb9SGleb Smirnoff #ifdef MAC 73*3b3a8eb9SGleb Smirnoff #include <security/mac/mac_framework.h> 74*3b3a8eb9SGleb Smirnoff #endif 75*3b3a8eb9SGleb Smirnoff 76*3b3a8eb9SGleb Smirnoff /* 77*3b3a8eb9SGleb Smirnoff * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T 78*3b3a8eb9SGleb Smirnoff * Other macros just cast void * into the appropriate type 79*3b3a8eb9SGleb Smirnoff */ 80*3b3a8eb9SGleb Smirnoff #define L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl)) 81*3b3a8eb9SGleb Smirnoff #define TCP(p) ((struct tcphdr *)(p)) 82*3b3a8eb9SGleb Smirnoff #define SCTP(p) ((struct sctphdr *)(p)) 83*3b3a8eb9SGleb Smirnoff #define UDP(p) ((struct udphdr *)(p)) 84*3b3a8eb9SGleb Smirnoff #define ICMP(p) ((struct icmphdr *)(p)) 85*3b3a8eb9SGleb Smirnoff #define ICMP6(p) ((struct icmp6_hdr *)(p)) 86*3b3a8eb9SGleb Smirnoff 87*3b3a8eb9SGleb Smirnoff #define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0 88*3b3a8eb9SGleb Smirnoff #define SNP(buf) buf, sizeof(buf) 89*3b3a8eb9SGleb Smirnoff 90*3b3a8eb9SGleb Smirnoff #ifdef WITHOUT_BPF 91*3b3a8eb9SGleb Smirnoff void 92*3b3a8eb9SGleb Smirnoff ipfw_log_bpf(int onoff) 93*3b3a8eb9SGleb Smirnoff { 94*3b3a8eb9SGleb Smirnoff } 95*3b3a8eb9SGleb Smirnoff #else /* !WITHOUT_BPF */ 96*3b3a8eb9SGleb Smirnoff static struct ifnet *log_if; /* hook to attach to bpf */ 97*3b3a8eb9SGleb Smirnoff static struct rwlock log_if_lock; 98*3b3a8eb9SGleb Smirnoff #define LOGIF_LOCK_INIT(x) rw_init(&log_if_lock, "ipfw log_if lock") 99*3b3a8eb9SGleb Smirnoff #define LOGIF_LOCK_DESTROY(x) rw_destroy(&log_if_lock) 100*3b3a8eb9SGleb Smirnoff #define LOGIF_RLOCK(x) rw_rlock(&log_if_lock) 101*3b3a8eb9SGleb Smirnoff #define LOGIF_RUNLOCK(x) rw_runlock(&log_if_lock) 102*3b3a8eb9SGleb Smirnoff #define LOGIF_WLOCK(x) rw_wlock(&log_if_lock) 103*3b3a8eb9SGleb Smirnoff #define LOGIF_WUNLOCK(x) rw_wunlock(&log_if_lock) 104*3b3a8eb9SGleb Smirnoff 105*3b3a8eb9SGleb Smirnoff #define IPFWNAME "ipfw" 106*3b3a8eb9SGleb Smirnoff 107*3b3a8eb9SGleb Smirnoff /* we use this dummy function for all ifnet callbacks */ 108*3b3a8eb9SGleb Smirnoff static int 109*3b3a8eb9SGleb Smirnoff log_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr) 110*3b3a8eb9SGleb Smirnoff { 111*3b3a8eb9SGleb Smirnoff return EINVAL; 112*3b3a8eb9SGleb Smirnoff } 113*3b3a8eb9SGleb Smirnoff 114*3b3a8eb9SGleb Smirnoff static int 115*3b3a8eb9SGleb Smirnoff ipfw_log_output(struct ifnet *ifp, struct mbuf *m, 116*3b3a8eb9SGleb Smirnoff struct sockaddr *dst, struct route *ro) 117*3b3a8eb9SGleb Smirnoff { 118*3b3a8eb9SGleb Smirnoff if (m != NULL) 119*3b3a8eb9SGleb Smirnoff FREE_PKT(m); 120*3b3a8eb9SGleb Smirnoff return EINVAL; 121*3b3a8eb9SGleb Smirnoff } 122*3b3a8eb9SGleb Smirnoff 123*3b3a8eb9SGleb Smirnoff static void 124*3b3a8eb9SGleb Smirnoff ipfw_log_start(struct ifnet* ifp) 125*3b3a8eb9SGleb Smirnoff { 126*3b3a8eb9SGleb Smirnoff panic("ipfw_log_start() must not be called"); 127*3b3a8eb9SGleb Smirnoff } 128*3b3a8eb9SGleb Smirnoff 129*3b3a8eb9SGleb Smirnoff static const u_char ipfwbroadcastaddr[6] = 130*3b3a8eb9SGleb Smirnoff { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 131*3b3a8eb9SGleb Smirnoff 132*3b3a8eb9SGleb Smirnoff static int 133*3b3a8eb9SGleb Smirnoff ipfw_log_clone_match(struct if_clone *ifc, const char *name) 134*3b3a8eb9SGleb Smirnoff { 135*3b3a8eb9SGleb Smirnoff 136*3b3a8eb9SGleb Smirnoff return (strncmp(name, IPFWNAME, sizeof(IPFWNAME) - 1) == 0); 137*3b3a8eb9SGleb Smirnoff } 138*3b3a8eb9SGleb Smirnoff 139*3b3a8eb9SGleb Smirnoff static int 140*3b3a8eb9SGleb Smirnoff ipfw_log_clone_create(struct if_clone *ifc, char *name, size_t len, 141*3b3a8eb9SGleb Smirnoff caddr_t params) 142*3b3a8eb9SGleb Smirnoff { 143*3b3a8eb9SGleb Smirnoff int error; 144*3b3a8eb9SGleb Smirnoff int unit; 145*3b3a8eb9SGleb Smirnoff struct ifnet *ifp; 146*3b3a8eb9SGleb Smirnoff 147*3b3a8eb9SGleb Smirnoff error = ifc_name2unit(name, &unit); 148*3b3a8eb9SGleb Smirnoff if (error) 149*3b3a8eb9SGleb Smirnoff return (error); 150*3b3a8eb9SGleb Smirnoff 151*3b3a8eb9SGleb Smirnoff error = ifc_alloc_unit(ifc, &unit); 152*3b3a8eb9SGleb Smirnoff if (error) 153*3b3a8eb9SGleb Smirnoff return (error); 154*3b3a8eb9SGleb Smirnoff 155*3b3a8eb9SGleb Smirnoff ifp = if_alloc(IFT_PFLOG); 156*3b3a8eb9SGleb Smirnoff if (ifp == NULL) { 157*3b3a8eb9SGleb Smirnoff ifc_free_unit(ifc, unit); 158*3b3a8eb9SGleb Smirnoff return (ENOSPC); 159*3b3a8eb9SGleb Smirnoff } 160*3b3a8eb9SGleb Smirnoff ifp->if_dname = IPFWNAME; 161*3b3a8eb9SGleb Smirnoff ifp->if_dunit = unit; 162*3b3a8eb9SGleb Smirnoff snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", IPFWNAME, unit); 163*3b3a8eb9SGleb Smirnoff strlcpy(name, ifp->if_xname, len); 164*3b3a8eb9SGleb Smirnoff ifp->if_mtu = 65536; 165*3b3a8eb9SGleb Smirnoff ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST; 166*3b3a8eb9SGleb Smirnoff ifp->if_init = (void *)log_dummy; 167*3b3a8eb9SGleb Smirnoff ifp->if_ioctl = log_dummy; 168*3b3a8eb9SGleb Smirnoff ifp->if_start = ipfw_log_start; 169*3b3a8eb9SGleb Smirnoff ifp->if_output = ipfw_log_output; 170*3b3a8eb9SGleb Smirnoff ifp->if_addrlen = 6; 171*3b3a8eb9SGleb Smirnoff ifp->if_hdrlen = 14; 172*3b3a8eb9SGleb Smirnoff ifp->if_broadcastaddr = ipfwbroadcastaddr; 173*3b3a8eb9SGleb Smirnoff ifp->if_baudrate = IF_Mbps(10); 174*3b3a8eb9SGleb Smirnoff 175*3b3a8eb9SGleb Smirnoff LOGIF_WLOCK(); 176*3b3a8eb9SGleb Smirnoff if (log_if == NULL) 177*3b3a8eb9SGleb Smirnoff log_if = ifp; 178*3b3a8eb9SGleb Smirnoff else { 179*3b3a8eb9SGleb Smirnoff LOGIF_WUNLOCK(); 180*3b3a8eb9SGleb Smirnoff if_free(ifp); 181*3b3a8eb9SGleb Smirnoff ifc_free_unit(ifc, unit); 182*3b3a8eb9SGleb Smirnoff return (EEXIST); 183*3b3a8eb9SGleb Smirnoff } 184*3b3a8eb9SGleb Smirnoff LOGIF_WUNLOCK(); 185*3b3a8eb9SGleb Smirnoff if_attach(ifp); 186*3b3a8eb9SGleb Smirnoff bpfattach(ifp, DLT_EN10MB, 14); 187*3b3a8eb9SGleb Smirnoff 188*3b3a8eb9SGleb Smirnoff return (0); 189*3b3a8eb9SGleb Smirnoff } 190*3b3a8eb9SGleb Smirnoff 191*3b3a8eb9SGleb Smirnoff static int 192*3b3a8eb9SGleb Smirnoff ipfw_log_clone_destroy(struct if_clone *ifc, struct ifnet *ifp) 193*3b3a8eb9SGleb Smirnoff { 194*3b3a8eb9SGleb Smirnoff int unit; 195*3b3a8eb9SGleb Smirnoff 196*3b3a8eb9SGleb Smirnoff if (ifp == NULL) 197*3b3a8eb9SGleb Smirnoff return (0); 198*3b3a8eb9SGleb Smirnoff 199*3b3a8eb9SGleb Smirnoff LOGIF_WLOCK(); 200*3b3a8eb9SGleb Smirnoff if (log_if != NULL && ifp == log_if) 201*3b3a8eb9SGleb Smirnoff log_if = NULL; 202*3b3a8eb9SGleb Smirnoff else { 203*3b3a8eb9SGleb Smirnoff LOGIF_WUNLOCK(); 204*3b3a8eb9SGleb Smirnoff return (EINVAL); 205*3b3a8eb9SGleb Smirnoff } 206*3b3a8eb9SGleb Smirnoff LOGIF_WUNLOCK(); 207*3b3a8eb9SGleb Smirnoff 208*3b3a8eb9SGleb Smirnoff unit = ifp->if_dunit; 209*3b3a8eb9SGleb Smirnoff bpfdetach(ifp); 210*3b3a8eb9SGleb Smirnoff if_detach(ifp); 211*3b3a8eb9SGleb Smirnoff if_free(ifp); 212*3b3a8eb9SGleb Smirnoff ifc_free_unit(ifc, unit); 213*3b3a8eb9SGleb Smirnoff 214*3b3a8eb9SGleb Smirnoff return (0); 215*3b3a8eb9SGleb Smirnoff } 216*3b3a8eb9SGleb Smirnoff 217*3b3a8eb9SGleb Smirnoff static struct if_clone ipfw_log_cloner = IFC_CLONE_INITIALIZER( 218*3b3a8eb9SGleb Smirnoff IPFWNAME, NULL, IF_MAXUNIT, 219*3b3a8eb9SGleb Smirnoff NULL, ipfw_log_clone_match, ipfw_log_clone_create, ipfw_log_clone_destroy); 220*3b3a8eb9SGleb Smirnoff 221*3b3a8eb9SGleb Smirnoff void 222*3b3a8eb9SGleb Smirnoff ipfw_log_bpf(int onoff) 223*3b3a8eb9SGleb Smirnoff { 224*3b3a8eb9SGleb Smirnoff 225*3b3a8eb9SGleb Smirnoff if (onoff) { 226*3b3a8eb9SGleb Smirnoff LOGIF_LOCK_INIT(); 227*3b3a8eb9SGleb Smirnoff if_clone_attach(&ipfw_log_cloner); 228*3b3a8eb9SGleb Smirnoff } else { 229*3b3a8eb9SGleb Smirnoff if_clone_detach(&ipfw_log_cloner); 230*3b3a8eb9SGleb Smirnoff LOGIF_LOCK_DESTROY(); 231*3b3a8eb9SGleb Smirnoff } 232*3b3a8eb9SGleb Smirnoff } 233*3b3a8eb9SGleb Smirnoff #endif /* !WITHOUT_BPF */ 234*3b3a8eb9SGleb Smirnoff 235*3b3a8eb9SGleb Smirnoff /* 236*3b3a8eb9SGleb Smirnoff * We enter here when we have a rule with O_LOG. 237*3b3a8eb9SGleb Smirnoff * XXX this function alone takes about 2Kbytes of code! 238*3b3a8eb9SGleb Smirnoff */ 239*3b3a8eb9SGleb Smirnoff void 240*3b3a8eb9SGleb Smirnoff ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args, 241*3b3a8eb9SGleb Smirnoff struct mbuf *m, struct ifnet *oif, u_short offset, uint32_t tablearg, 242*3b3a8eb9SGleb Smirnoff struct ip *ip) 243*3b3a8eb9SGleb Smirnoff { 244*3b3a8eb9SGleb Smirnoff char *action; 245*3b3a8eb9SGleb Smirnoff int limit_reached = 0; 246*3b3a8eb9SGleb Smirnoff char action2[92], proto[128], fragment[32]; 247*3b3a8eb9SGleb Smirnoff 248*3b3a8eb9SGleb Smirnoff if (V_fw_verbose == 0) { 249*3b3a8eb9SGleb Smirnoff #ifndef WITHOUT_BPF 250*3b3a8eb9SGleb Smirnoff LOGIF_RLOCK(); 251*3b3a8eb9SGleb Smirnoff if (log_if == NULL || log_if->if_bpf == NULL) { 252*3b3a8eb9SGleb Smirnoff LOGIF_RUNLOCK(); 253*3b3a8eb9SGleb Smirnoff return; 254*3b3a8eb9SGleb Smirnoff } 255*3b3a8eb9SGleb Smirnoff 256*3b3a8eb9SGleb Smirnoff if (args->eh) /* layer2, use orig hdr */ 257*3b3a8eb9SGleb Smirnoff BPF_MTAP2(log_if, args->eh, ETHER_HDR_LEN, m); 258*3b3a8eb9SGleb Smirnoff else 259*3b3a8eb9SGleb Smirnoff /* Add fake header. Later we will store 260*3b3a8eb9SGleb Smirnoff * more info in the header. 261*3b3a8eb9SGleb Smirnoff */ 262*3b3a8eb9SGleb Smirnoff BPF_MTAP2(log_if, "DDDDDDSSSSSS\x08\x00", ETHER_HDR_LEN, m); 263*3b3a8eb9SGleb Smirnoff LOGIF_RUNLOCK(); 264*3b3a8eb9SGleb Smirnoff #endif /* !WITHOUT_BPF */ 265*3b3a8eb9SGleb Smirnoff return; 266*3b3a8eb9SGleb Smirnoff } 267*3b3a8eb9SGleb Smirnoff /* the old 'log' function */ 268*3b3a8eb9SGleb Smirnoff fragment[0] = '\0'; 269*3b3a8eb9SGleb Smirnoff proto[0] = '\0'; 270*3b3a8eb9SGleb Smirnoff 271*3b3a8eb9SGleb Smirnoff if (f == NULL) { /* bogus pkt */ 272*3b3a8eb9SGleb Smirnoff if (V_verbose_limit != 0 && V_norule_counter >= V_verbose_limit) 273*3b3a8eb9SGleb Smirnoff return; 274*3b3a8eb9SGleb Smirnoff V_norule_counter++; 275*3b3a8eb9SGleb Smirnoff if (V_norule_counter == V_verbose_limit) 276*3b3a8eb9SGleb Smirnoff limit_reached = V_verbose_limit; 277*3b3a8eb9SGleb Smirnoff action = "Refuse"; 278*3b3a8eb9SGleb Smirnoff } else { /* O_LOG is the first action, find the real one */ 279*3b3a8eb9SGleb Smirnoff ipfw_insn *cmd = ACTION_PTR(f); 280*3b3a8eb9SGleb Smirnoff ipfw_insn_log *l = (ipfw_insn_log *)cmd; 281*3b3a8eb9SGleb Smirnoff 282*3b3a8eb9SGleb Smirnoff if (l->max_log != 0 && l->log_left == 0) 283*3b3a8eb9SGleb Smirnoff return; 284*3b3a8eb9SGleb Smirnoff l->log_left--; 285*3b3a8eb9SGleb Smirnoff if (l->log_left == 0) 286*3b3a8eb9SGleb Smirnoff limit_reached = l->max_log; 287*3b3a8eb9SGleb Smirnoff cmd += F_LEN(cmd); /* point to first action */ 288*3b3a8eb9SGleb Smirnoff if (cmd->opcode == O_ALTQ) { 289*3b3a8eb9SGleb Smirnoff ipfw_insn_altq *altq = (ipfw_insn_altq *)cmd; 290*3b3a8eb9SGleb Smirnoff 291*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, 0), "Altq %d", 292*3b3a8eb9SGleb Smirnoff altq->qid); 293*3b3a8eb9SGleb Smirnoff cmd += F_LEN(cmd); 294*3b3a8eb9SGleb Smirnoff } 295*3b3a8eb9SGleb Smirnoff if (cmd->opcode == O_PROB) 296*3b3a8eb9SGleb Smirnoff cmd += F_LEN(cmd); 297*3b3a8eb9SGleb Smirnoff 298*3b3a8eb9SGleb Smirnoff if (cmd->opcode == O_TAG) 299*3b3a8eb9SGleb Smirnoff cmd += F_LEN(cmd); 300*3b3a8eb9SGleb Smirnoff 301*3b3a8eb9SGleb Smirnoff action = action2; 302*3b3a8eb9SGleb Smirnoff switch (cmd->opcode) { 303*3b3a8eb9SGleb Smirnoff case O_DENY: 304*3b3a8eb9SGleb Smirnoff action = "Deny"; 305*3b3a8eb9SGleb Smirnoff break; 306*3b3a8eb9SGleb Smirnoff 307*3b3a8eb9SGleb Smirnoff case O_REJECT: 308*3b3a8eb9SGleb Smirnoff if (cmd->arg1==ICMP_REJECT_RST) 309*3b3a8eb9SGleb Smirnoff action = "Reset"; 310*3b3a8eb9SGleb Smirnoff else if (cmd->arg1==ICMP_UNREACH_HOST) 311*3b3a8eb9SGleb Smirnoff action = "Reject"; 312*3b3a8eb9SGleb Smirnoff else 313*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, 0), "Unreach %d", 314*3b3a8eb9SGleb Smirnoff cmd->arg1); 315*3b3a8eb9SGleb Smirnoff break; 316*3b3a8eb9SGleb Smirnoff 317*3b3a8eb9SGleb Smirnoff case O_UNREACH6: 318*3b3a8eb9SGleb Smirnoff if (cmd->arg1==ICMP6_UNREACH_RST) 319*3b3a8eb9SGleb Smirnoff action = "Reset"; 320*3b3a8eb9SGleb Smirnoff else 321*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, 0), "Unreach %d", 322*3b3a8eb9SGleb Smirnoff cmd->arg1); 323*3b3a8eb9SGleb Smirnoff break; 324*3b3a8eb9SGleb Smirnoff 325*3b3a8eb9SGleb Smirnoff case O_ACCEPT: 326*3b3a8eb9SGleb Smirnoff action = "Accept"; 327*3b3a8eb9SGleb Smirnoff break; 328*3b3a8eb9SGleb Smirnoff case O_COUNT: 329*3b3a8eb9SGleb Smirnoff action = "Count"; 330*3b3a8eb9SGleb Smirnoff break; 331*3b3a8eb9SGleb Smirnoff case O_DIVERT: 332*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, 0), "Divert %d", 333*3b3a8eb9SGleb Smirnoff cmd->arg1); 334*3b3a8eb9SGleb Smirnoff break; 335*3b3a8eb9SGleb Smirnoff case O_TEE: 336*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, 0), "Tee %d", 337*3b3a8eb9SGleb Smirnoff cmd->arg1); 338*3b3a8eb9SGleb Smirnoff break; 339*3b3a8eb9SGleb Smirnoff case O_SETFIB: 340*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, 0), "SetFib %d", 341*3b3a8eb9SGleb Smirnoff cmd->arg1); 342*3b3a8eb9SGleb Smirnoff break; 343*3b3a8eb9SGleb Smirnoff case O_SKIPTO: 344*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, 0), "SkipTo %d", 345*3b3a8eb9SGleb Smirnoff cmd->arg1); 346*3b3a8eb9SGleb Smirnoff break; 347*3b3a8eb9SGleb Smirnoff case O_PIPE: 348*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, 0), "Pipe %d", 349*3b3a8eb9SGleb Smirnoff cmd->arg1); 350*3b3a8eb9SGleb Smirnoff break; 351*3b3a8eb9SGleb Smirnoff case O_QUEUE: 352*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, 0), "Queue %d", 353*3b3a8eb9SGleb Smirnoff cmd->arg1); 354*3b3a8eb9SGleb Smirnoff break; 355*3b3a8eb9SGleb Smirnoff case O_FORWARD_IP: { 356*3b3a8eb9SGleb Smirnoff ipfw_insn_sa *sa = (ipfw_insn_sa *)cmd; 357*3b3a8eb9SGleb Smirnoff int len; 358*3b3a8eb9SGleb Smirnoff struct in_addr dummyaddr; 359*3b3a8eb9SGleb Smirnoff if (sa->sa.sin_addr.s_addr == INADDR_ANY) 360*3b3a8eb9SGleb Smirnoff dummyaddr.s_addr = htonl(tablearg); 361*3b3a8eb9SGleb Smirnoff else 362*3b3a8eb9SGleb Smirnoff dummyaddr.s_addr = sa->sa.sin_addr.s_addr; 363*3b3a8eb9SGleb Smirnoff 364*3b3a8eb9SGleb Smirnoff len = snprintf(SNPARGS(action2, 0), "Forward to %s", 365*3b3a8eb9SGleb Smirnoff inet_ntoa(dummyaddr)); 366*3b3a8eb9SGleb Smirnoff 367*3b3a8eb9SGleb Smirnoff if (sa->sa.sin_port) 368*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, len), ":%d", 369*3b3a8eb9SGleb Smirnoff sa->sa.sin_port); 370*3b3a8eb9SGleb Smirnoff } 371*3b3a8eb9SGleb Smirnoff break; 372*3b3a8eb9SGleb Smirnoff #ifdef INET6 373*3b3a8eb9SGleb Smirnoff case O_FORWARD_IP6: { 374*3b3a8eb9SGleb Smirnoff char buf[INET6_ADDRSTRLEN]; 375*3b3a8eb9SGleb Smirnoff ipfw_insn_sa6 *sa = (ipfw_insn_sa6 *)cmd; 376*3b3a8eb9SGleb Smirnoff int len; 377*3b3a8eb9SGleb Smirnoff 378*3b3a8eb9SGleb Smirnoff len = snprintf(SNPARGS(action2, 0), "Forward to [%s]", 379*3b3a8eb9SGleb Smirnoff ip6_sprintf(buf, &sa->sa.sin6_addr)); 380*3b3a8eb9SGleb Smirnoff 381*3b3a8eb9SGleb Smirnoff if (sa->sa.sin6_port) 382*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, len), ":%u", 383*3b3a8eb9SGleb Smirnoff sa->sa.sin6_port); 384*3b3a8eb9SGleb Smirnoff } 385*3b3a8eb9SGleb Smirnoff break; 386*3b3a8eb9SGleb Smirnoff #endif 387*3b3a8eb9SGleb Smirnoff case O_NETGRAPH: 388*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, 0), "Netgraph %d", 389*3b3a8eb9SGleb Smirnoff cmd->arg1); 390*3b3a8eb9SGleb Smirnoff break; 391*3b3a8eb9SGleb Smirnoff case O_NGTEE: 392*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, 0), "Ngtee %d", 393*3b3a8eb9SGleb Smirnoff cmd->arg1); 394*3b3a8eb9SGleb Smirnoff break; 395*3b3a8eb9SGleb Smirnoff case O_NAT: 396*3b3a8eb9SGleb Smirnoff action = "Nat"; 397*3b3a8eb9SGleb Smirnoff break; 398*3b3a8eb9SGleb Smirnoff case O_REASS: 399*3b3a8eb9SGleb Smirnoff action = "Reass"; 400*3b3a8eb9SGleb Smirnoff break; 401*3b3a8eb9SGleb Smirnoff case O_CALLRETURN: 402*3b3a8eb9SGleb Smirnoff if (cmd->len & F_NOT) 403*3b3a8eb9SGleb Smirnoff action = "Return"; 404*3b3a8eb9SGleb Smirnoff else 405*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(action2, 0), "Call %d", 406*3b3a8eb9SGleb Smirnoff cmd->arg1); 407*3b3a8eb9SGleb Smirnoff break; 408*3b3a8eb9SGleb Smirnoff default: 409*3b3a8eb9SGleb Smirnoff action = "UNKNOWN"; 410*3b3a8eb9SGleb Smirnoff break; 411*3b3a8eb9SGleb Smirnoff } 412*3b3a8eb9SGleb Smirnoff } 413*3b3a8eb9SGleb Smirnoff 414*3b3a8eb9SGleb Smirnoff if (hlen == 0) { /* non-ip */ 415*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(proto, 0), "MAC"); 416*3b3a8eb9SGleb Smirnoff 417*3b3a8eb9SGleb Smirnoff } else { 418*3b3a8eb9SGleb Smirnoff int len; 419*3b3a8eb9SGleb Smirnoff #ifdef INET6 420*3b3a8eb9SGleb Smirnoff char src[INET6_ADDRSTRLEN + 2], dst[INET6_ADDRSTRLEN + 2]; 421*3b3a8eb9SGleb Smirnoff #else 422*3b3a8eb9SGleb Smirnoff char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN]; 423*3b3a8eb9SGleb Smirnoff #endif 424*3b3a8eb9SGleb Smirnoff struct icmphdr *icmp; 425*3b3a8eb9SGleb Smirnoff struct tcphdr *tcp; 426*3b3a8eb9SGleb Smirnoff struct udphdr *udp; 427*3b3a8eb9SGleb Smirnoff #ifdef INET6 428*3b3a8eb9SGleb Smirnoff struct ip6_hdr *ip6 = NULL; 429*3b3a8eb9SGleb Smirnoff struct icmp6_hdr *icmp6; 430*3b3a8eb9SGleb Smirnoff u_short ip6f_mf; 431*3b3a8eb9SGleb Smirnoff #endif 432*3b3a8eb9SGleb Smirnoff src[0] = '\0'; 433*3b3a8eb9SGleb Smirnoff dst[0] = '\0'; 434*3b3a8eb9SGleb Smirnoff #ifdef INET6 435*3b3a8eb9SGleb Smirnoff ip6f_mf = offset & IP6F_MORE_FRAG; 436*3b3a8eb9SGleb Smirnoff offset &= IP6F_OFF_MASK; 437*3b3a8eb9SGleb Smirnoff 438*3b3a8eb9SGleb Smirnoff if (IS_IP6_FLOW_ID(&(args->f_id))) { 439*3b3a8eb9SGleb Smirnoff char ip6buf[INET6_ADDRSTRLEN]; 440*3b3a8eb9SGleb Smirnoff snprintf(src, sizeof(src), "[%s]", 441*3b3a8eb9SGleb Smirnoff ip6_sprintf(ip6buf, &args->f_id.src_ip6)); 442*3b3a8eb9SGleb Smirnoff snprintf(dst, sizeof(dst), "[%s]", 443*3b3a8eb9SGleb Smirnoff ip6_sprintf(ip6buf, &args->f_id.dst_ip6)); 444*3b3a8eb9SGleb Smirnoff 445*3b3a8eb9SGleb Smirnoff ip6 = (struct ip6_hdr *)ip; 446*3b3a8eb9SGleb Smirnoff tcp = (struct tcphdr *)(((char *)ip) + hlen); 447*3b3a8eb9SGleb Smirnoff udp = (struct udphdr *)(((char *)ip) + hlen); 448*3b3a8eb9SGleb Smirnoff } else 449*3b3a8eb9SGleb Smirnoff #endif 450*3b3a8eb9SGleb Smirnoff { 451*3b3a8eb9SGleb Smirnoff tcp = L3HDR(struct tcphdr, ip); 452*3b3a8eb9SGleb Smirnoff udp = L3HDR(struct udphdr, ip); 453*3b3a8eb9SGleb Smirnoff 454*3b3a8eb9SGleb Smirnoff inet_ntop(AF_INET, &ip->ip_src, src, sizeof(src)); 455*3b3a8eb9SGleb Smirnoff inet_ntop(AF_INET, &ip->ip_dst, dst, sizeof(dst)); 456*3b3a8eb9SGleb Smirnoff } 457*3b3a8eb9SGleb Smirnoff 458*3b3a8eb9SGleb Smirnoff switch (args->f_id.proto) { 459*3b3a8eb9SGleb Smirnoff case IPPROTO_TCP: 460*3b3a8eb9SGleb Smirnoff len = snprintf(SNPARGS(proto, 0), "TCP %s", src); 461*3b3a8eb9SGleb Smirnoff if (offset == 0) 462*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(proto, len), ":%d %s:%d", 463*3b3a8eb9SGleb Smirnoff ntohs(tcp->th_sport), 464*3b3a8eb9SGleb Smirnoff dst, 465*3b3a8eb9SGleb Smirnoff ntohs(tcp->th_dport)); 466*3b3a8eb9SGleb Smirnoff else 467*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(proto, len), " %s", dst); 468*3b3a8eb9SGleb Smirnoff break; 469*3b3a8eb9SGleb Smirnoff 470*3b3a8eb9SGleb Smirnoff case IPPROTO_UDP: 471*3b3a8eb9SGleb Smirnoff len = snprintf(SNPARGS(proto, 0), "UDP %s", src); 472*3b3a8eb9SGleb Smirnoff if (offset == 0) 473*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(proto, len), ":%d %s:%d", 474*3b3a8eb9SGleb Smirnoff ntohs(udp->uh_sport), 475*3b3a8eb9SGleb Smirnoff dst, 476*3b3a8eb9SGleb Smirnoff ntohs(udp->uh_dport)); 477*3b3a8eb9SGleb Smirnoff else 478*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(proto, len), " %s", dst); 479*3b3a8eb9SGleb Smirnoff break; 480*3b3a8eb9SGleb Smirnoff 481*3b3a8eb9SGleb Smirnoff case IPPROTO_ICMP: 482*3b3a8eb9SGleb Smirnoff icmp = L3HDR(struct icmphdr, ip); 483*3b3a8eb9SGleb Smirnoff if (offset == 0) 484*3b3a8eb9SGleb Smirnoff len = snprintf(SNPARGS(proto, 0), 485*3b3a8eb9SGleb Smirnoff "ICMP:%u.%u ", 486*3b3a8eb9SGleb Smirnoff icmp->icmp_type, icmp->icmp_code); 487*3b3a8eb9SGleb Smirnoff else 488*3b3a8eb9SGleb Smirnoff len = snprintf(SNPARGS(proto, 0), "ICMP "); 489*3b3a8eb9SGleb Smirnoff len += snprintf(SNPARGS(proto, len), "%s", src); 490*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(proto, len), " %s", dst); 491*3b3a8eb9SGleb Smirnoff break; 492*3b3a8eb9SGleb Smirnoff #ifdef INET6 493*3b3a8eb9SGleb Smirnoff case IPPROTO_ICMPV6: 494*3b3a8eb9SGleb Smirnoff icmp6 = (struct icmp6_hdr *)(((char *)ip) + hlen); 495*3b3a8eb9SGleb Smirnoff if (offset == 0) 496*3b3a8eb9SGleb Smirnoff len = snprintf(SNPARGS(proto, 0), 497*3b3a8eb9SGleb Smirnoff "ICMPv6:%u.%u ", 498*3b3a8eb9SGleb Smirnoff icmp6->icmp6_type, icmp6->icmp6_code); 499*3b3a8eb9SGleb Smirnoff else 500*3b3a8eb9SGleb Smirnoff len = snprintf(SNPARGS(proto, 0), "ICMPv6 "); 501*3b3a8eb9SGleb Smirnoff len += snprintf(SNPARGS(proto, len), "%s", src); 502*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(proto, len), " %s", dst); 503*3b3a8eb9SGleb Smirnoff break; 504*3b3a8eb9SGleb Smirnoff #endif 505*3b3a8eb9SGleb Smirnoff default: 506*3b3a8eb9SGleb Smirnoff len = snprintf(SNPARGS(proto, 0), "P:%d %s", 507*3b3a8eb9SGleb Smirnoff args->f_id.proto, src); 508*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(proto, len), " %s", dst); 509*3b3a8eb9SGleb Smirnoff break; 510*3b3a8eb9SGleb Smirnoff } 511*3b3a8eb9SGleb Smirnoff 512*3b3a8eb9SGleb Smirnoff #ifdef INET6 513*3b3a8eb9SGleb Smirnoff if (IS_IP6_FLOW_ID(&(args->f_id))) { 514*3b3a8eb9SGleb Smirnoff if (offset & (IP6F_OFF_MASK | IP6F_MORE_FRAG)) 515*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(fragment, 0), 516*3b3a8eb9SGleb Smirnoff " (frag %08x:%d@%d%s)", 517*3b3a8eb9SGleb Smirnoff args->f_id.extra, 518*3b3a8eb9SGleb Smirnoff ntohs(ip6->ip6_plen) - hlen, 519*3b3a8eb9SGleb Smirnoff ntohs(offset) << 3, ip6f_mf ? "+" : ""); 520*3b3a8eb9SGleb Smirnoff } else 521*3b3a8eb9SGleb Smirnoff #endif 522*3b3a8eb9SGleb Smirnoff { 523*3b3a8eb9SGleb Smirnoff int ipoff, iplen; 524*3b3a8eb9SGleb Smirnoff ipoff = ntohs(ip->ip_off); 525*3b3a8eb9SGleb Smirnoff iplen = ntohs(ip->ip_len); 526*3b3a8eb9SGleb Smirnoff if (ipoff & (IP_MF | IP_OFFMASK)) 527*3b3a8eb9SGleb Smirnoff snprintf(SNPARGS(fragment, 0), 528*3b3a8eb9SGleb Smirnoff " (frag %d:%d@%d%s)", 529*3b3a8eb9SGleb Smirnoff ntohs(ip->ip_id), iplen - (ip->ip_hl << 2), 530*3b3a8eb9SGleb Smirnoff offset << 3, 531*3b3a8eb9SGleb Smirnoff (ipoff & IP_MF) ? "+" : ""); 532*3b3a8eb9SGleb Smirnoff } 533*3b3a8eb9SGleb Smirnoff } 534*3b3a8eb9SGleb Smirnoff #ifdef __FreeBSD__ 535*3b3a8eb9SGleb Smirnoff if (oif || m->m_pkthdr.rcvif) 536*3b3a8eb9SGleb Smirnoff log(LOG_SECURITY | LOG_INFO, 537*3b3a8eb9SGleb Smirnoff "ipfw: %d %s %s %s via %s%s\n", 538*3b3a8eb9SGleb Smirnoff f ? f->rulenum : -1, 539*3b3a8eb9SGleb Smirnoff action, proto, oif ? "out" : "in", 540*3b3a8eb9SGleb Smirnoff oif ? oif->if_xname : m->m_pkthdr.rcvif->if_xname, 541*3b3a8eb9SGleb Smirnoff fragment); 542*3b3a8eb9SGleb Smirnoff else 543*3b3a8eb9SGleb Smirnoff #endif 544*3b3a8eb9SGleb Smirnoff log(LOG_SECURITY | LOG_INFO, 545*3b3a8eb9SGleb Smirnoff "ipfw: %d %s %s [no if info]%s\n", 546*3b3a8eb9SGleb Smirnoff f ? f->rulenum : -1, 547*3b3a8eb9SGleb Smirnoff action, proto, fragment); 548*3b3a8eb9SGleb Smirnoff if (limit_reached) 549*3b3a8eb9SGleb Smirnoff log(LOG_SECURITY | LOG_NOTICE, 550*3b3a8eb9SGleb Smirnoff "ipfw: limit %d reached on entry %d\n", 551*3b3a8eb9SGleb Smirnoff limit_reached, f ? f->rulenum : -1); 552*3b3a8eb9SGleb Smirnoff } 553*3b3a8eb9SGleb Smirnoff /* end of file */ 554