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