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