X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fipt_LOG.c;h=c96de16fefae67ed9a634fd2ad8c2f56edf65289;hb=refs%2Fheads%2Fvserver;hp=b79962e225f74048029fd5759b24e745c8164f39;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index b79962e22..c96de16fe 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -27,10 +27,6 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Netfilter Core Team "); 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,54 @@ 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; + case IPPROTO_UDP: + case IPPROTO_UDPLITE: { + struct udphdr _udph, *uh; - /* Max length: 10 "PROTO=UDP " */ - printk("PROTO=UDP "); + if (ih->protocol == IPPROTO_UDP) + /* Max length: 10 "PROTO=UDP " */ + printk("PROTO=UDP " ); + else /* Max length: 14 "PROTO=UDPLITE " */ + printk("PROTO=UDPLITE "); - 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 +222,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,68 +272,80 @@ 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 */ /* IP: 40+46+6+11+127 = 230 */ /* TCP: 10+max(25,20+30+13+9+32+11+127) = 252 */ /* UDP: 10+max(25,20) = 35 */ + /* UDPLITE: 14+max(25,20) = 39 */ /* ICMP: 11+max(25, 18+25+max(19,14,24+3+n+10,3+n+10)) = 91+n */ /* ESP: 10+max(25)+15 = 50 */ /* AH: 9+max(25)+15 = 49 */ @@ -329,19 +356,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 +420,74 @@ ipt_log_target(struct sk_buff **pskb, const struct net_device *in, const struct net_device *out, unsigned int hooknum, - const void *targinfo, - void *userinfo) + const struct xt_target *target, + const void *targinfo) { 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; + ipt_log_packet(PF_INET, hooknum, *pskb, in, out, &li, + loginfo->prefix); 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 = "" - }; - - ipt_log_packet(hooknum, skb, in, out, &loginfo, KERN_WARNING, prefix); -} - 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);