summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--am/ipv6.m456
-rw-r--r--configure.ac9
-rw-r--r--examples/.gitignore2
-rw-r--r--examples/Makefile.am1
-rw-r--r--examples/aclck.c89
-rw-r--r--examples/echosrv.c69
-rw-r--r--examples/sa.c93
-rw-r--r--include/mailutils/Makefile.am2
-rw-r--r--include/mailutils/acl.h8
-rw-r--r--include/mailutils/cidr.h61
-rw-r--r--include/mailutils/debug.h3
-rw-r--r--include/mailutils/mailutils.h2
-rw-r--r--include/mailutils/server.h12
-rw-r--r--include/mailutils/sockaddr.h78
-rw-r--r--include/mailutils/stream.h4
-rw-r--r--include/mailutils/types.hin3
-rw-r--r--include/mailutils/url.h9
-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
-rw-r--r--libmu_cfg/acl.c135
-rw-r--r--libproto/mailer/smtp.c25
-rw-r--r--libproto/pop/mbox.c27
-rw-r--r--mu/acl.c40
-rw-r--r--mu/imap.c25
-rw-r--r--mu/pop.c47
-rw-r--r--testsuite/smtpsend.c25
53 files changed, 2416 insertions, 980 deletions
diff --git a/am/ipv6.m4 b/am/ipv6.m4
new file mode 100644
index 000000000..2357314b9
--- /dev/null
+++ b/am/ipv6.m4
@@ -0,0 +1,56 @@
+dnl This file is part of GNU Mailutils. -*- autoconf -*-
+dnl Copyright (C) 2011 Free Software Foundation, Inc.
+dnl
+dnl GNU Mailutils is free software; you can redistribute it and/or modify
+dnl it under the terms of the GNU General Public License as published by
+dnl the Free Software Foundation; either version 3 of the License, or
+dnl (at your option) any later version.
+dnl
+dnl GNU Mailutils is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+dnl GNU General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU General Public License
+dnl along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
+
+AC_DEFUN([MU_ENABLE_IPV6],
+ [AC_ARG_ENABLE(ipv6,
+ [AC_HELP_STRING([--enable-ipv6], [enable IPv6 support])],
+ [status_ipv6=$enableval],
+ [status_ipv6=maybe])
+
+ if test $status_ipv6 != no; then
+ working_ipv6=no
+ AC_EGREP_CPP(MAILUTILS_AF_INET6_DEFINED,[
+#include <sys/socket.h>
+#if defined(AF_INET6)
+MAILUTILS_AF_INET6_DEFINED
+#endif
+],[working_ipv6=yes])
+
+ AC_CHECK_TYPE([struct sockaddr_storage],
+ [working_ipv6=yes], [working_ipv6=no],
+ [#include <sys/socket.h>])
+ AC_CHECK_TYPE([struct sockaddr_in6],
+ [working_ipv6=yes], [working_ipv6=no],
+ [#include <sys/types.h>
+ #include <netinet/in.h>])
+ AC_CHECK_TYPE([struct addrinfo],
+ [working_ipv6=yes], [working_ipv6=no],
+ [#include <netdb.h>])
+ AC_CHECK_FUNC([getnameinfo],
+ [working_ipv6=yes], [working_ipv6=no],
+ [#include <netdb.h>])
+
+ if test $working_ipv6 = no; then
+ if test $status_ipv6 = yes; then
+ AC_MSG_ERROR([IPv6 support is required but not available])
+ fi
+ fi
+ status_ipv6=$working_ipv6
+ if test $status_ipv6 = yes; then
+ AC_DEFINE_UNQUOTED([MAILUTILS_IPV6],1,
+ [Define to 1 if IPv6 support is enabled])
+ fi
+ fi]) \ No newline at end of file
diff --git a/configure.ac b/configure.ac
index e03a4c3b3..2edb49459 100644
--- a/configure.ac
+++ b/configure.ac
@@ -543,2 +543,6 @@ AH_BOTTOM([
+# IPv6 support
+MU_ENABLE_IPV6
+
+
## FriBidi support
@@ -1287,2 +1291,4 @@ Support for virtual domains ... $status_virtual_domains
+IPv6 support .................. $status_ipv6
+
Interfaces:
@@ -1334,2 +1340,3 @@ status_smtp=$mu_cv_enable_smtp
status_sendmail=$mu_cv_enable_sendmail
+status_ipv6=$status_ipv6
])
@@ -1384,2 +1391,4 @@ AC_CONFIG_FILES([
libmailutils/address/Makefile
+ libmailutils/sockaddr/Makefile
+ libmailutils/cidr/Makefile
libmailutils/cfg/Makefile
diff --git a/examples/.gitignore b/examples/.gitignore
index af4156be3..890812aae 100644
--- a/examples/.gitignore
+++ b/examples/.gitignore
@@ -13,2 +13,3 @@ lsf
mailcap
+mblconv
mimetest
@@ -22,2 +23,3 @@ musocio
nntpclient
+sa
sfrom
diff --git a/examples/Makefile.am b/examples/Makefile.am
index e22a8d355..9df91ea62 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -45,2 +45,3 @@ noinst_PROGRAMS = \
$(NNTPCLIENT)\
+ sa\
sfrom
diff --git a/examples/aclck.c b/examples/aclck.c
index 57f5c0388..033c444b1 100644
--- a/examples/aclck.c
+++ b/examples/aclck.c
@@ -30,31 +30,5 @@
-struct sockaddr *target_sa;
-int target_salen;
+struct mu_sockaddr *target_sa;
mu_acl_t acl;
-struct sockaddr *
-parse_address (int *psalen, char *str)
-{
- struct sockaddr_in in;
- struct sockaddr *sa;
-
- in.sin_family = AF_INET;
- if (inet_aton (str, &in.sin_addr) == 0)
- {
- mu_error ("Invalid IPv4: %s", str);
- exit (1);
- }
- in.sin_port = 0;
- *psalen = sizeof (in);
- sa = malloc (*psalen);
- if (!sa)
- {
- mu_error ("%s", mu_strerror (errno));
- exit (1);
- }
-
- memcpy (sa, &in, sizeof (in));
- return sa;
-}
-
void
@@ -78,8 +52,5 @@ read_rules (FILE *fp)
{
- unsigned long netmask;
- int salen;
- struct sockaddr *sa;
+ struct mu_cidr cidr;
mu_acl_action_t action;
void *data = NULL;
- char *p;
@@ -111,35 +82,11 @@ read_rules (FILE *fp)
- p = strchr (ws.ws_wordv[1], '/');
- if (p)
+ if (strcmp (ws.ws_wordv[1], "any") == 0)
+ memset (&cidr, 0, sizeof (cidr));
+ else
{
- char *q;
- unsigned netlen;
-
- *p++ = 0;
- netlen = strtoul (p, &q, 10);
- if (*q == 0)
- {
- if (netlen == 0)
- netmask = 0;
- else
- {
- netmask = 0xfffffffful >> (32 - netlen);
- netmask <<= (32 - netlen);
- netmask = htonl (netmask);
- }
- }
- else if (*q == '.')
+ rc = mu_cidr_from_string (&cidr, ws.ws_wordv[1]);
+ if (rc)
{
- struct in_addr addr;
-
- if (inet_aton (p, &addr) == 0)
- {
- mu_error ("%d: invalid netmask", line);
- continue;
- }
- netmask = addr.s_addr;
- }
- else
- {
- mu_error ("%d: invalid netmask", line);
+ mu_error ("%d: invalid source CIDR: %s",
+ line, mu_strerror (rc));
continue;
@@ -147,7 +94,3 @@ read_rules (FILE *fp)
}
- else
- netmask = 0xfffffffful;
-
- sa = parse_address (&salen, ws.ws_wordv[1]);
-
+
/* accept addr
@@ -176,3 +119,3 @@ read_rules (FILE *fp)
- rc = mu_acl_append (acl, action, data, sa, salen, netmask);
+ rc = mu_acl_append (acl, action, data, &cidr);
if (rc)
@@ -205,3 +148,8 @@ main (int argc, char **argv)
case 'a':
- target_sa = parse_address (&target_salen, optarg);
+ rc = mu_sockaddr_from_node (&target_sa, optarg, NULL, NULL);
+ if (rc)
+ {
+ mu_error ("mu_sockaddr_from_node: %s", mu_strerror (rc));
+ exit (1);
+ }
break;
@@ -227,3 +175,4 @@ main (int argc, char **argv)
read_rules (file ? file : stdin);
- rc = mu_acl_check_sockaddr (acl, target_sa, target_salen, &result);
+ rc = mu_acl_check_sockaddr (acl, target_sa->addr, target_sa->addrlen,
+ &result);
if (rc)
diff --git a/examples/echosrv.c b/examples/echosrv.c
index fb68e7aee..fffde7343 100644
--- a/examples/echosrv.c
+++ b/examples/echosrv.c
@@ -41,4 +41,2 @@ echo_conn (int fd, struct sockaddr *s, int len,
{
- struct sockaddr_in srv_addr, *s_in = (struct sockaddr_in *)s;
- int addrlen = sizeof srv_addr;
pid_t pid;
@@ -46,4 +44,2 @@ echo_conn (int fd, struct sockaddr *s, int len,
FILE *in, *out;
-
- mu_ip_server_get_sockaddr (srv, (struct sockaddr *)&srv_addr, &addrlen);
@@ -58,6 +54,16 @@ echo_conn (int fd, struct sockaddr *s, int len,
{
- mu_diag_output (MU_DIAG_INFO, "%lu: opened connection %s:%d => %s:%d",
+ struct mu_sockaddr *clt_addr;
+ int rc = mu_sockaddr_create (&clt_addr, s, len);
+ if (rc)
+ {
+ mu_error ("mu_sockaddr_create failed: %s", mu_strerror (rc));
+ return 0;
+ }
+
+ mu_diag_output (MU_DIAG_INFO, "%lu: opened connection %s => %s",
(unsigned long) pid,
- inet_ntoa (srv_addr.sin_addr), ntohs (srv_addr.sin_port),
- inet_ntoa (s_in->sin_addr), ntohs (s_in->sin_port));
+ mu_ip_server_addrstr (srv),
+ mu_sockaddr_str (clt_addr));
+
+ mu_sockaddr_free (clt_addr);
return 0;
@@ -110,30 +116,41 @@ create_server (char *arg)
{
- char *p, *q;
- struct sockaddr_in s;
+ struct mu_sockaddr *s;
mu_ip_server_t tcpsrv;
- unsigned n;
-
- p = strchr (arg, ':');
- if (!*p)
+ int rc;
+ mu_url_t url, url_hint;
+ struct mu_sockaddr_hints hints;
+
+ if (arg[0] == '/')
+ url_hint = NULL;
+ else
{
- mu_error ("invalid specification: %s\n", arg);
- exit (1);
+ rc = mu_url_create (&url_hint, "inet://");
+ if (rc)
+ {
+ mu_error ("cannot create URL hints: %s", mu_strerror (rc));
+ exit (1);
+ }
}
- *p++ = 0;
- s.sin_family = AF_INET;
- if (inet_aton (arg, &s.sin_addr) == 0)
+ rc = mu_url_create_hint (&url, arg, MU_URL_PARSE_DEFAULT, url_hint);
+ mu_url_destroy (&url_hint);
+ if (rc)
{
- mu_error ("invalid IP address: %s\n", arg);
+ mu_error ("cannot parse URL `%s': %s", arg, mu_strerror (rc));
exit (1);
}
- n = strtoul (p, &q, 0);
- if (*q)
+
+ memset (&hints, sizeof(hints), 0);
+ hints.flags = MU_AH_PASSIVE;
+ hints.socktype = SOCK_STREAM;
+ hints.protocol = IPPROTO_TCP;
+ rc = mu_sockaddr_from_url (&s, url, &hints);
+ mu_url_destroy (&url);
+
+ if (rc)
{
- mu_error ("invalid port number: %s\n", p);
+ mu_error ("cannot create sockaddr: %s", mu_strerror (rc));
exit (1);
- }
- s.sin_port = htons (n);
+ }
- MU_ASSERT (mu_ip_server_create (&tcpsrv, (struct sockaddr*) &s, sizeof s,
- MU_IP_TCP));
+ MU_ASSERT (mu_ip_server_create (&tcpsrv, s, MU_IP_TCP));
MU_ASSERT (mu_ip_server_open (tcpsrv));
diff --git a/examples/sa.c b/examples/sa.c
new file mode 100644
index 000000000..7cc7e93b5
--- /dev/null
+++ b/examples/sa.c
@@ -0,0 +1,93 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2010, 2011 Free
+ Software Foundation, Inc.
+
+ GNU Mailutils is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ GNU Mailutils 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <mailutils/mailutils.h>
+
+int
+main (int argc, char **argv)
+{
+ struct mu_sockaddr_hints hints;
+ struct mu_sockaddr *sa, *ap;
+ int rc, i;
+ char *node = NULL, *serv = NULL;
+ char *urlstr;
+
+ mu_set_program_name (argv[0]);
+
+ memset (&hints, 0, sizeof (hints));
+ hints.family = AF_UNSPEC;
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp (argv[i], "passive") == 0)
+ hints.flags |= MU_AH_PASSIVE;
+ else if (strcmp (argv[i], "detect") == 0)
+ hints.flags |= MU_AH_DETECT_FAMILY;
+ else if (strncmp (argv[i], "node=", 5) == 0)
+ node = argv[i] + 5;
+ else if (strncmp (argv[i], "serv=", 5) == 0)
+ serv = argv[i] + 5;
+ else if (strncmp (argv[i], "url=", 4) == 0)
+ urlstr = argv[i] + 4;
+ else if (strncmp (argv[i], "proto=", 6) == 0)
+ hints.protocol = atoi(argv[i] + 6);
+ else if (strncmp (argv[i], "family=", 7) == 0)
+ hints.family = atoi (argv[i] + 7);
+ else if (strncmp (argv[i], "socktype=", 9) == 0)
+ hints.socktype = atoi (argv[i] + 9);
+ else
+ {
+ mu_error ("unknown argument: %s", argv[i]);
+ exit (1);
+ }
+ }
+
+ if (urlstr)
+ {
+ mu_url_t url;
+
+ if (node || serv)
+ {
+ mu_error ("both url and host/serv are given");
+ exit (1);
+ }
+
+ rc = mu_url_create (&url, urlstr);
+ if (rc)
+ {
+ mu_error ("cannot create url: %s", mu_strerror (rc));
+ exit (2);
+ }
+ rc = mu_sockaddr_from_url (&sa, url, &hints);
+ }
+ else
+ rc = mu_sockaddr_from_node (&sa, node, serv, &hints);
+ if (rc)
+ {
+ mu_error ("cannot create sockaddr: %s", mu_strerror (rc));
+ exit (2);
+ }
+
+ for (ap = sa; ap; ap = ap->next)
+ printf ("%s\n", mu_sockaddr_str (ap));
+
+ mu_sockaddr_free (sa);
+ exit (0);
+}
+
diff --git a/include/mailutils/Makefile.am b/include/mailutils/Makefile.am
index daa46e9fe..1e2189437 100644
--- a/include/mailutils/Makefile.am
+++ b/include/mailutils/Makefile.am
@@ -38,2 +38,3 @@ pkginclude_HEADERS = \
cfg.h\
+ cidr.h\
cstr.h\
@@ -91,2 +92,3 @@ pkginclude_HEADERS = \
smtp.h\
+ sockaddr.h\
stdstream.h\
diff --git a/include/mailutils/acl.h b/include/mailutils/acl.h
index b898463eb..167acc82c 100644
--- a/include/mailutils/acl.h
+++ b/include/mailutils/acl.h
@@ -49,9 +49,7 @@ int 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);
+ struct mu_cidr *);
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 *);
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 *);
diff --git a/include/mailutils/cidr.h b/include/mailutils/cidr.h
new file mode 100644
index 000000000..c54bf6224
--- /dev/null
+++ b/include/mailutils/cidr.h
@@ -0,0 +1,61 @@
+/* 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/>. */
+
+#ifndef _MAILUTILS_CIDR_H
+#define _MAILUTILS_CIDR_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <mailutils/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MU_INADDR_BYTES 16
+
+struct mu_cidr
+{
+ int family;
+ int len;
+ unsigned char address[MU_INADDR_BYTES];
+ unsigned char netmask[MU_INADDR_BYTES];
+};
+
+#define MU_CIDR_MAXBUFSIZE 81
+
+int mu_cidr_from_sockaddr (struct mu_cidr *cp, const struct sockaddr *sa);
+int mu_cidr_from_string (struct mu_cidr *cp, const char *str);
+
+#define MU_CIDR_FMT_ADDRONLY 0x01
+
+int mu_cidr_to_string (struct mu_cidr *cidr, int flags, char *buf, size_t size,
+ size_t *pret);
+int mu_cidr_format (struct mu_cidr *, int flags, char **pbuf);
+int mu_cidr_to_sockaddr (struct mu_cidr *, struct sockaddr **sa);
+
+int mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b);
+
+int _mu_inaddr_to_bytes (int af, void *buf, unsigned char *bytes);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MAILUTILS_CIDR_H */
+
+
diff --git a/include/mailutils/debug.h b/include/mailutils/debug.h
index 5072d51d2..a619661d7 100644
--- a/include/mailutils/debug.h
+++ b/include/mailutils/debug.h
@@ -56,5 +56,2 @@ extern int mu_debug_line_info;
struct sockaddr;
-void mu_sockaddr_to_str (const struct sockaddr *sa, int salen,
- char *bufptr, size_t buflen,
- size_t *plen);
char *mu_sockaddr_to_astr (const struct sockaddr *sa, int salen);
diff --git a/include/mailutils/mailutils.h b/include/mailutils/mailutils.h
index 8d9e04b77..08a2fc0bc 100644
--- a/include/mailutils/mailutils.h
+++ b/include/mailutils/mailutils.h
@@ -69,2 +69,4 @@
#include <mailutils/prog.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/cidr.h>
diff --git a/include/mailutils/server.h b/include/mailutils/server.h
index bf8d10e6f..c5da97e43 100644
--- a/include/mailutils/server.h
+++ b/include/mailutils/server.h
@@ -56,4 +56,4 @@ typedef void (*mu_ip_server_free_fp) (void *data);
-int mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr,
- int len, int type);
+int mu_ip_server_create (mu_ip_server_t *psrv, struct mu_sockaddr *addr,
+ int type);
int mu_ip_server_destroy (mu_ip_server_t *psrv);
@@ -71,4 +71,4 @@ int mu_ip_server_loop (mu_ip_server_t srv, void *call_data);
int mu_ip_server_get_fd (mu_ip_server_t srv);
-int mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct sockaddr *s,
- int *size);
+int mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct mu_sockaddr **psa);
+const char *mu_ip_server_addrstr (mu_ip_server_t srv);
@@ -101,4 +101,2 @@ int mu_m_server_set_foreground (mu_m_server_t srv, int enable);
void mu_m_server_set_default_port (mu_m_server_t srv, int port);
-void mu_m_server_set_default_address (mu_m_server_t srv, struct sockaddr *sa,
- int salen);
void mu_m_server_set_timeout (mu_m_server_t srv, time_t t);
@@ -114,4 +112,2 @@ void mu_m_server_get_sigset (mu_m_server_t srv, sigset_t *sigset);
int mu_m_server_get_srvlist (mu_m_server_t srv, mu_list_t *plist);
-int mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa,
- int *salen);
diff --git a/include/mailutils/sockaddr.h b/include/mailutils/sockaddr.h
new file mode 100644
index 000000000..5a98f7a5a
--- /dev/null
+++ b/include/mailutils/sockaddr.h
@@ -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/>. */
+
+#ifndef _MAILUTILS_SOCKADDR_H
+#define _MAILUTILS_SOCKADDR_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <mailutils/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct mu_sockaddr
+{
+ struct mu_sockaddr *prev, *next;
+ struct sockaddr *addr; /* Address */
+ socklen_t addrlen; /* Size of addr */
+ char *str; /* string representation of addr,
+ filled up by mu_sockaddr_str */
+};
+
+#define MU_AH_PASSIVE 0x01
+#define MU_AH_DETECT_FAMILY 0x02
+
+struct mu_sockaddr_hints
+{
+ int flags;
+ int family;
+ int socktype;
+ int protocol;
+ unsigned short port;
+};
+
+int mu_sockaddr_create (struct mu_sockaddr **res,
+ struct sockaddr *addr, socklen_t len);
+int mu_sockaddr_copy (struct mu_sockaddr **pnew, struct mu_sockaddr *old);
+void mu_sockaddr_free (struct mu_sockaddr *addr);
+struct mu_sockaddr *mu_sockaddr_unlink (struct mu_sockaddr *addr);
+void mu_sockaddr_free_list (struct mu_sockaddr *addr);
+struct mu_sockaddr *mu_sockaddr_insert (struct mu_sockaddr *anchor,
+ struct mu_sockaddr *addr,
+ int before);
+const char *mu_sockaddr_str (struct mu_sockaddr *addr);
+
+int mu_sockaddr_format (char **pbuf, const struct sockaddr *sa,
+ socklen_t salen);
+
+int mu_sockaddr_from_node (struct mu_sockaddr **retval, const char *node,
+ const char *serv, struct mu_sockaddr_hints *hints);
+int mu_sockaddr_from_url (struct mu_sockaddr **retval, mu_url_t url,
+ struct mu_sockaddr_hints *hints);
+
+int mu_str_is_ipv4 (const char *addr);
+int mu_str_is_ipv6 (const char *addr);
+int mu_str_is_ipaddr (const char *addr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MAILUTILS_SOCKADDR_H */
+
diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h
index b253f4ef2..8bea9074d 100644
--- a/include/mailutils/stream.h
+++ b/include/mailutils/stream.h
@@ -317,2 +317,6 @@ int mu_streamref_create (mu_stream_t *pref, mu_stream_t str);
+int mu_tcp_stream_create_from_sa (mu_stream_t *pstream,
+ struct mu_sockaddr *remote_addr,
+ struct mu_sockaddr *source_addr, int flags);
+
int mu_tcp_stream_create_with_source_ip (mu_stream_t *stream,
diff --git a/include/mailutils/types.hin b/include/mailutils/types.hin
index e89b799c5..bf81756bb 100644
--- a/include/mailutils/types.hin
+++ b/include/mailutils/types.hin
@@ -77,2 +77,5 @@ struct _mu_server;
struct _mu_tcp_server;
+
+struct mu_sockaddr; /* defined in mailutils/sockaddr.h */
+struct mu_cidr; /* defined in mailutils/cidr.h */
diff --git a/include/mailutils/url.h b/include/mailutils/url.h
index 031e568c6..c33dadc45 100644
--- a/include/mailutils/url.h
+++ b/include/mailutils/url.h
@@ -36,2 +36,3 @@ extern "C" {
#define MU_URL_QUERY 0x0100 /* Has query */
+#define MU_URL_IPV6 0x0200 /* Host part is bracketed (IPv6) */
@@ -55,8 +56,10 @@ extern "C" {
#define MU_URL_PARSE_PORTWC 0x0008 /* Allow wildcard (*) as a port
- number (for tickets) */
+ number (for tickets) */
#define MU_URL_PARSE_PIPE 0x0010 /* Translate "| ..." to
- "prog://..." */
+ "prog://..." */
#define MU_URL_PARSE_SLASH 0x0020 /* Translate "/..." to
"file:///..." */
-
+#define MU_URL_PARSE_DSLASH_OPTIONAL 0x0040 /* Double-slash after scheme:
+ part is optional */
+
#define MU_URL_PARSE_DEFAULT \
diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am
index ed1aeb019..5aef3382d 100644
--- a/libmailutils/Makefile.am
+++ b/libmailutils/Makefile.am
@@ -18,3 +18,3 @@
-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
@@ -30,2 +30,4 @@ libmailutils_la_LIBADD = \
address/libaddress.la\
+ sockaddr/libsockaddr.la\
+ cidr/libcidr.la\
cfg/libcfg.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
@@ -691,2 +691,3 @@ mu_debug_log_begin (const char *fmt, ...)
mu_diag_init ();
+ mu_stream_flush (mu_strerr);
va_start (ap, fmt);
diff --git a/libmailutils/diag/errors b/libmailutils/diag/errors
index 869e4146f..03f71b715 100644
--- a/libmailutils/diag/errors
+++ b/libmailutils/diag/errors
@@ -1 +1,2 @@
+
# Error messages for GNU Mailutils
@@ -100 +101,8 @@ 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
@@ -42,2 +42,10 @@
#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
@@ -47,5 +55,3 @@ struct _mu_acl_entry
void *arg;
- unsigned netmask;
- int salen;
- struct sockaddr sa[1];
+ struct mu_cidr cidr;
};
@@ -66,29 +72,2 @@ _destroy_acl_entry (void *item)
-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
@@ -96,5 +75,5 @@ 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)
@@ -104,10 +83,4 @@ mu_acl_entry_create (struct _mu_acl_entry **pent,
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;
@@ -167,4 +140,3 @@ 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)
{
@@ -175,3 +147,3 @@ mu_acl_append (mu_acl_t acl, mu_acl_action_t act,
return EINVAL;
- rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+ rc = mu_acl_entry_create (&ent, act, data, cidr);
if (rc)
@@ -195,3 +167,3 @@ 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)
{
@@ -202,3 +174,3 @@ mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data,
return EINVAL;
- rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+ rc = mu_acl_entry_create (&ent, act, data, cidr);
if (rc)
@@ -221,4 +193,3 @@ 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)
{
@@ -238,3 +209,3 @@ mu_acl_insert (mu_acl_t acl, size_t pos, int before,
}
- rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+ rc = mu_acl_entry_create (&ent, act, data, cidr);
if (!ent)
@@ -281,120 +252,15 @@ mu_acl_string_to_action (const char *str, mu_acl_action_t *pres)
-#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)
{
@@ -406,14 +272,14 @@ _acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen)
{
- 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))
{
@@ -422,42 +288,2 @@ _acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen)
}
-
- 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");
@@ -466,12 +292,2 @@ _acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen)
-struct run_closure
-{
- unsigned idx;
- struct sockaddr *sa;
- char *numbuf;
- char *portbuf;
- int salen;
- mu_acl_result_t *result;
-};
-
#define SEQ(s, n, l) \
@@ -491,36 +307,20 @@ acl_getvar (const char *name, size_t nlen, void *data)
- 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;
@@ -537,3 +337,3 @@ expand_arg (const char *cmdline, struct run_closure *rp, char **s)
env[0] = "family";
- switch (rp->sa->sa_family)
+ switch (rp->addr.family)
{
@@ -543,2 +343,8 @@ expand_arg (const char *cmdline, struct run_closure *rp, char **s)
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ env[1] = "AF_INET6";
+ break;
+#endif
+
case AF_UNIX:
@@ -656,3 +462,3 @@ _run_entry (void *item, void *data)
- if (_acl_match (ent, rp->sa, rp->salen) == 0)
+ if (_acl_match (ent, rp) == 0)
{
@@ -680,4 +486,6 @@ _run_entry (void *item, void *data)
{
- 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);
}
@@ -714,3 +522,3 @@ _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);
@@ -723,2 +531,3 @@ mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen,
{
+ int rc;
struct run_closure r;
@@ -728,12 +537,11 @@ mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen,
- 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;
@@ -741,4 +549,4 @@ mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen,
{
- 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 ();
@@ -749,10 +557,9 @@ mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen,
*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
@@ -782,6 +589,13 @@ 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)
{
@@ -793,3 +607,3 @@ mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres)
- 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
@@ -36,2 +36,3 @@
#include <mailutils/nls.h>
+#include <mailutils/sockaddr.h>
@@ -41,4 +42,3 @@ struct _mu_ip_server
char *ident;
- struct sockaddr *addr;
- int addrlen;
+ struct mu_sockaddr *addr;
int fd;
@@ -68,4 +68,3 @@ struct _mu_ip_server
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)
{
@@ -86,10 +85,3 @@ mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr,
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;
@@ -122,3 +114,3 @@ mu_ip_server_destroy (mu_ip_server_t *psrv)
close (srv->fd);
- free (srv->addr);
+ mu_sockaddr_free (srv->addr);
free (srv->ident);
@@ -236,2 +228,7 @@ mu_address_family_to_domain (int family)
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ return PF_INET6;
+#endif
+
default:
@@ -249,10 +246,7 @@ mu_ip_server_open (mu_ip_server_t srv)
- 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);
@@ -265,3 +259,3 @@ mu_ip_server_open (mu_ip_server_t srv)
- switch (srv->addr->sa_family)
+ switch (srv->addr->addr->sa_family)
{
@@ -301,3 +295,3 @@ mu_ip_server_open (mu_ip_server_t srv)
- case AF_INET:
+ default:
{
@@ -310,3 +304,3 @@ 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)
{
@@ -338,8 +332,5 @@ mu_ip_server_shutdown (mu_ip_server_t srv)
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);
@@ -358,2 +349,5 @@ mu_ip_tcp_accept (mu_ip_server_t srv, void *call_data)
struct sockaddr_un s_un;
+#ifdef MAILUTILS_IPV6
+ struct sockaddr_in6 s_in6;
+#endif
} client;
@@ -409,2 +403,5 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
struct sockaddr_un s_un;
+#ifdef MAILUTILS_IPV6
+ struct sockaddr_in6 s_in6;
+#endif
} client;
@@ -465,3 +462,3 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
{
- 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);
@@ -530,20 +527,14 @@ 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
@@ -43,2 +43,4 @@
#include <mailutils/acl.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/url.h>
@@ -67,15 +69,2 @@ set_signal (int sig, mu_sig_handler_t handler)
-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
@@ -100,3 +89,3 @@ struct _mu_m_server
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. */
@@ -114,3 +103,3 @@ 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. */
@@ -397,12 +386,8 @@ 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));
}
@@ -410,16 +395,7 @@ mu_m_server_set_default_address (mu_m_server_t srv, struct sockaddr *sa,
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;
@@ -431,7 +407,3 @@ 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;
}
@@ -475,3 +447,3 @@ static int m_srv_conn (int fd, struct sockaddr *sa, int salen,
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)
{
@@ -480,3 +452,3 @@ add_server (mu_m_server_t msrv, struct sockaddr *s, int slen, int type)
- 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));
@@ -515,4 +487,17 @@ mu_m_server_begin (mu_m_server_t 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;
+ }
+ }
@@ -601,10 +586,2 @@ _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;
@@ -614,6 +591,4 @@ _open_conn (void *item, void *data)
{
- 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;
@@ -626,6 +601,4 @@ _open_conn (void *item, void *data)
{
- 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);
@@ -758,185 +731,32 @@ 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;
}
@@ -946,7 +766,16 @@ 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;
@@ -1004,2 +833,30 @@ _cb_daemon_mode (void *data, mu_config_value_t *val)
+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
@@ -1007,5 +864,5 @@ _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))
@@ -1015,6 +872,3 @@ _cb_port (void *data, mu_config_value_t *val)
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;
@@ -1038,3 +892,3 @@ static struct mu_cfg_param dot_server_cfg_param[] = {
{ "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.") },
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
@@ -41,3 +41,3 @@
#include <mailutils/util.h>
-
+#include <mailutils/sockaddr.h>
#include <mailutils/sys/stream.h>
@@ -54,14 +54,7 @@ struct _tcp_instance
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
@@ -85,17 +78,2 @@ _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)
@@ -106,3 +84,2 @@ _tcp_open (mu_stream_t stream)
struct sockaddr_in peer_addr;
- struct sockaddr_in soc_addr;
int flags;
@@ -116,3 +93,4 @@ _tcp_open (mu_stream_t stream)
{
- 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;
@@ -126,9 +104,6 @@ _tcp_open (mu_stream_t stream)
}
- 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)
{
@@ -144,13 +119,2 @@ _tcp_open (mu_stream_t stream)
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;
@@ -158,9 +122,4 @@ _tcp_open (mu_stream_t stream)
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)
{
@@ -256,6 +215,4 @@ _tcp_done (mu_stream_t 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);
}
@@ -317,6 +274,5 @@ _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)
{
@@ -326,8 +282,2 @@ mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
- 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);
@@ -335,11 +285,6 @@ mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
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;
@@ -353,2 +298,46 @@ mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
+
+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
@@ -359,8 +348,33 @@ mu_tcp_stream_create_with_source_host (mu_stream_t *stream,
{
- 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;
}
@@ -371,4 +385,4 @@ mu_tcp_stream_create (mu_stream_t *stream, const char *host, unsigned port,
{
- 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
@@ -2,2 +2,3 @@ atconfig
atlocal
+cidr
package.m4
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
@@ -43,2 +43,3 @@ noinst_PROGRAMS = \
addr\
+ cidr\
debugspec\
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
@@ -27,2 +27,3 @@
#include <mailutils/secret.h>
+#include <mailutils/kwd.h>
@@ -75,4 +76,18 @@ print_query (mu_url_t url)
+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)
{
@@ -80,3 +95,29 @@ main ()
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);
+ }
+ }
@@ -91,5 +132,5 @@ main ()
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));
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
@@ -22,2 +22,3 @@ dnl
+m4_pushdef([URL_PARSE_OPTIONS])
m4_pushdef([TESTURL],[
@@ -25,3 +26,3 @@ 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])
@@ -34,2 +35,4 @@ dnl ------------------------------------------------------------
+m4_define([URL_PARSE_OPTIONS],[default dslash_optional])
+
TESTURL([],[],
@@ -78,2 +81,6 @@ path </absolute/path>
+dnl ------------------------------------------------------------
+
+m4_define([URL_PARSE_OPTIONS],[default])
+
TESTURL([],[],
@@ -200,3 +207,3 @@ path </a/path>
TESTURL([],[],
-[ftp:/a/path],
+[ftp:///a/path],
[scheme <ftp>
@@ -718,2 +725,3 @@ param[0] <type=pass>
+m4_pushdef([URL_PARSE_OPTIONS],[default dslash_optional])
TESTURL([],[],
@@ -731,2 +739,3 @@ param[2] <user=gray>
]])
+m4_popdef([URL_PARSE_OPTIONS])
@@ -825 +834,2 @@ 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
@@ -61,5 +61,5 @@ getkn (struct mu_url_ctx *ctx, char *delim)
if (*ctx->cur == 0)
- return -1;
+ return MU_ERR_PARSE;
n = strcspn (ctx->cur, delim);
- if (n > ctx->toksize)
+ if (n + 1 > ctx->toksize)
{
@@ -222,3 +222,3 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host)
- rc = getkn (ctx, ":/;?");
+ rc = getkn (ctx, "[:/;?");
if (rc)
@@ -226,3 +226,20 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host)
- 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)
{
@@ -234,12 +251,10 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host)
}
-
+
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);
@@ -249,3 +264,3 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host)
}
-
+
if (*ctx->cur == '/')
@@ -271,3 +286,5 @@ _mu_url_ctx_parse_cred (struct mu_url_ctx *ctx)
const char *save = ctx->cur;
-
+
+ if (*ctx->cur == 0)
+ return 0;
rc = getkn (ctx, "@");
@@ -345,4 +362,8 @@ _mu_url_ctx_parse (struct mu_url_ctx *ctx)
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, ":/");
@@ -350,3 +371,5 @@ _mu_url_ctx_parse (struct mu_url_ctx *ctx)
return rc;
- if (*ctx->cur == ':')
+ if (*ctx->cur == ':'
+ && ((ctx->flags & MU_URL_PARSE_DSLASH_OPTIONAL)
+ || (ctx->cur[1] == '/' && ctx->cur[2] == '/')))
{
@@ -358,3 +381,8 @@ _mu_url_ctx_parse (struct mu_url_ctx *ctx)
}
-
+ else
+ {
+ ctx->cur = save;
+ return _mu_url_ctx_parse_cred (ctx);
+ }
+
if (*ctx->cur == 0)
@@ -537,3 +565,4 @@ mu_url_create (mu_url_t *purl, const char *str)
MU_URL_PARSE_PIPE |
- MU_URL_PARSE_SLASH, NULL);
+ MU_URL_PARSE_SLASH |
+ MU_URL_PARSE_DSLASH_OPTIONAL, NULL);
}
diff --git a/libmu_cfg/acl.c b/libmu_cfg/acl.c
index cfa9a54c0..e39b5fbb9 100644
--- a/libmu_cfg/acl.c
+++ b/libmu_cfg/acl.c
@@ -24,2 +24,3 @@
#include "mailutils/argcv.h"
+#include "mailutils/cidr.h"
#include <stdlib.h>
@@ -55,49 +56,9 @@ getword (mu_config_value_t *val, int *pn)
-struct netdef
-{
- struct sockaddr *sa;
- int len;
- unsigned long netmask;
-};
-
-#ifndef INADDR_ANY
-# define INADDR_ANY 0
-#endif
-
-int
-parse_address (const char *str, struct netdef *nd)
-{
- struct sockaddr_in in;
-
- in.sin_family = AF_INET;
- if (strcmp (str, "any") == 0)
- {
- in.sin_addr.s_addr = INADDR_ANY;
- nd->netmask = 0;
- }
- else if (inet_aton (str, &in.sin_addr) == 0)
- {
- mu_error (_("invalid IPv4: %s"), str);
- return 1;
- }
- in.sin_port = 0;
- nd->len = sizeof (in);
- nd->sa = malloc (nd->len);
- if (!nd->sa)
- {
- mu_error ("%s", mu_strerror (errno));
- return 1;
- }
- memcpy (nd->sa, &in, sizeof (in));
- return 0;
-}
-
static int
-parsearg (mu_config_value_t *val, struct netdef *pnd, char **prest)
+parsearg (mu_config_value_t *val, struct mu_cidr *cidr, char **prest)
{
const char *w;
- char *p;
- unsigned long netmask;
int n = 0;
-
+ int rc;
+
if (mu_cfg_assert_value_type (val, MU_CFG_ARRAY))
@@ -113,37 +74,11 @@ parsearg (mu_config_value_t *val, struct netdef *pnd, char **prest)
}
-
- p = strchr (w, '/');
- if (p)
- {
- char *q;
- unsigned netlen;
- /* FIXME: This modifies a const char! */
- *p++ = 0;
- netlen = strtoul (p, &q, 10);
- if (*q == 0)
- {
- if (netlen == 0)
- netmask = 0;
- else
- {
- netmask = 0xfffffffful >> (32 - netlen);
- netmask <<= (32 - netlen);
- netmask = htonl (netmask);
- }
- }
- else if (*q == '.')
- {
- struct in_addr addr;
-
- if (inet_aton (p, &addr) == 0)
- {
- mu_error (_("invalid netmask"));
- return 1;
- }
- netmask = addr.s_addr;
- }
- else
+ if (strcmp (w, "any") == 0)
+ cidr->len = 0;
+ else
+ {
+ rc = mu_cidr_from_string (cidr, w);
+ if (rc)
{
- mu_error (_("invalid netmask"));
+ mu_error (_("invalid source CIDR: %s"), mu_strerror (rc));
return 1;
@@ -151,9 +86,3 @@ parsearg (mu_config_value_t *val, struct netdef *pnd, char **prest)
}
- else
- netmask = 0xfffffffful;
-
- pnd->netmask = netmask;
- if (parse_address (w, pnd))
- return 1;
-
+
if (prest)
@@ -206,11 +135,9 @@ cb_allow (void *data, mu_config_value_t *val)
mu_acl_t acl = *(mu_acl_t*)data;
- struct netdef ndef;
+ struct mu_cidr cidr;
- if (parsearg (val, &ndef, NULL))
+ if (parsearg (val, &cidr, NULL))
return 1;
- rc = mu_acl_append (acl, mu_acl_accept, NULL, ndef.sa, ndef.len,
- ndef.netmask);
+ rc = mu_acl_append (acl, mu_acl_accept, NULL, &cidr);
if (rc)
mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
- free (ndef.sa);
return rc;
@@ -223,11 +150,9 @@ cb_deny (void *data, mu_config_value_t *val)
mu_acl_t acl = *(mu_acl_t*)data;
- struct netdef ndef;
+ struct mu_cidr cidr;
- if (parsearg (val, &ndef, NULL))
+ if (parsearg (val, &cidr, NULL))
return 1;
- rc = mu_acl_append (acl, mu_acl_deny, NULL, ndef.sa, ndef.len,
- ndef.netmask);
+ rc = mu_acl_append (acl, mu_acl_deny, NULL, &cidr);
if (rc)
mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
- free (ndef.sa);
return rc;
@@ -240,12 +165,10 @@ cb_log (void *data, mu_config_value_t *val)
mu_acl_t acl = *(mu_acl_t*)data;
- struct netdef ndef;
+ struct mu_cidr cidr;
char *rest;
- if (parsearg (val, &ndef, &rest))
+ if (parsearg (val, &cidr, &rest))
return 1;
- rc = mu_acl_append (acl, mu_acl_log, rest, ndef.sa, ndef.len,
- ndef.netmask);
+ rc = mu_acl_append (acl, mu_acl_log, rest, &cidr);
if (rc)
mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
- free (ndef.sa);
return rc;
@@ -258,12 +181,10 @@ cb_exec (void *data, mu_config_value_t *val)
mu_acl_t acl = *(mu_acl_t*)data;
- struct netdef ndef;
+ struct mu_cidr cidr;
char *rest;
- if (parsearg (val, &ndef, &rest))
+ if (parsearg (val, &cidr, &rest))
return 1;
- rc = mu_acl_append (acl, mu_acl_exec, rest, ndef.sa, ndef.len,
- ndef.netmask);
+ rc = mu_acl_append (acl, mu_acl_exec, rest, &cidr);
if (rc)
mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
- free (ndef.sa);
return rc;
@@ -276,12 +197,10 @@ cb_ifexec (void *data, mu_config_value_t *val)
mu_acl_t acl = *(mu_acl_t*)data;
- struct netdef ndef;
+ struct mu_cidr cidr;
char *rest;
- if (parsearg (val, &ndef, &rest))
+ if (parsearg (val, &cidr, &rest))
return 1;
- rc = mu_acl_append (acl, mu_acl_ifexec, rest, ndef.sa, ndef.len,
- ndef.netmask);
+ rc = mu_acl_append (acl, mu_acl_ifexec, rest, &cidr);
if (rc)
mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
- free (ndef.sa);
return rc;
diff --git a/libproto/mailer/smtp.c b/libproto/mailer/smtp.c
index fdda4b653..892a0ce05 100644
--- a/libproto/mailer/smtp.c
+++ b/libproto/mailer/smtp.c
@@ -50,2 +50,3 @@
#include <mailutils/cstr.h>
+#include <mailutils/sockaddr.h>
#include <mailutils/sys/mailer.h>
@@ -116,4 +117,3 @@ smtp_open (mu_mailer_t mailer, int flags)
{
- const char *host, *auth;
- unsigned port;
+ const char *auth;
struct _smtp_mailer *smtp_mailer = mailer->data;
@@ -140,8 +140,2 @@ smtp_open (mu_mailer_t mailer, int flags)
- rc = mu_url_sget_host (mailer->url, &host);
- if (rc)
- return rc;
- if (mu_url_get_port (mailer->url, &port))
- port = 25;
-
if (mu_url_sget_auth (mailer->url, &auth) == 0)
@@ -168,3 +162,16 @@ smtp_open (mu_mailer_t mailer, int flags)
{
- rc = mu_tcp_stream_create (&mailer->stream, host, port, mailer->flags);
+ struct mu_sockaddr *sa;
+ struct mu_sockaddr_hints hints;
+
+ memset (&hints, 0, sizeof (hints));
+ hints.flags = MU_AH_DETECT_FAMILY;
+ hints.port = 25;
+ hints.protocol = IPPROTO_TCP;
+ hints.socktype = SOCK_STREAM;
+ rc = mu_sockaddr_from_url (&sa, mailer->url, &hints);
+ if (rc)
+ return rc;
+
+ rc = mu_tcp_stream_create_from_sa (&mailer->stream, sa, NULL,
+ mailer->flags);
if (rc)
diff --git a/libproto/pop/mbox.c b/libproto/pop/mbox.c
index 67d97a9aa..79854aebc 100644
--- a/libproto/pop/mbox.c
+++ b/libproto/pop/mbox.c
@@ -29,2 +29,3 @@
#include <unistd.h>
+#include <netdb.h>
@@ -52,2 +53,3 @@
#include <mailutils/opool.h>
+#include <mailutils/sockaddr.h>
@@ -111,6 +113,6 @@ pop_open (mu_mailbox_t mbox, int flags)
int status;
- const char *host;
- unsigned port = mpd->pops ? MU_POPS_PORT : MU_POP_PORT;
mu_stream_t stream;
-
+ struct mu_sockaddr *sa;
+ struct mu_sockaddr_hints hints;
+
/* Sanity checks. */
@@ -119,11 +121,14 @@ pop_open (mu_mailbox_t mbox, int flags)
- /* Fetch the pop server name and the port in the mu_url_t. */
- status = mu_url_sget_host (mbox->url, &host);
- if (status != 0)
- return status;
- mu_url_get_port (mbox->url, &port);
-
mbox->flags = flags;
-
- status = mu_tcp_stream_create (&stream, host, port, mbox->flags);
+
+ memset (&hints, 0, sizeof (hints));
+ hints.flags = MU_AH_DETECT_FAMILY;
+ hints.port = mpd->pops ? MU_POPS_PORT : MU_POP_PORT;
+ hints.protocol = IPPROTO_TCP;
+ hints.socktype = SOCK_STREAM;
+ status = mu_sockaddr_from_url (&sa, mbox->url, &hints);
+ if (status)
+ return status;
+
+ status = mu_tcp_stream_create_from_sa (&stream, sa, NULL, mbox->flags);
if (status)
diff --git a/mu/acl.c b/mu/acl.c
index 9e9fd8b88..4f796c582 100644
--- a/mu/acl.c
+++ b/mu/acl.c
@@ -43,4 +43,3 @@ static struct argp_option acl_options[] = {
static char *input_file_name;
-static struct sockaddr *target_sa;
-static socklen_t target_salen;
+static struct mu_sockaddr *target_sa;
static mu_acl_t acl;
@@ -48,27 +47,2 @@ static const char *path = "acl";
-static struct sockaddr *
-parse_address (socklen_t *psalen, const char *str)
-{
- struct sockaddr_in in;
- struct sockaddr *sa;
-
- in.sin_family = AF_INET;
- if (inet_aton (str, &in.sin_addr) == 0)
- {
- mu_error ("Invalid IPv4: %s", str);
- exit (1);
- }
- in.sin_port = 0;
- *psalen = sizeof (in);
- sa = malloc (*psalen);
- if (!sa)
- {
- mu_error ("%s", mu_strerror (errno));
- exit (1);
- }
-
- memcpy (sa, &in, sizeof (in));
- return sa;
-}
-
static error_t
@@ -162,5 +136,13 @@ mutool_acl (int argc, char **argv)
- target_sa = parse_address (&target_salen, ap);
+ rc = mu_sockaddr_from_node (&target_sa, ap, NULL, NULL);
+ if (rc)
+ {
+ mu_error ("mu_sockaddr_from_node: %s", mu_strerror (rc));
+ exit (1);
+ }
+
mu_printf ("Testing %s:\n", ap);
- rc = mu_acl_check_sockaddr (acl, target_sa, target_salen, &result);
+ rc = mu_acl_check_sockaddr (acl, target_sa->addr, target_sa->addrlen,
+ &result);
+ mu_sockaddr_free_list (target_sa);
if (rc)
diff --git a/mu/imap.c b/mu/imap.c
index 85a27a343..deea939f2 100644
--- a/mu/imap.c
+++ b/mu/imap.c
@@ -115,3 +115,2 @@ static char **connect_argv;
#define host connect_argv[0]
-static int port = MU_IMAP_DEFAULT_PORT;
@@ -173,3 +172,2 @@ com_connect (int argc, char **argv)
int status;
- int n = 0;
int tls = 0;
@@ -196,12 +194,2 @@ com_connect (int argc, char **argv)
- if (argc >= 2)
- {
- if (get_port (argv[1], &n))
- return 0;
- }
- else if (tls)
- n = MU_IMAP_DEFAULT_SSL_PORT;
- else
- n = MU_IMAP_DEFAULT_PORT;
-
state = current_imap_state ();
@@ -215,2 +203,4 @@ com_connect (int argc, char **argv)
mu_stream_t tcp;
+ struct mu_sockaddr *sa;
+ struct mu_sockaddr_hints hints;
@@ -221,3 +211,11 @@ com_connect (int argc, char **argv)
}
- status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ);
+
+ memset (&hints, 0, sizeof (hints));
+ hints.flags = MU_AH_DETECT_FAMILY;
+ hints.port = tls ? MU_IMAP_DEFAULT_SSL_PORT : MU_IMAP_DEFAULT_PORT;
+ hints.protocol = IPPROTO_TCP;
+ hints.socktype = SOCK_STREAM;
+ status = mu_sockaddr_from_node (&sa, argv[0], argv[1], &hints);
+ if (status == 0)
+ status = mu_tcp_stream_create_from_sa (&tcp, sa, NULL, 0);
if (status == 0)
@@ -265,3 +263,2 @@ com_connect (int argc, char **argv)
connect_argv[i] = NULL;
- port = n;
diff --git a/mu/pop.c b/mu/pop.c
index d72091cb1..de092cd5f 100644
--- a/mu/pop.c
+++ b/mu/pop.c
@@ -22,2 +22,6 @@
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netdb.h>
#include <mailutils/mailutils.h>
@@ -472,2 +476,18 @@ com_disconnect (int argc MU_ARG_UNUSED, char **argv MU_ARG_UNUSED)
static int
+port_from_sa (struct mu_sockaddr *sa)
+{
+ switch (sa->addr->sa_family)
+ {
+ case AF_INET:
+ return ntohs (((struct sockaddr_in *)sa->addr)->sin_port);
+
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ return ntohs (((struct sockaddr_in6 *)sa->addr)->sin6_port);
+#endif
+ }
+ return 0;
+}
+
+static int
com_connect (int argc, char **argv)
@@ -475,5 +495,5 @@ com_connect (int argc, char **argv)
int status;
- int n = 0;
int tls = 0;
int i = 1;
+ int n;
@@ -498,12 +518,2 @@ com_connect (int argc, char **argv)
- if (argc >= 2)
- {
- if (get_port (argv[1], &n))
- return 0;
- }
- else if (tls)
- n = MU_POP3_DEFAULT_SSL_PORT;
- else
- n = MU_POP3_DEFAULT_PORT;
-
if (pop_session_status != pop_session_disconnected)
@@ -515,2 +525,4 @@ com_connect (int argc, char **argv)
mu_stream_t tcp;
+ struct mu_sockaddr *sa;
+ struct mu_sockaddr_hints hints;
@@ -521,3 +533,14 @@ com_connect (int argc, char **argv)
}
- status = mu_tcp_stream_create (&tcp, argv[0], n, MU_STREAM_READ);
+
+ memset (&hints, 0, sizeof (hints));
+ hints.flags = MU_AH_DETECT_FAMILY;
+ hints.port = tls ? MU_POP3_DEFAULT_SSL_PORT : MU_POP3_DEFAULT_PORT;
+ hints.protocol = IPPROTO_TCP;
+ hints.socktype = SOCK_STREAM;
+ status = mu_sockaddr_from_node (&sa, argv[0], argv[1], &hints);
+ if (status == 0)
+ {
+ n = port_from_sa (sa);
+ status = mu_tcp_stream_create_from_sa (&tcp, sa, NULL, 0);
+ }
if (status == 0)
diff --git a/testsuite/smtpsend.c b/testsuite/smtpsend.c
index e831968f5..2fe2d9f52 100644
--- a/testsuite/smtpsend.c
+++ b/testsuite/smtpsend.c
@@ -22,2 +22,3 @@
#include <stdlib.h>
+#include <netdb.h>
#include <mailutils/cctype.h>
@@ -87,3 +88,3 @@ main (int argc, char **argv)
char *infile = NULL;
- int port = 25;
+ char *port = NULL;
int tls = 0;
@@ -98,2 +99,4 @@ main (int argc, char **argv)
mu_list_t skiphdr_list = NULL;
+ struct mu_sockaddr *sa;
+ struct mu_sockaddr_hints hints;
@@ -113,10 +116,3 @@ main (int argc, char **argv)
if (strncmp (argv[i], "port=", 5) == 0)
- {
- port = atoi (argv[i] + 5);
- if (port == 0)
- {
- mu_error ("invalid port");
- return 1;
- }
- }
+ port = argv[i] + 5;
else if (strncmp (argv[i], "trace=", 6) == 0)
@@ -196,3 +192,12 @@ main (int argc, char **argv)
host = argv[1];
- MU_ASSERT (mu_tcp_stream_create (&stream, host, port, MU_STREAM_RDWR));
+
+ memset (&hints, 0, sizeof (hints));
+ hints.flags = MU_AH_DETECT_FAMILY;
+ hints.port = 25;
+ hints.protocol = IPPROTO_TCP;
+ hints.socktype = SOCK_STREAM;
+ MU_ASSERT (mu_sockaddr_from_node (&sa, host, port, &hints));
+
+ MU_ASSERT (mu_tcp_stream_create_from_sa (&stream, sa, NULL, MU_STREAM_RDWR));
+
mu_smtp_set_carrier (smtp, stream);

Return to:

Send suggestions and report system problems to the System administrator.