Commit 6679fdf8 authored by David S. Miller's avatar David S. Miller

Merge bk://212.42.230.204/nf-2.6

into nuts.davemloft.net:/disk1/BK/net-2.6
parents 2d43f325 b4726e94
......@@ -925,6 +925,9 @@ extern unsigned long netdev_fc_xoff;
extern atomic_t netdev_dropping;
extern int netdev_set_master(struct net_device *dev, struct net_device *master);
extern int skb_checksum_help(struct sk_buff *skb, int inward);
/* rx skb timestamps */
extern void net_enable_timestamp(void);
extern void net_disable_timestamp(void);
#ifdef CONFIG_SYSCTL
extern char *net_sysctl_strdup(const char *s);
......
......@@ -173,6 +173,7 @@ extern void nf_reinject(struct sk_buff *skb,
unsigned int verdict);
extern void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
extern void nf_ct_attach(struct sk_buff *, struct sk_buff *);
#ifdef CONFIG_NETFILTER_DEBUG
extern void nf_dump_skb(int pf, struct sk_buff *skb);
......@@ -183,6 +184,7 @@ extern void nf_invalidate_cache(int pf);
#else /* !CONFIG_NETFILTER */
#define NF_HOOK(pf, hook, skb, indev, outdev, okfn) (okfn)(skb)
static inline void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb) {}
#endif /*CONFIG_NETFILTER*/
#endif /*__KERNEL__*/
......
......@@ -18,7 +18,7 @@ struct ip_nat_protocol
/* Do a packet translation according to the ip_nat_proto_manip
* and manip type. Return true if succeeded. */
int (*manip_pkt)(struct sk_buff **pskb,
unsigned int hdroff,
unsigned int iphdroff,
const struct ip_conntrack_manip *manip,
enum ip_nat_manip_type maniptype);
......
......@@ -1270,19 +1270,7 @@ static inline void sk_eat_skb(struct sock *sk, struct sk_buff *skb)
__kfree_skb(skb);
}
extern atomic_t netstamp_needed;
extern void sock_enable_timestamp(struct sock *sk);
static inline void net_timestamp(struct timeval *stamp)
{
if (atomic_read(&netstamp_needed))
do_gettimeofday(stamp);
else {
stamp->tv_sec = 0;
stamp->tv_usec = 0;
}
}
extern int sock_get_timestamp(struct sock *, struct timeval __user *);
/*
......
......@@ -1001,6 +1001,29 @@ int call_netdevice_notifiers(unsigned long val, void *v)
return notifier_call_chain(&netdev_chain, val, v);
}
/* When > 0 there are consumers of rx skb time stamps */
static atomic_t netstamp_needed = ATOMIC_INIT(0);
void net_enable_timestamp(void)
{
atomic_inc(&netstamp_needed);
}
void net_disable_timestamp(void)
{
atomic_dec(&netstamp_needed);
}
static inline void net_timestamp(struct timeval *stamp)
{
if (atomic_read(&netstamp_needed))
do_gettimeofday(stamp);
else {
stamp->tv_sec = 0;
stamp->tv_usec = 0;
}
}
/*
* Support routine. Sends outgoing frames to any network
* taps currently in use.
......@@ -3215,6 +3238,8 @@ EXPORT_SYMBOL(skb_checksum_help);
EXPORT_SYMBOL(synchronize_net);
EXPORT_SYMBOL(unregister_netdevice);
EXPORT_SYMBOL(unregister_netdevice_notifier);
EXPORT_SYMBOL(net_enable_timestamp);
EXPORT_SYMBOL(net_disable_timestamp);
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
EXPORT_SYMBOL(br_handle_frame_hook);
......
......@@ -802,12 +802,21 @@ EXPORT_SYMBOL(nf_log_register);
EXPORT_SYMBOL(nf_log_unregister);
EXPORT_SYMBOL(nf_log_packet);
/* This does not belong here, but ipt_REJECT needs it if connection
tracking in use: without this, connection may not be in hash table,
and hence manufactured ICMP or RST packets will not be associated
with it. */
/* This does not belong here, but locally generated errors need it if connection
tracking in use: without this, connection may not be in hash table, and hence
manufactured ICMP or RST packets will not be associated with it. */
void (*ip_ct_attach)(struct sk_buff *, struct sk_buff *);
void nf_ct_attach(struct sk_buff *new, struct sk_buff *skb)
{
void (*attach)(struct sk_buff *, struct sk_buff *);
if (skb->nfct && (attach = ip_ct_attach) != NULL) {
mb(); /* Just to be sure: must be read before executing this */
attach(new, skb);
}
}
void __init netfilter_init(void)
{
int i, h;
......@@ -819,6 +828,7 @@ void __init netfilter_init(void)
}
EXPORT_SYMBOL(ip_ct_attach);
EXPORT_SYMBOL(nf_ct_attach);
EXPORT_SYMBOL(nf_getsockopt);
EXPORT_SYMBOL(nf_hook_slow);
EXPORT_SYMBOL(nf_hooks);
......
......@@ -179,7 +179,7 @@ static void sock_disable_timestamp(struct sock *sk)
{
if (sock_flag(sk, SOCK_TIMESTAMP)) {
sock_reset_flag(sk, SOCK_TIMESTAMP);
atomic_dec(&netstamp_needed);
net_disable_timestamp();
}
}
......@@ -1226,9 +1226,6 @@ void fastcall release_sock(struct sock *sk)
}
EXPORT_SYMBOL(release_sock);
/* When > 0 there are consumers of rx skb time stamps */
atomic_t netstamp_needed = ATOMIC_INIT(0);
int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
{
if (!sock_flag(sk, SOCK_TIMESTAMP))
......@@ -1246,7 +1243,7 @@ void sock_enable_timestamp(struct sock *sk)
{
if (!sock_flag(sk, SOCK_TIMESTAMP)) {
sock_set_flag(sk, SOCK_TIMESTAMP);
atomic_inc(&netstamp_needed);
net_enable_timestamp();
}
}
EXPORT_SYMBOL(sock_enable_timestamp);
......
......@@ -338,6 +338,8 @@ int icmp_glue_bits(void *from, char *to, int offset, int len, int odd,
to, len, 0);
skb->csum = csum_block_add(skb->csum, csum, odd);
if (icmp_pointers[icmp_param->data.icmph.type].error)
nf_ct_attach(skb, icmp_param->skb);
return 0;
}
......
......@@ -684,7 +684,7 @@ manip_pkt(u_int16_t proto,
iph = (void *)(*pskb)->data + iphdroff;
/* Manipulate protcol part. */
if (!ip_nat_find_proto(proto)->manip_pkt(pskb, iphdroff + iph->ihl*4,
if (!ip_nat_find_proto(proto)->manip_pkt(pskb, iphdroff,
manip, maniptype))
return 0;
......
......@@ -53,11 +53,13 @@ icmp_unique_tuple(struct ip_conntrack_tuple *tuple,
static int
icmp_manip_pkt(struct sk_buff **pskb,
unsigned int hdroff,
unsigned int iphdroff,
const struct ip_conntrack_manip *manip,
enum ip_nat_manip_type maniptype)
{
struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
struct icmphdr *hdr;
unsigned int hdroff = iphdroff + iph->ihl*4;
if (!skb_ip_make_writable(pskb, hdroff + sizeof(*hdr)))
return 0;
......
......@@ -84,11 +84,13 @@ tcp_unique_tuple(struct ip_conntrack_tuple *tuple,
static int
tcp_manip_pkt(struct sk_buff **pskb,
unsigned int hdroff,
unsigned int iphdroff,
const struct ip_conntrack_manip *manip,
enum ip_nat_manip_type maniptype)
{
struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
struct tcphdr *hdr;
unsigned int hdroff = iphdroff + iph->ihl*4;
u_int32_t oldip;
u_int16_t *portptr, oldport;
int hdrsize = 8; /* TCP connection tracking guarantees this much */
......@@ -106,11 +108,11 @@ tcp_manip_pkt(struct sk_buff **pskb,
if (maniptype == IP_NAT_MANIP_SRC) {
/* Get rid of src ip and src pt */
oldip = (*pskb)->nh.iph->saddr;
oldip = iph->saddr;
portptr = &hdr->source;
} else {
/* Get rid of dst ip and dst pt */
oldip = (*pskb)->nh.iph->daddr;
oldip = iph->daddr;
portptr = &hdr->dest;
}
......
......@@ -83,11 +83,13 @@ udp_unique_tuple(struct ip_conntrack_tuple *tuple,
static int
udp_manip_pkt(struct sk_buff **pskb,
unsigned int hdroff,
unsigned int iphdroff,
const struct ip_conntrack_manip *manip,
enum ip_nat_manip_type maniptype)
{
struct iphdr *iph = (struct iphdr *)((*pskb)->data + iphdroff);
struct udphdr *hdr;
unsigned int hdroff = iphdroff + iph->ihl*4;
u_int32_t oldip;
u_int16_t *portptr;
......@@ -97,11 +99,11 @@ udp_manip_pkt(struct sk_buff **pskb,
hdr = (void *)(*pskb)->data + hdroff;
if (maniptype == IP_NAT_MANIP_SRC) {
/* Get rid of src ip and src pt */
oldip = (*pskb)->nh.iph->saddr;
oldip = iph->saddr;
portptr = &hdr->source;
} else {
/* Get rid of dst ip and dst pt */
oldip = (*pskb)->nh.iph->daddr;
oldip = iph->daddr;
portptr = &hdr->dest;
}
if (hdr->check) /* 0 is a special case meaning no checksum */
......
......@@ -39,7 +39,7 @@ static int unknown_unique_tuple(struct ip_conntrack_tuple *tuple,
static int
unknown_manip_pkt(struct sk_buff **pskb,
unsigned int hdroff,
unsigned int iphdroff,
const struct ip_conntrack_manip *manip,
enum ip_nat_manip_type maniptype)
{
......
......@@ -162,6 +162,7 @@ static inline void
__ipq_reset(void)
{
peer_pid = 0;
net_disable_timestamp();
__ipq_set_mode(IPQ_COPY_NONE, 0);
__ipq_flush(NF_DROP);
}
......@@ -257,7 +258,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
}
if (data_len)
memcpy(pmsg->payload, entry->skb->data, data_len);
if (skb_copy_bits(entry->skb, 0, pmsg->payload, data_len))
BUG();
nlh->nlmsg_len = skb->tail - old_tail;
return skb;
......@@ -362,6 +364,8 @@ ipq_mangle_ipv4(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
}
skb_put(e->skb, diff);
}
if (!skb_ip_make_writable(&e->skb, v->data_len))
return -ENOMEM;
memcpy(e->skb->data, v->payload, v->data_len);
e->skb->nfcache |= NFC_ALTERED;
......@@ -514,9 +518,10 @@ ipq_rcv_skb(struct sk_buff *skb)
write_unlock_bh(&queue_lock);
RCV_SKB_FAIL(-EBUSY);
}
}
else
} else {
net_enable_timestamp();
peer_pid = pid;
}
write_unlock_bh(&queue_lock);
......
......@@ -118,49 +118,57 @@ masquerade_target(struct sk_buff **pskb,
}
static inline int
device_cmp(const struct ip_conntrack *i, void *_ina)
device_cmp(const struct ip_conntrack *i, void *ifindex)
{
int ret = 0;
struct in_ifaddr *ina = _ina;
int ret;
READ_LOCK(&masq_lock);
/* If it's masquerading out this interface with a different address,
or we don't know the new address of this interface. */
if (i->nat.masq_index == ina->ifa_dev->dev->ifindex
&& i->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip != ina->ifa_address)
ret = 1;
ret = (i->nat.masq_index == (int)(long)ifindex);
READ_UNLOCK(&masq_lock);
return ret;
}
static inline int
connect_unassure(const struct ip_conntrack *i, void *_ina)
static int masq_device_event(struct notifier_block *this,
unsigned long event,
void *ptr)
{
struct in_ifaddr *ina = _ina;
struct net_device *dev = ptr;
if (event == NETDEV_DOWN) {
/* Device was downed. Search entire table for
conntracks which were associated with that device,
and forget them. */
IP_NF_ASSERT(dev->ifindex != 0);
/* We reset the ASSURED bit on all connections, so they will
* get reaped under memory pressure. */
if (i->nat.masq_index == ina->ifa_dev->dev->ifindex)
clear_bit(IPS_ASSURED_BIT, (unsigned long *)&i->status);
return 0;
ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex);
}
return NOTIFY_DONE;
}
static int masq_inet_event(struct notifier_block *this,
unsigned long event,
void *ptr)
{
/* For some configurations, interfaces often come back with
* the same address. If not, clean up old conntrack
* entries. */
if (event == NETDEV_UP)
ip_ct_selective_cleanup(device_cmp, ptr);
else if (event == NETDEV_DOWN)
ip_ct_selective_cleanup(connect_unassure, ptr);
struct net_device *dev = ((struct in_ifaddr *)ptr)->ifa_dev->dev;
if (event == NETDEV_DOWN) {
/* IP address was deleted. Search entire table for
conntracks which were associated with that device,
and forget them. */
IP_NF_ASSERT(dev->ifindex != 0);
ip_ct_selective_cleanup(device_cmp, (void *)(long)dev->ifindex);
}
return NOTIFY_DONE;
}
static struct notifier_block masq_dev_notifier = {
.notifier_call = masq_device_event,
};
static struct notifier_block masq_inet_notifier = {
.notifier_call = masq_inet_event,
};
......@@ -178,9 +186,12 @@ static int __init init(void)
ret = ipt_register_target(&masquerade);
if (ret == 0)
if (ret == 0) {
/* Register for device down reports */
register_netdevice_notifier(&masq_dev_notifier);
/* Register IP address change reports */
register_inetaddr_notifier(&masq_inet_notifier);
}
return ret;
}
......@@ -188,6 +199,7 @@ static int __init init(void)
static void __exit fini(void)
{
ipt_unregister_target(&masquerade);
unregister_netdevice_notifier(&masq_dev_notifier);
unregister_inetaddr_notifier(&masq_inet_notifier);
}
......
......@@ -38,20 +38,6 @@ MODULE_DESCRIPTION("iptables REJECT target module");
#define DEBUGP(format, args...)
#endif
/* If the original packet is part of a connection, but the connection
is not confirmed, our manufactured reply will not be associated
with it, so we need to do this manually. */
static void connection_attach(struct sk_buff *new_skb, struct sk_buff *skb)
{
void (*attach)(struct sk_buff *, struct sk_buff *);
/* Avoid module unload race with ip_ct_attach being NULLed out */
if (skb->nfct && (attach = ip_ct_attach) != NULL) {
mb(); /* Just to be sure: must be read before executing this */
attach(new_skb, skb);
}
}
static inline struct rtable *route_reverse(struct sk_buff *skb, int hook)
{
struct iphdr *iph = skb->nh.iph;
......@@ -209,7 +195,7 @@ static void send_reset(struct sk_buff *oldskb, int hook)
if (nskb->len > dst_pmtu(nskb->dst))
goto free_nskb;
connection_attach(nskb, oldskb);
nf_ct_attach(nskb, oldskb);
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
ip_finish_output);
......@@ -360,7 +346,7 @@ static void send_unreach(struct sk_buff *skb_in, int code)
icmph->checksum = ip_compute_csum((unsigned char *)icmph,
length - sizeof(struct iphdr));
connection_attach(nskb, skb_in);
nf_ct_attach(nskb, skb_in);
NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
ip_finish_output);
......
......@@ -167,6 +167,7 @@ static inline void
__ipq_reset(void)
{
peer_pid = 0;
net_disable_timestamp();
__ipq_set_mode(IPQ_COPY_NONE, 0);
__ipq_flush(NF_DROP);
}
......@@ -262,7 +263,8 @@ ipq_build_packet_message(struct ipq_queue_entry *entry, int *errp)
}
if (data_len)
memcpy(pmsg->payload, entry->skb->data, data_len);
if (skb_copy_bits(entry->skb, 0, pmsg->payload, data_len))
BUG();
nlh->nlmsg_len = skb->tail - old_tail;
return skb;
......@@ -366,6 +368,8 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
}
skb_put(e->skb, diff);
}
if (!skb_ip_make_writable(&e->skb, v->data_len))
return -ENOMEM;
memcpy(e->skb->data, v->payload, v->data_len);
e->skb->nfcache |= NFC_ALTERED;
......@@ -517,9 +521,10 @@ ipq_rcv_skb(struct sk_buff *skb)
write_unlock_bh(&queue_lock);
RCV_SKB_FAIL(-EBUSY);
}
}
else
} else {
net_enable_timestamp();
peer_pid = pid;
}
write_unlock_bh(&queue_lock);
......
......@@ -69,7 +69,7 @@ ip6t_eui64_checkentry(const char *tablename,
{
if (hook_mask
& ~((1 << NF_IP6_PRE_ROUTING) | (1 << NF_IP6_LOCAL_IN) |
(1 << NF_IP6_PRE_ROUTING) )) {
(1 << NF_IP6_FORWARD))) {
printk("ip6t_eui64: only valid for PRE_ROUTING, LOCAL_IN or FORWARD.\n");
return 0;
}
......
......@@ -51,7 +51,7 @@ ipv6header_match(const struct sk_buff *skb,
temp = 0;
while (ip6t_ext_hdr(nexthdr)) {
struct ipv6_opt_hdr *hdr;
struct ipv6_opt_hdr _hdr, *hp;
int hdrlen;
/* Is there enough space for the next ext header? */
......@@ -68,15 +68,16 @@ ipv6header_match(const struct sk_buff *skb,
break;
}
hdr=(struct ipv6_opt_hdr *)skb->data+ptr;
hp = skb_header_pointer(skb, ptr, sizeof(_hdr), &_hdr);
BUG_ON(hp == NULL);
/* Calculate the header length */
if (nexthdr == NEXTHDR_FRAGMENT) {
hdrlen = 8;
} else if (nexthdr == NEXTHDR_AUTH)
hdrlen = (hdr->hdrlen+2)<<2;
hdrlen = (hp->hdrlen+2)<<2;
else
hdrlen = ipv6_optlen(hdr);
hdrlen = ipv6_optlen(hp);
/* set the flag */
switch (nexthdr){
......@@ -100,7 +101,7 @@ ipv6header_match(const struct sk_buff *skb,
break;
}
nexthdr = hdr->nexthdr;
nexthdr = hp->nexthdr;
len -= hdrlen;
ptr += hdrlen;
if (ptr > skb->len)
......@@ -111,10 +112,14 @@ ipv6header_match(const struct sk_buff *skb,
temp |= MASK_PROTO;
if (info->modeflag)
return (!( (temp & info->matchflags)
^ info->matchflags) ^ info->invflags);
else
return (!( temp ^ info->matchflags) ^ info->invflags);
return !((temp ^ info->matchflags ^ info->invflags)
& info->matchflags);
else {
if (info->invflags)
return temp != info->matchflags;
else
return temp == info->matchflags;
}
}
static int
......@@ -124,11 +129,18 @@ ipv6header_checkentry(const char *tablename,
unsigned int matchsize,
unsigned int hook_mask)
{
const struct ip6t_ipv6header_info *info = matchinfo;
/* Check for obvious errors */
/* This match is valid in all hooks! */
if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)))
return 0;
/* invflags is 0 or 0xff in hard mode */
if ((!info->modeflag) && info->invflags != 0x00
&& info->invflags != 0xFF)
return 0;
return 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