1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 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/mbuf.h> 44 #include <sys/socket.h> 45 #include <sys/sysctl.h> 46 #include <sys/syslog.h> 47 #include <net/ethernet.h> /* for ETHERTYPE_IP */ 48 #include <net/if.h> 49 #include <net/if_dl.h> 50 #include <net/if_var.h> 51 #include <net/if_private.h> 52 #include <net/vnet.h> 53 #include <net/route.h> 54 #include <net/route/route_var.h> 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/udp.h> 62 #include <netinet/tcp.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 #ifdef __APPLE__ 88 #undef snprintf 89 #define snprintf sprintf 90 #define SNPARGS(buf, len) buf + len 91 #define SNP(buf) buf 92 #else /* !__APPLE__ */ 93 #define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0 94 #define SNP(buf) buf, sizeof(buf) 95 #endif /* !__APPLE__ */ 96 97 #define TARG(k, f) IP_FW_ARG_TABLEARG(chain, k, f) 98 99 static void 100 ipfw_log_ipfw0(struct ip_fw_args *args, struct ip *ip) 101 { 102 if (args->flags & IPFW_ARGS_LENMASK) 103 ipfw_bpf_tap(args->mem, IPFW_ARGS_LENGTH(args->flags)); 104 else if (args->flags & IPFW_ARGS_ETHER) 105 /* layer2, use orig hdr */ 106 ipfw_bpf_mtap(args->m); 107 else { 108 /* Add fake header. Later we will store 109 * more info in the header. 110 */ 111 if (ip->ip_v == 4) 112 ipfw_bpf_mtap2("DDDDDDSSSSSS\x08\x00", 113 ETHER_HDR_LEN, args->m); 114 else if (ip->ip_v == 6) 115 ipfw_bpf_mtap2("DDDDDDSSSSSS\x86\xdd", 116 ETHER_HDR_LEN, args->m); 117 else 118 /* Obviously bogus EtherType. */ 119 ipfw_bpf_mtap2("DDDDDDSSSSSS\xff\xff", 120 ETHER_HDR_LEN, args->m); 121 } 122 } 123 124 /* 125 * XXX this function alone takes about 2Kbytes of code! 126 */ 127 static void 128 ipfw_log_syslog(struct ip_fw_chain *chain, struct ip_fw *f, u_int hlen, 129 struct ip_fw_args *args, u_short offset, uint32_t tablearg, struct ip *ip) 130 { 131 char *action; 132 int limit_reached = 0; 133 char action2[92], proto[128], fragment[32], mark_str[24]; 134 135 fragment[0] = '\0'; 136 proto[0] = '\0'; 137 138 if (f == NULL) { /* bogus pkt */ 139 if (V_verbose_limit != 0 && V_norule_counter >= V_verbose_limit) 140 return; 141 V_norule_counter++; 142 if (V_norule_counter == V_verbose_limit) 143 limit_reached = V_verbose_limit; 144 action = "Refuse"; 145 } else { /* O_LOG is the first action, find the real one */ 146 ipfw_insn *cmd = ACTION_PTR(f); 147 ipfw_insn_log *l = (ipfw_insn_log *)cmd; 148 149 if (l->max_log != 0 && l->log_left == 0) 150 return; 151 l->log_left--; 152 if (l->log_left == 0) 153 limit_reached = l->max_log; 154 cmd += F_LEN(cmd); /* point to first action */ 155 if (cmd->opcode == O_ALTQ) { 156 ipfw_insn_altq *altq = (ipfw_insn_altq *)cmd; 157 158 snprintf(SNPARGS(action2, 0), "Altq %d", 159 altq->qid); 160 cmd += F_LEN(cmd); 161 } 162 if (cmd->opcode == O_PROB || cmd->opcode == O_TAG) 163 cmd += F_LEN(cmd); 164 165 action = action2; 166 switch (cmd->opcode) { 167 case O_DENY: 168 action = "Deny"; 169 break; 170 171 case O_REJECT: 172 if (cmd->arg1==ICMP_REJECT_RST) 173 action = "Reset"; 174 else if (cmd->arg1==ICMP_REJECT_ABORT) 175 action = "Abort"; 176 else if (cmd->arg1==ICMP_UNREACH_HOST) 177 action = "Reject"; 178 else 179 snprintf(SNPARGS(action2, 0), "Unreach %d", 180 cmd->arg1); 181 break; 182 183 case O_UNREACH6: 184 if (cmd->arg1==ICMP6_UNREACH_RST) 185 action = "Reset"; 186 else if (cmd->arg1==ICMP6_UNREACH_ABORT) 187 action = "Abort"; 188 else 189 snprintf(SNPARGS(action2, 0), "Unreach %d", 190 cmd->arg1); 191 break; 192 193 case O_ACCEPT: 194 action = "Accept"; 195 break; 196 case O_COUNT: 197 action = "Count"; 198 break; 199 case O_DIVERT: 200 snprintf(SNPARGS(action2, 0), "Divert %d", 201 TARG(cmd->arg1, divert)); 202 break; 203 case O_TEE: 204 snprintf(SNPARGS(action2, 0), "Tee %d", 205 TARG(cmd->arg1, divert)); 206 break; 207 case O_SETDSCP: 208 snprintf(SNPARGS(action2, 0), "SetDscp %d", 209 TARG(cmd->arg1, dscp) & 0x3F); 210 break; 211 case O_SETFIB: 212 snprintf(SNPARGS(action2, 0), "SetFib %d", 213 TARG(cmd->arg1, fib) & 0x7FFF); 214 break; 215 case O_SKIPTO: 216 snprintf(SNPARGS(action2, 0), "SkipTo %d", 217 TARG(insntod(cmd, u32)->d[0], skipto)); 218 break; 219 case O_PIPE: 220 snprintf(SNPARGS(action2, 0), "Pipe %d", 221 TARG(cmd->arg1, pipe)); 222 break; 223 case O_QUEUE: 224 snprintf(SNPARGS(action2, 0), "Queue %d", 225 TARG(cmd->arg1, pipe)); 226 break; 227 case O_FORWARD_IP: 228 if (IS_IP4_FLOW_ID(&args->f_id)) { 229 char buf[INET_ADDRSTRLEN]; 230 const struct sockaddr_in *sin = &insntod(cmd, sa)->sa; 231 int len; 232 233 /* handle fwd tablearg */ 234 if (sin->sin_addr.s_addr == INADDR_ANY) { 235 struct in_addr tmp; 236 237 tmp.s_addr = htonl( 238 TARG_VAL(chain, tablearg, nh4)); 239 inet_ntoa_r(tmp, buf); 240 } else 241 inet_ntoa_r(sin->sin_addr, buf); 242 len = snprintf(SNPARGS(action2, 0), 243 "Forward to %s", buf); 244 if (sin->sin_port != 0) 245 snprintf(SNPARGS(action2, len), ":%d", 246 sin->sin_port); 247 } 248 /* FALLTHROUGH */ 249 #ifdef INET6 250 case O_FORWARD_IP6: 251 if (IS_IP6_FLOW_ID(&args->f_id)) { 252 char buf[INET6_ADDRSTRLEN]; 253 struct sockaddr_in6 tmp; 254 const struct sockaddr_in *sin = &insntod(cmd, sa)->sa; 255 struct sockaddr_in6 *sin6 = &insntod(cmd, sa6)->sa; 256 int len; 257 258 if (cmd->opcode == O_FORWARD_IP && 259 sin->sin_addr.s_addr == INADDR_ANY) { 260 sin6 = &tmp; 261 sin6->sin6_addr = 262 TARG_VAL(chain, tablearg, nh6); 263 sin6->sin6_scope_id = 264 TARG_VAL(chain, tablearg, zoneid); 265 sin6->sin6_port = sin->sin_port; 266 } 267 268 ip6_sprintf(buf, &sin6->sin6_addr); 269 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && 270 sin6->sin6_scope_id != 0) 271 len = snprintf(SNPARGS(action2, 0), 272 "Forward to [%s%%%u]", 273 buf, sin6->sin6_scope_id); 274 else 275 len = snprintf(SNPARGS(action2, 0), 276 "Forward to [%s]", buf); 277 if (sin6->sin6_port != 0) 278 snprintf(SNPARGS(action2, len), ":%u", 279 sin6->sin6_port); 280 } 281 #endif 282 break; 283 case O_NETGRAPH: 284 snprintf(SNPARGS(action2, 0), "Netgraph %d", 285 cmd->arg1); 286 break; 287 case O_NGTEE: 288 snprintf(SNPARGS(action2, 0), "Ngtee %d", 289 cmd->arg1); 290 break; 291 case O_NAT: 292 action = "Nat"; 293 break; 294 case O_REASS: 295 action = "Reass"; 296 break; 297 case O_CALLRETURN: 298 if (cmd->len & F_NOT) 299 snprintf(SNPARGS(action2, 0), "Return %s", 300 cmd->arg1 == RETURN_NEXT_RULENUM ? 301 "next-rulenum": "next-rule"); 302 else 303 snprintf(SNPARGS(action2, 0), "Call %d", 304 TARG(insntod(cmd, u32)->d[0], skipto)); 305 break; 306 case O_SETMARK: 307 if (cmd->arg1 == IP_FW_TARG) 308 snprintf(SNPARGS(action2, 0), "SetMark %#010x", 309 TARG(cmd->arg1, mark)); 310 else 311 snprintf(SNPARGS(action2, 0), "SetMark %#010x", 312 insntoc(cmd, u32)->d[0]); 313 break; 314 case O_EXTERNAL_ACTION: 315 snprintf(SNPARGS(action2, 0), "Eaction %s", 316 ((struct named_object *)SRV_OBJECT(chain, 317 insntod(cmd, kidx)->kidx))->name); 318 break; 319 default: 320 action = "UNKNOWN"; 321 break; 322 } 323 } 324 325 if (hlen == 0) { /* non-ip */ 326 snprintf(SNPARGS(proto, 0), "MAC"); 327 328 } else { 329 int len; 330 #ifdef INET6 331 char src[INET6_ADDRSTRLEN + 2], dst[INET6_ADDRSTRLEN + 2]; 332 #else 333 char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN]; 334 #endif 335 struct icmphdr *icmp; 336 struct tcphdr *tcp; 337 struct udphdr *udp; 338 #ifdef INET6 339 struct ip6_hdr *ip6 = NULL; 340 struct icmp6_hdr *icmp6; 341 u_short ip6f_mf; 342 #endif 343 src[0] = '\0'; 344 dst[0] = '\0'; 345 #ifdef INET6 346 ip6f_mf = offset & IP6F_MORE_FRAG; 347 offset &= IP6F_OFF_MASK; 348 349 if (IS_IP6_FLOW_ID(&(args->f_id))) { 350 char ip6buf[INET6_ADDRSTRLEN]; 351 snprintf(src, sizeof(src), "[%s]", 352 ip6_sprintf(ip6buf, &args->f_id.src_ip6)); 353 snprintf(dst, sizeof(dst), "[%s]", 354 ip6_sprintf(ip6buf, &args->f_id.dst_ip6)); 355 356 ip6 = (struct ip6_hdr *)ip; 357 tcp = (struct tcphdr *)(((char *)ip) + hlen); 358 udp = (struct udphdr *)(((char *)ip) + hlen); 359 } else 360 #endif 361 { 362 tcp = L3HDR(struct tcphdr, ip); 363 udp = L3HDR(struct udphdr, ip); 364 365 inet_ntop(AF_INET, &ip->ip_src, src, sizeof(src)); 366 inet_ntop(AF_INET, &ip->ip_dst, dst, sizeof(dst)); 367 } 368 369 switch (args->f_id.proto) { 370 case IPPROTO_TCP: 371 len = snprintf(SNPARGS(proto, 0), "TCP %s", src); 372 if (offset == 0) 373 snprintf(SNPARGS(proto, len), ":%d %s:%d", 374 ntohs(tcp->th_sport), 375 dst, 376 ntohs(tcp->th_dport)); 377 else 378 snprintf(SNPARGS(proto, len), " %s", dst); 379 break; 380 381 case IPPROTO_UDP: 382 case IPPROTO_UDPLITE: 383 len = snprintf(SNPARGS(proto, 0), "UDP%s%s", 384 args->f_id.proto == IPPROTO_UDP ? " ": "Lite ", 385 src); 386 if (offset == 0) 387 snprintf(SNPARGS(proto, len), ":%d %s:%d", 388 ntohs(udp->uh_sport), 389 dst, 390 ntohs(udp->uh_dport)); 391 else 392 snprintf(SNPARGS(proto, len), " %s", dst); 393 break; 394 395 case IPPROTO_ICMP: 396 icmp = L3HDR(struct icmphdr, ip); 397 if (offset == 0) 398 len = snprintf(SNPARGS(proto, 0), 399 "ICMP:%u.%u ", 400 icmp->icmp_type, icmp->icmp_code); 401 else 402 len = snprintf(SNPARGS(proto, 0), "ICMP "); 403 len += snprintf(SNPARGS(proto, len), "%s", src); 404 snprintf(SNPARGS(proto, len), " %s", dst); 405 break; 406 #ifdef INET6 407 case IPPROTO_ICMPV6: 408 icmp6 = (struct icmp6_hdr *)(((char *)ip) + hlen); 409 if (offset == 0) 410 len = snprintf(SNPARGS(proto, 0), 411 "ICMPv6:%u.%u ", 412 icmp6->icmp6_type, icmp6->icmp6_code); 413 else 414 len = snprintf(SNPARGS(proto, 0), "ICMPv6 "); 415 len += snprintf(SNPARGS(proto, len), "%s", src); 416 snprintf(SNPARGS(proto, len), " %s", dst); 417 break; 418 #endif 419 default: 420 len = snprintf(SNPARGS(proto, 0), "P:%d %s", 421 args->f_id.proto, src); 422 snprintf(SNPARGS(proto, len), " %s", dst); 423 break; 424 } 425 426 #ifdef INET6 427 if (IS_IP6_FLOW_ID(&(args->f_id))) { 428 if (offset || ip6f_mf) 429 snprintf(SNPARGS(fragment, 0), 430 " (frag %08x:%d@%d%s)", 431 args->f_id.extra, 432 ntohs(ip6->ip6_plen) - hlen, 433 ntohs(offset) << 3, ip6f_mf ? "+" : ""); 434 } else 435 #endif 436 { 437 int ipoff, iplen; 438 ipoff = ntohs(ip->ip_off); 439 iplen = ntohs(ip->ip_len); 440 if (ipoff & (IP_MF | IP_OFFMASK)) 441 snprintf(SNPARGS(fragment, 0), 442 " (frag %d:%d@%d%s)", 443 ntohs(ip->ip_id), iplen - (ip->ip_hl << 2), 444 offset << 3, 445 (ipoff & IP_MF) ? "+" : ""); 446 } 447 } 448 449 /* [fw]mark */ 450 if (args->rule.pkt_mark) 451 snprintf(SNPARGS(mark_str, 0), " mark:%#x", 452 args->rule.pkt_mark); 453 else 454 mark_str[0] = '\0'; 455 456 #ifdef __FreeBSD__ 457 log(LOG_SECURITY | LOG_INFO, "ipfw: %d %s %s%s %s via %s%s\n", 458 f ? f->rulenum : -1, action, proto, mark_str, 459 args->flags & IPFW_ARGS_OUT ? "out" : "in", args->ifp->if_xname, 460 fragment); 461 #else 462 log(LOG_SECURITY | LOG_INFO, "ipfw: %d %s %s%s [no if info]%s\n", 463 f ? f->rulenum : -1, action, proto, mark_str, fragment); 464 #endif 465 if (limit_reached) 466 log(LOG_SECURITY | LOG_NOTICE, 467 "ipfw: limit %d reached on entry %d\n", 468 limit_reached, f ? f->rulenum : -1); 469 } 470 471 static void 472 ipfw_rtsocklog_fill_l3(struct ip_fw_args *args, 473 char **buf, struct sockaddr **src, struct sockaddr **dst) 474 { 475 struct sockaddr_in *v4src, *v4dst; 476 #ifdef INET6 477 struct sockaddr_in6 *v6src, *v6dst; 478 479 if (IS_IP6_FLOW_ID(&(args->f_id))) { 480 v6src = (struct sockaddr_in6 *)*buf; 481 *buf += sizeof(*v6src); 482 v6dst = (struct sockaddr_in6 *)*buf; 483 *buf += sizeof(*v6dst); 484 v6src->sin6_len = v6dst->sin6_len = sizeof(*v6src); 485 v6src->sin6_family = v6dst->sin6_family = AF_INET6; 486 v6src->sin6_addr = args->f_id.src_ip6; 487 v6dst->sin6_addr = args->f_id.dst_ip6; 488 489 *src = (struct sockaddr *)v6src; 490 *dst = (struct sockaddr *)v6dst; 491 } else 492 #endif 493 { 494 v4src = (struct sockaddr_in *)*buf; 495 *buf += sizeof(*v4src); 496 v4dst = (struct sockaddr_in *)*buf; 497 *buf += sizeof(*v4dst); 498 v4src->sin_len = v4dst->sin_len = sizeof(*v4src); 499 v4src->sin_family = v4dst->sin_family = AF_INET; 500 v4src->sin_addr.s_addr = htonl(args->f_id.src_ip); 501 v4dst->sin_addr.s_addr = htonl(args->f_id.dst_ip); 502 503 *src = (struct sockaddr *)v4src; 504 *dst = (struct sockaddr *)v4dst; 505 } 506 } 507 508 static struct sockaddr * 509 ipfw_rtsocklog_handle_tablearg(struct ip_fw_chain *chain, 510 struct ip_fw_args *args, ipfw_insn *cmd, uint32_t tablearg, 511 uint32_t *targ_value, char **buf) 512 { 513 /* handle tablearg now */ 514 switch (cmd->opcode) { 515 case O_DIVERT: 516 case O_TEE: 517 *targ_value = TARG(cmd->arg1, divert); 518 break; 519 case O_NETGRAPH: 520 case O_NGTEE: 521 *targ_value = TARG(cmd->arg1, netgraph); 522 break; 523 case O_SETDSCP: 524 *targ_value = (TARG(cmd->arg1, dscp) & 0x3F); 525 break; 526 case O_SETFIB: 527 *targ_value = (TARG(cmd->arg1, fib) & 0x7FFF); 528 break; 529 case O_SKIPTO: 530 case O_CALLRETURN: 531 if (cmd->opcode == O_CALLRETURN && (cmd->len & F_NOT)) 532 break; 533 *targ_value = TARG(insntod(cmd, u32)->d[0], skipto); 534 break; 535 case O_PIPE: 536 case O_QUEUE: 537 *targ_value = TARG(cmd->arg1, pipe); 538 break; 539 case O_SETMARK: 540 if (cmd->arg1 == IP_FW_TARG) 541 *targ_value = TARG_VAL(chain, tablearg, mark); 542 break; 543 case O_FORWARD_IP: 544 if (IS_IP4_FLOW_ID(&args->f_id)) { 545 struct sockaddr_in *nh = (struct sockaddr_in *)*buf; 546 547 *buf += sizeof(*nh); 548 memcpy(nh, &insntod(cmd, sa)->sa, sizeof(*nh)); 549 if (nh->sin_addr.s_addr == INADDR_ANY) 550 nh->sin_addr.s_addr = htonl( 551 TARG_VAL(chain, tablearg, nh4)); 552 return ((struct sockaddr *)nh); 553 } 554 /* FALLTHROUGH */ 555 #ifdef INET6 556 case O_FORWARD_IP6: 557 if (IS_IP6_FLOW_ID(&args->f_id)) { 558 const struct sockaddr_in *sin = &insntod(cmd, sa)->sa; 559 struct sockaddr_in6 *nh = (struct sockaddr_in6 *)*buf; 560 561 *buf += sizeof(*nh); 562 if (cmd->opcode == O_FORWARD_IP && 563 sin->sin_addr.s_addr == INADDR_ANY) { 564 nh->sin6_family = AF_INET6; 565 nh->sin6_len = sizeof(*nh); 566 nh->sin6_addr = TARG_VAL(chain, tablearg, nh6); 567 nh->sin6_port = sin->sin_port; 568 nh->sin6_scope_id = 569 TARG_VAL(chain, tablearg, zoneid); 570 } else 571 memcpy(nh, &insntod(cmd, sa6)->sa, sizeof(*nh)); 572 return ((struct sockaddr *)nh); 573 } 574 #endif 575 default: 576 break; 577 } 578 579 return (NULL); 580 } 581 582 #define MAX_COMMENT_LEN 80 583 584 static size_t 585 ipfw_copy_rule_comment(struct ip_fw *f, char *dst) 586 { 587 ipfw_insn *cmd; 588 size_t rcomment_len = 0; 589 int l, cmdlen; 590 591 for (l = f->cmd_len, cmd = f->cmd; l > 0; l -= cmdlen, cmd += cmdlen) { 592 cmdlen = F_LEN(cmd); 593 if (cmd->opcode != O_NOP) { 594 continue; 595 } else if (cmd->len == 1) { 596 return (0); 597 } 598 break; 599 } 600 if (l <= 0) { 601 return (0); 602 } 603 rcomment_len = strnlen((char *)(cmd + 1), MAX_COMMENT_LEN - 1) + 1; 604 strlcpy(dst, (char *)(cmd + 1), rcomment_len); 605 return (rcomment_len); 606 } 607 608 /* 609 * Logs a packet matched by a rule as a route(4) socket message. 610 * 611 * While ipfw0 pseudo interface provides a way to observe full packet body, 612 * no metadata (rule number, action, mark, etc) is available. 613 * pflog(4) is not an option either as it's header is hardcoded and does not 614 * provide sufficient space for ipfw meta information. 615 * 616 * To be able to get a machine-readable event with all meta information needed 617 * for user-space daemons we construct a route(4) message and pack as much meta 618 * information as we can into it. 619 * 620 * RTAX_DST(0): (struct sockaddr_dl) carrying ipfwlog_rtsock_hdr_v2 in sdl_data 621 * with general rule information (rule number, set, action, mark, 622 * cmd, comment) and source/destination MAC addresses in case we're 623 * logging in layer2 pass. 624 * 625 * RTAX_GATEWAY(1): (struct sockaddr) IP source address 626 * 627 * RTAX_NETMASK(2): (struct sockaddr) IP destination address 628 * 629 * RTAX_GENMASK(3): (struct sockaddr) IP address and port used in fwd action 630 * 631 * One SHOULD set an explicit logamount for any rule using rtsock as flooding 632 * route socket with such events could lead to various system-wide side effects. 633 * RTF_PROTO1 flag in (struct rt_addrinfo).rti_flags is set in all messages 634 * once half of logamount limit is crossed. This could be used by the software 635 * processing these logs to issue `ipfw resetlog` command to keep the event 636 * flow. 637 * 638 * TODO: convert ipfwlog_rtsock_hdr_v2 data into TLV to ease expansion. 639 */ 640 641 static void 642 ipfw_log_rtsock(struct ip_fw_chain *chain, struct ip_fw *f, u_int hlen, 643 struct ip_fw_args *args, u_short offset, uint32_t tablearg, void *_eh) 644 { 645 struct sockaddr_dl *sdl_ipfwcmd; 646 struct ether_header *eh = _eh; 647 struct rt_addrinfo *info; 648 uint32_t *targ_value; 649 ipfwlog_rtsock_hdr_v2 *hdr; 650 ipfw_insn *cmd; 651 ipfw_insn_log *l; 652 char *buf, *orig_buf; 653 /* at least 4 x sizeof(struct sockaddr_dl) + rule comment (80) */ 654 size_t buflen = 512; 655 656 /* Should we log? O_LOG is the first one */ 657 cmd = ACTION_PTR(f); 658 l = (ipfw_insn_log *)cmd; 659 660 if (l->max_log != 0 && l->log_left == 0) 661 return; 662 663 if (hlen == 0) /* non-ip */ 664 return; 665 666 l->log_left--; 667 if (V_fw_verbose != 0 && l->log_left == 0) { 668 log(LOG_SECURITY | LOG_NOTICE, 669 "ipfw: limit %d reached on entry %d\n", 670 l->max_log, f ? f->rulenum : -1); 671 } 672 673 buf = orig_buf = malloc(buflen, M_TEMP, M_NOWAIT | M_ZERO); 674 if (buf == NULL) 675 return; 676 677 info = (struct rt_addrinfo *)buf; 678 buf += sizeof (*info); 679 680 cmd = ipfw_get_action(f); 681 sdl_ipfwcmd = (struct sockaddr_dl *)buf; 682 sdl_ipfwcmd->sdl_family = AF_IPFWLOG; 683 sdl_ipfwcmd->sdl_index = f->set; 684 sdl_ipfwcmd->sdl_type = 2; /* version */ 685 sdl_ipfwcmd->sdl_alen = sizeof(*hdr); 686 hdr = (ipfwlog_rtsock_hdr_v2 *)(sdl_ipfwcmd->sdl_data); 687 /* fill rule comment in if any */ 688 sdl_ipfwcmd->sdl_nlen = ipfw_copy_rule_comment(f, hdr->comment); 689 targ_value = &hdr->tablearg; 690 hdr->rulenum = f->rulenum; 691 hdr->mark = args->rule.pkt_mark; 692 hdr->cmd = *cmd; 693 694 sdl_ipfwcmd->sdl_len = sizeof(*sdl_ipfwcmd); 695 if (sizeof(*hdr) + sdl_ipfwcmd->sdl_nlen > sizeof(sdl_ipfwcmd->sdl_data)) { 696 sdl_ipfwcmd->sdl_len += sizeof(*hdr) + sdl_ipfwcmd->sdl_nlen - 697 sizeof(sdl_ipfwcmd->sdl_data); 698 } 699 buf += sdl_ipfwcmd->sdl_len; 700 701 /* fill L2 in if present */ 702 if (args->flags & IPFW_ARGS_ETHER && eh != NULL) { 703 sdl_ipfwcmd->sdl_slen = sizeof(eh->ether_shost); 704 memcpy(hdr->ether_shost, eh->ether_shost, 705 sdl_ipfwcmd->sdl_slen); 706 memcpy(hdr->ether_dhost, eh->ether_dhost, 707 sdl_ipfwcmd->sdl_slen); 708 } 709 710 info->rti_info[RTAX_DST] = (struct sockaddr *)sdl_ipfwcmd; 711 712 /* Warn if we're about to stop sending messages */ 713 if (l->max_log != 0 && l->log_left < (l->max_log >> 1)) { 714 info->rti_flags |= RTF_PROTO1; 715 } 716 717 /* handle tablearg */ 718 info->rti_info[RTAX_GENMASK] = ipfw_rtsocklog_handle_tablearg( 719 chain, args, cmd, tablearg, targ_value, &buf); 720 721 /* L3 */ 722 ipfw_rtsocklog_fill_l3(args, &buf, 723 &info->rti_info[RTAX_GATEWAY], 724 &info->rti_info[RTAX_NETMASK]); 725 726 KASSERT(buf <= (orig_buf + buflen), 727 ("ipfw: buffer for logdst rtsock is not big enough")); 728 729 info->rti_ifp = args->ifp; 730 rtsock_routemsg_info(RTM_IPFWLOG, info, RT_ALL_FIBS); 731 732 free(orig_buf, M_TEMP); 733 } 734 735 /* 736 * We enter here when we have a rule with O_LOG. 737 */ 738 void 739 ipfw_log(struct ip_fw_chain *chain, struct ip_fw *f, u_int hlen, 740 struct ip_fw_args *args, u_short offset, uint32_t tablearg, 741 struct ip *ip, void *eh) 742 { 743 ipfw_insn *cmd; 744 745 /* Fallback to default logging if we're missing rule pointer */ 746 if (f == NULL || 747 /* O_LOG is the first action */ 748 ((cmd = ACTION_PTR(f)) && cmd->arg1 == IPFW_LOG_DEFAULT)) { 749 if (V_fw_verbose == 0) { 750 ipfw_log_ipfw0(args, ip); 751 return; 752 } 753 ipfw_log_syslog(chain, f, hlen, args, offset, tablearg, ip); 754 return; 755 } 756 757 if (cmd->arg1 & IPFW_LOG_SYSLOG) 758 ipfw_log_syslog(chain, f, hlen, args, offset, tablearg, ip); 759 760 if (cmd->arg1 & IPFW_LOG_RTSOCK) 761 ipfw_log_rtsock(chain, f, hlen, args, offset, tablearg, eh); 762 763 if (cmd->arg1 & IPFW_LOG_IPFW0) 764 ipfw_log_ipfw0(args, ip); 765 } 766 /* end of file */ 767