ip_fw_log.c revision 201527
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/netinet/ipfw/ip_fw_log.c 201527 2010-01-04 19:01:22Z luigi $"); 28 29/* 30 * Logging support for ipfw 31 */ 32 33#if !defined(KLD_MODULE) 34#include "opt_ipfw.h" 35#include "opt_ipdivert.h" 36#include "opt_ipdn.h" 37#include "opt_inet.h" 38#ifndef INET 39#error IPFIREWALL requires INET. 40#endif /* INET */ 41#endif 42#include "opt_inet6.h" 43#include "opt_ipsec.h" 44 45#include <sys/param.h> 46#include <sys/systm.h> 47#include <sys/mbuf.h> 48#include <sys/kernel.h> 49#include <sys/socket.h> 50#include <sys/sysctl.h> 51#include <sys/syslog.h> 52#include <net/ethernet.h> /* for ETHERTYPE_IP */ 53#include <net/if.h> 54#include <net/vnet.h> 55#include <net/if_types.h> /* for IFT_ETHER */ 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_fw.h> 62#include <netinet/ipfw/ip_fw_private.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#ifdef MAC 73#include <security/mac/mac_framework.h> 74#endif 75 76/* 77 * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T 78 * Other macros just cast void * into the appropriate type 79 */ 80#define L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl)) 81#define TCP(p) ((struct tcphdr *)(p)) 82#define SCTP(p) ((struct sctphdr *)(p)) 83#define UDP(p) ((struct udphdr *)(p)) 84#define ICMP(p) ((struct icmphdr *)(p)) 85#define ICMP6(p) ((struct icmp6_hdr *)(p)) 86 87#define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0 88#define SNP(buf) buf, sizeof(buf) 89 90#ifdef WITHOUT_BPF 91void 92ipfw_log_bpf(int onoff) 93{ 94} 95#else /* !WITHOUT_BPF */ 96static struct ifnet *log_if; /* hook to attach to bpf */ 97 98/* we use this dummy function for all ifnet callbacks */ 99static int 100log_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr) 101{ 102 return EINVAL; 103} 104 105void 106ipfw_log_bpf(int onoff) 107{ 108 struct ifnet *ifp; 109 110 if (onoff) { 111 if (log_if) 112 return; 113 ifp = if_alloc(IFT_ETHER); 114 if (ifp == NULL) 115 return; 116 if_initname(ifp, "ipfw", 0); 117 ifp->if_mtu = 65536; 118 ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST; 119 ifp->if_init = (void *)log_dummy; 120 ifp->if_ioctl = log_dummy; 121 ifp->if_start = (void *)log_dummy; 122 ifp->if_output = (void *)log_dummy; 123 ifp->if_addrlen = 6; 124 ifp->if_hdrlen = 14; 125 if_attach(ifp); 126 ifp->if_baudrate = IF_Mbps(10); 127 bpfattach(ifp, DLT_EN10MB, 14); 128 log_if = ifp; 129 } else { 130 if (log_if) { 131 ether_ifdetach(log_if); 132 if_free(log_if); 133 } 134 log_if = NULL; 135 } 136} 137#endif /* !WITHOUT_BPF */ 138 139/* 140 * We enter here when we have a rule with O_LOG. 141 * XXX this function alone takes about 2Kbytes of code! 142 */ 143void 144ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args, 145 struct mbuf *m, struct ifnet *oif, u_short offset, uint32_t tablearg, 146 struct ip *ip) 147{ 148 char *action; 149 int limit_reached = 0; 150 char action2[40], proto[128], fragment[32]; 151 152 if (V_fw_verbose == 0) { 153#ifndef WITHOUT_BPF 154 struct m_hdr mh; 155 156 if (log_if == NULL || log_if->if_bpf == NULL) 157 return; 158 /* BPF treats the "mbuf" as read-only */ 159 mh.mh_next = m; 160 mh.mh_len = ETHER_HDR_LEN; 161 if (args->eh) { /* layer2, use orig hdr */ 162 mh.mh_data = (char *)args->eh; 163 } else { 164 /* add fake header. Later we will store 165 * more info in the header 166 */ 167 mh.mh_data = "DDDDDDSSSSSS\x08\x00"; 168 } 169 BPF_MTAP(log_if, (struct mbuf *)&mh); 170#endif /* !WITHOUT_BPF */ 171 return; 172 } 173 /* the old 'log' function */ 174 fragment[0] = '\0'; 175 proto[0] = '\0'; 176 177 if (f == NULL) { /* bogus pkt */ 178 if (V_verbose_limit != 0 && V_norule_counter >= V_verbose_limit) 179 return; 180 V_norule_counter++; 181 if (V_norule_counter == V_verbose_limit) 182 limit_reached = V_verbose_limit; 183 action = "Refuse"; 184 } else { /* O_LOG is the first action, find the real one */ 185 ipfw_insn *cmd = ACTION_PTR(f); 186 ipfw_insn_log *l = (ipfw_insn_log *)cmd; 187 188 if (l->max_log != 0 && l->log_left == 0) 189 return; 190 l->log_left--; 191 if (l->log_left == 0) 192 limit_reached = l->max_log; 193 cmd += F_LEN(cmd); /* point to first action */ 194 if (cmd->opcode == O_ALTQ) { 195 ipfw_insn_altq *altq = (ipfw_insn_altq *)cmd; 196 197 snprintf(SNPARGS(action2, 0), "Altq %d", 198 altq->qid); 199 cmd += F_LEN(cmd); 200 } 201 if (cmd->opcode == O_PROB) 202 cmd += F_LEN(cmd); 203 204 if (cmd->opcode == O_TAG) 205 cmd += F_LEN(cmd); 206 207 action = action2; 208 switch (cmd->opcode) { 209 case O_DENY: 210 action = "Deny"; 211 break; 212 213 case O_REJECT: 214 if (cmd->arg1==ICMP_REJECT_RST) 215 action = "Reset"; 216 else if (cmd->arg1==ICMP_UNREACH_HOST) 217 action = "Reject"; 218 else 219 snprintf(SNPARGS(action2, 0), "Unreach %d", 220 cmd->arg1); 221 break; 222 223 case O_UNREACH6: 224 if (cmd->arg1==ICMP6_UNREACH_RST) 225 action = "Reset"; 226 else 227 snprintf(SNPARGS(action2, 0), "Unreach %d", 228 cmd->arg1); 229 break; 230 231 case O_ACCEPT: 232 action = "Accept"; 233 break; 234 case O_COUNT: 235 action = "Count"; 236 break; 237 case O_DIVERT: 238 snprintf(SNPARGS(action2, 0), "Divert %d", 239 cmd->arg1); 240 break; 241 case O_TEE: 242 snprintf(SNPARGS(action2, 0), "Tee %d", 243 cmd->arg1); 244 break; 245 case O_SETFIB: 246 snprintf(SNPARGS(action2, 0), "SetFib %d", 247 cmd->arg1); 248 break; 249 case O_SKIPTO: 250 snprintf(SNPARGS(action2, 0), "SkipTo %d", 251 cmd->arg1); 252 break; 253 case O_PIPE: 254 snprintf(SNPARGS(action2, 0), "Pipe %d", 255 cmd->arg1); 256 break; 257 case O_QUEUE: 258 snprintf(SNPARGS(action2, 0), "Queue %d", 259 cmd->arg1); 260 break; 261 case O_FORWARD_IP: { 262 ipfw_insn_sa *sa = (ipfw_insn_sa *)cmd; 263 int len; 264 struct in_addr dummyaddr; 265 if (sa->sa.sin_addr.s_addr == INADDR_ANY) 266 dummyaddr.s_addr = htonl(tablearg); 267 else 268 dummyaddr.s_addr = sa->sa.sin_addr.s_addr; 269 270 len = snprintf(SNPARGS(action2, 0), "Forward to %s", 271 inet_ntoa(dummyaddr)); 272 273 if (sa->sa.sin_port) 274 snprintf(SNPARGS(action2, len), ":%d", 275 sa->sa.sin_port); 276 } 277 break; 278 case O_NETGRAPH: 279 snprintf(SNPARGS(action2, 0), "Netgraph %d", 280 cmd->arg1); 281 break; 282 case O_NGTEE: 283 snprintf(SNPARGS(action2, 0), "Ngtee %d", 284 cmd->arg1); 285 break; 286 case O_NAT: 287 action = "Nat"; 288 break; 289 case O_REASS: 290 action = "Reass"; 291 break; 292 default: 293 action = "UNKNOWN"; 294 break; 295 } 296 } 297 298 if (hlen == 0) { /* non-ip */ 299 snprintf(SNPARGS(proto, 0), "MAC"); 300 301 } else { 302 int len; 303#ifdef INET6 304 char src[INET6_ADDRSTRLEN + 2], dst[INET6_ADDRSTRLEN + 2]; 305#else 306 char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN]; 307#endif 308 struct icmphdr *icmp; 309 struct tcphdr *tcp; 310 struct udphdr *udp; 311#ifdef INET6 312 struct ip6_hdr *ip6 = NULL; 313 struct icmp6_hdr *icmp6; 314#endif 315 src[0] = '\0'; 316 dst[0] = '\0'; 317#ifdef INET6 318 if (IS_IP6_FLOW_ID(&(args->f_id))) { 319 char ip6buf[INET6_ADDRSTRLEN]; 320 snprintf(src, sizeof(src), "[%s]", 321 ip6_sprintf(ip6buf, &args->f_id.src_ip6)); 322 snprintf(dst, sizeof(dst), "[%s]", 323 ip6_sprintf(ip6buf, &args->f_id.dst_ip6)); 324 325 ip6 = (struct ip6_hdr *)ip; 326 tcp = (struct tcphdr *)(((char *)ip) + hlen); 327 udp = (struct udphdr *)(((char *)ip) + hlen); 328 } else 329#endif 330 { 331 tcp = L3HDR(struct tcphdr, ip); 332 udp = L3HDR(struct udphdr, ip); 333 334 inet_ntoa_r(ip->ip_src, src); 335 inet_ntoa_r(ip->ip_dst, dst); 336 } 337 338 switch (args->f_id.proto) { 339 case IPPROTO_TCP: 340 len = snprintf(SNPARGS(proto, 0), "TCP %s", src); 341 if (offset == 0) 342 snprintf(SNPARGS(proto, len), ":%d %s:%d", 343 ntohs(tcp->th_sport), 344 dst, 345 ntohs(tcp->th_dport)); 346 else 347 snprintf(SNPARGS(proto, len), " %s", dst); 348 break; 349 350 case IPPROTO_UDP: 351 len = snprintf(SNPARGS(proto, 0), "UDP %s", src); 352 if (offset == 0) 353 snprintf(SNPARGS(proto, len), ":%d %s:%d", 354 ntohs(udp->uh_sport), 355 dst, 356 ntohs(udp->uh_dport)); 357 else 358 snprintf(SNPARGS(proto, len), " %s", dst); 359 break; 360 361 case IPPROTO_ICMP: 362 icmp = L3HDR(struct icmphdr, ip); 363 if (offset == 0) 364 len = snprintf(SNPARGS(proto, 0), 365 "ICMP:%u.%u ", 366 icmp->icmp_type, icmp->icmp_code); 367 else 368 len = snprintf(SNPARGS(proto, 0), "ICMP "); 369 len += snprintf(SNPARGS(proto, len), "%s", src); 370 snprintf(SNPARGS(proto, len), " %s", dst); 371 break; 372#ifdef INET6 373 case IPPROTO_ICMPV6: 374 icmp6 = (struct icmp6_hdr *)(((char *)ip) + hlen); 375 if (offset == 0) 376 len = snprintf(SNPARGS(proto, 0), 377 "ICMPv6:%u.%u ", 378 icmp6->icmp6_type, icmp6->icmp6_code); 379 else 380 len = snprintf(SNPARGS(proto, 0), "ICMPv6 "); 381 len += snprintf(SNPARGS(proto, len), "%s", src); 382 snprintf(SNPARGS(proto, len), " %s", dst); 383 break; 384#endif 385 default: 386 len = snprintf(SNPARGS(proto, 0), "P:%d %s", 387 args->f_id.proto, src); 388 snprintf(SNPARGS(proto, len), " %s", dst); 389 break; 390 } 391 392#ifdef INET6 393 if (IS_IP6_FLOW_ID(&(args->f_id))) { 394 if (offset & (IP6F_OFF_MASK | IP6F_MORE_FRAG)) 395 snprintf(SNPARGS(fragment, 0), 396 " (frag %08x:%d@%d%s)", 397 args->f_id.frag_id6, 398 ntohs(ip6->ip6_plen) - hlen, 399 ntohs(offset & IP6F_OFF_MASK) << 3, 400 (offset & IP6F_MORE_FRAG) ? "+" : ""); 401 } else 402#endif 403 { 404 int ipoff, iplen; 405 ipoff = ntohs(ip->ip_off); 406 iplen = ntohs(ip->ip_len); 407 if (ipoff & (IP_MF | IP_OFFMASK)) 408 snprintf(SNPARGS(fragment, 0), 409 " (frag %d:%d@%d%s)", 410 ntohs(ip->ip_id), iplen - (ip->ip_hl << 2), 411 offset << 3, 412 (ipoff & IP_MF) ? "+" : ""); 413 } 414 } 415 if (oif || m->m_pkthdr.rcvif) 416 log(LOG_SECURITY | LOG_INFO, 417 "ipfw: %d %s %s %s via %s%s\n", 418 f ? f->rulenum : -1, 419 action, proto, oif ? "out" : "in", 420 oif ? oif->if_xname : m->m_pkthdr.rcvif->if_xname, 421 fragment); 422 else 423 log(LOG_SECURITY | LOG_INFO, 424 "ipfw: %d %s %s [no if info]%s\n", 425 f ? f->rulenum : -1, 426 action, proto, fragment); 427 if (limit_reached) 428 log(LOG_SECURITY | LOG_NOTICE, 429 "ipfw: limit %d reached on entry %d\n", 430 limit_reached, f ? f->rulenum : -1); 431} 432/* end of file */ 433