#include <net/ip.h>
#include <net/tcp.h>
#include <net/route.h>
+#include <net/dst.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_REJECT.h>
#ifdef CONFIG_BRIDGE_NETFILTER
#define DEBUGP(format, args...)
#endif
-/* If the original packet is part of a connection, but the connection
- is not confirmed, our manufactured reply will not be associated
- with it, so we need to do this manually. */
-static void connection_attach(struct sk_buff *new_skb, struct sk_buff *skb)
-{
- void (*attach)(struct sk_buff *, struct sk_buff *);
-
- /* Avoid module unload race with ip_ct_attach being NULLed out */
- if (skb->nfct && (attach = ip_ct_attach) != NULL) {
- mb(); /* Just to be sure: must be read before executing this */
- attach(new_skb, skb);
- }
-}
-
-static inline struct rtable *route_reverse(struct sk_buff *skb, int hook)
+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;
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;
+
+ if (xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0)) {
dst_release(&rt->u.dst);
rt = NULL;
}
return;
/* FIXME: Check checksum --RR */
- if ((rt = route_reverse(oldskb, hook)) == NULL)
+ if ((rt = route_reverse(oldskb, oth, hook)) == NULL)
return;
hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
if (nskb->len > dst_pmtu(nskb->dst))
goto free_nskb;
- connection_attach(nskb, oldskb);
+ nf_ct_attach(nskb, oldskb);
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
ip_finish_output);
static void send_unreach(struct sk_buff *skb_in, int code)
{
struct iphdr *iph;
- struct udphdr *udph;
struct icmphdr *icmph;
struct sk_buff *nskb;
u32 saddr;
if (skb_in->len < skb_in->nh.iph->ihl*4 + 8)
return;
- /* if UDP checksum is set, verify it's correct */
- if (iph->protocol == IPPROTO_UDP
- && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) {
- int datalen = skb_in->len - (iph->ihl<<2);
- udph = (struct udphdr *)((char *)iph + (iph->ihl<<2));
- if (udph->check
- && csum_tcpudp_magic(iph->saddr, iph->daddr,
- datalen, IPPROTO_UDP,
- csum_partial((char *)udph, datalen,
- 0)) != 0)
- return;
- }
-
/* If we send an ICMP error to an ICMP error a mess would result.. */
- if (iph->protocol == IPPROTO_ICMP
- && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) {
- icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
+ if (iph->protocol == IPPROTO_ICMP) {
+ struct icmphdr ihdr;
- if (skb_copy_bits(skb_in, skb_in->nh.iph->ihl*4,
- icmph, sizeof(*icmph)) < 0)
+ icmph = skb_header_pointer(skb_in, skb_in->nh.iph->ihl*4,
+ sizeof(ihdr), &ihdr);
+ if (!icmph)
return;
/* Between echo-reply (0) and timestamp (13),
tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL;
{
- struct flowi fl = { .nl_u = { .ip4_u =
- { .daddr = skb_in->nh.iph->saddr,
- .saddr = saddr,
- .tos = RT_TOS(tos) } } };
+ struct flowi fl = {
+ .nl_u = {
+ .ip4_u = {
+ .daddr = skb_in->nh.iph->saddr,
+ .saddr = saddr,
+ .tos = RT_TOS(tos)
+ }
+ },
+ .proto = IPPROTO_ICMP,
+ .uli_u = {
+ .icmpt = {
+ .type = ICMP_DEST_UNREACH,
+ .code = code
+ }
+ }
+ };
+
if (ip_route_output_key(&rt, &fl))
return;
}
icmph->checksum = ip_compute_csum((unsigned char *)icmph,
length - sizeof(struct iphdr));
- connection_attach(nskb, skb_in);
+ nf_ct_attach(nskb, skb_in);
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
ip_finish_output);