*
* Authors:
* Bart De Schuymer <bdschuym@pandora.be>
+ * Harald Welte <laforge@netfilter.org>
*
* April, 2002
*
*/
+#include <linux/in.h>
#include <linux/netfilter_bridge/ebtables.h>
#include <linux/netfilter_bridge/ebt_log.h>
+#include <linux/netfilter.h>
#include <linux/module.h>
#include <linux/ip.h>
+#include <linux/in.h>
#include <linux/if_arp.h>
#include <linux/spinlock.h>
-static spinlock_t ebt_log_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(ebt_log_lock);
static int ebt_log_check(const char *tablename, unsigned int hookmask,
const struct ebt_entry *e, void *data, unsigned int datalen)
}
#define myNIPQUAD(a) a[0], a[1], a[2], a[3]
-static void ebt_log(const struct sk_buff *skb, const struct net_device *in,
- const struct net_device *out, const void *data, unsigned int datalen)
+static void
+ebt_log_packet(unsigned int pf, unsigned int hooknum,
+ const struct sk_buff *skb, const struct net_device *in,
+ const struct net_device *out, const struct nf_loginfo *loginfo,
+ const char *prefix)
{
- struct ebt_log_info *info = (struct ebt_log_info *)data;
- char level_string[4] = "< >";
- union {struct iphdr iph; struct tcpudphdr ports;
- struct arphdr arph; struct arppayload arpp;} u;
+ unsigned int bitmask;
- level_string[1] = '0' + info->loglevel;
spin_lock_bh(&ebt_log_lock);
- printk(level_string);
- printk("%s IN=%s OUT=%s ", info->prefix, in ? in->name : "",
- out ? out->name : "");
+ printk("<%c>%s IN=%s OUT=%s MAC source = ", '0' + loginfo->u.log.level,
+ prefix, in ? in->name : "", out ? out->name : "");
- printk("MAC source = ");
- print_MAC((skb->mac.ethernet)->h_source);
+ print_MAC(eth_hdr(skb)->h_source);
printk("MAC dest = ");
- print_MAC((skb->mac.ethernet)->h_dest);
+ print_MAC(eth_hdr(skb)->h_dest);
+
+ printk("proto = 0x%04x", ntohs(eth_hdr(skb)->h_proto));
- printk("proto = 0x%04x", ntohs(((*skb).mac.ethernet)->h_proto));
+ if (loginfo->type == NF_LOG_TYPE_LOG)
+ bitmask = loginfo->u.log.logflags;
+ else
+ bitmask = NF_LOG_MASK;
- if ((info->bitmask & EBT_LOG_IP) && skb->mac.ethernet->h_proto ==
+ if ((bitmask & EBT_LOG_IP) && eth_hdr(skb)->h_proto ==
htons(ETH_P_IP)){
- if (skb_copy_bits(skb, 0, &u.iph, sizeof(u.iph))) {
+ struct iphdr _iph, *ih;
+
+ ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
+ if (ih == NULL) {
printk(" INCOMPLETE IP header");
goto out;
}
- printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,",
- NIPQUAD(u.iph.saddr), NIPQUAD(u.iph.daddr));
- printk(" IP tos=0x%02X, IP proto=%d", u.iph.tos,
- u.iph.protocol);
- if (u.iph.protocol == IPPROTO_TCP ||
- u.iph.protocol == IPPROTO_UDP) {
- if (skb_copy_bits(skb, u.iph.ihl*4, &u.ports,
- sizeof(u.ports))) {
+ printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u, IP "
+ "tos=0x%02X, IP proto=%d", NIPQUAD(ih->saddr),
+ NIPQUAD(ih->daddr), ih->tos, ih->protocol);
+ if (ih->protocol == IPPROTO_TCP ||
+ ih->protocol == IPPROTO_UDP ||
+ ih->protocol == IPPROTO_SCTP ||
+ ih->protocol == IPPROTO_DCCP) {
+ struct tcpudphdr _ports, *pptr;
+
+ pptr = skb_header_pointer(skb, ih->ihl*4,
+ sizeof(_ports), &_ports);
+ if (pptr == NULL) {
printk(" INCOMPLETE TCP/UDP header");
goto out;
}
- printk(" SPT=%u DPT=%u", ntohs(u.ports.src),
- ntohs(u.ports.dst));
+ printk(" SPT=%u DPT=%u", ntohs(pptr->src),
+ ntohs(pptr->dst));
}
goto out;
}
- if ((info->bitmask & EBT_LOG_ARP) &&
- ((skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) ||
- (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_RARP)))) {
- if (skb_copy_bits(skb, 0, &u.arph, sizeof(u.arph))) {
+ if ((bitmask & EBT_LOG_ARP) &&
+ ((eth_hdr(skb)->h_proto == htons(ETH_P_ARP)) ||
+ (eth_hdr(skb)->h_proto == htons(ETH_P_RARP)))) {
+ struct arphdr _arph, *ah;
+
+ ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
+ if (ah == NULL) {
printk(" INCOMPLETE ARP header");
goto out;
}
printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d",
- ntohs(u.arph.ar_hrd), ntohs(u.arph.ar_pro),
- ntohs(u.arph.ar_op));
+ ntohs(ah->ar_hrd), ntohs(ah->ar_pro),
+ ntohs(ah->ar_op));
/* If it's for Ethernet and the lengths are OK,
* then log the ARP payload */
- if (u.arph.ar_hrd == __constant_htons(1) &&
- u.arph.ar_hln == ETH_ALEN &&
- u.arph.ar_pln == sizeof(uint32_t)) {
- if (skb_copy_bits(skb, sizeof(u.arph), &u.arpp,
- sizeof(u.arpp))) {
+ if (ah->ar_hrd == htons(1) &&
+ ah->ar_hln == ETH_ALEN &&
+ ah->ar_pln == sizeof(uint32_t)) {
+ struct arppayload _arpp, *ap;
+
+ ap = skb_header_pointer(skb, sizeof(_arph),
+ sizeof(_arpp), &_arpp);
+ if (ap == NULL) {
printk(" INCOMPLETE ARP payload");
goto out;
}
printk(" ARP MAC SRC=");
- print_MAC(u.arpp.mac_src);
+ print_MAC(ap->mac_src);
printk(" ARP IP SRC=%u.%u.%u.%u",
- myNIPQUAD(u.arpp.ip_src));
+ myNIPQUAD(ap->ip_src));
printk(" ARP MAC DST=");
- print_MAC(u.arpp.mac_dst);
+ print_MAC(ap->mac_dst);
printk(" ARP IP DST=%u.%u.%u.%u",
- myNIPQUAD(u.arpp.ip_dst));
+ myNIPQUAD(ap->ip_dst));
}
}
out:
printk("\n");
spin_unlock_bh(&ebt_log_lock);
+
+}
+
+static void ebt_log(const struct sk_buff *skb, unsigned int hooknr,
+ const struct net_device *in, const struct net_device *out,
+ const void *data, unsigned int datalen)
+{
+ struct ebt_log_info *info = (struct ebt_log_info *)data;
+ struct nf_loginfo li;
+
+ li.type = NF_LOG_TYPE_LOG;
+ li.u.log.level = info->loglevel;
+ li.u.log.logflags = info->bitmask;
+
+ if (info->bitmask & EBT_LOG_NFLOG)
+ nf_log_packet(PF_BRIDGE, hooknr, skb, in, out, &li,
+ "%s", info->prefix);
+ else
+ ebt_log_packet(PF_BRIDGE, hooknr, skb, in, out, &li,
+ info->prefix);
}
static struct ebt_watcher log =
.me = THIS_MODULE,
};
-static int __init init(void)
+static struct nf_logger ebt_log_logger = {
+ .name = "ebt_log",
+ .logfn = &ebt_log_packet,
+ .me = THIS_MODULE,
+};
+
+static int __init ebt_log_init(void)
{
- return ebt_register_watcher(&log);
+ int ret;
+
+ ret = ebt_register_watcher(&log);
+ if (ret < 0)
+ return ret;
+ if (nf_log_register(PF_BRIDGE, &ebt_log_logger) < 0) {
+ printk(KERN_WARNING "ebt_log: not logging via system console "
+ "since somebody else already registered for PF_INET\n");
+ /* we cannot make module load fail here, since otherwise
+ * ebtables userspace would abort */
+ }
+
+ return 0;
}
-static void __exit fini(void)
+static void __exit ebt_log_fini(void)
{
+ nf_log_unregister_logger(&ebt_log_logger);
ebt_unregister_watcher(&log);
}
-module_init(init);
-module_exit(fini);
+module_init(ebt_log_init);
+module_exit(ebt_log_fini);
MODULE_LICENSE("GPL");