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