mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-22 23:12:32 +00:00
133 lines
3.9 KiB
Diff
133 lines
3.9 KiB
Diff
|
From 2df5996350da51bcdee798c00ae1f2415fd9ad20 Mon Sep 17 00:00:00 2001
|
||
|
From: Robert Love <rlove@google.com>
|
||
|
Date: Mon, 12 May 2008 17:08:29 -0400
|
||
|
Subject: [PATCH 081/134] net: socket ioctl to reset connections matching local address
|
||
|
|
||
|
Introduce a new socket ioctl, SIOCKILLADDR, that nukes all sockets
|
||
|
bound to the same local address. This is useful in situations with
|
||
|
dynamic IPs, to kill stuck connections.
|
||
|
|
||
|
Signed-off-by: Brian Swetland <swetland@google.com>
|
||
|
|
||
|
net: fix tcp_v4_nuke_addr
|
||
|
|
||
|
Signed-off-by: Dima Zavin <dima@android.com>
|
||
|
---
|
||
|
include/linux/sockios.h | 1 +
|
||
|
include/net/tcp.h | 2 ++
|
||
|
net/ipv4/af_inet.c | 1 +
|
||
|
net/ipv4/devinet.c | 9 ++++++++-
|
||
|
net/ipv4/tcp_ipv4.c | 31 +++++++++++++++++++++++++++++++
|
||
|
5 files changed, 43 insertions(+), 1 deletions(-)
|
||
|
|
||
|
--- a/include/linux/sockios.h
|
||
|
+++ b/include/linux/sockios.h
|
||
|
@@ -65,6 +65,7 @@
|
||
|
#define SIOCDIFADDR 0x8936 /* delete PA address */
|
||
|
#define SIOCSIFHWBROADCAST 0x8937 /* set hardware broadcast addr */
|
||
|
#define SIOCGIFCOUNT 0x8938 /* get number of devices */
|
||
|
+#define SIOCKILLADDR 0x8939 /* kill sockets with this local addr */
|
||
|
|
||
|
#define SIOCGIFBR 0x8940 /* Bridging support */
|
||
|
#define SIOCSIFBR 0x8941 /* Set bridging options */
|
||
|
--- a/include/net/tcp.h
|
||
|
+++ b/include/net/tcp.h
|
||
|
@@ -1381,6 +1381,8 @@ extern struct sk_buff **tcp4_gro_receive
|
||
|
extern int tcp_gro_complete(struct sk_buff *skb);
|
||
|
extern int tcp4_gro_complete(struct sk_buff *skb);
|
||
|
|
||
|
+extern void tcp_v4_nuke_addr(__u32 saddr);
|
||
|
+
|
||
|
#ifdef CONFIG_PROC_FS
|
||
|
extern int tcp4_proc_init(void);
|
||
|
extern void tcp4_proc_exit(void);
|
||
|
--- a/net/ipv4/af_inet.c
|
||
|
+++ b/net/ipv4/af_inet.c
|
||
|
@@ -825,6 +825,7 @@ int inet_ioctl(struct socket *sock, unsi
|
||
|
case SIOCSIFPFLAGS:
|
||
|
case SIOCGIFPFLAGS:
|
||
|
case SIOCSIFFLAGS:
|
||
|
+ case SIOCKILLADDR:
|
||
|
err = devinet_ioctl(net, cmd, (void __user *)arg);
|
||
|
break;
|
||
|
default:
|
||
|
--- a/net/ipv4/devinet.c
|
||
|
+++ b/net/ipv4/devinet.c
|
||
|
@@ -57,6 +57,7 @@
|
||
|
|
||
|
#include <net/arp.h>
|
||
|
#include <net/ip.h>
|
||
|
+#include <net/tcp.h>
|
||
|
#include <net/route.h>
|
||
|
#include <net/ip_fib.h>
|
||
|
#include <net/rtnetlink.h>
|
||
|
@@ -631,6 +632,7 @@ int devinet_ioctl(struct net *net, unsig
|
||
|
case SIOCSIFBRDADDR: /* Set the broadcast address */
|
||
|
case SIOCSIFDSTADDR: /* Set the destination address */
|
||
|
case SIOCSIFNETMASK: /* Set the netmask for the interface */
|
||
|
+ case SIOCKILLADDR: /* Nuke all sockets on this address */
|
||
|
ret = -EACCES;
|
||
|
if (!capable(CAP_NET_ADMIN))
|
||
|
goto out;
|
||
|
@@ -680,7 +682,8 @@ int devinet_ioctl(struct net *net, unsig
|
||
|
}
|
||
|
|
||
|
ret = -EADDRNOTAVAIL;
|
||
|
- if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS)
|
||
|
+ if (!ifa && cmd != SIOCSIFADDR && cmd != SIOCSIFFLAGS
|
||
|
+ && cmd != SIOCKILLADDR)
|
||
|
goto done;
|
||
|
|
||
|
switch (cmd) {
|
||
|
@@ -804,6 +807,10 @@ int devinet_ioctl(struct net *net, unsig
|
||
|
inet_insert_ifa(ifa);
|
||
|
}
|
||
|
break;
|
||
|
+ case SIOCKILLADDR: /* Nuke all connections on this address */
|
||
|
+ ret = 0;
|
||
|
+ tcp_v4_nuke_addr(sin->sin_addr.s_addr);
|
||
|
+ break;
|
||
|
}
|
||
|
done:
|
||
|
rtnl_unlock();
|
||
|
--- a/net/ipv4/tcp_ipv4.c
|
||
|
+++ b/net/ipv4/tcp_ipv4.c
|
||
|
@@ -1845,6 +1845,37 @@ void tcp_v4_destroy_sock(struct sock *sk
|
||
|
|
||
|
EXPORT_SYMBOL(tcp_v4_destroy_sock);
|
||
|
|
||
|
+/*
|
||
|
+ * tcp_v4_nuke_addr - destroy all sockets on the given local address
|
||
|
+ */
|
||
|
+void tcp_v4_nuke_addr(__u32 saddr)
|
||
|
+{
|
||
|
+ unsigned int bucket;
|
||
|
+
|
||
|
+ for (bucket = 0; bucket < tcp_hashinfo.ehash_size; bucket++) {
|
||
|
+ struct hlist_nulls_node *node;
|
||
|
+ struct sock *sk;
|
||
|
+ spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, bucket);
|
||
|
+
|
||
|
+ spin_lock_bh(lock);
|
||
|
+ sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[bucket].chain) {
|
||
|
+ struct inet_sock *inet = inet_sk(sk);
|
||
|
+
|
||
|
+ if (inet->rcv_saddr != saddr)
|
||
|
+ continue;
|
||
|
+ if (sysctl_ip_dynaddr && sk->sk_state == TCP_SYN_SENT)
|
||
|
+ continue;
|
||
|
+ if (sock_flag(sk, SOCK_DEAD))
|
||
|
+ continue;
|
||
|
+
|
||
|
+ sk->sk_err = ETIMEDOUT;
|
||
|
+ sk->sk_error_report(sk);
|
||
|
+ tcp_done(sk);
|
||
|
+ }
|
||
|
+ spin_unlock_bh(lock);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
#ifdef CONFIG_PROC_FS
|
||
|
/* Proc filesystem TCP sock list dumping. */
|
||
|
|