Signed-off-by: Hannes Frederic Sowa <han...@stressinduktion.org>
---
 include/net/inet_common.h |  1 +
 net/ipv4/af_inet.c        | 51 ++++++++++++++++++++++++++++++-----------------
 2 files changed, 34 insertions(+), 18 deletions(-)

diff --git a/include/net/inet_common.h b/include/net/inet_common.h
index b7952d55b9c000..4ac8229dca6af4 100644
--- a/include/net/inet_common.h
+++ b/include/net/inet_common.h
@@ -30,6 +30,7 @@ int inet_shutdown(struct socket *sock, int how);
 int inet_listen(struct socket *sock, int backlog);
 void inet_sock_destruct(struct sock *sk);
 int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len);
+int inet_allow_bind(struct sock *sk, __be32 addr);
 int inet_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len,
                 int peer);
 int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg);
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 602d40f43687c9..aee599e23137e7 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -428,6 +428,35 @@ int inet_release(struct socket *sock)
 }
 EXPORT_SYMBOL(inet_release);
 
+int inet_allow_bind(struct sock *sk, __be32 addr)
+{
+       struct inet_sock *inet = inet_sk(sk);
+       struct net *net = sock_net(sk);
+       u32 tb_id = RT_TABLE_LOCAL;
+       int chk_addr_ret;
+
+       tb_id = l3mdev_fib_table_by_index(net, sk->sk_bound_dev_if) ? : tb_id;
+       chk_addr_ret = inet_addr_type_table(net, addr, tb_id);
+
+       /* Not specified by any standard per-se, however it breaks too
+        * many applications when removed.  It is unfortunate since
+        * allowing applications to make a non-local bind solves
+        * several problems with systems using dynamic addressing.
+        * (ie. your servers still start up even if your ISDN link
+        *  is temporarily down)
+        */
+       if (!net->ipv4.sysctl_ip_nonlocal_bind &&
+           !(inet->freebind || inet->transparent) &&
+           addr != htonl(INADDR_ANY) &&
+           chk_addr_ret != RTN_LOCAL &&
+           chk_addr_ret != RTN_MULTICAST &&
+           chk_addr_ret != RTN_BROADCAST)
+               return -EADDRNOTAVAIL;
+
+       return chk_addr_ret;
+}
+EXPORT_SYMBOL(inet_allow_bind);
+
 int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
 {
        struct sockaddr_in *addr = (struct sockaddr_in *)uaddr;
@@ -436,7 +465,6 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, 
int addr_len)
        struct net *net = sock_net(sk);
        unsigned short snum;
        int chk_addr_ret;
-       u32 tb_id = RT_TABLE_LOCAL;
        int err;
 
        /* If the socket has its own bind function then use it. (RAW) */
@@ -458,24 +486,11 @@ int inet_bind(struct socket *sock, struct sockaddr 
*uaddr, int addr_len)
                        goto out;
        }
 
-       tb_id = l3mdev_fib_table_by_index(net, sk->sk_bound_dev_if) ? : tb_id;
-       chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id);
-
-       /* Not specified by any standard per-se, however it breaks too
-        * many applications when removed.  It is unfortunate since
-        * allowing applications to make a non-local bind solves
-        * several problems with systems using dynamic addressing.
-        * (ie. your servers still start up even if your ISDN link
-        *  is temporarily down)
-        */
-       err = -EADDRNOTAVAIL;
-       if (!net->ipv4.sysctl_ip_nonlocal_bind &&
-           !(inet->freebind || inet->transparent) &&
-           addr->sin_addr.s_addr != htonl(INADDR_ANY) &&
-           chk_addr_ret != RTN_LOCAL &&
-           chk_addr_ret != RTN_MULTICAST &&
-           chk_addr_ret != RTN_BROADCAST)
+       chk_addr_ret = inet_allow_bind(sk, addr->sin_addr.s_addr);
+       if (chk_addr_ret < 0) {
+               err = chk_addr_ret;
                goto out;
+       }
 
        snum = ntohs(addr->sin_port);
        err = -EACCES;
-- 
2.9.3

Reply via email to