Re: [PATCH] ipfw logging through tcpdump ?

From: David Horn <dhorn2000_at_gmail.com>
Date: Tue, 15 Dec 2009 00:23:45 -0500
On Mon, Dec 14, 2009 at 6:53 PM, Luigi Rizzo <rizzo_at_iet.unipi.it> wrote:
> The following ipfw patch (which i wrote back in 2001/2002) makes
> ipfw logging possible through tcpdump -- it works by passing to the
> fake device 'ipfw0' all packets matching rules marked 'log' .
> The use is very simple -- to test it just do
>
>        ipfw add 100 count log ip from any to any
>
> and then
>
>        tcpdump -ni ipfw0
>
> will show all matching traffic.
>
> I think this is a quite convenient and flexible option, so if there
> are no objections I plan to commit it to head.
>
>        cheers
>        luigi
>
> Index: ../head/sys/netinet/ipfw/ip_fw2.c
> ===================================================================
> --- ../head/sys/netinet/ipfw/ip_fw2.c   (revision 200551)
> +++ ../head/sys/netinet/ipfw/ip_fw2.c   (working copy)
> _at__at_ -65,6 +65,8 _at__at_
>  #include <sys/ucred.h>
>  #include <net/ethernet.h> /* for ETHERTYPE_IP */
>  #include <net/if.h>
> +#include <net/if_types.h>      /* for IFT_ETHER */
> +#include <net/bpf.h>           /* for BPF */
>  #include <net/radix.h>
>  #include <net/route.h>
>  #include <net/pf_mtag.h>
> _at__at_ -338,6 +340,15 _at__at_
>     "Enable keepalives for dyn. rules");
>  #endif /* SYSCTL_NODE */
>
> +#ifdef DEV_IPFW
> +static struct ifnet *ifn;      /* hook to attach to bpf */
> +static int
> +ipfw_ifnet_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr)
> +{
> +       return EINVAL;
> +}
> +#endif
> +
>  /*
>  * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T
>  * Other macros just cast void * into the appropriate type
> _at__at_ -3056,6 +3067,29 _at__at_
>                                if (V_fw_verbose)
>                                        ipfw_log(f, hlen, args, m,
>                                            oif, offset, tablearg, ip);
> +#ifdef DEV_IPFW
> +                               else if (ifn && ifn->if_bpf != NULL) {
> +                                   /* This kludge is OK; BPF treats
> +                                    *the "mbuf" as read-only */
> +                                   struct m_hdr mh;
> +                                   mh.mh_next = m;
> +                                   mh.mh_len = ETHER_HDR_LEN;
> +                                   if (args->eh)       /* layer2, complete */
> +                                       mh.mh_data = (char *)args->eh;
> +                                   else {
> +                                       /* fake header and restore wire format*/
> +                                       mh.mh_data = "DDDDDDSSSSSS\x08\x00";
> +                                       ip->ip_off = ntohs(ip->ip_off);
> +                                       ip->ip_len = ntohs(ip->ip_len);
> +                                   }
> +                                   BPF_MTAP(ifn, (struct mbuf *)&mh);
> +                                   if (args->eh == NULL) {
> +                                       /* restore IP format */
> +                                       ip->ip_off = htons(ip->ip_off);
> +                                       ip->ip_len = htons(ip->ip_len);
> +                                   }
> +                               }
> +#endif /* DEV_IPFW */
>                                match = 1;
>                                break;
>
> _at__at_ -4830,6 +4864,19 _at__at_
>                printf("limited to %d packets/entry by default\n",
>                    V_verbose_limit);
>
> +#ifdef DEV_IPFW        /** bpf code **/
> +       ifn = if_alloc(IFT_ETHER);
> +       if_initname(ifn, "ipfw", 0);
> +       ifn->if_mtu = 65536;
> +       ifn->if_flags = IFF_UP | IFF_SIMPLEX | IFF_MULTICAST;
> +       ifn->if_ioctl = ipfw_ifnet_ioctl;        /* getaddr */
> +       ifn->if_addrlen = 6;
> +       ifn->if_hdrlen = 14;
> +       if_attach(ifn);
> +       ifn->if_baudrate = IF_Mbps(10);
> +       bpfattach(ifn, DLT_EN10MB, 14);
> +#endif /** end bpf code **/
> +
>        return (error);
>  }
>
> _at__at_ -4840,6 +4887,11 _at__at_
>  ipfw_destroy(void)
>  {
>
> +#ifdef DEV_IPFW
> +       ether_ifdetach(ifn);
> +       if_free(ifn);
> +       ifn = NULL;
> +#endif
>        uma_zdestroy(ipfw_dyn_rule_zone);
>        IPFW_DYN_LOCK_DESTROY();
>        printf("IP firewall unloaded\n");

Code works well for me with latest current r200562, although a bit of
extra fuzz factor was needed for the patch to apply cleanly.

My only comment is that I would prefer a tunable or sysctl to having
to recompile with CFLAGS+= -DDEV_IPFW added to the ipfw module
Makefile.

Very useful code.

---Dave Horn
Received on Tue Dec 15 2009 - 04:55:26 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:39:59 UTC