1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
2 | |
---|
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 <rtems/bsd/local/opt_ipfw.h> |
---|
36 | #include <rtems/bsd/local/opt_inet.h> |
---|
37 | #ifndef INET |
---|
38 | #error IPFIREWALL requires INET. |
---|
39 | #endif /* INET */ |
---|
40 | #include <rtems/bsd/local/opt_inet6.h> |
---|
41 | |
---|
42 | #include <rtems/bsd/sys/param.h> |
---|
43 | #include <sys/systm.h> |
---|
44 | #include <sys/mbuf.h> |
---|
45 | #include <sys/kernel.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/vnet.h> |
---|
52 | #include <net/if_types.h> /* for IFT_ETHER */ |
---|
53 | #include <net/bpf.h> /* for BPF */ |
---|
54 | |
---|
55 | #include <netinet/in.h> |
---|
56 | #include <netinet/ip.h> |
---|
57 | #include <netinet/ip_icmp.h> |
---|
58 | #include <netinet/ip_var.h> |
---|
59 | #include <netinet/ip_fw.h> |
---|
60 | #include <netinet/ipfw/ip_fw_private.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 | #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 | #define SNPARGS(buf, len) buf + len, sizeof(buf) > len ? sizeof(buf) - len : 0 |
---|
86 | #define SNP(buf) buf, sizeof(buf) |
---|
87 | |
---|
88 | #ifdef WITHOUT_BPF |
---|
89 | void |
---|
90 | ipfw_log_bpf(int onoff) |
---|
91 | { |
---|
92 | } |
---|
93 | #else /* !WITHOUT_BPF */ |
---|
94 | static struct ifnet *log_if; /* hook to attach to bpf */ |
---|
95 | |
---|
96 | /* we use this dummy function for all ifnet callbacks */ |
---|
97 | static int |
---|
98 | log_dummy(struct ifnet *ifp, u_long cmd, caddr_t addr) |
---|
99 | { |
---|
100 | return EINVAL; |
---|
101 | } |
---|
102 | |
---|
103 | static int |
---|
104 | ipfw_log_output(struct ifnet *ifp, struct mbuf *m, |
---|
105 | struct sockaddr *dst, struct route *ro) |
---|
106 | { |
---|
107 | if (m != NULL) |
---|
108 | m_freem(m); |
---|
109 | return EINVAL; |
---|
110 | } |
---|
111 | |
---|
112 | static void |
---|
113 | ipfw_log_start(struct ifnet* ifp) |
---|
114 | { |
---|
115 | panic("ipfw_log_start() must not be called"); |
---|
116 | } |
---|
117 | |
---|
118 | static const u_char ipfwbroadcastaddr[6] = |
---|
119 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
---|
120 | |
---|
121 | void |
---|
122 | ipfw_log_bpf(int onoff) |
---|
123 | { |
---|
124 | struct ifnet *ifp; |
---|
125 | |
---|
126 | if (onoff) { |
---|
127 | if (log_if) |
---|
128 | return; |
---|
129 | ifp = if_alloc(IFT_ETHER); |
---|
130 | if (ifp == NULL) |
---|
131 | return; |
---|
132 | if_initname(ifp, "ipfw", 0); |
---|
133 | ifp->if_mtu = 65536; |
---|
134 | ifp->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST; |
---|
135 | ifp->if_init = (void *)log_dummy; |
---|
136 | ifp->if_ioctl = log_dummy; |
---|
137 | ifp->if_start = ipfw_log_start; |
---|
138 | ifp->if_output = ipfw_log_output; |
---|
139 | ifp->if_addrlen = 6; |
---|
140 | ifp->if_hdrlen = 14; |
---|
141 | if_attach(ifp); |
---|
142 | ifp->if_broadcastaddr = ipfwbroadcastaddr; |
---|
143 | ifp->if_baudrate = IF_Mbps(10); |
---|
144 | bpfattach(ifp, DLT_EN10MB, 14); |
---|
145 | log_if = ifp; |
---|
146 | } else { |
---|
147 | if (log_if) { |
---|
148 | ether_ifdetach(log_if); |
---|
149 | if_free(log_if); |
---|
150 | } |
---|
151 | log_if = NULL; |
---|
152 | } |
---|
153 | } |
---|
154 | #endif /* !WITHOUT_BPF */ |
---|
155 | |
---|
156 | /* |
---|
157 | * We enter here when we have a rule with O_LOG. |
---|
158 | * XXX this function alone takes about 2Kbytes of code! |
---|
159 | */ |
---|
160 | void |
---|
161 | ipfw_log(struct ip_fw *f, u_int hlen, struct ip_fw_args *args, |
---|
162 | struct mbuf *m, struct ifnet *oif, u_short offset, uint32_t tablearg, |
---|
163 | struct ip *ip) |
---|
164 | { |
---|
165 | char *action; |
---|
166 | int limit_reached = 0; |
---|
167 | char action2[40], proto[128], fragment[32]; |
---|
168 | |
---|
169 | if (V_fw_verbose == 0) { |
---|
170 | #ifndef WITHOUT_BPF |
---|
171 | |
---|
172 | if (log_if == NULL || log_if->if_bpf == NULL) |
---|
173 | return; |
---|
174 | |
---|
175 | if (args->eh) /* layer2, use orig hdr */ |
---|
176 | BPF_MTAP2(log_if, args->eh, ETHER_HDR_LEN, m); |
---|
177 | else |
---|
178 | /* Add fake header. Later we will store |
---|
179 | * more info in the header. |
---|
180 | */ |
---|
181 | BPF_MTAP2(log_if, "DDDDDDSSSSSS\x08\x00", ETHER_HDR_LEN, m); |
---|
182 | #endif /* !WITHOUT_BPF */ |
---|
183 | return; |
---|
184 | } |
---|
185 | /* the old 'log' function */ |
---|
186 | fragment[0] = '\0'; |
---|
187 | proto[0] = '\0'; |
---|
188 | |
---|
189 | if (f == NULL) { /* bogus pkt */ |
---|
190 | if (V_verbose_limit != 0 && V_norule_counter >= V_verbose_limit) |
---|
191 | return; |
---|
192 | V_norule_counter++; |
---|
193 | if (V_norule_counter == V_verbose_limit) |
---|
194 | limit_reached = V_verbose_limit; |
---|
195 | action = "Refuse"; |
---|
196 | } else { /* O_LOG is the first action, find the real one */ |
---|
197 | ipfw_insn *cmd = ACTION_PTR(f); |
---|
198 | ipfw_insn_log *l = (ipfw_insn_log *)cmd; |
---|
199 | |
---|
200 | if (l->max_log != 0 && l->log_left == 0) |
---|
201 | return; |
---|
202 | l->log_left--; |
---|
203 | if (l->log_left == 0) |
---|
204 | limit_reached = l->max_log; |
---|
205 | cmd += F_LEN(cmd); /* point to first action */ |
---|
206 | if (cmd->opcode == O_ALTQ) { |
---|
207 | ipfw_insn_altq *altq = (ipfw_insn_altq *)cmd; |
---|
208 | |
---|
209 | snprintf(SNPARGS(action2, 0), "Altq %d", |
---|
210 | altq->qid); |
---|
211 | cmd += F_LEN(cmd); |
---|
212 | } |
---|
213 | if (cmd->opcode == O_PROB) |
---|
214 | cmd += F_LEN(cmd); |
---|
215 | |
---|
216 | if (cmd->opcode == O_TAG) |
---|
217 | cmd += F_LEN(cmd); |
---|
218 | |
---|
219 | action = action2; |
---|
220 | switch (cmd->opcode) { |
---|
221 | case O_DENY: |
---|
222 | action = "Deny"; |
---|
223 | break; |
---|
224 | |
---|
225 | case O_REJECT: |
---|
226 | if (cmd->arg1==ICMP_REJECT_RST) |
---|
227 | action = "Reset"; |
---|
228 | else if (cmd->arg1==ICMP_UNREACH_HOST) |
---|
229 | action = "Reject"; |
---|
230 | else |
---|
231 | snprintf(SNPARGS(action2, 0), "Unreach %d", |
---|
232 | cmd->arg1); |
---|
233 | break; |
---|
234 | |
---|
235 | case O_UNREACH6: |
---|
236 | if (cmd->arg1==ICMP6_UNREACH_RST) |
---|
237 | action = "Reset"; |
---|
238 | else |
---|
239 | snprintf(SNPARGS(action2, 0), "Unreach %d", |
---|
240 | cmd->arg1); |
---|
241 | break; |
---|
242 | |
---|
243 | case O_ACCEPT: |
---|
244 | action = "Accept"; |
---|
245 | break; |
---|
246 | case O_COUNT: |
---|
247 | action = "Count"; |
---|
248 | break; |
---|
249 | case O_DIVERT: |
---|
250 | snprintf(SNPARGS(action2, 0), "Divert %d", |
---|
251 | cmd->arg1); |
---|
252 | break; |
---|
253 | case O_TEE: |
---|
254 | snprintf(SNPARGS(action2, 0), "Tee %d", |
---|
255 | cmd->arg1); |
---|
256 | break; |
---|
257 | case O_SETFIB: |
---|
258 | snprintf(SNPARGS(action2, 0), "SetFib %d", |
---|
259 | cmd->arg1); |
---|
260 | break; |
---|
261 | case O_SKIPTO: |
---|
262 | snprintf(SNPARGS(action2, 0), "SkipTo %d", |
---|
263 | cmd->arg1); |
---|
264 | break; |
---|
265 | case O_PIPE: |
---|
266 | snprintf(SNPARGS(action2, 0), "Pipe %d", |
---|
267 | cmd->arg1); |
---|
268 | break; |
---|
269 | case O_QUEUE: |
---|
270 | snprintf(SNPARGS(action2, 0), "Queue %d", |
---|
271 | cmd->arg1); |
---|
272 | break; |
---|
273 | case O_FORWARD_IP: { |
---|
274 | ipfw_insn_sa *sa = (ipfw_insn_sa *)cmd; |
---|
275 | int len; |
---|
276 | struct in_addr dummyaddr; |
---|
277 | if (sa->sa.sin_addr.s_addr == INADDR_ANY) |
---|
278 | dummyaddr.s_addr = htonl(tablearg); |
---|
279 | else |
---|
280 | dummyaddr.s_addr = sa->sa.sin_addr.s_addr; |
---|
281 | |
---|
282 | len = snprintf(SNPARGS(action2, 0), "Forward to %s", |
---|
283 | inet_ntoa(dummyaddr)); |
---|
284 | |
---|
285 | if (sa->sa.sin_port) |
---|
286 | snprintf(SNPARGS(action2, len), ":%d", |
---|
287 | sa->sa.sin_port); |
---|
288 | } |
---|
289 | break; |
---|
290 | case O_NETGRAPH: |
---|
291 | snprintf(SNPARGS(action2, 0), "Netgraph %d", |
---|
292 | cmd->arg1); |
---|
293 | break; |
---|
294 | case O_NGTEE: |
---|
295 | snprintf(SNPARGS(action2, 0), "Ngtee %d", |
---|
296 | cmd->arg1); |
---|
297 | break; |
---|
298 | case O_NAT: |
---|
299 | action = "Nat"; |
---|
300 | break; |
---|
301 | case O_REASS: |
---|
302 | action = "Reass"; |
---|
303 | break; |
---|
304 | case O_CALLRETURN: |
---|
305 | if (cmd->len & F_NOT) |
---|
306 | action = "Return"; |
---|
307 | else |
---|
308 | snprintf(SNPARGS(action2, 0), "Call %d", |
---|
309 | cmd->arg1); |
---|
310 | break; |
---|
311 | default: |
---|
312 | action = "UNKNOWN"; |
---|
313 | break; |
---|
314 | } |
---|
315 | } |
---|
316 | |
---|
317 | if (hlen == 0) { /* non-ip */ |
---|
318 | snprintf(SNPARGS(proto, 0), "MAC"); |
---|
319 | |
---|
320 | } else { |
---|
321 | int len; |
---|
322 | #ifdef INET6 |
---|
323 | char src[INET6_ADDRSTRLEN + 2], dst[INET6_ADDRSTRLEN + 2]; |
---|
324 | #else |
---|
325 | char src[INET_ADDRSTRLEN], dst[INET_ADDRSTRLEN]; |
---|
326 | #endif |
---|
327 | struct icmphdr *icmp; |
---|
328 | struct tcphdr *tcp; |
---|
329 | struct udphdr *udp; |
---|
330 | #ifdef INET6 |
---|
331 | struct ip6_hdr *ip6 = NULL; |
---|
332 | struct icmp6_hdr *icmp6; |
---|
333 | u_short ip6f_mf; |
---|
334 | #endif |
---|
335 | src[0] = '\0'; |
---|
336 | dst[0] = '\0'; |
---|
337 | #ifdef INET6 |
---|
338 | ip6f_mf = offset & IP6F_MORE_FRAG; |
---|
339 | offset &= IP6F_OFF_MASK; |
---|
340 | |
---|
341 | if (IS_IP6_FLOW_ID(&(args->f_id))) { |
---|
342 | char ip6buf[INET6_ADDRSTRLEN]; |
---|
343 | snprintf(src, sizeof(src), "[%s]", |
---|
344 | ip6_sprintf(ip6buf, &args->f_id.src_ip6)); |
---|
345 | snprintf(dst, sizeof(dst), "[%s]", |
---|
346 | ip6_sprintf(ip6buf, &args->f_id.dst_ip6)); |
---|
347 | |
---|
348 | ip6 = (struct ip6_hdr *)ip; |
---|
349 | tcp = (struct tcphdr *)(((char *)ip) + hlen); |
---|
350 | udp = (struct udphdr *)(((char *)ip) + hlen); |
---|
351 | } else |
---|
352 | #endif |
---|
353 | { |
---|
354 | tcp = L3HDR(struct tcphdr, ip); |
---|
355 | udp = L3HDR(struct udphdr, ip); |
---|
356 | |
---|
357 | inet_ntoa_r(ip->ip_src, src); |
---|
358 | inet_ntoa_r(ip->ip_dst, dst); |
---|
359 | } |
---|
360 | |
---|
361 | switch (args->f_id.proto) { |
---|
362 | case IPPROTO_TCP: |
---|
363 | len = snprintf(SNPARGS(proto, 0), "TCP %s", src); |
---|
364 | if (offset == 0) |
---|
365 | snprintf(SNPARGS(proto, len), ":%d %s:%d", |
---|
366 | ntohs(tcp->th_sport), |
---|
367 | dst, |
---|
368 | ntohs(tcp->th_dport)); |
---|
369 | else |
---|
370 | snprintf(SNPARGS(proto, len), " %s", dst); |
---|
371 | break; |
---|
372 | |
---|
373 | case IPPROTO_UDP: |
---|
374 | len = snprintf(SNPARGS(proto, 0), "UDP %s", src); |
---|
375 | if (offset == 0) |
---|
376 | snprintf(SNPARGS(proto, len), ":%d %s:%d", |
---|
377 | ntohs(udp->uh_sport), |
---|
378 | dst, |
---|
379 | ntohs(udp->uh_dport)); |
---|
380 | else |
---|
381 | snprintf(SNPARGS(proto, len), " %s", dst); |
---|
382 | break; |
---|
383 | |
---|
384 | case IPPROTO_ICMP: |
---|
385 | icmp = L3HDR(struct icmphdr, ip); |
---|
386 | if (offset == 0) |
---|
387 | len = snprintf(SNPARGS(proto, 0), |
---|
388 | "ICMP:%u.%u ", |
---|
389 | icmp->icmp_type, icmp->icmp_code); |
---|
390 | else |
---|
391 | len = snprintf(SNPARGS(proto, 0), "ICMP "); |
---|
392 | len += snprintf(SNPARGS(proto, len), "%s", src); |
---|
393 | snprintf(SNPARGS(proto, len), " %s", dst); |
---|
394 | break; |
---|
395 | #ifdef INET6 |
---|
396 | case IPPROTO_ICMPV6: |
---|
397 | icmp6 = (struct icmp6_hdr *)(((char *)ip) + hlen); |
---|
398 | if (offset == 0) |
---|
399 | len = snprintf(SNPARGS(proto, 0), |
---|
400 | "ICMPv6:%u.%u ", |
---|
401 | icmp6->icmp6_type, icmp6->icmp6_code); |
---|
402 | else |
---|
403 | len = snprintf(SNPARGS(proto, 0), "ICMPv6 "); |
---|
404 | len += snprintf(SNPARGS(proto, len), "%s", src); |
---|
405 | snprintf(SNPARGS(proto, len), " %s", dst); |
---|
406 | break; |
---|
407 | #endif |
---|
408 | default: |
---|
409 | len = snprintf(SNPARGS(proto, 0), "P:%d %s", |
---|
410 | args->f_id.proto, src); |
---|
411 | snprintf(SNPARGS(proto, len), " %s", dst); |
---|
412 | break; |
---|
413 | } |
---|
414 | |
---|
415 | #ifdef INET6 |
---|
416 | if (IS_IP6_FLOW_ID(&(args->f_id))) { |
---|
417 | if (offset & (IP6F_OFF_MASK | IP6F_MORE_FRAG)) |
---|
418 | snprintf(SNPARGS(fragment, 0), |
---|
419 | " (frag %08x:%d@%d%s)", |
---|
420 | args->f_id.extra, |
---|
421 | ntohs(ip6->ip6_plen) - hlen, |
---|
422 | ntohs(offset) << 3, ip6f_mf ? "+" : ""); |
---|
423 | } else |
---|
424 | #endif |
---|
425 | { |
---|
426 | int ipoff, iplen; |
---|
427 | ipoff = ntohs(ip->ip_off); |
---|
428 | iplen = ntohs(ip->ip_len); |
---|
429 | if (ipoff & (IP_MF | IP_OFFMASK)) |
---|
430 | snprintf(SNPARGS(fragment, 0), |
---|
431 | " (frag %d:%d@%d%s)", |
---|
432 | ntohs(ip->ip_id), iplen - (ip->ip_hl << 2), |
---|
433 | offset << 3, |
---|
434 | (ipoff & IP_MF) ? "+" : ""); |
---|
435 | } |
---|
436 | } |
---|
437 | #ifdef __FreeBSD__ |
---|
438 | if (oif || m->m_pkthdr.rcvif) |
---|
439 | log(LOG_SECURITY | LOG_INFO, |
---|
440 | "ipfw: %d %s %s %s via %s%s\n", |
---|
441 | f ? f->rulenum : -1, |
---|
442 | action, proto, oif ? "out" : "in", |
---|
443 | oif ? oif->if_xname : m->m_pkthdr.rcvif->if_xname, |
---|
444 | fragment); |
---|
445 | else |
---|
446 | #endif |
---|
447 | log(LOG_SECURITY | LOG_INFO, |
---|
448 | "ipfw: %d %s %s [no if info]%s\n", |
---|
449 | f ? f->rulenum : -1, |
---|
450 | action, proto, fragment); |
---|
451 | if (limit_reached) |
---|
452 | log(LOG_SECURITY | LOG_NOTICE, |
---|
453 | "ipfw: limit %d reached on entry %d\n", |
---|
454 | limit_reached, f ? f->rulenum : -1); |
---|
455 | } |
---|
456 | /* end of file */ |
---|