Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / net / ipv4 / netfilter / ipt_LOG.c
index 0f1b881..b98f7b0 100644 (file)
@@ -27,10 +27,6 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Netfilter Core Team <coreteam@netfilter.org>");
 MODULE_DESCRIPTION("iptables syslog logging module");
 
-static unsigned int nflog = 1;
-MODULE_PARM(nflog, "i");
-MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
 #if 0
 #define DEBUGP printk
 #else
@@ -38,16 +34,23 @@ MODULE_PARM_DESC(nflog, "register as internal netfilter logging module");
 #endif
 
 /* Use lock to serialize, so printks don't overlap */
-static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(log_lock);
 
 /* One level of recursion won't kill us */
-static void dump_packet(const struct ipt_log_info *info,
+static void dump_packet(const struct nf_loginfo *info,
                        const struct sk_buff *skb,
                        unsigned int iphoff)
 {
-       struct iphdr iph;
+       struct iphdr _iph, *ih;
+       unsigned int logflags;
 
-       if (skb_copy_bits(skb, iphoff, &iph, sizeof(iph)) < 0) {
+       if (info->type == NF_LOG_TYPE_LOG)
+               logflags = info->u.log.logflags;
+       else
+               logflags = NF_LOG_MASK;
+
+       ih = skb_header_pointer(skb, iphoff, sizeof(_iph), &_iph);
+       if (ih == NULL) {
                printk("TRUNCATED");
                return;
        }
@@ -56,32 +59,34 @@ static void dump_packet(const struct ipt_log_info *info,
         * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */
        /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
        printk("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ",
-              NIPQUAD(iph.saddr), NIPQUAD(iph.daddr));
+              NIPQUAD(ih->saddr), NIPQUAD(ih->daddr));
 
        /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */
        printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
-              ntohs(iph.tot_len), iph.tos & IPTOS_TOS_MASK,
-              iph.tos & IPTOS_PREC_MASK, iph.ttl, ntohs(iph.id));
+              ntohs(ih->tot_len), ih->tos & IPTOS_TOS_MASK,
+              ih->tos & IPTOS_PREC_MASK, ih->ttl, ntohs(ih->id));
 
        /* Max length: 6 "CE DF MF " */
-       if (ntohs(iph.frag_off) & IP_CE)
+       if (ntohs(ih->frag_off) & IP_CE)
                printk("CE ");
-       if (ntohs(iph.frag_off) & IP_DF)
+       if (ntohs(ih->frag_off) & IP_DF)
                printk("DF ");
-       if (ntohs(iph.frag_off) & IP_MF)
+       if (ntohs(ih->frag_off) & IP_MF)
                printk("MF ");
 
        /* Max length: 11 "FRAG:65535 " */
-       if (ntohs(iph.frag_off) & IP_OFFSET)
-               printk("FRAG:%u ", ntohs(iph.frag_off) & IP_OFFSET);
+       if (ntohs(ih->frag_off) & IP_OFFSET)
+               printk("FRAG:%u ", ntohs(ih->frag_off) & IP_OFFSET);
 
-       if ((info->logflags & IPT_LOG_IPOPT)
-           && iph.ihl * 4 != sizeof(struct iphdr)) {
-               unsigned char opt[4 * 15 - sizeof(struct iphdr)];
+       if ((logflags & IPT_LOG_IPOPT)
+           && ih->ihl * 4 > sizeof(struct iphdr)) {
+               unsigned char _opt[4 * 15 - sizeof(struct iphdr)], *op;
                unsigned int i, optsize;
 
-               optsize = iph.ihl * 4 - sizeof(struct iphdr);
-               if (skb_copy_bits(skb, iphoff+sizeof(iph), opt, optsize) < 0) {
+               optsize = ih->ihl * 4 - sizeof(struct iphdr);
+               op = skb_header_pointer(skb, iphoff+sizeof(_iph),
+                                       optsize, _opt);
+               if (op == NULL) {
                        printk("TRUNCATED");
                        return;
                }
@@ -89,67 +94,71 @@ static void dump_packet(const struct ipt_log_info *info,
                /* Max length: 127 "OPT (" 15*4*2chars ") " */
                printk("OPT (");
                for (i = 0; i < optsize; i++)
-                       printk("%02X", opt[i]);
+                       printk("%02X", op[i]);
                printk(") ");
        }
 
-       switch (iph.protocol) {
+       switch (ih->protocol) {
        case IPPROTO_TCP: {
-               struct tcphdr tcph;
+               struct tcphdr _tcph, *th;
 
                /* Max length: 10 "PROTO=TCP " */
                printk("PROTO=TCP ");
 
-               if (ntohs(iph.frag_off) & IP_OFFSET)
+               if (ntohs(ih->frag_off) & IP_OFFSET)
                        break;
 
                /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               if (skb_copy_bits(skb, iphoff+iph.ihl*4, &tcph, sizeof(tcph))
-                   < 0) {
+               th = skb_header_pointer(skb, iphoff + ih->ihl * 4,
+                                       sizeof(_tcph), &_tcph);
+               if (th == NULL) {
                        printk("INCOMPLETE [%u bytes] ",
-                              skb->len - iphoff - iph.ihl*4);
+                              skb->len - iphoff - ih->ihl*4);
                        break;
                }
 
                /* Max length: 20 "SPT=65535 DPT=65535 " */
                printk("SPT=%u DPT=%u ",
-                      ntohs(tcph.source), ntohs(tcph.dest));
+                      ntohs(th->source), ntohs(th->dest));
                /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
-               if (info->logflags & IPT_LOG_TCPSEQ)
+               if (logflags & IPT_LOG_TCPSEQ)
                        printk("SEQ=%u ACK=%u ",
-                              ntohl(tcph.seq), ntohl(tcph.ack_seq));
+                              ntohl(th->seq), ntohl(th->ack_seq));
                /* Max length: 13 "WINDOW=65535 " */
-               printk("WINDOW=%u ", ntohs(tcph.window));
+               printk("WINDOW=%u ", ntohs(th->window));
                /* Max length: 9 "RES=0x3F " */
-               printk("RES=0x%02x ", (u8)(ntohl(tcp_flag_word(&tcph) & TCP_RESERVED_BITS) >> 22));
+               printk("RES=0x%02x ", (u8)(ntohl(tcp_flag_word(th) & TCP_RESERVED_BITS) >> 22));
                /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
-               if (tcph.cwr)
+               if (th->cwr)
                        printk("CWR ");
-               if (tcph.ece)
+               if (th->ece)
                        printk("ECE ");
-               if (tcph.urg)
+               if (th->urg)
                        printk("URG ");
-               if (tcph.ack)
+               if (th->ack)
                        printk("ACK ");
-               if (tcph.psh)
+               if (th->psh)
                        printk("PSH ");
-               if (tcph.rst)
+               if (th->rst)
                        printk("RST ");
-               if (tcph.syn)
+               if (th->syn)
                        printk("SYN ");
-               if (tcph.fin)
+               if (th->fin)
                        printk("FIN ");
                /* Max length: 11 "URGP=65535 " */
-               printk("URGP=%u ", ntohs(tcph.urg_ptr));
+               printk("URGP=%u ", ntohs(th->urg_ptr));
 
-               if ((info->logflags & IPT_LOG_TCPOPT)
-                   && tcph.doff * 4 != sizeof(struct tcphdr)) {
-                       unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
+               if ((logflags & IPT_LOG_TCPOPT)
+                   && th->doff * 4 > sizeof(struct tcphdr)) {
+                       unsigned char _opt[4 * 15 - sizeof(struct tcphdr)];
+                       unsigned char *op;
                        unsigned int i, optsize;
 
-                       optsize = tcph.doff * 4 - sizeof(struct tcphdr);
-                       if (skb_copy_bits(skb, iphoff+iph.ihl*4 + sizeof(tcph),
-                                         opt, optsize) < 0) {
+                       optsize = th->doff * 4 - sizeof(struct tcphdr);
+                       op = skb_header_pointer(skb,
+                                               iphoff+ih->ihl*4+sizeof(_tcph),
+                                               optsize, _opt);
+                       if (op == NULL) {
                                printk("TRUNCATED");
                                return;
                        }
@@ -157,49 +166,50 @@ static void dump_packet(const struct ipt_log_info *info,
                        /* Max length: 127 "OPT (" 15*4*2chars ") " */
                        printk("OPT (");
                        for (i = 0; i < optsize; i++)
-                               printk("%02X", opt[i]);
+                               printk("%02X", op[i]);
                        printk(") ");
                }
                break;
        }
        case IPPROTO_UDP: {
-               struct udphdr udph;
+               struct udphdr _udph, *uh;
 
                /* Max length: 10 "PROTO=UDP " */
                printk("PROTO=UDP ");
 
-               if (ntohs(iph.frag_off) & IP_OFFSET)
+               if (ntohs(ih->frag_off) & IP_OFFSET)
                        break;
 
                /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               if (skb_copy_bits(skb, iphoff+iph.ihl*4, &udph, sizeof(udph))
-                   < 0) {
+               uh = skb_header_pointer(skb, iphoff+ih->ihl*4,
+                                       sizeof(_udph), &_udph);
+               if (uh == NULL) {
                        printk("INCOMPLETE [%u bytes] ",
-                              skb->len - iphoff - iph.ihl*4);
+                              skb->len - iphoff - ih->ihl*4);
                        break;
                }
 
                /* Max length: 20 "SPT=65535 DPT=65535 " */
                printk("SPT=%u DPT=%u LEN=%u ",
-                      ntohs(udph.source), ntohs(udph.dest),
-                      ntohs(udph.len));
+                      ntohs(uh->source), ntohs(uh->dest),
+                      ntohs(uh->len));
                break;
        }
        case IPPROTO_ICMP: {
-               struct icmphdr icmph;
-               static size_t required_len[NR_ICMP_TYPES+1]
+               struct icmphdr _icmph, *ich;
+               static const size_t required_len[NR_ICMP_TYPES+1]
                        = { [ICMP_ECHOREPLY] = 4,
                            [ICMP_DEST_UNREACH]
-                           = 8 + sizeof(struct iphdr) + 8,
+                           = 8 + sizeof(struct iphdr),
                            [ICMP_SOURCE_QUENCH]
-                           = 8 + sizeof(struct iphdr) + 8,
+                           = 8 + sizeof(struct iphdr),
                            [ICMP_REDIRECT]
-                           = 8 + sizeof(struct iphdr) + 8,
+                           = 8 + sizeof(struct iphdr),
                            [ICMP_ECHO] = 4,
                            [ICMP_TIME_EXCEEDED]
-                           = 8 + sizeof(struct iphdr) + 8,
+                           = 8 + sizeof(struct iphdr),
                            [ICMP_PARAMETERPROB]
-                           = 8 + sizeof(struct iphdr) + 8,
+                           = 8 + sizeof(struct iphdr),
                            [ICMP_TIMESTAMP] = 20,
                            [ICMP_TIMESTAMPREPLY] = 20,
                            [ICMP_ADDRESS] = 12,
@@ -208,47 +218,48 @@ static void dump_packet(const struct ipt_log_info *info,
                /* Max length: 11 "PROTO=ICMP " */
                printk("PROTO=ICMP ");
 
-               if (ntohs(iph.frag_off) & IP_OFFSET)
+               if (ntohs(ih->frag_off) & IP_OFFSET)
                        break;
 
                /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               if (skb_copy_bits(skb, iphoff+iph.ihl*4, &icmph, sizeof(icmph))
-                   < 0) {
+               ich = skb_header_pointer(skb, iphoff + ih->ihl * 4,
+                                        sizeof(_icmph), &_icmph);
+               if (ich == NULL) {
                        printk("INCOMPLETE [%u bytes] ",
-                              skb->len - iphoff - iph.ihl*4);
+                              skb->len - iphoff - ih->ihl*4);
                        break;
                }
 
                /* Max length: 18 "TYPE=255 CODE=255 " */
-               printk("TYPE=%u CODE=%u ", icmph.type, icmph.code);
+               printk("TYPE=%u CODE=%u ", ich->type, ich->code);
 
                /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               if (icmph.type <= NR_ICMP_TYPES
-                   && required_len[icmph.type]
-                   && skb->len-iphoff-iph.ihl*4 < required_len[icmph.type]) {
+               if (ich->type <= NR_ICMP_TYPES
+                   && required_len[ich->type]
+                   && skb->len-iphoff-ih->ihl*4 < required_len[ich->type]) {
                        printk("INCOMPLETE [%u bytes] ",
-                              skb->len - iphoff - iph.ihl*4);
+                              skb->len - iphoff - ih->ihl*4);
                        break;
                }
 
-               switch (icmph.type) {
+               switch (ich->type) {
                case ICMP_ECHOREPLY:
                case ICMP_ECHO:
                        /* Max length: 19 "ID=65535 SEQ=65535 " */
                        printk("ID=%u SEQ=%u ",
-                              ntohs(icmph.un.echo.id),
-                              ntohs(icmph.un.echo.sequence));
+                              ntohs(ich->un.echo.id),
+                              ntohs(ich->un.echo.sequence));
                        break;
 
                case ICMP_PARAMETERPROB:
                        /* Max length: 14 "PARAMETER=255 " */
                        printk("PARAMETER=%u ",
-                              ntohl(icmph.un.gateway) >> 24);
+                              ntohl(ich->un.gateway) >> 24);
                        break;
                case ICMP_REDIRECT:
                        /* Max length: 24 "GATEWAY=255.255.255.255 " */
                        printk("GATEWAY=%u.%u.%u.%u ",
-                              NIPQUAD(icmph.un.gateway));
+                              NIPQUAD(ich->un.gateway));
                        /* Fall through */
                case ICMP_DEST_UNREACH:
                case ICMP_SOURCE_QUENCH:
@@ -257,62 +268,73 @@ static void dump_packet(const struct ipt_log_info *info,
                        if (!iphoff) { /* Only recurse once. */
                                printk("[");
                                dump_packet(info, skb,
-                                           iphoff + iph.ihl*4+sizeof(icmph));
+                                           iphoff + ih->ihl*4+sizeof(_icmph));
                                printk("] ");
                        }
 
                        /* Max length: 10 "MTU=65535 " */
-                       if (icmph.type == ICMP_DEST_UNREACH
-                           && icmph.code == ICMP_FRAG_NEEDED)
-                               printk("MTU=%u ", ntohs(icmph.un.frag.mtu));
+                       if (ich->type == ICMP_DEST_UNREACH
+                           && ich->code == ICMP_FRAG_NEEDED)
+                               printk("MTU=%u ", ntohs(ich->un.frag.mtu));
                }
                break;
        }
        /* Max Length */
        case IPPROTO_AH: {
-               struct ip_auth_hdr ah;
+               struct ip_auth_hdr _ahdr, *ah;
 
-               if (ntohs(iph.frag_off) & IP_OFFSET)
+               if (ntohs(ih->frag_off) & IP_OFFSET)
                        break;
                
                /* Max length: 9 "PROTO=AH " */
                printk("PROTO=AH ");
 
                /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               if (skb_copy_bits(skb, iphoff+iph.ihl*4, &ah, sizeof(ah)) < 0) {
+               ah = skb_header_pointer(skb, iphoff+ih->ihl*4,
+                                       sizeof(_ahdr), &_ahdr);
+               if (ah == NULL) {
                        printk("INCOMPLETE [%u bytes] ",
-                              skb->len - iphoff - iph.ihl*4);
+                              skb->len - iphoff - ih->ihl*4);
                        break;
                }
 
                /* Length: 15 "SPI=0xF1234567 " */
-               printk("SPI=0x%x ", ntohl(ah.spi));
+               printk("SPI=0x%x ", ntohl(ah->spi));
                break;
        }
        case IPPROTO_ESP: {
-               struct ip_esp_hdr esph;
+               struct ip_esp_hdr _esph, *eh;
 
                /* Max length: 10 "PROTO=ESP " */
                printk("PROTO=ESP ");
 
-               if (ntohs(iph.frag_off) & IP_OFFSET)
+               if (ntohs(ih->frag_off) & IP_OFFSET)
                        break;
 
                /* Max length: 25 "INCOMPLETE [65535 bytes] " */
-               if (skb_copy_bits(skb, iphoff+iph.ihl*4, &esph, sizeof(esph))
-                   < 0) {
+               eh = skb_header_pointer(skb, iphoff+ih->ihl*4,
+                                       sizeof(_esph), &_esph);
+               if (eh == NULL) {
                        printk("INCOMPLETE [%u bytes] ",
-                              skb->len - iphoff - iph.ihl*4);
+                              skb->len - iphoff - ih->ihl*4);
                        break;
                }
 
                /* Length: 15 "SPI=0xF1234567 " */
-               printk("SPI=0x%x ", ntohl(esph.spi));
+               printk("SPI=0x%x ", ntohl(eh->spi));
                break;
        }
        /* Max length: 10 "PROTO 255 " */
        default:
-               printk("PROTO=%u ", iph.protocol);
+               printk("PROTO=%u ", ih->protocol);
+       }
+
+       /* Max length: 15 "UID=4294967295 " */
+       if ((logflags & IPT_LOG_UID) && !iphoff && skb->sk) {
+               read_lock_bh(&skb->sk->sk_callback_lock);
+               if (skb->sk->sk_socket && skb->sk->sk_socket->file)
+                       printk("UID=%u ", skb->sk->sk_socket->file->f_uid);
+               read_unlock_bh(&skb->sk->sk_callback_lock);
        }
 
        /* Proto    Max log string length */
@@ -329,19 +351,31 @@ static void dump_packet(const struct ipt_log_info *info,
        /* maxlen = 230+   91  + 230 + 252 = 803 */
 }
 
+static struct nf_loginfo default_loginfo = {
+       .type   = NF_LOG_TYPE_LOG,
+       .u = {
+               .log = {
+                       .level    = 0,
+                       .logflags = NF_LOG_MASK,
+               },
+       },
+};
+
 static void
-ipt_log_packet(unsigned int hooknum,
+ipt_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 ipt_log_info *loginfo,
-              const char *level_string,
+              const struct nf_loginfo *loginfo,
               const char *prefix)
 {
+       if (!loginfo)
+               loginfo = &default_loginfo;
+
        spin_lock_bh(&log_lock);
-       printk(level_string);
-       printk("%sIN=%s OUT=%s ",
-              prefix == NULL ? loginfo->prefix : prefix,
+       printk("<%d>%sIN=%s OUT=%s ", loginfo->u.log.level,
+              prefix,
               in ? in->name : "",
               out ? out->name : "");
 #ifdef CONFIG_BRIDGE_NETFILTER
@@ -381,85 +415,81 @@ ipt_log_target(struct sk_buff **pskb,
               const struct net_device *in,
               const struct net_device *out,
               unsigned int hooknum,
+              const struct xt_target *target,
               const void *targinfo,
               void *userinfo)
 {
        const struct ipt_log_info *loginfo = targinfo;
-       char level_string[4] = "< >";
+       struct nf_loginfo li;
 
-       level_string[1] = '0' + (loginfo->level % 8);
-       ipt_log_packet(hooknum, *pskb, in, out, loginfo, level_string, NULL);
+       li.type = NF_LOG_TYPE_LOG;
+       li.u.log.level = loginfo->level;
+       li.u.log.logflags = loginfo->logflags;
 
-       return IPT_CONTINUE;
-}
-
-static void
-ipt_logfn(unsigned int hooknum,
-         const struct sk_buff *skb,
-         const struct net_device *in,
-         const struct net_device *out,
-         const char *prefix)
-{
-       struct ipt_log_info loginfo = { 
-               .level = 0, 
-               .logflags = IPT_LOG_MASK, 
-               .prefix = "" 
-       };
+       if (loginfo->logflags & IPT_LOG_NFLOG)
+               nf_log_packet(PF_INET, hooknum, *pskb, in, out, &li,
+                             "%s", loginfo->prefix);
+       else
+               ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li,
+                              loginfo->prefix);
 
-       ipt_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix);
+       return IPT_CONTINUE;
 }
 
 static int ipt_log_checkentry(const char *tablename,
-                             const struct ipt_entry *e,
+                             const void *e,
+                             const struct xt_target *target,
                              void *targinfo,
                              unsigned int targinfosize,
                              unsigned int hook_mask)
 {
        const struct ipt_log_info *loginfo = targinfo;
 
-       if (targinfosize != IPT_ALIGN(sizeof(struct ipt_log_info))) {
-               DEBUGP("LOG: targinfosize %u != %u\n",
-                      targinfosize, IPT_ALIGN(sizeof(struct ipt_log_info)));
-               return 0;
-       }
-
        if (loginfo->level >= 8) {
                DEBUGP("LOG: level %u >= 8\n", loginfo->level);
                return 0;
        }
-
        if (loginfo->prefix[sizeof(loginfo->prefix)-1] != '\0') {
                DEBUGP("LOG: prefix term %i\n",
                       loginfo->prefix[sizeof(loginfo->prefix)-1]);
                return 0;
        }
-
        return 1;
 }
 
 static struct ipt_target ipt_log_reg = {
        .name           = "LOG",
        .target         = ipt_log_target,
+       .targetsize     = sizeof(struct ipt_log_info),
        .checkentry     = ipt_log_checkentry,
        .me             = THIS_MODULE,
 };
 
-static int __init init(void)
+static struct nf_logger ipt_log_logger ={
+       .name           = "ipt_LOG",
+       .logfn          = &ipt_log_packet,
+       .me             = THIS_MODULE,
+};
+
+static int __init ipt_log_init(void)
 {
        if (ipt_register_target(&ipt_log_reg))
                return -EINVAL;
-       if (nflog)
-               nf_log_register(PF_INET, &ipt_logfn);
+       if (nf_log_register(PF_INET, &ipt_log_logger) < 0) {
+               printk(KERN_WARNING "ipt_LOG: not logging via system console "
+                      "since somebody else already registered for PF_INET\n");
+               /* we cannot make module load fail here, since otherwise
+                * iptables userspace would abort */
+       }
        
        return 0;
 }
 
-static void __exit fini(void)
+static void __exit ipt_log_fini(void)
 {
-       if (nflog)
-               nf_log_unregister(PF_INET, &ipt_logfn);
+       nf_log_unregister_logger(&ipt_log_logger);
        ipt_unregister_target(&ipt_log_reg);
 }
 
-module_init(init);
-module_exit(fini);
+module_init(ipt_log_init);
+module_exit(ipt_log_fini);