OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [ipv4/] [netfilter/] [ipt_REJECT.c] - Diff between revs 1275 and 1765

Only display areas with differences | Details | Blame | View Log

Rev 1275 Rev 1765
/*
/*
 * This is a module which is used for rejecting packets.
 * This is a module which is used for rejecting packets.
 * Added support for customized reject packets (Jozsef Kadlecsik).
 * Added support for customized reject packets (Jozsef Kadlecsik).
 * Added support for ICMP type-3-code-13 (Maciej Soltysiak). [RFC 1812]
 * Added support for ICMP type-3-code-13 (Maciej Soltysiak). [RFC 1812]
 */
 */
#include <linux/config.h>
#include <linux/config.h>
#include <linux/module.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include <linux/icmp.h>
#include <net/icmp.h>
#include <net/icmp.h>
#include <net/ip.h>
#include <net/ip.h>
#include <net/tcp.h>
#include <net/tcp.h>
#include <net/route.h>
#include <net/route.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_REJECT.h>
#include <linux/netfilter_ipv4/ipt_REJECT.h>
 
 
#if 0
#if 0
#define DEBUGP printk
#define DEBUGP printk
#else
#else
#define DEBUGP(format, args...)
#define DEBUGP(format, args...)
#endif
#endif
 
 
/* If the original packet is part of a connection, but the connection
/* If the original packet is part of a connection, but the connection
   is not confirmed, our manufactured reply will not be associated
   is not confirmed, our manufactured reply will not be associated
   with it, so we need to do this manually. */
   with it, so we need to do this manually. */
static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
{
{
        void (*attach)(struct sk_buff *, struct nf_ct_info *);
        void (*attach)(struct sk_buff *, struct nf_ct_info *);
 
 
        /* Avoid module unload race with ip_ct_attach being NULLed out */
        /* Avoid module unload race with ip_ct_attach being NULLed out */
        if (nfct && (attach = ip_ct_attach) != NULL)
        if (nfct && (attach = ip_ct_attach) != NULL)
                attach(new_skb, nfct);
                attach(new_skb, nfct);
}
}
 
 
static inline struct rtable *route_reverse(struct sk_buff *skb, int hook)
static inline struct rtable *route_reverse(struct sk_buff *skb, int hook)
{
{
        struct iphdr *iph = skb->nh.iph;
        struct iphdr *iph = skb->nh.iph;
        struct dst_entry *odst;
        struct dst_entry *odst;
        struct rt_key key = {};
        struct rt_key key = {};
        struct rtable *rt;
        struct rtable *rt;
 
 
        if (hook != NF_IP_FORWARD) {
        if (hook != NF_IP_FORWARD) {
                key.dst = iph->saddr;
                key.dst = iph->saddr;
                if (hook == NF_IP_LOCAL_IN)
                if (hook == NF_IP_LOCAL_IN)
                        key.src = iph->daddr;
                        key.src = iph->daddr;
                key.tos = RT_TOS(iph->tos);
                key.tos = RT_TOS(iph->tos);
 
 
                if (ip_route_output_key(&rt, &key) != 0)
                if (ip_route_output_key(&rt, &key) != 0)
                        return NULL;
                        return NULL;
        } else {
        } else {
                /* non-local src, find valid iif to satisfy
                /* non-local src, find valid iif to satisfy
                 * rp-filter when calling ip_route_input. */
                 * rp-filter when calling ip_route_input. */
                key.dst = iph->daddr;
                key.dst = iph->daddr;
                if (ip_route_output_key(&rt, &key) != 0)
                if (ip_route_output_key(&rt, &key) != 0)
                        return NULL;
                        return NULL;
 
 
                odst = skb->dst;
                odst = skb->dst;
                if (ip_route_input(skb, iph->saddr, iph->daddr,
                if (ip_route_input(skb, iph->saddr, iph->daddr,
                                   RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
                                   RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
                        dst_release(&rt->u.dst);
                        dst_release(&rt->u.dst);
                        return NULL;
                        return NULL;
                }
                }
                dst_release(&rt->u.dst);
                dst_release(&rt->u.dst);
                rt = (struct rtable *)skb->dst;
                rt = (struct rtable *)skb->dst;
                skb->dst = odst;
                skb->dst = odst;
        }
        }
 
 
        if (rt->u.dst.error) {
        if (rt->u.dst.error) {
                dst_release(&rt->u.dst);
                dst_release(&rt->u.dst);
                rt = NULL;
                rt = NULL;
        }
        }
 
 
        return rt;
        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 tcphdr *otcph, *tcph;
        struct tcphdr *otcph, *tcph;
        struct rtable *rt;
        struct rtable *rt;
        unsigned int otcplen;
        unsigned int otcplen;
        u_int16_t tmp_port;
        u_int16_t tmp_port;
        u_int32_t tmp_addr;
        u_int32_t tmp_addr;
        int needs_ack;
        int needs_ack;
        int hh_len;
        int hh_len;
 
 
        /* IP header checks: fragment, too short. */
        /* IP header checks: fragment, too short. */
        if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
        if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
            || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
            || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
                return;
                return;
 
 
        otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
        otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
        otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
        otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
 
 
        /* No RST for RST. */
        /* No RST for RST. */
        if (otcph->rst)
        if (otcph->rst)
                return;
                return;
 
 
        /* Check checksum. */
        /* Check checksum. */
        if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
        if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
                         oldskb->nh.iph->daddr,
                         oldskb->nh.iph->daddr,
                         csum_partial((char *)otcph, otcplen, 0)) != 0)
                         csum_partial((char *)otcph, otcplen, 0)) != 0)
                return;
                return;
 
 
        if ((rt = route_reverse(oldskb, hook)) == NULL)
        if ((rt = route_reverse(oldskb, hook)) == NULL)
                return;
                return;
 
 
        hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
        hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
 
 
 
 
        /* Copy skb (even if skb is about to be dropped, we can't just
        /* Copy skb (even if skb is about to be dropped, we can't just
           clone it because there may be other things, such as tcpdump,
           clone it because there may be other things, such as tcpdump,
           interested in it). We also need to expand headroom in case
           interested in it). We also need to expand headroom in case
           hh_len of incoming interface < hh_len of outgoing interface */
           hh_len of incoming interface < hh_len of outgoing interface */
        nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
        nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
                               GFP_ATOMIC);
                               GFP_ATOMIC);
        if (!nskb) {
        if (!nskb) {
                dst_release(&rt->u.dst);
                dst_release(&rt->u.dst);
                return;
                return;
        }
        }
 
 
        dst_release(nskb->dst);
        dst_release(nskb->dst);
        nskb->dst = &rt->u.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_conntrack_put(nskb->nfct);
        nf_conntrack_put(nskb->nfct);
        nskb->nfct = NULL;
        nskb->nfct = NULL;
        nskb->nfcache = 0;
        nskb->nfcache = 0;
#ifdef CONFIG_NETFILTER_DEBUG
#ifdef CONFIG_NETFILTER_DEBUG
        nskb->nf_debug = 0;
        nskb->nf_debug = 0;
#endif
#endif
        nskb->nfmark = 0;
        nskb->nfmark = 0;
 
 
        tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
        tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
 
 
        /* Swap source and dest */
        /* Swap source and dest */
        tmp_addr = nskb->nh.iph->saddr;
        tmp_addr = nskb->nh.iph->saddr;
        nskb->nh.iph->saddr = nskb->nh.iph->daddr;
        nskb->nh.iph->saddr = nskb->nh.iph->daddr;
        nskb->nh.iph->daddr = tmp_addr;
        nskb->nh.iph->daddr = tmp_addr;
        tmp_port = tcph->source;
        tmp_port = tcph->source;
        tcph->source = tcph->dest;
        tcph->source = tcph->dest;
        tcph->dest = tmp_port;
        tcph->dest = tmp_port;
 
 
        /* Truncate to length (no data) */
        /* Truncate to length (no data) */
        tcph->doff = sizeof(struct tcphdr)/4;
        tcph->doff = sizeof(struct tcphdr)/4;
        skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
        skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
        nskb->nh.iph->tot_len = htons(nskb->len);
        nskb->nh.iph->tot_len = htons(nskb->len);
 
 
        if (tcph->ack) {
        if (tcph->ack) {
                needs_ack = 0;
                needs_ack = 0;
                tcph->seq = otcph->ack_seq;
                tcph->seq = otcph->ack_seq;
                tcph->ack_seq = 0;
                tcph->ack_seq = 0;
        } else {
        } else {
                needs_ack = 1;
                needs_ack = 1;
                tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
                tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
                                      + otcplen - (otcph->doff<<2));
                                      + otcplen - (otcph->doff<<2));
                tcph->seq = 0;
                tcph->seq = 0;
        }
        }
 
 
        /* Reset flags */
        /* Reset flags */
        ((u_int8_t *)tcph)[13] = 0;
        ((u_int8_t *)tcph)[13] = 0;
        tcph->rst = 1;
        tcph->rst = 1;
        tcph->ack = needs_ack;
        tcph->ack = needs_ack;
 
 
        tcph->window = 0;
        tcph->window = 0;
        tcph->urg_ptr = 0;
        tcph->urg_ptr = 0;
 
 
        /* Adjust TCP checksum */
        /* Adjust TCP checksum */
        tcph->check = 0;
        tcph->check = 0;
        tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
        tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
                                   nskb->nh.iph->saddr,
                                   nskb->nh.iph->saddr,
                                   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, DF */
        nskb->nh.iph->ttl = MAXTTL;
        nskb->nh.iph->ttl = MAXTTL;
        /* Set DF, id = 0 */
        /* Set DF, id = 0 */
        nskb->nh.iph->frag_off = htons(IP_DF);
        nskb->nh.iph->frag_off = htons(IP_DF);
        nskb->nh.iph->id = 0;
        nskb->nh.iph->id = 0;
 
 
        /* Adjust IP checksum */
        /* Adjust IP checksum */
        nskb->nh.iph->check = 0;
        nskb->nh.iph->check = 0;
        nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,
        nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,
                                           nskb->nh.iph->ihl);
                                           nskb->nh.iph->ihl);
 
 
        /* "Never happens" */
        /* "Never happens" */
        if (nskb->len > nskb->dst->pmtu)
        if (nskb->len > nskb->dst->pmtu)
                goto free_nskb;
                goto free_nskb;
 
 
        connection_attach(nskb, oldskb->nfct);
        connection_attach(nskb, oldskb->nfct);
 
 
        NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
        NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
                ip_finish_output);
                ip_finish_output);
        return;
        return;
 
 
 free_nskb:
 free_nskb:
        kfree_skb(nskb);
        kfree_skb(nskb);
}
}
 
 
static void send_unreach(struct sk_buff *skb_in, int code)
static void send_unreach(struct sk_buff *skb_in, int code)
{
{
        struct iphdr *iph;
        struct iphdr *iph;
        struct udphdr *udph;
        struct udphdr *udph;
        struct icmphdr *icmph;
        struct icmphdr *icmph;
        struct sk_buff *nskb;
        struct sk_buff *nskb;
        u32 saddr;
        u32 saddr;
        u8 tos;
        u8 tos;
        int hh_len, length;
        int hh_len, length;
        struct rtable *rt = (struct rtable*)skb_in->dst;
        struct rtable *rt = (struct rtable*)skb_in->dst;
        unsigned char *data;
        unsigned char *data;
 
 
        if (!rt)
        if (!rt)
                return;
                return;
 
 
        /* FIXME: Use sysctl number. --RR */
        /* FIXME: Use sysctl number. --RR */
        if (!xrlim_allow(&rt->u.dst, 1*HZ))
        if (!xrlim_allow(&rt->u.dst, 1*HZ))
                return;
                return;
 
 
        iph = skb_in->nh.iph;
        iph = skb_in->nh.iph;
 
 
        /* No replies to physical multicast/broadcast */
        /* No replies to physical multicast/broadcast */
        if (skb_in->pkt_type!=PACKET_HOST)
        if (skb_in->pkt_type!=PACKET_HOST)
                return;
                return;
 
 
        /* Now check at the protocol level */
        /* Now check at the protocol level */
        if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
        if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST))
                return;
                return;
 
 
        /* Only reply to fragment 0. */
        /* Only reply to fragment 0. */
        if (iph->frag_off&htons(IP_OFFSET))
        if (iph->frag_off&htons(IP_OFFSET))
                return;
                return;
 
 
        /* if UDP checksum is set, verify it's correct */
        /* if UDP checksum is set, verify it's correct */
        if (iph->protocol == IPPROTO_UDP
        if (iph->protocol == IPPROTO_UDP
            && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) {
            && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) {
                int datalen = skb_in->len - (iph->ihl<<2);
                int datalen = skb_in->len - (iph->ihl<<2);
                udph = (struct udphdr *)((char *)iph + (iph->ihl<<2));
                udph = (struct udphdr *)((char *)iph + (iph->ihl<<2));
                if (udph->check
                if (udph->check
                    && csum_tcpudp_magic(iph->saddr, iph->daddr,
                    && csum_tcpudp_magic(iph->saddr, iph->daddr,
                                         datalen, IPPROTO_UDP,
                                         datalen, IPPROTO_UDP,
                                         csum_partial((char *)udph, datalen,
                                         csum_partial((char *)udph, datalen,
                                                      0)) != 0)
                                                      0)) != 0)
                        return;
                        return;
        }
        }
 
 
        /* If we send an ICMP error to an ICMP error a mess would result.. */
        /* If we send an ICMP error to an ICMP error a mess would result.. */
        if (iph->protocol == IPPROTO_ICMP
        if (iph->protocol == IPPROTO_ICMP
            && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) {
            && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) {
                icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
                icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
                /* Between echo-reply (0) and timestamp (13),
                /* Between echo-reply (0) and timestamp (13),
                   everything except echo-request (8) is an error.
                   everything except echo-request (8) is an error.
                   Also, anything greater than NR_ICMP_TYPES is
                   Also, anything greater than NR_ICMP_TYPES is
                   unknown, and hence should be treated as an error... */
                   unknown, and hence should be treated as an error... */
                if ((icmph->type < ICMP_TIMESTAMP
                if ((icmph->type < ICMP_TIMESTAMP
                     && icmph->type != ICMP_ECHOREPLY
                     && icmph->type != ICMP_ECHOREPLY
                     && icmph->type != ICMP_ECHO)
                     && icmph->type != ICMP_ECHO)
                    || icmph->type > NR_ICMP_TYPES)
                    || icmph->type > NR_ICMP_TYPES)
                        return;
                        return;
        }
        }
 
 
        saddr = iph->daddr;
        saddr = iph->daddr;
        if (!(rt->rt_flags & RTCF_LOCAL))
        if (!(rt->rt_flags & RTCF_LOCAL))
                saddr = 0;
                saddr = 0;
 
 
        tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL;
        tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL;
 
 
        if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
        if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0))
                return;
                return;
 
 
        /* RFC says return as much as we can without exceeding 576 bytes. */
        /* RFC says return as much as we can without exceeding 576 bytes. */
        length = skb_in->len + sizeof(struct iphdr) + sizeof(struct icmphdr);
        length = skb_in->len + sizeof(struct iphdr) + sizeof(struct icmphdr);
 
 
        if (length > rt->u.dst.pmtu)
        if (length > rt->u.dst.pmtu)
                length = rt->u.dst.pmtu;
                length = rt->u.dst.pmtu;
        if (length > 576)
        if (length > 576)
                length = 576;
                length = 576;
 
 
        hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
        hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
 
 
        nskb = alloc_skb(hh_len+15+length, GFP_ATOMIC);
        nskb = alloc_skb(hh_len+15+length, GFP_ATOMIC);
        if (!nskb) {
        if (!nskb) {
                ip_rt_put(rt);
                ip_rt_put(rt);
                return;
                return;
        }
        }
 
 
        nskb->priority = 0;
        nskb->priority = 0;
        nskb->dst = &rt->u.dst;
        nskb->dst = &rt->u.dst;
        skb_reserve(nskb, hh_len);
        skb_reserve(nskb, hh_len);
 
 
        /* Set up IP header */
        /* Set up IP header */
        iph = nskb->nh.iph
        iph = nskb->nh.iph
                = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
                = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
        iph->version=4;
        iph->version=4;
        iph->ihl=5;
        iph->ihl=5;
        iph->tos=tos;
        iph->tos=tos;
        iph->tot_len = htons(length);
        iph->tot_len = htons(length);
 
 
        /* PMTU discovery never applies to ICMP packets. */
        /* PMTU discovery never applies to ICMP packets. */
        iph->frag_off = 0;
        iph->frag_off = 0;
 
 
        iph->ttl = MAXTTL;
        iph->ttl = MAXTTL;
        ip_select_ident(iph, &rt->u.dst, NULL);
        ip_select_ident(iph, &rt->u.dst, NULL);
        iph->protocol=IPPROTO_ICMP;
        iph->protocol=IPPROTO_ICMP;
        iph->saddr=rt->rt_src;
        iph->saddr=rt->rt_src;
        iph->daddr=rt->rt_dst;
        iph->daddr=rt->rt_dst;
        iph->check=0;
        iph->check=0;
        iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
        iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
 
 
        /* Set up ICMP header. */
        /* Set up ICMP header. */
        icmph = nskb->h.icmph
        icmph = nskb->h.icmph
                = (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr));
                = (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr));
        icmph->type = ICMP_DEST_UNREACH;
        icmph->type = ICMP_DEST_UNREACH;
        icmph->code = code;
        icmph->code = code;
        icmph->un.gateway = 0;
        icmph->un.gateway = 0;
        icmph->checksum = 0;
        icmph->checksum = 0;
 
 
        /* Copy as much of original packet as will fit */
        /* Copy as much of original packet as will fit */
        data = skb_put(nskb,
        data = skb_put(nskb,
                       length - sizeof(struct iphdr) - sizeof(struct icmphdr));
                       length - sizeof(struct iphdr) - sizeof(struct icmphdr));
        /* FIXME: won't work with nonlinear skbs --RR */
        /* FIXME: won't work with nonlinear skbs --RR */
        memcpy(data, skb_in->nh.iph,
        memcpy(data, skb_in->nh.iph,
               length - sizeof(struct iphdr) - sizeof(struct icmphdr));
               length - sizeof(struct iphdr) - sizeof(struct icmphdr));
        icmph->checksum = ip_compute_csum((unsigned char *)icmph,
        icmph->checksum = ip_compute_csum((unsigned char *)icmph,
                                          length - sizeof(struct iphdr));
                                          length - sizeof(struct iphdr));
 
 
        connection_attach(nskb, skb_in->nfct);
        connection_attach(nskb, skb_in->nfct);
 
 
        NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
        NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
                ip_finish_output);
                ip_finish_output);
}
}
 
 
static unsigned int reject(struct sk_buff **pskb,
static unsigned int reject(struct sk_buff **pskb,
                           unsigned int hooknum,
                           unsigned int hooknum,
                           const struct net_device *in,
                           const struct net_device *in,
                           const struct net_device *out,
                           const struct net_device *out,
                           const void *targinfo,
                           const void *targinfo,
                           void *userinfo)
                           void *userinfo)
{
{
        const struct ipt_reject_info *reject = targinfo;
        const struct ipt_reject_info *reject = targinfo;
 
 
        /* Our naive response construction doesn't deal with IP
        /* Our naive response construction doesn't deal with IP
           options, and probably shouldn't try. */
           options, and probably shouldn't try. */
        if ((*pskb)->nh.iph->ihl<<2 != sizeof(struct iphdr))
        if ((*pskb)->nh.iph->ihl<<2 != sizeof(struct iphdr))
                return NF_DROP;
                return NF_DROP;
 
 
        /* WARNING: This code causes reentry within iptables.
        /* WARNING: This code causes reentry within iptables.
           This means that the iptables jump stack is now crap.  We
           This means that the iptables jump stack is now crap.  We
           must return an absolute verdict. --RR */
           must return an absolute verdict. --RR */
        switch (reject->with) {
        switch (reject->with) {
        case IPT_ICMP_NET_UNREACHABLE:
        case IPT_ICMP_NET_UNREACHABLE:
                send_unreach(*pskb, ICMP_NET_UNREACH);
                send_unreach(*pskb, ICMP_NET_UNREACH);
                break;
                break;
        case IPT_ICMP_HOST_UNREACHABLE:
        case IPT_ICMP_HOST_UNREACHABLE:
                send_unreach(*pskb, ICMP_HOST_UNREACH);
                send_unreach(*pskb, ICMP_HOST_UNREACH);
                break;
                break;
        case IPT_ICMP_PROT_UNREACHABLE:
        case IPT_ICMP_PROT_UNREACHABLE:
                send_unreach(*pskb, ICMP_PROT_UNREACH);
                send_unreach(*pskb, ICMP_PROT_UNREACH);
                break;
                break;
        case IPT_ICMP_PORT_UNREACHABLE:
        case IPT_ICMP_PORT_UNREACHABLE:
                send_unreach(*pskb, ICMP_PORT_UNREACH);
                send_unreach(*pskb, ICMP_PORT_UNREACH);
                break;
                break;
        case IPT_ICMP_NET_PROHIBITED:
        case IPT_ICMP_NET_PROHIBITED:
                send_unreach(*pskb, ICMP_NET_ANO);
                send_unreach(*pskb, ICMP_NET_ANO);
                break;
                break;
        case IPT_ICMP_HOST_PROHIBITED:
        case IPT_ICMP_HOST_PROHIBITED:
                send_unreach(*pskb, ICMP_HOST_ANO);
                send_unreach(*pskb, ICMP_HOST_ANO);
                break;
                break;
        case IPT_ICMP_ADMIN_PROHIBITED:
        case IPT_ICMP_ADMIN_PROHIBITED:
                send_unreach(*pskb, ICMP_PKT_FILTERED);
                send_unreach(*pskb, ICMP_PKT_FILTERED);
                break;
                break;
        case IPT_TCP_RESET:
        case IPT_TCP_RESET:
                send_reset(*pskb, hooknum);
                send_reset(*pskb, hooknum);
        case IPT_ICMP_ECHOREPLY:
        case IPT_ICMP_ECHOREPLY:
                /* Doesn't happen. */
                /* Doesn't happen. */
                break;
                break;
        }
        }
 
 
        return NF_DROP;
        return NF_DROP;
}
}
 
 
static int check(const char *tablename,
static int check(const char *tablename,
                 const struct ipt_entry *e,
                 const struct ipt_entry *e,
                 void *targinfo,
                 void *targinfo,
                 unsigned int targinfosize,
                 unsigned int targinfosize,
                 unsigned int hook_mask)
                 unsigned int hook_mask)
{
{
        const struct ipt_reject_info *rejinfo = targinfo;
        const struct ipt_reject_info *rejinfo = targinfo;
 
 
        if (targinfosize != IPT_ALIGN(sizeof(struct ipt_reject_info))) {
        if (targinfosize != IPT_ALIGN(sizeof(struct ipt_reject_info))) {
                DEBUGP("REJECT: targinfosize %u != 0\n", targinfosize);
                DEBUGP("REJECT: targinfosize %u != 0\n", targinfosize);
                return 0;
                return 0;
        }
        }
 
 
        /* Only allow these for packet filtering. */
        /* Only allow these for packet filtering. */
        if (strcmp(tablename, "filter") != 0) {
        if (strcmp(tablename, "filter") != 0) {
                DEBUGP("REJECT: bad table `%s'.\n", tablename);
                DEBUGP("REJECT: bad table `%s'.\n", tablename);
                return 0;
                return 0;
        }
        }
        if ((hook_mask & ~((1 << NF_IP_LOCAL_IN)
        if ((hook_mask & ~((1 << NF_IP_LOCAL_IN)
                           | (1 << NF_IP_FORWARD)
                           | (1 << NF_IP_FORWARD)
                           | (1 << NF_IP_LOCAL_OUT))) != 0) {
                           | (1 << NF_IP_LOCAL_OUT))) != 0) {
                DEBUGP("REJECT: bad hook mask %X\n", hook_mask);
                DEBUGP("REJECT: bad hook mask %X\n", hook_mask);
                return 0;
                return 0;
        }
        }
 
 
        if (rejinfo->with == IPT_ICMP_ECHOREPLY) {
        if (rejinfo->with == IPT_ICMP_ECHOREPLY) {
                printk("REJECT: ECHOREPLY no longer supported.\n");
                printk("REJECT: ECHOREPLY no longer supported.\n");
                return 0;
                return 0;
        } else if (rejinfo->with == IPT_TCP_RESET) {
        } else if (rejinfo->with == IPT_TCP_RESET) {
                /* Must specify that it's a TCP packet */
                /* Must specify that it's a TCP packet */
                if (e->ip.proto != IPPROTO_TCP
                if (e->ip.proto != IPPROTO_TCP
                    || (e->ip.invflags & IPT_INV_PROTO)) {
                    || (e->ip.invflags & IPT_INV_PROTO)) {
                        DEBUGP("REJECT: TCP_RESET illegal for non-tcp\n");
                        DEBUGP("REJECT: TCP_RESET illegal for non-tcp\n");
                        return 0;
                        return 0;
                }
                }
        }
        }
 
 
        return 1;
        return 1;
}
}
 
 
static struct ipt_target ipt_reject_reg
static struct ipt_target ipt_reject_reg
= { { NULL, NULL }, "REJECT", reject, check, NULL, THIS_MODULE };
= { { NULL, NULL }, "REJECT", reject, check, NULL, THIS_MODULE };
 
 
static int __init init(void)
static int __init init(void)
{
{
        if (ipt_register_target(&ipt_reject_reg))
        if (ipt_register_target(&ipt_reject_reg))
                return -EINVAL;
                return -EINVAL;
        return 0;
        return 0;
}
}
 
 
static void __exit fini(void)
static void __exit fini(void)
{
{
        ipt_unregister_target(&ipt_reject_reg);
        ipt_unregister_target(&ipt_reject_reg);
}
}
 
 
module_init(init);
module_init(init);
module_exit(fini);
module_exit(fini);
MODULE_LICENSE("GPL");
MODULE_LICENSE("GPL");
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.