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 #define 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 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 = IFC_CLONE_INITIALIZER( 218 IPFWNAME, NULL, IF_MAXUNIT, 219 NULL, ipfw_log_clone_match, ipfw_log_clone_create, ipfw_log_clone_destroy); 220 221 void 222 ipfw_log_bpf(int onoff) 223 { 224 225 if (onoff) { 226 LOGIF_LOCK_INIT(); 227 if_clone_attach(&ipfw_log_cloner); 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) 296 cmd += F_LEN(cmd); 297 298 if (cmd->opcode == O_TAG) 299 cmd += F_LEN(cmd); 300 301 action = action2; 302 switch (cmd->opcode) { 303 case O_DENY: 304 action = "Deny"; 305 break; 306 307 case O_REJECT: 308 if (cmd->arg1==ICMP_REJECT_RST) 309 action = "Reset"; 310 else if (cmd->arg1==ICMP_UNREACH_HOST) 311 action = "Reject"; 312 else 313 snprintf(SNPARGS(action2, 0), "Unreach %d", 314 cmd->arg1); 315 break; 316 317 case O_UNREACH6: 318 if (cmd->arg1==ICMP6_UNREACH_RST) 319 action = "Reset"; 320 else 321 snprintf(SNPARGS(action2, 0), "Unreach %d", 322 cmd->arg1); 323 break; 324 325 case O_ACCEPT: 326 action = "Accept"; 327 break; 328 case O_COUNT: 329 action = "Count"; 330 break; 331 case O_DIVERT: 332 snprintf(SNPARGS(action2, 0), "Divert %d", 333 cmd->arg1); 334 break; 335 case O_TEE: 336 snprintf(SNPARGS(action2, 0), "Tee %d", 337 cmd->arg1); 338 break; 339 case O_SETFIB: 340 snprintf(SNPARGS(action2, 0), "SetFib %d", 341 cmd->arg1); 342 break; 343 case O_SKIPTO: 344 snprintf(SNPARGS(action2, 0), "SkipTo %d", 345 cmd->arg1); 346 break; 347 case O_PIPE: 348 snprintf(SNPARGS(action2, 0), "Pipe %d", 349 cmd->arg1); 350 break; 351 case O_QUEUE: 352 snprintf(SNPARGS(action2, 0), "Queue %d", 353 cmd->arg1); 354 break; 355 case O_FORWARD_IP: { 356 ipfw_insn_sa *sa = (ipfw_insn_sa *)cmd; 357 int len; 358 struct in_addr dummyaddr; 359 if (sa->sa.sin_addr.s_addr == INADDR_ANY) 360 dummyaddr.s_addr = htonl(tablearg); 361 else 362 dummyaddr.s_addr = sa->sa.sin_addr.s_addr; 363 364 len = snprintf(SNPARGS(action2, 0), "Forward to %s", 365 inet_ntoa(dummyaddr)); 366 367 if (sa->sa.sin_port) 368 snprintf(SNPARGS(action2, len), ":%d", 369 sa->sa.sin_port); 370 } 371 break; 372 #ifdef INET6 373 case O_FORWARD_IP6: { 374 char buf[INET6_ADDRSTRLEN]; 375 ipfw_insn_sa6 *sa = (ipfw_insn_sa6 *)cmd; 376 int len; 377 378 len = snprintf(SNPARGS(action2, 0), "Forward to [%s]", 379 ip6_sprintf(buf, &sa->sa.sin6_addr)); 380 381 if (sa->sa.sin6_port) 382 snprintf(SNPARGS(action2, len), ":%u", 383 sa->sa.sin6_port); 384 } 385 break; 386 #endif 387 case O_NETGRAPH: 388 snprintf(SNPARGS(action2, 0), "Netgraph %d", 389 cmd->arg1); 390 break; 391 case O_NGTEE: 392 snprintf(SNPARGS(action2, 0), "Ngtee %d", 393 cmd->arg1); 394 break; 395 case O_NAT: 396 action = "Nat"; 397 break; 398 case O_REASS: 399 action = "Reass"; 400 break; 401 case O_CALLRETURN: 402 if (cmd->len & F_NOT) 403 action = "Return"; 404 else 405 snprintf(SNPARGS(action2, 0), "Call %d", 406 cmd->arg1); 407 break; 408 default: 409 action = "UNKNOWN"; 410 break; 411 } 412 } 413 414 if (hlen == 0) { /* non-ip */ 415 snprintf(SNPARGS(proto, 0), "MAC"); 416 417 } else { 418 int len; 419 #ifdef INET6 420 char src[INET6_ADDRSTRLEN + 2], dst[INET6_ADDRSTRLEN + 2]; 421 #else 422 char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN]; 423 #endif 424 struct icmphdr *icmp; 425 struct tcphdr *tcp; 426 struct udphdr *udp; 427 #ifdef INET6 428 struct ip6_hdr *ip6 = NULL; 429 struct icmp6_hdr *icmp6; 430 u_short ip6f_mf; 431 #endif 432 src[0] = '\0'; 433 dst[0] = '\0'; 434 #ifdef INET6 435 ip6f_mf = offset & IP6F_MORE_FRAG; 436 offset &= IP6F_OFF_MASK; 437 438 if (IS_IP6_FLOW_ID(&(args->f_id))) { 439 char ip6buf[INET6_ADDRSTRLEN]; 440 snprintf(src, sizeof(src), "[%s]", 441 ip6_sprintf(ip6buf, &args->f_id.src_ip6)); 442 snprintf(dst, sizeof(dst), "[%s]", 443 ip6_sprintf(ip6buf, &args->f_id.dst_ip6)); 444 445 ip6 = (struct ip6_hdr *)ip; 446 tcp = (struct tcphdr *)(((char *)ip) + hlen); 447 udp = (struct udphdr *)(((char *)ip) + hlen); 448 } else 449 #endif 450 { 451 tcp = L3HDR(struct tcphdr, ip); 452 udp = L3HDR(struct udphdr, ip); 453 454 inet_ntop(AF_INET, &ip->ip_src, src, sizeof(src)); 455 inet_ntop(AF_INET, &ip->ip_dst, dst, sizeof(dst)); 456 } 457 458 switch (args->f_id.proto) { 459 case IPPROTO_TCP: 460 len = snprintf(SNPARGS(proto, 0), "TCP %s", src); 461 if (offset == 0) 462 snprintf(SNPARGS(proto, len), ":%d %s:%d", 463 ntohs(tcp->th_sport), 464 dst, 465 ntohs(tcp->th_dport)); 466 else 467 snprintf(SNPARGS(proto, len), " %s", dst); 468 break; 469 470 case IPPROTO_UDP: 471 len = snprintf(SNPARGS(proto, 0), "UDP %s", src); 472 if (offset == 0) 473 snprintf(SNPARGS(proto, len), ":%d %s:%d", 474 ntohs(udp->uh_sport), 475 dst, 476 ntohs(udp->uh_dport)); 477 else 478 snprintf(SNPARGS(proto, len), " %s", dst); 479 break; 480 481 case IPPROTO_ICMP: 482 icmp = L3HDR(struct icmphdr, ip); 483 if (offset == 0) 484 len = snprintf(SNPARGS(proto, 0), 485 "ICMP:%u.%u ", 486 icmp->icmp_type, icmp->icmp_code); 487 else 488 len = snprintf(SNPARGS(proto, 0), "ICMP "); 489 len += snprintf(SNPARGS(proto, len), "%s", src); 490 snprintf(SNPARGS(proto, len), " %s", dst); 491 break; 492 #ifdef INET6 493 case IPPROTO_ICMPV6: 494 icmp6 = (struct icmp6_hdr *)(((char *)ip) + hlen); 495 if (offset == 0) 496 len = snprintf(SNPARGS(proto, 0), 497 "ICMPv6:%u.%u ", 498 icmp6->icmp6_type, icmp6->icmp6_code); 499 else 500 len = snprintf(SNPARGS(proto, 0), "ICMPv6 "); 501 len += snprintf(SNPARGS(proto, len), "%s", src); 502 snprintf(SNPARGS(proto, len), " %s", dst); 503 break; 504 #endif 505 default: 506 len = snprintf(SNPARGS(proto, 0), "P:%d %s", 507 args->f_id.proto, src); 508 snprintf(SNPARGS(proto, len), " %s", dst); 509 break; 510 } 511 512 #ifdef INET6 513 if (IS_IP6_FLOW_ID(&(args->f_id))) { 514 if (offset & (IP6F_OFF_MASK | IP6F_MORE_FRAG)) 515 snprintf(SNPARGS(fragment, 0), 516 " (frag %08x:%d@%d%s)", 517 args->f_id.extra, 518 ntohs(ip6->ip6_plen) - hlen, 519 ntohs(offset) << 3, ip6f_mf ? "+" : ""); 520 } else 521 #endif 522 { 523 int ipoff, iplen; 524 ipoff = ntohs(ip->ip_off); 525 iplen = ntohs(ip->ip_len); 526 if (ipoff & (IP_MF | IP_OFFMASK)) 527 snprintf(SNPARGS(fragment, 0), 528 " (frag %d:%d@%d%s)", 529 ntohs(ip->ip_id), iplen - (ip->ip_hl << 2), 530 offset << 3, 531 (ipoff & IP_MF) ? "+" : ""); 532 } 533 } 534 #ifdef __FreeBSD__ 535 if (oif || m->m_pkthdr.rcvif) 536 log(LOG_SECURITY | LOG_INFO, 537 "ipfw: %d %s %s %s via %s%s\n", 538 f ? f->rulenum : -1, 539 action, proto, oif ? "out" : "in", 540 oif ? oif->if_xname : m->m_pkthdr.rcvif->if_xname, 541 fragment); 542 else 543 #endif 544 log(LOG_SECURITY | LOG_INFO, 545 "ipfw: %d %s %s [no if info]%s\n", 546 f ? f->rulenum : -1, 547 action, proto, fragment); 548 if (limit_reached) 549 log(LOG_SECURITY | LOG_NOTICE, 550 "ipfw: limit %d reached on entry %d\n", 551 limit_reached, f ? f->rulenum : -1); 552 } 553 /* end of file */ 554