summaryrefslogtreecommitdiff
path: root/libmailutils
diff options
context:
space:
mode:
Diffstat (limited to 'libmailutils')
-rw-r--r--libmailutils/Makefile.am4
-rw-r--r--libmailutils/cidr/Makefile.am27
-rw-r--r--libmailutils/cidr/fromsa.c101
-rw-r--r--libmailutils/cidr/fromstr.c128
-rw-r--r--libmailutils/cidr/match.c38
-rw-r--r--libmailutils/cidr/tosa.c78
-rw-r--r--libmailutils/cidr/tostr.c159
-rw-r--r--libmailutils/diag/debug.c1
-rw-r--r--libmailutils/diag/errors8
-rw-r--r--libmailutils/server/acl.c366
-rw-r--r--libmailutils/server/ipsrv.c83
-rw-r--r--libmailutils/server/msrv.c348
-rw-r--r--libmailutils/sockaddr/Makefile.am31
-rw-r--r--libmailutils/sockaddr/copy.c36
-rw-r--r--libmailutils/sockaddr/create.c47
-rw-r--r--libmailutils/sockaddr/free.c50
-rw-r--r--libmailutils/sockaddr/fromnode.c253
-rw-r--r--libmailutils/sockaddr/insert.c64
-rw-r--r--libmailutils/sockaddr/ipaddr.c88
-rw-r--r--libmailutils/sockaddr/str.c109
-rw-r--r--libmailutils/sockaddr/unlink.c45
-rw-r--r--libmailutils/sockaddr/url.c130
-rw-r--r--libmailutils/stream/tcp.c178
-rw-r--r--libmailutils/tests/.gitignore1
-rw-r--r--libmailutils/tests/Makefile.am1
-rw-r--r--libmailutils/tests/cidr.c77
-rw-r--r--libmailutils/tests/url-parse.c49
-rw-r--r--libmailutils/tests/url.at14
-rw-r--r--libmailutils/url/create.c57
29 files changed, 1899 insertions, 672 deletions
diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am
index ed1aeb019..5aef3382d 100644
--- a/libmailutils/Makefile.am
+++ b/libmailutils/Makefile.am
@@ -16,7 +16,7 @@
# Public License along with this library. If not, see
# <http://www.gnu.org/licenses/>.
-SUBDIRS = auth base address cfg diag filter mailbox mailer mime\
+SUBDIRS = auth base address sockaddr cidr cfg diag filter mailbox mailer mime\
server string stream stdstream property url . tests
lib_LTLIBRARIES = libmailutils.la
@@ -28,6 +28,8 @@ libmailutils_la_LIBADD = \
auth/libauth.la\
base/libbase.la\
address/libaddress.la\
+ sockaddr/libsockaddr.la\
+ cidr/libcidr.la\
cfg/libcfg.la\
diag/libdiag.la\
filter/libfilter.la\
diff --git a/libmailutils/cidr/Makefile.am b/libmailutils/cidr/Makefile.am
new file mode 100644
index 000000000..408806f79
--- /dev/null
+++ b/libmailutils/cidr/Makefile.am
@@ -0,0 +1,27 @@
+# GNU Mailutils -- a suite of utilities for electronic mail
+# Copyright (C) 2011 Free Software Foundation, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General
+# Public License along with this library. If not, see
+# <http://www.gnu.org/licenses/>.
+
+noinst_LTLIBRARIES = libcidr.la
+
+libcidr_la_SOURCES = \
+ fromsa.c\
+ fromstr.c\
+ match.c\
+ tosa.c\
+ tostr.c
+
+INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
diff --git a/libmailutils/cidr/fromsa.c b/libmailutils/cidr/fromsa.c
new file mode 100644
index 000000000..a2fda6680
--- /dev/null
+++ b/libmailutils/cidr/fromsa.c
@@ -0,0 +1,101 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+
+static void
+uint32_to_bytes (unsigned char *bytes, uint32_t u)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ bytes[i] = u & 0xff;
+ u >>= 8;
+ }
+}
+
+int
+_mu_inaddr_to_bytes (int af, void *buf, unsigned char *bytes)
+{
+ uint32_t u;
+
+ switch (af)
+ {
+ case AF_INET:
+ memcpy (&u, buf, sizeof u);
+ uint32_to_bytes (bytes, u);
+ return 4;
+
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ memcpy (bytes, buf, 16);
+ return 16;
+#endif
+ }
+ return 0;
+}
+
+int
+_mu_sockaddr_to_bytes (unsigned char *bytes, struct sockaddr const *sa)
+{
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ uint32_to_bytes (bytes, ((struct sockaddr_in*)sa)->sin_addr.s_addr);
+ return 4;
+
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ memcpy (bytes, &((struct sockaddr_in6*)sa)->sin6_addr, 16);
+ return 16;
+#endif
+ }
+ return 0;
+}
+
+int
+mu_cidr_from_sockaddr (struct mu_cidr *cidr, const struct sockaddr *sa)
+{
+ unsigned char address[MU_INADDR_BYTES];
+ int len;
+ int i;
+
+ len = _mu_sockaddr_to_bytes (address, sa);
+ if (len == 0)
+ return MU_ERR_FAMILY;
+ cidr->family = sa->sa_family;
+ cidr->len = len;
+ memcpy (cidr->address, address, sizeof (cidr->address));
+ for (i = 0; i < MU_INADDR_BYTES; i++)
+ cidr->netmask[i] = 0xff;
+ return 0;
+}
+
+
diff --git a/libmailutils/cidr/fromstr.c b/libmailutils/cidr/fromstr.c
new file mode 100644
index 000000000..4e7a56f80
--- /dev/null
+++ b/libmailutils/cidr/fromstr.c
@@ -0,0 +1,128 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+#include <mailutils/sockaddr.h>
+
+static void
+masklen_to_netmask (unsigned char *buf, size_t len, size_t masklen)
+{
+ int i, cnt;
+
+ cnt = masklen / 8;
+ for (i = 0; i < cnt; i++)
+ buf[i] = 0xff;
+ if (i == MU_INADDR_BYTES)
+ return;
+ cnt = 8 - masklen % 8;
+ buf[i++] = (0xff >> cnt) << cnt;
+ for (; i < MU_INADDR_BYTES; i++)
+ buf[i] = 0;
+}
+
+int
+mu_cidr_from_string (struct mu_cidr *pcidr, const char *str)
+{
+ int rc;
+ char ipbuf[41];
+ struct mu_cidr cidr;
+ char *p;
+ size_t len;
+ union
+ {
+ struct in_addr in;
+#ifdef MAILUTILS_IPV6
+ struct in6_addr in6;
+#endif
+ } inaddr;
+
+ p = strchr (str, '/');
+ if (p)
+ len = p - str;
+ else
+ len = strlen (str);
+
+ if (len > sizeof (ipbuf))
+ return MU_ERR_BUFSPACE;
+
+ memcpy (ipbuf, str, len);
+ ipbuf[len] = 0;
+
+ if (mu_str_is_ipv4 (ipbuf))
+ cidr.family = AF_INET;
+#ifdef MAILUTILS_IPV6
+ else if (mu_str_is_ipv6 (ipbuf))
+ cidr.family = AF_INET6;
+#endif
+ else
+ return MU_ERR_FAMILY;
+
+ rc = inet_pton (cidr.family, ipbuf, &inaddr);
+ if (rc == -1)
+ return MU_ERR_FAMILY;
+ else if (rc == 0)
+ return MU_ERR_NONAME;
+ else if (rc != 1)
+ return MU_ERR_FAILURE;
+
+ cidr.len = _mu_inaddr_to_bytes (cidr.family, &inaddr, cidr.address);
+ if (cidr.len == 0)
+ return MU_ERR_FAMILY;
+
+ if (p)
+ {
+ char *end;
+ unsigned long masklen;
+
+ p++;
+
+ masklen = strtoul (p, &end, 10);
+ if (*end == 0)
+ masklen_to_netmask (cidr.netmask, cidr.len, masklen);
+ else if ((cidr.family == AF_INET && mu_str_is_ipv4 (p))
+#ifdef MAILUTILS_IPV6
+ || (cidr.family == AF_INET6 && mu_str_is_ipv6 (ipbuf))
+#endif
+ )
+ {
+ rc = inet_pton (cidr.family, p, &inaddr);
+ if (rc == -1)
+ return MU_ERR_FAMILY;
+ else if (rc == 0)
+ return MU_ERR_NONAME;
+ else if (rc != 1)
+ return MU_ERR_FAILURE;
+
+ _mu_inaddr_to_bytes (cidr.family, &inaddr, cidr.netmask);
+ }
+ else
+ return MU_ERR_FAMILY;
+ }
+ else
+ masklen_to_netmask (cidr.netmask, cidr.len, cidr.len * 8);
+
+ memcpy (pcidr, &cidr, sizeof (*pcidr));
+ return 0;
+}
+
diff --git a/libmailutils/cidr/match.c b/libmailutils/cidr/match.c
new file mode 100644
index 000000000..dff9194ee
--- /dev/null
+++ b/libmailutils/cidr/match.c
@@ -0,0 +1,38 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+
+int
+mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b)
+{
+ int i;
+
+ if (a->family != b->family)
+ return 1;
+ for (i = 0; i < a->len; i++)
+ {
+ if (a->address[i] != (b->address[i] & a->netmask[i]))
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/libmailutils/cidr/tosa.c b/libmailutils/cidr/tosa.c
new file mode 100644
index 000000000..c14a995da
--- /dev/null
+++ b/libmailutils/cidr/tosa.c
@@ -0,0 +1,78 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+
+int
+mu_cidr_to_sockaddr (struct mu_cidr *cidr, struct sockaddr **psa)
+{
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in s_in;
+#ifdef MAILUTILS_IPV6
+ struct sockaddr_in6 s_in6;
+#endif
+ } addr;
+ struct sockaddr *sa;
+ int socklen;
+ int i;
+
+ memset (&addr, 0, sizeof (addr));
+ addr.sa.sa_family = cidr->family;
+ switch (cidr->family)
+ {
+ case AF_INET:
+ socklen = sizeof (addr.s_in);
+ for (i = 0; i < cidr->len; i++)
+ {
+ addr.s_in.sin_addr.s_addr <<= 8;
+ addr.s_in.sin_addr.s_addr |= cidr->address[i];
+ }
+ break;
+
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ socklen = sizeof (addr.s_in6);
+ memcpy (&addr.s_in6.sin6_addr, cidr->address, 16);
+ break;
+#endif
+
+ default:
+ return MU_ERR_FAMILY;
+ }
+
+ sa = malloc (socklen);
+ if (!sa)
+ return ENOMEM;
+ memcpy (sa, &addr, socklen);
+ *psa = sa;
+ return 0;
+}
+
diff --git a/libmailutils/cidr/tostr.c b/libmailutils/cidr/tostr.c
new file mode 100644
index 000000000..3d1ee5f49
--- /dev/null
+++ b/libmailutils/cidr/tostr.c
@@ -0,0 +1,159 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+
+static int
+to_xdig (unsigned char b)
+{
+ if (b >= 0xa)
+ return 'A' + b - 0xa;
+ else
+ return '0' + b;
+}
+
+static size_t
+format_ipv6_bytes (const unsigned char *bytes, int len,
+ char *buf, size_t size)
+{
+ size_t total = 0;
+ int i;
+
+ for (i = 0; i < len; i += 2)
+ {
+ if (i)
+ {
+ if (total++ < size)
+ *buf++ = ':';
+ }
+ if (total++ < size)
+ *buf++ = to_xdig (*bytes >> 4);
+ if (total++ < size)
+ *buf++ = to_xdig (*bytes & 0xf);
+ bytes++;
+ if (total++ < size)
+ *buf++ = to_xdig (*bytes >> 4);
+ if (total++ < size)
+ *buf++ = to_xdig (*bytes & 0xf);
+ bytes++;
+ }
+ return total;
+}
+
+static size_t
+format_ipv4_bytes (const unsigned char *bytes, int len,
+ char *buf, size_t size)
+{
+ int i;
+ size_t total = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ unsigned char b = *bytes++;
+ char nbuf[3];
+ int j;
+
+ if (i)
+ {
+ if (total++ < size)
+ *buf++ = '.';
+ }
+
+ j = 0;
+ do
+ {
+ nbuf[j++] = b % 10 + '0';
+ b /= 10;
+ }
+ while (b);
+
+ for (; j; j--)
+ {
+ if (total++ < size)
+ *buf++ = nbuf[j - 1];
+ }
+ }
+ return total;
+}
+
+int
+mu_cidr_to_string (struct mu_cidr *cidr, int flags,
+ char *buf, size_t size, size_t *pret)
+{
+ size_t (*fmt) (const unsigned char *bytes, int len, char *buf, size_t size);
+ size_t n, total = 0;
+
+ if (size == 0)
+ return MU_ERR_BUFSPACE;
+ size--;
+ switch (cidr->family)
+ {
+ case AF_INET:
+ fmt = format_ipv4_bytes;
+ break;
+
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ fmt = format_ipv6_bytes;
+ break;
+#endif
+
+ default:
+ return MU_ERR_FAMILY;
+ }
+
+ n = fmt (cidr->address, cidr->len, buf, size);
+ if (buf)
+ buf += n;
+ total += n;
+
+ if (!(flags & MU_CIDR_FMT_ADDRONLY))
+ {
+ if (total++ < size)
+ *buf++ = '/';
+ n = fmt (cidr->netmask, cidr->len, buf, size - total);
+ if (buf)
+ buf += n;
+ total += n;
+ }
+
+ if (buf)
+ *buf++ = 0;
+ if (pret)
+ *pret = total;
+ return 0;
+}
+
+int
+mu_cidr_format (struct mu_cidr *cidr, int flags, char **pbuf)
+{
+ char buf[MU_CIDR_MAXBUFSIZE];
+ int rc = mu_cidr_to_string (cidr, flags, buf, sizeof (buf), NULL);
+ if (rc)
+ return rc;
+ *pbuf = strdup (buf);
+ if (!*buf)
+ return ENOMEM;
+ return 0;
+}
+
diff --git a/libmailutils/diag/debug.c b/libmailutils/diag/debug.c
index 124311bd8..aa10e41ba 100644
--- a/libmailutils/diag/debug.c
+++ b/libmailutils/diag/debug.c
@@ -689,6 +689,7 @@ mu_debug_log_begin (const char *fmt, ...)
va_list ap;
mu_diag_init ();
+ mu_stream_flush (mu_strerr);
va_start (ap, fmt);
mu_stream_printf (mu_strerr, "\033s<%d>", MU_LOG_DEBUG);
mu_stream_vprintf (mu_strerr, fmt, ap);
diff --git a/libmailutils/diag/errors b/libmailutils/diag/errors
index 869e4146f..03f71b715 100644
--- a/libmailutils/diag/errors
+++ b/libmailutils/diag/errors
@@ -1,3 +1,4 @@
+
# Error messages for GNU Mailutils
# Copyright (C) 2005, 2006, 2007, 2010, 2011 Free Software Foundation,
# Inc.
@@ -98,3 +99,10 @@ MU_ERR_URL_MISS_PARTS _("URL missing required parts")
MU_ERR_URL_EXTRA_PARTS _("URL has parts not allowed by its scheme")
MU_ERR_INFO_UNAVAILABLE _("Information is not yet available")
+
+# The following are mapped to the corresponding EAI_ errors
+MU_ERR_NONAME _("Name or service not known")
+MU_ERR_BADFLAGS _("Bad value for flags")
+MU_ERR_SOCKTYPE _("Socket type not supported")
+MU_ERR_FAMILY _("Address family not supported")
+MU_ERR_SERVICE _("Requested service not supported")
diff --git a/libmailutils/server/acl.c b/libmailutils/server/acl.c
index 0b7a507e0..ba1a4b86b 100644
--- a/libmailutils/server/acl.c
+++ b/libmailutils/server/acl.c
@@ -40,14 +40,20 @@
#include <mailutils/kwd.h>
#include <mailutils/io.h>
#include <mailutils/util.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/cidr.h>
+#include <mailutils/stream.h>
+#include <mailutils/stdstream.h>
+
+#ifndef MU_INADDR_BYTES
+#define MU_INADDR_BYTES 16
+#endif
struct _mu_acl_entry
{
mu_acl_action_t action;
void *arg;
- unsigned netmask;
- int salen;
- struct sockaddr sa[1];
+ struct mu_cidr cidr;
};
struct _mu_acl
@@ -64,52 +70,19 @@ _destroy_acl_entry (void *item)
/* FIXME: free arg? */
}
-static size_t
-mu_acl_entry_size (int salen)
-{
- return sizeof (struct _mu_acl_entry) + salen - sizeof (struct sockaddr);
-}
-
-static int
-prepare_sa (struct sockaddr *sa)
-{
- switch (sa->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
- s_in->sin_addr.s_addr = ntohl (s_in->sin_addr.s_addr);
- break;
- }
-
- case AF_UNIX:
- break;
-
- default:
- return 1;
- }
- return 0;
-}
-
int
mu_acl_entry_create (struct _mu_acl_entry **pent,
mu_acl_action_t action, void *data,
- struct sockaddr *sa, int salen, unsigned long netmask)
+ struct mu_cidr *cidr)
{
- struct _mu_acl_entry *p = malloc (mu_acl_entry_size (salen));
+ struct _mu_acl_entry *p = malloc (sizeof (*p));
if (!p)
return EINVAL;
p->action = action;
p->arg = data;
- p->netmask = ntohl (netmask);
- p->salen = salen;
- memcpy (p->sa, sa, salen);
- if (prepare_sa (p->sa))
- {
- free (p);
- return EINVAL;
- }
+ memcpy (&p->cidr, cidr, sizeof (p->cidr));
+
*pent = p;
return 0;
}
@@ -165,15 +138,14 @@ mu_acl_get_iterator (mu_acl_t acl, mu_iterator_t *pitr)
int
mu_acl_append (mu_acl_t acl, mu_acl_action_t act,
- void *data, struct sockaddr *sa, int salen,
- unsigned long netmask)
+ void *data, struct mu_cidr *cidr)
{
int rc;
struct _mu_acl_entry *ent;
if (!acl)
return EINVAL;
- rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+ rc = mu_acl_entry_create (&ent, act, data, cidr);
if (rc)
{
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
@@ -193,14 +165,14 @@ mu_acl_append (mu_acl_t acl, mu_acl_action_t act,
int
mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data,
- struct sockaddr *sa, int salen, unsigned long netmask)
+ struct mu_cidr *cidr)
{
int rc;
struct _mu_acl_entry *ent;
if (!acl)
return EINVAL;
- rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+ rc = mu_acl_entry_create (&ent, act, data, cidr);
if (rc)
{
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
@@ -219,8 +191,7 @@ mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data,
int
mu_acl_insert (mu_acl_t acl, size_t pos, int before,
- mu_acl_action_t act, void *data,
- struct sockaddr *sa, int salen, unsigned long netmask)
+ mu_acl_action_t act, void *data, struct mu_cidr *cidr)
{
int rc;
void *ptr;
@@ -236,7 +207,7 @@ mu_acl_insert (mu_acl_t acl, size_t pos, int before,
("No such entry %lu", (unsigned long) pos));
return rc;
}
- rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+ rc = mu_acl_entry_create (&ent, act, data, cidr);
if (!ent)
{
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
@@ -279,124 +250,19 @@ mu_acl_string_to_action (const char *str, mu_acl_action_t *pres)
return rc;
}
-#define MU_S_UN_NAME(sa, salen) \
- ((salen < mu_offsetof (struct sockaddr_un,sun_path)) ? "" : (sa)->sun_path)
-
-static void
-debug_sockaddr (struct sockaddr *sa, int salen)
-{
- switch (sa->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in s_in = *(struct sockaddr_in *)sa;
- s_in.sin_addr.s_addr = htonl (s_in.sin_addr.s_addr);
- mu_debug_log_cont ("{AF_INET %s:%d}",
- inet_ntoa (s_in.sin_addr), ntohs (s_in.sin_port));
- break;
- }
-
- case AF_UNIX:
- {
- struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
- if (MU_S_UN_NAME(s_un, salen)[0] == 0)
- mu_debug_log_cont ("{AF_UNIX}");
- else
- mu_debug_log_cont ("{AF_UNIX %s}", s_un->sun_path);
- break;
- }
-
- default:
- mu_debug_log_cont ("{Unsupported family: %d}", sa->sa_family);
- }
-}
-
-size_t
-mu_stpcpy (char **pbuf, size_t *psize, const char *src)
-{
- size_t slen = strlen (src);
- if (pbuf == NULL || *pbuf == NULL)
- return slen;
- else
- {
- char *buf = *pbuf;
- size_t size = *psize;
- if (size > slen)
- size = slen;
- memcpy (buf, src, size);
- *psize -= size;
- *pbuf += size;
- if (*psize)
- **pbuf = 0;
- else
- (*pbuf)[-1] = 0;
- return size;
- }
-}
-
-void
-mu_sockaddr_to_str (const struct sockaddr *sa, int salen,
- char *bufptr, size_t buflen,
- size_t *plen)
+struct run_closure
{
- char *nbuf;
- size_t len = 0;
- switch (sa->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in s_in = *(struct sockaddr_in *)sa;
- len += mu_stpcpy (&bufptr, &buflen, inet_ntoa (s_in.sin_addr));
- len += mu_stpcpy (&bufptr, &buflen, ":");
- if (mu_asprintf (&nbuf, "%hu", ntohs (s_in.sin_port)) == 0)
- {
- len += mu_stpcpy (&bufptr, &buflen, nbuf);
- free (nbuf);
- }
- break;
- }
-
- case AF_UNIX:
- {
- struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
- if (MU_S_UN_NAME(s_un, salen)[0] == 0)
- len += mu_stpcpy (&bufptr, &buflen, "anonymous socket");
- else
- {
- len += mu_stpcpy (&bufptr, &buflen, "socket ");
- len += mu_stpcpy (&bufptr, &buflen, s_un->sun_path);
- }
- break;
- }
-
- default:
- len += mu_stpcpy (&bufptr, &buflen, "{Unsupported family");
- if (mu_asprintf (&nbuf, ": %d", sa->sa_family) == 0)
- {
- len += mu_stpcpy (&bufptr, &buflen, nbuf);
- free (nbuf);
- }
- len += mu_stpcpy (&bufptr, &buflen, "}");
- }
- if (plen)
- *plen = len + 1;
-}
+ unsigned idx;
+ struct mu_cidr addr;
-char *
-mu_sockaddr_to_astr (const struct sockaddr *sa, int salen)
-{
- size_t size;
- char *p;
-
- mu_sockaddr_to_str (sa, salen, NULL, 0, &size);
- p = malloc (size);
- if (p)
- mu_sockaddr_to_str (sa, salen, p, size, NULL);
- return p;
-}
+ char ipstr[40];
+ char *addrstr;
+ char *numbuf;
+ mu_acl_result_t *result;
+};
int
-_acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen)
+_acl_match (struct _mu_acl_entry *ent, struct run_closure *rp)
{
#define RESMATCH(word) \
if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) \
@@ -404,76 +270,26 @@ _acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen)
if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
{
- struct in_addr a;
-
- mu_debug_log_begin ("Does ");
- debug_sockaddr (sa, salen);
- mu_debug_log_cont (" match ");
- debug_sockaddr (ent->sa, salen);
- a.s_addr = ent->netmask;
- a.s_addr = htonl (a.s_addr);
- mu_debug_log_cont (" netmask %s? ", inet_ntoa (a));
+ char *s;
+
+ if (ent->cidr.len == 0)
+ s = strdup ("any");
+ mu_cidr_format (&ent->cidr, 0, &s);
+ if (!rp->addrstr)
+ mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr);
+ mu_debug_log_begin ("Does %s match %s? ", s, rp->addrstr);
+ free (s);
}
- if (ent->sa->sa_family != sa->sa_family)
+ if (ent->cidr.len > 0 && mu_cidr_match (&ent->cidr, &rp->addr))
{
RESMATCH ("no");
return 1;
}
-
- switch (ent->sa->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in *sin_ent = (struct sockaddr_in *)ent->sa;
- struct sockaddr_in *sin_item = (struct sockaddr_in *)sa;
-
- if (sin_ent->sin_addr.s_addr !=
- (sin_item->sin_addr.s_addr & ent->netmask))
- {
- RESMATCH ("no (address differs)");
- return 1;
- }
-
- if (sin_ent->sin_port && sin_item->sin_port
- && sin_ent->sin_port != sin_item->sin_port)
- {
- RESMATCH ("no (port differs)");
- return 1;
- }
- break;
- }
-
- case AF_UNIX:
- {
- struct sockaddr_un *sun_ent = (struct sockaddr_un *)ent->sa;
- struct sockaddr_un *sun_item = (struct sockaddr_un *)sa;
-
- if (MU_S_UN_NAME (sun_ent, ent->salen)[0]
- && MU_S_UN_NAME (sun_item, salen)[0]
- && strcmp (sun_ent->sun_path, sun_item->sun_path))
- {
- RESMATCH ("no");
- return 1;
- }
- break;
- }
- }
-
RESMATCH ("yes");
return 0;
}
-struct run_closure
-{
- unsigned idx;
- struct sockaddr *sa;
- char *numbuf;
- char *portbuf;
- int salen;
- mu_acl_result_t *result;
-};
-
#define SEQ(s, n, l) \
(((l) == (sizeof(s) - 1)) && memcmp (s, n, l) == 0)
@@ -489,40 +305,24 @@ acl_getvar (const char *name, size_t nlen, void *data)
return rp->numbuf;
}
- switch (rp->sa->sa_family)
+ if (SEQ ("address", name, nlen))
{
- case AF_INET:
- {
- struct sockaddr_in *s_in = (struct sockaddr_in *)rp->sa;
-
- if (SEQ ("address", name, nlen))
- {
- struct in_addr addr = s_in->sin_addr;
- addr.s_addr = htonl (addr.s_addr);
- return inet_ntoa (addr);
- }
+ if (!rp->addrstr)
+ mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr);
+ return rp->addrstr;
+ }
- if (SEQ ("port", name, nlen))
- {
- if (!rp->portbuf &&
- mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port)))
- return NULL;
- return rp->portbuf;
- }
- break;
-
- case AF_UNIX:
- if (SEQ ("address", name, nlen))
- {
- struct sockaddr_un *s_un = (struct sockaddr_un *)rp->sa;
- if (rp->salen == sizeof (s_un->sun_family))
- return NULL;
- else
- return s_un->sun_path;
- }
- }
- break;
+#if 0
+ /* FIXME?: */
+ if (SEQ ("port", name, nlen))
+ {
+ if (!rp->portbuf &&
+ mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port)))
+ return NULL;
+ return rp->portbuf;
}
+#endif
+
return NULL;
}
@@ -535,12 +335,18 @@ expand_arg (const char *cmdline, struct run_closure *rp, char **s)
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_TRACE, ("Expanding \"%s\"", cmdline));
env[0] = "family";
- switch (rp->sa->sa_family)
+ switch (rp->addr.family)
{
case AF_INET:
env[1] = "AF_INET";
break;
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ env[1] = "AF_INET6";
+ break;
+#endif
+
case AF_UNIX:
env[1] = "AF_UNIX";
break;
@@ -654,7 +460,7 @@ _run_entry (void *item, void *data)
mu_debug_log_begin ("%d:%s: ", rp->idx, s);
}
- if (_acl_match (ent, rp->sa, rp->salen) == 0)
+ if (_acl_match (ent, rp) == 0)
{
switch (ent->action)
{
@@ -678,8 +484,10 @@ _run_entry (void *item, void *data)
}
else
{
- debug_sockaddr (rp->sa, rp->salen);
- mu_debug_log_nl ();
+ if (!rp->addrstr)
+ mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY,
+ &rp->addrstr);
+ mu_diag_output (MU_DIAG_INFO, "%s", rp->addrstr);
}
}
break;
@@ -712,7 +520,7 @@ _run_entry (void *item, void *data)
}
if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
- mu_debug_log_nl ();
+ mu_stream_flush (mu_strerr);
return status;
}
@@ -721,40 +529,39 @@ int
mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen,
mu_acl_result_t *pres)
{
+ int rc;
struct run_closure r;
if (!acl)
return EINVAL;
- r.sa = malloc (salen);
- if (!r.sa)
- return ENOMEM;
- memcpy (r.sa, sa, salen);
- if (prepare_sa (r.sa))
+ memset (&r, 0, sizeof (r));
+ if (sa->sa_family == AF_UNIX)
{
- free (r.sa);
- return EINVAL;
+ *pres = mu_acl_result_accept;
+ return 0;
}
- r.salen = salen;
+ rc = mu_cidr_from_sockaddr (&r.addr, sa);
+ if (rc)
+ return rc;
if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
{
- mu_debug_log_begin ("Checking sockaddr ");
- debug_sockaddr (r.sa, r.salen);
+ mu_cidr_format (&r.addr, MU_CIDR_FMT_ADDRONLY, &r.addrstr);
+ mu_debug_log_begin ("Checking sockaddr %s", r.addrstr);
mu_debug_log_nl ();
}
r.idx = 0;
r.result = pres;
*r.result = mu_acl_result_undefined;
- r.numbuf = r.portbuf = NULL;
+ r.numbuf = NULL;
mu_list_do (acl->aclist, _run_entry, &r);
free (r.numbuf);
- free (r.portbuf);
- free (r.sa);
+ free (r.addrstr);
return 0;
}
-
+
int
mu_acl_check_inaddr (mu_acl_t acl, const struct in_addr *inp,
mu_acl_result_t *pres)
@@ -780,10 +587,17 @@ mu_acl_check_ipv4 (mu_acl_t acl, unsigned int addr, mu_acl_result_t *pres)
int
mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres)
{
- struct sockaddr_in cs;
- socklen_t len = sizeof cs;
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifdef MAILUTILS_IPV6
+ struct sockaddr_in6 in6;
+#endif
+ } addr;
+ socklen_t len = sizeof addr;
- if (getpeername (fd, (struct sockaddr *) &cs, &len) < 0)
+ if (getpeername (fd, &addr.sa, &len) < 0)
{
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
("Cannot obtain IP address of client: %s",
@@ -791,6 +605,6 @@ mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres)
return MU_ERR_FAILURE;
}
- return mu_acl_check_sockaddr (acl, (struct sockaddr *) &cs, len, pres);
+ return mu_acl_check_sockaddr (acl, &addr.sa, len, pres);
}
diff --git a/libmailutils/server/ipsrv.c b/libmailutils/server/ipsrv.c
index a80290834..73b2e361e 100644
--- a/libmailutils/server/ipsrv.c
+++ b/libmailutils/server/ipsrv.c
@@ -34,13 +34,13 @@
#include <mailutils/diag.h>
#include <mailutils/errno.h>
#include <mailutils/nls.h>
+#include <mailutils/sockaddr.h>
struct _mu_ip_server
{
char *ident;
- struct sockaddr *addr;
- int addrlen;
+ struct mu_sockaddr *addr;
int fd;
int type;
mu_acl_t acl;
@@ -66,8 +66,7 @@ struct _mu_ip_server
#define IDENTSTR(s) ((s)->ident ? (s)->ident : "default")
int
-mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr,
- int addrlen, int type)
+mu_ip_server_create (mu_ip_server_t *psrv, struct mu_sockaddr *addr, int type)
{
struct _mu_ip_server *srv;
@@ -84,14 +83,7 @@ mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr,
srv = calloc (1, sizeof *srv);
if (!srv)
return ENOMEM;
- srv->addr = calloc (1, addrlen);
- if (!srv->addr)
- {
- free (srv);
- return ENOMEM;
- }
- memcpy (srv->addr, addr, addrlen);
- srv->addrlen = addrlen;
+ srv->addr = addr;
srv->type = type;
srv->fd = -1;
switch (type)
@@ -120,7 +112,7 @@ mu_ip_server_destroy (mu_ip_server_t *psrv)
if (srv->f_free)
srv->f_free (srv->data);
close (srv->fd);
- free (srv->addr);
+ mu_sockaddr_free (srv->addr);
free (srv->ident);
if (srv->type == MU_IP_UDP && srv->v.udp_data.buf)
free (srv->v.udp_data.buf);
@@ -234,6 +226,11 @@ mu_address_family_to_domain (int family)
case AF_INET:
return PF_INET;
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ return PF_INET6;
+#endif
+
default:
abort ();
}
@@ -247,14 +244,11 @@ mu_ip_server_open (mu_ip_server_t srv)
if (!srv || srv->fd != -1)
return EINVAL;
- if (mu_debug_level_p (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0))
- {
- char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
- mu_debug_log ("opening server \"%s\" %s", IDENTSTR (srv), p);
- free (p);
- }
+ mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0,
+ ("opening server \"%s\" %s", IDENTSTR (srv),
+ mu_sockaddr_str (srv->addr)));
- fd = socket (mu_address_family_to_domain (srv->addr->sa_family),
+ fd = socket (mu_address_family_to_domain (srv->addr->addr->sa_family),
((srv->type == MU_IP_UDP) ? SOCK_DGRAM : SOCK_STREAM), 0);
if (fd == -1)
{
@@ -263,7 +257,7 @@ mu_ip_server_open (mu_ip_server_t srv)
return errno;
}
- switch (srv->addr->sa_family)
+ switch (srv->addr->addr->sa_family)
{
case AF_UNIX:
{
@@ -299,7 +293,7 @@ mu_ip_server_open (mu_ip_server_t srv)
}
break;
- case AF_INET:
+ default:
{
int t;
@@ -308,7 +302,7 @@ mu_ip_server_open (mu_ip_server_t srv)
}
}
- if (bind (fd, srv->addr, srv->addrlen) == -1)
+ if (bind (fd, srv->addr->addr, srv->addr->addrlen) == -1)
{
mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
("%s: bind: %s", IDENTSTR (srv), mu_strerror (errno)));
@@ -336,12 +330,9 @@ mu_ip_server_shutdown (mu_ip_server_t srv)
{
if (!srv || srv->fd != -1)
return EINVAL;
- if (mu_debug_level_p (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0))
- {
- char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
- mu_debug_log ("closing server \"%s\" %s", IDENTSTR (srv), p);
- free (p);
- }
+ mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0,
+ ("closing server \"%s\" %s", IDENTSTR (srv),
+ mu_sockaddr_str (srv->addr)));
close (srv->fd);
return 0;
}
@@ -356,6 +347,9 @@ mu_ip_tcp_accept (mu_ip_server_t srv, void *call_data)
struct sockaddr sa;
struct sockaddr_in s_in;
struct sockaddr_un s_un;
+#ifdef MAILUTILS_IPV6
+ struct sockaddr_in6 s_in6;
+#endif
} client;
socklen_t size = sizeof (client);
@@ -407,6 +401,9 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
struct sockaddr sa;
struct sockaddr_in s_in;
struct sockaddr_un s_un;
+#ifdef MAILUTILS_IPV6
+ struct sockaddr_in6 s_in6;
+#endif
} client;
fd_set rdset;
@@ -463,7 +460,7 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
IDENTSTR (srv), strerror (rc)));
if (res == mu_acl_result_deny)
{
- char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
+ char *p = mu_sockaddr_to_astr (&client.sa, salen);
mu_diag_output (MU_DIAG_INFO, "Denying connection from %s", p);
free (p);
return 0;
@@ -528,22 +525,16 @@ mu_udp_server_get_rdata (mu_ip_server_t srv, char **pbuf, size_t *pbufsize)
}
int
-mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct sockaddr *s, int *size)
+mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct mu_sockaddr **psa)
{
- int len;
-
- if (!srv || !s)
+ if (!srv || !psa)
return EINVAL;
- if (s == 0)
- len = srv->addrlen;
- else
- {
- len = srv->addrlen;
- if (*size < len)
- return MU_ERR_BUFSPACE;
- memcpy (s, srv->addr, len);
- }
- *size = len;
- return 0;
+ return mu_sockaddr_copy (psa, srv->addr);
}
-
+
+const char *
+mu_ip_server_addrstr (mu_ip_server_t srv)
+{
+ return mu_sockaddr_str (srv->addr);
+}
+
diff --git a/libmailutils/server/msrv.c b/libmailutils/server/msrv.c
index 5c46e9d70..d5ceb8a39 100644
--- a/libmailutils/server/msrv.c
+++ b/libmailutils/server/msrv.c
@@ -41,6 +41,8 @@
#include <mailutils/nls.h>
#include <mailutils/daemon.h>
#include <mailutils/acl.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/url.h>
typedef RETSIGTYPE (*mu_sig_handler_t) (int);
@@ -65,19 +67,6 @@ set_signal (int sig, mu_sig_handler_t handler)
# define NSIG 64
#endif
-union m_sockaddr
-{
- struct sockaddr s_sa;
- struct sockaddr_in s_in;
- struct sockaddr_un s_un;
-};
-
-struct m_default_address
-{
- union m_sockaddr s;
- int len;
-};
-
struct _mu_m_server
{
char *ident; /* Server identifier, for logging purposes.*/
@@ -98,7 +87,7 @@ struct _mu_m_server
size_t num_children; /* Current number of running sub-processes. */
pid_t *child_pid;
char *pidfile; /* Name of a PID-file. */
- struct m_default_address defaddr; /* Default address. */
+ struct mu_sockaddr_hints hints; /* Default address hints. */
time_t timeout; /* Default idle timeout. */
mu_acl_t acl; /* Global access control list. */
@@ -112,7 +101,7 @@ struct _mu_m_server
struct m_srv_config /* Configuration data for a single TCP server. */
{
mu_m_server_t msrv; /* Parent m-server. */
- mu_ip_server_t tcpsrv; /* TCP server these data are for. */
+ mu_ip_server_t tcpsrv; /* TCP server these data are for. */
mu_acl_t acl; /* Access control list for this server. */
int single_process; /* Should it run as a single process? */
int transcript; /* Enable session transcript. */
@@ -395,33 +384,20 @@ mu_m_server_pidfile (mu_m_server_t srv)
}
void
-mu_m_server_set_default_address (mu_m_server_t srv, struct sockaddr *sa,
- int salen)
+mu_m_server_set_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints)
{
- if (salen > sizeof srv->defaddr.s)
- {
- mu_error (_("unhandled sockaddr size"));
- abort ();
- }
- memcpy (&srv->defaddr.s.s_sa, sa, salen);
- srv->defaddr.len = salen;
+ if (!hints)
+ memset (&srv->hints, 0, sizeof (srv->hints));
+ else
+ memcpy (&srv->hints, hints, sizeof (srv->hints));
}
int
-mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa,
- int *salen)
+mu_m_server_get_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints)
{
- int len;
-
- if (!sa)
+ if (!hints)
return EINVAL;
- len = srv->defaddr.len;
- if (sa)
- {
- if (*salen < len)
- return MU_ERR_BUFSPACE;
- memcpy (sa, &srv->defaddr.s.s_sa, len);
- }
+ memcpy (hints, &srv->hints, sizeof (hints));
return 0;
}
@@ -429,11 +405,7 @@ mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa,
void
mu_m_server_set_default_port (mu_m_server_t srv, int num)
{
- struct sockaddr_in s_in;
- s_in.sin_family = AF_INET;
- s_in.sin_addr.s_addr = htonl (INADDR_ANY);
- s_in.sin_port = htons (num);
- mu_m_server_set_default_address (srv, (struct sockaddr*) &s_in, sizeof s_in);
+ srv->hints.port = num;
}
void
@@ -473,12 +445,12 @@ static int m_srv_conn (int fd, struct sockaddr *sa, int salen,
mu_ip_server_t srv);
static struct m_srv_config *
-add_server (mu_m_server_t msrv, struct sockaddr *s, int slen, int type)
+add_server (mu_m_server_t msrv, struct mu_sockaddr *s, int type)
{
mu_ip_server_t tcpsrv;
struct m_srv_config *pconf;
- MU_ASSERT (mu_ip_server_create (&tcpsrv, s, slen, type)); /* FIXME: type */
+ MU_ASSERT (mu_ip_server_create (&tcpsrv, s, type)); /* FIXME: type */
MU_ASSERT (mu_ip_server_set_conn (tcpsrv, m_srv_conn));
pconf = calloc (1, sizeof (*pconf));
if (!pconf)
@@ -513,8 +485,21 @@ mu_m_server_begin (mu_m_server_t msrv)
alloc_children (msrv);
mu_list_count (msrv->srvlist, &count);
- if (count == 0 && msrv->defaddr.len)
- add_server (msrv, &msrv->defaddr.s.s_sa, msrv->defaddr.len, msrv->deftype);
+ if (count == 0)
+ {
+ struct mu_sockaddr *ta;
+
+ msrv->hints.flags = MU_AH_PASSIVE;
+ rc = mu_sockaddr_from_node (&ta, NULL, NULL, &msrv->hints);
+ if (rc == 0)
+ while (ta)
+ {
+ struct mu_sockaddr *next = ta->next;
+ ta->next = ta->prev = NULL;
+ add_server (msrv, ta, msrv->deftype);
+ ta = next;
+ }
+ }
if (!msrv->foreground)
{
@@ -599,23 +584,13 @@ tcp_conn_free (void *conn_data, void *server_data)
static int
_open_conn (void *item, void *data)
{
- union
- {
- struct sockaddr sa;
- char pad[512];
- }
- addr;
- int addrlen = sizeof addr;
- char *p;
mu_ip_server_t tcpsrv = item;
mu_m_server_t msrv = data;
int rc = mu_ip_server_open (tcpsrv);
if (rc)
{
- mu_ip_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen);
- p = mu_sockaddr_to_astr (&addr.sa, addrlen);
- mu_error (_("cannot open connection on %s: %s"), p, mu_strerror (rc));
- free (p);
+ mu_error (_("cannot open connection on %s: %s"),
+ mu_ip_server_addrstr (tcpsrv), mu_strerror (rc));
return 0;
}
rc = mu_server_add_connection (msrv->server,
@@ -624,10 +599,8 @@ _open_conn (void *item, void *data)
tcp_conn_handler, tcp_conn_free);
if (rc)
{
- mu_ip_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen);
- p = mu_sockaddr_to_astr (&addr.sa, addrlen);
- mu_error (_("cannot add connection %s: %s"), p, mu_strerror (rc));
- free (p);
+ mu_error (_("cannot add connection %s: %s"),
+ mu_ip_server_addrstr (tcpsrv), mu_strerror (rc));
mu_ip_server_shutdown (tcpsrv);
mu_ip_server_destroy (&tcpsrv);
}
@@ -756,199 +729,55 @@ m_srv_conn (int fd, struct sockaddr *sa, int salen,
}
-
-unsigned short
-get_port (const char *p)
-{
- if (p)
- {
- char *q;
- unsigned long n = strtoul (p, &q, 0);
- if (*q == 0)
- {
- if (n > USHRT_MAX)
- {
- mu_error (_("invalid port number: %s"), p);
- return 1;
- }
-
- return htons (n);
- }
- else
- {
- struct servent *sp = getservbyname (p, "tcp");
- if (!sp)
- return 0;
- return sp->s_port;
- }
- }
- return 0;
-}
-
-static int
-get_family (const char **pstr, sa_family_t *pfamily)
-{
- static struct family_tab
- {
- int len;
- char *pfx;
- int family;
- } ftab[] = {
-#define S(s,f) { sizeof (#s":") - 1, #s":", f }
- S (file, AF_UNIX),
- S (unix, AF_UNIX),
- S (local, AF_UNIX),
- S (socket, AF_UNIX),
- S (inet, AF_INET),
- S (tcp, AF_INET),
-#undef S
- { 0 }
- };
- struct family_tab *fp;
-
- const char *str = *pstr;
- int len = strlen (str);
- for (fp = ftab; fp->len; fp++)
- {
- if (len > fp->len && memcmp (str, fp->pfx, fp->len) == 0)
- {
- str += fp->len;
- if (str[0] == '/' && str[1] == '/')
- str += 2;
- *pstr = str;
- *pfamily = fp->family;
- return 0;
- }
- }
- return 1;
-}
-
-static int
-is_ip_addr (const char *arg)
-{
- int dot_count;
- int digit_count;
-
- dot_count = 0;
- digit_count = 0;
- for (; *arg != 0 && *arg != ':'; arg++)
- {
- if (*arg == '.')
- {
- if (++dot_count > 3)
- break;
- digit_count = 0;
- }
- else if (!(mu_isdigit (*arg) && ++digit_count <= 3))
- return 0;
- }
- return dot_count == 3;
-}
-
int
-_mu_m_server_parse_url (const char *arg, union m_sockaddr *s,
- int *psalen, struct sockaddr *defsa)
+mu_m_server_parse_url (mu_m_server_t msrv, const char *arg,
+ struct mu_sockaddr **psa)
{
- char *p;
- unsigned short n;
- int len;
-
- if (is_ip_addr (arg))
- s->s_sa.sa_family = AF_INET;
- else if (get_family (&arg, &s->s_sa.sa_family))
+ int rc;
+ mu_url_t url, url_hint;
+
+ if (arg[0] == '/')
+ url_hint = NULL;
+ else
{
- mu_error (_("invalid family"));
- return EINVAL;
+ rc = mu_url_create (&url_hint, "inet://");
+ if (rc)
+ return rc;
}
-
- switch (s->s_sa.sa_family)
+ rc = mu_url_create_hint (&url, arg, MU_URL_PARSE_DEFAULT, url_hint);
+ mu_url_destroy (&url_hint);
+ if (rc)
{
- case AF_INET:
- *psalen = sizeof (s->s_in);
- if ((n = get_port (arg)))
- {
- s->s_in.sin_addr.s_addr = htonl (INADDR_ANY);
- s->s_in.sin_port = htons (n);
- }
- else
- {
- p = strchr (arg, ':');
- if (p)
- *p++ = 0;
- if (inet_aton (arg, &s->s_in.sin_addr) == 0)
- {
- struct hostent *hp = gethostbyname (arg);
- if (hp)
- s->s_in.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
- else
- {
- mu_error (_("invalid IP address: %s"), arg);
- return EINVAL;
- }
- }
- if (p)
- {
- n = get_port (p);
- if (!n)
- {
- mu_error (_("invalid port number: %s"), p);
- return EINVAL;
- }
- s->s_in.sin_port = n;
- }
- else if (defsa && defsa->sa_family == AF_INET)
- s->s_in.sin_port = ((struct sockaddr_in*)defsa)->sin_port;
- else
- {
- mu_error (_("missing port number"));
- return EINVAL;
- }
- }
- break;
-
- case AF_UNIX:
- *psalen = sizeof (s->s_un);
- len = strlen (arg);
- if (len > sizeof s->s_un.sun_path - 1)
- {
- mu_error (_("%s: file name too long"), arg);
- return EINVAL;
- }
- strcpy (s->s_un.sun_path, arg);
- break;
+ mu_error (_("cannot parse URL `%s': %s"), arg, mu_strerror (rc));
+ return rc;
}
- return 0;
-}
-
-int
-mu_m_server_parse_url (mu_m_server_t msrv, char *arg,
- struct sockaddr *sa, int *psalen)
-{
- int rc;
- union m_sockaddr s;
- int salen;
- rc = _mu_m_server_parse_url (arg, &s, &salen, &msrv->defaddr.s.s_sa);
+ msrv->hints.flags = MU_AH_PASSIVE;
+ rc = mu_sockaddr_from_url (psa, url, &msrv->hints);
if (rc)
- return rc;
- if (sa)
- {
- if (*psalen < salen)
- return MU_ERR_BUFSPACE;
- memcpy (sa, &s.s_sa, salen);
- }
- *psalen = salen;
- return 0;
+ mu_error (_("cannot create sockaddr for URL `%s': %s"), arg,
+ mu_strerror (rc));
+ mu_url_destroy (&url);
+ return rc;
}
static int
server_block_begin (const char *arg, mu_m_server_t msrv, void **pdata)
{
- union m_sockaddr s;
- int salen;
- if (_mu_m_server_parse_url (arg, &s, &salen, &msrv->defaddr.s.s_sa))
+ struct mu_sockaddr *s;
+ if (mu_m_server_parse_url (msrv, arg, &s))
return 1;
- *pdata = add_server (msrv, &s.s_sa, salen, msrv->deftype);
+ if (s->next)
+ {
+ /* FIXME: (1) Find a way to handle all addresses.
+ (2) Print which address is being used.
+ */
+ mu_diag_output (MU_DIAG_WARNING,
+ _("%s resolves to several addresses, "
+ "only the first is used"), arg);
+ mu_sockaddr_free (s->next);
+ }
+ *pdata = add_server (msrv, s, msrv->deftype);
return 0;
}
@@ -1002,21 +831,46 @@ _cb_daemon_mode (void *data, mu_config_value_t *val)
return 0;
}
+unsigned short
+get_port (const char *p)
+{
+ if (p)
+ {
+ char *q;
+ unsigned long n = strtoul (p, &q, 0);
+ if (*q == 0)
+ {
+ if (n > USHRT_MAX)
+ {
+ mu_error (_("invalid port number: %s"), p);
+ return 1;
+ }
+
+ return htons (n);
+ }
+ else
+ {
+ struct servent *sp = getservbyname (p, "tcp");
+ if (!sp)
+ return 0;
+ return sp->s_port;
+ }
+ }
+ return 0;
+}
+
static int
_cb_port (void *data, mu_config_value_t *val)
{
- struct m_default_address *ap = data;
+ struct mu_sockaddr_hints *hp = data;
unsigned short num;
-
+
if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
return 1;
num = get_port (val->v.string);
if (!num)
return 1;
- ap->s.s_in.sin_family = AF_INET;
- ap->s.s_in.sin_addr.s_addr = htonl (INADDR_ANY);
- ap->s.s_in.sin_port = num;
- ap->len = sizeof ap->s.s_in;
+ hp->port = num;
return 0;
}
@@ -1036,7 +890,7 @@ static struct mu_cfg_param dot_server_cfg_param[] = {
N_("Store PID of the master process in this file."),
N_("file") },
{ "port", mu_cfg_callback,
- NULL, mu_offsetof (struct _mu_m_server,defaddr), _cb_port,
+ NULL, mu_offsetof (struct _mu_m_server, hints), _cb_port,
N_("Default port number.") },
{ "timeout", mu_cfg_time,
NULL, mu_offsetof (struct _mu_m_server,timeout), NULL,
diff --git a/libmailutils/sockaddr/Makefile.am b/libmailutils/sockaddr/Makefile.am
new file mode 100644
index 000000000..dcfb18446
--- /dev/null
+++ b/libmailutils/sockaddr/Makefile.am
@@ -0,0 +1,31 @@
+# GNU Mailutils -- a suite of utilities for electronic mail
+# Copyright (C) 2011 Free Software Foundation, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General
+# Public License along with this library. If not, see
+# <http://www.gnu.org/licenses/>.
+
+noinst_LTLIBRARIES = libsockaddr.la
+
+libsockaddr_la_SOURCES = \
+ copy.c\
+ create.c\
+ free.c\
+ fromnode.c\
+ insert.c\
+ ipaddr.c\
+ str.c\
+ unlink.c\
+ url.c
+
+INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
diff --git a/libmailutils/sockaddr/copy.c b/libmailutils/sockaddr/copy.c
new file mode 100644
index 000000000..5e28e7857
--- /dev/null
+++ b/libmailutils/sockaddr/copy.c
@@ -0,0 +1,36 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/sockaddr.h>
+
+int
+mu_sockaddr_copy (struct mu_sockaddr **pnew, struct mu_sockaddr *old)
+{
+ if (!old)
+ {
+ *pnew = NULL;
+ return 0;
+ }
+ return mu_sockaddr_create (pnew, old->addr, old->addrlen);
+}
+
+
diff --git a/libmailutils/sockaddr/create.c b/libmailutils/sockaddr/create.c
new file mode 100644
index 000000000..5b49471e6
--- /dev/null
+++ b/libmailutils/sockaddr/create.c
@@ -0,0 +1,47 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <mailutils/sockaddr.h>
+
+int
+mu_sockaddr_create (struct mu_sockaddr **res,
+ struct sockaddr *addr, socklen_t len)
+{
+ struct mu_sockaddr *sa;
+
+ sa = calloc (1, sizeof (*sa));
+ if (!sa)
+ return ENOMEM;
+ sa->addr = malloc (len);
+ if (!sa->addr)
+ {
+ free (sa);
+ return ENOMEM;
+ }
+ memcpy (sa->addr, addr, len);
+ sa->addrlen = len;
+ *res = sa;
+ return 0;
+}
+
diff --git a/libmailutils/sockaddr/free.c b/libmailutils/sockaddr/free.c
new file mode 100644
index 000000000..2a31ec36d
--- /dev/null
+++ b/libmailutils/sockaddr/free.c
@@ -0,0 +1,50 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/sockaddr.h>
+
+void
+mu_sockaddr_free (struct mu_sockaddr *addr)
+{
+ if (!addr)
+ return;
+ free (addr->addr);
+ free (addr->str);
+}
+
+void
+mu_sockaddr_free_list (struct mu_sockaddr *addr)
+{
+ if (!addr)
+ return;
+ if (addr->prev)
+ addr->prev->next = NULL;
+ while (addr)
+ {
+ struct mu_sockaddr *next = addr->next;
+ mu_sockaddr_free (addr);
+ addr = next;
+ }
+}
+
+
+
diff --git a/libmailutils/sockaddr/fromnode.c b/libmailutils/sockaddr/fromnode.c
new file mode 100644
index 000000000..d79b9523a
--- /dev/null
+++ b/libmailutils/sockaddr/fromnode.c
@@ -0,0 +1,253 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/url.h>
+#include <mailutils/io.h>
+#include <mailutils/errno.h>
+#include <mailutils/error.h>
+#include <mailutils/nls.h>
+
+static struct mu_sockaddr *
+match_sa (struct mu_sockaddr *list, struct sockaddr *sa, socklen_t len)
+{
+ for (; list; list = list->next)
+ if (len == list->addrlen && memcmp (list->addr, sa, len) == 0)
+ break;
+ return list;
+}
+
+int
+mu_sockaddr_from_node (struct mu_sockaddr **retval, const char *node,
+ const char *serv, struct mu_sockaddr_hints *mh)
+{
+ int rc;
+
+ if (!mh)
+ {
+ static struct mu_sockaddr_hints nullhints = { 0, AF_UNSPEC };
+ mh = &nullhints;
+ }
+
+ if (mh->family == AF_UNIX)
+ {
+ size_t slen;
+ struct sockaddr_un s_un;
+
+ if (!node)
+ return MU_ERR_NONAME;
+ slen = strlen (node);
+ if (slen >= sizeof s_un.sun_path)
+ return MU_ERR_BUFSPACE;
+
+ s_un.sun_family = AF_UNIX;
+ strcpy(s_un.sun_path, node);
+ return mu_sockaddr_create (retval, (struct sockaddr*) &s_un,
+ sizeof (s_un));
+ }
+ else
+#ifdef MAILUTILS_IPV6
+ {
+ struct addrinfo hints;
+ struct addrinfo *res, *ap;
+ char portbuf[64];
+ struct mu_sockaddr *tail = NULL;
+
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = mh->family;
+ hints.ai_socktype = mh->socktype;
+ hints.ai_protocol = mh->protocol;
+
+ if (!node)
+ {
+ if (mh->flags & MU_AH_PASSIVE)
+ hints.ai_flags |= AI_PASSIVE;
+ else
+ return MU_ERR_NONAME;
+ }
+ if (!serv && mh->port)
+ {
+ snprintf (portbuf, sizeof portbuf, "%hu", mh->port);
+ serv = portbuf;
+ }
+
+ rc = getaddrinfo (node, serv, &hints, &res);
+
+ switch (rc)
+ {
+ case 0:
+ break;
+
+ case EAI_FAIL:
+ return MU_ERR_GETHOSTBYNAME;
+
+ case EAI_FAMILY:
+ return MU_ERR_FAMILY;
+
+ case EAI_NONAME:
+ return MU_ERR_NONAME;
+
+ case EAI_SERVICE:
+ return MU_ERR_SERVICE;
+
+ case EAI_SYSTEM:
+ mu_error (_("%s:%s: cannot parse address: %s"),
+ node, serv, mu_strerror (errno));
+ return errno;
+
+ case EAI_BADFLAGS:
+ return MU_ERR_BADFLAGS;
+
+ case EAI_SOCKTYPE:
+ return MU_ERR_SOCKTYPE;
+
+ case EAI_MEMORY:
+ return ENOMEM;
+
+ default:
+ mu_error ("%s:%s: %s", node, serv, gai_strerror (rc));
+ return MU_ERR_FAILURE;
+ }
+
+ *retval = NULL;
+ for (ap = res; ap; ap = ap->ai_next)
+ if (mh->family == AF_UNSPEC || ap->ai_addr->sa_family == mh->family)
+ {
+ struct mu_sockaddr *sa;
+
+ if (match_sa (*retval, ap->ai_addr, ap->ai_addrlen))
+ continue;
+ rc = mu_sockaddr_create (&sa, ap->ai_addr, ap->ai_addrlen);
+ if (rc)
+ {
+ mu_sockaddr_free_list (*retval);
+ freeaddrinfo (res);
+ return rc;
+ }
+ if (tail)
+ mu_sockaddr_insert (tail, sa, 0);
+ else
+ *retval = sa;
+ tail = sa;
+ }
+ freeaddrinfo (res);
+ }
+#else
+ if (mh->family == AF_INET)
+ {
+ short port;
+ struct hostent *hp;
+ struct mu_sockaddr *tail = NULL;
+ char **p;
+
+ if (serv)
+ {
+ char *end;
+ unsigned long n = strtoul (serv, &end, 10);
+
+ if (*end)
+ {
+ struct servent *sp;
+ const char *proto;
+
+ if (mh->protocol)
+ {
+ struct protoent *pp = getprotobynumber (mh->protocol);
+ if (!pp)
+ return EINVAL;
+ proto = pp->p_name;
+ }
+ else
+ proto = NULL;
+
+ sp = getservbyname (serv, proto);
+ if (!sp)
+ return MU_ERR_SERVICE;
+ port = sp->s_port;
+ }
+ else if (n == 0 || (port = n) != n)
+ return MU_ERR_PARSE; /* FIXME: need MU_ERR_RANGE? */
+ }
+ else if (mh->port)
+ port = htons (mh->port);
+ else
+ return MU_ERR_NONAME;
+
+ if (!node)
+ {
+ struct sockaddr_in s_in;
+
+ if (!(mh->flags & MU_AH_PASSIVE))
+ return MU_ERR_NONAME;
+
+ s_in.sin_family = AF_INET;
+ s_in.sin_addr.s_addr = INADDR_ANY;
+ s_in.sin_port = port;
+ return mu_sockaddr_create (retval, (struct sockaddr*)&s_in,
+ sizeof (s_in));
+ }
+
+ hp = gethostbyname (node);
+ if (!hp)
+ return MU_ERR_GETHOSTBYNAME;
+
+ if (hp->h_addrtype != AF_INET || hp->h_length != 4)
+ return MU_ERR_FAMILY;
+
+ for (p = hp->h_addr_list; *p; p++)
+ {
+ struct mu_sockaddr *sa;
+ struct sockaddr_in s_in;
+
+ s_in.sin_family = AF_INET;
+ memcpy(&s_in.sin_addr, *p, 4);
+ s_in.sin_port = port;
+
+ rc = mu_sockaddr_create (&sa, (struct sockaddr*)&s_in,
+ sizeof (s_in));
+ if (rc)
+ {
+ mu_sockaddr_free_list (*retval);
+ return rc;
+ }
+ if (tail)
+ mu_sockaddr_insert (tail, sa, 0);
+ else
+ *retval = sa;
+ tail = sa;
+ }
+ }
+ else
+ return MU_ERR_FAMILY;
+#endif
+ return 0;
+}
diff --git a/libmailutils/sockaddr/insert.c b/libmailutils/sockaddr/insert.c
new file mode 100644
index 000000000..dbac151c1
--- /dev/null
+++ b/libmailutils/sockaddr/insert.c
@@ -0,0 +1,64 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/sockaddr.h>
+
+static void
+set_next (struct mu_sockaddr *sp, struct mu_sockaddr *tgt)
+{
+ for (; sp->next; sp = sp->next)
+ ;
+ sp->next = tgt;
+ if (tgt)
+ tgt->prev = sp;
+}
+
+struct mu_sockaddr *
+mu_sockaddr_insert (struct mu_sockaddr *anchor, struct mu_sockaddr *addr,
+ int before)
+{
+ struct mu_sockaddr *ret = anchor;
+
+ if (!anchor)
+ {
+ addr->prev = NULL;
+ set_next (addr, NULL);
+ return addr;
+ }
+
+ if (before)
+ {
+ if (anchor->prev)
+ anchor = anchor->prev;
+ else
+ {
+ addr->prev = NULL;
+ set_next (addr, anchor);
+ return addr;
+ }
+ }
+
+ set_next (addr, anchor->next);
+ anchor->next = addr;
+ addr->prev = anchor;
+ return ret;
+}
diff --git a/libmailutils/sockaddr/ipaddr.c b/libmailutils/sockaddr/ipaddr.c
new file mode 100644
index 000000000..6b14b4c29
--- /dev/null
+++ b/libmailutils/sockaddr/ipaddr.c
@@ -0,0 +1,88 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/cctype.h>
+
+int
+mu_str_is_ipv4 (const char *addr)
+{
+ int dot_count = 0;
+ int digit_count = 0;
+
+ for (; *addr; addr++)
+ {
+ if (!mu_isascii (*addr))
+ return 0;
+ if (*addr == '.')
+ {
+ if (++dot_count > 3)
+ break;
+ digit_count = 0;
+ }
+ else if (!(mu_isdigit (*addr) && ++digit_count <= 3))
+ return 0;
+ }
+
+ return (dot_count == 3);
+}
+
+int
+mu_str_is_ipv6 (const char *addr)
+{
+ int col_count = 0; /* Number of colons */
+ int dcol = 0; /* Did we encounter a double-colon? */
+ int dig_count = 0; /* Number of digits in the last group */
+
+ for (; *addr; addr++)
+ {
+ if (!mu_isascii (*addr))
+ return 0;
+ else if (mu_isxdigit (*addr))
+ {
+ if (++dig_count > 4)
+ return 0;
+ }
+ else if (*addr == ':')
+ {
+ if (col_count && dig_count == 0 && ++dcol > 1)
+ return 0;
+ if (++col_count > 7)
+ return 0;
+ dig_count = 0;
+ }
+ else
+ return 0;
+ }
+
+ return (col_count == 7 || dcol);
+}
+
+int
+mu_str_is_ipaddr (const char *addr)
+{
+ if (strchr (addr, '.'))
+ return mu_str_is_ipv4(addr);
+ else if (strchr (addr, ':'))
+ return mu_str_is_ipv6(addr);
+ return 0;
+}
diff --git a/libmailutils/sockaddr/str.c b/libmailutils/sockaddr/str.c
new file mode 100644
index 000000000..949f21ef9
--- /dev/null
+++ b/libmailutils/sockaddr/str.c
@@ -0,0 +1,109 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <mailutils/sockaddr.h>
+#include <mailutils/errno.h>
+#include <mailutils/io.h>
+
+static char *default_sockaddr_text = "[not enogh memory]";
+
+#define S_UN_NAME(sa, salen) \
+ ((salen < mu_offsetof(struct sockaddr_un,sun_path)) ? \
+ "" : (sa)->sun_path)
+
+int
+mu_sockaddr_format (char **pbuf, const struct sockaddr *sa, socklen_t salen)
+{
+ int rc = MU_ERR_FAILURE;
+
+ switch (sa->sa_family)
+ {
+#ifdef MAILUTILS_IPV6
+ case AF_INET:
+ case AF_INET6:
+ {
+ char host[NI_MAXHOST];
+ char srv[NI_MAXSERV];
+ if (getnameinfo (sa, salen,
+ host, sizeof (host), srv, sizeof (srv),
+ NI_NUMERICHOST|NI_NUMERICSERV) == 0)
+ {
+ if (sa->sa_family == AF_INET6)
+ rc = mu_asprintf (pbuf, "inet6://[%s]:%s", host, srv);
+ else
+ rc = mu_asprintf (pbuf, "inet://%s:%s", host, srv);
+ }
+ else
+ rc = mu_asprintf (pbuf, "%s://[getnameinfo failed]",
+ sa->sa_family == AF_INET ?
+ "inet" : "inet6");
+ break;
+ }
+#else
+ case AF_INET:
+ {
+ struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
+ rc = mu_asprintf (pbuf, "inet://%s:%hu",
+ inet_ntoa (s_in->sin_addr), s_in->sin_port);
+ break;
+ }
+#endif
+
+ case AF_UNIX:
+ {
+ struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
+ if (S_UN_NAME (s_un, salen)[0] == 0)
+ rc = mu_asprintf (pbuf, "unix://[anonymous socket]");
+ else
+ rc = mu_asprintf (pbuf, "unix://%s", s_un->sun_path);
+ break;
+ }
+
+ default:
+ rc = mu_asprintf (pbuf, "family:%d", sa->sa_family);
+ }
+ return rc;
+}
+
+char *
+mu_sockaddr_to_astr (const struct sockaddr *sa, int salen)
+{
+ char *buf = NULL;
+ mu_sockaddr_format (&buf, sa, salen);
+ return buf;
+}
+
+const char *
+mu_sockaddr_str (struct mu_sockaddr *sa)
+{
+ if (!sa->str && mu_sockaddr_format (&sa->str, sa->addr, sa->addrlen))
+ return default_sockaddr_text;
+ return sa->str;
+}
+
+
diff --git a/libmailutils/sockaddr/unlink.c b/libmailutils/sockaddr/unlink.c
new file mode 100644
index 000000000..65808f568
--- /dev/null
+++ b/libmailutils/sockaddr/unlink.c
@@ -0,0 +1,45 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/sockaddr.h>
+
+struct mu_sockaddr *
+mu_sockaddr_unlink (struct mu_sockaddr *addr)
+{
+ struct mu_sockaddr *p;
+
+ if (!addr)
+ return NULL;
+
+ p = addr->prev;
+ if (p)
+ p->next = addr->next;
+
+ p = addr->next;
+ if (p)
+ p->prev = addr->prev;
+
+ addr->prev = addr->next = NULL;
+
+ return p;
+}
+
diff --git a/libmailutils/sockaddr/url.c b/libmailutils/sockaddr/url.c
new file mode 100644
index 000000000..0eaf870be
--- /dev/null
+++ b/libmailutils/sockaddr/url.c
@@ -0,0 +1,130 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/url.h>
+#include <mailutils/io.h>
+#include <mailutils/errno.h>
+#include <mailutils/nls.h>
+#include <mailutils/kwd.h>
+
+static struct mu_kwd famtab[] = {
+ { "unix", AF_UNIX },
+ { "local", AF_UNIX },
+ { "inet4", AF_INET },
+#ifdef MAILUTILS_IPV6
+ { "inet6", AF_INET6 },
+ { "inet", AF_UNSPEC },
+#else
+ { "inet", AF_INET },
+#endif
+ { NULL }
+};
+
+int
+mu_sockaddr_from_url (struct mu_sockaddr **retval, mu_url_t url,
+ struct mu_sockaddr_hints *mh)
+{
+ int rc;
+ const char *scheme;
+ const char *node = NULL, *serv = NULL;
+ struct mu_sockaddr_hints hints;
+
+ if (mh)
+ memcpy (&hints, mh, sizeof (hints));
+ else
+ {
+ memset (&hints, sizeof(hints), 0);
+ hints.family = AF_UNSPEC;
+ hints.socktype = SOCK_STREAM;
+ hints.protocol = IPPROTO_TCP;
+ }
+
+ if (hints.family == AF_UNSPEC)
+ {
+ rc = mu_url_sget_scheme (url, &scheme);
+ if (rc)
+ return rc;
+
+ if (mu_kwd_xlat_name (famtab, scheme, &hints.family))
+ {
+ if (hints.flags & MU_AH_DETECT_FAMILY)
+ {
+ int flags = 0;
+
+ mu_url_get_flags (url, &flags);
+#ifdef MAILUTILS_IPV6
+ if (flags & MU_URL_IPV6)
+ hints.family = AF_INET6;
+ else
+#endif
+ if (flags & (MU_URL_HOST|MU_URL_PORT))
+ hints.family = AF_INET;
+ else if (flags & MU_URL_PATH)
+ hints.family = AF_UNIX;
+ else
+ return MU_ERR_FAMILY;
+ }
+ else
+ return MU_ERR_FAMILY;
+ }
+ }
+
+ if (hints.family == AF_UNIX)
+ {
+ rc = mu_url_sget_path (url, &node);
+ if (rc)
+ {
+ if (rc == MU_ERR_NOENT)
+ {
+ rc = mu_url_sget_host (url, &node);
+ if (rc == MU_ERR_NOENT)
+ return MU_ERR_NONAME;
+ }
+ if (rc)
+ return rc;
+ }
+ }
+ else
+ {
+#ifdef MAILUTILS_IPV6
+ if (hints.family == AF_UNSPEC)
+ hints.family = mu_url_has_flag (url, MU_URL_IPV6) ? AF_INET6 : AF_INET;
+#endif
+ rc = mu_url_sget_host (url, &node);
+ if (rc && rc != MU_ERR_NOENT)
+ return MU_ERR_NONAME;
+ rc = mu_url_sget_portstr (url, &serv);
+ if (rc && rc != MU_ERR_NOENT)
+ return MU_ERR_NONAME;
+ }
+ return mu_sockaddr_from_node (retval, node, serv, &hints);
+}
diff --git a/libmailutils/stream/tcp.c b/libmailutils/stream/tcp.c
index 40b37124d..f383f1b5a 100644
--- a/libmailutils/stream/tcp.c
+++ b/libmailutils/stream/tcp.c
@@ -39,7 +39,7 @@
#include <mailutils/errno.h>
#include <mailutils/stream.h>
#include <mailutils/util.h>
-
+#include <mailutils/sockaddr.h>
#include <mailutils/sys/stream.h>
#define TCP_STATE_INIT 1
@@ -52,18 +52,11 @@ struct _tcp_instance
{
struct _mu_stream stream;
int fd;
- char *host;
- unsigned short port;
int state;
- unsigned long address;
- unsigned long source_addr;
+ struct mu_sockaddr *remote_addr;
+ struct mu_sockaddr *source_addr;
};
-/* On solaris inet_addr() return -1. */
-#ifndef INADDR_NONE
-# define INADDR_NONE (unsigned long)-1
-#endif
-
static int
_tcp_close (mu_stream_t stream)
{
@@ -83,28 +76,12 @@ _tcp_close (mu_stream_t stream)
}
static int
-resolve_hostname (const char *host, unsigned long *ip)
-{
- unsigned long address = inet_addr (host);
- if (address == INADDR_NONE)
- {
- struct hostent *phe = gethostbyname (host);
- if (!phe)
- return MU_ERR_GETHOSTBYNAME;
- address = *(((unsigned long **) phe->h_addr_list)[0]);
- }
- *ip = address;
- return 0;
-}
-
-static int
_tcp_open (mu_stream_t stream)
{
struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
int flgs, ret;
socklen_t namelen;
struct sockaddr_in peer_addr;
- struct sockaddr_in soc_addr;
int flags;
mu_stream_get_flags (stream, &flags);
@@ -114,7 +91,8 @@ _tcp_open (mu_stream_t stream)
case TCP_STATE_INIT:
if (tcp->fd == -1)
{
- if ((tcp->fd = socket (PF_INET, SOCK_STREAM, 0)) == -1)
+ tcp->fd = socket (tcp->remote_addr->addr->sa_family, SOCK_STREAM, 0);
+ if (tcp->fd == -1)
return errno;
}
if (flags & MU_STREAM_NONBLOCK)
@@ -124,13 +102,10 @@ _tcp_open (mu_stream_t stream)
fcntl (tcp->fd, F_SETFL, flgs);
mu_stream_set_flags (stream, MU_STREAM_NONBLOCK);
}
- if (tcp->source_addr != INADDR_ANY)
+ if (tcp->source_addr)
{
- struct sockaddr_in s;
- s.sin_family = AF_INET;
- s.sin_addr.s_addr = tcp->source_addr;
- s.sin_port = 0;
- if (bind (tcp->fd, (struct sockaddr*) &s, sizeof(s)) < 0)
+ if (bind (tcp->fd, tcp->source_addr->addr,
+ tcp->source_addr->addrlen) < 0)
{
int e = errno;
close (tcp->fd);
@@ -142,27 +117,11 @@ _tcp_open (mu_stream_t stream)
tcp->state = TCP_STATE_RESOLVING;
case TCP_STATE_RESOLVING:
- if (!(tcp->host != NULL && tcp->port > 0))
- {
- _tcp_close (stream);
- return EINVAL;
- }
-
- if ((ret = resolve_hostname (tcp->host, &tcp->address)))
- {
- _tcp_close (stream);
- return ret;
- }
tcp->state = TCP_STATE_RESOLVE;
case TCP_STATE_RESOLVE:
- memset (&soc_addr, 0, sizeof (soc_addr));
- soc_addr.sin_family = AF_INET;
- soc_addr.sin_port = htons (tcp->port);
- soc_addr.sin_addr.s_addr = tcp->address;
-
- if ((connect (tcp->fd,
- (struct sockaddr *) &soc_addr, sizeof (soc_addr))) == -1)
+ if (connect (tcp->fd, tcp->remote_addr->addr,
+ tcp->remote_addr->addrlen) == -1)
{
ret = errno;
if (ret == EINPROGRESS || ret == EAGAIN)
@@ -254,10 +213,8 @@ _tcp_done (mu_stream_t stream)
{
struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
- if (tcp->host)
- free (tcp->host);
- if (tcp->fd != -1)
- close (tcp->fd);
+ mu_sockaddr_free (tcp->remote_addr);
+ mu_sockaddr_free (tcp->source_addr);
}
int
@@ -315,33 +272,21 @@ _create_tcp_stream (int flags)
}
int
-mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
- const char *host, unsigned port,
- unsigned long source_ip,
- int flags)
+mu_tcp_stream_create_from_sa (mu_stream_t *pstream,
+ struct mu_sockaddr *remote_addr,
+ struct mu_sockaddr *source_addr, int flags)
{
int rc;
mu_stream_t stream;
struct _tcp_instance *tcp;
- if (host == NULL)
- return MU_ERR_TCP_NO_HOST;
-
- if (port > USHRT_MAX)
- return MU_ERR_TCP_NO_PORT;
-
tcp = _create_tcp_stream (flags | MU_STREAM_RDWR);
if (!tcp)
return ENOMEM;
- tcp->host = strdup (host);
- if (!tcp->host)
- {
- free (tcp);
- return ENOMEM;
- }
- tcp->port = port;
- tcp->state = TCP_STATE_INIT;
- tcp->source_addr = source_ip;
+
+ tcp->remote_addr = remote_addr;
+ tcp->source_addr = source_addr;
+
stream = (mu_stream_t) tcp;
rc = mu_stream_open (stream);
if (rc == 0 || rc == EAGAIN || rc == EINPROGRESS)
@@ -351,24 +296,93 @@ mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
return rc;
}
+
+int
+mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
+ const char *host, unsigned port,
+ unsigned long source_ip,
+ int flags)
+{
+ int rc;
+ struct mu_sockaddr *remote_addr, *source_addr = NULL;
+ struct mu_sockaddr_hints hints;
+
+ memset (&hints, 0, sizeof hints);
+ hints.family = AF_INET;
+ hints.socktype = SOCK_STREAM;
+ hints.protocol = IPPROTO_TCP;
+ hints.port = port;
+ rc = mu_sockaddr_from_node (&remote_addr, host, NULL, &hints);
+ if (rc)
+ return rc;
+
+ if (source_ip)
+ {
+ struct sockaddr_in s;
+ s.sin_family = AF_INET;
+ s.sin_addr.s_addr = source_ip;
+ s.sin_port = 0;
+ rc = mu_sockaddr_create (&source_addr, (struct sockaddr*)&s,
+ sizeof (s));
+ if (rc)
+ {
+ mu_sockaddr_free (remote_addr);
+ return 0;
+ }
+ }
+
+ rc = mu_tcp_stream_create_from_sa (pstream, remote_addr, source_addr, flags);
+ if (rc)
+ {
+ mu_sockaddr_free (remote_addr);
+ mu_sockaddr_free (source_addr);
+ }
+ return rc;
+}
+
int
mu_tcp_stream_create_with_source_host (mu_stream_t *stream,
const char *host, unsigned port,
const char *source_host,
int flags)
{
- unsigned long source_addr;
- int ret = resolve_hostname (source_host, &source_addr);
- if (ret == 0)
- ret = mu_tcp_stream_create_with_source_ip (stream, host, port,
- source_addr, flags);
- return ret;
+ int rc;
+ struct mu_sockaddr *remote_addr, *source_addr = NULL;
+ struct mu_sockaddr_hints hints;
+
+ memset (&hints, 0, sizeof hints);
+ hints.family = AF_INET;
+ hints.socktype = SOCK_STREAM;
+ hints.port = port;
+ rc = mu_sockaddr_from_node (&remote_addr, host, NULL, &hints);
+ if (rc)
+ return rc;
+
+ if (source_host)
+ {
+ hints.flags = MU_AH_PASSIVE;
+ hints.port = 0;
+ rc = mu_sockaddr_from_node (&source_addr, source_host, NULL, &hints);
+ if (rc)
+ {
+ mu_sockaddr_free (remote_addr);
+ return 0;
+ }
+ }
+
+ rc = mu_tcp_stream_create_from_sa (stream, remote_addr, source_addr, flags);
+ if (rc)
+ {
+ mu_sockaddr_free (remote_addr);
+ mu_sockaddr_free (source_addr);
+ }
+ return rc;
}
int
mu_tcp_stream_create (mu_stream_t *stream, const char *host, unsigned port,
int flags)
{
- return mu_tcp_stream_create_with_source_ip (stream, host, port,
- INADDR_ANY, flags);
+ return mu_tcp_stream_create_with_source_host (stream, host, port,
+ NULL, flags);
}
diff --git a/libmailutils/tests/.gitignore b/libmailutils/tests/.gitignore
index d205efe63..d01d4ad93 100644
--- a/libmailutils/tests/.gitignore
+++ b/libmailutils/tests/.gitignore
@@ -1,5 +1,6 @@
atconfig
atlocal
+cidr
package.m4
testsuite
testsuite.dir
diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am
index 68618a1df..5c0087398 100644
--- a/libmailutils/tests/Makefile.am
+++ b/libmailutils/tests/Makefile.am
@@ -41,6 +41,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
INCLUDES = @MU_LIB_COMMON_INCLUDES@
noinst_PROGRAMS = \
addr\
+ cidr\
debugspec\
decode2047\
encode2047\
diff --git a/libmailutils/tests/cidr.c b/libmailutils/tests/cidr.c
new file mode 100644
index 000000000..797fb248e
--- /dev/null
+++ b/libmailutils/tests/cidr.c
@@ -0,0 +1,77 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <mailutils/mailutils.h>
+
+static void
+print_bytes (unsigned char *b, size_t l)
+{
+ for (; l; l--, b++)
+ printf (" %02x", *b);
+ printf ("\n");
+}
+
+int
+main (int argc, char **argv)
+{
+ mu_set_program_name (argv[0]);
+ if (argc < 2)
+ {
+ mu_error ("usage: %s CIDR [CIDR...]", argv[0]);
+ return 1;
+ }
+
+ while (--argc)
+ {
+ char *arg = *++argv;
+ struct mu_cidr cidr;
+ int rc;
+ char *str;
+
+ rc = mu_cidr_from_string (&cidr, arg);
+ if (rc)
+ {
+ mu_error ("%s: %s", arg, mu_strerror (rc));
+ continue;
+ }
+
+ printf ("%s:\n", arg);
+ printf ("family = %d\n", cidr.family);
+ printf ("len = %d\n", cidr.len);
+ printf ("address =");
+ print_bytes (cidr.address, cidr.len);
+ printf ("netmask =");
+ print_bytes (cidr.netmask, cidr.len);
+ rc = mu_cidr_format (&cidr, 0, &str);
+ if (rc)
+ {
+ mu_error ("cannot covert to string: %s", mu_strerror (rc));
+ return 2;
+ }
+
+ printf ("string = %s\n", str);
+ free (str);
+ }
+ return 0;
+}
+
+
diff --git a/libmailutils/tests/url-parse.c b/libmailutils/tests/url-parse.c
index 86c917315..48dd40f84 100644
--- a/libmailutils/tests/url-parse.c
+++ b/libmailutils/tests/url-parse.c
@@ -25,6 +25,7 @@
#include <mailutils/errno.h>
#include <mailutils/url.h>
#include <mailutils/secret.h>
+#include <mailutils/kwd.h>
#define CAT2(a,b) a ## b
@@ -73,12 +74,52 @@ print_query (mu_url_t url)
printf ("query[%lu] <%s>\n", (unsigned long) i, qargv[i]);
}
+struct mu_kwd parse_kwtab[] = {
+ { "hexcode", MU_URL_PARSE_HEXCODE },
+ { "hidepass", MU_URL_PARSE_HIDEPASS },
+ { "portsrv", MU_URL_PARSE_PORTSRV },
+ { "portwc", MU_URL_PARSE_PORTWC },
+ { "pipe", MU_URL_PARSE_PIPE },
+ { "slash", MU_URL_PARSE_SLASH },
+ { "dslash_optional", MU_URL_PARSE_DSLASH_OPTIONAL },
+ { "default", MU_URL_PARSE_DEFAULT },
+ { "all", MU_URL_PARSE_ALL },
+ { NULL }
+};
+
+
int
-main ()
+main (int argc, char **argv)
{
char str[1024];
unsigned port = 0;
- mu_url_t u = NULL;
+ mu_url_t u = NULL, uhint = NULL;
+ int i;
+ int parse_flags = 0;
+ int rc;
+
+ mu_set_program_name (argv[0]);
+ for (i = 1; i < argc; i++)
+ {
+ int flag;
+
+ if (strncmp (argv[i], "hint=", 5) == 0)
+ {
+ rc = mu_url_create (&uhint, argv[i] + 5);
+ if (rc)
+ {
+ mu_error ("cannot create hints: %s", mu_strerror (rc));
+ exit (1);
+ }
+ }
+ else if (mu_kwd_xlat_name_ci (parse_kwtab, argv[i], &flag) == 0)
+ parse_flags |= flag;
+ else
+ {
+ mu_error ("%s: unknown flag %s", argv[0], argv[i]);
+ exit (1);
+ }
+ }
while (fgets (str, sizeof (str), stdin) != NULL)
{
@@ -89,9 +130,9 @@ main ()
str[strlen (str) - 1] = '\0'; /* chop newline */
if (strspn (str, " \t") == strlen (str))
continue; /* skip empty lines */
- if ((rc = mu_url_create (&u, str)) != 0)
+ if ((rc = mu_url_create_hint (&u, str, parse_flags, uhint)) != 0)
{
- fprintf (stderr, "mu_url_create %s ERROR: [%d] %s",
+ fprintf (stderr, "mu_url_create %s ERROR: [%d] %s\n",
str, rc, mu_strerror (rc));
exit (1);
}
diff --git a/libmailutils/tests/url.at b/libmailutils/tests/url.at
index 8c392ea0e..c0669e2aa 100644
--- a/libmailutils/tests/url.at
+++ b/libmailutils/tests/url.at
@@ -20,10 +20,11 @@ dnl TESTURL([NAME], [KW = `'], [INPUT], [STDOUT = `'],
dnl [STDERR = `'], [RUN-IF-FAIL], [RUN-IF-PASS])
dnl
+m4_pushdef([URL_PARSE_OPTIONS])
m4_pushdef([TESTURL],[
m4_pushdef([MU_TEST_GROUP],[Url])
m4_pushdef([MU_TEST_KEYWORDS],[url])
-m4_pushdef([MU_TEST_COMMAND],[url-parse])
+m4_pushdef([MU_TEST_COMMAND],[url-parse URL_PARSE_OPTIONS])
MU_GENERIC_TEST([$1],[$2 url-m4_translit($3,[ ],[_])],[$3],[],[$4],[$5])
m4_popdef([MU_TEST_COMMAND])
m4_popdef([MU_TEST_KEYWORDS])
@@ -32,6 +33,8 @@ m4_popdef([MU_TEST_GROUP])
dnl ------------------------------------------------------------
+m4_define([URL_PARSE_OPTIONS],[default dslash_optional])
+
TESTURL([],[],
[scheme:],
[scheme <scheme>
@@ -76,6 +79,10 @@ port 0
path </absolute/path>
])
+dnl ------------------------------------------------------------
+
+m4_define([URL_PARSE_OPTIONS],[default])
+
TESTURL([],[],
[scheme://%75%73%65%72:%70%61%73%73@%68%6f%73%74],
[scheme <scheme>
@@ -198,7 +205,7 @@ path </a/path>
])
TESTURL([],[],
-[ftp:/a/path],
+[ftp:///a/path],
[scheme <ftp>
user <>
passwd <>
@@ -716,6 +723,7 @@ path <mbox/user@host>
param[0] <type=pass>
]])
+m4_pushdef([URL_PARSE_OPTIONS],[default dslash_optional])
TESTURL([],[],
[mbox:/var/spool/mail;type=index;param=2;user=gray],
[[scheme <mbox>
@@ -729,6 +737,7 @@ param[0] <type=index>
param[1] <param=2>
param[2] <user=gray>
]])
+m4_popdef([URL_PARSE_OPTIONS])
TESTURL([],[],
[mbox:///var/spool/mail;type=index;param=2;user=gray],
@@ -823,3 +832,4 @@ query[1] <list@dom>
]])
m4_popdef([TESTURL])
+m4_popdef([URL_PARSE_OPTIONS])
diff --git a/libmailutils/url/create.c b/libmailutils/url/create.c
index e58064081..130b7a2bc 100644
--- a/libmailutils/url/create.c
+++ b/libmailutils/url/create.c
@@ -59,9 +59,9 @@ getkn (struct mu_url_ctx *ctx, char *delim)
size_t n;
if (*ctx->cur == 0)
- return -1;
+ return MU_ERR_PARSE;
n = strcspn (ctx->cur, delim);
- if (n > ctx->toksize)
+ if (n + 1 > ctx->toksize)
{
char *p = realloc (ctx->tokbuf, n + 1);
if (!p)
@@ -220,11 +220,28 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host)
int rc;
mu_url_t url = ctx->url;
- rc = getkn (ctx, ":/;?");
+ rc = getkn (ctx, "[:/;?");
if (rc)
return rc;
- if (ctx->toklen)
+ if (*ctx->cur == '[')
+ {
+ /* Possibly IPv6 address */
+ rc = getkn (ctx, "]/;?");
+ if (rc)
+ return rc;
+ if (*ctx->cur == ']')
+ {
+ ctx->cur++;
+ rc = str_assign (&url->host, ctx->tokbuf + 1);
+ if (rc)
+ return rc;
+ url->flags |= MU_URL_HOST | MU_URL_IPV6;
+ has_host = 1;
+ }
+ }
+
+ if (!(url->flags & MU_URL_HOST) && ctx->toklen)
{
rc = str_assign (&url->host, ctx->tokbuf);
if (rc)
@@ -232,22 +249,20 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host)
url->flags |= MU_URL_HOST;
has_host = 1;
}
-
+
if (*ctx->cur == ':')
{
- ctx->cur++;
has_host = 1;
-
- rc = getkn (ctx, "/;?");
+ ctx->cur++;
+ rc = getkn (ctx, ":/;?");
if (rc)
return rc;
-
rc = str_assign (&url->portstr, ctx->tokbuf);
if (rc)
return rc;
url->flags |= MU_URL_PORT;
}
-
+
if (*ctx->cur == '/')
{
if (has_host)
@@ -269,7 +284,9 @@ _mu_url_ctx_parse_cred (struct mu_url_ctx *ctx)
int rc, has_cred;
mu_url_t url = ctx->url;
const char *save = ctx->cur;
-
+
+ if (*ctx->cur == 0)
+ return 0;
rc = getkn (ctx, "@");
if (rc)
return rc;
@@ -343,12 +360,18 @@ _mu_url_ctx_parse (struct mu_url_ctx *ctx)
{
int rc;
mu_url_t url = ctx->url;
+ const char *save = ctx->cur;
/* Parse the scheme part */
+ if (*ctx->cur == ':')
+ return _mu_url_ctx_parse_cred (ctx);
+
rc = getkn (ctx, ":/");
if (rc)
return rc;
- if (*ctx->cur == ':')
+ if (*ctx->cur == ':'
+ && ((ctx->flags & MU_URL_PARSE_DSLASH_OPTIONAL)
+ || (ctx->cur[1] == '/' && ctx->cur[2] == '/')))
{
rc = str_assign (&url->scheme, ctx->tokbuf);
if (rc)
@@ -356,7 +379,12 @@ _mu_url_ctx_parse (struct mu_url_ctx *ctx)
url->flags |= MU_URL_SCHEME;
ctx->cur++;
}
-
+ else
+ {
+ ctx->cur = save;
+ return _mu_url_ctx_parse_cred (ctx);
+ }
+
if (*ctx->cur == 0)
return 0;
@@ -535,5 +563,6 @@ mu_url_create (mu_url_t *purl, const char *str)
MU_URL_PARSE_HIDEPASS |
MU_URL_PARSE_PORTSRV |
MU_URL_PARSE_PIPE |
- MU_URL_PARSE_SLASH, NULL);
+ MU_URL_PARSE_SLASH |
+ MU_URL_PARSE_DSLASH_OPTIONAL, NULL);
}

Return to:

Send suggestions and report system problems to the System administrator.