vss: Fix computation of extra slices.
[paraslash.git] / net.c
diff --git a/net.c b/net.c
index 2a3fc72be0ad446fa101dcbd9459107fb49f50dd..ab6a98940b1e920eee7ee5e3f8f6b9bb33cf94b9 100644 (file)
--- a/net.c
+++ b/net.c
@@ -6,6 +6,12 @@
 
 /** \file net.c Networking-related helper functions. */
 
+/*
+ * Since glibc 2.8, the _GNU_SOURCE feature test macro must be defined in order
+ * to obtain the definition of the ucred structure.
+ */
+#define _GNU_SOURCE
+
 #include <netdb.h>
 
 /* At least NetBSD needs these. */
@@ -86,6 +92,47 @@ void disable_crypt(int fd)
        crypt_data_array[fd].private_data = NULL;
 }
 
+/**
+ * Parse and validate IPv4 address/netmask string.
+ *
+ * \param cidr   Address in CIDR notation
+ * \param addr   Copy of the IPv4 address part of \a cidr
+ * \param addrlen Size of \a addr in bytes
+ * \param netmask Value of the netmask part in \a cidr or the
+ *               default of 32 if not specified.
+ *
+ * \return Pointer to \a addr if succesful, NULL on error.
+ * \sa RFC 4632
+ */
+char *parse_cidr(const char *cidr,
+                char    *addr, ssize_t addrlen,
+                int32_t *netmask)
+{
+       const char *o = cidr;
+       char *c = addr, *end = c + (addrlen - 1);
+
+       *netmask = 0x20;
+
+       if (cidr == NULL || addrlen < 1)
+               goto failed;
+
+       for (o = cidr; (*c = *o == '/'? '\0' : *o); c++, o++)
+               if (c == end)
+                       goto failed;
+
+       if (*o == '/')
+               if (para_atoi32(++o, netmask) < 0 ||
+                   *netmask < 0 || *netmask > 0x20)
+                       goto failed;
+
+       if (is_valid_ipv4_address(addr))
+               return addr;
+failed:
+       *addr = '\0';
+       return NULL;
+}
+
+
 /**
  * Match string as a candidate IPv4 address.
  *
@@ -428,11 +475,31 @@ static char *__get_sock_name(int fd, int (*getname)(int, struct sockaddr*,
        return host_and_port((struct sockaddr *)&ss, sslen);
 }
 
+/**
+ * Look up the local side of a connected socket structure.
+ *
+ * \param sockfd The file descriptor of the socket.
+ *
+ * \return A pointer to a static buffer containing hostname an port. This
+ * buffer must not be freed by the caller.
+ *
+ * \sa remote_name().
+ */
 char *local_name(int sockfd)
 {
        return __get_sock_name(sockfd, getsockname);
 }
 
+/**
+ * Look up the remote side of a connected socket structure.
+ *
+ * \param sockfd The file descriptor of the socket.
+ *
+ * \return Analogous to the return value of \ref local_name() but for the
+ * remote side.
+ *
+ * \sa local_name().
+ */
 char *remote_name(int sockfd)
 {
        return __get_sock_name(sockfd, getpeername);
@@ -450,7 +517,7 @@ struct in_addr extract_v4_addr(const struct sockaddr_storage *ss)
        struct in_addr ia = {.s_addr = 0};
 
        if (ss->ss_family == AF_INET)
-                ia.s_addr = ((struct sockaddr_in *)ss)->sin_addr.s_addr;
+               ia.s_addr = ((struct sockaddr_in *)ss)->sin_addr.s_addr;
        if (ss->ss_family == AF_INET6) {
                const struct in6_addr v6_addr = ((struct sockaddr_in6 *)ss)->sin6_addr;
 
@@ -468,8 +535,8 @@ struct in_addr extract_v4_addr(const struct sockaddr_storage *ss)
  * \param len The length of \a buf.
  *
  * Check if encryption is available. If yes, encrypt the given buffer.  Send
- * out the buffer, encrypted or not, and try to resend the remaing part in case
- * of short writes.
+ * out the buffer, encrypted or not, and try to resend the remaining part in
+ * case of short writes.
  *
  * \return Standard.
  */
@@ -736,7 +803,7 @@ int recv_cred_buffer(int fd, char *buf, size_t size)
  */
 ssize_t send_cred_buffer(int sock, char *buf)
 {
-       char control[sizeof(struct cmsghdr) + 10];
+       char control[sizeof(struct cmsghdr) + sizeof(struct ucred)];
        struct msghdr msg;
        struct cmsghdr *cmsg;
        static struct iovec iov;