summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2011-05-02 15:23:08 +1000
committerAndrew Bartlett <abartlet@samba.org>2011-05-03 07:37:07 +0200
commitfbea52f74a80268446f45936a0cf40400aba8565 (patch)
tree5f77314c19f34a05683d9ee8f76ab250e4e8da6f /lib
parent85fa87ea82a1dcbd4d0145e417d615ffca116751 (diff)
downloadsamba-fbea52f74a80268446f45936a0cf40400aba8565.tar.gz
samba-fbea52f74a80268446f45936a0cf40400aba8565.tar.bz2
samba-fbea52f74a80268446f45936a0cf40400aba8565.zip
lib/util Move more network utility functions from source3 into lib/util
This will help with the merge of the interfaces layer. Andrew Bartlett
Diffstat (limited to 'lib')
-rw-r--r--lib/util/system.c72
-rw-r--r--lib/util/util.h14
-rw-r--r--lib/util/util_net.c155
-rw-r--r--lib/util/util_net.h35
4 files changed, 275 insertions, 1 deletions
diff --git a/lib/util/system.c b/lib/util/system.c
index 9bf5de1a83..17c0553102 100644
--- a/lib/util/system.c
+++ b/lib/util/system.c
@@ -117,3 +117,75 @@ _PUBLIC_ pid_t sys_getpid(void)
return mypid;
}
+
+
+_PUBLIC_ int sys_getpeereid( int s, uid_t *uid)
+{
+#if defined(HAVE_PEERCRED)
+ struct ucred cred;
+ socklen_t cred_len = sizeof(struct ucred);
+ int ret;
+
+ ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len);
+ if (ret != 0) {
+ return -1;
+ }
+
+ if (cred_len != sizeof(struct ucred)) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ *uid = cred.uid;
+ return 0;
+#else
+#if defined(HAVE_GETPEEREID)
+ gid_t gid;
+ return getpeereid(s, uid, &gid);
+#endif
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+
+_PUBLIC_ int sys_getnameinfo(const struct sockaddr *psa,
+ int salen,
+ char *host,
+ size_t hostlen,
+ char *service,
+ size_t servlen,
+ int flags)
+{
+ /*
+ * For Solaris we must make sure salen is the
+ * correct length for the incoming sa_family.
+ */
+
+ if (salen == sizeof(struct sockaddr_storage)) {
+ salen = sizeof(struct sockaddr_in);
+#if defined(HAVE_IPV6)
+ if (psa->sa_family == AF_INET6) {
+ salen = sizeof(struct sockaddr_in6);
+ }
+#endif
+ }
+ return getnameinfo(psa, salen, host, hostlen, service, servlen, flags);
+}
+
+_PUBLIC_ int sys_connect(int fd, const struct sockaddr * addr)
+{
+ socklen_t salen = (socklen_t)-1;
+
+ if (addr->sa_family == AF_INET) {
+ salen = sizeof(struct sockaddr_in);
+ } else if (addr->sa_family == AF_UNIX) {
+ salen = sizeof(struct sockaddr_un);
+ }
+#if defined(HAVE_IPV6)
+ else if (addr->sa_family == AF_INET6) {
+ salen = sizeof(struct sockaddr_in6);
+ }
+#endif
+
+ return connect(fd, addr, salen);
+}
diff --git a/lib/util/util.h b/lib/util/util.h
index 8dffece0da..5ed8427498 100644
--- a/lib/util/util.h
+++ b/lib/util/util.h
@@ -131,8 +131,20 @@ _PUBLIC_ pid_t sys_fork(void);
**/
_PUBLIC_ pid_t sys_getpid(void);
-/* The following definitions come from lib/util/genrand.c */
+_PUBLIC_ int sys_getpeereid( int s, uid_t *uid);
+
+struct sockaddr;
+_PUBLIC_ int sys_getnameinfo(const struct sockaddr *psa,
+ int salen,
+ char *host,
+ size_t hostlen,
+ char *service,
+ size_t servlen,
+ int flags);
+_PUBLIC_ int sys_connect(int fd, const struct sockaddr * addr);
+
+/* The following definitions come from lib/util/genrand.c */
/**
Copy any user given reseed data.
**/
diff --git a/lib/util/util_net.c b/lib/util/util_net.c
index 9c8f5c6d47..e80447128f 100644
--- a/lib/util/util_net.c
+++ b/lib/util/util_net.c
@@ -540,3 +540,158 @@ void set_sockaddr_port(struct sockaddr *psa, uint16_t port)
}
+/****************************************************************************
+ Get a port number in host byte order from a sockaddr_storage.
+****************************************************************************/
+
+uint16_t get_sockaddr_port(const struct sockaddr_storage *pss)
+{
+ uint16_t port = 0;
+
+ if (pss->ss_family != AF_INET) {
+#if defined(HAVE_IPV6)
+ /* IPv6 */
+ const struct sockaddr_in6 *sa6 =
+ (const struct sockaddr_in6 *)pss;
+ port = ntohs(sa6->sin6_port);
+#endif
+ } else {
+ const struct sockaddr_in *sa =
+ (const struct sockaddr_in *)pss;
+ port = ntohs(sa->sin_port);
+ }
+ return port;
+}
+
+/****************************************************************************
+ Print out an IPv4 or IPv6 address from a struct sockaddr_storage.
+****************************************************************************/
+
+char *print_sockaddr_len(char *dest,
+ size_t destlen,
+ const struct sockaddr *psa,
+ socklen_t psalen)
+{
+ if (destlen > 0) {
+ dest[0] = '\0';
+ }
+ (void)sys_getnameinfo(psa,
+ psalen,
+ dest, destlen,
+ NULL, 0,
+ NI_NUMERICHOST);
+ return 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, (struct sockaddr *)psa,
+ sizeof(struct sockaddr_storage));
+}
+
+/****************************************************************************
+ 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;
+
+ /* Linux getnameinfo() man pages says port is unitialized if
+ service name is NULL. */
+
+ ret = sys_getnameinfo((const struct sockaddr *)pss,
+ sizeof(struct sockaddr_storage),
+ addr, sizeof(addr),
+ NULL, 0,
+ NI_NUMERICHOST);
+ if (ret != 0) {
+ return NULL;
+ }
+
+ if (pss->ss_family != AF_INET) {
+#if defined(HAVE_IPV6)
+ dest = talloc_asprintf(ctx, "[%s]", addr);
+#else
+ return NULL;
+#endif
+ } else {
+ dest = talloc_asprintf(ctx, "%s", addr);
+ }
+
+ return dest;
+}
+
+/****************************************************************************
+ Return the port number we've bound to on a socket.
+****************************************************************************/
+
+int get_socket_port(int fd)
+{
+ struct sockaddr_storage sa;
+ socklen_t length = sizeof(sa);
+
+ if (fd == -1) {
+ return -1;
+ }
+
+ if (getsockname(fd, (struct sockaddr *)&sa, &length) < 0) {
+ int level = (errno == ENOTCONN) ? 2 : 0;
+ DEBUG(level, ("getsockname failed. Error was %s\n",
+ strerror(errno)));
+ return -1;
+ }
+
+#if defined(HAVE_IPV6)
+ if (sa.ss_family == AF_INET6) {
+ return ntohs(((struct sockaddr_in6 *)&sa)->sin6_port);
+ }
+#endif
+ if (sa.ss_family == AF_INET) {
+ return ntohs(((struct sockaddr_in *)&sa)->sin_port);
+ }
+ return -1;
+}
+
+/****************************************************************************
+ Return the string of an IP address (IPv4 or IPv6).
+****************************************************************************/
+
+static const char *get_socket_addr(int fd, char *addr_buf, size_t addr_len)
+{
+ struct sockaddr_storage sa;
+ socklen_t length = sizeof(sa);
+
+ /* Ok, returning a hard coded IPv4 address
+ * is bogus, but it's just as bogus as a
+ * zero IPv6 address. No good choice here.
+ */
+
+ strlcpy(addr_buf, "0.0.0.0", addr_len);
+
+ if (fd == -1) {
+ return addr_buf;
+ }
+
+ if (getsockname(fd, (struct sockaddr *)&sa, &length) < 0) {
+ DEBUG(0,("getsockname failed. Error was %s\n",
+ strerror(errno) ));
+ return addr_buf;
+ }
+
+ return print_sockaddr_len(addr_buf, addr_len, (struct sockaddr *)&sa, length);
+}
+
+const char *client_socket_addr(int fd, char *addr, size_t addr_len)
+{
+ return get_socket_addr(fd, addr, addr_len);
+}
diff --git a/lib/util/util_net.h b/lib/util/util_net.h
index 530311e5c8..71d1d1a6bd 100644
--- a/lib/util/util_net.h
+++ b/lib/util/util_net.h
@@ -50,6 +50,15 @@ void set_sockaddr_port(struct sockaddr *psa, uint16_t port);
**/
_PUBLIC_ bool is_zero_ip_v4(struct in_addr ip);
+void in_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
+ struct in_addr ip);
+#if defined(HAVE_IPV6)
+/**
+ * Convert an IPv6 struct in_addr to a struct sockaddr_storage.
+ */
+void in6_addr_to_sockaddr_storage(struct sockaddr_storage *ss,
+ struct in6_addr ip);
+#endif
/**
Are two IPs on the same subnet?
**/
@@ -60,6 +69,11 @@ _PUBLIC_ bool same_net_v4(struct in_addr ip1,struct in_addr ip2,struct in_addr m
**/
_PUBLIC_ bool is_ipaddress(const char *str);
+bool is_broadcast_addr(const struct sockaddr *pss);
+bool is_loopback_ip_v4(struct in_addr ip);
+bool is_loopback_addr(const struct sockaddr *pss);
+bool is_zero_addr(const struct sockaddr_storage *pss);
+void zero_ip_v4(struct in_addr *ip);
/**
Interpret an internet address or name into an IP address in 4 byte form.
**/
@@ -72,5 +86,26 @@ _PUBLIC_ struct in_addr interpret_addr2(const char *str);
_PUBLIC_ bool is_ipaddress_v4(const char *str);
+bool is_address_any(const struct sockaddr *psa);
+bool same_net(const struct sockaddr *ip1,
+ const struct sockaddr *ip2,
+ const struct sockaddr *mask);
+bool sockaddr_equal(const struct sockaddr *ip1,
+ const struct sockaddr *ip2);
+
+bool is_address_any(const struct sockaddr *psa);
+uint16_t get_sockaddr_port(const struct sockaddr_storage *pss);
+char *print_sockaddr_len(char *dest,
+ size_t destlen,
+ const struct sockaddr *psa,
+ socklen_t psalen);
+char *print_sockaddr(char *dest,
+ size_t destlen,
+ const struct sockaddr_storage *psa);
+char *print_canonical_sockaddr(TALLOC_CTX *ctx,
+ const struct sockaddr_storage *pss);
+const char *client_name(int fd);
+int get_socket_port(int fd);
+const char *client_socket_addr(int fd, char *addr, size_t addr_len);
#endif /* _SAMBA_UTIL_NET_H_ */