summaryrefslogtreecommitdiff
path: root/source3/lib
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2007-10-24 14:16:54 -0700
committerJeremy Allison <jra@samba.org>2007-10-24 14:16:54 -0700
commitf88b7a076be74a29a3bf876b4e2705f4a1ecf42b (patch)
tree2d5167540fcbe1ad245fce697924b18216b2d142 /source3/lib
parente01cbcb28e63abb0f681a5a168fc2445744eec93 (diff)
downloadsamba-f88b7a076be74a29a3bf876b4e2705f4a1ecf42b.tar.gz
samba-f88b7a076be74a29a3bf876b4e2705f4a1ecf42b.tar.bz2
samba-f88b7a076be74a29a3bf876b4e2705f4a1ecf42b.zip
This is a large patch (sorry). Migrate from struct in_addr
to struct sockaddr_storage in most places that matter (ie. not the nmbd and NetBIOS lookups). This passes make test on an IPv4 box, but I'll have to do more work/testing on IPv6 enabled boxes. This should now give us a framework for testing and finishing the IPv6 migration. It's at the state where someone with a working IPv6 setup should (theorecically) be able to type : smbclient //ipv6-address/share and have it work. Jeremy. (This used to be commit 98e154c3125d5732c37a72d74b0eb5cd7b6155fd)
Diffstat (limited to 'source3/lib')
-rw-r--r--source3/lib/interface.c14
-rw-r--r--source3/lib/util_sock.c206
-rw-r--r--source3/lib/util_str.c83
3 files changed, 227 insertions, 76 deletions
diff --git a/source3/lib/interface.c b/source3/lib/interface.c
index 0696329fd6..49bbceceb7 100644
--- a/source3/lib/interface.c
+++ b/source3/lib/interface.c
@@ -269,7 +269,7 @@ const struct sockaddr_storage *iface_ip(const struct sockaddr_storage *ip)
return True if a IP is directly reachable on one of our interfaces
*/
-bool iface_local(struct sockaddr_storage *ip)
+bool iface_local(const struct sockaddr_storage *ip)
{
return iface_find(ip, True) ? true : false;
}
@@ -285,8 +285,7 @@ static void add_interface(const struct iface_struct *ifs)
if (iface_find(&ifs->ip, False)) {
DEBUG(3,("add_interface: not adding duplicate interface %s\n",
- print_sockaddr(addr, sizeof(addr),
- &ifs->ip, sizeof(struct sockaddr_storage)) ));
+ print_sockaddr(addr, sizeof(addr), &ifs->ip) ));
return;
}
@@ -317,16 +316,13 @@ static void add_interface(const struct iface_struct *ifs)
DEBUG(2,("added interface %s ip=%s ",
iface->name,
- print_sockaddr(addr, sizeof(addr),
- &iface->ip, sizeof(struct sockaddr_storage)) ));
+ print_sockaddr(addr, sizeof(addr), &iface->ip) ));
DEBUG(2,("bcast=%s ",
print_sockaddr(addr, sizeof(addr),
- &iface->bcast,
- sizeof(struct sockaddr_storage)) ));
+ &iface->bcast) ));
DEBUG(2,("netmask=%s\n",
print_sockaddr(addr, sizeof(addr),
- &iface->netmask,
- sizeof(struct sockaddr_storage)) ));
+ &iface->netmask) ));
}
/****************************************************************************
diff --git a/source3/lib/util_sock.c b/source3/lib/util_sock.c
index c6b1311cf5..2d784717b2 100644
--- a/source3/lib/util_sock.c
+++ b/source3/lib/util_sock.c
@@ -63,6 +63,27 @@ bool is_ipaddress(const char *str)
return is_ipaddress_v4(str);
}
+/****************************************************************************
+ Is a sockaddr_storage a broadcast address ?
+****************************************************************************/
+
+bool is_broadcast_addr(const struct sockaddr_storage *pss)
+{
+#if defined(HAVE_IPV6)
+ if (pss->ss_family == AF_INET6) {
+ const struct in6_addr *sin6 =
+ &((const struct sockaddr_in6 *)pss)->sin6_addr;
+ return IN6_IS_ADDR_MULTICAST(sin6);
+ }
+#endif
+ if (pss->ss_family == AF_INET) {
+ uint32_t addr =
+ ntohl(((const struct sockaddr_in *)pss)->sin_addr.s_addr);
+ return addr == INADDR_BROADCAST;
+ }
+ return false;
+}
+
/*******************************************************************
Wrap getaddrinfo...
******************************************************************/
@@ -181,7 +202,7 @@ bool interpret_string_addr(struct sockaddr_storage *pss,
{
struct addrinfo *res = NULL;
- memset(pss,'\0', sizeof(*pss));
+ zero_addr(pss, AF_INET);
if (!interpret_string_addr_internal(&res, str, flags|AI_ADDRCONFIG)) {
return false;
@@ -275,6 +296,17 @@ void zero_ip_v4(struct in_addr *ip)
}
/*******************************************************************
+ Set an address to INADDR_ANY, or IN6ADDR_ANY.
+******************************************************************/
+
+void zero_addr(struct sockaddr_storage *pss, int family)
+{
+ memset(pss, '\0', sizeof(*pss));
+ /* Ensure we're at least a valid sockaddr-storage. */
+ pss->ss_family = family;
+}
+
+/*******************************************************************
Are two IPs on the same subnet - IPv4 version ?
********************************************************************/
@@ -385,7 +417,6 @@ bool addr_equal(const struct sockaddr_storage *ip1,
return false;
}
-
/****************************************************************************
Is an IP address the INADDR_ANY or in6addr_any value ?
****************************************************************************/
@@ -417,7 +448,7 @@ bool is_address_any(const struct sockaddr_storage *psa)
Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
****************************************************************************/
-char *print_sockaddr(char *dest,
+char *print_sockaddr_len(char *dest,
size_t destlen,
const struct sockaddr_storage *psa,
socklen_t psalen)
@@ -434,6 +465,75 @@ char *print_sockaddr(char *dest,
}
/****************************************************************************
+ Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+char *print_sockaddr(char *dest,
+ size_t destlen,
+ const struct sockaddr_storage *psa)
+{
+ return print_sockaddr_len(dest, destlen, psa, sizeof(*psa));
+}
+
+/****************************************************************************
+ Print out a canonical IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+char *print_canonical_sockaddr(TALLOC_CTX *ctx,
+ const struct sockaddr_storage *pss)
+{
+ char addr[INET6_ADDRSTRLEN];
+ char *dest = NULL;
+ int ret;
+
+ ret = getnameinfo((const struct sockaddr *)pss,
+ sizeof(struct sockaddr_storage),
+ addr, sizeof(addr),
+ NULL, 0,
+ NI_NUMERICHOST);
+ if (ret) {
+ return NULL;
+ }
+ if (pss->ss_family != AF_INET) {
+#if defined(HAVE_IPV6)
+ /* IPv6 */
+ const struct sockaddr_in6 *sa6 =
+ (const struct sockaddr_in6 *)pss;
+ uint16_t port = ntohs(sa6->sin6_port);
+
+ if (port) {
+ dest = talloc_asprintf(ctx,
+ "[%s]:%d",
+ addr,
+ (unsigned int)port);
+ } else {
+ dest = talloc_asprintf(ctx,
+ "[%s]",
+ addr);
+ }
+#else
+ return NULL;
+#endif
+ } else {
+ const struct sockaddr_in *sa =
+ (const struct sockaddr_in *)pss;
+ uint16_t port = ntohs(sa->sin_port);
+
+ if (port) {
+ dest = talloc_asprintf(ctx,
+ "%s:%d",
+ addr,
+ (unsigned int)port);
+ } else {
+ dest = talloc_asprintf(ctx,
+ "%s",
+ addr);
+ }
+ }
+ return dest;
+}
+
+/****************************************************************************
Set the global client_fd variable.
****************************************************************************/
@@ -472,7 +572,7 @@ static const char *get_socket_addr(int fd)
return addr_buf;
}
- return print_sockaddr(addr_buf, sizeof(addr_buf), &sa, length);
+ return print_sockaddr_len(addr_buf, sizeof(addr_buf), &sa, length);
}
/****************************************************************************
@@ -1274,24 +1374,26 @@ bool send_smb(int fd, char *buffer)
****************************************************************************/
int open_socket_in(int type,
- int port,
+ uint16_t port,
int dlevel,
- uint32 socket_addr, /* NETWORK BYTE ORDER */
- bool rebind )
+ const struct sockaddr_storage *psock,
+ bool rebind)
{
- struct sockaddr_in sock;
+ struct sockaddr_storage sock;
int res;
- memset( (char *)&sock, '\0', sizeof(sock) );
+ sock = *psock;
-#ifdef HAVE_SOCK_SIN_LEN
- sock.sin_len = sizeof(sock);
+#if defined(HAVE_IPV6)
+ if (sock.ss_family == AF_INET6) {
+ ((struct sockaddr_in6 *)&sock)->sin6_port = htons(port);
+ }
#endif
- sock.sin_port = htons( port );
- sock.sin_family = AF_INET;
- sock.sin_addr.s_addr = socket_addr;
+ if (sock.ss_family == AF_INET) {
+ ((struct sockaddr_in *)&sock)->sin_port = htons(port);
+ }
- res = socket( AF_INET, type, 0 );
+ res = socket(sock.ss_family, type, 0 );
if( res == -1 ) {
if( DEBUGLVL(0) ) {
dbgtext( "open_socket_in(): socket() call failed: " );
@@ -1319,9 +1421,9 @@ int open_socket_in(int type,
if( DEBUGLVL( dlevel ) ) {
dbgtext( "open_socket_in(): setsockopt: ");
dbgtext( "SO_REUSEPORT = %s ",
- val?"true":"false" );
- dbgtext( "on port %d failed ", port );
- dbgtext( "with error = %s\n", strerror(errno) );
+ val?"true":"false");
+ dbgtext( "on port %d failed ", port);
+ dbgtext( "with error = %s\n", strerror(errno));
}
}
#endif /* SO_REUSEPORT */
@@ -1331,17 +1433,18 @@ int open_socket_in(int type,
if( bind( res, (struct sockaddr *)&sock, sizeof(sock) ) == -1 ) {
if( DEBUGLVL(dlevel) && (port == SMB_PORT1 ||
port == SMB_PORT2 || port == NMB_PORT) ) {
- dbgtext( "bind failed on port %d ", port );
- dbgtext( "socket_addr = %s.\n",
- inet_ntoa( sock.sin_addr ) );
- dbgtext( "Error = %s\n", strerror(errno) );
+ char addr[INET6_ADDRSTRLEN];
+ print_sockaddr(addr, sizeof(addr),
+ &sock);
+ dbgtext( "bind failed on port %d ", port);
+ dbgtext( "socket_addr = %s.\n", addr);
+ dbgtext( "Error = %s\n", strerror(errno));
}
- close( res );
+ close(res);
return -1;
}
DEBUG( 10, ( "bind succeeded on port %d\n", port ) );
-
return( res );
}
@@ -1349,33 +1452,46 @@ int open_socket_in(int type,
Create an outgoing socket. timeout is in milliseconds.
**************************************************************************/
-int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
+int open_socket_out(int type,
+ const struct sockaddr_storage *pss,
+ uint16_t port,
+ int timeout)
{
- struct sockaddr_in sock_out;
+ char addr[INET6_ADDRSTRLEN];
+ struct sockaddr_storage sock_out = *pss;
int res,ret;
int connect_loop = 10;
int increment = 10;
/* create a socket to write to */
- res = socket(PF_INET, type, 0);
+ res = socket(pss->ss_family, type, 0);
if (res == -1) {
DEBUG(0,("socket error (%s)\n", strerror(errno)));
return -1;
}
- if (type != SOCK_STREAM)
- return(res);
-
- memset((char *)&sock_out,'\0',sizeof(sock_out));
- putip((char *)&sock_out.sin_addr,(char *)addr);
+ if (type != SOCK_STREAM) {
+ return res;
+ }
- sock_out.sin_port = htons( port );
- sock_out.sin_family = PF_INET;
+#if defined(HAVE_IPV6)
+ if (pss->ss_family == AF_INET6) {
+ struct sockaddr_in6 *psa6 = (struct sockaddr_in6 *)&sock_out;
+ psa6->sin6_port = htons(port);
+ }
+#endif
+ if (pss->ss_family == AF_INET) {
+ struct sockaddr_in *psa = (struct sockaddr_in *)&sock_out;
+ psa->sin_port = htons(port);
+ }
/* set it non-blocking */
set_blocking(res,false);
- DEBUG(3,("Connecting to %s at port %d\n",inet_ntoa(*addr),port));
+ print_sockaddr(addr, sizeof(addr), &sock_out);
+ DEBUG(3,("Connecting to %s at port %u\n",
+ addr,
+ (unsigned int)port));
/* and connect it to the destination */
connect_again:
@@ -1397,8 +1513,9 @@ int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
if (ret < 0 && (errno == EINPROGRESS || errno == EALREADY ||
errno == EAGAIN)) {
- DEBUG(1,("timeout connecting to %s:%d\n",
- inet_ntoa(*addr),port));
+ DEBUG(1,("timeout connecting to %s:%u\n",
+ addr,
+ (unsigned int)port));
close(res);
return -1;
}
@@ -1412,7 +1529,9 @@ int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
if (ret < 0) {
DEBUG(2,("error connecting to %s:%d (%s)\n",
- inet_ntoa(*addr),port,strerror(errno)));
+ addr,
+ (unsigned int)port,
+ strerror(errno)));
close(res);
return -1;
}
@@ -1429,7 +1548,7 @@ int open_socket_out(int type, struct in_addr *addr, int port ,int timeout)
of DC's all of which are equivalent for our purposes.
**************************************************************************/
-bool open_any_socket_out(struct sockaddr_in *addrs, int num_addrs,
+bool open_any_socket_out(struct sockaddr_storage *addrs, int num_addrs,
int timeout, int *fd_index, int *fd)
{
int i, resulting_index, res;
@@ -1455,7 +1574,7 @@ bool open_any_socket_out(struct sockaddr_in *addrs, int num_addrs,
sockets[i] = -1;
for (i=0; i<num_addrs; i++) {
- sockets[i] = socket(PF_INET, SOCK_STREAM, 0);
+ sockets[i] = socket(addrs[i].ss_family, SOCK_STREAM, 0);
if (sockets[i] < 0)
goto done;
set_blocking(sockets[i], false);
@@ -1639,7 +1758,7 @@ static const char *get_peer_addr_internal(int fd,
return addr_buf;
}
- print_sockaddr(addr_buf,
+ print_sockaddr_len(addr_buf,
sizeof(addr_buf),
pss,
*plength);
@@ -1705,7 +1824,7 @@ static bool matchname(const char *remotehost,
*/
DEBUG(0,("matchname: host name/address mismatch: %s != %s\n",
- print_sockaddr(addr_buf,
+ print_sockaddr_len(addr_buf,
sizeof(addr_buf),
pss,
len),
@@ -2004,8 +2123,7 @@ bool is_myname_or_ipaddr(const char *s)
if (interpret_string_addr(&ss, servername,0)) {
print_sockaddr(name,
sizeof(name),
- &ss,
- sizeof(ss));
+ &ss);
servername = name;
}
}
diff --git a/source3/lib/util_str.c b/source3/lib/util_str.c
index 2fd22280a4..226bf826fb 100644
--- a/source3/lib/util_str.c
+++ b/source3/lib/util_str.c
@@ -2270,27 +2270,54 @@ bool str_list_substitute(char **list, const char *pattern, const char *insert)
* reallocated to new length
**/
-char *ipstr_list_add(char **ipstr_list, const struct ip_service *service)
+static char *ipstr_list_add(char **ipstr_list, const struct ip_service *service)
{
char *new_ipstr = NULL;
+ char addr_buf[INET6_ADDRSTRLEN];
/* arguments checking */
- if (!ipstr_list || !service) return NULL;
+ if (!ipstr_list || !service) {
+ return NULL;
+ }
/* attempt to convert ip to a string and append colon separator to it */
if (*ipstr_list) {
- asprintf(&new_ipstr, "%s%s%s:%d", *ipstr_list, IPSTR_LIST_SEP,
- inet_ntoa(service->ip), service->port);
+ print_sockaddr(addr_buf,
+ sizeof(addr_buf),
+ &service->ss);
+ if (service->ss.ss_family == AF_INET) {
+ /* IPv4 */
+ asprintf(&new_ipstr, "%s%s%s:%d",
+ *ipstr_list,
+ IPSTR_LIST_SEP,
+ addr_buf,
+ service->port);
+ } else {
+ /* IPv6 */
+ asprintf(&new_ipstr, "%s%s[%s]:%d",
+ *ipstr_list,
+ IPSTR_LIST_SEP,
+ addr_buf,
+ service->port);
+ }
SAFE_FREE(*ipstr_list);
} else {
- asprintf(&new_ipstr, "%s:%d",
- inet_ntoa(service->ip), service->port);
+ if (service->ss.ss_family == AF_INET) {
+ /* IPv4 */
+ asprintf(&new_ipstr, "%s:%d",
+ addr_buf,
+ service->port);
+ } else {
+ /* IPv6 */
+ asprintf(&new_ipstr, "[%s]:%d",
+ addr_buf,
+ service->port);
+ }
}
*ipstr_list = new_ipstr;
return *ipstr_list;
}
-
/**
* Allocate and initialise an ipstr list using ip adresses
* passed as arguments.
@@ -2302,18 +2329,22 @@ char *ipstr_list_add(char **ipstr_list, const struct ip_service *service)
**/
char *ipstr_list_make(char **ipstr_list,
- const struct ip_service * ip_list, int ip_count)
+ const struct ip_service *ip_list,
+ int ip_count)
{
int i;
/* arguments checking */
- if (!ip_list || !ipstr_list) return 0;
+ if (!ip_list || !ipstr_list) {
+ return 0;
+ }
*ipstr_list = NULL;
/* process ip addresses given as arguments */
- for (i = 0; i < ip_count; i++)
+ for (i = 0; i < ip_count; i++) {
*ipstr_list = ipstr_list_add(ipstr_list, &ip_list[i]);
+ }
return (*ipstr_list);
}
@@ -2322,7 +2353,7 @@ char *ipstr_list_make(char **ipstr_list,
/**
* Parse given ip string list into array of ip addresses
* (as ip_service structures)
- * e.g. 192.168.1.100:389,192.168.1.78, ...
+ * e.g. [IPv6]:port,192.168.1.100:389,192.168.1.78, ...
*
* @param ipstr ip string list to be parsed
* @param ip_list pointer to array of ip addresses which is
@@ -2330,7 +2361,7 @@ char *ipstr_list_make(char **ipstr_list,
* @return number of succesfully parsed addresses
**/
-int ipstr_list_parse(const char* ipstr_list, struct ip_service **ip_list)
+int ipstr_list_parse(const char *ipstr_list, struct ip_service **ip_list)
{
fstring token_str;
size_t count;
@@ -2348,27 +2379,34 @@ int ipstr_list_parse(const char* ipstr_list, struct ip_service **ip_list)
for ( i=0; next_token(&ipstr_list, token_str,
IPSTR_LIST_SEP, FSTRING_LEN) && i<count; i++ ) {
- struct in_addr addr;
- unsigned port = 0;
- char *p = strchr(token_str, ':');
+ char *s = token_str;
+ char *p = strrchr(token_str, ':');
if (p) {
*p = 0;
- port = atoi(p+1);
+ (*ip_list)[i].port = atoi(p+1);
}
/* convert single token to ip address */
- if ( (addr.s_addr = inet_addr(token_str)) == INADDR_NONE )
- break;
-
- (*ip_list)[i].ip = addr;
- (*ip_list)[i].port = port;
+ if (token_str[0] == '[') {
+ /* IPv6 address. */
+ s++;
+ p = strchr(token_str, ']');
+ if (!p) {
+ continue;
+ }
+ *p = '\0';
+ }
+ if (!interpret_string_addr(&(*ip_list)[i].ss,
+ s,
+ AI_NUMERICHOST)) {
+ continue;
+ }
}
return count;
}
-
/**
* Safely free ip string list
*
@@ -2380,7 +2418,6 @@ void ipstr_list_free(char* ipstr_list)
SAFE_FREE(ipstr_list);
}
-
/**
Unescape a URL encoded string, in place.
**/