|
@@ -38,76 +38,16 @@ MODULE_DESCRIPTION("iptables REJECT target module");
|
|
#define DEBUGP(format, args...)
|
|
#define DEBUGP(format, args...)
|
|
#endif
|
|
#endif
|
|
|
|
|
|
-static inline struct rtable *route_reverse(struct sk_buff *skb,
|
|
|
|
- struct tcphdr *tcph, int hook)
|
|
|
|
-{
|
|
|
|
- struct iphdr *iph = skb->nh.iph;
|
|
|
|
- struct dst_entry *odst;
|
|
|
|
- struct flowi fl = {};
|
|
|
|
- struct rtable *rt;
|
|
|
|
-
|
|
|
|
- /* We don't require ip forwarding to be enabled to be able to
|
|
|
|
- * send a RST reply for bridged traffic. */
|
|
|
|
- if (hook != NF_IP_FORWARD
|
|
|
|
-#ifdef CONFIG_BRIDGE_NETFILTER
|
|
|
|
- || (skb->nf_bridge && skb->nf_bridge->mask & BRNF_BRIDGED)
|
|
|
|
-#endif
|
|
|
|
- ) {
|
|
|
|
- fl.nl_u.ip4_u.daddr = iph->saddr;
|
|
|
|
- if (hook == NF_IP_LOCAL_IN)
|
|
|
|
- fl.nl_u.ip4_u.saddr = iph->daddr;
|
|
|
|
- fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
|
|
|
|
-
|
|
|
|
- if (ip_route_output_key(&rt, &fl) != 0)
|
|
|
|
- return NULL;
|
|
|
|
- } else {
|
|
|
|
- /* non-local src, find valid iif to satisfy
|
|
|
|
- * rp-filter when calling ip_route_input. */
|
|
|
|
- fl.nl_u.ip4_u.daddr = iph->daddr;
|
|
|
|
- if (ip_route_output_key(&rt, &fl) != 0)
|
|
|
|
- return NULL;
|
|
|
|
-
|
|
|
|
- odst = skb->dst;
|
|
|
|
- if (ip_route_input(skb, iph->saddr, iph->daddr,
|
|
|
|
- RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
|
|
|
|
- dst_release(&rt->u.dst);
|
|
|
|
- return NULL;
|
|
|
|
- }
|
|
|
|
- dst_release(&rt->u.dst);
|
|
|
|
- rt = (struct rtable *)skb->dst;
|
|
|
|
- skb->dst = odst;
|
|
|
|
-
|
|
|
|
- fl.nl_u.ip4_u.daddr = iph->saddr;
|
|
|
|
- fl.nl_u.ip4_u.saddr = iph->daddr;
|
|
|
|
- fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (rt->u.dst.error) {
|
|
|
|
- dst_release(&rt->u.dst);
|
|
|
|
- return NULL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- fl.proto = IPPROTO_TCP;
|
|
|
|
- fl.fl_ip_sport = tcph->dest;
|
|
|
|
- fl.fl_ip_dport = tcph->source;
|
|
|
|
- security_skb_classify_flow(skb, &fl);
|
|
|
|
-
|
|
|
|
- xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0);
|
|
|
|
-
|
|
|
|
- return rt;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
/* Send RST reply */
|
|
/* Send RST reply */
|
|
static void send_reset(struct sk_buff *oldskb, int hook)
|
|
static void send_reset(struct sk_buff *oldskb, int hook)
|
|
{
|
|
{
|
|
struct sk_buff *nskb;
|
|
struct sk_buff *nskb;
|
|
struct iphdr *iph = oldskb->nh.iph;
|
|
struct iphdr *iph = oldskb->nh.iph;
|
|
struct tcphdr _otcph, *oth, *tcph;
|
|
struct tcphdr _otcph, *oth, *tcph;
|
|
- struct rtable *rt;
|
|
|
|
__be16 tmp_port;
|
|
__be16 tmp_port;
|
|
__be32 tmp_addr;
|
|
__be32 tmp_addr;
|
|
int needs_ack;
|
|
int needs_ack;
|
|
- int hh_len;
|
|
|
|
|
|
+ unsigned int addr_type;
|
|
|
|
|
|
/* IP header checks: fragment. */
|
|
/* IP header checks: fragment. */
|
|
if (oldskb->nh.iph->frag_off & htons(IP_OFFSET))
|
|
if (oldskb->nh.iph->frag_off & htons(IP_OFFSET))
|
|
@@ -126,23 +66,13 @@ static void send_reset(struct sk_buff *oldskb, int hook)
|
|
if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP))
|
|
if (nf_ip_checksum(oldskb, hook, iph->ihl * 4, IPPROTO_TCP))
|
|
return;
|
|
return;
|
|
|
|
|
|
- if ((rt = route_reverse(oldskb, oth, hook)) == NULL)
|
|
|
|
- return;
|
|
|
|
-
|
|
|
|
- hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
|
|
|
|
-
|
|
|
|
/* We need a linear, writeable skb. We also need to expand
|
|
/* We need a linear, writeable skb. We also need to expand
|
|
headroom in case hh_len of incoming interface < hh_len of
|
|
headroom in case hh_len of incoming interface < hh_len of
|
|
outgoing interface */
|
|
outgoing interface */
|
|
- nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
|
|
|
|
|
|
+ nskb = skb_copy_expand(oldskb, LL_MAX_HEADER, skb_tailroom(oldskb),
|
|
GFP_ATOMIC);
|
|
GFP_ATOMIC);
|
|
- if (!nskb) {
|
|
|
|
- dst_release(&rt->u.dst);
|
|
|
|
|
|
+ if (!nskb)
|
|
return;
|
|
return;
|
|
- }
|
|
|
|
-
|
|
|
|
- dst_release(nskb->dst);
|
|
|
|
- nskb->dst = &rt->u.dst;
|
|
|
|
|
|
|
|
/* This packet will not be the same as the other: clear nf fields */
|
|
/* This packet will not be the same as the other: clear nf fields */
|
|
nf_reset(nskb);
|
|
nf_reset(nskb);
|
|
@@ -184,6 +114,21 @@ static void send_reset(struct sk_buff *oldskb, int hook)
|
|
tcph->window = 0;
|
|
tcph->window = 0;
|
|
tcph->urg_ptr = 0;
|
|
tcph->urg_ptr = 0;
|
|
|
|
|
|
|
|
+ /* Set DF, id = 0 */
|
|
|
|
+ nskb->nh.iph->frag_off = htons(IP_DF);
|
|
|
|
+ nskb->nh.iph->id = 0;
|
|
|
|
+
|
|
|
|
+ addr_type = RTN_UNSPEC;
|
|
|
|
+ if (hook != NF_IP_FORWARD
|
|
|
|
+#ifdef CONFIG_BRIDGE_NETFILTER
|
|
|
|
+ || (nskb->nf_bridge && nskb->nf_bridge->mask & BRNF_BRIDGED)
|
|
|
|
+#endif
|
|
|
|
+ )
|
|
|
|
+ addr_type = RTN_LOCAL;
|
|
|
|
+
|
|
|
|
+ if (ip_route_me_harder(&nskb, addr_type))
|
|
|
|
+ goto free_nskb;
|
|
|
|
+
|
|
/* Adjust TCP checksum */
|
|
/* Adjust TCP checksum */
|
|
nskb->ip_summed = CHECKSUM_NONE;
|
|
nskb->ip_summed = CHECKSUM_NONE;
|
|
tcph->check = 0;
|
|
tcph->check = 0;
|
|
@@ -192,12 +137,8 @@ static void send_reset(struct sk_buff *oldskb, int hook)
|
|
nskb->nh.iph->daddr,
|
|
nskb->nh.iph->daddr,
|
|
csum_partial((char *)tcph,
|
|
csum_partial((char *)tcph,
|
|
sizeof(struct tcphdr), 0));
|
|
sizeof(struct tcphdr), 0));
|
|
-
|
|
|
|
- /* Adjust IP TTL, DF */
|
|
|
|
|
|
+ /* Adjust IP TTL */
|
|
nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
|
|
nskb->nh.iph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
|
|
- /* Set DF, id = 0 */
|
|
|
|
- nskb->nh.iph->frag_off = htons(IP_DF);
|
|
|
|
- nskb->nh.iph->id = 0;
|
|
|
|
|
|
|
|
/* Adjust IP checksum */
|
|
/* Adjust IP checksum */
|
|
nskb->nh.iph->check = 0;
|
|
nskb->nh.iph->check = 0;
|