nf_reject_ipv4.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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. #include <linux/module.h>
  6. #include <net/ip.h>
  7. #include <net/tcp.h>
  8. #include <net/route.h>
  9. #include <net/dst.h>
  10. #include <net/netfilter/ipv4/nf_reject.h>
  11. #include <linux/netfilter_ipv4.h>
  12. #include <linux/netfilter_bridge.h>
  13. const struct tcphdr *nf_reject_ip_tcphdr_get(struct sk_buff *oldskb,
  14. struct tcphdr *_oth, int hook)
  15. {
  16. const struct tcphdr *oth;
  17. /* IP header checks: fragment. */
  18. if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
  19. return NULL;
  20. if (ip_hdr(oldskb)->protocol != IPPROTO_TCP)
  21. return NULL;
  22. oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
  23. sizeof(struct tcphdr), _oth);
  24. if (oth == NULL)
  25. return NULL;
  26. /* No RST for RST. */
  27. if (oth->rst)
  28. return NULL;
  29. /* Check checksum */
  30. if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
  31. return NULL;
  32. return oth;
  33. }
  34. EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_get);
  35. struct iphdr *nf_reject_iphdr_put(struct sk_buff *nskb,
  36. const struct sk_buff *oldskb,
  37. __u8 protocol, int ttl)
  38. {
  39. struct iphdr *niph, *oiph = ip_hdr(oldskb);
  40. skb_reset_network_header(nskb);
  41. niph = skb_put(nskb, sizeof(struct iphdr));
  42. niph->version = 4;
  43. niph->ihl = sizeof(struct iphdr) / 4;
  44. niph->tos = 0;
  45. niph->id = 0;
  46. niph->frag_off = htons(IP_DF);
  47. niph->protocol = protocol;
  48. niph->check = 0;
  49. niph->saddr = oiph->daddr;
  50. niph->daddr = oiph->saddr;
  51. niph->ttl = ttl;
  52. nskb->protocol = htons(ETH_P_IP);
  53. return niph;
  54. }
  55. EXPORT_SYMBOL_GPL(nf_reject_iphdr_put);
  56. void nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb,
  57. const struct tcphdr *oth)
  58. {
  59. struct iphdr *niph = ip_hdr(nskb);
  60. struct tcphdr *tcph;
  61. skb_reset_transport_header(nskb);
  62. tcph = skb_put_zero(nskb, sizeof(struct tcphdr));
  63. tcph->source = oth->dest;
  64. tcph->dest = oth->source;
  65. tcph->doff = sizeof(struct tcphdr) / 4;
  66. if (oth->ack) {
  67. tcph->seq = oth->ack_seq;
  68. } else {
  69. tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
  70. oldskb->len - ip_hdrlen(oldskb) -
  71. (oth->doff << 2));
  72. tcph->ack = 1;
  73. }
  74. tcph->rst = 1;
  75. tcph->check = ~tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
  76. niph->daddr, 0);
  77. nskb->ip_summed = CHECKSUM_PARTIAL;
  78. nskb->csum_start = (unsigned char *)tcph - nskb->head;
  79. nskb->csum_offset = offsetof(struct tcphdr, check);
  80. }
  81. EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_put);
  82. static int nf_reject_fill_skb_dst(struct sk_buff *skb_in)
  83. {
  84. struct dst_entry *dst = NULL;
  85. struct flowi fl;
  86. memset(&fl, 0, sizeof(struct flowi));
  87. fl.u.ip4.daddr = ip_hdr(skb_in)->saddr;
  88. nf_ip_route(dev_net(skb_in->dev), &dst, &fl, false);
  89. if (!dst)
  90. return -1;
  91. skb_dst_set(skb_in, dst);
  92. return 0;
  93. }
  94. /* Send RST reply */
  95. void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook)
  96. {
  97. struct net_device *br_indev __maybe_unused;
  98. struct sk_buff *nskb;
  99. struct iphdr *niph;
  100. const struct tcphdr *oth;
  101. struct tcphdr _oth;
  102. oth = nf_reject_ip_tcphdr_get(oldskb, &_oth, hook);
  103. if (!oth)
  104. return;
  105. if (hook == NF_INET_PRE_ROUTING && nf_reject_fill_skb_dst(oldskb))
  106. return;
  107. if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
  108. return;
  109. nskb = alloc_skb(sizeof(struct iphdr) + sizeof(struct tcphdr) +
  110. LL_MAX_HEADER, GFP_ATOMIC);
  111. if (!nskb)
  112. return;
  113. /* ip_route_me_harder expects skb->dst to be set */
  114. skb_dst_set_noref(nskb, skb_dst(oldskb));
  115. nskb->mark = IP4_REPLY_MARK(net, oldskb->mark);
  116. skb_reserve(nskb, LL_MAX_HEADER);
  117. niph = nf_reject_iphdr_put(nskb, oldskb, IPPROTO_TCP,
  118. ip4_dst_hoplimit(skb_dst(nskb)));
  119. nf_reject_ip_tcphdr_put(nskb, oldskb, oth);
  120. if (ip_route_me_harder(net, nskb->sk, nskb, RTN_UNSPEC))
  121. goto free_nskb;
  122. niph = ip_hdr(nskb);
  123. /* "Never happens" */
  124. if (nskb->len > dst_mtu(skb_dst(nskb)))
  125. goto free_nskb;
  126. nf_ct_attach(nskb, oldskb);
  127. #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
  128. /* If we use ip_local_out for bridged traffic, the MAC source on
  129. * the RST will be ours, instead of the destination's. This confuses
  130. * some routers/firewalls, and they drop the packet. So we need to
  131. * build the eth header using the original destination's MAC as the
  132. * source, and send the RST packet directly.
  133. */
  134. br_indev = nf_bridge_get_physindev(oldskb);
  135. if (br_indev) {
  136. struct ethhdr *oeth = eth_hdr(oldskb);
  137. nskb->dev = br_indev;
  138. niph->tot_len = htons(nskb->len);
  139. ip_send_check(niph);
  140. if (dev_hard_header(nskb, nskb->dev, ntohs(nskb->protocol),
  141. oeth->h_source, oeth->h_dest, nskb->len) < 0)
  142. goto free_nskb;
  143. dev_queue_xmit(nskb);
  144. } else
  145. #endif
  146. ip_local_out(net, nskb->sk, nskb);
  147. return;
  148. free_nskb:
  149. kfree_skb(nskb);
  150. }
  151. EXPORT_SYMBOL_GPL(nf_send_reset);
  152. void nf_send_unreach(struct sk_buff *skb_in, int code, int hook)
  153. {
  154. struct iphdr *iph = ip_hdr(skb_in);
  155. u8 proto = iph->protocol;
  156. if (iph->frag_off & htons(IP_OFFSET))
  157. return;
  158. if (hook == NF_INET_PRE_ROUTING && nf_reject_fill_skb_dst(skb_in))
  159. return;
  160. if (skb_csum_unnecessary(skb_in) || !nf_reject_verify_csum(proto)) {
  161. icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
  162. return;
  163. }
  164. if (nf_ip_checksum(skb_in, hook, ip_hdrlen(skb_in), proto) == 0)
  165. icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
  166. }
  167. EXPORT_SYMBOL_GPL(nf_send_unreach);
  168. MODULE_LICENSE("GPL");