xref: /freebsd/sys/netpfil/ipfw/ip_fw_log.c (revision 3b3a8eb937bf8045231e8364bfd1b94cd4a95979)
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