1 // SPDX-License-Identifier: GPL-2.0-only 2 /* (C) 1999-2001 Paul `Rusty' Russell 3 * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org> 4 */ 5 6 #include <linux/module.h> 7 #include <net/ipv6.h> 8 #include <net/ip6_route.h> 9 #include <net/ip6_fib.h> 10 #include <net/ip6_checksum.h> 11 #include <net/netfilter/ipv6/nf_reject.h> 12 #include <linux/netfilter_ipv6.h> 13 #include <linux/netfilter_bridge.h> 14 15 static bool nf_reject_v6_csum_ok(struct sk_buff *skb, int hook) 16 { 17 const struct ipv6hdr *ip6h = ipv6_hdr(skb); 18 int thoff; 19 __be16 fo; 20 u8 proto = ip6h->nexthdr; 21 22 if (skb_csum_unnecessary(skb)) 23 return true; 24 25 if (ip6h->payload_len && 26 pskb_trim_rcsum(skb, ntohs(ip6h->payload_len) + sizeof(*ip6h))) 27 return false; 28 29 ip6h = ipv6_hdr(skb); 30 thoff = ipv6_skip_exthdr(skb, ((u8*)(ip6h+1) - skb->data), &proto, &fo); 31 if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0) 32 return false; 33 34 if (!nf_reject_verify_csum(proto)) 35 return true; 36 37 return nf_ip6_checksum(skb, hook, thoff, proto) == 0; 38 } 39 40 static int nf_reject_ip6hdr_validate(struct sk_buff *skb) 41 { 42 struct ipv6hdr *hdr; 43 u32 pkt_len; 44 45 if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) 46 return 0; 47 48 hdr = ipv6_hdr(skb); 49 if (hdr->version != 6) 50 return 0; 51 52 pkt_len = ntohs(hdr->payload_len); 53 if (pkt_len + sizeof(struct ipv6hdr) > skb->len) 54 return 0; 55 56 return 1; 57 } 58 59 struct sk_buff *nf_reject_skb_v6_tcp_reset(struct net *net, 60 struct sk_buff *oldskb, 61 const struct net_device *dev, 62 int hook) 63 { 64 struct sk_buff *nskb; 65 const struct tcphdr *oth; 66 struct tcphdr _oth; 67 unsigned int otcplen; 68 struct ipv6hdr *nip6h; 69 70 if (!nf_reject_ip6hdr_validate(oldskb)) 71 return NULL; 72 73 oth = nf_reject_ip6_tcphdr_get(oldskb, &_oth, &otcplen, hook); 74 if (!oth) 75 return NULL; 76 77 nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 78 LL_MAX_HEADER, GFP_ATOMIC); 79 if (!nskb) 80 return NULL; 81 82 nskb->dev = (struct net_device *)dev; 83 84 skb_reserve(nskb, LL_MAX_HEADER); 85 nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP, 86 net->ipv6.devconf_all->hop_limit); 87 nf_reject_ip6_tcphdr_put(nskb, oldskb, oth, otcplen); 88 nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr)); 89 90 return nskb; 91 } 92 EXPORT_SYMBOL_GPL(nf_reject_skb_v6_tcp_reset); 93 94 struct sk_buff *nf_reject_skb_v6_unreach(struct net *net, 95 struct sk_buff *oldskb, 96 const struct net_device *dev, 97 int hook, u8 code) 98 { 99 struct sk_buff *nskb; 100 struct ipv6hdr *nip6h; 101 struct icmp6hdr *icmp6h; 102 unsigned int len; 103 104 if (!nf_reject_ip6hdr_validate(oldskb)) 105 return NULL; 106 107 /* Include "As much of invoking packet as possible without the ICMPv6 108 * packet exceeding the minimum IPv6 MTU" in the ICMP payload. 109 */ 110 len = min_t(unsigned int, 1220, oldskb->len); 111 112 if (!pskb_may_pull(oldskb, len)) 113 return NULL; 114 115 if (!nf_reject_v6_csum_ok(oldskb, hook)) 116 return NULL; 117 118 nskb = alloc_skb(sizeof(struct ipv6hdr) + sizeof(struct icmp6hdr) + 119 LL_MAX_HEADER + len, GFP_ATOMIC); 120 if (!nskb) 121 return NULL; 122 123 nskb->dev = (struct net_device *)dev; 124 125 skb_reserve(nskb, LL_MAX_HEADER); 126 nip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_ICMPV6, 127 net->ipv6.devconf_all->hop_limit); 128 129 skb_reset_transport_header(nskb); 130 icmp6h = skb_put_zero(nskb, sizeof(struct icmp6hdr)); 131 icmp6h->icmp6_type = ICMPV6_DEST_UNREACH; 132 icmp6h->icmp6_code = code; 133 134 skb_put_data(nskb, skb_network_header(oldskb), len); 135 nip6h->payload_len = htons(nskb->len - sizeof(struct ipv6hdr)); 136 137 icmp6h->icmp6_cksum = 138 csum_ipv6_magic(&nip6h->saddr, &nip6h->daddr, 139 nskb->len - sizeof(struct ipv6hdr), 140 IPPROTO_ICMPV6, 141 csum_partial(icmp6h, 142 nskb->len - sizeof(struct ipv6hdr), 143 0)); 144 145 return nskb; 146 } 147 EXPORT_SYMBOL_GPL(nf_reject_skb_v6_unreach); 148 149 const struct tcphdr *nf_reject_ip6_tcphdr_get(struct sk_buff *oldskb, 150 struct tcphdr *otcph, 151 unsigned int *otcplen, int hook) 152 { 153 const struct ipv6hdr *oip6h = ipv6_hdr(oldskb); 154 u8 proto; 155 __be16 frag_off; 156 int tcphoff; 157 158 proto = oip6h->nexthdr; 159 tcphoff = ipv6_skip_exthdr(oldskb, ((u8 *)(oip6h + 1) - oldskb->data), 160 &proto, &frag_off); 161 162 if ((tcphoff < 0) || (tcphoff > oldskb->len)) { 163 pr_debug("Cannot get TCP header.\n"); 164 return NULL; 165 } 166 167 *otcplen = oldskb->len - tcphoff; 168 169 /* IP header checks: fragment, too short. */ 170 if (proto != IPPROTO_TCP || *otcplen < sizeof(struct tcphdr)) { 171 pr_debug("proto(%d) != IPPROTO_TCP or too short (len = %d)\n", 172 proto, *otcplen); 173 return NULL; 174 } 175 176 otcph = skb_header_pointer(oldskb, tcphoff, sizeof(struct tcphdr), 177 otcph); 178 if (otcph == NULL) 179 return NULL; 180 181 /* No RST for RST. */ 182 if (otcph->rst) { 183 pr_debug("RST is set\n"); 184 return NULL; 185 } 186 187 /* Check checksum. */ 188 if (nf_ip6_checksum(oldskb, hook, tcphoff, IPPROTO_TCP)) { 189 pr_debug("TCP checksum is invalid\n"); 190 return NULL; 191 } 192 193 return otcph; 194 } 195 EXPORT_SYMBOL_GPL(nf_reject_ip6_tcphdr_get); 196 197 struct ipv6hdr *nf_reject_ip6hdr_put(struct sk_buff *nskb, 198 const struct sk_buff *oldskb, 199 __u8 protocol, int hoplimit) 200 { 201 struct ipv6hdr *ip6h; 202 const struct ipv6hdr *oip6h = ipv6_hdr(oldskb); 203 #define DEFAULT_TOS_VALUE 0x0U 204 const __u8 tclass = DEFAULT_TOS_VALUE; 205 206 skb_put(nskb, sizeof(struct ipv6hdr)); 207 skb_reset_network_header(nskb); 208 ip6h = ipv6_hdr(nskb); 209 ip6_flow_hdr(ip6h, tclass, 0); 210 ip6h->hop_limit = hoplimit; 211 ip6h->nexthdr = protocol; 212 ip6h->saddr = oip6h->daddr; 213 ip6h->daddr = oip6h->saddr; 214 215 nskb->protocol = htons(ETH_P_IPV6); 216 217 return ip6h; 218 } 219 EXPORT_SYMBOL_GPL(nf_reject_ip6hdr_put); 220 221 void nf_reject_ip6_tcphdr_put(struct sk_buff *nskb, 222 const struct sk_buff *oldskb, 223 const struct tcphdr *oth, unsigned int otcplen) 224 { 225 struct tcphdr *tcph; 226 int needs_ack; 227 228 skb_reset_transport_header(nskb); 229 tcph = skb_put(nskb, sizeof(struct tcphdr)); 230 /* Truncate to length (no data) */ 231 tcph->doff = sizeof(struct tcphdr)/4; 232 tcph->source = oth->dest; 233 tcph->dest = oth->source; 234 235 if (oth->ack) { 236 needs_ack = 0; 237 tcph->seq = oth->ack_seq; 238 tcph->ack_seq = 0; 239 } else { 240 needs_ack = 1; 241 tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin + 242 otcplen - (oth->doff<<2)); 243 tcph->seq = 0; 244 } 245 246 /* Reset flags */ 247 ((u_int8_t *)tcph)[13] = 0; 248 tcph->rst = 1; 249 tcph->ack = needs_ack; 250 tcph->window = 0; 251 tcph->urg_ptr = 0; 252 tcph->check = 0; 253 254 /* Adjust TCP checksum */ 255 tcph->check = csum_ipv6_magic(&ipv6_hdr(nskb)->saddr, 256 &ipv6_hdr(nskb)->daddr, 257 sizeof(struct tcphdr), IPPROTO_TCP, 258 csum_partial(tcph, 259 sizeof(struct tcphdr), 0)); 260 } 261 EXPORT_SYMBOL_GPL(nf_reject_ip6_tcphdr_put); 262 263 static int nf_reject6_fill_skb_dst(struct sk_buff *skb_in) 264 { 265 struct dst_entry *dst = NULL; 266 struct flowi fl; 267 268 memset(&fl, 0, sizeof(struct flowi)); 269 fl.u.ip6.daddr = ipv6_hdr(skb_in)->saddr; 270 nf_ip6_route(dev_net(skb_in->dev), &dst, &fl, false); 271 if (!dst) 272 return -1; 273 274 skb_dst_set(skb_in, dst); 275 return 0; 276 } 277 278 void nf_send_reset6(struct net *net, struct sock *sk, struct sk_buff *oldskb, 279 int hook) 280 { 281 struct net_device *br_indev __maybe_unused; 282 struct sk_buff *nskb; 283 struct tcphdr _otcph; 284 const struct tcphdr *otcph; 285 unsigned int otcplen, hh_len; 286 const struct ipv6hdr *oip6h = ipv6_hdr(oldskb); 287 struct ipv6hdr *ip6h; 288 struct dst_entry *dst = NULL; 289 struct flowi6 fl6; 290 291 if ((!(ipv6_addr_type(&oip6h->saddr) & IPV6_ADDR_UNICAST)) || 292 (!(ipv6_addr_type(&oip6h->daddr) & IPV6_ADDR_UNICAST))) { 293 pr_debug("addr is not unicast.\n"); 294 return; 295 } 296 297 otcph = nf_reject_ip6_tcphdr_get(oldskb, &_otcph, &otcplen, hook); 298 if (!otcph) 299 return; 300 301 memset(&fl6, 0, sizeof(fl6)); 302 fl6.flowi6_proto = IPPROTO_TCP; 303 fl6.saddr = oip6h->daddr; 304 fl6.daddr = oip6h->saddr; 305 fl6.fl6_sport = otcph->dest; 306 fl6.fl6_dport = otcph->source; 307 308 if (hook == NF_INET_PRE_ROUTING || hook == NF_INET_INGRESS) { 309 nf_ip6_route(net, &dst, flowi6_to_flowi(&fl6), false); 310 if (!dst) 311 return; 312 skb_dst_set(oldskb, dst); 313 } 314 315 fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst(oldskb)->dev); 316 fl6.flowi6_mark = IP6_REPLY_MARK(net, oldskb->mark); 317 security_skb_classify_flow(oldskb, flowi6_to_flowi_common(&fl6)); 318 dst = ip6_route_output(net, NULL, &fl6); 319 if (dst->error) { 320 dst_release(dst); 321 return; 322 } 323 dst = xfrm_lookup(net, dst, flowi6_to_flowi(&fl6), NULL, 0); 324 if (IS_ERR(dst)) 325 return; 326 327 hh_len = (dst->dev->hard_header_len + 15)&~15; 328 nskb = alloc_skb(hh_len + 15 + dst->header_len + sizeof(struct ipv6hdr) 329 + sizeof(struct tcphdr) + dst->trailer_len, 330 GFP_ATOMIC); 331 332 if (!nskb) { 333 net_dbg_ratelimited("cannot alloc skb\n"); 334 dst_release(dst); 335 return; 336 } 337 338 skb_dst_set(nskb, dst); 339 340 nskb->mark = fl6.flowi6_mark; 341 342 skb_reserve(nskb, hh_len + dst->header_len); 343 ip6h = nf_reject_ip6hdr_put(nskb, oldskb, IPPROTO_TCP, 344 ip6_dst_hoplimit(dst)); 345 nf_reject_ip6_tcphdr_put(nskb, oldskb, otcph, otcplen); 346 347 nf_ct_attach(nskb, oldskb); 348 349 #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) 350 /* If we use ip6_local_out for bridged traffic, the MAC source on 351 * the RST will be ours, instead of the destination's. This confuses 352 * some routers/firewalls, and they drop the packet. So we need to 353 * build the eth header using the original destination's MAC as the 354 * source, and send the RST packet directly. 355 */ 356 br_indev = nf_bridge_get_physindev(oldskb); 357 if (br_indev) { 358 struct ethhdr *oeth = eth_hdr(oldskb); 359 360 nskb->dev = br_indev; 361 nskb->protocol = htons(ETH_P_IPV6); 362 ip6h->payload_len = htons(sizeof(struct tcphdr)); 363 if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol), 364 oeth->h_source, oeth->h_dest, nskb->len) < 0) { 365 kfree_skb(nskb); 366 return; 367 } 368 dev_queue_xmit(nskb); 369 } else 370 #endif 371 ip6_local_out(net, sk, nskb); 372 } 373 EXPORT_SYMBOL_GPL(nf_send_reset6); 374 375 static bool reject6_csum_ok(struct sk_buff *skb, int hook) 376 { 377 const struct ipv6hdr *ip6h = ipv6_hdr(skb); 378 int thoff; 379 __be16 fo; 380 u8 proto; 381 382 if (skb_csum_unnecessary(skb)) 383 return true; 384 385 proto = ip6h->nexthdr; 386 thoff = ipv6_skip_exthdr(skb, ((u8 *)(ip6h + 1) - skb->data), &proto, &fo); 387 388 if (thoff < 0 || thoff >= skb->len || (fo & htons(~0x7)) != 0) 389 return false; 390 391 if (!nf_reject_verify_csum(proto)) 392 return true; 393 394 return nf_ip6_checksum(skb, hook, thoff, proto) == 0; 395 } 396 397 void nf_send_unreach6(struct net *net, struct sk_buff *skb_in, 398 unsigned char code, unsigned int hooknum) 399 { 400 if (!reject6_csum_ok(skb_in, hooknum)) 401 return; 402 403 if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL) 404 skb_in->dev = net->loopback_dev; 405 406 if ((hooknum == NF_INET_PRE_ROUTING || hooknum == NF_INET_INGRESS) && 407 nf_reject6_fill_skb_dst(skb_in) < 0) 408 return; 409 410 icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0); 411 } 412 EXPORT_SYMBOL_GPL(nf_send_unreach6); 413 414 MODULE_LICENSE("GPL"); 415
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.