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