Commit c4f3db15958277c03d1c324894255ea3ecbf86e1

Authored by Florian Westphal
Committed by Pablo Neira Ayuso
1 parent 2420770b3f

netfilter: conntrack: add and use nf_l4proto_log_invalid

We currently pass down the l4 protocol to the conntrack ->packet()
function, but the only user of this is the debug info decision.

Same information can be derived from struct nf_conn.
As a first step, add and use a new log function for this, similar to
nf_ct_helper_log().

Add __cold annotation -- invalid packets should be infrequent so
gcc can consider all call paths that lead to such a function as
unlikely.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

Showing 8 changed files with 82 additions and 52 deletions Side-by-side Diff

include/net/netfilter/nf_conntrack_l4proto.h
... ... @@ -152,8 +152,18 @@
152 152 #define LOG_INVALID(net, proto) \
153 153 ((net)->ct.sysctl_log_invalid == (proto) || \
154 154 (net)->ct.sysctl_log_invalid == IPPROTO_RAW)
  155 +
  156 +__printf(5, 6) __cold
  157 +void nf_l4proto_log_invalid(const struct sk_buff *skb,
  158 + struct net *net,
  159 + u16 pf, u8 protonum,
  160 + const char *fmt, ...);
155 161 #else
156 162 static inline int LOG_INVALID(struct net *net, int proto) { return 0; }
  163 +
  164 +static inline __printf(5, 6) __cold
  165 +void nf_l4proto_log_invalid(const struct sk_buff *skb, struct net *net,
  166 + u16 pf, u8 protonum, const char *fmt, ...) {}
157 167 #endif /* CONFIG_SYSCTL */
158 168  
159 169 #endif /*_NF_CONNTRACK_PROTOCOL_H*/
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
... ... @@ -165,6 +165,12 @@
165 165 return NF_ACCEPT;
166 166 }
167 167  
  168 +static void icmp_error_log(const struct sk_buff *skb, struct net *net,
  169 + u8 pf, const char *msg)
  170 +{
  171 + nf_l4proto_log_invalid(skb, net, pf, IPPROTO_ICMP, "%s", msg);
  172 +}
  173 +
168 174 /* Small and modified version of icmp_rcv */
169 175 static int
170 176 icmp_error(struct net *net, struct nf_conn *tmpl,
171 177  
... ... @@ -177,18 +183,14 @@
177 183 /* Not enough header? */
178 184 icmph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_ih), &_ih);
179 185 if (icmph == NULL) {
180   - if (LOG_INVALID(net, IPPROTO_ICMP))
181   - nf_log_packet(net, PF_INET, 0, skb, NULL, NULL,
182   - NULL, "nf_ct_icmp: short packet ");
  186 + icmp_error_log(skb, net, pf, "short packet");
183 187 return -NF_ACCEPT;
184 188 }
185 189  
186 190 /* See ip_conntrack_proto_tcp.c */
187 191 if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
188 192 nf_ip_checksum(skb, hooknum, dataoff, 0)) {
189   - if (LOG_INVALID(net, IPPROTO_ICMP))
190   - nf_log_packet(net, PF_INET, 0, skb, NULL, NULL, NULL,
191   - "nf_ct_icmp: bad HW ICMP checksum ");
  193 + icmp_error_log(skb, net, pf, "bad hw icmp checksum");
192 194 return -NF_ACCEPT;
193 195 }
194 196  
... ... @@ -199,9 +201,7 @@
199 201 * discarded.
200 202 */
201 203 if (icmph->type > NR_ICMP_TYPES) {
202   - if (LOG_INVALID(net, IPPROTO_ICMP))
203   - nf_log_packet(net, PF_INET, 0, skb, NULL, NULL, NULL,
204   - "nf_ct_icmp: invalid ICMP type ");
  204 + icmp_error_log(skb, net, pf, "invalid icmp type");
205 205 return -NF_ACCEPT;
206 206 }
207 207  
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
... ... @@ -176,6 +176,12 @@
176 176 return NF_ACCEPT;
177 177 }
178 178  
  179 +static void icmpv6_error_log(const struct sk_buff *skb, struct net *net,
  180 + u8 pf, const char *msg)
  181 +{
  182 + nf_l4proto_log_invalid(skb, net, pf, IPPROTO_ICMPV6, "%s", msg);
  183 +}
  184 +
179 185 static int
180 186 icmpv6_error(struct net *net, struct nf_conn *tmpl,
181 187 struct sk_buff *skb, unsigned int dataoff,
182 188  
... ... @@ -187,17 +193,13 @@
187 193  
188 194 icmp6h = skb_header_pointer(skb, dataoff, sizeof(_ih), &_ih);
189 195 if (icmp6h == NULL) {
190   - if (LOG_INVALID(net, IPPROTO_ICMPV6))
191   - nf_log_packet(net, PF_INET6, 0, skb, NULL, NULL, NULL,
192   - "nf_ct_icmpv6: short packet ");
  196 + icmpv6_error_log(skb, net, pf, "short packet");
193 197 return -NF_ACCEPT;
194 198 }
195 199  
196 200 if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
197 201 nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) {
198   - if (LOG_INVALID(net, IPPROTO_ICMPV6))
199   - nf_log_packet(net, PF_INET6, 0, skb, NULL, NULL, NULL,
200   - "nf_ct_icmpv6: ICMPv6 checksum failed ");
  202 + icmpv6_error_log(skb, net, pf, "ICMPv6 checksum failed");
201 203 return -NF_ACCEPT;
202 204 }
203 205  
net/netfilter/nf_conntrack_proto.c
... ... @@ -27,6 +27,7 @@
27 27 #include <net/netfilter/nf_conntrack_l3proto.h>
28 28 #include <net/netfilter/nf_conntrack_l4proto.h>
29 29 #include <net/netfilter/nf_conntrack_core.h>
  30 +#include <net/netfilter/nf_log.h>
30 31  
31 32 static struct nf_conntrack_l4proto __rcu **nf_ct_protos[NFPROTO_NUMPROTO] __read_mostly;
32 33 struct nf_conntrack_l3proto __rcu *nf_ct_l3protos[NFPROTO_NUMPROTO] __read_mostly;
... ... @@ -63,6 +64,29 @@
63 64 *header = NULL;
64 65 *table = NULL;
65 66 }
  67 +
  68 +__printf(5, 6)
  69 +void nf_l4proto_log_invalid(const struct sk_buff *skb,
  70 + struct net *net,
  71 + u16 pf, u8 protonum,
  72 + const char *fmt, ...)
  73 +{
  74 + struct va_format vaf;
  75 + va_list args;
  76 +
  77 + if (net->ct.sysctl_log_invalid != protonum ||
  78 + net->ct.sysctl_log_invalid != IPPROTO_RAW)
  79 + return;
  80 +
  81 + va_start(args, fmt);
  82 + vaf.fmt = fmt;
  83 + vaf.va = &args;
  84 +
  85 + nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
  86 + "nf_ct_proto_%d: %pV ", protonum, &vaf);
  87 + va_end(args);
  88 +}
  89 +EXPORT_SYMBOL_GPL(nf_l4proto_log_invalid);
66 90 #endif
67 91  
68 92 const struct nf_conntrack_l4proto *
net/netfilter/nf_conntrack_proto_dccp.c
... ... @@ -604,8 +604,7 @@
604 604 return NF_ACCEPT;
605 605  
606 606 out_invalid:
607   - if (LOG_INVALID(net, IPPROTO_DCCP))
608   - nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, "%s", msg);
  607 + nf_l4proto_log_invalid(skb, net, pf, IPPROTO_DCCP, "%s", msg);
609 608 return -NF_ACCEPT;
610 609 }
611 610  
net/netfilter/nf_conntrack_proto_sctp.c
... ... @@ -522,8 +522,7 @@
522 522 }
523 523 return NF_ACCEPT;
524 524 out_invalid:
525   - if (LOG_INVALID(net, IPPROTO_SCTP))
526   - nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL, "%s", logmsg);
  525 + nf_l4proto_log_invalid(skb, net, pf, IPPROTO_SCTP, "%s", logmsg);
527 526 return -NF_ACCEPT;
528 527 }
529 528  
net/netfilter/nf_conntrack_proto_tcp.c
... ... @@ -738,6 +738,12 @@
738 738 [TCPHDR_ACK|TCPHDR_URG] = 1,
739 739 };
740 740  
  741 +static void tcp_error_log(const struct sk_buff *skb, struct net *net,
  742 + u8 pf, const char *msg)
  743 +{
  744 + nf_l4proto_log_invalid(skb, net, pf, IPPROTO_TCP, "%s", msg);
  745 +}
  746 +
741 747 /* Protect conntrack agaist broken packets. Code taken from ipt_unclean.c. */
742 748 static int tcp_error(struct net *net, struct nf_conn *tmpl,
743 749 struct sk_buff *skb,
744 750  
... ... @@ -753,17 +759,13 @@
753 759 /* Smaller that minimal TCP header? */
754 760 th = skb_header_pointer(skb, dataoff, sizeof(_tcph), &_tcph);
755 761 if (th == NULL) {
756   - if (LOG_INVALID(net, IPPROTO_TCP))
757   - nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
758   - "nf_ct_tcp: short packet ");
  762 + tcp_error_log(skb, net, pf, "short packet");
759 763 return -NF_ACCEPT;
760 764 }
761 765  
762 766 /* Not whole TCP header or malformed packet */
763 767 if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) {
764   - if (LOG_INVALID(net, IPPROTO_TCP))
765   - nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
766   - "nf_ct_tcp: truncated/malformed packet ");
  768 + tcp_error_log(skb, net, pf, "truncated packet");
767 769 return -NF_ACCEPT;
768 770 }
769 771  
770 772  
... ... @@ -774,18 +776,14 @@
774 776 /* FIXME: Source route IP option packets --RR */
775 777 if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
776 778 nf_checksum(skb, hooknum, dataoff, IPPROTO_TCP, pf)) {
777   - if (LOG_INVALID(net, IPPROTO_TCP))
778   - nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
779   - "nf_ct_tcp: bad TCP checksum ");
  779 + tcp_error_log(skb, net, pf, "bad checksum");
780 780 return -NF_ACCEPT;
781 781 }
782 782  
783 783 /* Check TCP flags. */
784 784 tcpflags = (tcp_flag_byte(th) & ~(TCPHDR_ECE|TCPHDR_CWR|TCPHDR_PSH));
785 785 if (!tcp_valid_flags[tcpflags]) {
786   - if (LOG_INVALID(net, IPPROTO_TCP))
787   - nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
788   - "nf_ct_tcp: invalid TCP flag combination ");
  786 + tcp_error_log(skb, net, pf, "invalid tcp flag combination");
789 787 return -NF_ACCEPT;
790 788 }
791 789  
net/netfilter/nf_conntrack_proto_udp.c
... ... @@ -99,6 +99,12 @@
99 99 }
100 100  
101 101 #ifdef CONFIG_NF_CT_PROTO_UDPLITE
  102 +static void udplite_error_log(const struct sk_buff *skb, struct net *net,
  103 + u8 pf, const char *msg)
  104 +{
  105 + nf_l4proto_log_invalid(skb, net, pf, IPPROTO_UDPLITE, "%s", msg);
  106 +}
  107 +
102 108 static int udplite_error(struct net *net, struct nf_conn *tmpl,
103 109 struct sk_buff *skb,
104 110 unsigned int dataoff,
... ... @@ -112,9 +118,7 @@
112 118 /* Header is too small? */
113 119 hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
114 120 if (!hdr) {
115   - if (LOG_INVALID(net, IPPROTO_UDPLITE))
116   - nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
117   - "nf_ct_udplite: short packet ");
  121 + udplite_error_log(skb, net, pf, "short packet");
118 122 return -NF_ACCEPT;
119 123 }
120 124  
121 125  
... ... @@ -122,17 +126,13 @@
122 126 if (cscov == 0) {
123 127 cscov = udplen;
124 128 } else if (cscov < sizeof(*hdr) || cscov > udplen) {
125   - if (LOG_INVALID(net, IPPROTO_UDPLITE))
126   - nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
127   - "nf_ct_udplite: invalid checksum coverage ");
  129 + udplite_error_log(skb, net, pf, "invalid checksum coverage");
128 130 return -NF_ACCEPT;
129 131 }
130 132  
131 133 /* UDPLITE mandates checksums */
132 134 if (!hdr->check) {
133   - if (LOG_INVALID(net, IPPROTO_UDPLITE))
134   - nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
135   - "nf_ct_udplite: checksum missing ");
  135 + udplite_error_log(skb, net, pf, "checksum missing");
136 136 return -NF_ACCEPT;
137 137 }
138 138  
... ... @@ -140,9 +140,7 @@
140 140 if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
141 141 nf_checksum_partial(skb, hooknum, dataoff, cscov, IPPROTO_UDP,
142 142 pf)) {
143   - if (LOG_INVALID(net, IPPROTO_UDPLITE))
144   - nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
145   - "nf_ct_udplite: bad UDPLite checksum ");
  143 + udplite_error_log(skb, net, pf, "bad checksum");
146 144 return -NF_ACCEPT;
147 145 }
148 146  
... ... @@ -150,6 +148,12 @@
150 148 }
151 149 #endif
152 150  
  151 +static void udp_error_log(const struct sk_buff *skb, struct net *net,
  152 + u8 pf, const char *msg)
  153 +{
  154 + nf_l4proto_log_invalid(skb, net, pf, IPPROTO_UDP, "%s", msg);
  155 +}
  156 +
153 157 static int udp_error(struct net *net, struct nf_conn *tmpl, struct sk_buff *skb,
154 158 unsigned int dataoff,
155 159 u_int8_t pf,
156 160  
... ... @@ -162,17 +166,13 @@
162 166 /* Header is too small? */
163 167 hdr = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
164 168 if (hdr == NULL) {
165   - if (LOG_INVALID(net, IPPROTO_UDP))
166   - nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
167   - "nf_ct_udp: short packet ");
  169 + udp_error_log(skb, net, pf, "short packet");
168 170 return -NF_ACCEPT;
169 171 }
170 172  
171 173 /* Truncated/malformed packets */
172 174 if (ntohs(hdr->len) > udplen || ntohs(hdr->len) < sizeof(*hdr)) {
173   - if (LOG_INVALID(net, IPPROTO_UDP))
174   - nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
175   - "nf_ct_udp: truncated/malformed packet ");
  175 + udp_error_log(skb, net, pf, "truncated/malformed packet");
176 176 return -NF_ACCEPT;
177 177 }
178 178  
... ... @@ -186,9 +186,7 @@
186 186 * FIXME: Source route IP option packets --RR */
187 187 if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
188 188 nf_checksum(skb, hooknum, dataoff, IPPROTO_UDP, pf)) {
189   - if (LOG_INVALID(net, IPPROTO_UDP))
190   - nf_log_packet(net, pf, 0, skb, NULL, NULL, NULL,
191   - "nf_ct_udp: bad UDP checksum ");
  189 + udp_error_log(skb, net, pf, "bad checksum");
192 190 return -NF_ACCEPT;
193 191 }
194 192