[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]

FreeBSD/Linux Kernel Cross Reference
sys/netinet/ip_fw_pfil.c

Version: -  FREEBSD  -  FREEBSD7  -  FREEBSD70  -  FREEBSD6  -  FREEBSD64  -  FREEBSD63  -  FREEBSD62  -  FREEBSD61  -  FREEBSD60  -  FREEBSD5  -  FREEBSD55  -  FREEBSD54  -  FREEBSD53  -  FREEBSD52  -  FREEBSD51  -  FREEBSD50  -  FREEBSD4  -  FREEBSD3  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  OPENSOLARIS  -  minix-3-1-1  -  TRUSTEDBSD-SEBSD  -  FREEBSD-LIBC  -  FREEBSD7-LIBC  -  FREEBSD6-LIBC  -  GLIBC27 
SearchContext: -  none  -  excerpts  -  bigexcerpts 

  1 /*-
  2  * Copyright (c) 2004 Andre Oppermann, Internet Business Solutions AG
  3  * All rights reserved.
  4  *
  5  * Redistribution and use in source and binary forms, with or without
  6  * modification, are permitted provided that the following conditions
  7  * are met:
  8  * 1. Redistributions of source code must retain the above copyright
  9  *    notice, this list of conditions and the following disclaimer.
 10  * 2. Redistributions in binary form must reproduce the above copyright
 11  *    notice, this list of conditions and the following disclaimer in the
 12  *    documentation and/or other materials provided with the distribution.
 13  *
 14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 24  * SUCH DAMAGE.
 25  */
 26 
 27 #include <sys/cdefs.h>
 28 __FBSDID("$FreeBSD: src/sys/netinet/ip_fw_pfil.c,v 1.29 2008/11/26 22:32:07 zec Exp $");
 29 
 30 #if !defined(KLD_MODULE)
 31 #include "opt_ipfw.h"
 32 #include "opt_ipdn.h"
 33 #include "opt_inet.h"
 34 #ifndef INET
 35 #error IPFIREWALL requires INET.
 36 #endif /* INET */
 37 #endif /* KLD_MODULE */
 38 #include "opt_inet6.h"
 39 
 40 #include <sys/param.h>
 41 #include <sys/systm.h>
 42 #include <sys/malloc.h>
 43 #include <sys/mbuf.h>
 44 #include <sys/module.h>
 45 #include <sys/kernel.h>
 46 #include <sys/socket.h>
 47 #include <sys/socketvar.h>
 48 #include <sys/sysctl.h>
 49 #include <sys/ucred.h>
 50 #include <sys/vimage.h>
 51 
 52 #include <net/if.h>
 53 #include <net/route.h>
 54 #include <net/pfil.h>
 55 
 56 #include <netinet/in.h>
 57 #include <netinet/in_systm.h>
 58 #include <netinet/in_var.h>
 59 #include <netinet/ip.h>
 60 #include <netinet/ip_var.h>
 61 #include <netinet/ip_fw.h>
 62 #include <netinet/ip_divert.h>
 63 #include <netinet/ip_dummynet.h>
 64 
 65 #include <netgraph/ng_ipfw.h>
 66 
 67 #include <machine/in_cksum.h>
 68 
 69 int fw_enable = 1;
 70 #ifdef INET6
 71 int fw6_enable = 1;
 72 #endif
 73 
 74 int ipfw_chg_hook(SYSCTL_HANDLER_ARGS);
 75 
 76 /* Dummynet hooks. */
 77 ip_dn_ruledel_t *ip_dn_ruledel_ptr = NULL;
 78 
 79 /* Divert hooks. */
 80 ip_divert_packet_t *ip_divert_ptr = NULL;
 81 
 82 /* ng_ipfw hooks. */
 83 ng_ipfw_input_t *ng_ipfw_input_p = NULL;
 84 
 85 /* Forward declarations. */
 86 static int      ipfw_divert(struct mbuf **, int, int);
 87 #define DIV_DIR_IN      1
 88 #define DIV_DIR_OUT     0
 89 
 90 int
 91 ipfw_check_in(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
 92     struct inpcb *inp)
 93 {
 94         struct ip_fw_args args;
 95         struct ng_ipfw_tag *ng_tag;
 96         struct m_tag *dn_tag;
 97         int ipfw = 0;
 98         int divert;
 99         int tee;
100 #ifdef IPFIREWALL_FORWARD
101         struct m_tag *fwd_tag;
102 #endif
103 
104         KASSERT(dir == PFIL_IN, ("ipfw_check_in wrong direction!"));
105 
106         bzero(&args, sizeof(args));
107 
108         ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0,
109             NULL);
110         if (ng_tag != NULL) {
111                 KASSERT(ng_tag->dir == NG_IPFW_IN,
112                     ("ng_ipfw tag with wrong direction"));
113                 args.rule = ng_tag->rule;
114                 m_tag_delete(*m0, (struct m_tag *)ng_tag);
115         }
116 
117 again:
118         dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
119         if (dn_tag != NULL){
120                 struct dn_pkt_tag *dt;
121 
122                 dt = (struct dn_pkt_tag *)(dn_tag+1);
123                 args.rule = dt->rule;
124 
125                 m_tag_delete(*m0, dn_tag);
126         }
127 
128         args.m = *m0;
129         args.inp = inp;
130         ipfw = ipfw_chk(&args);
131         *m0 = args.m;
132         tee = 0;
133 
134         KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
135             __func__));
136 
137         switch (ipfw) {
138         case IP_FW_PASS:
139                 if (args.next_hop == NULL)
140                         goto pass;
141 
142 #ifdef IPFIREWALL_FORWARD
143                 fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
144                                 sizeof(struct sockaddr_in), M_NOWAIT);
145                 if (fwd_tag == NULL)
146                         goto drop;
147                 bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
148                 m_tag_prepend(*m0, fwd_tag);
149 
150                 if (in_localip(args.next_hop->sin_addr))
151                         (*m0)->m_flags |= M_FASTFWD_OURS;
152                 goto pass;
153 #endif
154                 break;                  /* not reached */
155 
156         case IP_FW_DENY:
157                 goto drop;
158                 break;                  /* not reached */
159 
160         case IP_FW_DUMMYNET:
161                 if (!DUMMYNET_LOADED)
162                         goto drop;
163                 if (mtod(*m0, struct ip *)->ip_v == 4)
164                         ip_dn_io_ptr(m0, DN_TO_IP_IN, &args);
165                 else if (mtod(*m0, struct ip *)->ip_v == 6)
166                         ip_dn_io_ptr(m0, DN_TO_IP6_IN, &args);
167                 if (*m0 != NULL)
168                         goto again;
169                 return 0;               /* packet consumed */
170 
171         case IP_FW_TEE:
172                 tee = 1;
173                 /* fall through */
174 
175         case IP_FW_DIVERT:
176                 divert = ipfw_divert(m0, DIV_DIR_IN, tee);
177                 if (divert) {
178                         *m0 = NULL;
179                         return 0;       /* packet consumed */
180                 } else {
181                         args.rule = NULL;
182                         goto again;     /* continue with packet */
183                 }
184 
185         case IP_FW_NGTEE:
186                 if (!NG_IPFW_LOADED)
187                         goto drop;
188                 (void)ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 1);
189                 goto again;             /* continue with packet */
190 
191         case IP_FW_NETGRAPH:
192                 if (!NG_IPFW_LOADED)
193                         goto drop;
194                 return ng_ipfw_input_p(m0, NG_IPFW_IN, &args, 0);
195                 
196         case IP_FW_NAT:
197                 goto again;             /* continue with packet */
198 
199         default:
200                 KASSERT(0, ("%s: unknown retval", __func__));
201         }
202 
203 drop:
204         if (*m0)
205                 m_freem(*m0);
206         *m0 = NULL;
207         return (EACCES);
208 pass:
209         return 0;       /* not filtered */
210 }
211 
212 int
213 ipfw_check_out(void *arg, struct mbuf **m0, struct ifnet *ifp, int dir,
214     struct inpcb *inp)
215 {
216         struct ip_fw_args args;
217         struct ng_ipfw_tag *ng_tag;
218         struct m_tag *dn_tag;
219         int ipfw = 0;
220         int divert;
221         int tee;
222 #ifdef IPFIREWALL_FORWARD
223         struct m_tag *fwd_tag;
224 #endif
225 
226         KASSERT(dir == PFIL_OUT, ("ipfw_check_out wrong direction!"));
227 
228         bzero(&args, sizeof(args));
229 
230         ng_tag = (struct ng_ipfw_tag *)m_tag_locate(*m0, NGM_IPFW_COOKIE, 0,
231             NULL);
232         if (ng_tag != NULL) {
233                 KASSERT(ng_tag->dir == NG_IPFW_OUT,
234                     ("ng_ipfw tag with wrong direction"));
235                 args.rule = ng_tag->rule;
236                 m_tag_delete(*m0, (struct m_tag *)ng_tag);
237         }
238 
239 again:
240         dn_tag = m_tag_find(*m0, PACKET_TAG_DUMMYNET, NULL);
241         if (dn_tag != NULL) {
242                 struct dn_pkt_tag *dt;
243 
244                 dt = (struct dn_pkt_tag *)(dn_tag+1);
245                 args.rule = dt->rule;
246 
247                 m_tag_delete(*m0, dn_tag);
248         }
249 
250         args.m = *m0;
251         args.oif = ifp;
252         args.inp = inp;
253         ipfw = ipfw_chk(&args);
254         *m0 = args.m;
255         tee = 0;
256 
257         KASSERT(*m0 != NULL || ipfw == IP_FW_DENY, ("%s: m0 is NULL",
258             __func__));
259 
260         switch (ipfw) {
261         case IP_FW_PASS:
262                 if (args.next_hop == NULL)
263                         goto pass;
264 #ifdef IPFIREWALL_FORWARD
265                 /* Overwrite existing tag. */
266                 fwd_tag = m_tag_find(*m0, PACKET_TAG_IPFORWARD, NULL);
267                 if (fwd_tag == NULL) {
268                         fwd_tag = m_tag_get(PACKET_TAG_IPFORWARD,
269                                 sizeof(struct sockaddr_in), M_NOWAIT);
270                         if (fwd_tag == NULL)
271                                 goto drop;
272                 } else
273                         m_tag_unlink(*m0, fwd_tag);
274                 bcopy(args.next_hop, (fwd_tag+1), sizeof(struct sockaddr_in));
275                 m_tag_prepend(*m0, fwd_tag);
276 
277                 if (in_localip(args.next_hop->sin_addr))
278                         (*m0)->m_flags |= M_FASTFWD_OURS;
279                 goto pass;
280 #endif
281                 break;                  /* not reached */
282 
283         case IP_FW_DENY:
284                 goto drop;
285                 break;                  /* not reached */
286 
287         case IP_FW_DUMMYNET:
288                 if (!DUMMYNET_LOADED)
289                         break;
290                 if (mtod(*m0, struct ip *)->ip_v == 4)
291                         ip_dn_io_ptr(m0, DN_TO_IP_OUT, &args);
292                 else if (mtod(*m0, struct ip *)->ip_v == 6)
293                         ip_dn_io_ptr(m0, DN_TO_IP6_OUT, &args);
294                 if (*m0 != NULL)
295                         goto again;
296                 return 0;               /* packet consumed */
297 
298                 break;
299 
300         case IP_FW_TEE:
301                 tee = 1;
302                 /* fall through */
303 
304         case IP_FW_DIVERT:
305                 divert = ipfw_divert(m0, DIV_DIR_OUT, tee);
306                 if (divert) {
307                         *m0 = NULL;
308                         return 0;       /* packet consumed */
309                 } else {
310                         args.rule = NULL;
311                         goto again;     /* continue with packet */
312                 }
313 
314         case IP_FW_NGTEE:
315                 if (!NG_IPFW_LOADED)
316                         goto drop;
317                 (void)ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 1);
318                 goto again;             /* continue with packet */
319 
320         case IP_FW_NETGRAPH:
321                 if (!NG_IPFW_LOADED)
322                         goto drop;
323                 return ng_ipfw_input_p(m0, NG_IPFW_OUT, &args, 0);
324 
325         case IP_FW_NAT:
326                 goto again;             /* continue with packet */
327                 
328         default:
329                 KASSERT(0, ("%s: unknown retval", __func__));
330         }
331 
332 drop:
333         if (*m0)
334                 m_freem(*m0);
335         *m0 = NULL;
336         return (EACCES);
337 pass:
338         return 0;       /* not filtered */
339 }
340 
341 static int
342 ipfw_divert(struct mbuf **m, int incoming, int tee)
343 {
344         /*
345          * ipfw_chk() has already tagged the packet with the divert tag.
346          * If tee is set, copy packet and return original.
347          * If not tee, consume packet and send it to divert socket.
348          */
349         struct mbuf *clone, *reass;
350         struct ip *ip;
351         int hlen;
352 
353         reass = NULL;
354 
355         /* Is divert module loaded? */
356         if (ip_divert_ptr == NULL)
357                 goto nodivert;
358 
359         /* Cloning needed for tee? */
360         if (tee)
361                 clone = m_dup(*m, M_DONTWAIT);
362         else
363                 clone = *m;
364 
365         /* In case m_dup was unable to allocate mbufs. */
366         if (clone == NULL)
367                 goto teeout;
368 
369         /*
370          * Divert listeners can only handle non-fragmented packets.
371          * However when tee is set we will *not* de-fragment the packets;
372          * Doing do would put the reassembly into double-jeopardy.  On top
373          * of that someone doing a tee will probably want to get the packet
374          * in its original form.
375          */
376         ip = mtod(clone, struct ip *);
377         if (!tee && ip->ip_off & (IP_MF | IP_OFFMASK)) {
378 
379                 /* Reassemble packet. */
380                 reass = ip_reass(clone);
381 
382                 /*
383                  * IP header checksum fixup after reassembly and leave header
384                  * in network byte order.
385                  */
386                 if (reass != NULL) {
387                         ip = mtod(reass, struct ip *);
388                         hlen = ip->ip_hl << 2;
389                         ip->ip_len = htons(ip->ip_len);
390                         ip->ip_off = htons(ip->ip_off);
391                         ip->ip_sum = 0;
392                         if (hlen == sizeof(struct ip))
393                                 ip->ip_sum = in_cksum_hdr(ip);
394                         else
395                                 ip->ip_sum = in_cksum(reass, hlen);
396                         clone = reass;
397                 } else
398                         clone = NULL;
399         } else {
400                 /* Convert header to network byte order. */
401                 ip->ip_len = htons(ip->ip_len);
402                 ip->ip_off = htons(ip->ip_off);
403         }
404 
405         /* Do the dirty job... */
406         if (clone && ip_divert_ptr != NULL)
407                 ip_divert_ptr(clone, incoming);
408 
409 teeout:
410         /*
411          * For tee we leave the divert tag attached to original packet.
412          * It will then continue rule evaluation after the tee rule.
413          */
414         if (tee)
415                 return 0;
416 
417         /* Packet diverted and consumed */
418         return 1;
419 
420 nodivert:
421         m_freem(*m);
422         return 1;
423 }
424 
425 static int
426 ipfw_hook(void)
427 {
428         struct pfil_head *pfh_inet;
429 
430         pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
431         if (pfh_inet == NULL)
432                 return ENOENT;
433 
434         pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
435         pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
436 
437         return 0;
438 }
439 
440 static int
441 ipfw_unhook(void)
442 {
443         struct pfil_head *pfh_inet;
444 
445         pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET);
446         if (pfh_inet == NULL)
447                 return ENOENT;
448 
449         pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet);
450         pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet);
451 
452         return 0;
453 }
454 
455 #ifdef INET6
456 static int
457 ipfw6_hook(void)
458 {
459         struct pfil_head *pfh_inet6;
460 
461         pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
462         if (pfh_inet6 == NULL)
463                 return ENOENT;
464 
465         pfil_add_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
466         pfil_add_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
467 
468         return 0;
469 }
470 
471 static int
472 ipfw6_unhook(void)
473 {
474         struct pfil_head *pfh_inet6;
475 
476         pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6);
477         if (pfh_inet6 == NULL)
478                 return ENOENT;
479 
480         pfil_remove_hook(ipfw_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6);
481         pfil_remove_hook(ipfw_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6);
482 
483         return 0;
484 }
485 #endif /* INET6 */
486 
487 int
488 ipfw_chg_hook(SYSCTL_HANDLER_ARGS)
489 {
490         INIT_VNET_IPFW(curvnet);
491         int enable = *(int *)arg1;
492         int error;
493 
494         error = sysctl_handle_int(oidp, &enable, 0, req);
495         if (error)
496                 return (error);
497 
498         enable = (enable) ? 1 : 0;
499 
500         if (enable == *(int *)arg1)
501                 return (0);
502 
503         if (arg1 == &V_fw_enable) {
504                 if (enable)
505                         error = ipfw_hook();
506                 else
507                         error = ipfw_unhook();
508         }
509 #ifdef INET6
510         if (arg1 == &V_fw6_enable) {
511                 if (enable)
512                         error = ipfw6_hook();
513                 else
514                         error = ipfw6_unhook();
515         }
516 #endif
517 
518         if (error)
519                 return (error);
520 
521         *(int *)arg1 = enable;
522 
523         return (0);
524 }
525 
526 static int
527 ipfw_modevent(module_t mod, int type, void *unused)
528 {
529         int err = 0;
530 
531         switch (type) {
532         case MOD_LOAD:
533                 if ((err = ipfw_init()) != 0) {
534                         printf("ipfw_init() error\n");
535                         break;
536                 }
537                 if ((err = ipfw_hook()) != 0) {
538                         printf("ipfw_hook() error\n");
539                         break;
540                 }
541 #ifdef INET6
542                 if ((err = ipfw6_hook()) != 0) {
543                         printf("ipfw_hook() error\n");
544                         break;
545                 }
546 #endif
547                 break;
548 
549         case MOD_UNLOAD:
550                 if ((err = ipfw_unhook()) > 0)
551                         break;
552 #ifdef INET6
553                 if ((err = ipfw6_unhook()) > 0)
554                         break;
555 #endif
556                 ipfw_destroy();
557                 break;
558 
559         default:
560                 return EOPNOTSUPP;
561                 break;
562         }
563         return err;
564 }
565 
566 static moduledata_t ipfwmod = {
567         "ipfw",
568         ipfw_modevent,
569         0
570 };
571 DECLARE_MODULE(ipfw, ipfwmod, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_ANY - 256);
572 MODULE_VERSION(ipfw, 2);
573 

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.