Commit 274cac6d authored by David S. Miller's avatar David S. Miller

[NET]: Add skb_header_pointer, and use it where possible.

This greatly improves netfilter performance where
the wanted header area is in the linear SKB data
area, therefore no copy into the temporary buffer
is needed.
Signed-off-by: default avatarDavid S. Miller <davem@redhat.com>
parent 4638004e
......@@ -1107,6 +1107,20 @@ extern void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
extern void skb_split(struct sk_buff *skb,
struct sk_buff *skb1, const u32 len);
static inline void *skb_header_pointer(const struct sk_buff *skb, int offset,
int len, void *buffer)
{
int hlen = skb_headlen(skb);
if (offset + len <= hlen)
return skb->data + offset;
if (skb_copy_bits(skb, offset, buffer, len) < 0)
return NULL;
return buffer;
}
extern void skb_init(void);
extern void skb_add_mtu(int mtu);
......
......@@ -73,20 +73,27 @@ static int ebt_mac_wormhash_check_integrity(const struct ebt_mac_wormhash
static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr)
{
if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP)) {
struct iphdr iph;
struct iphdr _iph, *ih;
if (skb_copy_bits(skb, 0, &iph, sizeof(iph)))
ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
if (ih == NULL)
return -1;
*addr = iph.daddr;
*addr = ih->daddr;
} else if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) {
struct arphdr arph;
struct arphdr _arph, *ah;
uint32_t buf, *bp;
if (skb_copy_bits(skb, 0, &arph, sizeof(arph)) ||
arph.ar_pln != sizeof(uint32_t) || arph.ar_hln != ETH_ALEN)
ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
if (ah == NULL ||
ah->ar_pln != sizeof(uint32_t) ||
ah->ar_hln != ETH_ALEN)
return -1;
if (skb_copy_bits(skb, sizeof(struct arphdr) +
2 * ETH_ALEN + sizeof(uint32_t), addr, sizeof(uint32_t)))
bp = skb_header_pointer(skb, sizeof(struct arphdr) +
2 * ETH_ALEN + sizeof(uint32_t),
sizeof(uint32_t), &buf);
if (bp == NULL)
return -1;
*addr = *bp;
}
return 0;
}
......@@ -94,20 +101,26 @@ static int get_ip_dst(const struct sk_buff *skb, uint32_t *addr)
static int get_ip_src(const struct sk_buff *skb, uint32_t *addr)
{
if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_IP)) {
struct iphdr iph;
struct iphdr _iph, *ih;
if (skb_copy_bits(skb, 0, &iph, sizeof(iph)))
ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
if (ih == NULL)
return -1;
*addr = iph.saddr;
*addr = ih->saddr;
} else if (skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) {
struct arphdr arph;
struct arphdr _arph, *ah;
uint32_t buf, *bp;
if (skb_copy_bits(skb, 0, &arph, sizeof(arph)) ||
arph.ar_pln != sizeof(uint32_t) || arph.ar_hln != ETH_ALEN)
ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
if (ah == NULL ||
ah->ar_pln != sizeof(uint32_t) ||
ah->ar_hln != ETH_ALEN)
return -1;
if (skb_copy_bits(skb, sizeof(struct arphdr) +
ETH_ALEN, addr, sizeof(uint32_t)))
bp = skb_header_pointer(skb, sizeof(struct arphdr) +
ETH_ALEN, sizeof(uint32_t), &buf);
if (bp == NULL)
return -1;
*addr = *bp;
}
return 0;
}
......
......@@ -19,72 +19,79 @@ static int ebt_filter_arp(const struct sk_buff *skb, const struct net_device *in
const struct net_device *out, const void *data, unsigned int datalen)
{
struct ebt_arp_info *info = (struct ebt_arp_info *)data;
struct arphdr arph;
struct arphdr _arph, *ah;
if (skb_copy_bits(skb, 0, &arph, sizeof(arph)))
ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
if (ah == NULL)
return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_OPCODE && FWINV(info->opcode !=
arph.ar_op, EBT_ARP_OPCODE))
ah->ar_op, EBT_ARP_OPCODE))
return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_HTYPE && FWINV(info->htype !=
arph.ar_hrd, EBT_ARP_HTYPE))
ah->ar_hrd, EBT_ARP_HTYPE))
return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_PTYPE && FWINV(info->ptype !=
arph.ar_pro, EBT_ARP_PTYPE))
ah->ar_pro, EBT_ARP_PTYPE))
return EBT_NOMATCH;
if (info->bitmask & (EBT_ARP_SRC_IP | EBT_ARP_DST_IP)) {
uint32_t addr;
uint32_t _addr, *ap;
/* IPv4 addresses are always 4 bytes */
if (arph.ar_pln != sizeof(uint32_t))
if (ah->ar_pln != sizeof(uint32_t))
return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_SRC_IP) {
if (skb_copy_bits(skb, sizeof(struct arphdr) +
arph.ar_hln, &addr, sizeof(addr)))
ap = skb_header_pointer(skb, sizeof(struct arphdr) +
ah->ar_hln, sizeof(_addr),
&_addr);
if (ap == NULL)
return EBT_NOMATCH;
if (FWINV(info->saddr != (addr & info->smsk),
if (FWINV(info->saddr != (*ap & info->smsk),
EBT_ARP_SRC_IP))
return EBT_NOMATCH;
}
if (info->bitmask & EBT_ARP_DST_IP) {
if (skb_copy_bits(skb, sizeof(struct arphdr) +
2*arph.ar_hln + sizeof(uint32_t), &addr,
sizeof(addr)))
ap = skb_header_pointer(skb, sizeof(struct arphdr) +
2*ah->ar_hln+sizeof(uint32_t),
sizeof(_addr), &_addr);
if (ap == NULL)
return EBT_NOMATCH;
if (FWINV(info->daddr != (addr & info->dmsk),
if (FWINV(info->daddr != (*ap & info->dmsk),
EBT_ARP_DST_IP))
return EBT_NOMATCH;
}
}
if (info->bitmask & (EBT_ARP_SRC_MAC | EBT_ARP_DST_MAC)) {
unsigned char mac[ETH_ALEN];
unsigned char _mac[ETH_ALEN], *mp;
uint8_t verdict, i;
/* MAC addresses are 6 bytes */
if (arph.ar_hln != ETH_ALEN)
if (ah->ar_hln != ETH_ALEN)
return EBT_NOMATCH;
if (info->bitmask & EBT_ARP_SRC_MAC) {
if (skb_copy_bits(skb, sizeof(struct arphdr), &mac,
ETH_ALEN))
mp = skb_header_pointer(skb, sizeof(struct arphdr),
sizeof(_mac), &_mac);
if (mp == NULL)
return EBT_NOMATCH;
verdict = 0;
for (i = 0; i < 6; i++)
verdict |= (mac[i] ^ info->smaddr[i]) &
verdict |= (mp[i] ^ info->smaddr[i]) &
info->smmsk[i];
if (FWINV(verdict != 0, EBT_ARP_SRC_MAC))
return EBT_NOMATCH;
}
if (info->bitmask & EBT_ARP_DST_MAC) {
if (skb_copy_bits(skb, sizeof(struct arphdr) +
arph.ar_hln + arph.ar_pln, &mac, ETH_ALEN))
mp = skb_header_pointer(skb, sizeof(struct arphdr) +
ah->ar_hln + ah->ar_pln,
sizeof(_mac), &_mac);
if (mp == NULL)
return EBT_NOMATCH;
verdict = 0;
for (i = 0; i < 6; i++)
verdict |= (mac[i] ^ info->dmaddr[i]) &
verdict |= (mp[i] ^ info->dmaddr[i]) &
info->dmmsk[i];
if (FWINV(verdict != 0, EBT_ARP_DST_MAC))
return EBT_NOMATCH;
......
......@@ -20,30 +20,38 @@ static int ebt_target_reply(struct sk_buff **pskb, unsigned int hooknr,
const void *data, unsigned int datalen)
{
struct ebt_arpreply_info *info = (struct ebt_arpreply_info *)data;
u32 sip, dip;
struct arphdr ah;
unsigned char sha[ETH_ALEN];
u32 _sip, *siptr, _dip, *diptr;
struct arphdr _ah, *ap;
unsigned char _sha[ETH_ALEN], *shp;
struct sk_buff *skb = *pskb;
if (skb_copy_bits(skb, 0, &ah, sizeof(ah)))
ap = skb_header_pointer(skb, 0, sizeof(_ah), &_ah);
if (ap == NULL)
return EBT_DROP;
if (ah.ar_op != __constant_htons(ARPOP_REQUEST) || ah.ar_hln != ETH_ALEN
|| ah.ar_pro != __constant_htons(ETH_P_IP) || ah.ar_pln != 4)
if (ap->ar_op != __constant_htons(ARPOP_REQUEST) ||
ap->ar_hln != ETH_ALEN ||
ap->ar_pro != __constant_htons(ETH_P_IP) ||
ap->ar_pln != 4)
return EBT_CONTINUE;
if (skb_copy_bits(skb, sizeof(ah), &sha, ETH_ALEN))
shp = skb_header_pointer(skb, sizeof(_ah), ETH_ALEN, &_sha);
if (shp == NULL)
return EBT_DROP;
if (skb_copy_bits(skb, sizeof(ah) + ETH_ALEN, &sip, sizeof(sip)))
siptr = skb_header_pointer(skb, sizeof(_ah) + ETH_ALEN,
sizeof(_sip), &_sip);
if (siptr == NULL)
return EBT_DROP;
if (skb_copy_bits(skb, sizeof(ah) + 2 * ETH_ALEN + sizeof(sip),
&dip, sizeof(dip)))
diptr = skb_header_pointer(skb,
sizeof(_ah) + 2 * ETH_ALEN + sizeof(_sip),
sizeof(_dip), &_dip);
if (diptr == NULL)
return EBT_DROP;
arp_send(ARPOP_REPLY, ETH_P_ARP, sip, (struct net_device *)in,
dip, sha, info->mac, sha);
arp_send(ARPOP_REPLY, ETH_P_ARP, *siptr, (struct net_device *)in,
*diptr, shp, info->mac, shp);
return info->target;
}
......
......@@ -28,41 +28,44 @@ static int ebt_filter_ip(const struct sk_buff *skb, const struct net_device *in,
unsigned int datalen)
{
struct ebt_ip_info *info = (struct ebt_ip_info *)data;
union {struct iphdr iph; struct tcpudphdr ports;} u;
struct iphdr _iph, *ih;
struct tcpudphdr _ports, *pptr;
if (skb_copy_bits(skb, 0, &u.iph, sizeof(u.iph)))
ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
if (ih == NULL)
return EBT_NOMATCH;
if (info->bitmask & EBT_IP_TOS &&
FWINV(info->tos != u.iph.tos, EBT_IP_TOS))
FWINV(info->tos != ih->tos, EBT_IP_TOS))
return EBT_NOMATCH;
if (info->bitmask & EBT_IP_SOURCE &&
FWINV((u.iph.saddr & info->smsk) !=
FWINV((ih->saddr & info->smsk) !=
info->saddr, EBT_IP_SOURCE))
return EBT_NOMATCH;
if ((info->bitmask & EBT_IP_DEST) &&
FWINV((u.iph.daddr & info->dmsk) !=
FWINV((ih->daddr & info->dmsk) !=
info->daddr, EBT_IP_DEST))
return EBT_NOMATCH;
if (info->bitmask & EBT_IP_PROTO) {
if (FWINV(info->protocol != u.iph.protocol, EBT_IP_PROTO))
if (FWINV(info->protocol != ih->protocol, EBT_IP_PROTO))
return EBT_NOMATCH;
if (!(info->bitmask & EBT_IP_DPORT) &&
!(info->bitmask & EBT_IP_SPORT))
return EBT_MATCH;
if (skb_copy_bits(skb, u.iph.ihl*4, &u.ports,
sizeof(u.ports)))
pptr = skb_header_pointer(skb, ih->ihl*4,
sizeof(_ports), &_ports);
if (pptr == NULL)
return EBT_NOMATCH;
if (info->bitmask & EBT_IP_DPORT) {
u.ports.dst = ntohs(u.ports.dst);
if (FWINV(u.ports.dst < info->dport[0] ||
u.ports.dst > info->dport[1],
u32 dst = ntohs(pptr->dst);
if (FWINV(dst < info->dport[0] ||
dst > info->dport[1],
EBT_IP_DPORT))
return EBT_NOMATCH;
}
if (info->bitmask & EBT_IP_SPORT) {
u.ports.src = ntohs(u.ports.src);
if (FWINV(u.ports.src < info->sport[0] ||
u.ports.src > info->sport[1],
u32 src = ntohs(pptr->src);
if (FWINV(src < info->sport[0] ||
src > info->sport[1],
EBT_IP_SPORT))
return EBT_NOMATCH;
}
......
......@@ -78,23 +78,29 @@ static void ebt_log(const struct sk_buff *skb, const struct net_device *in,
if ((info->bitmask & EBT_LOG_IP) && skb->mac.ethernet->h_proto ==
htons(ETH_P_IP)){
if (skb_copy_bits(skb, 0, &u.iph, sizeof(u.iph))) {
struct iphdr _iph, *ih;
ih = skb_header_pointer(skb, 0, sizeof(_iph), &_iph);
if (ih == NULL) {
printk(" INCOMPLETE IP header");
goto out;
}
printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u,",
NIPQUAD(u.iph.saddr), NIPQUAD(u.iph.daddr));
NIPQUAD(ih->saddr), NIPQUAD(ih->daddr));
printk(" IP tos=0x%02X, IP proto=%d", u.iph.tos,
u.iph.protocol);
if (u.iph.protocol == IPPROTO_TCP ||
u.iph.protocol == IPPROTO_UDP) {
if (skb_copy_bits(skb, u.iph.ihl*4, &u.ports,
sizeof(u.ports))) {
ih->protocol);
if (ih->protocol == IPPROTO_TCP ||
ih->protocol == IPPROTO_UDP) {
struct tcpudphdr _ports, *pptr;
pptr = skb_header_pointer(skb, ih->ihl*4,
sizeof(_ports), &_ports);
if (pptr == NULL) {
printk(" INCOMPLETE TCP/UDP header");
goto out;
}
printk(" SPT=%u DPT=%u", ntohs(u.ports.src),
ntohs(u.ports.dst));
printk(" SPT=%u DPT=%u", ntohs(pptr->src),
ntohs(pptr->dst));
}
goto out;
}
......@@ -102,32 +108,38 @@ static void ebt_log(const struct sk_buff *skb, const struct net_device *in,
if ((info->bitmask & EBT_LOG_ARP) &&
((skb->mac.ethernet->h_proto == __constant_htons(ETH_P_ARP)) ||
(skb->mac.ethernet->h_proto == __constant_htons(ETH_P_RARP)))) {
if (skb_copy_bits(skb, 0, &u.arph, sizeof(u.arph))) {
struct arphdr _arph, *ah;
ah = skb_header_pointer(skb, 0, sizeof(_arph), &_arph);
if (ah == NULL) {
printk(" INCOMPLETE ARP header");
goto out;
}
printk(" ARP HTYPE=%d, PTYPE=0x%04x, OPCODE=%d",
ntohs(u.arph.ar_hrd), ntohs(u.arph.ar_pro),
ntohs(u.arph.ar_op));
ntohs(ah->ar_hrd), ntohs(ah->ar_pro),
ntohs(ah->ar_op));
/* If it's for Ethernet and the lengths are OK,
* then log the ARP payload */
if (u.arph.ar_hrd == __constant_htons(1) &&
u.arph.ar_hln == ETH_ALEN &&
u.arph.ar_pln == sizeof(uint32_t)) {
if (skb_copy_bits(skb, sizeof(u.arph), &u.arpp,
sizeof(u.arpp))) {
if (ah->ar_hrd == __constant_htons(1) &&
ah->ar_hln == ETH_ALEN &&
ah->ar_pln == sizeof(uint32_t)) {
struct arppayload _arpp, *ap;
ap = skb_header_pointer(skb, sizeof(u.arph),
sizeof(_arpp), &_arpp);
if (ap == NULL) {
printk(" INCOMPLETE ARP payload");
goto out;
}
printk(" ARP MAC SRC=");
print_MAC(u.arpp.mac_src);
print_MAC(ap->mac_src);
printk(" ARP IP SRC=%u.%u.%u.%u",
myNIPQUAD(u.arpp.ip_src));
myNIPQUAD(ap->ip_src));
printk(" ARP MAC DST=");
print_MAC(u.arpp.mac_dst);
print_MAC(ap->mac_dst);
printk(" ARP IP DST=%u.%u.%u.%u",
myNIPQUAD(u.arpp.ip_dst));
myNIPQUAD(ap->ip_dst));
}
}
out:
......
......@@ -122,26 +122,30 @@ static int ebt_filter_stp(const struct sk_buff *skb, const struct net_device *in
const struct net_device *out, const void *data, unsigned int datalen)
{
struct ebt_stp_info *info = (struct ebt_stp_info *)data;
struct stp_header stph;
struct stp_header _stph, *sp;
uint8_t header[6] = {0x42, 0x42, 0x03, 0x00, 0x00, 0x00};
if (skb_copy_bits(skb, 0, &stph, sizeof(stph)))
sp = skb_header_pointer(skb, 0, sizeof(_stph), &_stph);
if (sp == NULL)
return EBT_NOMATCH;
/* The stp code only considers these */
if (memcmp(&stph, header, sizeof(header)))
if (memcmp(sp, header, sizeof(header)))
return EBT_NOMATCH;
if (info->bitmask & EBT_STP_TYPE
&& FWINV(info->type != stph.type, EBT_STP_TYPE))
&& FWINV(info->type != sp->type, EBT_STP_TYPE))
return EBT_NOMATCH;
if (stph.type == BPDU_TYPE_CONFIG &&
if (sp->type == BPDU_TYPE_CONFIG &&
info->bitmask & EBT_STP_CONFIG_MASK) {
struct stp_config_pdu stpc;
struct stp_config_pdu _stpc, *st;
if (skb_copy_bits(skb, sizeof(stph), &stpc, sizeof(stpc)))
return EBT_NOMATCH;
return ebt_filter_config(info, &stpc);
st = skb_header_pointer(skb, sizeof(_stph),
sizeof(_stpc), &_stpc);
if (st == NULL)
return EBT_NOMATCH;
return ebt_filter_config(info, st);
}
return EBT_MATCH;
}
......
......@@ -48,7 +48,7 @@ ebt_filter_vlan(const struct sk_buff *skb,
const void *data, unsigned int datalen)
{
struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
struct vlan_hdr frame;
struct vlan_hdr _frame, *fp;
unsigned short TCI; /* Whole TCI, given from parsed frame */
unsigned short id; /* VLAN ID, given from frame TCI */
......@@ -56,7 +56,8 @@ ebt_filter_vlan(const struct sk_buff *skb,
/* VLAN encapsulated Type/Length field, given from orig frame */
unsigned short encap;
if (skb_copy_bits(skb, 0, &frame, sizeof(frame)))
fp = skb_header_pointer(skb, 0, sizeof(_frame), &_frame);
if (fp == NULL)
return EBT_NOMATCH;
/* Tag Control Information (TCI) consists of the following elements:
......@@ -66,10 +67,10 @@ ebt_filter_vlan(const struct sk_buff *skb,
* (CFI) is a single bit flag value. Currently ignored.
* - VLAN Identifier (VID). The VID is encoded as
* an unsigned binary number. */
TCI = ntohs(frame.h_vlan_TCI);
TCI = ntohs(fp->h_vlan_TCI);
id = TCI & VLAN_VID_MASK;
prio = (TCI >> 13) & 0x7;
encap = frame.h_vlan_encapsulated_proto;
encap = fp->h_vlan_encapsulated_proto;
/* Checking VLAN Identifier (VID) */
if (GET_BITMASK(EBT_VLAN_ID))
......
......@@ -183,9 +183,10 @@ int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
continue;
}
} else {
u32 tmp;
if (!skb_copy_bits(skb, k, &tmp, 4)) {
A = ntohl(tmp);
u32 _tmp, *p;
p = skb_header_pointer(skb, k, 4, &_tmp);
if (p != NULL) {
A = ntohl(*p);
continue;
}
}
......@@ -208,9 +209,10 @@ int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
continue;
}
} else {
u16 tmp;
if (!skb_copy_bits(skb, k, &tmp, 2)) {
A = ntohs(tmp);
u16 _tmp, *p;
p = skb_header_pointer(skb, k, 2, &_tmp);
if (p != NULL) {
A = ntohs(*p);
continue;
}
}
......@@ -233,9 +235,10 @@ int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
continue;
}
} else {
u8 tmp;
if (!skb_copy_bits(skb, k, &tmp, 1)) {
A = tmp;
u8 _tmp, *p;
p = skb_header_pointer(skb, k, 1, &_tmp);
if (p != NULL) {
A = *p;
continue;
}
}
......
......@@ -695,11 +695,12 @@ int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
/* DaveM says protocol headers are also modifiable. */
switch ((*pskb)->nh.iph->protocol) {
case IPPROTO_TCP: {
struct tcphdr hdr;
if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
&hdr, sizeof(hdr)) != 0)
struct tcphdr _hdr, *hp;
hp = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
sizeof(_hdr), &_hdr);
if (hp == NULL)
goto copy_skb;
if (writable_len <= (*pskb)->nh.iph->ihl*4 + hdr.doff*4)
if (writable_len <= (*pskb)->nh.iph->ihl*4 + hp->doff*4)
goto pull_skb;
goto copy_skb;
}
......
......@@ -478,20 +478,25 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
* ICMP error
*/
if (iph->protocol == IPPROTO_ICMP) {
u8 inner_type;
if (skb_copy_bits(skb_in,
skb_in->nh.raw + (iph->ihl << 2) +
offsetof(struct icmphdr, type) -
skb_in->data, &inner_type, 1))
u8 _inner_type, *itp;
itp = skb_header_pointer(skb_in,
skb_in->nh.raw +
(iph->ihl << 2) +
offsetof(struct icmphdr,
type) -
skb_in->data,
sizeof(_inner_type),
&_inner_type);
if (itp == NULL)
goto out;
/*
* Assume any unknown ICMP type is an error. This
* isn't specified by the RFC, but think about it..
*/
if (inner_type > NR_ICMP_TYPES ||
icmp_pointers[inner_type].error)
if (*itp > NR_ICMP_TYPES ||
icmp_pointers[*itp].error)
goto out;
}
}
......@@ -880,7 +885,6 @@ static void icmp_address_reply(struct sk_buff *skb)
struct net_device *dev = skb->dev;
struct in_device *in_dev;
struct in_ifaddr *ifa;
u32 mask;
if (skb->len < 4 || !(rt->rt_flags&RTCF_DIRECTSRC))
goto out;
......@@ -892,17 +896,20 @@ static void icmp_address_reply(struct sk_buff *skb)
if (in_dev->ifa_list &&
IN_DEV_LOG_MARTIANS(in_dev) &&
IN_DEV_FORWARD(in_dev)) {
if (skb_copy_bits(skb, 0, &mask, 4))
u32 _mask, *mp;
mp = skb_header_pointer(skb, 0, sizeof(_mask), &_mask);
if (mp == NULL)
BUG();
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
if (mask == ifa->ifa_mask &&
if (*mp == ifa->ifa_mask &&
inet_ifa_match(rt->rt_src, ifa))
break;
}
if (!ifa && net_ratelimit()) {
printk(KERN_INFO "Wrong address mask %u.%u.%u.%u from "
"%s/%u.%u.%u.%u\n",
NIPQUAD(mask), dev->name, NIPQUAD(rt->rt_src));
NIPQUAD(*mp), dev->name, NIPQUAD(rt->rt_src));
}
}
read_unlock(&in_dev->lock);
......
......@@ -383,21 +383,23 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
struct ip_vs_conn *cp = NULL;
struct iphdr *iph = skb->nh.iph;
struct ip_vs_dest *dest;
__u16 ports[2];
__u16 _ports[2], *pptr;
if (skb_copy_bits(skb, iph->ihl*4, ports, sizeof(ports)) < 0)
pptr = skb_header_pointer(skb, iph->ihl*4,
sizeof(_ports), _ports);
if (pptr == NULL)
return NULL;
/*
* Persistent service
*/
if (svc->flags & IP_VS_SVC_F_PERSISTENT)
return ip_vs_sched_persist(svc, skb, ports);
return ip_vs_sched_persist(svc, skb, pptr);
/*
* Non-persistent service
*/
if (!svc->fwmark && ports[1] != svc->port) {
if (!svc->fwmark && pptr[1] != svc->port) {
if (!svc->port)
IP_VS_ERR("Schedule: port zero only supported "
"in persistent services, "
......@@ -415,9 +417,9 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
* Create a connection entry.
*/
cp = ip_vs_conn_new(iph->protocol,
iph->saddr, ports[0],
iph->daddr, ports[1],
dest->addr, dest->port?dest->port:ports[1],
iph->saddr, pptr[0],
iph->daddr, pptr[1],
dest->addr, dest->port?dest->port:pptr[1],
0,
dest);
if (cp == NULL)
......@@ -444,10 +446,12 @@ ip_vs_schedule(struct ip_vs_service *svc, const struct sk_buff *skb)
int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
struct ip_vs_protocol *pp)
{
__u16 ports[2];
__u16 _ports[2], *pptr;
struct iphdr *iph = skb->nh.iph;
if (skb_copy_bits(skb, iph->ihl*4, ports, sizeof(ports)) < 0) {
pptr = skb_header_pointer(skb, iph->ihl*4,
sizeof(_ports), _ports);
if (pptr == NULL) {
ip_vs_service_put(svc);
return NF_DROP;
}
......@@ -465,8 +469,8 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
/* create a new connection entry */
IP_VS_DBG(6, "ip_vs_leave: create a cache_bypass entry\n");
cp = ip_vs_conn_new(iph->protocol,
iph->saddr, ports[0],
iph->daddr, ports[1],
iph->saddr, pptr[0],
iph->daddr, pptr[1],
0, 0,
IP_VS_CONN_F_BYPASS,
NULL);
......@@ -494,7 +498,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,
* listed in the ipvs table), pass the packets, because it is
* not ipvs job to decide to drop the packets.
*/
if ((svc->port == FTPPORT) && (ports[1] != FTPPORT)) {
if ((svc->port == FTPPORT) && (pptr[1] != FTPPORT)) {
ip_vs_service_put(svc);
return NF_ACCEPT;
}
......@@ -607,8 +611,8 @@ static int ip_vs_out_icmp(struct sk_buff **pskb, int *related)
{
struct sk_buff *skb = *pskb;
struct iphdr *iph;
struct icmphdr icmph;
struct iphdr ciph; /* The ip header contained within the ICMP */
struct icmphdr _icmph, *ic;
struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
struct ip_vs_conn *cp;
struct ip_vs_protocol *pp;
unsigned int offset, ihl, verdict;
......@@ -625,11 +629,12 @@ static int ip_vs_out_icmp(struct sk_buff **pskb, int *related)
iph = skb->nh.iph;
offset = ihl = iph->ihl * 4;
if (skb_copy_bits(skb, offset, &icmph, sizeof(icmph)) < 0)
ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
if (ic == NULL)
return NF_DROP;
IP_VS_DBG(12, "Outgoing ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n",
icmph.type, ntohs(icmp_id(&icmph)),
ic->type, ntohs(icmp_id(ic)),
NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
/*
......@@ -639,33 +644,34 @@ static int ip_vs_out_icmp(struct sk_buff **pskb, int *related)
* this means that some packets will manage to get a long way
* down this stack and then be rejected, but that's life.
*/
if ((icmph.type != ICMP_DEST_UNREACH) &&
(icmph.type != ICMP_SOURCE_QUENCH) &&
(icmph.type != ICMP_TIME_EXCEEDED)) {
if ((ic->type != ICMP_DEST_UNREACH) &&
(ic->type != ICMP_SOURCE_QUENCH) &&
(ic->type != ICMP_TIME_EXCEEDED)) {
*related = 0;
return NF_ACCEPT;
}
/* Now find the contained IP header */
offset += sizeof(icmph);
if (skb_copy_bits(skb, offset, &ciph, sizeof(ciph)) < 0)
offset += sizeof(_icmph);
cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
if (cih == NULL)
return NF_ACCEPT; /* The packet looks wrong, ignore */
pp = ip_vs_proto_get(ciph.protocol);
pp = ip_vs_proto_get(cih->protocol);
if (!pp)
return NF_ACCEPT;
/* Is the embedded protocol header present? */
if (unlikely(ciph.frag_off & __constant_htons(IP_OFFSET) &&
if (unlikely(cih->frag_off & __constant_htons(IP_OFFSET) &&
pp->dont_defrag))
return NF_ACCEPT;
IP_VS_DBG_PKT(11, pp, skb, offset, "Checking outgoing ICMP for");
offset += ciph.ihl * 4;
offset += cih->ihl * 4;
/* The embedded headers contain source and dest in reverse order */
cp = pp->conn_out_get(skb, pp, &ciph, offset, 1);
cp = pp->conn_out_get(skb, pp, cih, offset, 1);
if (!cp)
return NF_ACCEPT;
......@@ -685,7 +691,7 @@ static int ip_vs_out_icmp(struct sk_buff **pskb, int *related)
goto out;
}
if (IPPROTO_TCP == ciph.protocol || IPPROTO_UDP == ciph.protocol)
if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol)
offset += 2 * sizeof(__u16);
if (!ip_vs_make_skb_writable(pskb, offset))
goto out;
......@@ -707,11 +713,13 @@ static int ip_vs_out_icmp(struct sk_buff **pskb, int *related)
static inline int is_tcp_reset(const struct sk_buff *skb)
{
struct tcphdr tcph;
struct tcphdr _tcph, *th;
if (skb_copy_bits(skb, skb->nh.iph->ihl * 4, &tcph, sizeof(tcph)) < 0)
th = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
sizeof(_tcph), &_tcph);
if (th == NULL)
return 0;
return tcph.rst;
return th->rst;
}
/*
......@@ -777,12 +785,14 @@ ip_vs_out(unsigned int hooknum, struct sk_buff **pskb,
if (sysctl_ip_vs_nat_icmp_send &&
(pp->protocol == IPPROTO_TCP ||
pp->protocol == IPPROTO_UDP)) {
__u16 ports[2];
__u16 _ports[2], *pptr;
if (skb_copy_bits(skb, ihl, ports, sizeof(ports)) < 0)
pptr = skb_header_pointer(skb, ihl,
sizeof(_ports), _ports);
if (pptr == NULL)
return NF_ACCEPT; /* Not for me */
if (ip_vs_lookup_real_service(iph->protocol,
iph->saddr, ports[0])) {
iph->saddr, pptr[0])) {
/*
* Notify the real server: there is no
* existing entry if it is not RST
......@@ -866,8 +876,8 @@ static int ip_vs_in_icmp(struct sk_buff **pskb, int *related)
{
struct sk_buff *skb = *pskb;
struct iphdr *iph;
struct icmphdr icmph;
struct iphdr ciph; /* The ip header contained within the ICMP */
struct icmphdr _icmph, *ic;
struct iphdr _ciph, *cih; /* The ip header contained within the ICMP */
struct ip_vs_conn *cp;
struct ip_vs_protocol *pp;
unsigned int offset, ihl, verdict;
......@@ -884,11 +894,12 @@ static int ip_vs_in_icmp(struct sk_buff **pskb, int *related)
iph = skb->nh.iph;
offset = ihl = iph->ihl * 4;
if (skb_copy_bits(skb, offset, &icmph, sizeof(icmph)) < 0)
ic = skb_header_pointer(skb, offset, sizeof(_icmph), &_icmph);
if (ic == NULL)
return NF_DROP;
IP_VS_DBG(12, "Incoming ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n",
icmph.type, ntohs(icmp_id(&icmph)),
ic->type, ntohs(icmp_id(ic)),
NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
/*
......@@ -898,33 +909,34 @@ static int ip_vs_in_icmp(struct sk_buff **pskb, int *related)
* this means that some packets will manage to get a long way
* down this stack and then be rejected, but that's life.
*/
if ((icmph.type != ICMP_DEST_UNREACH) &&
(icmph.type != ICMP_SOURCE_QUENCH) &&
(icmph.type != ICMP_TIME_EXCEEDED)) {
if ((ic->type != ICMP_DEST_UNREACH) &&
(ic->type != ICMP_SOURCE_QUENCH) &&
(ic->type != ICMP_TIME_EXCEEDED)) {
*related = 0;
return NF_ACCEPT;
}
/* Now find the contained IP header */
offset += sizeof(icmph);
if (skb_copy_bits(skb, offset, &ciph, sizeof(ciph)) < 0)
offset += sizeof(_icmph);
cih = skb_header_pointer(skb, offset, sizeof(_ciph), &_ciph);
if (cih == NULL)
return NF_ACCEPT; /* The packet looks wrong, ignore */
pp = ip_vs_proto_get(ciph.protocol);
pp = ip_vs_proto_get(cih->protocol);
if (!pp)
return NF_ACCEPT;
/* Is the embedded protocol header present? */
if (unlikely(ciph.frag_off & __constant_htons(IP_OFFSET) &&
if (unlikely(cih->frag_off & __constant_htons(IP_OFFSET) &&
pp->dont_defrag))
return NF_ACCEPT;
IP_VS_DBG_PKT(11, pp, skb, offset, "Checking incoming ICMP for");
offset += ciph.ihl * 4;
offset += cih->ihl * 4;
/* The embedded headers contain source and dest in reverse order */
cp = pp->conn_in_get(skb, pp, &ciph, offset, 1);
cp = pp->conn_in_get(skb, pp, cih, offset, 1);
if (!cp)
return NF_ACCEPT;
......@@ -941,7 +953,7 @@ static int ip_vs_in_icmp(struct sk_buff **pskb, int *related)
/* do the statistics and put it back */
ip_vs_in_stats(cp, skb);
if (IPPROTO_TCP == ciph.protocol || IPPROTO_UDP == ciph.protocol)
if (IPPROTO_TCP == cih->protocol || IPPROTO_UDP == cih->protocol)
offset += 2 * sizeof(__u16);
verdict = ip_vs_icmp_xmit(skb, cp, pp, offset);
/* do not touch skb anymore */
......
......@@ -166,27 +166,33 @@ ip_vs_tcpudp_debug_packet(struct ip_vs_protocol *pp,
const char *msg)
{
char buf[128];
__u16 ports[2];
struct iphdr iph;
struct iphdr _iph, *ih;
if (skb_copy_bits(skb, offset, &iph, sizeof(iph)) < 0)
ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
if (ih == NULL)
sprintf(buf, "%s TRUNCATED", pp->name);
else if (iph.frag_off & __constant_htons(IP_OFFSET))
else if (ih->frag_off & __constant_htons(IP_OFFSET))
sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u frag",
pp->name, NIPQUAD(iph.saddr),
NIPQUAD(iph.daddr));
else if (skb_copy_bits(skb, offset + iph.ihl*4, ports, sizeof(ports)) < 0)
sprintf(buf, "%s TRUNCATED %u.%u.%u.%u->%u.%u.%u.%u",
pp->name,
NIPQUAD(iph.saddr),
NIPQUAD(iph.daddr));
else
sprintf(buf, "%s %u.%u.%u.%u:%u->%u.%u.%u.%u:%u",
pp->name,
NIPQUAD(iph.saddr),
ntohs(ports[0]),
NIPQUAD(iph.daddr),
ntohs(ports[1]));
pp->name, NIPQUAD(ih->saddr),
NIPQUAD(ih->daddr));
else {
__u16 _ports[2], *pptr
;
pptr = skb_header_pointer(skb, offset + ih->ihl*4,
sizeof(_ports), _ports);
if (pptr == NULL)
sprintf(buf, "%s TRUNCATED %u.%u.%u.%u->%u.%u.%u.%u",
pp->name,
NIPQUAD(ih->saddr),
NIPQUAD(ih->daddr));
else
sprintf(buf, "%s %u.%u.%u.%u:%u->%u.%u.%u.%u:%u",
pp->name,
NIPQUAD(ih->saddr),
ntohs(pptr[0]),
NIPQUAD(ih->daddr),
ntohs(pptr[1]));
}
printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
}
......
......@@ -129,14 +129,15 @@ ah_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
int offset, const char *msg)
{
char buf[256];
struct iphdr iph;
struct iphdr _iph, *ih;
if (skb_copy_bits(skb, offset, &iph, sizeof(iph)) < 0)
ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
if (ih == NULL)
sprintf(buf, "%s TRUNCATED", pp->name);
else
sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u",
pp->name, NIPQUAD(iph.saddr),
NIPQUAD(iph.daddr));
pp->name, NIPQUAD(ih->saddr),
NIPQUAD(ih->daddr));
printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
}
......
......@@ -128,14 +128,15 @@ esp_debug_packet(struct ip_vs_protocol *pp, const struct sk_buff *skb,
int offset, const char *msg)
{
char buf[256];
struct iphdr iph;
struct iphdr _iph, *ih;
if (skb_copy_bits(skb, offset, &iph, sizeof(iph)) < 0)
ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
if (ih == NULL)
sprintf(buf, "%s TRUNCATED", pp->name);
else
sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u",
pp->name, NIPQUAD(iph.saddr),
NIPQUAD(iph.daddr));
pp->name, NIPQUAD(ih->saddr),
NIPQUAD(ih->daddr));
printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
}
......
......@@ -104,24 +104,29 @@ icmp_debug_packet(struct ip_vs_protocol *pp,
const char *msg)
{
char buf[256];
struct iphdr iph;
struct icmphdr icmph;
struct iphdr _iph, *ih;
if (skb_copy_bits(skb, offset, &iph, sizeof(iph)) < 0)
ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
if (ih == NULL)
sprintf(buf, "%s TRUNCATED", pp->name);
else if (iph.frag_off & __constant_htons(IP_OFFSET))
else if (ih->frag_off & __constant_htons(IP_OFFSET))
sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u frag",
pp->name, NIPQUAD(iph.saddr),
NIPQUAD(iph.daddr));
else if (skb_copy_bits(skb, offset + iph.ihl*4, &icmph, sizeof(icmph)) < 0)
sprintf(buf, "%s TRUNCATED to %u bytes\n",
pp->name, skb->len - offset);
else
sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u T:%d C:%d",
pp->name, NIPQUAD(iph.saddr),
NIPQUAD(iph.daddr),
icmph.type, icmph.code);
pp->name, NIPQUAD(ih->saddr),
NIPQUAD(ih->daddr));
else {
struct icmphdr _icmph, *ic;
ic = skb_header_pointer(skb, offset + ih->ihl*4,
sizeof(_icmph), &_icmph);
if (ic == NULL)
sprintf(buf, "%s TRUNCATED to %u bytes\n",
pp->name, skb->len - offset);
else
sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u T:%d C:%d",
pp->name, NIPQUAD(ih->saddr),
NIPQUAD(ih->daddr),
ic->type, ic->code);
}
printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
}
......
......@@ -29,19 +29,20 @@ static struct ip_vs_conn *
tcp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse)
{
__u16 ports[2];
__u16 _ports[2], *pptr;
if (skb_copy_bits(skb, proto_off, ports, sizeof(ports)) < 0)
pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
if (pptr == NULL)
return NULL;
if (likely(!inverse)) {
return ip_vs_conn_in_get(iph->protocol,
iph->saddr, ports[0],
iph->daddr, ports[1]);
iph->saddr, pptr[0],
iph->daddr, pptr[1]);
} else {
return ip_vs_conn_in_get(iph->protocol,
iph->daddr, ports[1],
iph->saddr, ports[0]);
iph->daddr, pptr[1],
iph->saddr, pptr[0]);
}
}
......@@ -49,19 +50,20 @@ static struct ip_vs_conn *
tcp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse)
{
__u16 ports[2];
__u16 _ports[2], *pptr;
if (skb_copy_bits(skb, proto_off, ports, sizeof(ports)) < 0)
pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
if (pptr == NULL)
return NULL;
if (likely(!inverse)) {
return ip_vs_conn_out_get(iph->protocol,
iph->saddr, ports[0],
iph->daddr, ports[1]);
iph->saddr, pptr[0],
iph->daddr, pptr[1]);
} else {
return ip_vs_conn_out_get(iph->protocol,
iph->daddr, ports[1],
iph->saddr, ports[0]);
iph->daddr, pptr[1],
iph->saddr, pptr[0]);
}
}
......@@ -72,16 +74,18 @@ tcp_conn_schedule(struct sk_buff *skb,
int *verdict, struct ip_vs_conn **cpp)
{
struct ip_vs_service *svc;
struct tcphdr tcph;
struct tcphdr _tcph, *th;
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0) {
th = skb_header_pointer(skb, skb->nh.iph->ihl*4,
sizeof(_tcph), &_tcph);
if (th == NULL) {
*verdict = NF_DROP;
return 0;
}
if (tcph.syn &&
if (th->syn &&
(svc = ip_vs_service_get(skb->nfmark, skb->nh.iph->protocol,
skb->nh.iph->daddr, tcph.dest))) {
skb->nh.iph->daddr, th->dest))) {
if (ip_vs_todrop()) {
/*
* It seems that we are very loaded.
......@@ -483,13 +487,15 @@ tcp_state_transition(struct ip_vs_conn *cp, int direction,
const struct sk_buff *skb,
struct ip_vs_protocol *pp)
{
struct tcphdr tcph;
struct tcphdr _tcph, *th;
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0)
th = skb_header_pointer(skb, skb->nh.iph->ihl*4,
sizeof(_tcph), &_tcph);
if (th == NULL)
return 0;
spin_lock(&cp->lock);
set_tcp_state(pp, cp, direction, &tcph);
set_tcp_state(pp, cp, direction, th);
spin_unlock(&cp->lock);
return 1;
......
......@@ -26,19 +26,20 @@ udp_conn_in_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse)
{
struct ip_vs_conn *cp;
__u16 ports[2];
__u16 _ports[2], *pptr;
if (skb_copy_bits(skb, proto_off, ports, sizeof(ports)) < 0)
pptr = skb_header_pointer(skb, proto_off, sizeof(_ports), _ports);
if (pptr == NULL)
return NULL;
if (likely(!inverse)) {
cp = ip_vs_conn_in_get(iph->protocol,
iph->saddr, ports[0],
iph->daddr, ports[1]);
iph->saddr, pptr[0],
iph->daddr, pptr[1]);
} else {
cp = ip_vs_conn_in_get(iph->protocol,
iph->daddr, ports[1],
iph->saddr, ports[0]);
iph->daddr, pptr[1],
iph->saddr, pptr[0]);
}
return cp;
......@@ -50,19 +51,21 @@ udp_conn_out_get(const struct sk_buff *skb, struct ip_vs_protocol *pp,
const struct iphdr *iph, unsigned int proto_off, int inverse)
{
struct ip_vs_conn *cp;
__u16 ports[2];
__u16 _ports[2], *pptr;
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0)
pptr = skb_header_pointer(skb, skb->nh.iph->ihl*4,
sizeof(_ports), _ports);
if (pptr == NULL)
return NULL;
if (likely(!inverse)) {
cp = ip_vs_conn_out_get(iph->protocol,
iph->saddr, ports[0],
iph->daddr, ports[1]);
iph->saddr, pptr[0],
iph->daddr, pptr[1]);
} else {
cp = ip_vs_conn_out_get(iph->protocol,
iph->daddr, ports[1],
iph->saddr, ports[0]);
iph->daddr, pptr[1],
iph->saddr, pptr[0]);
}
return cp;
......@@ -74,15 +77,17 @@ udp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
int *verdict, struct ip_vs_conn **cpp)
{
struct ip_vs_service *svc;
struct udphdr udph;
struct udphdr _udph, *uh;
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0) {
uh = skb_header_pointer(skb, skb->nh.iph->ihl*4,
sizeof(_udph), &_udph);
if (uh == NULL) {
*verdict = NF_DROP;
return 0;
}
if ((svc = ip_vs_service_get(skb->nfmark, skb->nh.iph->protocol,
skb->nh.iph->daddr, udph.dest))) {
skb->nh.iph->daddr, uh->dest))) {
if (ip_vs_todrop()) {
/*
* It seems that we are very loaded.
......@@ -230,13 +235,14 @@ udp_dnat_handler(struct sk_buff **pskb,
static int
udp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
{
struct udphdr udph;
struct udphdr _udph, *uh;
unsigned int udphoff = skb->nh.iph->ihl*4;
if (skb_copy_bits(skb, udphoff, &udph, sizeof(udph)) < 0)
uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
if (uh == NULL)
return 0;
if (udph.check != 0) {
if (uh->check != 0) {
switch (skb->ip_summed) {
case CHECKSUM_NONE:
skb->csum = skb_checksum(skb, udphoff,
......
......@@ -234,11 +234,12 @@ ip_vs_nat_xmit(struct sk_buff *skb, struct ip_vs_conn *cp,
/* check if it is a connection of no-client-port */
if (unlikely(cp->flags & IP_VS_CONN_F_NO_CPORT)) {
__u16 pt;
if (skb_copy_bits(skb, iph->ihl*4, &pt, sizeof(pt)) < 0)
__u16 _pt, *p;
p = skb_header_pointer(skb, iph->ihl*4, sizeof(_pt), &_pt);
if (p == NULL)
goto tx_error;
ip_vs_conn_fill_cport(cp, pt);
IP_VS_DBG(10, "filled cport=%d\n", ntohs(pt));
ip_vs_conn_fill_cport(cp, *p);
IP_VS_DBG(10, "filled cport=%d\n", ntohs(*p));
}
if (!(rt = __ip_vs_get_out_rt(cp, RT_TOS(iph->tos))))
......
......@@ -49,7 +49,7 @@ static int help(struct sk_buff *skb,
{
struct ip_conntrack_expect *exp;
struct ip_ct_amanda_expect *exp_amanda_info;
char *data, *data_limit, *tmp;
char *amp, *data, *data_limit, *tmp;
unsigned int dataoff, i;
u_int16_t port, len;
......@@ -70,9 +70,11 @@ static int help(struct sk_buff *skb,
}
LOCK_BH(&amanda_buffer_lock);
skb_copy_bits(skb, dataoff, amanda_buffer, skb->len - dataoff);
data = amanda_buffer;
data_limit = amanda_buffer + skb->len - dataoff;
amp = skb_header_pointer(skb, dataoff,
skb->len - dataoff, amanda_buffer);
BUG_ON(amp == NULL);
data = amp;
data_limit = amp + skb->len - dataoff;
*data_limit = '\0';
/* Search for the CONNECT string */
......@@ -108,7 +110,7 @@ static int help(struct sk_buff *skb,
exp->mask.dst.u.tcp.port = 0xFFFF;
exp_amanda_info = &exp->help.exp_amanda_info;
exp_amanda_info->offset = tmp - amanda_buffer;
exp_amanda_info->offset = tmp - amp;
exp_amanda_info->port = port;
exp_amanda_info->len = len;
......
......@@ -248,7 +248,8 @@ static int help(struct sk_buff *skb,
enum ip_conntrack_info ctinfo)
{
unsigned int dataoff, datalen;
struct tcphdr tcph;
struct tcphdr _tcph, *th;
char *fb_ptr;
u_int32_t old_seq_aft_nl;
int old_seq_aft_nl_set, ret;
u_int32_t array[6] = { 0 };
......@@ -268,10 +269,12 @@ static int help(struct sk_buff *skb,
return NF_ACCEPT;
}
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0)
th = skb_header_pointer(skb, skb->nh.iph->ihl*4,
sizeof(_tcph), &_tcph);
if (th == NULL)
return NF_ACCEPT;
dataoff = skb->nh.iph->ihl*4 + tcph.doff*4;
dataoff = skb->nh.iph->ihl*4 + th->doff*4;
/* No data? */
if (dataoff >= skb->len) {
DEBUGP("ftp: skblen = %u\n", skb->len);
......@@ -280,26 +283,28 @@ static int help(struct sk_buff *skb,
datalen = skb->len - dataoff;
LOCK_BH(&ip_ftp_lock);
skb_copy_bits(skb, dataoff, ftp_buffer, skb->len - dataoff);
fb_ptr = skb_header_pointer(skb, dataoff,
skb->len - dataoff, ftp_buffer);
BUG_ON(fb_ptr == NULL);
old_seq_aft_nl_set = ct_ftp_info->seq_aft_nl_set[dir];
old_seq_aft_nl = ct_ftp_info->seq_aft_nl[dir];
DEBUGP("conntrack_ftp: datalen %u\n", datalen);
if (ftp_buffer[datalen - 1] == '\n') {
if (fb_ptr[datalen - 1] == '\n') {
DEBUGP("conntrack_ftp: datalen %u ends in \\n\n", datalen);
if (!old_seq_aft_nl_set
|| after(ntohl(tcph.seq) + datalen, old_seq_aft_nl)) {
|| after(ntohl(th->seq) + datalen, old_seq_aft_nl)) {
DEBUGP("conntrack_ftp: updating nl to %u\n",
ntohl(tcph.seq) + datalen);
ntohl(th->seq) + datalen);
ct_ftp_info->seq_aft_nl[dir] =
ntohl(tcph.seq) + datalen;
ntohl(th->seq) + datalen;
ct_ftp_info->seq_aft_nl_set[dir] = 1;
}
}
if(!old_seq_aft_nl_set ||
(ntohl(tcph.seq) != old_seq_aft_nl)) {
(ntohl(th->seq) != old_seq_aft_nl)) {
DEBUGP("ip_conntrack_ftp_help: wrong seq pos %s(%u)\n",
old_seq_aft_nl_set ? "":"(UNSET) ", old_seq_aft_nl);
ret = NF_ACCEPT;
......@@ -316,7 +321,7 @@ static int help(struct sk_buff *skb,
for (i = 0; i < ARRAY_SIZE(search); i++) {
if (search[i].dir != dir) continue;
found = find_pattern(ftp_buffer, skb->len - dataoff,
found = find_pattern(fb_ptr, skb->len - dataoff,
search[i].pattern,
search[i].plen,
search[i].skip,
......@@ -334,7 +339,7 @@ static int help(struct sk_buff *skb,
if (net_ratelimit())
printk("conntrack_ftp: partial %s %u+%u\n",
search[i].pattern,
ntohl(tcph.seq), datalen);
ntohl(th->seq), datalen);
ret = NF_DROP;
goto out;
} else if (found == 0) { /* No match */
......@@ -344,7 +349,7 @@ static int help(struct sk_buff *skb,
DEBUGP("conntrack_ftp: match `%.*s' (%u bytes at %u)\n",
(int)matchlen, data + matchoff,
matchlen, ntohl(tcph.seq) + matchoff);
matchlen, ntohl(th->seq) + matchoff);
/* Allocate expectation which will be inserted */
exp = ip_conntrack_expect_alloc();
......@@ -358,7 +363,7 @@ static int help(struct sk_buff *skb,
/* Update the ftp info */
if (htonl((array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3])
== ct->tuplehash[dir].tuple.src.ip) {
exp->seq = ntohl(tcph.seq) + matchoff;
exp->seq = ntohl(th->seq) + matchoff;
exp_ftp_info->len = matchlen;
exp_ftp_info->ftptype = search[i].ftptype;
exp_ftp_info->port = array[4] << 8 | array[5];
......
......@@ -102,8 +102,8 @@ static int help(struct sk_buff *skb,
struct ip_conntrack *ct, enum ip_conntrack_info ctinfo)
{
unsigned int dataoff;
struct tcphdr tcph;
char *data, *data_limit;
struct tcphdr _tcph, *th;
char *data, *data_limit, *ib_ptr;
int dir = CTINFO2DIR(ctinfo);
struct ip_conntrack_expect *exp;
struct ip_ct_irc_expect *exp_irc_info = NULL;
......@@ -127,19 +127,23 @@ static int help(struct sk_buff *skb,
}
/* Not a full tcp header? */
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) != 0)
th = skb_header_pointer(skb, skb->nh.iph->ihl*4,
sizeof(_tcph), &_tcph);
if (th == NULL)
return NF_ACCEPT;
/* No data? */
dataoff = skb->nh.iph->ihl*4 + tcph.doff*4;
dataoff = skb->nh.iph->ihl*4 + th->doff*4;
if (dataoff >= skb->len)
return NF_ACCEPT;
LOCK_BH(&ip_irc_lock);
skb_copy_bits(skb, dataoff, irc_buffer, skb->len - dataoff);
ib_ptr = skb_header_pointer(skb, dataoff,
skb->len - dataoff, irc_buffer);
BUG_ON(ib_ptr == NULL);
data = irc_buffer;
data_limit = irc_buffer + skb->len - dataoff;
data = ib_ptr;
data_limit = ib_ptr + skb->len - dataoff;
/* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
* 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
......@@ -153,8 +157,8 @@ static int help(struct sk_buff *skb,
/* we have at least (19+MINMATCHLEN)-5 bytes valid data left */
DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n",
NIPQUAD(iph->saddr), ntohs(tcph.source),
NIPQUAD(iph->daddr), ntohs(tcph.dest));
NIPQUAD(iph->saddr), ntohs(th->source),
NIPQUAD(iph->daddr), ntohs(th->dest));
for (i = 0; i < ARRAY_SIZE(dccprotos); i++) {
if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) {
......@@ -198,8 +202,8 @@ static int help(struct sk_buff *skb,
/* save position of address in dcc string,
* necessary for NAT */
DEBUGP("tcph->seq = %u\n", tcph.seq);
exp->seq = ntohl(tcph.seq) + (addr_beg_p - irc_buffer);
DEBUGP("tcph->seq = %u\n", th->seq);
exp->seq = ntohl(th->seq) + (addr_beg_p - ib_ptr);
exp_irc_info->len = (addr_end_p - addr_beg_p);
exp_irc_info->port = dcc_port;
DEBUGP("wrote info seq=%u (ofs=%u), len=%d\n",
......
......@@ -31,14 +31,15 @@ static int icmp_pkt_to_tuple(const struct sk_buff *skb,
unsigned int dataoff,
struct ip_conntrack_tuple *tuple)
{
struct icmphdr hdr;
struct icmphdr _hdr, *hp;
if (skb_copy_bits(skb, dataoff, &hdr, sizeof(hdr)) != 0)
hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
if (hp == NULL)
return 0;
tuple->dst.u.icmp.type = hdr.type;
tuple->src.u.icmp.id = hdr.un.echo.id;
tuple->dst.u.icmp.code = hdr.code;
tuple->dst.u.icmp.type = hp->type;
tuple->src.u.icmp.id = hp->un.echo.id;
tuple->dst.u.icmp.code = hp->code;
return 1;
}
......
......@@ -293,14 +293,15 @@ static int tcp_pkt_to_tuple(const struct sk_buff *skb,
unsigned int dataoff,
struct ip_conntrack_tuple *tuple)
{
struct tcphdr hdr;
struct tcphdr _hdr, *hp;
/* Actually only need first 8 bytes. */
if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0)
hp = skb_header_pointer(skb, dataoff, 8, &_hdr);
if (hp == NULL)
return 0;
tuple->src.u.tcp.port = hdr.source;
tuple->dst.u.tcp.port = hdr.dest;
tuple->src.u.tcp.port = hp->source;
tuple->dst.u.tcp.port = hp->dest;
return 1;
}
......@@ -385,12 +386,23 @@ static inline __u32 segment_seq_plus_len(__u32 seq,
/*
* Simplified tcp_parse_options routine from tcp_input.c
*/
static void tcp_options(struct tcphdr *tcph,
static void tcp_options(struct sk_buff *skb,
struct iphdr *iph,
struct tcphdr *tcph,
struct ip_ct_tcp_state *state)
{
unsigned char *ptr = (unsigned char *)(tcph + 1);
unsigned char buff[(15 * 4) - sizeof(struct tcphdr)];
unsigned char *ptr;
int length = (tcph->doff*4) - sizeof(struct tcphdr);
if (!length)
return;
ptr = skb_header_pointer(skb,
(iph->ihl * 4) + sizeof(struct tcphdr),
length, buff);
BUG_ON(ptr == NULL);
state->td_scale =
state->flags = 0;
......@@ -533,7 +545,7 @@ static int tcp_in_window(struct ip_ct_tcp *state,
sender->td_maxend = end;
sender->td_maxwin = (win == 0 ? 1 : win);
tcp_options(tcph, sender);
tcp_options(skb, iph, tcph, sender);
/*
* RFC 1323:
* Both sides must send the Window Scale option
......@@ -565,7 +577,7 @@ static int tcp_in_window(struct ip_ct_tcp *state,
sender->td_maxend = end;
sender->td_maxwin = (win == 0 ? 1 : win);
tcp_options(tcph, sender);
tcp_options(skb, iph, tcph, sender);
}
if (!(tcph->ack)) {
......@@ -760,12 +772,14 @@ static int tcp_error(struct sk_buff *skb,
unsigned int hooknum)
{
struct iphdr *iph = skb->nh.iph;
struct tcphdr tcph;
struct tcphdr _tcph, *th;
unsigned int tcplen = skb->len - iph->ihl * 4;
u_int8_t tcpflags;
/* Smaller that minimal TCP header? */
if (skb_copy_bits(skb, iph->ihl * 4, &tcph, sizeof(tcph)) != 0) {
th = skb_header_pointer(skb, iph->ihl * 4,
sizeof(_tcph), &_tcph);
if (th == NULL) {
if (LOG_INVALID(IPPROTO_TCP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL,
"ip_ct_tcp: short packet ");
......@@ -773,7 +787,7 @@ static int tcp_error(struct sk_buff *skb,
}
/* Not whole TCP header or malformed packet */
if (tcph.doff*4 < sizeof(struct tcphdr) || tcplen < tcph.doff*4) {
if (th->doff*4 < sizeof(struct tcphdr) || tcplen < th->doff*4) {
if (LOG_INVALID(IPPROTO_TCP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL,
"ip_ct_tcp: truncated/malformed packet ");
......@@ -797,7 +811,7 @@ static int tcp_error(struct sk_buff *skb,
}
/* Check TCP flags. */
tcpflags = (((u_int8_t *)&tcph)[13] & ~(TH_ECE|TH_CWR));
tcpflags = (((u_int8_t *)th)[13] & ~(TH_ECE|TH_CWR));
if (!tcp_valid_flags[tcpflags]) {
if (LOG_INVALID(IPPROTO_TCP))
nf_log_packet(PF_INET, 0, skb, NULL, NULL,
......@@ -808,19 +822,6 @@ static int tcp_error(struct sk_buff *skb,
return NF_ACCEPT;
}
static inline void copy_whole_tcp_header(const struct sk_buff *skb,
unsigned char *buff)
{
struct iphdr *iph = skb->nh.iph;
struct tcphdr *tcph = (struct tcphdr *)buff;
/* tcp_error guarantees for us that the packet is not malformed */
skb_copy_bits(skb, iph->ihl * 4, buff, sizeof(*tcph));
skb_copy_bits(skb, iph->ihl * 4 + sizeof(*tcph),
buff + sizeof(*tcph),
tcph->doff * 4 - sizeof(*tcph));
}
/* Returns verdict for packet, or -1 for invalid. */
static int tcp_packet(struct ip_conntrack *conntrack,
const struct sk_buff *skb,
......@@ -829,17 +830,18 @@ static int tcp_packet(struct ip_conntrack *conntrack,
enum tcp_conntrack new_state, old_state;
enum ip_conntrack_dir dir;
struct iphdr *iph = skb->nh.iph;
unsigned char buff[15 * 4];
struct tcphdr *tcph = (struct tcphdr *)buff;
struct tcphdr *th, _tcph;
unsigned long timeout;
unsigned int index;
copy_whole_tcp_header(skb, buff);
th = skb_header_pointer(skb, iph->ihl * 4,
sizeof(_tcph), &_tcph);
BUG_ON(th == NULL);
WRITE_LOCK(&tcp_lock);
old_state = conntrack->proto.tcp.state;
dir = CTINFO2DIR(ctinfo);
index = get_conntrack_index(tcph);
index = get_conntrack_index(th);
new_state = tcp_conntracks[dir][index][old_state];
switch (new_state) {
......@@ -848,7 +850,7 @@ static int tcp_packet(struct ip_conntrack *conntrack,
if (index == TCP_SYNACK_SET
&& conntrack->proto.tcp.last_index == TCP_SYN_SET
&& conntrack->proto.tcp.last_dir != dir
&& after(ntohl(tcph->ack_seq),
&& after(ntohl(th->ack_seq),
conntrack->proto.tcp.last_seq)) {
/* This SYN/ACK acknowledges a SYN that we earlier
* ignored as invalid. This means that the client and
......@@ -868,7 +870,7 @@ static int tcp_packet(struct ip_conntrack *conntrack,
}
conntrack->proto.tcp.last_index = index;
conntrack->proto.tcp.last_dir = dir;
conntrack->proto.tcp.last_seq = ntohl(tcph->seq);
conntrack->proto.tcp.last_seq = ntohl(th->seq);
WRITE_UNLOCK(&tcp_lock);
if (LOG_INVALID(IPPROTO_TCP))
......@@ -878,7 +880,7 @@ static int tcp_packet(struct ip_conntrack *conntrack,
case TCP_CONNTRACK_MAX:
/* Invalid packet */
DEBUGP("ip_ct_tcp: Invalid dir=%i index=%u ostate=%u\n",
dir, get_conntrack_index(tcph),
dir, get_conntrack_index(th),
old_state);
WRITE_UNLOCK(&tcp_lock);
if (LOG_INVALID(IPPROTO_TCP))
......@@ -900,7 +902,7 @@ static int tcp_packet(struct ip_conntrack *conntrack,
if (index == TCP_RST_SET
&& test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status)
&& conntrack->proto.tcp.last_index <= TCP_SYNACK_SET
&& after(ntohl(tcph->ack_seq),
&& after(ntohl(th->ack_seq),
conntrack->proto.tcp.last_seq)) {
/* Ignore RST closing down invalid SYN
we had let trough. */
......@@ -917,7 +919,7 @@ static int tcp_packet(struct ip_conntrack *conntrack,
}
if (!tcp_in_window(&conntrack->proto.tcp, dir, &index,
skb, iph, tcph)) {
skb, iph, th)) {
WRITE_UNLOCK(&tcp_lock);
return -NF_ACCEPT;
}
......@@ -929,10 +931,10 @@ static int tcp_packet(struct ip_conntrack *conntrack,
DEBUGP("tcp_conntracks: src=%u.%u.%u.%u:%hu dst=%u.%u.%u.%u:%hu "
"syn=%i ack=%i fin=%i rst=%i old=%i new=%i\n",
NIPQUAD(iph->saddr), ntohs(tcph->source),
NIPQUAD(iph->daddr), ntohs(tcph->dest),
(tcph->syn ? 1 : 0), (tcph->ack ? 1 : 0),
(tcph->fin ? 1 : 0), (tcph->rst ? 1 : 0),
NIPQUAD(iph->saddr), ntohs(th->source),
NIPQUAD(iph->daddr), ntohs(th->dest),
(th->syn ? 1 : 0), (th->ack ? 1 : 0),
(th->fin ? 1 : 0), (th->rst ? 1 : 0),
old_state, new_state);
conntrack->proto.tcp.state = new_state;
......@@ -946,7 +948,7 @@ static int tcp_packet(struct ip_conntrack *conntrack,
have an established connection: this is a fairly common
problem case, so we can delete the conntrack
immediately. --RR */
if (tcph->rst) {
if (th->rst) {
if (del_timer(&conntrack->timeout))
conntrack->timeout.function((unsigned long)
conntrack);
......@@ -972,18 +974,19 @@ static int tcp_new(struct ip_conntrack *conntrack,
{
enum tcp_conntrack new_state;
struct iphdr *iph = skb->nh.iph;
unsigned char buff[15 * 4];
struct tcphdr *tcph = (struct tcphdr *)buff;
struct tcphdr *th, _tcph;
#ifdef DEBUGP_VARS
struct ip_ct_tcp_state *sender = &conntrack->proto.tcp.seen[0];
struct ip_ct_tcp_state *receiver = &conntrack->proto.tcp.seen[1];
#endif
copy_whole_tcp_header(skb, buff);
th = skb_header_pointer(skb, iph->ihl * 4,
sizeof(_tcph), &_tcph);
BUG_ON(th == NULL);
/* Don't need lock here: this conntrack not in circulation yet */
new_state
= tcp_conntracks[0][get_conntrack_index(tcph)]
= tcp_conntracks[0][get_conntrack_index(th)]
[TCP_CONNTRACK_NONE];
/* Invalid: delete conntrack */
......@@ -995,15 +998,15 @@ static int tcp_new(struct ip_conntrack *conntrack,
if (new_state == TCP_CONNTRACK_SYN_SENT) {
/* SYN packet */
conntrack->proto.tcp.seen[0].td_end =
segment_seq_plus_len(ntohl(tcph->seq), skb->len,
iph, tcph);
conntrack->proto.tcp.seen[0].td_maxwin = ntohs(tcph->window);
segment_seq_plus_len(ntohl(th->seq), skb->len,
iph, th);
conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
conntrack->proto.tcp.seen[0].td_maxwin = 1;
conntrack->proto.tcp.seen[0].td_maxend =
conntrack->proto.tcp.seen[0].td_end;
tcp_options(tcph, &conntrack->proto.tcp.seen[0]);
tcp_options(skb, iph, th, &conntrack->proto.tcp.seen[0]);
conntrack->proto.tcp.seen[1].flags = 0;
conntrack->proto.tcp.seen[0].loose =
conntrack->proto.tcp.seen[1].loose = 0;
......@@ -1017,9 +1020,9 @@ static int tcp_new(struct ip_conntrack *conntrack,
* Let's try to use the data from the packet.
*/
conntrack->proto.tcp.seen[0].td_end =
segment_seq_plus_len(ntohl(tcph->seq), skb->len,
iph, tcph);
conntrack->proto.tcp.seen[0].td_maxwin = ntohs(tcph->window);
segment_seq_plus_len(ntohl(th->seq), skb->len,
iph, th);
conntrack->proto.tcp.seen[0].td_maxwin = ntohs(th->window);
if (conntrack->proto.tcp.seen[0].td_maxwin == 0)
conntrack->proto.tcp.seen[0].td_maxwin = 1;
conntrack->proto.tcp.seen[0].td_maxend =
......@@ -1056,14 +1059,16 @@ static int tcp_exp_matches_pkt(struct ip_conntrack_expect *exp,
const struct sk_buff *skb)
{
const struct iphdr *iph = skb->nh.iph;
struct tcphdr tcph;
struct tcphdr *th, _tcph;
unsigned int datalen;
if (skb_copy_bits(skb, iph->ihl * 4, &tcph, sizeof(tcph)) != 0)
th = skb_header_pointer(skb, iph->ihl * 4,
sizeof(_tcph), &_tcph);
if (th == NULL)
return 0;
datalen = skb->len - iph->ihl*4 - tcph.doff*4;
datalen = skb->len - iph->ihl*4 - th->doff*4;
return between(exp->seq, ntohl(tcph.seq), ntohl(tcph.seq) + datalen);
return between(exp->seq, ntohl(th->seq), ntohl(th->seq) + datalen);
}
struct ip_conntrack_protocol ip_conntrack_protocol_tcp =
......
......@@ -23,14 +23,15 @@ static int udp_pkt_to_tuple(const struct sk_buff *skb,
unsigned int dataoff,
struct ip_conntrack_tuple *tuple)
{
struct udphdr hdr;
struct udphdr _hdr, *hp;
/* Actually only need first 8 bytes. */
if (skb_copy_bits(skb, dataoff, &hdr, 8) != 0)
hp = skb_header_pointer(skb, dataoff, sizeof(_hdr), &_hdr);
if (hp == NULL)
return 0;
tuple->src.u.udp.port = hdr.source;
tuple->dst.u.udp.port = hdr.dest;
tuple->src.u.udp.port = hp->source;
tuple->dst.u.udp.port = hp->dest;
return 1;
}
......
......@@ -42,14 +42,16 @@ static int tftp_help(struct sk_buff *skb,
struct ip_conntrack *ct,
enum ip_conntrack_info ctinfo)
{
struct tftphdr tftph;
struct tftphdr _tftph, *tfh;
struct ip_conntrack_expect *exp;
if (skb_copy_bits(skb, skb->nh.iph->ihl * 4 + sizeof(struct udphdr),
&tftph, sizeof(tftph)) != 0)
tfh = skb_header_pointer(skb,
skb->nh.iph->ihl * 4 + sizeof(struct udphdr),
sizeof(_tftph), &_tftph);
if (tfh == NULL)
return NF_ACCEPT;
switch (ntohs(tftph.opcode)) {
switch (ntohs(tfh->opcode)) {
/* RRQ and WRQ works the same way */
case TFTP_OPCODE_READ:
case TFTP_OPCODE_WRITE:
......
......@@ -99,11 +99,13 @@ ip_nat_fn(unsigned int hooknum,
hash table yet). We must not let this through, in
case we're doing NAT to the same network. */
if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
struct icmphdr hdr;
struct icmphdr _hdr, *hp;
if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
&hdr, sizeof(hdr)) == 0
&& hdr.type == ICMP_REDIRECT)
hp = skb_header_pointer(*pskb,
(*pskb)->nh.iph->ihl*4,
sizeof(_hdr), &_hdr);
if (hp != NULL &&
hp->type == ICMP_REDIRECT)
return NF_DROP;
}
return NF_ACCEPT;
......
......@@ -60,7 +60,7 @@ tftp_nat_help(struct ip_conntrack *ct,
struct sk_buff **pskb)
{
int dir = CTINFO2DIR(ctinfo);
struct tftphdr tftph;
struct tftphdr _tftph, *tfh;
struct ip_conntrack_tuple repl;
if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
......@@ -72,11 +72,13 @@ tftp_nat_help(struct ip_conntrack *ct,
return NF_ACCEPT;
}
if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4+sizeof(struct udphdr),
&tftph, sizeof(tftph)) != 0)
tfh = skb_header_pointer(*pskb,
(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr),
sizeof(_tftph), &_tftph);
if (tfh == NULL)
return NF_DROP;
switch (ntohs(tftph.opcode)) {
switch (ntohs(tfh->opcode)) {
/* RRQ and WRQ works the same way */
case TFTP_OPCODE_READ:
case TFTP_OPCODE_WRITE:
......@@ -109,9 +111,12 @@ tftp_nat_expected(struct sk_buff **pskb,
#if 0
const struct ip_conntrack_tuple *repl =
&master->tuplehash[IP_CT_DIR_REPLY].tuple;
struct udphdr udph;
struct udphdr _udph, *uh;
if (skb_copy_bits(*pskb,(*pskb)->nh.iph->ihl*4,&udph,sizeof(udph))!=0)
uh = skb_header_pointer(*pskb,
(*pskb)->nh.iph->ihl*4,
sizeof(_udph), &_udph);
if (uh == NULL)
return NF_DROP;
#endif
......@@ -126,8 +131,8 @@ tftp_nat_expected(struct sk_buff **pskb,
mr.range[0].min_ip = mr.range[0].max_ip = orig->dst.ip;
DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u "
"newsrc: %u.%u.%u.%u\n",
NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph.source),
NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph.dest),
NIPQUAD((*pskb)->nh.iph->saddr), ntohs(uh->source),
NIPQUAD((*pskb)->nh.iph->daddr), ntohs(uh->dest),
NIPQUAD(orig->dst.ip));
} else {
mr.range[0].min_ip = mr.range[0].max_ip = orig->src.ip;
......@@ -137,8 +142,8 @@ tftp_nat_expected(struct sk_buff **pskb,
DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u "
"newdst: %u.%u.%u.%u:%u\n",
NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph.source),
NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph.dest),
NIPQUAD((*pskb)->nh.iph->saddr), ntohs(uh->source),
NIPQUAD((*pskb)->nh.iph->daddr), ntohs(uh->dest),
NIPQUAD(orig->src.ip), ntohs(orig->src.u.udp.port));
}
......
......@@ -1460,21 +1460,24 @@ tcp_find_option(u_int8_t option,
int *hotdrop)
{
/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
u_int8_t opt[60 - sizeof(struct tcphdr)];
u_int8_t _opt[60 - sizeof(struct tcphdr)], *op;
unsigned int i;
duprintf("tcp_match: finding option\n");
/* If we don't have the whole header, drop packet. */
if (skb_copy_bits(skb, skb->nh.iph->ihl*4 + sizeof(struct tcphdr),
opt, optlen) < 0) {
BUG_ON(!optlen);
op = skb_header_pointer(skb,
skb->nh.iph->ihl*4 + sizeof(struct tcphdr),
optlen, _opt);
if (op == NULL) {
*hotdrop = 1;
return 0;
}
for (i = 0; i < optlen; ) {
if (opt[i] == option) return !invert;
if (opt[i] < 2) i++;
else i += opt[i+1]?:1;
if (op[i] == option) return !invert;
if (op[i] < 2) i++;
else i += op[i+1]?:1;
}
return invert;
......@@ -1488,7 +1491,7 @@ tcp_match(const struct sk_buff *skb,
int offset,
int *hotdrop)
{
struct tcphdr tcph;
struct tcphdr _tcph, *th;
const struct ipt_tcp *tcpinfo = matchinfo;
if (offset) {
......@@ -1508,7 +1511,9 @@ tcp_match(const struct sk_buff *skb,
#define FWINVTCP(bool,invflg) ((bool) ^ !!(tcpinfo->invflags & invflg))
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0) {
th = skb_header_pointer(skb, skb->nh.iph->ihl*4,
sizeof(_tcph), &_tcph);
if (th == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
duprintf("Dropping evil TCP offset=0 tinygram.\n");
......@@ -1517,23 +1522,24 @@ tcp_match(const struct sk_buff *skb,
}
if (!port_match(tcpinfo->spts[0], tcpinfo->spts[1],
ntohs(tcph.source),
ntohs(th->source),
!!(tcpinfo->invflags & IPT_TCP_INV_SRCPT)))
return 0;
if (!port_match(tcpinfo->dpts[0], tcpinfo->dpts[1],
ntohs(tcph.dest),
ntohs(th->dest),
!!(tcpinfo->invflags & IPT_TCP_INV_DSTPT)))
return 0;
if (!FWINVTCP((((unsigned char *)&tcph)[13] & tcpinfo->flg_mask)
if (!FWINVTCP((((unsigned char *)th)[13] & tcpinfo->flg_mask)
== tcpinfo->flg_cmp,
IPT_TCP_INV_FLAGS))
return 0;
if (tcpinfo->option) {
if (tcph.doff * 4 < sizeof(tcph)) {
if (th->doff * 4 < sizeof(_tcph)) {
*hotdrop = 1;
return 0;
}
if (!tcp_find_option(tcpinfo->option, skb, tcph.doff*4 - sizeof(tcph),
if (!tcp_find_option(tcpinfo->option, skb,
th->doff*4 - sizeof(_tcph),
tcpinfo->invflags & IPT_TCP_INV_OPTION,
hotdrop))
return 0;
......@@ -1566,14 +1572,16 @@ udp_match(const struct sk_buff *skb,
int offset,
int *hotdrop)
{
struct udphdr udph;
struct udphdr _udph, *uh;
const struct ipt_udp *udpinfo = matchinfo;
/* Must not be a fragment. */
if (offset)
return 0;
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &udph, sizeof(udph)) < 0) {
uh = skb_header_pointer(skb, skb->nh.iph->ihl*4,
sizeof(_udph), &_udph);
if (uh == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
duprintf("Dropping evil UDP tinygram.\n");
......@@ -1582,10 +1590,10 @@ udp_match(const struct sk_buff *skb,
}
return port_match(udpinfo->spts[0], udpinfo->spts[1],
ntohs(udph.source),
ntohs(uh->source),
!!(udpinfo->invflags & IPT_UDP_INV_SRCPT))
&& port_match(udpinfo->dpts[0], udpinfo->dpts[1],
ntohs(udph.dest),
ntohs(uh->dest),
!!(udpinfo->invflags & IPT_UDP_INV_DSTPT));
}
......@@ -1637,16 +1645,19 @@ icmp_match(const struct sk_buff *skb,
int offset,
int *hotdrop)
{
struct icmphdr icmph;
struct icmphdr _icmph, *ic;
const struct ipt_icmp *icmpinfo = matchinfo;
/* Must not be a fragment. */
if (offset)
return 0;
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &icmph, sizeof(icmph)) < 0){
ic = skb_header_pointer(skb, skb->nh.iph->ihl*4,
sizeof(_icmph), &_icmph);
if (ic == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
* can't. Hence, no choice but to drop.
*/
duprintf("Dropping evil ICMP tinygram.\n");
*hotdrop = 1;
return 0;
......@@ -1655,7 +1666,7 @@ icmp_match(const struct sk_buff *skb,
return icmp_type_code_match(icmpinfo->type,
icmpinfo->code[0],
icmpinfo->code[1],
icmph.type, icmph.code,
ic->type, ic->code,
!!(icmpinfo->invflags&IPT_ICMP_INV));
}
......
......@@ -679,49 +679,53 @@ ip_fw_check(const char *rif,
case IPPROTO_TCP:
dprintf("TCP ");
if (!offset) {
struct tcphdr tcph;
struct tcphdr _tcph, *th;
if (skb_copy_bits(*pskb,
(*pskb)->nh.iph->ihl * 4,
&tcph, sizeof(tcph)))
th = skb_header_pointer(*pskb,
(*pskb)->nh.iph->ihl*4,
sizeof(_tcph), &_tcph);
if (th == NULL)
return FW_BLOCK;
src_port = ntohs(tcph.source);
dst_port = ntohs(tcph.dest);
src_port = ntohs(th->source);
dst_port = ntohs(th->dest);
/* Connection initilisation can only
* be made when the syn bit is set and
* neither of the ack or reset is
* set. */
if (tcph.syn && !(tcph.ack || tcph.rst))
if (th->syn && !(th->ack || th->rst))
tcpsyn = 1;
}
break;
case IPPROTO_UDP:
dprintf("UDP ");
if (!offset) {
struct udphdr udph;
struct udphdr _udph, *uh;
if (skb_copy_bits(*pskb,
(*pskb)->nh.iph->ihl * 4,
&udph, sizeof(udph)))
uh = skb_header_pointer(*pskb,
(*pskb)->nh.iph->ihl*4,
sizeof(_udph), &_udph);
if (uh == NULL)
return FW_BLOCK;
src_port = ntohs(udph.source);
dst_port = ntohs(udph.dest);
src_port = ntohs(uh->source);
dst_port = ntohs(uh->dest);
}
break;
case IPPROTO_ICMP:
if (!offset) {
struct icmphdr icmph;
struct icmphdr _icmph, *ic;
if (skb_copy_bits(*pskb,
(*pskb)->nh.iph->ihl * 4,
&icmph, sizeof(icmph)))
ic = skb_header_pointer(*pskb,
(*pskb)->nh.iph->ihl*4,
sizeof(_icmph),
&_icmph);
if (ic == NULL)
return FW_BLOCK;
src_port = (__u16) icmph.type;
dst_port = (__u16) icmph.code;
src_port = (__u16) ic->type;
dst_port = (__u16) ic->code;
}
dprintf("ICMP ");
break;
......
......@@ -410,20 +410,21 @@ int ip_fw_chk(struct sk_buff **pskb,
dprintf1("TCP ");
/* ports stay 0xFFFF if it is not the first fragment */
if (!offset) {
struct tcphdr tcph;
struct tcphdr _tcph, *th;
if (skb_copy_bits(*pskb,
(*pskb)->nh.iph->ihl * 4,
&tcph, sizeof(tcph)))
th = skb_header_pointer(*pskb,
(*pskb)->nh.iph->ihl*4,
sizeof(_tcph), &_tcph);
if (th == NULL)
return FW_BLOCK;
src_port = ntohs(tcph.source);
dst_port = ntohs(tcph.dest);
src_port = ntohs(th->source);
dst_port = ntohs(th->dest);
if(!tcph.ack && !tcph.rst)
if(!th->ack && !th->rst)
/* We do NOT have ACK, value TRUE */
notcpack = 1;
if(!tcph.syn || !notcpack)
if(!th->syn || !notcpack)
/* We do NOT have SYN, value TRUE */
notcpsyn = 1;
}
......@@ -433,29 +434,32 @@ int ip_fw_chk(struct sk_buff **pskb,
dprintf1("UDP ");
/* ports stay 0xFFFF if it is not the first fragment */
if (!offset) {
struct udphdr udph;
struct udphdr _udph, *uh;
if (skb_copy_bits(*pskb,
(*pskb)->nh.iph->ihl * 4,
&udph, sizeof(udph)))
uh = skb_header_pointer(*pskb,
(*pskb)->nh.iph->ihl*4,
sizeof(_udph), &_udph);
if (uh == NULL)
return FW_BLOCK;
src_port = ntohs(udph.source);
dst_port = ntohs(udph.dest);
src_port = ntohs(uh->source);
dst_port = ntohs(uh->dest);
}
prt = IP_FW_F_UDP;
break;
case IPPROTO_ICMP:
/* icmp_type stays 255 if it is not the first fragment */
if (!offset) {
struct icmphdr icmph;
struct icmphdr _icmph, *ic;
if (skb_copy_bits(*pskb,
(*pskb)->nh.iph->ihl * 4,
&icmph, sizeof(icmph)))
ic = skb_header_pointer(*pskb,
(*pskb)->nh.iph->ihl*4,
sizeof(_icmph),
&_icmph);
if (ic == NULL)
return FW_BLOCK;
icmp_type = (__u16) icmph.type;
icmp_type = (__u16) ic->type;
}
dprintf2("ICMP:%d ", icmp_type);
prt = IP_FW_F_ICMP;
......
......@@ -52,34 +52,39 @@ set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
static inline int
set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo, int inward)
{
struct tcphdr tcph;
struct tcphdr _tcph, *th;
u_int16_t diffs[2];
/* Not enought header? */
if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4, &tcph, sizeof(tcph))
< 0)
th = skb_header_pointer(*pskb, (*pskb)->nh.iph->ihl*4,
sizeof(_tcph), &_tcph);
if (th == NULL)
return 0;
diffs[0] = ((u_int16_t *)&tcph)[6];
diffs[0] = ((u_int16_t *)th)[6];
if (einfo->operation & IPT_ECN_OP_SET_ECE)
tcph.ece = einfo->proto.tcp.ece;
th->ece = einfo->proto.tcp.ece;
if (einfo->operation & IPT_ECN_OP_SET_CWR)
tcph.cwr = einfo->proto.tcp.cwr;
diffs[1] = ((u_int16_t *)&tcph)[6];
th->cwr = einfo->proto.tcp.cwr;
diffs[1] = ((u_int16_t *)&th)[6];
/* Only mangle if it's changed. */
if (diffs[0] != diffs[1]) {
diffs[0] = diffs[0] ^ 0xFFFF;
if (!skb_ip_make_writable(pskb,
(*pskb)->nh.iph->ihl*4+sizeof(tcph)))
(*pskb)->nh.iph->ihl*4+sizeof(_tcph)))
return 0;
if (th != &_tcph)
memcpy(&_tcph, th, sizeof(_tcph));
if ((*pskb)->ip_summed != CHECKSUM_HW)
tcph.check = csum_fold(csum_partial((char *)diffs,
sizeof(diffs),
tcph.check^0xFFFF));
_tcph.check = csum_fold(csum_partial((char *)diffs,
sizeof(diffs),
_tcph.check^0xFFFF));
memcpy((*pskb)->data + (*pskb)->nh.iph->ihl*4,
&tcph, sizeof(tcph));
&_tcph, sizeof(_tcph));
if ((*pskb)->ip_summed == CHECKSUM_HW)
if (skb_checksum_help(pskb, inward))
return 0;
......
This diff is collapsed.
......@@ -103,7 +103,7 @@ static inline struct rtable *route_reverse(struct sk_buff *skb, int hook)
static void send_reset(struct sk_buff *oldskb, int hook)
{
struct sk_buff *nskb;
struct tcphdr otcph, *tcph;
struct tcphdr _otcph, *oth, *tcph;
struct rtable *rt;
u_int16_t tmp_port;
u_int32_t tmp_addr;
......@@ -114,12 +114,13 @@ static void send_reset(struct sk_buff *oldskb, int hook)
if (oldskb->nh.iph->frag_off & htons(IP_OFFSET))
return;
if (skb_copy_bits(oldskb, oldskb->nh.iph->ihl*4,
&otcph, sizeof(otcph)) < 0)
oth = skb_header_pointer(oldskb, oldskb->nh.iph->ihl * 4,
sizeof(_otcph), &_otcph);
if (oth == NULL)
return;
/* No RST for RST. */
if (otcph.rst)
if (oth->rst)
return;
/* FIXME: Check checksum --RR */
......@@ -167,13 +168,13 @@ static void send_reset(struct sk_buff *oldskb, int hook)
if (tcph->ack) {
needs_ack = 0;
tcph->seq = otcph.ack_seq;
tcph->seq = oth->ack_seq;
tcph->ack_seq = 0;
} else {
needs_ack = 1;
tcph->ack_seq = htonl(ntohl(otcph.seq) + otcph.syn + otcph.fin
tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin
+ oldskb->len - oldskb->nh.iph->ihl*4
- (otcph.doff<<2));
- (oth->doff<<2));
tcph->seq = 0;
}
......
......@@ -43,23 +43,26 @@ match(const struct sk_buff *skb,
int offset,
int *hotdrop)
{
struct ip_auth_hdr ah;
struct ip_auth_hdr _ahdr, *ah;
const struct ipt_ah *ahinfo = matchinfo;
/* Must not be a fragment. */
if (offset)
return 0;
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &ah, sizeof(ah)) < 0) {
ah = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
sizeof(_ahdr), &_ahdr);
if (ah == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
* can't. Hence, no choice but to drop.
*/
duprintf("Dropping evil AH tinygram.\n");
*hotdrop = 1;
return 0;
}
return spi_match(ahinfo->spis[0], ahinfo->spis[1],
ntohl(ah.spi),
ntohl(ah->spi),
!!(ahinfo->invflags & IPT_AH_INV_SPI));
}
......
......@@ -30,31 +30,34 @@ static inline int match_tcp(const struct sk_buff *skb,
const struct ipt_ecn_info *einfo,
int *hotdrop)
{
struct tcphdr tcph;
struct tcphdr _tcph, *th;
/* In practice, TCP match does this, so can't fail. But let's
be good citizens. */
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0) {
* be good citizens.
*/
th = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
sizeof(_tcph), &_tcph);
if (th == NULL) {
*hotdrop = 0;
return 0;
}
if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
if (einfo->invert & IPT_ECN_OP_MATCH_ECE) {
if (tcph.ece == 1)
if (th->ece == 1)
return 0;
} else {
if (tcph.ece == 0)
if (th->ece == 0)
return 0;
}
}
if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
if (einfo->invert & IPT_ECN_OP_MATCH_CWR) {
if (tcph.cwr == 1)
if (th->cwr == 1)
return 0;
} else {
if (tcph.cwr == 0)
if (th->cwr == 0)
return 0;
}
}
......
......@@ -44,23 +44,26 @@ match(const struct sk_buff *skb,
int offset,
int *hotdrop)
{
struct ip_esp_hdr esp;
struct ip_esp_hdr _esp, *eh;
const struct ipt_esp *espinfo = matchinfo;
/* Must not be a fragment. */
if (offset)
return 0;
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &esp, sizeof(esp)) < 0) {
eh = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
sizeof(_esp), &_esp);
if (eh == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
* can't. Hence, no choice but to drop.
*/
duprintf("Dropping evil ESP tinygram.\n");
*hotdrop = 1;
return 0;
}
return spi_match(espinfo->spis[0], espinfo->spis[1],
ntohl(esp.spi),
ntohl(eh->spi),
!!(espinfo->invflags & IPT_ESP_INV_SPI));
}
......
......@@ -54,7 +54,7 @@ match(const struct sk_buff *skb,
int offset,
int *hotdrop)
{
u16 ports[2];
u16 _ports[2], *pptr;
const struct ipt_multiport *multiinfo = matchinfo;
/* Must not be a fragment. */
......@@ -63,18 +63,21 @@ match(const struct sk_buff *skb,
/* Must be big enough to read ports (both UDP and TCP have
them at the start). */
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, ports, sizeof(ports)) < 0) {
pptr = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
sizeof(_ports), &_ports[0]);
if (pptr == NULL) {
/* We've been asked to examine this packet, and we
can't. Hence, no choice but to drop. */
duprintf("ipt_multiport:"
" Dropping evil offset=0 tinygram.\n");
*hotdrop = 1;
return 0;
* can't. Hence, no choice but to drop.
*/
duprintf("ipt_multiport:"
" Dropping evil offset=0 tinygram.\n");
*hotdrop = 1;
return 0;
}
return ports_match(multiinfo->ports,
multiinfo->flags, multiinfo->count,
ntohs(ports[0]), ntohs(ports[1]));
ntohs(pptr[0]), ntohs(pptr[1]));
}
/* Called when user tries to insert an entry of this type. */
......
......@@ -27,37 +27,45 @@ mssoption_match(u_int16_t min, u_int16_t max,
int invert,
int *hotdrop)
{
struct tcphdr tcph;
struct tcphdr _tcph, *th;
/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
u8 opt[15 * 4 - sizeof(tcph)];
u8 _opt[15 * 4 - sizeof(_tcph)], *op;
unsigned int i, optlen;
/* If we don't have the whole header, drop packet. */
if (skb_copy_bits(skb, skb->nh.iph->ihl*4, &tcph, sizeof(tcph)) < 0)
th = skb_header_pointer(skb, skb->nh.iph->ihl * 4,
sizeof(_tcph), &_tcph);
if (th == NULL)
goto dropit;
/* Malformed. */
if (tcph.doff*4 < sizeof(tcph))
if (th->doff*4 < sizeof(*th))
goto dropit;
optlen = tcph.doff*4 - sizeof(tcph);
optlen = th->doff*4 - sizeof(*th);
if (!optlen)
goto out;
/* Truncated options. */
if (skb_copy_bits(skb, skb->nh.iph->ihl*4+sizeof(tcph), opt, optlen)<0)
op = skb_header_pointer(skb, skb->nh.iph->ihl * 4 + sizeof(*th),
optlen, _opt);
if (op == NULL)
goto dropit;
for (i = 0; i < optlen; ) {
if (opt[i] == TCPOPT_MSS
if (op[i] == TCPOPT_MSS
&& (optlen - i) >= TCPOLEN_MSS
&& opt[i+1] == TCPOLEN_MSS) {
&& op[i+1] == TCPOLEN_MSS) {
u_int16_t mssval;
mssval = (opt[i+2] << 8) | opt[i+3];
mssval = (op[i+2] << 8) | op[i+3];
return (mssval >= min && mssval <= max) ^ invert;
}
if (opt[i] < 2) i++;
else i += opt[i+1]?:1;
if (op[i] < 2) i++;
else i += op[i+1]?:1;
}
out:
return invert;
dropit:
......
......@@ -68,34 +68,35 @@ int ipv6_skip_exthdr(const struct sk_buff *skb, int start, u8 *nexthdrp, int len
u8 nexthdr = *nexthdrp;
while (ipv6_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr hdr;
struct ipv6_opt_hdr _hdr, *hp;
int hdrlen;
if (len < (int)sizeof(struct ipv6_opt_hdr))
return -1;
if (nexthdr == NEXTHDR_NONE)
return -1;
if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
hp = skb_header_pointer(skb, start, sizeof(_hdr), &_hdr);
if (hp == NULL)
BUG();
if (nexthdr == NEXTHDR_FRAGMENT) {
unsigned short frag_off;
if (skb_copy_bits(skb,
start+offsetof(struct frag_hdr,
frag_off),
&frag_off,
sizeof(frag_off))) {
unsigned short _frag_off, *fp;
fp = skb_header_pointer(skb,
start+offsetof(struct frag_hdr,
frag_off),
sizeof(_frag_off),
&_frag_off);
if (fp == NULL)
return -1;
}
if (ntohs(frag_off) & ~0x7)
if (ntohs(*fp) & ~0x7)
break;
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr.hdrlen+2)<<2;
hdrlen = (hp->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(&hdr);
hdrlen = ipv6_optlen(hp);
nexthdr = hdr.nexthdr;
nexthdr = hp->nexthdr;
len -= hdrlen;
start += hdrlen;
}
......
......@@ -139,10 +139,12 @@ static int is_ineligible(struct sk_buff *skb)
if (ptr < 0)
return 0;
if (nexthdr == IPPROTO_ICMPV6) {
u8 type;
if (skb_copy_bits(skb, ptr+offsetof(struct icmp6hdr, icmp6_type),
&type, 1)
|| !(type & ICMPV6_INFOMSG_MASK))
u8 _type, *tp;
tp = skb_header_pointer(skb,
ptr+offsetof(struct icmp6hdr, icmp6_type),
sizeof(_type), &_type);
if (tp == NULL ||
!(*tp & ICMPV6_INFOMSG_MASK))
return 1;
}
return 0;
......@@ -200,12 +202,13 @@ static inline int icmpv6_xrlim_allow(struct sock *sk, int type,
static __inline__ int opt_unrec(struct sk_buff *skb, __u32 offset)
{
u8 optval;
u8 _optval, *op;
offset += skb->nh.raw - skb->data;
if (skb_copy_bits(skb, offset, &optval, 1))
op = skb_header_pointer(skb, offset, sizeof(_optval), &_optval);
if (op == NULL)
return 1;
return (optval&0xC0) == 0x80;
return (*op & 0xC0) == 0x80;
}
int icmpv6_push_pending_frames(struct sock *sk, struct flowi *fl, struct icmp6hdr *thdr, int len)
......
......@@ -929,7 +929,6 @@ static void rxrpc_call_receive_packet(struct rxrpc_call *call)
{
struct rxrpc_message *msg;
struct list_head *_p;
uint32_t data32;
_enter("%p", call);
......@@ -986,22 +985,21 @@ static void rxrpc_call_receive_packet(struct rxrpc_call *call)
break;
/* deal with abort packets */
case RXRPC_PACKET_TYPE_ABORT:
data32 = 0;
if (skb_copy_bits(msg->pkt, msg->offset,
&data32, sizeof(data32)) < 0) {
case RXRPC_PACKET_TYPE_ABORT: {
uint32_t _dbuf, *dp;
dp = skb_header_pointer(msg->pkt, msg->offset,
sizeof(_dbuf), &_dbuf);
if (dp == NULL)
printk("Rx Received short ABORT packet\n");
}
else {
data32 = ntohl(data32);
}
_proto("Rx Received Call ABORT { data=%d }", data32);
_proto("Rx Received Call ABORT { data=%d }",
(dp ? ntohl(*dp) : 0));
spin_lock(&call->lock);
call->app_call_state = RXRPC_CSTATE_ERROR;
call->app_err_state = RXRPC_ESTATE_PEER_ABORT;
call->app_abort_code = data32;
call->app_abort_code = (dp ? ntohl(*dp) : 0);
call->app_errno = -ECONNABORTED;
call->app_mark = RXRPC_APP_MARK_EOF;
call->app_read_buf = NULL;
......@@ -1013,7 +1011,7 @@ static void rxrpc_call_receive_packet(struct rxrpc_call *call)
spin_unlock(&call->lock);
call->app_error_func(call);
break;
}
default:
/* deal with other packet types */
_proto("Rx Unsupported packet type %u (#%u)",
......@@ -1271,7 +1269,7 @@ static void rxrpc_call_receive_data_packet(struct rxrpc_call *call,
static void rxrpc_call_receive_ack_packet(struct rxrpc_call *call,
struct rxrpc_message *msg)
{
struct rxrpc_ackpacket ack;
struct rxrpc_ackpacket _ack, *ap;
rxrpc_serial_t serial;
rxrpc_seq_t seq;
int ret;
......@@ -1279,33 +1277,34 @@ static void rxrpc_call_receive_ack_packet(struct rxrpc_call *call,
_enter("%p{%u},%p{%u}", call, ntohl(call->call_id), msg, msg->seq);
/* extract the basic ACK record */
if (skb_copy_bits(msg->pkt, msg->offset, &ack, sizeof(ack)) < 0) {
ap = skb_header_pointer(msg->pkt, msg->offset, sizeof(_ack), &_ack);
if (ap == NULL) {
printk("Rx Received short ACK packet\n");
return;
}
msg->offset += sizeof(ack);
msg->offset += sizeof(_ack);
serial = ack.serial;
seq = ntohl(ack.firstPacket);
serial = ap->serial;
seq = ntohl(ap->firstPacket);
_proto("Rx Received ACK %%%d { b=%hu m=%hu f=%u p=%u s=%u r=%s n=%u }",
ntohl(msg->hdr.serial),
ntohs(ack.bufferSpace),
ntohs(ack.maxSkew),
ntohs(ap->bufferSpace),
ntohs(ap->maxSkew),
seq,
ntohl(ack.previousPacket),
ntohl(ap->previousPacket),
ntohl(serial),
rxrpc_acks[ack.reason],
rxrpc_acks[ap->reason],
call->ackr.nAcks
);
/* check the other side isn't ACK'ing a sequence number I haven't sent
* yet */
if (ack.nAcks > 0 &&
if (ap->nAcks > 0 &&
(seq > call->snd_seq_count ||
seq + ack.nAcks - 1 > call->snd_seq_count)) {
seq + ap->nAcks - 1 > call->snd_seq_count)) {
printk("Received ACK (#%u-#%u) for unsent packet\n",
seq, seq + ack.nAcks - 1);
seq, seq + ap->nAcks - 1);
rxrpc_call_abort(call, -EINVAL);
_leave("");
return;
......@@ -1354,7 +1353,7 @@ static void rxrpc_call_receive_ack_packet(struct rxrpc_call *call,
}
}
switch (ack.reason) {
switch (ap->reason) {
/* deal with negative/positive acknowledgement of data
* packets */
case RXRPC_ACK_REQUESTED:
......@@ -1366,14 +1365,14 @@ static void rxrpc_call_receive_ack_packet(struct rxrpc_call *call,
case RXRPC_ACK_OUT_OF_SEQUENCE:
case RXRPC_ACK_EXCEEDS_WINDOW:
call->snd_resend_cnt = 0;
ret = rxrpc_call_record_ACK(call, msg, seq, ack.nAcks);
ret = rxrpc_call_record_ACK(call, msg, seq, ap->nAcks);
if (ret < 0)
rxrpc_call_abort(call, ret);
break;
/* respond to ping packets immediately */
case RXRPC_ACK_PING:
rxrpc_call_generate_ACK(call, &msg->hdr, &ack);
rxrpc_call_generate_ACK(call, &msg->hdr, ap);
break;
/* only record RTT on ping response packets */
......@@ -1386,7 +1385,7 @@ static void rxrpc_call_receive_ack_packet(struct rxrpc_call *call,
rttmsg = NULL;
spin_lock(&call->lock);
if (call->snd_ping &&
call->snd_ping->hdr.serial == ack.serial) {
call->snd_ping->hdr.serial == ap->serial) {
rttmsg = call->snd_ping;
call->snd_ping = NULL;
}
......@@ -1402,7 +1401,7 @@ static void rxrpc_call_receive_ack_packet(struct rxrpc_call *call,
break;
default:
printk("Unsupported ACK reason %u\n", ack.reason);
printk("Unsupported ACK reason %u\n", ap->reason);
break;
}
......
......@@ -753,7 +753,7 @@ udp_data_ready(struct sock *sk, int len)
struct rpc_rqst *rovr;
struct sk_buff *skb;
int err, repsize, copied;
u32 xid;
u32 _xid, *xp;
read_lock(&sk->sk_callback_lock);
dprintk("RPC: udp_data_ready...\n");
......@@ -777,12 +777,14 @@ udp_data_ready(struct sock *sk, int len)
}
/* Copy the XID from the skb... */
if (skb_copy_bits(skb, sizeof(struct udphdr), &xid, sizeof(xid)) < 0)
xp = skb_header_pointer(skb, sizeof(struct udphdr),
sizeof(_xid), &_xid);
if (xp == NULL)
goto dropit;
/* Look up and lock the request corresponding to the given XID */
spin_lock(&xprt->sock_lock);
rovr = xprt_lookup_rqst(xprt, xid);
rovr = xprt_lookup_rqst(xprt, *xp);
if (!rovr)
goto out_unlock;
task = rovr->rq_task;
......
......@@ -2823,48 +2823,50 @@ static void selinux_task_to_inode(struct task_struct *p,
static int selinux_parse_skb_ipv4(struct sk_buff *skb, struct avc_audit_data *ad)
{
int offset, ihlen, ret;
struct iphdr iph;
struct iphdr _iph, *ih;
offset = skb->nh.raw - skb->data;
ret = skb_copy_bits(skb, offset, &iph, sizeof(iph));
if (ret)
ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
if (ih == NULL)
goto out;
ihlen = iph.ihl * 4;
if (ihlen < sizeof(iph))
ihlen = ih->ihl * 4;
if (ihlen < sizeof(_iph))
goto out;
ad->u.net.v4info.saddr = iph.saddr;
ad->u.net.v4info.daddr = iph.daddr;
ad->u.net.v4info.saddr = ih->saddr;
ad->u.net.v4info.daddr = ih->daddr;
switch (iph.protocol) {
switch (ih->protocol) {
case IPPROTO_TCP: {
struct tcphdr tcph;
struct tcphdr _tcph, *th;
if (ntohs(iph.frag_off) & IP_OFFSET)
if (ntohs(ih->frag_off) & IP_OFFSET)
break;
offset += ihlen;
if (skb_copy_bits(skb, offset, &tcph, sizeof(tcph)) < 0)
th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
if (th == NULL)
break;
ad->u.net.sport = tcph.source;
ad->u.net.dport = tcph.dest;
ad->u.net.sport = th->source;
ad->u.net.dport = th->dest;
break;
}
case IPPROTO_UDP: {
struct udphdr udph;
struct udphdr _udph, *uh;
if (ntohs(iph.frag_off) & IP_OFFSET)
if (ntohs(ih->frag_off) & IP_OFFSET)
break;
offset += ihlen;
if (skb_copy_bits(skb, offset, &udph, sizeof(udph)) < 0)
break;
uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
if (uh == NULL)
break;
ad->u.net.sport = udph.source;
ad->u.net.dport = udph.dest;
ad->u.net.sport = uh->source;
ad->u.net.dport = uh->dest;
break;
}
......@@ -2882,18 +2884,18 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, struct avc_audit_data *ad
{
u8 nexthdr;
int ret, offset;
struct ipv6hdr ipv6h;
struct ipv6hdr _ipv6h, *ip6;
offset = skb->nh.raw - skb->data;
ret = skb_copy_bits(skb, offset, &ipv6h, sizeof(ipv6h));
if (ret)
ip6 = skb_header_pointer(skb, offset, sizeof(_ipv6h), &_ipv6h);
if (ip6 == NULL)
goto out;
ipv6_addr_copy(&ad->u.net.v6info.saddr, &ipv6h.saddr);
ipv6_addr_copy(&ad->u.net.v6info.daddr, &ipv6h.daddr);
ipv6_addr_copy(&ad->u.net.v6info.saddr, &ip6->saddr);
ipv6_addr_copy(&ad->u.net.v6info.daddr, &ip6->daddr);
nexthdr = ipv6h.nexthdr;
offset += sizeof(ipv6h);
nexthdr = ip6->nexthdr;
offset += sizeof(_ipv6h);
offset = ipv6_skip_exthdr(skb, offset, &nexthdr,
skb->tail - skb->head - offset);
if (offset < 0)
......@@ -2901,24 +2903,26 @@ static int selinux_parse_skb_ipv6(struct sk_buff *skb, struct avc_audit_data *ad
switch (nexthdr) {
case IPPROTO_TCP: {
struct tcphdr tcph;
struct tcphdr _tcph, *th;
if (skb_copy_bits(skb, offset, &tcph, sizeof(tcph)) < 0)
th = skb_header_pointer(skb, offset, sizeof(_tcph), &_tcph);
if (th == NULL)
break;
ad->u.net.sport = tcph.source;
ad->u.net.dport = tcph.dest;
ad->u.net.sport = th->source;
ad->u.net.dport = th->dest;
break;
}
case IPPROTO_UDP: {
struct udphdr udph;
struct udphdr _udph, *uh;
if (skb_copy_bits(skb, offset, &udph, sizeof(udph)) < 0)
uh = skb_header_pointer(skb, offset, sizeof(_udph), &_udph);
if (uh == NULL)
break;
ad->u.net.sport = udph.source;
ad->u.net.dport = udph.dest;
ad->u.net.sport = uh->source;
ad->u.net.dport = uh->dest;
break;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment