diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/netfilter/ipt_REJECT.c | 97 |
1 files changed, 19 insertions, 78 deletions
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index fd0c05efed8a..ad0312d0e4fd 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c | |||
@@ -38,76 +38,16 @@ MODULE_DESCRIPTION("iptables REJECT target module"); | |||
38 | #define DEBUGP(format, args...) | 38 | #define DEBUGP(format, args...) |
39 | #endif | 39 | #endif |
40 | 40 | ||
41 | static inline struct rtable *route_reverse(struct sk_buff *skb, | ||
42 | struct tcphdr *tcph, int hook) | ||
43 | { | ||
44 | struct iphdr *iph = skb->nh.iph; | ||
45 | struct dst_entry *odst; | ||
46 | struct flowi fl = {}; | ||
47 | struct rtable *rt; | ||
48 | |||
49 | /* We don't require ip forwarding to be enabled to be able to | ||
50 | * send a RST reply for bridged traffic. */ | ||
51 | if (hook != NF_IP_FORWARD | ||
52 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
53 | || (skb->nf_bridge && skb->nf_bridge->mask & BRNF_BRIDGED) | ||
54 | #endif | ||
55 | ) { | ||
56 | fl.nl_u.ip4_u.daddr = iph->saddr; | ||
57 | if (hook == NF_IP_LOCAL_IN) | ||
58 | fl.nl_u.ip4_u.saddr = iph->daddr; | ||
59 | fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); | ||
60 | |||
61 | if (ip_route_output_key(&rt, &fl) != 0) | ||
62 | return NULL; | ||
63 | } else { | ||
64 | /* non-local src, find valid iif to satisfy | ||
65 | * rp-filter when calling ip_route_input. */ | ||
66 | fl.nl_u.ip4_u.daddr = iph->daddr; | ||
67 | if (ip_route_output_key(&rt, &fl) != 0) | ||
68 | return NULL; | ||
69 | |||
70 | odst = skb->dst; | ||
71 | if (ip_route_input(skb, iph->saddr, iph->daddr, | ||
72 | RT_TOS(iph->tos), rt->u.dst.dev) != 0) { | ||
73 | dst_release(&rt->u.dst); | ||
74 | return NULL; | ||
75 | } | ||
76 | dst_release(&rt->u.dst); | ||
77 | rt = (struct rtable *)skb->dst; | ||
78 | skb->dst = odst; | ||
79 | |||
80 | fl.nl_u.ip4_u.daddr = iph->saddr; | ||
81 | fl.nl_u.ip4_u.saddr = iph->daddr; | ||
82 | fl.nl_u.ip4_u.tos = RT_TOS(iph->tos); | ||
83 | } | ||
84 | |||
85 | if (rt->u.dst.error) { | ||
86 | dst_release(&rt->u.dst); | ||
87 | return NULL; | ||
88 | } | ||
89 | |||
90 | fl.proto = IPPROTO_TCP; | ||
91 | fl.fl_ip_sport = tcph->dest; | ||
92 | fl.fl_ip_dport = tcph->source; | ||
93 | security_skb_classify_flow(skb, &fl); | ||
94 | |||
95 | xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0); | ||
96 | |||
97 | return rt; | ||
98 | } | ||
99 | |||
100 | /* Send RST reply */ | 41 | /* Send RST reply */ |
101 | static void send_reset(struct sk_buff *oldskb, int hook) | 42 | static void send_reset(struct sk_buff *oldskb, int hook) |
102 | { | 43 | { |
103 | struct sk_buff *nskb; | 44 | struct sk_buff *nskb; |
104 | struct iphdr *iph = oldskb->nh.iph; | 45 | struct iphdr *iph = oldskb->nh.iph; |
105 | struct tcphdr _otcph, *oth, *tcph; | 46 | struct tcphdr _otcph, *oth, *tcph; |
106 | struct rtable *rt; | ||
107 | __be16 tmp_port; | 47 | __be16 tmp_port; |
108 | __be32 tmp_addr; | 48 | __be32 tmp_addr; |
109 | int needs_ack; | 49 | int needs_ack; |
110 | int hh_len; | 50 | unsigned int addr_type; |
111 | 51 | ||
112 | /* IP header checks: fragment. */ | 52 | /* IP header checks: fragment. */ |
113 | if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)) | 53 | if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)) |
@@ -126,23 +66,13 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
126 | if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP)) | 66 | if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP)) |
127 | return; | 67 | return; |
128 | 68 | ||
129 | if ((rt = route_reverse(oldskb, oth, hook)) == NULL) | ||
130 | return; | ||
131 | |||
132 | hh_len = LL_RESERVED_SPACE(rt->u.dst.dev); | ||
133 | |||
134 | /* We need a linear, writeable skb. We also need to expand | 69 | /* We need a linear, writeable skb. We also need to expand |
135 | headroom in case hh_len of incoming interface < hh_len of | 70 | headroom in case hh_len of incoming interface < hh_len of |
136 | outgoing interface */ | 71 | outgoing interface */ |
137 | nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb), | 72 | nskb = skb_copy_expand(oldskb, LL_MAX_HEADER, skb_tailroom(oldskb), |
138 | GFP_ATOMIC); | 73 | GFP_ATOMIC); |
139 | if (!nskb) { | 74 | if (!nskb) |
140 | dst_release(&rt->u.dst); | ||
141 | return; | 75 | return; |
142 | } | ||
143 | |||
144 | dst_release(nskb->dst); | ||
145 | nskb->dst = &rt->u.dst; | ||
146 | 76 | ||
147 | /* This packet will not be the same as the other: clear nf fields */ | 77 | /* This packet will not be the same as the other: clear nf fields */ |
148 | nf_reset(nskb); | 78 | nf_reset(nskb); |
@@ -184,6 +114,21 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
184 | tcph->window = 0; | 114 | tcph->window = 0; |
185 | tcph->urg_ptr = 0; | 115 | tcph->urg_ptr = 0; |
186 | 116 | ||
117 | /* Set DF, id = 0 */ | ||
118 | nskb->nh.iph->frag_off = htons(IP_DF); | ||
119 | nskb->nh.iph->id = 0; | ||
120 | |||
121 | addr_type = RTN_UNSPEC; | ||
122 | if (hook != NF_IP_FORWARD | ||
123 | #ifdef CONFIG_BRIDGE_NETFILTER | ||
124 | || (nskb->nf_bridge && nskb->nf_bridge->mask & BRNF_BRIDGED) | ||
125 | #endif | ||
126 | ) | ||
127 | addr_type = RTN_LOCAL; | ||
128 | |||
129 | if (ip_route_me_harder(&nskb, addr_type)) | ||
130 | goto free_nskb; | ||
131 | |||
187 | /* Adjust TCP checksum */ | 132 | /* Adjust TCP checksum */ |
188 | nskb->ip_summed = CHECKSUM_NONE; | 133 | nskb->ip_summed = CHECKSUM_NONE; |
189 | tcph->check = 0; | 134 | tcph->check = 0; |
@@ -192,12 +137,8 @@ static void send_reset(struct sk_buff *oldskb, int hook) | |||
192 | nskb->nh.iph->daddr, | 137 | nskb->nh.iph->daddr, |
193 | csum_partial((char *)tcph, | 138 | csum_partial((char *)tcph, |
194 | sizeof(struct tcphdr), 0)); | 139 | sizeof(struct tcphdr), 0)); |
195 | 140 | /* Adjust IP TTL */ | |
196 | /* Adjust IP TTL, DF */ | ||
197 | nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); | 141 | nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT); |
198 | /* Set DF, id = 0 */ | ||
199 | nskb->nh.iph->frag_off = htons(IP_DF); | ||
200 | nskb->nh.iph->id = 0; | ||
201 | 142 | ||
202 | /* Adjust IP checksum */ | 143 | /* Adjust IP checksum */ |
203 | nskb->nh.iph->check = 0; | 144 | nskb->nh.iph->check = 0; |