static unsigned int
fw_in(unsigned int hooknum,
struct sk_buff **pskb,
const struct net_device *in,
const struct net_device *out,
int (*okfn)(struct sk_buff *))
{
int ret = FW_BLOCK;
u_int16_t redirpt;
/* Assume worse case: any hook could change packet */
(*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
if ((*pskb)->ip_summed == CHECKSUM_HW)
(*pskb)->ip_summed = CHECKSUM_NONE;
/* Firewall rules can alter TOS: raw socket (tcpdump) may have
clone of incoming skb: don't disturb it --RR */
if (skb_cloned(*pskb) && !(*pskb)->sk) {
struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
if (!nskb)
return NF_DROP;
kfree_skb(*pskb);
*pskb = nskb;
}
switch (hooknum) {
case NF_IP_PRE_ROUTING:
if (fwops->fw_acct_in)
fwops->fw_acct_in(fwops, PF_INET,
(struct net_device *)in,
(*pskb)->nh.raw, &redirpt, pskb);
if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
*pskb = ip_ct_gather_frags(*pskb, IP_DEFRAG_CONNTRACK_IN);
if (!*pskb)
return NF_STOLEN;
}
ret = fwops->fw_input(fwops, PF_INET, (struct net_device *)in,
(*pskb)->nh.raw, &redirpt, pskb);
break;
case NF_IP_FORWARD:
/* Connection will only be set if it was
demasqueraded: if so, skip forward chain. */
if ((*pskb)->nfct)
ret = FW_ACCEPT;
else ret = fwops->fw_forward(fwops, PF_INET,
(struct net_device *)out,
(*pskb)->nh.raw, &redirpt, pskb);
break;
case NF_IP_POST_ROUTING:
ret = fwops->fw_output(fwops, PF_INET,
(struct net_device *)out,
(*pskb)->nh.raw, &redirpt, pskb);
if (ret == FW_ACCEPT || ret == FW_SKIP) {
if (fwops->fw_acct_out)
fwops->fw_acct_out(fwops, PF_INET,
(struct net_device *)out,
(*pskb)->nh.raw, &redirpt,
pskb);
/* ip_conntrack_confirm return NF_DROP or NF_ACCEPT */
if (ip_conntrack_confirm(hooknum, *pskb) == NF_DROP)
ret = FW_BLOCK;
}
break;
}
switch (ret) {
case FW_REJECT: {
/* Alexey says:
*
* Generally, routing is THE FIRST thing to make, when
* packet enters IP stack. Before packet is routed you
* cannot call any service routines from IP stack. */
struct iphdr *iph = (*pskb)->nh.iph;
if ((*pskb)->dst != NULL
|| ip_route_input(*pskb, iph->daddr, iph->saddr, iph->tos,
(struct net_device *)in) == 0)
icmp_send(*pskb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH,
0);
return NF_DROP;
}
case FW_ACCEPT:
case FW_SKIP:
if (hooknum == NF_IP_PRE_ROUTING) {
check_for_demasq(pskb);
check_for_redirect(*pskb);
} else if (hooknum == NF_IP_POST_ROUTING) {
check_for_unredirect(*pskb);
/* Handle ICMP errors from client here */
if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
&& (*pskb)->nfct)
check_for_masq_error(*pskb);
}
//.........这里部分代码省略.........
int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
{
int copyflag;
int elt;
struct sk_buff *skb1, **skb_p;
/* If skb is cloned or its head is paged, reallocate
* head pulling out all the pages (pages are considered not writable
* at the moment even if they are anonymous).
*/
if ((skb_cloned(skb) || skb_shinfo(skb)->nr_frags) &&
__pskb_pull_tail(skb, skb_pagelen(skb)-skb_headlen(skb)) == NULL)
return -ENOMEM;
/* Easy case. Most of packets will go this way. */
if (!skb_shinfo(skb)->frag_list) {
/* A little of trouble, not enough of space for trailer.
* This should not happen, when stack is tuned to generate
* good frames. OK, on miss we reallocate and reserve even more
* space, 128 bytes is fair. */
if (skb_tailroom(skb) < tailbits &&
pskb_expand_head(skb, 0, tailbits-skb_tailroom(skb)+128, GFP_ATOMIC))
return -ENOMEM;
/* Voila! */
*trailer = skb;
return 1;
}
/* Misery. We are in troubles, going to mincer fragments... */
elt = 1;
skb_p = &skb_shinfo(skb)->frag_list;
copyflag = 0;
while ((skb1 = *skb_p) != NULL) {
int ntail = 0;
/* The fragment is partially pulled by someone,
* this can happen on input. Copy it and everything
* after it. */
if (skb_shared(skb1))
copyflag = 1;
/* If the skb is the last, worry about trailer. */
if (skb1->next == NULL && tailbits) {
if (skb_shinfo(skb1)->nr_frags ||
skb_shinfo(skb1)->frag_list ||
skb_tailroom(skb1) < tailbits)
ntail = tailbits + 128;
}
if (copyflag ||
skb_cloned(skb1) ||
ntail ||
skb_shinfo(skb1)->nr_frags ||
skb_shinfo(skb1)->frag_list) {
struct sk_buff *skb2;
/* Fuck, we are miserable poor guys... */
if (ntail == 0)
skb2 = skb_copy(skb1, GFP_ATOMIC);
else
skb2 = skb_copy_expand(skb1,
skb_headroom(skb1),
ntail,
GFP_ATOMIC);
if (unlikely(skb2 == NULL))
return -ENOMEM;
if (skb1->sk)
skb_set_owner_w(skb, skb1->sk);
/* Looking around. Are we still alive?
* OK, link new skb, drop old one */
skb2->next = skb1->next;
*skb_p = skb2;
kfree_skb(skb1);
skb1 = skb2;
}
elt++;
*trailer = skb1;
skb_p = &skb1->next;
}
return elt;
}
/*
* Check if this packet is complete.
* Returns NULL on failure by any reason, and pointer
* to current nexthdr field in reassembled frame.
*
* It is called with locked fq, and caller must check that
* queue is eligible for reassembly i.e. it is not COMPLETE,
* the last and the first frames arrived and all the bits are here.
*/
static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
struct net_device *dev)
{
struct net *net = container_of(fq->q.net, struct net, ipv6.frags);
struct sk_buff *fp, *head = fq->q.fragments;
int payload_len;
unsigned int nhoff;
fq_kill(fq);
/* Make the one we just received the head. */
if (prev) {
head = prev->next;
fp = skb_clone(head, GFP_ATOMIC);
if (!fp)
goto out_oom;
fp->next = head->next;
prev->next = fp;
skb_morph(head, fq->q.fragments);
head->next = fq->q.fragments->next;
kfree_skb(fq->q.fragments);
fq->q.fragments = head;
}
WARN_ON(head == NULL);
WARN_ON(FRAG6_CB(head)->offset != 0);
/* Unfragmented part is taken from the first segment. */
payload_len = ((head->data - skb_network_header(head)) -
sizeof(struct ipv6hdr) + fq->q.len -
sizeof(struct frag_hdr));
if (payload_len > IPV6_MAXPLEN)
goto out_oversize;
/* Head of list must not be cloned. */
if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
goto out_oom;
/* If the first fragment is fragmented itself, we split
* it to two chunks: the first with data and paged part
* and the second, holding only fragments. */
if (skb_shinfo(head)->frag_list) {
struct sk_buff *clone;
int i, plen = 0;
if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL)
goto out_oom;
clone->next = head->next;
head->next = clone;
skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
skb_shinfo(head)->frag_list = NULL;
for (i=0; i<skb_shinfo(head)->nr_frags; i++)
plen += skb_shinfo(head)->frags[i].size;
clone->len = clone->data_len = head->data_len - plen;
head->data_len -= clone->len;
head->len -= clone->len;
clone->csum = 0;
clone->ip_summed = head->ip_summed;
atomic_add(clone->truesize, &fq->q.net->mem);
}
/* We have to remove fragment header from datagram and to relocate
* header in order to calculate ICV correctly. */
nhoff = fq->nhoffset;
skb_network_header(head)[nhoff] = skb_transport_header(head)[0];
memmove(head->head + sizeof(struct frag_hdr), head->head,
(head->data - head->head) - sizeof(struct frag_hdr));
head->mac_header += sizeof(struct frag_hdr);
head->network_header += sizeof(struct frag_hdr);
skb_shinfo(head)->frag_list = head->next;
skb_reset_transport_header(head);
skb_push(head, head->data - skb_network_header(head));
atomic_sub(head->truesize, &fq->q.net->mem);
for (fp=head->next; fp; fp = fp->next) {
head->data_len += fp->len;
head->len += fp->len;
if (head->ip_summed != fp->ip_summed)
head->ip_summed = CHECKSUM_NONE;
else if (head->ip_summed == CHECKSUM_COMPLETE)
head->csum = csum_add(head->csum, fp->csum);
head->truesize += fp->truesize;
atomic_sub(fp->truesize, &fq->q.net->mem);
}
head->next = NULL;
//.........这里部分代码省略.........
/*
* Check if this packet is complete.
* Returns NULL on failure by any reason, and pointer
* to current nexthdr field in reassembled frame.
*
* It is called with locked fq, and caller must check that
* queue is eligible for reassembly i.e. it is not COMPLETE,
* the last and the first frames arrived and all the bits are here.
*/
static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff **skb_in,
struct net_device *dev)
{
struct sk_buff *fp, *head = fq->fragments;
int remove_fraghdr = 0;
int payload_len;
int nhoff;
fq_kill(fq);
BUG_TRAP(head != NULL);
BUG_TRAP(FRAG6_CB(head)->offset == 0);
/* Unfragmented part is taken from the first segment. */
payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len;
nhoff = head->h.raw - head->nh.raw;
if (payload_len > 65535) {
payload_len -= 8;
if (payload_len > 65535)
goto out_oversize;
remove_fraghdr = 1;
}
/* Head of list must not be cloned. */
if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC))
goto out_oom;
/* If the first fragment is fragmented itself, we split
* it to two chunks: the first with data and paged part
* and the second, holding only fragments. */
if (skb_shinfo(head)->frag_list) {
struct sk_buff *clone;
int i, plen = 0;
if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL)
goto out_oom;
clone->next = head->next;
head->next = clone;
skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list;
skb_shinfo(head)->frag_list = NULL;
for (i=0; i<skb_shinfo(head)->nr_frags; i++)
plen += skb_shinfo(head)->frags[i].size;
clone->len = clone->data_len = head->data_len - plen;
head->data_len -= clone->len;
head->len -= clone->len;
clone->csum = 0;
clone->ip_summed = head->ip_summed;
atomic_add(clone->truesize, &ip6_frag_mem);
}
/* Normally we do not remove frag header from datagram, but
* we have to do this and to relocate header, when payload
* is > 65535-8. */
if (remove_fraghdr) {
nhoff = fq->nhoffset;
head->nh.raw[nhoff] = head->h.raw[0];
memmove(head->head+8, head->head, (head->data-head->head)-8);
head->mac.raw += 8;
head->nh.raw += 8;
} else {
((struct frag_hdr*)head->h.raw)->frag_off = 0;
}
skb_shinfo(head)->frag_list = head->next;
head->h.raw = head->data;
skb_push(head, head->data - head->nh.raw);
atomic_sub(head->truesize, &ip6_frag_mem);
for (fp=head->next; fp; fp = fp->next) {
head->data_len += fp->len;
head->len += fp->len;
if (head->ip_summed != fp->ip_summed)
head->ip_summed = CHECKSUM_NONE;
else if (head->ip_summed == CHECKSUM_HW)
head->csum = csum_add(head->csum, fp->csum);
head->truesize += fp->truesize;
atomic_sub(fp->truesize, &ip6_frag_mem);
}
head->next = NULL;
head->dev = dev;
head->stamp = fq->stamp;
head->nh.ipv6h->payload_len = ntohs(payload_len);
*skb_in = head;
/* Yes, and fold redundant checksum back. 8) */
if (head->ip_summed == CHECKSUM_HW)
head->csum = csum_partial(head->nh.raw, head->h.raw-head->nh.raw, head->csum);
//.........这里部分代码省略.........
请发表评论