Commit c4f3db15958277c03d1c324894255ea3ecbf86e1
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
- net/ipv4/netfilter/nf_conntrack_proto_icmp.c
- net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
- net/netfilter/nf_conntrack_proto.c
- net/netfilter/nf_conntrack_proto_dccp.c
- net/netfilter/nf_conntrack_proto_sctp.c
- net/netfilter/nf_conntrack_proto_tcp.c
- net/netfilter/nf_conntrack_proto_udp.c
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 |