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