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