All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ben Greear <greearb-my8/4N5VtI7c+919tysfdA@public.gmane.org>
To: Steve French <smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: Jeff Layton <jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>,
	linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
Subject: Re: [cifs bindaddr v3] cifs: Allow binding to local IP address.
Date: Mon, 30 Aug 2010 11:19:40 -0700	[thread overview]
Message-ID: <4C7BF63C.2060503@candelatech.com> (raw)
In-Reply-To: <AANLkTikDjbWv0F18WevNbsfJyutEu28RCCgtmp1=ZBd4-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 328 bytes --]

Updated patch is attached.  It *should* support IPv4 & IPv6, but I've only
tested IPv4 to date.  I need to work on my test rig before I can
test v6, hopefully will get that done in a day or two.

Thanks,
Ben

-- 
Ben Greear <greearb-my8/4N5VtI7c+919tysfdA@public.gmane.org>
Candela Technologies Inc  http://www.candelatech.com


[-- Attachment #2: cifs_bind_v4_v6.patch --]
[-- Type: text/plain, Size: 7780 bytes --]

diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index b7431af..fb4ecbe 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -357,6 +357,24 @@ cifs_show_address(struct seq_file *s, struct TCP_Server_Info *server)
 	}
 }
 
+bool
+cifs_addr_is_specified(struct sockaddr* srcaddr) {
+	struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
+	struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
+	switch (srcaddr->sa_family) {
+	case AF_INET:
+		return saddr4->sin_addr.s_addr != 0;
+		
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	case AF_INET6:
+		/* in6addr_any isn't available if IPv6 isn't compiled in */
+		return (memcmp(&in6addr_any, &saddr6->sin6_addr,
+			       sizeof(in6addr_any)) == 0);
+#endif
+	}
+	return false;
+}
+
 /*
  * cifs_show_options() is for displaying mount options in /proc/mounts.
  * Not all settable options are displayed but most of the important
@@ -374,6 +392,19 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m)
 	if (tcon->ses->domainName)
 		seq_printf(s, ",domain=%s", tcon->ses->domainName);
 
+	if (cifs_addr_is_specified((struct sockaddr*)(&tcon->ses->server->srcaddr))) {
+		struct sockaddr_in *saddr4;
+		struct sockaddr_in6 *saddr6;
+		saddr4 = (struct sockaddr_in *)&tcon->ses->server->srcaddr;
+		saddr6 = (struct sockaddr_in6 *)&tcon->ses->server->srcaddr;
+		if (saddr6->sin6_family == AF_INET6)
+			seq_printf(s, ",srcaddr=%pI6",
+			   &saddr6->sin6_addr);
+		else
+			seq_printf(s, ",srcaddr=%pI4",
+			   &saddr4->sin_addr.s_addr);	
+	}
+
 	seq_printf(s, ",uid=%d", cifs_sb->mnt_uid);
 	if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID)
 		seq_printf(s, ",forceuid");
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index d82f5fb..0f0d786 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -110,6 +110,9 @@ extern ssize_t	cifs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t	cifs_listxattr(struct dentry *, char *, size_t);
 extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 
+struct sockaddr;
+extern bool cifs_addr_is_specified(struct sockaddr* srcaddr);
+
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 extern const struct export_operations cifs_export_ops;
 #endif /* EXPERIMENTAL */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index c9d0cfc..784fd4a 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -157,6 +157,7 @@ struct TCP_Server_Info {
 		struct sockaddr_in sockAddr;
 		struct sockaddr_in6 sockAddr6;
 	} addr;
+	struct sockaddr_storage srcaddr; /* locally bind to this IP */
 	wait_queue_head_t response_q;
 	wait_queue_head_t request_q; /* if more than maxmpx to srvr must block*/
 	struct list_head pending_mid_q;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index ec0ea4a..f88af63 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -49,6 +49,7 @@
 #include "rfc1002pdu.h"
 #include "cn_cifs.h"
 #include "fscache.h"
+#include "cifsfs.h"
 
 #define CIFS_PORT 445
 #define RFC1001_PORT 139
@@ -105,6 +106,7 @@ struct smb_vol {
 	bool sockopt_tcp_nodelay:1;
 	unsigned short int port;
 	char *prepath;
+	struct sockaddr_storage srcaddr; /* allow binding to a local IP address */
 	struct nls_table *local_nls;
 };
 
@@ -1064,6 +1066,22 @@ cifs_parse_mount_options(char *options, const char *devname,
 						    "long\n");
 				return 1;
 			}
+		} else if (strnicmp(data, "srcaddr", 8) == 0) {
+			memset(&vol->srcaddr, 0, sizeof(vol->srcaddr));
+
+			if (!value || !*value) {
+				printk(KERN_WARNING "CIFS: srcaddr value"
+				       " not specified.\n");
+				return 1;	/* needs_arg; */
+			}
+			i = cifs_convert_address((struct sockaddr *)(&vol->srcaddr),
+						 value, strlen(value));
+			if (i < 0) {
+				printk(KERN_WARNING "CIFS:  Could not parse"
+				       " srcaddr: %s\n",
+				       value);
+				return 1;
+			}
 		} else if (strnicmp(data, "prefixpath", 10) == 0) {
 			if (!value || !*value) {
 				printk(KERN_WARNING
@@ -1392,8 +1410,37 @@ cifs_parse_mount_options(char *options, const char *devname,
 	return 0;
 }
 
+/** Returns true if srcaddr isn't specified or if it matches
+ * the IP address of the rhs argument.
+ */
 static bool
-match_address(struct TCP_Server_Info *server, struct sockaddr *addr)
+srcip_matches(struct sockaddr* srcaddr, struct sockaddr* rhs)
+{
+	if (cifs_addr_is_specified(srcaddr)) {
+		struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
+		struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
+		struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
+		struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)&rhs;
+
+		switch (srcaddr->sa_family) {
+		case AF_INET:
+			if (saddr4->sin_addr.s_addr != vaddr4->sin_addr.s_addr)
+				return false;
+			break;
+		case AF_INET6:
+			if (memcmp(&saddr6->sin6_addr, &vaddr6->sin6_addr,
+				   sizeof(saddr6->sin6_addr)) != 0)
+				return false;
+			break;
+		}
+	}
+	return true;
+}
+
+
+static bool
+match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
+	      struct sockaddr* srcaddr)
 {
 	struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
 	struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
@@ -1420,6 +1467,9 @@ match_address(struct TCP_Server_Info *server, struct sockaddr *addr)
 		break;
 	}
 
+	if (!srcip_matches(srcaddr, (struct sockaddr*)&server->srcaddr))
+		return false;
+	
 	return true;
 }
 
@@ -1487,7 +1537,7 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
 		if (server->tcpStatus == CifsNew)
 			continue;
 
-		if (!match_address(server, addr))
+		if (!match_address(server, addr, (struct sockaddr*)&vol->srcaddr))
 			continue;
 
 		if (!match_security(server, vol))
@@ -1602,6 +1652,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
 	 * no need to spinlock this init of tcpStatus or srv_count
 	 */
 	tcp_ses->tcpStatus = CifsNew;
+	memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, sizeof(tcp_ses->srcaddr));
 	++tcp_ses->srv_count;
 
 	if (addr.ss_family == AF_INET6) {
@@ -1678,6 +1729,9 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
 				    vol->password ? vol->password : "",
 				    MAX_PASSWORD_SIZE))
 				continue;
+			if (!srcip_matches((struct sockaddr*)&server->srcaddr,
+					   (struct sockaddr*)&ses->server->srcaddr))
+				continue;
 		}
 		++ses->ses_count;
 		write_unlock(&cifs_tcp_ses_lock);
@@ -2051,6 +2105,24 @@ ipv4_connect(struct TCP_Server_Info *server)
 		cifs_reclassify_socket4(socket);
 	}
 
+	if (cifs_addr_is_specified((struct sockaddr*)&server->srcaddr)) {
+		/* Bind to the local IP address if specified */
+		rc = socket->ops->bind(socket, (struct sockaddr *) &server->srcaddr,
+				       sizeof(server->srcaddr));
+		if (rc < 0) {
+			struct sockaddr_in *saddr4;
+			struct sockaddr_in6 *saddr6;
+			saddr4 = (struct sockaddr_in *)&server->srcaddr;
+			saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
+			if (saddr6->sin6_family == AF_INET6)
+				cERROR(1, "Failed to bind to: %pI6, error: %d\n",
+				       &saddr6->sin6_addr, rc);
+			else
+				cERROR(1, "Failed to bind to: %pI4, error: %d\n",
+				       &saddr4->sin_addr.s_addr, rc);
+		}
+	}
+	
 	/* user overrode default port */
 	if (server->addr.sockAddr.sin_port) {
 		rc = socket->ops->connect(socket, (struct sockaddr *)
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index ab70a3f..4c0e04b 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -234,6 +234,8 @@ const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
 const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
 const struct in6_addr in6addr_linklocal_allrouters = IN6ADDR_LINKLOCAL_ALLROUTERS_INIT;
 
+EXPORT_SYMBOL(in6addr_any);
+
 /* Check if a valid qdisc is available */
 static inline bool addrconf_qdisc_ok(const struct net_device *dev)
 {

  parent reply	other threads:[~2010-08-30 18:19 UTC|newest]

Thread overview: 16+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2010-08-26 17:34 [cifs bindaddr v2] cifs: Allow binding to local IP address Ben Greear
     [not found] ` <1282844096-13295-1-git-send-email-greearb-my8/4N5VtI7c+919tysfdA@public.gmane.org>
2010-08-26 19:57   ` Jeff Layton
     [not found]     ` <20100826155733.6eccc377-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2010-08-26 23:36       ` Steve French
     [not found]         ` <AANLkTikdghfNW0Qq9DkWk8a363EYvKHQn65iOn0ni6e7-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-08-27  1:07           ` Jeff Layton
     [not found] ` <AANLkTik4Cffnr0ciYAVXz_jb_=EG5kBaKNE3V3cNVtwf@mail.gmail.com>
     [not found]   ` <4C777615.2080109@erion.co.uk>
     [not found]     ` <AANLkTi=9xBr2gABJSUSk2DMJEYho+jA3rbCk1PSfuQQ5@mail.gmail.com>
     [not found]       ` <20100827095433.26bb3c3e@corrin.poochiereds.net>
     [not found]         ` <20100827095433.26bb3c3e-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2010-08-27 15:29           ` Ben Greear
     [not found]             ` <4C77D9ED.4050101-my8/4N5VtI7c+919tysfdA@public.gmane.org>
2010-08-27 16:52               ` Jeff Layton
     [not found]                 ` <20100827125242.0798ffe9-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2010-08-27 17:08                   ` Steve French
     [not found]                     ` <AANLkTim-Hsn77fJUR1TrM_szVaJ3_vYzw61j0GYMt+Rr-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-08-27 17:12                       ` Ben Greear
     [not found]                         ` <4C77F1F0.4070800-my8/4N5VtI7c+919tysfdA@public.gmane.org>
2010-08-27 17:34                           ` Jeff Layton
     [not found]                             ` <20100827133401.75eb7f7f-9yPaYZwiELC+kQycOl6kW4xkIHaj4LzF@public.gmane.org>
2010-08-27 17:59                               ` Steve French
     [not found]                                 ` <AANLkTikDjbWv0F18WevNbsfJyutEu28RCCgtmp1=ZBd4-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2010-08-30 18:19                                   ` Ben Greear [this message]
  -- strict thread matches above, loose matches on Subject: below --
2010-08-31 19:55 [cifs bindaddr v3] " Ben Greear
     [not found] ` <1283284514-25588-1-git-send-email-greearb-my8/4N5VtI7c+919tysfdA@public.gmane.org>
2010-09-01 12:41   ` Jeff Layton
     [not found]     ` <20100901084147.4aa66e9d-4QP7MXygkU+dMjc06nkz3ljfA9RmPOcC@public.gmane.org>
2010-09-01 16:31       ` Ben Greear
     [not found]         ` <4C7E7FDC.7060606-my8/4N5VtI7c+919tysfdA@public.gmane.org>
2010-09-01 16:40           ` Jeff Layton
2010-09-01 16:46           ` Steve French

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4C7BF63C.2060503@candelatech.com \
    --to=greearb-my8/4n5vti7c+919tysfda@public.gmane.org \
    --cc=jlayton-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org \
    --cc=linux-cifs-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
    --cc=smfrench-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.