Commit 473ba53f authored by Rusty Russell's avatar Rusty Russell Committed by David S. Miller

[NETFILTER]: Linearize iptables targets.

Adjusts the IPTables targets to handle non-linear packets.
ipt_ULOG untested.
parent 8dcfc9e3
...@@ -23,37 +23,31 @@ MODULE_LICENSE("GPL"); ...@@ -23,37 +23,31 @@ MODULE_LICENSE("GPL");
static unsigned int static unsigned int
target(struct sk_buff **pskb, target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
unsigned int hooknum,
const void *targinfo, const void *targinfo,
void *userinfo) void *userinfo)
{ {
struct iphdr *iph = (*pskb)->nh.iph;
const struct ipt_DSCP_info *dinfo = targinfo; const struct ipt_DSCP_info *dinfo = targinfo;
u_int8_t sh_dscp = ((dinfo->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK); u_int8_t sh_dscp = ((dinfo->dscp << IPT_DSCP_SHIFT) & IPT_DSCP_MASK);
if ((iph->tos & IPT_DSCP_MASK) != sh_dscp) { if (((*pskb)->nh.iph->tos & IPT_DSCP_MASK) != sh_dscp) {
u_int16_t diffs[2]; u_int16_t diffs[2];
/* raw socket (tcpdump) may have clone of incoming if (!skb_ip_make_writable(pskb, sizeof(struct iphdr)))
* skb: don't disturb it --RR */
if (skb_cloned(*pskb) && !(*pskb)->sk) {
struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
if (!nskb)
return NF_DROP; return NF_DROP;
kfree_skb(*pskb);
*pskb = nskb;
iph = (*pskb)->nh.iph;
}
diffs[0] = htons(iph->tos) ^ 0xFFFF; diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF;
iph->tos = (iph->tos & ~IPT_DSCP_MASK) | sh_dscp; (*pskb)->nh.iph->tos = ((*pskb)->nh.iph->tos & ~IPT_DSCP_MASK)
diffs[1] = htons(iph->tos); | sh_dscp;
iph->check = csum_fold(csum_partial((char *)diffs, diffs[1] = htons((*pskb)->nh.iph->tos);
(*pskb)->nh.iph->check
= csum_fold(csum_partial((char *)diffs,
sizeof(diffs), sizeof(diffs),
iph->check^0xFFFF)); (*pskb)->nh.iph->check
^ 0xFFFF));
(*pskb)->nfcache |= NFC_ALTERED; (*pskb)->nfcache |= NFC_ALTERED;
} }
return IPT_CONTINUE; return IPT_CONTINUE;
......
...@@ -19,105 +19,85 @@ ...@@ -19,105 +19,85 @@
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
/* set ECT codepoint from IP header. /* set ECT codepoint from IP header.
* return 0 in case there was no ECT codepoint * return 0 if there was an error. */
* return 1 in case ECT codepoint has been overwritten
* return < 0 in case there was error */
static inline int static inline int
set_ect_ip(struct sk_buff **pskb, struct iphdr *iph, set_ect_ip(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
const struct ipt_ECN_info *einfo)
{ {
if ((iph->tos & IPT_ECN_IP_MASK) if (((*pskb)->nh.iph->tos & IPT_ECN_IP_MASK)
!= (einfo->ip_ect & IPT_ECN_IP_MASK)) { != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
u_int16_t diffs[2]; u_int16_t diffs[2];
/* raw socket (tcpdump) may have clone of incoming if (!skb_ip_make_writable(pskb, sizeof(struct iphdr)))
* skb: don't disturb it --RR */ return 0;
if (skb_cloned(*pskb) && !(*pskb)->sk) {
struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
if (!nskb)
return NF_DROP;
kfree_skb(*pskb);
*pskb = nskb;
iph = (*pskb)->nh.iph;
}
diffs[0] = htons(iph->tos) ^ 0xFFFF; diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF;
iph->tos = iph->tos & ~IPT_ECN_IP_MASK; (*pskb)->nh.iph->tos &= ~IPT_ECN_IP_MASK;
iph->tos = iph->tos | (einfo->ip_ect & IPT_ECN_IP_MASK); (*pskb)->nh.iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK);
diffs[1] = htons(iph->tos); diffs[1] = htons((*pskb)->nh.iph->tos);
iph->check = csum_fold(csum_partial((char *)diffs, (*pskb)->nh.iph->check
= csum_fold(csum_partial((char *)diffs,
sizeof(diffs), sizeof(diffs),
iph->check^0xFFFF)); (*pskb)->nh.iph->check
^0xFFFF));
(*pskb)->nfcache |= NFC_ALTERED; (*pskb)->nfcache |= NFC_ALTERED;
return 1;
} }
return 0; return 1;
} }
/* Return 0 if there was an error. */
static inline int static inline int
set_ect_tcp(struct sk_buff **pskb, struct iphdr *iph, set_ect_tcp(struct sk_buff **pskb, const struct ipt_ECN_info *einfo)
const struct ipt_ECN_info *einfo)
{ {
struct tcphdr tcph;
struct tcphdr *tcph = (void *) iph + iph->ihl * 4;
u_int16_t *tcpflags = (u_int16_t *)tcph + 6;
u_int16_t diffs[2]; u_int16_t diffs[2];
/* raw socket (tcpdump) may have clone of incoming /* Not enought header? */
* skb: don't disturb it --RR */ if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4, &tcph, sizeof(tcph))
if (skb_cloned(*pskb) && !(*pskb)->sk) { < 0)
struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC); return 0;
if (!nskb)
return NF_DROP;
kfree_skb(*pskb);
*pskb = nskb;
iph = (*pskb)->nh.iph;
}
diffs[0] = *tcpflags;
if (einfo->operation & IPT_ECN_OP_SET_ECE diffs[0] = ((u_int16_t *)&tcph)[6];
&& tcph->ece != einfo->proto.tcp.ece) { if (einfo->operation & IPT_ECN_OP_SET_ECE)
tcph->ece = einfo->proto.tcp.ece; tcph.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) { tcph.cwr = einfo->proto.tcp.cwr;
tcph->cwr = einfo->proto.tcp.cwr; diffs[1] = ((u_int16_t *)&tcph)[6];
}
if (diffs[0] != *tcpflags) { /* Only mangle if it's changed. */
if (diffs[0] != diffs[1]) {
diffs[0] = diffs[0] ^ 0xFFFF; diffs[0] = diffs[0] ^ 0xFFFF;
diffs[1] = *tcpflags; if (!skb_ip_make_writable(pskb,
tcph->check = csum_fold(csum_partial((char *)diffs, (*pskb)->nh.iph->ihl*4+sizeof(tcph)))
return 0;
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,
&tcph, sizeof(tcph));
(*pskb)->nfcache |= NFC_ALTERED; (*pskb)->nfcache |= NFC_ALTERED;
return 1;
} }
return 1;
return 0;
} }
static unsigned int static unsigned int
target(struct sk_buff **pskb, target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
unsigned int hooknum,
const void *targinfo, const void *targinfo,
void *userinfo) void *userinfo)
{ {
struct iphdr *iph = (*pskb)->nh.iph;
const struct ipt_ECN_info *einfo = targinfo; const struct ipt_ECN_info *einfo = targinfo;
if (einfo->operation & IPT_ECN_OP_SET_IP) if (einfo->operation & IPT_ECN_OP_SET_IP)
set_ect_ip(pskb, iph, einfo); if (!set_ect_ip(pskb, einfo))
return NF_DROP;
if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR) if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR)
&& iph->protocol == IPPROTO_TCP) && (*pskb)->nh.iph->protocol == IPPROTO_TCP)
set_ect_tcp(pskb, iph, einfo); if (!set_ect_tcp(pskb, einfo))
return NF_DROP;
return IPT_CONTINUE; return IPT_CONTINUE;
} }
......
...@@ -29,127 +29,151 @@ static spinlock_t log_lock = SPIN_LOCK_UNLOCKED; ...@@ -29,127 +29,151 @@ static spinlock_t log_lock = SPIN_LOCK_UNLOCKED;
/* One level of recursion won't kill us */ /* One level of recursion won't kill us */
static void dump_packet(const struct ipt_log_info *info, static void dump_packet(const struct ipt_log_info *info,
struct iphdr *iph, unsigned int len, int recurse) const struct sk_buff *skb,
unsigned int iphoff)
{ {
void *protoh = (u_int32_t *)iph + iph->ihl; struct iphdr iph;
unsigned int datalen = len - iph->ihl * 4;
if (skb_copy_bits(skb, iphoff, &iph, sizeof(iph)) < 0) {
printk("TRUNCATED");
return;
}
/* Important fields: /* Important fields:
* TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */
/* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */
printk("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ", printk("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ",
NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); NIPQUAD(iph.saddr), NIPQUAD(iph.daddr));
/* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */
printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ",
ntohs(iph->tot_len), iph->tos & IPTOS_TOS_MASK, ntohs(iph.tot_len), iph.tos & IPTOS_TOS_MASK,
iph->tos & IPTOS_PREC_MASK, iph->ttl, ntohs(iph->id)); iph.tos & IPTOS_PREC_MASK, iph.ttl, ntohs(iph.id));
/* Max length: 6 "CE DF MF " */ /* Max length: 6 "CE DF MF " */
if (ntohs(iph->frag_off) & IP_CE) if (ntohs(iph.frag_off) & IP_CE)
printk("CE "); printk("CE ");
if (ntohs(iph->frag_off) & IP_DF) if (ntohs(iph.frag_off) & IP_DF)
printk("DF "); printk("DF ");
if (ntohs(iph->frag_off) & IP_MF) if (ntohs(iph.frag_off) & IP_MF)
printk("MF "); printk("MF ");
/* Max length: 11 "FRAG:65535 " */ /* Max length: 11 "FRAG:65535 " */
if (ntohs(iph->frag_off) & IP_OFFSET) if (ntohs(iph.frag_off) & IP_OFFSET)
printk("FRAG:%u ", ntohs(iph->frag_off) & IP_OFFSET); printk("FRAG:%u ", ntohs(iph.frag_off) & IP_OFFSET);
if ((info->logflags & IPT_LOG_IPOPT) if ((info->logflags & IPT_LOG_IPOPT)
&& iph->ihl * 4 != sizeof(struct iphdr)) { && iph.ihl * 4 != sizeof(struct iphdr)) {
unsigned int i; unsigned char opt[4 * 15 - sizeof(struct iphdr)];
unsigned int i, optsize;
optsize = iph.ihl * 4 - sizeof(struct iphdr);
if (skb_copy_bits(skb, iphoff+sizeof(iph), opt, optsize) < 0) {
printk("TRUNCATED");
return;
}
/* Max length: 127 "OPT (" 15*4*2chars ") " */ /* Max length: 127 "OPT (" 15*4*2chars ") " */
printk("OPT ("); printk("OPT (");
for (i = sizeof(struct iphdr); i < iph->ihl * 4; i++) for (i = 0; i < optsize; i++)
printk("%02X", ((u_int8_t *)iph)[i]); printk("%02X", opt[i]);
printk(") "); printk(") ");
} }
switch (iph->protocol) { switch (iph.protocol) {
case IPPROTO_TCP: { case IPPROTO_TCP: {
struct tcphdr *tcph = protoh; struct tcphdr tcph;
/* Max length: 10 "PROTO=TCP " */ /* Max length: 10 "PROTO=TCP " */
printk("PROTO=TCP "); printk("PROTO=TCP ");
if (ntohs(iph->frag_off) & IP_OFFSET) if (ntohs(iph.frag_off) & IP_OFFSET)
break; break;
/* Max length: 25 "INCOMPLETE [65535 bytes] " */ /* Max length: 25 "INCOMPLETE [65535 bytes] " */
if (datalen < sizeof (*tcph)) { if (skb_copy_bits(skb, iphoff+iph.ihl*4, &tcph, sizeof(tcph))
printk("INCOMPLETE [%u bytes] ", datalen); < 0) {
printk("INCOMPLETE [%u bytes] ",
skb->len - iphoff - iph.ihl*4);
break; break;
} }
/* Max length: 20 "SPT=65535 DPT=65535 " */ /* Max length: 20 "SPT=65535 DPT=65535 " */
printk("SPT=%u DPT=%u ", printk("SPT=%u DPT=%u ",
ntohs(tcph->source), ntohs(tcph->dest)); ntohs(tcph.source), ntohs(tcph.dest));
/* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */ /* Max length: 30 "SEQ=4294967295 ACK=4294967295 " */
if (info->logflags & IPT_LOG_TCPSEQ) if (info->logflags & IPT_LOG_TCPSEQ)
printk("SEQ=%u ACK=%u ", printk("SEQ=%u ACK=%u ",
ntohl(tcph->seq), ntohl(tcph->ack_seq)); ntohl(tcph.seq), ntohl(tcph.ack_seq));
/* Max length: 13 "WINDOW=65535 " */ /* Max length: 13 "WINDOW=65535 " */
printk("WINDOW=%u ", ntohs(tcph->window)); printk("WINDOW=%u ", ntohs(tcph.window));
/* Max length: 9 "RES=0x3F " */ /* Max length: 9 "RES=0x3F " */
printk("RES=0x%02x ", (u_int8_t)(ntohl(tcp_flag_word(tcph) & TCP_RESERVED_BITS) >> 22)); printk("RES=0x%02x ", (u8)(ntohl(tcp_flag_word(&tcph) & TCP_RESERVED_BITS) >> 22));
/* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */ /* Max length: 32 "CWR ECE URG ACK PSH RST SYN FIN " */
if (tcph->cwr) if (tcph.cwr)
printk("CWR "); printk("CWR ");
if (tcph->ece) if (tcph.ece)
printk("ECE "); printk("ECE ");
if (tcph->urg) if (tcph.urg)
printk("URG "); printk("URG ");
if (tcph->ack) if (tcph.ack)
printk("ACK "); printk("ACK ");
if (tcph->psh) if (tcph.psh)
printk("PSH "); printk("PSH ");
if (tcph->rst) if (tcph.rst)
printk("RST "); printk("RST ");
if (tcph->syn) if (tcph.syn)
printk("SYN "); printk("SYN ");
if (tcph->fin) if (tcph.fin)
printk("FIN "); printk("FIN ");
/* Max length: 11 "URGP=65535 " */ /* Max length: 11 "URGP=65535 " */
printk("URGP=%u ", ntohs(tcph->urg_ptr)); printk("URGP=%u ", ntohs(tcph.urg_ptr));
if ((info->logflags & IPT_LOG_TCPOPT) if ((info->logflags & IPT_LOG_TCPOPT)
&& tcph->doff * 4 != sizeof(struct tcphdr)) { && tcph.doff * 4 != sizeof(struct tcphdr)) {
unsigned int i; unsigned char opt[4 * 15 - sizeof(struct tcphdr)];
unsigned int i, optsize;
optsize = tcph.doff * 4 - sizeof(struct tcphdr);
if (skb_copy_bits(skb, iphoff+iph.ihl*4 + sizeof(tcph),
opt, optsize) < 0) {
printk("TRUNCATED");
return;
}
/* Max length: 127 "OPT (" 15*4*2chars ") " */ /* Max length: 127 "OPT (" 15*4*2chars ") " */
printk("OPT ("); printk("OPT (");
for (i =sizeof(struct tcphdr); i < tcph->doff * 4; i++) for (i = 0; i < optsize; i++)
printk("%02X", ((u_int8_t *)tcph)[i]); printk("%02X", opt[i]);
printk(") "); printk(") ");
} }
break; break;
} }
case IPPROTO_UDP: { case IPPROTO_UDP: {
struct udphdr *udph = protoh; struct udphdr udph;
/* Max length: 10 "PROTO=UDP " */ /* Max length: 10 "PROTO=UDP " */
printk("PROTO=UDP "); printk("PROTO=UDP ");
if (ntohs(iph->frag_off) & IP_OFFSET) if (ntohs(iph.frag_off) & IP_OFFSET)
break; break;
/* Max length: 25 "INCOMPLETE [65535 bytes] " */ /* Max length: 25 "INCOMPLETE [65535 bytes] " */
if (datalen < sizeof (*udph)) { if (skb_copy_bits(skb, iphoff+iph.ihl*4, &udph, sizeof(udph))
printk("INCOMPLETE [%u bytes] ", datalen); < 0) {
printk("INCOMPLETE [%u bytes] ",
skb->len - iphoff - iph.ihl*4);
break; break;
} }
/* Max length: 20 "SPT=65535 DPT=65535 " */ /* Max length: 20 "SPT=65535 DPT=65535 " */
printk("SPT=%u DPT=%u LEN=%u ", printk("SPT=%u DPT=%u LEN=%u ",
ntohs(udph->source), ntohs(udph->dest), ntohs(udph.source), ntohs(udph.dest),
ntohs(udph->len)); ntohs(udph.len));
break; break;
} }
case IPPROTO_ICMP: { case IPPROTO_ICMP: {
struct icmphdr *icmph = protoh; struct icmphdr icmph;
static size_t required_len[NR_ICMP_TYPES+1] static size_t required_len[NR_ICMP_TYPES+1]
= { [ICMP_ECHOREPLY] = 4, = { [ICMP_ECHOREPLY] = 4,
[ICMP_DEST_UNREACH] [ICMP_DEST_UNREACH]
...@@ -171,89 +195,93 @@ static void dump_packet(const struct ipt_log_info *info, ...@@ -171,89 +195,93 @@ static void dump_packet(const struct ipt_log_info *info,
/* Max length: 11 "PROTO=ICMP " */ /* Max length: 11 "PROTO=ICMP " */
printk("PROTO=ICMP "); printk("PROTO=ICMP ");
if (ntohs(iph->frag_off) & IP_OFFSET) if (ntohs(iph.frag_off) & IP_OFFSET)
break; break;
/* Max length: 25 "INCOMPLETE [65535 bytes] " */ /* Max length: 25 "INCOMPLETE [65535 bytes] " */
if (datalen < 4) { if (skb_copy_bits(skb, iphoff+iph.ihl*4, &icmph, sizeof(icmph))
printk("INCOMPLETE [%u bytes] ", datalen); < 0) {
printk("INCOMPLETE [%u bytes] ",
skb->len - iphoff - iph.ihl*4);
break; break;
} }
/* Max length: 18 "TYPE=255 CODE=255 " */ /* Max length: 18 "TYPE=255 CODE=255 " */
printk("TYPE=%u CODE=%u ", icmph->type, icmph->code); printk("TYPE=%u CODE=%u ", icmph.type, icmph.code);
/* Max length: 25 "INCOMPLETE [65535 bytes] " */ /* Max length: 25 "INCOMPLETE [65535 bytes] " */
if (icmph->type <= NR_ICMP_TYPES if (icmph.type <= NR_ICMP_TYPES
&& required_len[icmph->type] && required_len[icmph.type]
&& datalen < required_len[icmph->type]) { && skb->len-iphoff-iph.ihl*4 < required_len[icmph.type]) {
printk("INCOMPLETE [%u bytes] ", datalen); printk("INCOMPLETE [%u bytes] ",
skb->len - iphoff - iph.ihl*4);
break; break;
} }
switch (icmph->type) { switch (icmph.type) {
case ICMP_ECHOREPLY: case ICMP_ECHOREPLY:
case ICMP_ECHO: case ICMP_ECHO:
/* Max length: 19 "ID=65535 SEQ=65535 " */ /* Max length: 19 "ID=65535 SEQ=65535 " */
printk("ID=%u SEQ=%u ", printk("ID=%u SEQ=%u ",
ntohs(icmph->un.echo.id), ntohs(icmph.un.echo.id),
ntohs(icmph->un.echo.sequence)); ntohs(icmph.un.echo.sequence));
break; break;
case ICMP_PARAMETERPROB: case ICMP_PARAMETERPROB:
/* Max length: 14 "PARAMETER=255 " */ /* Max length: 14 "PARAMETER=255 " */
printk("PARAMETER=%u ", printk("PARAMETER=%u ",
ntohl(icmph->un.gateway) >> 24); ntohl(icmph.un.gateway) >> 24);
break; break;
case ICMP_REDIRECT: case ICMP_REDIRECT:
/* Max length: 24 "GATEWAY=255.255.255.255 " */ /* Max length: 24 "GATEWAY=255.255.255.255 " */
printk("GATEWAY=%u.%u.%u.%u ", NIPQUAD(icmph->un.gateway)); printk("GATEWAY=%u.%u.%u.%u ",
NIPQUAD(icmph.un.gateway));
/* Fall through */ /* Fall through */
case ICMP_DEST_UNREACH: case ICMP_DEST_UNREACH:
case ICMP_SOURCE_QUENCH: case ICMP_SOURCE_QUENCH:
case ICMP_TIME_EXCEEDED: case ICMP_TIME_EXCEEDED:
/* Max length: 3+maxlen */ /* Max length: 3+maxlen */
if (recurse) { if (!iphoff) { /* Only recurse once. */
printk("["); printk("[");
dump_packet(info, dump_packet(info, skb,
(struct iphdr *)(icmph + 1), iphoff + iph.ihl*4+sizeof(icmph));
datalen-sizeof(struct icmphdr),
0);
printk("] "); printk("] ");
} }
/* Max length: 10 "MTU=65535 " */ /* Max length: 10 "MTU=65535 " */
if (icmph->type == ICMP_DEST_UNREACH if (icmph.type == ICMP_DEST_UNREACH
&& icmph->code == ICMP_FRAG_NEEDED) && icmph.code == ICMP_FRAG_NEEDED)
printk("MTU=%u ", ntohs(icmph->un.frag.mtu)); printk("MTU=%u ", ntohs(icmph.un.frag.mtu));
} }
break; break;
} }
/* Max Length */ /* Max Length */
case IPPROTO_AH: case IPPROTO_AH:
case IPPROTO_ESP: { case IPPROTO_ESP: {
struct esphdr *esph = protoh; struct esphdr esph;
int esp= (iph->protocol==IPPROTO_ESP); int esp = (iph.protocol==IPPROTO_ESP);
/* Max length: 10 "PROTO=ESP " */ /* Max length: 10 "PROTO=ESP " */
printk("PROTO=%s ",esp? "ESP" : "AH"); printk("PROTO=%s ",esp? "ESP" : "AH");
if (ntohs(iph->frag_off) & IP_OFFSET) if (ntohs(iph.frag_off) & IP_OFFSET)
break; break;
/* Max length: 25 "INCOMPLETE [65535 bytes] " */ /* Max length: 25 "INCOMPLETE [65535 bytes] " */
if (datalen < sizeof (*esph)) { if (skb_copy_bits(skb, iphoff+iph.ihl*4, &esph, sizeof(esph))
printk("INCOMPLETE [%u bytes] ", datalen); < 0) {
printk("INCOMPLETE [%u bytes] ",
skb->len - iphoff - iph.ihl*4);
break; break;
} }
/* Length: 15 "SPI=0xF1234567 " */ /* Length: 15 "SPI=0xF1234567 " */
printk("SPI=0x%x ", ntohl(esph->spi) ); printk("SPI=0x%x ", ntohl(esph.spi));
break; break;
} }
/* Max length: 10 "PROTO 255 " */ /* Max length: 10 "PROTO 255 " */
default: default:
printk("PROTO=%u ", iph->protocol); printk("PROTO=%u ", iph.protocol);
} }
/* Proto Max log string length */ /* Proto Max log string length */
...@@ -272,13 +300,12 @@ static void dump_packet(const struct ipt_log_info *info, ...@@ -272,13 +300,12 @@ static void dump_packet(const struct ipt_log_info *info,
static unsigned int static unsigned int
ipt_log_target(struct sk_buff **pskb, ipt_log_target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
unsigned int hooknum,
const void *targinfo, const void *targinfo,
void *userinfo) void *userinfo)
{ {
struct iphdr *iph = (*pskb)->nh.iph;
const struct ipt_log_info *loginfo = targinfo; const struct ipt_log_info *loginfo = targinfo;
char level_string[4] = "< >"; char level_string[4] = "< >";
...@@ -304,7 +331,8 @@ ipt_log_target(struct sk_buff **pskb, ...@@ -304,7 +331,8 @@ ipt_log_target(struct sk_buff **pskb,
if (in && !out) { if (in && !out) {
/* MAC logging for input chain only. */ /* MAC logging for input chain only. */
printk("MAC="); printk("MAC=");
if ((*pskb)->dev && (*pskb)->dev->hard_header_len && (*pskb)->mac.raw != (void*)iph) { if ((*pskb)->dev && (*pskb)->dev->hard_header_len
&& (*pskb)->mac.raw != (void*)(*pskb)->nh.iph) {
int i; int i;
unsigned char *p = (*pskb)->mac.raw; unsigned char *p = (*pskb)->mac.raw;
for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++) for (i = 0; i < (*pskb)->dev->hard_header_len; i++,p++)
...@@ -315,7 +343,7 @@ ipt_log_target(struct sk_buff **pskb, ...@@ -315,7 +343,7 @@ ipt_log_target(struct sk_buff **pskb,
printk(" "); printk(" ");
} }
dump_packet(loginfo, iph, (*pskb)->len, 1); dump_packet(loginfo, *pskb, 0);
printk("\n"); printk("\n");
spin_unlock_bh(&log_lock); spin_unlock_bh(&log_lock);
......
...@@ -9,9 +9,9 @@ ...@@ -9,9 +9,9 @@
static unsigned int static unsigned int
target(struct sk_buff **pskb, target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
unsigned int hooknum,
const void *targinfo, const void *targinfo,
void *userinfo) void *userinfo)
{ {
......
...@@ -57,9 +57,9 @@ masquerade_check(const char *tablename, ...@@ -57,9 +57,9 @@ masquerade_check(const char *tablename,
static unsigned int static unsigned int
masquerade_target(struct sk_buff **pskb, masquerade_target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
unsigned int hooknum,
const void *targinfo, const void *targinfo,
void *userinfo) void *userinfo)
{ {
......
...@@ -65,18 +65,22 @@ static int route_mirror(struct sk_buff *skb) ...@@ -65,18 +65,22 @@ static int route_mirror(struct sk_buff *skb)
return 0; return 0;
} }
static void static int ip_rewrite(struct sk_buff **pskb)
ip_rewrite(struct sk_buff *skb)
{ {
struct iphdr *iph = skb->nh.iph; u32 odaddr, osaddr;
u32 odaddr = iph->saddr;
u32 osaddr = iph->daddr; if (!skb_ip_make_writable(pskb, sizeof(struct iphdr)))
return 0;
skb->nfcache |= NFC_ALTERED; odaddr = (*pskb)->nh.iph->saddr;
osaddr = (*pskb)->nh.iph->daddr;
(*pskb)->nfcache |= NFC_ALTERED;
/* Rewrite IP header */ /* Rewrite IP header */
iph->daddr = odaddr; (*pskb)->nh.iph->daddr = odaddr;
iph->saddr = osaddr; (*pskb)->nh.iph->saddr = osaddr;
return 1;
} }
/* Stolen from ip_finish_output2 */ /* Stolen from ip_finish_output2 */
...@@ -100,29 +104,28 @@ static void ip_direct_send(struct sk_buff *skb) ...@@ -100,29 +104,28 @@ static void ip_direct_send(struct sk_buff *skb)
} }
static unsigned int ipt_mirror_target(struct sk_buff **pskb, static unsigned int ipt_mirror_target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
unsigned int hooknum,
const void *targinfo, const void *targinfo,
void *userinfo) void *userinfo)
{ {
if (((*pskb)->dst != NULL) && if (((*pskb)->dst != NULL) && route_mirror(*pskb)) {
route_mirror(*pskb)) { if (!ip_rewrite(pskb))
return NF_DROP;
ip_rewrite(*pskb);
/* If we are not at FORWARD hook (INPUT/PREROUTING), /* If we are not at FORWARD hook (INPUT/PREROUTING),
* the TTL isn't decreased by the IP stack */ * the TTL isn't decreased by the IP stack */
if (hooknum != NF_IP_FORWARD) { if (hooknum != NF_IP_FORWARD) {
struct iphdr *iph = (*pskb)->nh.iph; if ((*pskb)->nh.iph->ttl <= 1) {
if (iph->ttl <= 1) {
/* this will traverse normal stack, and /* this will traverse normal stack, and
* thus call conntrack on the icmp packet */ * thus call conntrack on the icmp packet */
icmp_send(*pskb, ICMP_TIME_EXCEEDED, icmp_send(*pskb, ICMP_TIME_EXCEEDED,
ICMP_EXC_TTL, 0); ICMP_EXC_TTL, 0);
return NF_DROP; return NF_DROP;
} }
ip_decrease_ttl(iph); /* Made writable by ip_rewrite */
ip_decrease_ttl((*pskb)->nh.iph);
} }
/* Don't let conntrack code see this packet: /* Don't let conntrack code see this packet:
......
...@@ -53,9 +53,9 @@ redirect_check(const char *tablename, ...@@ -53,9 +53,9 @@ redirect_check(const char *tablename,
static unsigned int static unsigned int
redirect_target(struct sk_buff **pskb, redirect_target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
unsigned int hooknum,
const void *targinfo, const void *targinfo,
void *userinfo) void *userinfo)
{ {
......
...@@ -29,152 +29,140 @@ static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct) ...@@ -29,152 +29,140 @@ static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
void (*attach)(struct sk_buff *, struct nf_ct_info *); void (*attach)(struct sk_buff *, struct nf_ct_info *);
/* Avoid module unload race with ip_ct_attach being NULLed out */ /* Avoid module unload race with ip_ct_attach being NULLed out */
if (nfct && (attach = ip_ct_attach) != NULL) if (nfct && (attach = ip_ct_attach) != NULL) {
mb(); /* Just to be sure: must be read before executing this */
attach(new_skb, nfct); attach(new_skb, nfct);
}
} }
/* Send RST reply */ /* Send RST reply */
static void send_reset(struct sk_buff *oldskb, int local) static unsigned int send_reset(struct sk_buff **pskb, int local)
{ {
struct sk_buff *nskb; struct tcphdr tcph;
struct tcphdr *otcph, *tcph;
struct rtable *rt; struct rtable *rt;
unsigned int otcplen;
u_int16_t tmp_port; u_int16_t tmp_port;
u_int32_t tmp_addr; u_int32_t tmp_addr;
int needs_ack; int needs_ack, hh_len, datalen;
int hh_len; struct nf_ct_info *oldnfct;
/* IP header checks: fragment, too short. */ /* No RSTs for fragments. */
if (oldskb->nh.iph->frag_off & htons(IP_OFFSET) if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET))
|| oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr)) return NF_DROP;
return;
otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl); if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
otcplen = oldskb->len - oldskb->nh.iph->ihl*4; &tcph, sizeof(tcph)) < 0)
return NF_DROP;
/* No RST for RST. */ /* No RST for RST. */
if (otcph->rst) if (tcph.rst)
return; return NF_DROP;
/* Check checksum. */
if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
oldskb->nh.iph->daddr,
csum_partial((char *)otcph, otcplen, 0)) != 0)
return;
/* FIXME: Check checksum. */
{ {
struct flowi fl = { .nl_u = { .ip4_u = struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = oldskb->nh.iph->saddr, { .daddr = (*pskb)->nh.iph->saddr,
.saddr = (local ? .saddr = (local ?
oldskb->nh.iph->daddr : (*pskb)->nh.iph->daddr :
0), 0),
.tos = RT_TOS(oldskb->nh.iph->tos) } } }; .tos = RT_TOS((*pskb)->nh.iph->tos) } } };
/* Routing: if not headed for us, route won't like source */ /* Routing: if not headed for us, route won't like source */
if (ip_route_output_key(&rt, &fl)) if (ip_route_output_key(&rt, &fl))
return; return NF_DROP;
hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15; hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
} }
/* We're going to flip the header around, drop options and data. */
/* Copy skb (even if skb is about to be dropped, we can't just if (!skb_ip_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(tcph))) {
clone it because there may be other things, such as tcpdump, ip_rt_put(rt);
interested in it). We also need to expand headroom in case return NF_DROP;
hh_len of incoming interface < hh_len of outgoing interface */
nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
GFP_ATOMIC);
if (!nskb) {
dst_release(&rt->u.dst);
return;
} }
dst_release(nskb->dst); (*pskb)->h.th = (void *)(*pskb)->nh.iph + sizeof(tcph);
nskb->dst = &rt->u.dst; datalen = (*pskb)->len - (*pskb)->nh.iph->ihl*4 - tcph.doff*4;
/* Change over route. */
dst_release((*pskb)->dst);
(*pskb)->dst = &rt->u.dst;
/* This packet will not be the same as the other: clear nf fields */ /* This packet will not be the same as the other: clear nf fields */
nf_conntrack_put(nskb->nfct); (*pskb)->nfcache = 0;
nskb->nfct = NULL;
nskb->nfcache = 0;
#ifdef CONFIG_NETFILTER_DEBUG #ifdef CONFIG_NETFILTER_DEBUG
nskb->nf_debug = 0; (*pskb)->nf_debug = 0;
#endif #endif
nskb->nfmark = 0; (*pskb)->nfmark = 0;
tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
/* Swap source and dest */ /* Swap source and dest */
tmp_addr = nskb->nh.iph->saddr; tmp_addr = (*pskb)->nh.iph->saddr;
nskb->nh.iph->saddr = nskb->nh.iph->daddr; (*pskb)->nh.iph->saddr = (*pskb)->nh.iph->daddr;
nskb->nh.iph->daddr = tmp_addr; (*pskb)->nh.iph->daddr = tmp_addr;
tmp_port = tcph->source; tmp_port = (*pskb)->h.th->source;
tcph->source = tcph->dest; (*pskb)->h.th->source = (*pskb)->h.th->dest;
tcph->dest = tmp_port; (*pskb)->h.th->dest = tmp_port;
/* Truncate to length (no data) */ /* Truncate to length (no data) */
tcph->doff = sizeof(struct tcphdr)/4; (*pskb)->h.th->doff = sizeof(struct tcphdr)/4;
skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr)); skb_trim(*pskb, (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr));
nskb->nh.iph->tot_len = htons(nskb->len); (*pskb)->nh.iph->tot_len = htons((*pskb)->len);
if (tcph->ack) { if ((*pskb)->h.th->ack) {
needs_ack = 0; needs_ack = 0;
tcph->seq = otcph->ack_seq; (*pskb)->h.th->seq = tcph.ack_seq;
tcph->ack_seq = 0; (*pskb)->h.th->ack_seq = 0;
} else { } else {
needs_ack = 1; needs_ack = 1;
tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin (*pskb)->h.th->ack_seq = htonl(ntohl(tcph.seq)
+ otcplen - (otcph->doff<<2)); + tcph.syn + tcph.fin
tcph->seq = 0; + datalen);
(*pskb)->h.th->seq = 0;
} }
/* Reset flags */ /* Reset flags */
((u_int8_t *)tcph)[13] = 0; memset((*pskb)->h.raw + 13, 0, 1);
tcph->rst = 1; (*pskb)->h.th->rst = 1;
tcph->ack = needs_ack; (*pskb)->h.th->ack = needs_ack;
tcph->window = 0; (*pskb)->h.th->window = 0;
tcph->urg_ptr = 0; (*pskb)->h.th->urg_ptr = 0;
/* Adjust TCP checksum */ /* Adjust TCP checksum */
tcph->check = 0; (*pskb)->h.th->check = 0;
tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), (*pskb)->h.th->check
nskb->nh.iph->saddr, = tcp_v4_check((*pskb)->h.th,
nskb->nh.iph->daddr, sizeof(struct tcphdr),
csum_partial((char *)tcph, (*pskb)->nh.iph->saddr,
(*pskb)->nh.iph->daddr,
csum_partial((*pskb)->h.raw,
sizeof(struct tcphdr), 0)); sizeof(struct tcphdr), 0));
/* Adjust IP TTL, DF */ /* Adjust IP TTL, DF */
nskb->nh.iph->ttl = MAXTTL; (*pskb)->nh.iph->ttl = MAXTTL;
/* Set DF, id = 0 */ /* Set DF, id = 0 */
nskb->nh.iph->frag_off = htons(IP_DF); (*pskb)->nh.iph->frag_off = htons(IP_DF);
nskb->nh.iph->id = 0; (*pskb)->nh.iph->id = 0;
/* Adjust IP checksum */ /* Adjust IP checksum */
nskb->nh.iph->check = 0; (*pskb)->nh.iph->check = 0;
nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, (*pskb)->nh.iph->check = ip_fast_csum((*pskb)->nh.raw,
nskb->nh.iph->ihl); (*pskb)->nh.iph->ihl);
/* "Never happens" */ /* "Never happens" */
if (nskb->len > dst_pmtu(nskb->dst)) if ((*pskb)->len > dst_pmtu((*pskb)->dst))
goto free_nskb; return NF_DROP;
connection_attach(nskb, oldskb->nfct); /* Related to old connection. */
oldnfct = (*pskb)->nfct;
connection_attach(*pskb, oldnfct);
nf_conntrack_put(oldnfct);
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, *pskb, NULL, (*pskb)->dst->dev,
ip_finish_output); ip_finish_output);
return; return NF_STOLEN;
free_nskb:
kfree_skb(nskb);
} }
static void send_unreach(struct sk_buff *skb_in, int code) static void send_unreach(const struct sk_buff *skb_in, int code)
{ {
struct iphdr *iph;
struct udphdr *udph;
struct icmphdr *icmph;
struct sk_buff *nskb; struct sk_buff *nskb;
u32 saddr; u32 saddr;
u8 tos; u8 tos;
...@@ -189,8 +177,6 @@ static void send_unreach(struct sk_buff *skb_in, int code) ...@@ -189,8 +177,6 @@ static void send_unreach(struct sk_buff *skb_in, int code)
if (!xrlim_allow(&rt->u.dst, 1*HZ)) if (!xrlim_allow(&rt->u.dst, 1*HZ))
return; return;
iph = skb_in->nh.iph;
/* No replies to physical multicast/broadcast */ /* No replies to physical multicast/broadcast */
if (skb_in->pkt_type!=PACKET_HOST) if (skb_in->pkt_type!=PACKET_HOST)
return; return;
...@@ -200,46 +186,41 @@ static void send_unreach(struct sk_buff *skb_in, int code) ...@@ -200,46 +186,41 @@ static void send_unreach(struct sk_buff *skb_in, int code)
return; return;
/* Only reply to fragment 0. */ /* Only reply to fragment 0. */
if (iph->frag_off&htons(IP_OFFSET)) if (skb_in->nh.iph->frag_off&htons(IP_OFFSET))
return; return;
/* if UDP checksum is set, verify it's correct */ /* Ensure we have at least 8 bytes of proto header. */
if (iph->protocol == IPPROTO_UDP if (skb_in->len < skb_in->nh.iph->ihl*4 + 8)
&& skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) {
int datalen = skb_in->len - (iph->ihl<<2);
udph = (struct udphdr *)((char *)iph + (iph->ihl<<2));
if (udph->check
&& csum_tcpudp_magic(iph->saddr, iph->daddr,
datalen, IPPROTO_UDP,
csum_partial((char *)udph, datalen,
0)) != 0)
return; return;
}
/* If we send an ICMP error to an ICMP error a mess would result.. */ /* If we send an ICMP error to an ICMP error a mess would result.. */
if (iph->protocol == IPPROTO_ICMP if (skb_in->nh.iph->protocol == IPPROTO_ICMP) {
&& skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) { struct icmphdr icmph;
icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
if (skb_copy_bits(skb_in, skb_in->nh.iph->ihl*4,
&icmph, sizeof(icmph)) < 0)
return;
/* Between echo-reply (0) and timestamp (13), /* Between echo-reply (0) and timestamp (13),
everything except echo-request (8) is an error. everything except echo-request (8) is an error.
Also, anything greater than NR_ICMP_TYPES is Also, anything greater than NR_ICMP_TYPES is
unknown, and hence should be treated as an error... */ unknown, and hence should be treated as an error... */
if ((icmph->type < ICMP_TIMESTAMP if ((icmph.type < ICMP_TIMESTAMP
&& icmph->type != ICMP_ECHOREPLY && icmph.type != ICMP_ECHOREPLY
&& icmph->type != ICMP_ECHO) && icmph.type != ICMP_ECHO)
|| icmph->type > NR_ICMP_TYPES) || icmph.type > NR_ICMP_TYPES)
return; return;
} }
saddr = iph->daddr; saddr = skb_in->nh.iph->daddr;
if (!(rt->rt_flags & RTCF_LOCAL)) if (!(rt->rt_flags & RTCF_LOCAL))
saddr = 0; saddr = 0;
tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL; tos = (skb_in->nh.iph->tos & IPTOS_TOS_MASK)
| IPTOS_PREC_INTERNETCONTROL;
{ {
struct flowi fl = { .nl_u = { .ip4_u = struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = iph->saddr, { .daddr = skb_in->nh.iph->saddr,
.saddr = saddr, .saddr = saddr,
.tos = RT_TOS(tos) } } }; .tos = RT_TOS(tos) } } };
if (ip_route_output_key(&rt, &fl)) if (ip_route_output_key(&rt, &fl))
...@@ -266,40 +247,38 @@ static void send_unreach(struct sk_buff *skb_in, int code) ...@@ -266,40 +247,38 @@ static void send_unreach(struct sk_buff *skb_in, int code)
skb_reserve(nskb, hh_len); skb_reserve(nskb, hh_len);
/* Set up IP header */ /* Set up IP header */
iph = nskb->nh.iph nskb->nh.iph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
= (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); nskb->nh.iph->version=4;
iph->version=4; nskb->nh.iph->ihl=5;
iph->ihl=5; nskb->nh.iph->tos=tos;
iph->tos=tos; nskb->nh.iph->tot_len = htons(length);
iph->tot_len = htons(length);
/* PMTU discovery never applies to ICMP packets. */ /* PMTU discovery never applies to ICMP packets. */
iph->frag_off = 0; nskb->nh.iph->frag_off = 0;
iph->ttl = MAXTTL; nskb->nh.iph->ttl = MAXTTL;
ip_select_ident(iph, &rt->u.dst, NULL); ip_select_ident(nskb->nh.iph, &rt->u.dst, NULL);
iph->protocol=IPPROTO_ICMP; nskb->nh.iph->protocol=IPPROTO_ICMP;
iph->saddr=rt->rt_src; nskb->nh.iph->saddr=rt->rt_src;
iph->daddr=rt->rt_dst; nskb->nh.iph->daddr=rt->rt_dst;
iph->check=0; nskb->nh.iph->check=0;
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); nskb->nh.iph->check = ip_fast_csum(nskb->nh.raw,
nskb->nh.iph->ihl);
/* Set up ICMP header. */ /* Set up ICMP header. */
icmph = nskb->h.icmph nskb->h.icmph = (struct icmphdr *)skb_put(nskb,sizeof(struct icmphdr));
= (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr)); nskb->h.icmph->type = ICMP_DEST_UNREACH;
icmph->type = ICMP_DEST_UNREACH; nskb->h.icmph->code = code;
icmph->code = code; nskb->h.icmph->un.gateway = 0;
icmph->un.gateway = 0; nskb->h.icmph->checksum = 0;
icmph->checksum = 0;
/* Copy as much of original packet as will fit */ /* Copy as much of original packet as will fit */
data = skb_put(nskb, data = skb_put(nskb,
length - sizeof(struct iphdr) - sizeof(struct icmphdr)); length - sizeof(struct iphdr) - sizeof(struct icmphdr));
/* FIXME: won't work with nonlinear skbs --RR */ skb_copy_bits(skb_in, 0, data,
memcpy(data, skb_in->nh.iph,
length - sizeof(struct iphdr) - sizeof(struct icmphdr)); length - sizeof(struct iphdr) - sizeof(struct icmphdr));
icmph->checksum = ip_compute_csum((unsigned char *)icmph, nskb->h.icmph->checksum = ip_compute_csum(nskb->h.raw,
length - sizeof(struct iphdr)); length-sizeof(struct iphdr));
connection_attach(nskb, skb_in->nfct); connection_attach(nskb, skb_in->nfct);
...@@ -308,9 +287,9 @@ static void send_unreach(struct sk_buff *skb_in, int code) ...@@ -308,9 +287,9 @@ static void send_unreach(struct sk_buff *skb_in, int code)
} }
static unsigned int reject(struct sk_buff **pskb, static unsigned int reject(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
unsigned int hooknum,
const void *targinfo, const void *targinfo,
void *userinfo) void *userinfo)
{ {
...@@ -344,7 +323,7 @@ static unsigned int reject(struct sk_buff **pskb, ...@@ -344,7 +323,7 @@ static unsigned int reject(struct sk_buff **pskb,
send_unreach(*pskb, ICMP_HOST_ANO); send_unreach(*pskb, ICMP_HOST_ANO);
break; break;
case IPT_TCP_RESET: case IPT_TCP_RESET:
send_reset(*pskb, hooknum == NF_IP_LOCAL_IN); return send_reset(pskb, hooknum == NF_IP_LOCAL_IN);
case IPT_ICMP_ECHOREPLY: case IPT_ICMP_ECHOREPLY:
/* Doesn't happen. */ /* Doesn't happen. */
break; break;
......
...@@ -36,9 +36,9 @@ optlen(const u_int8_t *opt, unsigned int offset) ...@@ -36,9 +36,9 @@ optlen(const u_int8_t *opt, unsigned int offset)
static unsigned int static unsigned int
ipt_tcpmss_target(struct sk_buff **pskb, ipt_tcpmss_target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
unsigned int hooknum,
const void *targinfo, const void *targinfo,
void *userinfo) void *userinfo)
{ {
...@@ -49,15 +49,8 @@ ipt_tcpmss_target(struct sk_buff **pskb, ...@@ -49,15 +49,8 @@ ipt_tcpmss_target(struct sk_buff **pskb,
unsigned int i; unsigned int i;
u_int8_t *opt; u_int8_t *opt;
/* raw socket (tcpdump) may have clone of incoming skb: don't if (!skb_ip_make_writable(pskb, (*pskb)->len))
disturb it --RR */
if (skb_cloned(*pskb) && !(*pskb)->sk) {
struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
if (!nskb)
return NF_DROP; return NF_DROP;
kfree_skb(*pskb);
*pskb = nskb;
}
iph = (*pskb)->nh.iph; iph = (*pskb)->nh.iph;
tcplen = (*pskb)->len - iph->ihl*4; tcplen = (*pskb)->len - iph->ihl*4;
......
...@@ -9,35 +9,30 @@ ...@@ -9,35 +9,30 @@
static unsigned int static unsigned int
target(struct sk_buff **pskb, target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
unsigned int hooknum,
const void *targinfo, const void *targinfo,
void *userinfo) void *userinfo)
{ {
struct iphdr *iph = (*pskb)->nh.iph;
const struct ipt_tos_target_info *tosinfo = targinfo; const struct ipt_tos_target_info *tosinfo = targinfo;
if ((iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) { if (((*pskb)->nh.iph->tos & IPTOS_TOS_MASK) != tosinfo->tos) {
u_int16_t diffs[2]; u_int16_t diffs[2];
/* raw socket (tcpdump) may have clone of incoming if (!skb_ip_make_writable(pskb, sizeof(struct iphdr)))
skb: don't disturb it --RR */
if (skb_cloned(*pskb) && !(*pskb)->sk) {
struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
if (!nskb)
return NF_DROP; return NF_DROP;
kfree_skb(*pskb);
*pskb = nskb;
iph = (*pskb)->nh.iph;
}
diffs[0] = htons(iph->tos) ^ 0xFFFF; diffs[0] = htons((*pskb)->nh.iph->tos) ^ 0xFFFF;
iph->tos = (iph->tos & IPTOS_PREC_MASK) | tosinfo->tos; (*pskb)->nh.iph->tos
diffs[1] = htons(iph->tos); = ((*pskb)->nh.iph->tos & IPTOS_PREC_MASK)
iph->check = csum_fold(csum_partial((char *)diffs, | tosinfo->tos;
diffs[1] = htons((*pskb)->nh.iph->tos);
(*pskb)->nh.iph->check
= csum_fold(csum_partial((char *)diffs,
sizeof(diffs), sizeof(diffs),
iph->check^0xFFFF)); (*pskb)->nh.iph->check
^0xFFFF));
(*pskb)->nfcache |= NFC_ALTERED; (*pskb)->nfcache |= NFC_ALTERED;
} }
return IPT_CONTINUE; return IPT_CONTINUE;
......
...@@ -155,9 +155,9 @@ struct sk_buff *ulog_alloc_skb(unsigned int size) ...@@ -155,9 +155,9 @@ struct sk_buff *ulog_alloc_skb(unsigned int size)
} }
static unsigned int ipt_ulog_target(struct sk_buff **pskb, static unsigned int ipt_ulog_target(struct sk_buff **pskb,
unsigned int hooknum,
const struct net_device *in, const struct net_device *in,
const struct net_device *out, const struct net_device *out,
unsigned int hooknum,
const void *targinfo, void *userinfo) const void *targinfo, void *userinfo)
{ {
ulog_buff_t *ub; ulog_buff_t *ub;
...@@ -238,8 +238,9 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb, ...@@ -238,8 +238,9 @@ static unsigned int ipt_ulog_target(struct sk_buff **pskb,
else else
pm->outdev_name[0] = '\0'; pm->outdev_name[0] = '\0';
if (copy_len) /* copy_len <= (*pskb)->len, so can't fail. */
memcpy(pm->payload, (*pskb)->data, copy_len); if (skb_copy_bits(*pskb, 0, pm->payload, copy_len) < 0)
BUG();
/* check if we are building multi-part messages */ /* check if we are building multi-part messages */
if (ub->qlen > 1) { if (ub->qlen > 1) {
......
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