summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2011-03-30 00:49:43 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2011-03-30 15:51:47 +0300
commitadca074d616ac562095a92e01f2b181e6d3593c8 (patch)
treef4c11a1c11fcb137cfada7643e6f284465a75c16
parent827cb66a4c639139c3f11c7af26aa5149f25a7e0 (diff)
downloadmailutils-adca074d616ac562095a92e01f2b181e6d3593c8.tar.gz
mailutils-adca074d616ac562095a92e01f2b181e6d3593c8.tar.bz2
Implement IPv6 support.
* am/ipv6.m4: New file. * examples/sa.c: New file. * include/mailutils/cidr.h: New file. * include/mailutils/sockaddr.h: New file. * libmailutils/cidr/Makefile.am: New file. * libmailutils/cidr/fromsa.c: New file. * libmailutils/cidr/fromstr.c: New file. * libmailutils/cidr/match.c: New file. * libmailutils/cidr/tosa.c: New file. * libmailutils/cidr/tostr.c: New file. * libmailutils/sockaddr/Makefile.am: New file. * libmailutils/sockaddr/copy.c: New file. * libmailutils/sockaddr/create.c: New file. * libmailutils/sockaddr/free.c: New file. * libmailutils/sockaddr/fromnode.c: New file. * libmailutils/sockaddr/insert.c: New file. * libmailutils/sockaddr/ipaddr.c: New file. * libmailutils/sockaddr/str.c: New file. * libmailutils/sockaddr/unlink.c: New file. * libmailutils/sockaddr/url.c: New file. * libmailutils/tests/cidr.c: New file. * configure.ac: Call MU_ENABLE_IPV6. Build libmailutils/sockaddr and libmailutils/cidr. * examples/.gitignore: Add mblconv and sa * examples/Makefile.am: (noinst_PROGRAMS): Add sa. * examples/aclck.c: Use new ACL API. * examples/echosrv.c: Use new mserv API. * include/mailutils/Makefile.am (pkginclude_HEADERS): Add cidr.h and sockaddr.h * include/mailutils/acl.h (mu_acl_append, mu_acl_prepend) (mu_acl_insert): Change signatures. * include/mailutils/debug.h (mu_sockaddr_to_str): Remove proto. * include/mailutils/mailutils.h: Include cidr.h and sockaddr.h * include/mailutils/server.h (mu_ip_server_create): Change signature. (mu_ip_server_get_sockaddr): Likewise. (mu_m_server_set_default_address) (mu_m_server_get_default_address): Remove. * include/mailutils/stream.h (mu_tcp_stream_create_from_sa): New proto. * include/mailutils/types.hin (mu_cidr, mu_sockaddr): New structs. * include/mailutils/url.h (MU_URL_IPV6): New flag. (MU_URL_PARSE_DSLASH_OPTIONAL): New parse flag. * libmailutils/Makefile.am: Descend into cidr and sockaddr. Link in libcidr and libsockaddr. * libmailutils/diag/debug.c (mu_debug_log_begin): Flush mu_strerr. * libmailutils/diag/errors (MU_ERR_NONAME) (MU_ERR_BADFLAGS,MU_ERR_SOCKTYPE) (MU_ERR_FAMILY,MU_ERR_SERVICE): New errors. * libmailutils/server/acl.c: Rewrite API using mu_cidr. * libmailutils/server/ipsrv.c: Rewrite AI using mu_sockaddr. * libmailutils/server/msrv.c: Likewise. * libmailutils/stream/tcp.c: Likewise. * libmailutils/tests/.gitignore: Add cidr. * libmailutils/tests/Makefile.am (noinst_PROGRAMS): Add cidr. * libmailutils/tests/url-parse.c: Support command line options to tune the parsing. * libmailutils/tests/url.at: Pass options to url-parse. * libmailutils/url/create.c (getkn): Return meaningful error code. (_mu_url_ctx_parse_host): Accept IPv6 addresses. Set the MU_URL_IPV6 flag if one is given. (_mu_url_ctx_parse): Unless MU_URL_PARSE_DSLASH_OPTIONAL flag is given, request :// after scheme part. (mu_url_create): Add MU_URL_PARSE_DSLASH_OPTIONAL flag. * libmu_cfg/acl.c: Use new ACL API. * mu/acl.c: Likewise. * libproto/mailer/smtp.c (smtp_open): Use mu_tcp_stream_create_from_sa * libproto/pop/mbox.c (pop_open): Likewise. * mu/imap.c (com_connect): Likewise. * mu/pop.c (com_connect): Likewise. * testsuite/smtpsend.c (main): Likewise.
-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
@@ -541,6 +541,10 @@ AH_BOTTOM([
])
+# IPv6 support
+MU_ENABLE_IPV6
+
+
## FriBidi support
AC_CHECK_FUNCS(wcwidth)
@@ -1285,6 +1289,8 @@ LDAP support .................. $status_ldap
Radius support ................ $status_radius
Support for virtual domains ... $status_virtual_domains
+IPv6 support .................. $status_ipv6
+
Interfaces:
Guile ......................... $status_guile
@@ -1332,6 +1338,7 @@ status_mh=$mu_cv_enable_mh
status_maildir=$mu_cv_enable_maildir
status_smtp=$mu_cv_enable_smtp
status_sendmail=$mu_cv_enable_sendmail
+status_ipv6=$status_ipv6
])
dnl Output Makefiles
@@ -1382,6 +1389,8 @@ AC_CONFIG_FILES([
libmailutils/auth/Makefile
libmailutils/base/Makefile
libmailutils/address/Makefile
+ libmailutils/sockaddr/Makefile
+ libmailutils/cidr/Makefile
libmailutils/cfg/Makefile
libmailutils/diag/Makefile
libmailutils/filter/Makefile
diff --git a/examples/.gitignore b/examples/.gitignore
index af4156be3..890812aae 100644
--- a/examples/.gitignore
+++ b/examples/.gitignore
@@ -11,6 +11,7 @@ iconv
listop
lsf
mailcap
+mblconv
mimetest
msg-send
mta
@@ -20,5 +21,6 @@ muemail
murun
musocio
nntpclient
+sa
sfrom
url-parse
diff --git a/examples/Makefile.am b/examples/Makefile.am
index e22a8d355..9df91ea62 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -43,6 +43,7 @@ noinst_PROGRAMS = \
murun\
musocio\
$(NNTPCLIENT)\
+ sa\
sfrom
EXTRA_PROGRAMS = nntpclient
diff --git a/examples/aclck.c b/examples/aclck.c
index 57f5c0388..033c444b1 100644
--- a/examples/aclck.c
+++ b/examples/aclck.c
@@ -28,35 +28,9 @@
#include <stdlib.h>
#include <string.h>
-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
read_rules (FILE *fp)
{
@@ -76,12 +50,9 @@ read_rules (FILE *fp)
ws.ws_comment = "#";
while (fgets (buf, sizeof buf, fp))
{
- unsigned long netmask;
- int salen;
- struct sockaddr *sa;
+ struct mu_cidr cidr;
mu_acl_action_t action;
void *data = NULL;
- char *p;
int len = strlen (buf);
if (len == 0)
@@ -109,47 +80,19 @@ read_rules (FILE *fp)
continue;
}
- 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;
}
}
- else
- netmask = 0xfffffffful;
-
- sa = parse_address (&salen, ws.ws_wordv[1]);
-
+
/* accept addr
deny addr
log addr [rest ...]
@@ -174,7 +117,7 @@ read_rules (FILE *fp)
data = strdup (ws.ws_wordv[2]);
}
- rc = mu_acl_append (acl, action, data, sa, salen, netmask);
+ rc = mu_acl_append (acl, action, data, &cidr);
if (rc)
mu_error ("%d: cannot append acl entry: %s", line,
mu_strerror (rc));
@@ -203,7 +146,12 @@ main (int argc, char **argv)
break;
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;
case 'f':
@@ -225,7 +173,8 @@ main (int argc, char **argv)
argc -= optind;
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)
{
mu_error ("mu_acl_check_sockaddr failed: %s", mu_strerror (rc));
diff --git a/examples/echosrv.c b/examples/echosrv.c
index fb68e7aee..fffde7343 100644
--- a/examples/echosrv.c
+++ b/examples/echosrv.c
@@ -39,13 +39,9 @@ echo_conn (int fd, struct sockaddr *s, int len,
void *server_data, void *call_data,
mu_ip_server_t srv)
{
- struct sockaddr_in srv_addr, *s_in = (struct sockaddr_in *)s;
- int addrlen = sizeof srv_addr;
pid_t pid;
char buf[512];
FILE *in, *out;
-
- mu_ip_server_get_sockaddr (srv, (struct sockaddr *)&srv_addr, &addrlen);
pid = fork ();
if (pid == -1)
@@ -56,10 +52,20 @@ echo_conn (int fd, struct sockaddr *s, int len,
if (pid)
{
- 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;
}
@@ -108,34 +114,45 @@ tcp_conn_free (void *conn_data, void *server_data)
void
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));
MU_ASSERT (mu_ip_server_set_conn (tcpsrv, echo_conn));
MU_ASSERT (mu_server_add_connection (server,
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
@@ -36,6 +36,7 @@ pkginclude_HEADERS = \
body.h\
cctype.h\
cfg.h\
+ cidr.h\
cstr.h\
daemon.h\
debug.h\
@@ -89,6 +90,7 @@ pkginclude_HEADERS = \
server.h\
sieve.h\
smtp.h\
+ sockaddr.h\
stdstream.h\
stream.h\
syslog.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
@@ -47,13 +47,11 @@ int mu_acl_destroy (mu_acl_t *acl);
int mu_acl_count (mu_acl_t acl, size_t *pcount);
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 *);
int mu_acl_check_ipv4 (mu_acl_t acl, unsigned int addr, mu_acl_result_t *pres);
int mu_acl_check_inaddr (mu_acl_t acl, const struct in_addr *inp,
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
@@ -54,9 +54,6 @@ 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
@@ -67,5 +67,7 @@
#include <mailutils/log.h>
#include <mailutils/stdstream.h>
#include <mailutils/prog.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/cidr.h>
/* EOF */
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
@@ -54,8 +54,8 @@ typedef void (*mu_ip_server_free_fp) (void *data);
#define MU_IP_TCP 0
#define MU_IP_UDP 1
-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);
int mu_ip_server_get_type (mu_ip_server_t srv, int *ptype);
int mu_ip_server_set_ident (mu_ip_server_t srv, const char *ident);
@@ -69,8 +69,8 @@ int mu_ip_server_shutdown (mu_ip_server_t srv);
int mu_ip_server_accept (mu_ip_server_t srv, void *call_data);
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);
int mu_tcp_server_set_backlog (mu_ip_server_t srv, int backlog);
int mu_udp_server_set_bufsize (mu_ip_server_t srv, size_t size);
@@ -99,8 +99,6 @@ void mu_m_server_set_max_children (mu_m_server_t srv, size_t num);
int mu_m_server_set_pidfile (mu_m_server_t srv, const char *pidfile);
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);
void mu_m_server_set_mode (mu_m_server_t srv, int mode);
void mu_m_server_set_sigset (mu_m_server_t srv, sigset_t *sigset);
@@ -112,8 +110,6 @@ time_t mu_m_server_timeout (mu_m_server_t srv);
const char * mu_m_server_pidfile (mu_m_server_t srv);
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);
void mu_m_server_configured_count (mu_m_server_t msrv, size_t count);
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
@@ -315,6 +315,10 @@ int mu_streamref_create_abridged (mu_stream_t *pref, mu_stream_t str,
mu_off_t start, mu_off_t end);
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,
const char *host, unsigned port,
unsigned long source_ip,
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
@@ -75,6 +75,9 @@ struct _mu_assoc;
struct _mu_acl;
struct _mu_server;
struct _mu_tcp_server;
+
+struct mu_sockaddr; /* defined in mailutils/sockaddr.h */
+struct mu_cidr; /* defined in mailutils/cidr.h */
typedef _MU_OFF_TYPE_ mu_off_t;
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
@@ -34,6 +34,7 @@ extern "C" {
#define MU_URL_PATH 0x0040 /* Has path */
#define MU_URL_PARAM 0x0080 /* Has parameters */
#define MU_URL_QUERY 0x0100 /* Has query */
+#define MU_URL_IPV6 0x0200 /* Host part is bracketed (IPv6) */
#define MU_URL_CRED (MU_URL_USER | MU_URL_SECRET | MU_URL_AUTH)
/* Has some of authentication credentials */
@@ -53,12 +54,14 @@ extern "C" {
#define MU_URL_PARSE_PORTSRV 0x0004 /* Use getservbyname to determine
port number */
#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 \
(MU_URL_PARSE_HEXCODE|MU_URL_PARSE_HIDEPASS|MU_URL_PARSE_PORTSRV|\
MU_URL_PARSE_PIPE|MU_URL_PARSE_SLASH)
diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am
index ed1aeb019..5aef3382d 100644
--- a/libmailutils/Makefile.am
+++ b/libmailutils/Makefile.am
@@ -16,7 +16,7 @@
# Public License along with this library. If not, see
# <http://www.gnu.org/licenses/>.
-SUBDIRS = auth base address cfg diag filter mailbox mailer mime\
+SUBDIRS = auth base address sockaddr cidr cfg diag filter mailbox mailer mime\
server string stream stdstream property url . tests
lib_LTLIBRARIES = libmailutils.la
@@ -28,6 +28,8 @@ libmailutils_la_LIBADD = \
auth/libauth.la\
base/libbase.la\
address/libaddress.la\
+ sockaddr/libsockaddr.la\
+ cidr/libcidr.la\
cfg/libcfg.la\
diag/libdiag.la\
filter/libfilter.la\
diff --git a/libmailutils/cidr/Makefile.am b/libmailutils/cidr/Makefile.am
new file mode 100644
index 000000000..408806f79
--- /dev/null
+++ b/libmailutils/cidr/Makefile.am
@@ -0,0 +1,27 @@
+# GNU Mailutils -- a suite of utilities for electronic mail
+# Copyright (C) 2011 Free Software Foundation, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General
+# Public License along with this library. If not, see
+# <http://www.gnu.org/licenses/>.
+
+noinst_LTLIBRARIES = libcidr.la
+
+libcidr_la_SOURCES = \
+ fromsa.c\
+ fromstr.c\
+ match.c\
+ tosa.c\
+ tostr.c
+
+INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
diff --git a/libmailutils/cidr/fromsa.c b/libmailutils/cidr/fromsa.c
new file mode 100644
index 000000000..a2fda6680
--- /dev/null
+++ b/libmailutils/cidr/fromsa.c
@@ -0,0 +1,101 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+
+static void
+uint32_to_bytes (unsigned char *bytes, uint32_t u)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ {
+ bytes[i] = u & 0xff;
+ u >>= 8;
+ }
+}
+
+int
+_mu_inaddr_to_bytes (int af, void *buf, unsigned char *bytes)
+{
+ uint32_t u;
+
+ switch (af)
+ {
+ case AF_INET:
+ memcpy (&u, buf, sizeof u);
+ uint32_to_bytes (bytes, u);
+ return 4;
+
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ memcpy (bytes, buf, 16);
+ return 16;
+#endif
+ }
+ return 0;
+}
+
+int
+_mu_sockaddr_to_bytes (unsigned char *bytes, struct sockaddr const *sa)
+{
+ switch (sa->sa_family)
+ {
+ case AF_INET:
+ uint32_to_bytes (bytes, ((struct sockaddr_in*)sa)->sin_addr.s_addr);
+ return 4;
+
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ memcpy (bytes, &((struct sockaddr_in6*)sa)->sin6_addr, 16);
+ return 16;
+#endif
+ }
+ return 0;
+}
+
+int
+mu_cidr_from_sockaddr (struct mu_cidr *cidr, const struct sockaddr *sa)
+{
+ unsigned char address[MU_INADDR_BYTES];
+ int len;
+ int i;
+
+ len = _mu_sockaddr_to_bytes (address, sa);
+ if (len == 0)
+ return MU_ERR_FAMILY;
+ cidr->family = sa->sa_family;
+ cidr->len = len;
+ memcpy (cidr->address, address, sizeof (cidr->address));
+ for (i = 0; i < MU_INADDR_BYTES; i++)
+ cidr->netmask[i] = 0xff;
+ return 0;
+}
+
+
diff --git a/libmailutils/cidr/fromstr.c b/libmailutils/cidr/fromstr.c
new file mode 100644
index 000000000..4e7a56f80
--- /dev/null
+++ b/libmailutils/cidr/fromstr.c
@@ -0,0 +1,128 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+#include <mailutils/sockaddr.h>
+
+static void
+masklen_to_netmask (unsigned char *buf, size_t len, size_t masklen)
+{
+ int i, cnt;
+
+ cnt = masklen / 8;
+ for (i = 0; i < cnt; i++)
+ buf[i] = 0xff;
+ if (i == MU_INADDR_BYTES)
+ return;
+ cnt = 8 - masklen % 8;
+ buf[i++] = (0xff >> cnt) << cnt;
+ for (; i < MU_INADDR_BYTES; i++)
+ buf[i] = 0;
+}
+
+int
+mu_cidr_from_string (struct mu_cidr *pcidr, const char *str)
+{
+ int rc;
+ char ipbuf[41];
+ struct mu_cidr cidr;
+ char *p;
+ size_t len;
+ union
+ {
+ struct in_addr in;
+#ifdef MAILUTILS_IPV6
+ struct in6_addr in6;
+#endif
+ } inaddr;
+
+ p = strchr (str, '/');
+ if (p)
+ len = p - str;
+ else
+ len = strlen (str);
+
+ if (len > sizeof (ipbuf))
+ return MU_ERR_BUFSPACE;
+
+ memcpy (ipbuf, str, len);
+ ipbuf[len] = 0;
+
+ if (mu_str_is_ipv4 (ipbuf))
+ cidr.family = AF_INET;
+#ifdef MAILUTILS_IPV6
+ else if (mu_str_is_ipv6 (ipbuf))
+ cidr.family = AF_INET6;
+#endif
+ else
+ return MU_ERR_FAMILY;
+
+ rc = inet_pton (cidr.family, ipbuf, &inaddr);
+ if (rc == -1)
+ return MU_ERR_FAMILY;
+ else if (rc == 0)
+ return MU_ERR_NONAME;
+ else if (rc != 1)
+ return MU_ERR_FAILURE;
+
+ cidr.len = _mu_inaddr_to_bytes (cidr.family, &inaddr, cidr.address);
+ if (cidr.len == 0)
+ return MU_ERR_FAMILY;
+
+ if (p)
+ {
+ char *end;
+ unsigned long masklen;
+
+ p++;
+
+ masklen = strtoul (p, &end, 10);
+ if (*end == 0)
+ masklen_to_netmask (cidr.netmask, cidr.len, masklen);
+ else if ((cidr.family == AF_INET && mu_str_is_ipv4 (p))
+#ifdef MAILUTILS_IPV6
+ || (cidr.family == AF_INET6 && mu_str_is_ipv6 (ipbuf))
+#endif
+ )
+ {
+ rc = inet_pton (cidr.family, p, &inaddr);
+ if (rc == -1)
+ return MU_ERR_FAMILY;
+ else if (rc == 0)
+ return MU_ERR_NONAME;
+ else if (rc != 1)
+ return MU_ERR_FAILURE;
+
+ _mu_inaddr_to_bytes (cidr.family, &inaddr, cidr.netmask);
+ }
+ else
+ return MU_ERR_FAMILY;
+ }
+ else
+ masklen_to_netmask (cidr.netmask, cidr.len, cidr.len * 8);
+
+ memcpy (pcidr, &cidr, sizeof (*pcidr));
+ return 0;
+}
+
diff --git a/libmailutils/cidr/match.c b/libmailutils/cidr/match.c
new file mode 100644
index 000000000..dff9194ee
--- /dev/null
+++ b/libmailutils/cidr/match.c
@@ -0,0 +1,38 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+
+int
+mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b)
+{
+ int i;
+
+ if (a->family != b->family)
+ return 1;
+ for (i = 0; i < a->len; i++)
+ {
+ if (a->address[i] != (b->address[i] & a->netmask[i]))
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/libmailutils/cidr/tosa.c b/libmailutils/cidr/tosa.c
new file mode 100644
index 000000000..c14a995da
--- /dev/null
+++ b/libmailutils/cidr/tosa.c
@@ -0,0 +1,78 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include <stdlib.h>
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+
+int
+mu_cidr_to_sockaddr (struct mu_cidr *cidr, struct sockaddr **psa)
+{
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in s_in;
+#ifdef MAILUTILS_IPV6
+ struct sockaddr_in6 s_in6;
+#endif
+ } addr;
+ struct sockaddr *sa;
+ int socklen;
+ int i;
+
+ memset (&addr, 0, sizeof (addr));
+ addr.sa.sa_family = cidr->family;
+ switch (cidr->family)
+ {
+ case AF_INET:
+ socklen = sizeof (addr.s_in);
+ for (i = 0; i < cidr->len; i++)
+ {
+ addr.s_in.sin_addr.s_addr <<= 8;
+ addr.s_in.sin_addr.s_addr |= cidr->address[i];
+ }
+ break;
+
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ socklen = sizeof (addr.s_in6);
+ memcpy (&addr.s_in6.sin6_addr, cidr->address, 16);
+ break;
+#endif
+
+ default:
+ return MU_ERR_FAMILY;
+ }
+
+ sa = malloc (socklen);
+ if (!sa)
+ return ENOMEM;
+ memcpy (sa, &addr, socklen);
+ *psa = sa;
+ return 0;
+}
+
diff --git a/libmailutils/cidr/tostr.c b/libmailutils/cidr/tostr.c
new file mode 100644
index 000000000..3d1ee5f49
--- /dev/null
+++ b/libmailutils/cidr/tostr.c
@@ -0,0 +1,159 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include <mailutils/cidr.h>
+#include <mailutils/errno.h>
+
+static int
+to_xdig (unsigned char b)
+{
+ if (b >= 0xa)
+ return 'A' + b - 0xa;
+ else
+ return '0' + b;
+}
+
+static size_t
+format_ipv6_bytes (const unsigned char *bytes, int len,
+ char *buf, size_t size)
+{
+ size_t total = 0;
+ int i;
+
+ for (i = 0; i < len; i += 2)
+ {
+ if (i)
+ {
+ if (total++ < size)
+ *buf++ = ':';
+ }
+ if (total++ < size)
+ *buf++ = to_xdig (*bytes >> 4);
+ if (total++ < size)
+ *buf++ = to_xdig (*bytes & 0xf);
+ bytes++;
+ if (total++ < size)
+ *buf++ = to_xdig (*bytes >> 4);
+ if (total++ < size)
+ *buf++ = to_xdig (*bytes & 0xf);
+ bytes++;
+ }
+ return total;
+}
+
+static size_t
+format_ipv4_bytes (const unsigned char *bytes, int len,
+ char *buf, size_t size)
+{
+ int i;
+ size_t total = 0;
+
+ for (i = 0; i < len; i++)
+ {
+ unsigned char b = *bytes++;
+ char nbuf[3];
+ int j;
+
+ if (i)
+ {
+ if (total++ < size)
+ *buf++ = '.';
+ }
+
+ j = 0;
+ do
+ {
+ nbuf[j++] = b % 10 + '0';
+ b /= 10;
+ }
+ while (b);
+
+ for (; j; j--)
+ {
+ if (total++ < size)
+ *buf++ = nbuf[j - 1];
+ }
+ }
+ return total;
+}
+
+int
+mu_cidr_to_string (struct mu_cidr *cidr, int flags,
+ char *buf, size_t size, size_t *pret)
+{
+ size_t (*fmt) (const unsigned char *bytes, int len, char *buf, size_t size);
+ size_t n, total = 0;
+
+ if (size == 0)
+ return MU_ERR_BUFSPACE;
+ size--;
+ switch (cidr->family)
+ {
+ case AF_INET:
+ fmt = format_ipv4_bytes;
+ break;
+
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ fmt = format_ipv6_bytes;
+ break;
+#endif
+
+ default:
+ return MU_ERR_FAMILY;
+ }
+
+ n = fmt (cidr->address, cidr->len, buf, size);
+ if (buf)
+ buf += n;
+ total += n;
+
+ if (!(flags & MU_CIDR_FMT_ADDRONLY))
+ {
+ if (total++ < size)
+ *buf++ = '/';
+ n = fmt (cidr->netmask, cidr->len, buf, size - total);
+ if (buf)
+ buf += n;
+ total += n;
+ }
+
+ if (buf)
+ *buf++ = 0;
+ if (pret)
+ *pret = total;
+ return 0;
+}
+
+int
+mu_cidr_format (struct mu_cidr *cidr, int flags, char **pbuf)
+{
+ char buf[MU_CIDR_MAXBUFSIZE];
+ int rc = mu_cidr_to_string (cidr, flags, buf, sizeof (buf), NULL);
+ if (rc)
+ return rc;
+ *pbuf = strdup (buf);
+ if (!*buf)
+ return ENOMEM;
+ return 0;
+}
+
diff --git a/libmailutils/diag/debug.c b/libmailutils/diag/debug.c
index 124311bd8..aa10e41ba 100644
--- a/libmailutils/diag/debug.c
+++ b/libmailutils/diag/debug.c
@@ -689,6 +689,7 @@ mu_debug_log_begin (const char *fmt, ...)
va_list ap;
mu_diag_init ();
+ mu_stream_flush (mu_strerr);
va_start (ap, fmt);
mu_stream_printf (mu_strerr, "\033s<%d>", MU_LOG_DEBUG);
mu_stream_vprintf (mu_strerr, fmt, ap);
diff --git a/libmailutils/diag/errors b/libmailutils/diag/errors
index 869e4146f..03f71b715 100644
--- a/libmailutils/diag/errors
+++ b/libmailutils/diag/errors
@@ -1,3 +1,4 @@
+
# Error messages for GNU Mailutils
# Copyright (C) 2005, 2006, 2007, 2010, 2011 Free Software Foundation,
# Inc.
@@ -98,3 +99,10 @@ MU_ERR_URL_MISS_PARTS _("URL missing required parts")
MU_ERR_URL_EXTRA_PARTS _("URL has parts not allowed by its scheme")
MU_ERR_INFO_UNAVAILABLE _("Information is not yet available")
+
+# The following are mapped to the corresponding EAI_ errors
+MU_ERR_NONAME _("Name or service not known")
+MU_ERR_BADFLAGS _("Bad value for flags")
+MU_ERR_SOCKTYPE _("Socket type not supported")
+MU_ERR_FAMILY _("Address family not supported")
+MU_ERR_SERVICE _("Requested service not supported")
diff --git a/libmailutils/server/acl.c b/libmailutils/server/acl.c
index 0b7a507e0..ba1a4b86b 100644
--- a/libmailutils/server/acl.c
+++ b/libmailutils/server/acl.c
@@ -40,14 +40,20 @@
#include <mailutils/kwd.h>
#include <mailutils/io.h>
#include <mailutils/util.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/cidr.h>
+#include <mailutils/stream.h>
+#include <mailutils/stdstream.h>
+
+#ifndef MU_INADDR_BYTES
+#define MU_INADDR_BYTES 16
+#endif
struct _mu_acl_entry
{
mu_acl_action_t action;
void *arg;
- unsigned netmask;
- int salen;
- struct sockaddr sa[1];
+ struct mu_cidr cidr;
};
struct _mu_acl
@@ -64,52 +70,19 @@ _destroy_acl_entry (void *item)
/* FIXME: free arg? */
}
-static size_t
-mu_acl_entry_size (int salen)
-{
- return sizeof (struct _mu_acl_entry) + salen - sizeof (struct sockaddr);
-}
-
-static int
-prepare_sa (struct sockaddr *sa)
-{
- switch (sa->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
- s_in->sin_addr.s_addr = ntohl (s_in->sin_addr.s_addr);
- break;
- }
-
- case AF_UNIX:
- break;
-
- default:
- return 1;
- }
- return 0;
-}
-
int
mu_acl_entry_create (struct _mu_acl_entry **pent,
mu_acl_action_t action, void *data,
- struct sockaddr *sa, int salen, unsigned long netmask)
+ struct mu_cidr *cidr)
{
- struct _mu_acl_entry *p = malloc (mu_acl_entry_size (salen));
+ struct _mu_acl_entry *p = malloc (sizeof (*p));
if (!p)
return EINVAL;
p->action = action;
p->arg = data;
- p->netmask = ntohl (netmask);
- p->salen = salen;
- memcpy (p->sa, sa, salen);
- if (prepare_sa (p->sa))
- {
- free (p);
- return EINVAL;
- }
+ memcpy (&p->cidr, cidr, sizeof (p->cidr));
+
*pent = p;
return 0;
}
@@ -165,15 +138,14 @@ mu_acl_get_iterator (mu_acl_t acl, mu_iterator_t *pitr)
int
mu_acl_append (mu_acl_t acl, mu_acl_action_t act,
- void *data, struct sockaddr *sa, int salen,
- unsigned long netmask)
+ void *data, struct mu_cidr *cidr)
{
int rc;
struct _mu_acl_entry *ent;
if (!acl)
return EINVAL;
- rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+ rc = mu_acl_entry_create (&ent, act, data, cidr);
if (rc)
{
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
@@ -193,14 +165,14 @@ mu_acl_append (mu_acl_t acl, mu_acl_action_t act,
int
mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data,
- struct sockaddr *sa, int salen, unsigned long netmask)
+ struct mu_cidr *cidr)
{
int rc;
struct _mu_acl_entry *ent;
if (!acl)
return EINVAL;
- rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+ rc = mu_acl_entry_create (&ent, act, data, cidr);
if (rc)
{
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
@@ -219,8 +191,7 @@ mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data,
int
mu_acl_insert (mu_acl_t acl, size_t pos, int before,
- mu_acl_action_t act, void *data,
- struct sockaddr *sa, int salen, unsigned long netmask)
+ mu_acl_action_t act, void *data, struct mu_cidr *cidr)
{
int rc;
void *ptr;
@@ -236,7 +207,7 @@ mu_acl_insert (mu_acl_t acl, size_t pos, int before,
("No such entry %lu", (unsigned long) pos));
return rc;
}
- rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask);
+ rc = mu_acl_entry_create (&ent, act, data, cidr);
if (!ent)
{
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
@@ -279,124 +250,19 @@ mu_acl_string_to_action (const char *str, mu_acl_action_t *pres)
return rc;
}
-#define MU_S_UN_NAME(sa, salen) \
- ((salen < mu_offsetof (struct sockaddr_un,sun_path)) ? "" : (sa)->sun_path)
-
-static void
-debug_sockaddr (struct sockaddr *sa, int salen)
-{
- switch (sa->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in s_in = *(struct sockaddr_in *)sa;
- s_in.sin_addr.s_addr = htonl (s_in.sin_addr.s_addr);
- mu_debug_log_cont ("{AF_INET %s:%d}",
- inet_ntoa (s_in.sin_addr), ntohs (s_in.sin_port));
- break;
- }
-
- case AF_UNIX:
- {
- struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
- if (MU_S_UN_NAME(s_un, salen)[0] == 0)
- mu_debug_log_cont ("{AF_UNIX}");
- else
- mu_debug_log_cont ("{AF_UNIX %s}", s_un->sun_path);
- break;
- }
-
- default:
- mu_debug_log_cont ("{Unsupported family: %d}", sa->sa_family);
- }
-}
-
-size_t
-mu_stpcpy (char **pbuf, size_t *psize, const char *src)
-{
- size_t slen = strlen (src);
- if (pbuf == NULL || *pbuf == NULL)
- return slen;
- else
- {
- char *buf = *pbuf;
- size_t size = *psize;
- if (size > slen)
- size = slen;
- memcpy (buf, src, size);
- *psize -= size;
- *pbuf += size;
- if (*psize)
- **pbuf = 0;
- else
- (*pbuf)[-1] = 0;
- return size;
- }
-}
-
-void
-mu_sockaddr_to_str (const struct sockaddr *sa, int salen,
- char *bufptr, size_t buflen,
- size_t *plen)
+struct run_closure
{
- char *nbuf;
- size_t len = 0;
- switch (sa->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in s_in = *(struct sockaddr_in *)sa;
- len += mu_stpcpy (&bufptr, &buflen, inet_ntoa (s_in.sin_addr));
- len += mu_stpcpy (&bufptr, &buflen, ":");
- if (mu_asprintf (&nbuf, "%hu", ntohs (s_in.sin_port)) == 0)
- {
- len += mu_stpcpy (&bufptr, &buflen, nbuf);
- free (nbuf);
- }
- break;
- }
-
- case AF_UNIX:
- {
- struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
- if (MU_S_UN_NAME(s_un, salen)[0] == 0)
- len += mu_stpcpy (&bufptr, &buflen, "anonymous socket");
- else
- {
- len += mu_stpcpy (&bufptr, &buflen, "socket ");
- len += mu_stpcpy (&bufptr, &buflen, s_un->sun_path);
- }
- break;
- }
-
- default:
- len += mu_stpcpy (&bufptr, &buflen, "{Unsupported family");
- if (mu_asprintf (&nbuf, ": %d", sa->sa_family) == 0)
- {
- len += mu_stpcpy (&bufptr, &buflen, nbuf);
- free (nbuf);
- }
- len += mu_stpcpy (&bufptr, &buflen, "}");
- }
- if (plen)
- *plen = len + 1;
-}
+ unsigned idx;
+ struct mu_cidr addr;
-char *
-mu_sockaddr_to_astr (const struct sockaddr *sa, int salen)
-{
- size_t size;
- char *p;
-
- mu_sockaddr_to_str (sa, salen, NULL, 0, &size);
- p = malloc (size);
- if (p)
- mu_sockaddr_to_str (sa, salen, p, size, NULL);
- return p;
-}
+ char ipstr[40];
+ char *addrstr;
+ char *numbuf;
+ mu_acl_result_t *result;
+};
int
-_acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen)
+_acl_match (struct _mu_acl_entry *ent, struct run_closure *rp)
{
#define RESMATCH(word) \
if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) \
@@ -404,76 +270,26 @@ _acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen)
if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
{
- struct in_addr a;
-
- mu_debug_log_begin ("Does ");
- debug_sockaddr (sa, salen);
- mu_debug_log_cont (" match ");
- debug_sockaddr (ent->sa, salen);
- a.s_addr = ent->netmask;
- a.s_addr = htonl (a.s_addr);
- mu_debug_log_cont (" netmask %s? ", inet_ntoa (a));
+ char *s;
+
+ if (ent->cidr.len == 0)
+ s = strdup ("any");
+ mu_cidr_format (&ent->cidr, 0, &s);
+ if (!rp->addrstr)
+ mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr);
+ mu_debug_log_begin ("Does %s match %s? ", s, rp->addrstr);
+ free (s);
}
- if (ent->sa->sa_family != sa->sa_family)
+ if (ent->cidr.len > 0 && mu_cidr_match (&ent->cidr, &rp->addr))
{
RESMATCH ("no");
return 1;
}
-
- switch (ent->sa->sa_family)
- {
- case AF_INET:
- {
- struct sockaddr_in *sin_ent = (struct sockaddr_in *)ent->sa;
- struct sockaddr_in *sin_item = (struct sockaddr_in *)sa;
-
- if (sin_ent->sin_addr.s_addr !=
- (sin_item->sin_addr.s_addr & ent->netmask))
- {
- RESMATCH ("no (address differs)");
- return 1;
- }
-
- if (sin_ent->sin_port && sin_item->sin_port
- && sin_ent->sin_port != sin_item->sin_port)
- {
- RESMATCH ("no (port differs)");
- return 1;
- }
- break;
- }
-
- case AF_UNIX:
- {
- struct sockaddr_un *sun_ent = (struct sockaddr_un *)ent->sa;
- struct sockaddr_un *sun_item = (struct sockaddr_un *)sa;
-
- if (MU_S_UN_NAME (sun_ent, ent->salen)[0]
- && MU_S_UN_NAME (sun_item, salen)[0]
- && strcmp (sun_ent->sun_path, sun_item->sun_path))
- {
- RESMATCH ("no");
- return 1;
- }
- break;
- }
- }
-
RESMATCH ("yes");
return 0;
}
-struct run_closure
-{
- unsigned idx;
- struct sockaddr *sa;
- char *numbuf;
- char *portbuf;
- int salen;
- mu_acl_result_t *result;
-};
-
#define SEQ(s, n, l) \
(((l) == (sizeof(s) - 1)) && memcmp (s, n, l) == 0)
@@ -489,40 +305,24 @@ acl_getvar (const char *name, size_t nlen, void *data)
return rp->numbuf;
}
- switch (rp->sa->sa_family)
+ if (SEQ ("address", name, nlen))
{
- case AF_INET:
- {
- struct sockaddr_in *s_in = (struct sockaddr_in *)rp->sa;
-
- if (SEQ ("address", name, nlen))
- {
- struct in_addr addr = s_in->sin_addr;
- addr.s_addr = htonl (addr.s_addr);
- return inet_ntoa (addr);
- }
+ if (!rp->addrstr)
+ mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr);
+ return rp->addrstr;
+ }
- if (SEQ ("port", name, nlen))
- {
- if (!rp->portbuf &&
- mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port)))
- return NULL;
- return rp->portbuf;
- }
- break;
-
- case AF_UNIX:
- if (SEQ ("address", name, nlen))
- {
- struct sockaddr_un *s_un = (struct sockaddr_un *)rp->sa;
- if (rp->salen == sizeof (s_un->sun_family))
- return NULL;
- else
- return s_un->sun_path;
- }
- }
- break;
+#if 0
+ /* FIXME?: */
+ if (SEQ ("port", name, nlen))
+ {
+ if (!rp->portbuf &&
+ mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port)))
+ return NULL;
+ return rp->portbuf;
}
+#endif
+
return NULL;
}
@@ -535,12 +335,18 @@ expand_arg (const char *cmdline, struct run_closure *rp, char **s)
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_TRACE, ("Expanding \"%s\"", cmdline));
env[0] = "family";
- switch (rp->sa->sa_family)
+ switch (rp->addr.family)
{
case AF_INET:
env[1] = "AF_INET";
break;
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ env[1] = "AF_INET6";
+ break;
+#endif
+
case AF_UNIX:
env[1] = "AF_UNIX";
break;
@@ -654,7 +460,7 @@ _run_entry (void *item, void *data)
mu_debug_log_begin ("%d:%s: ", rp->idx, s);
}
- if (_acl_match (ent, rp->sa, rp->salen) == 0)
+ if (_acl_match (ent, rp) == 0)
{
switch (ent->action)
{
@@ -678,8 +484,10 @@ _run_entry (void *item, void *data)
}
else
{
- debug_sockaddr (rp->sa, rp->salen);
- mu_debug_log_nl ();
+ if (!rp->addrstr)
+ mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY,
+ &rp->addrstr);
+ mu_diag_output (MU_DIAG_INFO, "%s", rp->addrstr);
}
}
break;
@@ -712,7 +520,7 @@ _run_entry (void *item, void *data)
}
if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
- mu_debug_log_nl ();
+ mu_stream_flush (mu_strerr);
return status;
}
@@ -721,40 +529,39 @@ int
mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen,
mu_acl_result_t *pres)
{
+ int rc;
struct run_closure r;
if (!acl)
return EINVAL;
- r.sa = malloc (salen);
- if (!r.sa)
- return ENOMEM;
- memcpy (r.sa, sa, salen);
- if (prepare_sa (r.sa))
+ memset (&r, 0, sizeof (r));
+ if (sa->sa_family == AF_UNIX)
{
- free (r.sa);
- return EINVAL;
+ *pres = mu_acl_result_accept;
+ return 0;
}
- r.salen = salen;
+ rc = mu_cidr_from_sockaddr (&r.addr, sa);
+ if (rc)
+ return rc;
if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
{
- mu_debug_log_begin ("Checking sockaddr ");
- debug_sockaddr (r.sa, r.salen);
+ mu_cidr_format (&r.addr, MU_CIDR_FMT_ADDRONLY, &r.addrstr);
+ mu_debug_log_begin ("Checking sockaddr %s", r.addrstr);
mu_debug_log_nl ();
}
r.idx = 0;
r.result = pres;
*r.result = mu_acl_result_undefined;
- r.numbuf = r.portbuf = NULL;
+ r.numbuf = NULL;
mu_list_do (acl->aclist, _run_entry, &r);
free (r.numbuf);
- free (r.portbuf);
- free (r.sa);
+ free (r.addrstr);
return 0;
}
-
+
int
mu_acl_check_inaddr (mu_acl_t acl, const struct in_addr *inp,
mu_acl_result_t *pres)
@@ -780,10 +587,17 @@ mu_acl_check_ipv4 (mu_acl_t acl, unsigned int addr, mu_acl_result_t *pres)
int
mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres)
{
- struct sockaddr_in cs;
- socklen_t len = sizeof cs;
+ union
+ {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+#ifdef MAILUTILS_IPV6
+ struct sockaddr_in6 in6;
+#endif
+ } addr;
+ socklen_t len = sizeof addr;
- if (getpeername (fd, (struct sockaddr *) &cs, &len) < 0)
+ if (getpeername (fd, &addr.sa, &len) < 0)
{
mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
("Cannot obtain IP address of client: %s",
@@ -791,6 +605,6 @@ mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres)
return MU_ERR_FAILURE;
}
- return mu_acl_check_sockaddr (acl, (struct sockaddr *) &cs, len, pres);
+ return mu_acl_check_sockaddr (acl, &addr.sa, len, pres);
}
diff --git a/libmailutils/server/ipsrv.c b/libmailutils/server/ipsrv.c
index a80290834..73b2e361e 100644
--- a/libmailutils/server/ipsrv.c
+++ b/libmailutils/server/ipsrv.c
@@ -34,13 +34,13 @@
#include <mailutils/diag.h>
#include <mailutils/errno.h>
#include <mailutils/nls.h>
+#include <mailutils/sockaddr.h>
struct _mu_ip_server
{
char *ident;
- struct sockaddr *addr;
- int addrlen;
+ struct mu_sockaddr *addr;
int fd;
int type;
mu_acl_t acl;
@@ -66,8 +66,7 @@ struct _mu_ip_server
#define IDENTSTR(s) ((s)->ident ? (s)->ident : "default")
int
-mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr,
- int addrlen, int type)
+mu_ip_server_create (mu_ip_server_t *psrv, struct mu_sockaddr *addr, int type)
{
struct _mu_ip_server *srv;
@@ -84,14 +83,7 @@ mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr,
srv = calloc (1, sizeof *srv);
if (!srv)
return ENOMEM;
- srv->addr = calloc (1, addrlen);
- if (!srv->addr)
- {
- free (srv);
- return ENOMEM;
- }
- memcpy (srv->addr, addr, addrlen);
- srv->addrlen = addrlen;
+ srv->addr = addr;
srv->type = type;
srv->fd = -1;
switch (type)
@@ -120,7 +112,7 @@ mu_ip_server_destroy (mu_ip_server_t *psrv)
if (srv->f_free)
srv->f_free (srv->data);
close (srv->fd);
- free (srv->addr);
+ mu_sockaddr_free (srv->addr);
free (srv->ident);
if (srv->type == MU_IP_UDP && srv->v.udp_data.buf)
free (srv->v.udp_data.buf);
@@ -234,6 +226,11 @@ mu_address_family_to_domain (int family)
case AF_INET:
return PF_INET;
+#ifdef MAILUTILS_IPV6
+ case AF_INET6:
+ return PF_INET6;
+#endif
+
default:
abort ();
}
@@ -247,14 +244,11 @@ mu_ip_server_open (mu_ip_server_t srv)
if (!srv || srv->fd != -1)
return EINVAL;
- if (mu_debug_level_p (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0))
- {
- char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
- mu_debug_log ("opening server \"%s\" %s", IDENTSTR (srv), p);
- free (p);
- }
+ mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0,
+ ("opening server \"%s\" %s", IDENTSTR (srv),
+ mu_sockaddr_str (srv->addr)));
- fd = socket (mu_address_family_to_domain (srv->addr->sa_family),
+ fd = socket (mu_address_family_to_domain (srv->addr->addr->sa_family),
((srv->type == MU_IP_UDP) ? SOCK_DGRAM : SOCK_STREAM), 0);
if (fd == -1)
{
@@ -263,7 +257,7 @@ mu_ip_server_open (mu_ip_server_t srv)
return errno;
}
- switch (srv->addr->sa_family)
+ switch (srv->addr->addr->sa_family)
{
case AF_UNIX:
{
@@ -299,7 +293,7 @@ mu_ip_server_open (mu_ip_server_t srv)
}
break;
- case AF_INET:
+ default:
{
int t;
@@ -308,7 +302,7 @@ mu_ip_server_open (mu_ip_server_t srv)
}
}
- if (bind (fd, srv->addr, srv->addrlen) == -1)
+ if (bind (fd, srv->addr->addr, srv->addr->addrlen) == -1)
{
mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
("%s: bind: %s", IDENTSTR (srv), mu_strerror (errno)));
@@ -336,12 +330,9 @@ mu_ip_server_shutdown (mu_ip_server_t srv)
{
if (!srv || srv->fd != -1)
return EINVAL;
- if (mu_debug_level_p (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0))
- {
- char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
- mu_debug_log ("closing server \"%s\" %s", IDENTSTR (srv), p);
- free (p);
- }
+ mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0,
+ ("closing server \"%s\" %s", IDENTSTR (srv),
+ mu_sockaddr_str (srv->addr)));
close (srv->fd);
return 0;
}
@@ -356,6 +347,9 @@ mu_ip_tcp_accept (mu_ip_server_t srv, void *call_data)
struct sockaddr sa;
struct sockaddr_in s_in;
struct sockaddr_un s_un;
+#ifdef MAILUTILS_IPV6
+ struct sockaddr_in6 s_in6;
+#endif
} client;
socklen_t size = sizeof (client);
@@ -407,6 +401,9 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
struct sockaddr sa;
struct sockaddr_in s_in;
struct sockaddr_un s_un;
+#ifdef MAILUTILS_IPV6
+ struct sockaddr_in6 s_in6;
+#endif
} client;
fd_set rdset;
@@ -463,7 +460,7 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
IDENTSTR (srv), strerror (rc)));
if (res == mu_acl_result_deny)
{
- char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen);
+ char *p = mu_sockaddr_to_astr (&client.sa, salen);
mu_diag_output (MU_DIAG_INFO, "Denying connection from %s", p);
free (p);
return 0;
@@ -528,22 +525,16 @@ mu_udp_server_get_rdata (mu_ip_server_t srv, char **pbuf, size_t *pbufsize)
}
int
-mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct sockaddr *s, int *size)
+mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct mu_sockaddr **psa)
{
- int len;
-
- if (!srv || !s)
+ if (!srv || !psa)
return EINVAL;
- if (s == 0)
- len = srv->addrlen;
- else
- {
- len = srv->addrlen;
- if (*size < len)
- return MU_ERR_BUFSPACE;
- memcpy (s, srv->addr, len);
- }
- *size = len;
- return 0;
+ return mu_sockaddr_copy (psa, srv->addr);
}
-
+
+const char *
+mu_ip_server_addrstr (mu_ip_server_t srv)
+{
+ return mu_sockaddr_str (srv->addr);
+}
+
diff --git a/libmailutils/server/msrv.c b/libmailutils/server/msrv.c
index 5c46e9d70..d5ceb8a39 100644
--- a/libmailutils/server/msrv.c
+++ b/libmailutils/server/msrv.c
@@ -41,6 +41,8 @@
#include <mailutils/nls.h>
#include <mailutils/daemon.h>
#include <mailutils/acl.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/url.h>
typedef RETSIGTYPE (*mu_sig_handler_t) (int);
@@ -65,19 +67,6 @@ set_signal (int sig, mu_sig_handler_t handler)
# define NSIG 64
#endif
-union m_sockaddr
-{
- struct sockaddr s_sa;
- struct sockaddr_in s_in;
- struct sockaddr_un s_un;
-};
-
-struct m_default_address
-{
- union m_sockaddr s;
- int len;
-};
-
struct _mu_m_server
{
char *ident; /* Server identifier, for logging purposes.*/
@@ -98,7 +87,7 @@ struct _mu_m_server
size_t num_children; /* Current number of running sub-processes. */
pid_t *child_pid;
char *pidfile; /* Name of a PID-file. */
- struct m_default_address defaddr; /* Default address. */
+ struct mu_sockaddr_hints hints; /* Default address hints. */
time_t timeout; /* Default idle timeout. */
mu_acl_t acl; /* Global access control list. */
@@ -112,7 +101,7 @@ struct _mu_m_server
struct m_srv_config /* Configuration data for a single TCP server. */
{
mu_m_server_t msrv; /* Parent m-server. */
- mu_ip_server_t tcpsrv; /* TCP server these data are for. */
+ mu_ip_server_t tcpsrv; /* TCP server these data are for. */
mu_acl_t acl; /* Access control list for this server. */
int single_process; /* Should it run as a single process? */
int transcript; /* Enable session transcript. */
@@ -395,33 +384,20 @@ mu_m_server_pidfile (mu_m_server_t srv)
}
void
-mu_m_server_set_default_address (mu_m_server_t srv, struct sockaddr *sa,
- int salen)
+mu_m_server_set_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints)
{
- if (salen > sizeof srv->defaddr.s)
- {
- mu_error (_("unhandled sockaddr size"));
- abort ();
- }
- memcpy (&srv->defaddr.s.s_sa, sa, salen);
- srv->defaddr.len = salen;
+ if (!hints)
+ memset (&srv->hints, 0, sizeof (srv->hints));
+ else
+ memcpy (&srv->hints, hints, sizeof (srv->hints));
}
int
-mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa,
- int *salen)
+mu_m_server_get_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints)
{
- int len;
-
- if (!sa)
+ if (!hints)
return EINVAL;
- len = srv->defaddr.len;
- if (sa)
- {
- if (*salen < len)
- return MU_ERR_BUFSPACE;
- memcpy (sa, &srv->defaddr.s.s_sa, len);
- }
+ memcpy (hints, &srv->hints, sizeof (hints));
return 0;
}
@@ -429,11 +405,7 @@ mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa,
void
mu_m_server_set_default_port (mu_m_server_t srv, int num)
{
- struct sockaddr_in s_in;
- s_in.sin_family = AF_INET;
- s_in.sin_addr.s_addr = htonl (INADDR_ANY);
- s_in.sin_port = htons (num);
- mu_m_server_set_default_address (srv, (struct sockaddr*) &s_in, sizeof s_in);
+ srv->hints.port = num;
}
void
@@ -473,12 +445,12 @@ static int m_srv_conn (int fd, struct sockaddr *sa, int salen,
mu_ip_server_t srv);
static struct m_srv_config *
-add_server (mu_m_server_t msrv, struct sockaddr *s, int slen, int type)
+add_server (mu_m_server_t msrv, struct mu_sockaddr *s, int type)
{
mu_ip_server_t tcpsrv;
struct m_srv_config *pconf;
- MU_ASSERT (mu_ip_server_create (&tcpsrv, s, slen, type)); /* FIXME: type */
+ MU_ASSERT (mu_ip_server_create (&tcpsrv, s, type)); /* FIXME: type */
MU_ASSERT (mu_ip_server_set_conn (tcpsrv, m_srv_conn));
pconf = calloc (1, sizeof (*pconf));
if (!pconf)
@@ -513,8 +485,21 @@ mu_m_server_begin (mu_m_server_t msrv)
alloc_children (msrv);
mu_list_count (msrv->srvlist, &count);
- if (count == 0 && msrv->defaddr.len)
- add_server (msrv, &msrv->defaddr.s.s_sa, msrv->defaddr.len, msrv->deftype);
+ if (count == 0)
+ {
+ struct mu_sockaddr *ta;
+
+ msrv->hints.flags = MU_AH_PASSIVE;
+ rc = mu_sockaddr_from_node (&ta, NULL, NULL, &msrv->hints);
+ if (rc == 0)
+ while (ta)
+ {
+ struct mu_sockaddr *next = ta->next;
+ ta->next = ta->prev = NULL;
+ add_server (msrv, ta, msrv->deftype);
+ ta = next;
+ }
+ }
if (!msrv->foreground)
{
@@ -599,23 +584,13 @@ tcp_conn_free (void *conn_data, void *server_data)
static int
_open_conn (void *item, void *data)
{
- union
- {
- struct sockaddr sa;
- char pad[512];
- }
- addr;
- int addrlen = sizeof addr;
- char *p;
mu_ip_server_t tcpsrv = item;
mu_m_server_t msrv = data;
int rc = mu_ip_server_open (tcpsrv);
if (rc)
{
- mu_ip_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen);
- p = mu_sockaddr_to_astr (&addr.sa, addrlen);
- mu_error (_("cannot open connection on %s: %s"), p, mu_strerror (rc));
- free (p);
+ mu_error (_("cannot open connection on %s: %s"),
+ mu_ip_server_addrstr (tcpsrv), mu_strerror (rc));
return 0;
}
rc = mu_server_add_connection (msrv->server,
@@ -624,10 +599,8 @@ _open_conn (void *item, void *data)
tcp_conn_handler, tcp_conn_free);
if (rc)
{
- mu_ip_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen);
- p = mu_sockaddr_to_astr (&addr.sa, addrlen);
- mu_error (_("cannot add connection %s: %s"), p, mu_strerror (rc));
- free (p);
+ mu_error (_("cannot add connection %s: %s"),
+ mu_ip_server_addrstr (tcpsrv), mu_strerror (rc));
mu_ip_server_shutdown (tcpsrv);
mu_ip_server_destroy (&tcpsrv);
}
@@ -756,199 +729,55 @@ m_srv_conn (int fd, struct sockaddr *sa, int salen,
}
-
-unsigned short
-get_port (const char *p)
-{
- if (p)
- {
- char *q;
- unsigned long n = strtoul (p, &q, 0);
- if (*q == 0)
- {
- if (n > USHRT_MAX)
- {
- mu_error (_("invalid port number: %s"), p);
- return 1;
- }
-
- return htons (n);
- }
- else
- {
- struct servent *sp = getservbyname (p, "tcp");
- if (!sp)
- return 0;
- return sp->s_port;
- }
- }
- return 0;
-}
-
-static int
-get_family (const char **pstr, sa_family_t *pfamily)
-{
- static struct family_tab
- {
- int len;
- char *pfx;
- int family;
- } ftab[] = {
-#define S(s,f) { sizeof (#s":") - 1, #s":", f }
- S (file, AF_UNIX),
- S (unix, AF_UNIX),
- S (local, AF_UNIX),
- S (socket, AF_UNIX),
- S (inet, AF_INET),
- S (tcp, AF_INET),
-#undef S
- { 0 }
- };
- struct family_tab *fp;
-
- const char *str = *pstr;
- int len = strlen (str);
- for (fp = ftab; fp->len; fp++)
- {
- if (len > fp->len && memcmp (str, fp->pfx, fp->len) == 0)
- {
- str += fp->len;
- if (str[0] == '/' && str[1] == '/')
- str += 2;
- *pstr = str;
- *pfamily = fp->family;
- return 0;
- }
- }
- return 1;
-}
-
-static int
-is_ip_addr (const char *arg)
-{
- int dot_count;
- int digit_count;
-
- dot_count = 0;
- digit_count = 0;
- for (; *arg != 0 && *arg != ':'; arg++)
- {
- if (*arg == '.')
- {
- if (++dot_count > 3)
- break;
- digit_count = 0;
- }
- else if (!(mu_isdigit (*arg) && ++digit_count <= 3))
- return 0;
- }
- return dot_count == 3;
-}
-
int
-_mu_m_server_parse_url (const char *arg, union m_sockaddr *s,
- int *psalen, struct sockaddr *defsa)
+mu_m_server_parse_url (mu_m_server_t msrv, const char *arg,
+ struct mu_sockaddr **psa)
{
- char *p;
- unsigned short n;
- int len;
-
- if (is_ip_addr (arg))
- s->s_sa.sa_family = AF_INET;
- else if (get_family (&arg, &s->s_sa.sa_family))
+ int rc;
+ mu_url_t url, url_hint;
+
+ if (arg[0] == '/')
+ url_hint = NULL;
+ else
{
- mu_error (_("invalid family"));
- return EINVAL;
+ rc = mu_url_create (&url_hint, "inet://");
+ if (rc)
+ return rc;
}
-
- switch (s->s_sa.sa_family)
+ rc = mu_url_create_hint (&url, arg, MU_URL_PARSE_DEFAULT, url_hint);
+ mu_url_destroy (&url_hint);
+ if (rc)
{
- case AF_INET:
- *psalen = sizeof (s->s_in);
- if ((n = get_port (arg)))
- {
- s->s_in.sin_addr.s_addr = htonl (INADDR_ANY);
- s->s_in.sin_port = htons (n);
- }
- else
- {
- p = strchr (arg, ':');
- if (p)
- *p++ = 0;
- if (inet_aton (arg, &s->s_in.sin_addr) == 0)
- {
- struct hostent *hp = gethostbyname (arg);
- if (hp)
- s->s_in.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
- else
- {
- mu_error (_("invalid IP address: %s"), arg);
- return EINVAL;
- }
- }
- if (p)
- {
- n = get_port (p);
- if (!n)
- {
- mu_error (_("invalid port number: %s"), p);
- return EINVAL;
- }
- s->s_in.sin_port = n;
- }
- else if (defsa && defsa->sa_family == AF_INET)
- s->s_in.sin_port = ((struct sockaddr_in*)defsa)->sin_port;
- else
- {
- mu_error (_("missing port number"));
- return EINVAL;
- }
- }
- break;
-
- case AF_UNIX:
- *psalen = sizeof (s->s_un);
- len = strlen (arg);
- if (len > sizeof s->s_un.sun_path - 1)
- {
- mu_error (_("%s: file name too long"), arg);
- return EINVAL;
- }
- strcpy (s->s_un.sun_path, arg);
- break;
+ mu_error (_("cannot parse URL `%s': %s"), arg, mu_strerror (rc));
+ return rc;
}
- return 0;
-}
-
-int
-mu_m_server_parse_url (mu_m_server_t msrv, char *arg,
- struct sockaddr *sa, int *psalen)
-{
- int rc;
- union m_sockaddr s;
- int salen;
- rc = _mu_m_server_parse_url (arg, &s, &salen, &msrv->defaddr.s.s_sa);
+ msrv->hints.flags = MU_AH_PASSIVE;
+ rc = mu_sockaddr_from_url (psa, url, &msrv->hints);
if (rc)
- return rc;
- if (sa)
- {
- if (*psalen < salen)
- return MU_ERR_BUFSPACE;
- memcpy (sa, &s.s_sa, salen);
- }
- *psalen = salen;
- return 0;
+ mu_error (_("cannot create sockaddr for URL `%s': %s"), arg,
+ mu_strerror (rc));
+ mu_url_destroy (&url);
+ return rc;
}
static int
server_block_begin (const char *arg, mu_m_server_t msrv, void **pdata)
{
- union m_sockaddr s;
- int salen;
- if (_mu_m_server_parse_url (arg, &s, &salen, &msrv->defaddr.s.s_sa))
+ struct mu_sockaddr *s;
+ if (mu_m_server_parse_url (msrv, arg, &s))
return 1;
- *pdata = add_server (msrv, &s.s_sa, salen, msrv->deftype);
+ if (s->next)
+ {
+ /* FIXME: (1) Find a way to handle all addresses.
+ (2) Print which address is being used.
+ */
+ mu_diag_output (MU_DIAG_WARNING,
+ _("%s resolves to several addresses, "
+ "only the first is used"), arg);
+ mu_sockaddr_free (s->next);
+ }
+ *pdata = add_server (msrv, s, msrv->deftype);
return 0;
}
@@ -1002,21 +831,46 @@ _cb_daemon_mode (void *data, mu_config_value_t *val)
return 0;
}
+unsigned short
+get_port (const char *p)
+{
+ if (p)
+ {
+ char *q;
+ unsigned long n = strtoul (p, &q, 0);
+ if (*q == 0)
+ {
+ if (n > USHRT_MAX)
+ {
+ mu_error (_("invalid port number: %s"), p);
+ return 1;
+ }
+
+ return htons (n);
+ }
+ else
+ {
+ struct servent *sp = getservbyname (p, "tcp");
+ if (!sp)
+ return 0;
+ return sp->s_port;
+ }
+ }
+ return 0;
+}
+
static int
_cb_port (void *data, mu_config_value_t *val)
{
- struct m_default_address *ap = data;
+ struct mu_sockaddr_hints *hp = data;
unsigned short num;
-
+
if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
return 1;
num = get_port (val->v.string);
if (!num)
return 1;
- ap->s.s_in.sin_family = AF_INET;
- ap->s.s_in.sin_addr.s_addr = htonl (INADDR_ANY);
- ap->s.s_in.sin_port = num;
- ap->len = sizeof ap->s.s_in;
+ hp->port = num;
return 0;
}
@@ -1036,7 +890,7 @@ static struct mu_cfg_param dot_server_cfg_param[] = {
N_("Store PID of the master process in this file."),
N_("file") },
{ "port", mu_cfg_callback,
- NULL, mu_offsetof (struct _mu_m_server,defaddr), _cb_port,
+ NULL, mu_offsetof (struct _mu_m_server, hints), _cb_port,
N_("Default port number.") },
{ "timeout", mu_cfg_time,
NULL, mu_offsetof (struct _mu_m_server,timeout), NULL,
diff --git a/libmailutils/sockaddr/Makefile.am b/libmailutils/sockaddr/Makefile.am
new file mode 100644
index 000000000..dcfb18446
--- /dev/null
+++ b/libmailutils/sockaddr/Makefile.am
@@ -0,0 +1,31 @@
+# GNU Mailutils -- a suite of utilities for electronic mail
+# Copyright (C) 2011 Free Software Foundation, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General
+# Public License along with this library. If not, see
+# <http://www.gnu.org/licenses/>.
+
+noinst_LTLIBRARIES = libsockaddr.la
+
+libsockaddr_la_SOURCES = \
+ copy.c\
+ create.c\
+ free.c\
+ fromnode.c\
+ insert.c\
+ ipaddr.c\
+ str.c\
+ unlink.c\
+ url.c
+
+INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
diff --git a/libmailutils/sockaddr/copy.c b/libmailutils/sockaddr/copy.c
new file mode 100644
index 000000000..5e28e7857
--- /dev/null
+++ b/libmailutils/sockaddr/copy.c
@@ -0,0 +1,36 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/sockaddr.h>
+
+int
+mu_sockaddr_copy (struct mu_sockaddr **pnew, struct mu_sockaddr *old)
+{
+ if (!old)
+ {
+ *pnew = NULL;
+ return 0;
+ }
+ return mu_sockaddr_create (pnew, old->addr, old->addrlen);
+}
+
+
diff --git a/libmailutils/sockaddr/create.c b/libmailutils/sockaddr/create.c
new file mode 100644
index 000000000..5b49471e6
--- /dev/null
+++ b/libmailutils/sockaddr/create.c
@@ -0,0 +1,47 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <mailutils/sockaddr.h>
+
+int
+mu_sockaddr_create (struct mu_sockaddr **res,
+ struct sockaddr *addr, socklen_t len)
+{
+ struct mu_sockaddr *sa;
+
+ sa = calloc (1, sizeof (*sa));
+ if (!sa)
+ return ENOMEM;
+ sa->addr = malloc (len);
+ if (!sa->addr)
+ {
+ free (sa);
+ return ENOMEM;
+ }
+ memcpy (sa->addr, addr, len);
+ sa->addrlen = len;
+ *res = sa;
+ return 0;
+}
+
diff --git a/libmailutils/sockaddr/free.c b/libmailutils/sockaddr/free.c
new file mode 100644
index 000000000..2a31ec36d
--- /dev/null
+++ b/libmailutils/sockaddr/free.c
@@ -0,0 +1,50 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/sockaddr.h>
+
+void
+mu_sockaddr_free (struct mu_sockaddr *addr)
+{
+ if (!addr)
+ return;
+ free (addr->addr);
+ free (addr->str);
+}
+
+void
+mu_sockaddr_free_list (struct mu_sockaddr *addr)
+{
+ if (!addr)
+ return;
+ if (addr->prev)
+ addr->prev->next = NULL;
+ while (addr)
+ {
+ struct mu_sockaddr *next = addr->next;
+ mu_sockaddr_free (addr);
+ addr = next;
+ }
+}
+
+
+
diff --git a/libmailutils/sockaddr/fromnode.c b/libmailutils/sockaddr/fromnode.c
new file mode 100644
index 000000000..d79b9523a
--- /dev/null
+++ b/libmailutils/sockaddr/fromnode.c
@@ -0,0 +1,253 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/url.h>
+#include <mailutils/io.h>
+#include <mailutils/errno.h>
+#include <mailutils/error.h>
+#include <mailutils/nls.h>
+
+static struct mu_sockaddr *
+match_sa (struct mu_sockaddr *list, struct sockaddr *sa, socklen_t len)
+{
+ for (; list; list = list->next)
+ if (len == list->addrlen && memcmp (list->addr, sa, len) == 0)
+ break;
+ return list;
+}
+
+int
+mu_sockaddr_from_node (struct mu_sockaddr **retval, const char *node,
+ const char *serv, struct mu_sockaddr_hints *mh)
+{
+ int rc;
+
+ if (!mh)
+ {
+ static struct mu_sockaddr_hints nullhints = { 0, AF_UNSPEC };
+ mh = &nullhints;
+ }
+
+ if (mh->family == AF_UNIX)
+ {
+ size_t slen;
+ struct sockaddr_un s_un;
+
+ if (!node)
+ return MU_ERR_NONAME;
+ slen = strlen (node);
+ if (slen >= sizeof s_un.sun_path)
+ return MU_ERR_BUFSPACE;
+
+ s_un.sun_family = AF_UNIX;
+ strcpy(s_un.sun_path, node);
+ return mu_sockaddr_create (retval, (struct sockaddr*) &s_un,
+ sizeof (s_un));
+ }
+ else
+#ifdef MAILUTILS_IPV6
+ {
+ struct addrinfo hints;
+ struct addrinfo *res, *ap;
+ char portbuf[64];
+ struct mu_sockaddr *tail = NULL;
+
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_family = mh->family;
+ hints.ai_socktype = mh->socktype;
+ hints.ai_protocol = mh->protocol;
+
+ if (!node)
+ {
+ if (mh->flags & MU_AH_PASSIVE)
+ hints.ai_flags |= AI_PASSIVE;
+ else
+ return MU_ERR_NONAME;
+ }
+ if (!serv && mh->port)
+ {
+ snprintf (portbuf, sizeof portbuf, "%hu", mh->port);
+ serv = portbuf;
+ }
+
+ rc = getaddrinfo (node, serv, &hints, &res);
+
+ switch (rc)
+ {
+ case 0:
+ break;
+
+ case EAI_FAIL:
+ return MU_ERR_GETHOSTBYNAME;
+
+ case EAI_FAMILY:
+ return MU_ERR_FAMILY;
+
+ case EAI_NONAME:
+ return MU_ERR_NONAME;
+
+ case EAI_SERVICE:
+ return MU_ERR_SERVICE;
+
+ case EAI_SYSTEM:
+ mu_error (_("%s:%s: cannot parse address: %s"),
+ node, serv, mu_strerror (errno));
+ return errno;
+
+ case EAI_BADFLAGS:
+ return MU_ERR_BADFLAGS;
+
+ case EAI_SOCKTYPE:
+ return MU_ERR_SOCKTYPE;
+
+ case EAI_MEMORY:
+ return ENOMEM;
+
+ default:
+ mu_error ("%s:%s: %s", node, serv, gai_strerror (rc));
+ return MU_ERR_FAILURE;
+ }
+
+ *retval = NULL;
+ for (ap = res; ap; ap = ap->ai_next)
+ if (mh->family == AF_UNSPEC || ap->ai_addr->sa_family == mh->family)
+ {
+ struct mu_sockaddr *sa;
+
+ if (match_sa (*retval, ap->ai_addr, ap->ai_addrlen))
+ continue;
+ rc = mu_sockaddr_create (&sa, ap->ai_addr, ap->ai_addrlen);
+ if (rc)
+ {
+ mu_sockaddr_free_list (*retval);
+ freeaddrinfo (res);
+ return rc;
+ }
+ if (tail)
+ mu_sockaddr_insert (tail, sa, 0);
+ else
+ *retval = sa;
+ tail = sa;
+ }
+ freeaddrinfo (res);
+ }
+#else
+ if (mh->family == AF_INET)
+ {
+ short port;
+ struct hostent *hp;
+ struct mu_sockaddr *tail = NULL;
+ char **p;
+
+ if (serv)
+ {
+ char *end;
+ unsigned long n = strtoul (serv, &end, 10);
+
+ if (*end)
+ {
+ struct servent *sp;
+ const char *proto;
+
+ if (mh->protocol)
+ {
+ struct protoent *pp = getprotobynumber (mh->protocol);
+ if (!pp)
+ return EINVAL;
+ proto = pp->p_name;
+ }
+ else
+ proto = NULL;
+
+ sp = getservbyname (serv, proto);
+ if (!sp)
+ return MU_ERR_SERVICE;
+ port = sp->s_port;
+ }
+ else if (n == 0 || (port = n) != n)
+ return MU_ERR_PARSE; /* FIXME: need MU_ERR_RANGE? */
+ }
+ else if (mh->port)
+ port = htons (mh->port);
+ else
+ return MU_ERR_NONAME;
+
+ if (!node)
+ {
+ struct sockaddr_in s_in;
+
+ if (!(mh->flags & MU_AH_PASSIVE))
+ return MU_ERR_NONAME;
+
+ s_in.sin_family = AF_INET;
+ s_in.sin_addr.s_addr = INADDR_ANY;
+ s_in.sin_port = port;
+ return mu_sockaddr_create (retval, (struct sockaddr*)&s_in,
+ sizeof (s_in));
+ }
+
+ hp = gethostbyname (node);
+ if (!hp)
+ return MU_ERR_GETHOSTBYNAME;
+
+ if (hp->h_addrtype != AF_INET || hp->h_length != 4)
+ return MU_ERR_FAMILY;
+
+ for (p = hp->h_addr_list; *p; p++)
+ {
+ struct mu_sockaddr *sa;
+ struct sockaddr_in s_in;
+
+ s_in.sin_family = AF_INET;
+ memcpy(&s_in.sin_addr, *p, 4);
+ s_in.sin_port = port;
+
+ rc = mu_sockaddr_create (&sa, (struct sockaddr*)&s_in,
+ sizeof (s_in));
+ if (rc)
+ {
+ mu_sockaddr_free_list (*retval);
+ return rc;
+ }
+ if (tail)
+ mu_sockaddr_insert (tail, sa, 0);
+ else
+ *retval = sa;
+ tail = sa;
+ }
+ }
+ else
+ return MU_ERR_FAMILY;
+#endif
+ return 0;
+}
diff --git a/libmailutils/sockaddr/insert.c b/libmailutils/sockaddr/insert.c
new file mode 100644
index 000000000..dbac151c1
--- /dev/null
+++ b/libmailutils/sockaddr/insert.c
@@ -0,0 +1,64 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/sockaddr.h>
+
+static void
+set_next (struct mu_sockaddr *sp, struct mu_sockaddr *tgt)
+{
+ for (; sp->next; sp = sp->next)
+ ;
+ sp->next = tgt;
+ if (tgt)
+ tgt->prev = sp;
+}
+
+struct mu_sockaddr *
+mu_sockaddr_insert (struct mu_sockaddr *anchor, struct mu_sockaddr *addr,
+ int before)
+{
+ struct mu_sockaddr *ret = anchor;
+
+ if (!anchor)
+ {
+ addr->prev = NULL;
+ set_next (addr, NULL);
+ return addr;
+ }
+
+ if (before)
+ {
+ if (anchor->prev)
+ anchor = anchor->prev;
+ else
+ {
+ addr->prev = NULL;
+ set_next (addr, anchor);
+ return addr;
+ }
+ }
+
+ set_next (addr, anchor->next);
+ anchor->next = addr;
+ addr->prev = anchor;
+ return ret;
+}
diff --git a/libmailutils/sockaddr/ipaddr.c b/libmailutils/sockaddr/ipaddr.c
new file mode 100644
index 000000000..6b14b4c29
--- /dev/null
+++ b/libmailutils/sockaddr/ipaddr.c
@@ -0,0 +1,88 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <string.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/cctype.h>
+
+int
+mu_str_is_ipv4 (const char *addr)
+{
+ int dot_count = 0;
+ int digit_count = 0;
+
+ for (; *addr; addr++)
+ {
+ if (!mu_isascii (*addr))
+ return 0;
+ if (*addr == '.')
+ {
+ if (++dot_count > 3)
+ break;
+ digit_count = 0;
+ }
+ else if (!(mu_isdigit (*addr) && ++digit_count <= 3))
+ return 0;
+ }
+
+ return (dot_count == 3);
+}
+
+int
+mu_str_is_ipv6 (const char *addr)
+{
+ int col_count = 0; /* Number of colons */
+ int dcol = 0; /* Did we encounter a double-colon? */
+ int dig_count = 0; /* Number of digits in the last group */
+
+ for (; *addr; addr++)
+ {
+ if (!mu_isascii (*addr))
+ return 0;
+ else if (mu_isxdigit (*addr))
+ {
+ if (++dig_count > 4)
+ return 0;
+ }
+ else if (*addr == ':')
+ {
+ if (col_count && dig_count == 0 && ++dcol > 1)
+ return 0;
+ if (++col_count > 7)
+ return 0;
+ dig_count = 0;
+ }
+ else
+ return 0;
+ }
+
+ return (col_count == 7 || dcol);
+}
+
+int
+mu_str_is_ipaddr (const char *addr)
+{
+ if (strchr (addr, '.'))
+ return mu_str_is_ipv4(addr);
+ else if (strchr (addr, ':'))
+ return mu_str_is_ipv6(addr);
+ return 0;
+}
diff --git a/libmailutils/sockaddr/str.c b/libmailutils/sockaddr/str.c
new file mode 100644
index 000000000..949f21ef9
--- /dev/null
+++ b/libmailutils/sockaddr/str.c
@@ -0,0 +1,109 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include <mailutils/sockaddr.h>
+#include <mailutils/errno.h>
+#include <mailutils/io.h>
+
+static char *default_sockaddr_text = "[not enogh memory]";
+
+#define S_UN_NAME(sa, salen) \
+ ((salen < mu_offsetof(struct sockaddr_un,sun_path)) ? \
+ "" : (sa)->sun_path)
+
+int
+mu_sockaddr_format (char **pbuf, const struct sockaddr *sa, socklen_t salen)
+{
+ int rc = MU_ERR_FAILURE;
+
+ switch (sa->sa_family)
+ {
+#ifdef MAILUTILS_IPV6
+ case AF_INET:
+ case AF_INET6:
+ {
+ char host[NI_MAXHOST];
+ char srv[NI_MAXSERV];
+ if (getnameinfo (sa, salen,
+ host, sizeof (host), srv, sizeof (srv),
+ NI_NUMERICHOST|NI_NUMERICSERV) == 0)
+ {
+ if (sa->sa_family == AF_INET6)
+ rc = mu_asprintf (pbuf, "inet6://[%s]:%s", host, srv);
+ else
+ rc = mu_asprintf (pbuf, "inet://%s:%s", host, srv);
+ }
+ else
+ rc = mu_asprintf (pbuf, "%s://[getnameinfo failed]",
+ sa->sa_family == AF_INET ?
+ "inet" : "inet6");
+ break;
+ }
+#else
+ case AF_INET:
+ {
+ struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
+ rc = mu_asprintf (pbuf, "inet://%s:%hu",
+ inet_ntoa (s_in->sin_addr), s_in->sin_port);
+ break;
+ }
+#endif
+
+ case AF_UNIX:
+ {
+ struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
+ if (S_UN_NAME (s_un, salen)[0] == 0)
+ rc = mu_asprintf (pbuf, "unix://[anonymous socket]");
+ else
+ rc = mu_asprintf (pbuf, "unix://%s", s_un->sun_path);
+ break;
+ }
+
+ default:
+ rc = mu_asprintf (pbuf, "family:%d", sa->sa_family);
+ }
+ return rc;
+}
+
+char *
+mu_sockaddr_to_astr (const struct sockaddr *sa, int salen)
+{
+ char *buf = NULL;
+ mu_sockaddr_format (&buf, sa, salen);
+ return buf;
+}
+
+const char *
+mu_sockaddr_str (struct mu_sockaddr *sa)
+{
+ if (!sa->str && mu_sockaddr_format (&sa->str, sa->addr, sa->addrlen))
+ return default_sockaddr_text;
+ return sa->str;
+}
+
+
diff --git a/libmailutils/sockaddr/unlink.c b/libmailutils/sockaddr/unlink.c
new file mode 100644
index 000000000..65808f568
--- /dev/null
+++ b/libmailutils/sockaddr/unlink.c
@@ -0,0 +1,45 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <mailutils/sockaddr.h>
+
+struct mu_sockaddr *
+mu_sockaddr_unlink (struct mu_sockaddr *addr)
+{
+ struct mu_sockaddr *p;
+
+ if (!addr)
+ return NULL;
+
+ p = addr->prev;
+ if (p)
+ p->next = addr->next;
+
+ p = addr->next;
+ if (p)
+ p->prev = addr->prev;
+
+ addr->prev = addr->next = NULL;
+
+ return p;
+}
+
diff --git a/libmailutils/sockaddr/url.c b/libmailutils/sockaddr/url.c
new file mode 100644
index 000000000..0eaf870be
--- /dev/null
+++ b/libmailutils/sockaddr/url.c
@@ -0,0 +1,130 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <mailutils/sockaddr.h>
+#include <mailutils/url.h>
+#include <mailutils/io.h>
+#include <mailutils/errno.h>
+#include <mailutils/nls.h>
+#include <mailutils/kwd.h>
+
+static struct mu_kwd famtab[] = {
+ { "unix", AF_UNIX },
+ { "local", AF_UNIX },
+ { "inet4", AF_INET },
+#ifdef MAILUTILS_IPV6
+ { "inet6", AF_INET6 },
+ { "inet", AF_UNSPEC },
+#else
+ { "inet", AF_INET },
+#endif
+ { NULL }
+};
+
+int
+mu_sockaddr_from_url (struct mu_sockaddr **retval, mu_url_t url,
+ struct mu_sockaddr_hints *mh)
+{
+ int rc;
+ const char *scheme;
+ const char *node = NULL, *serv = NULL;
+ struct mu_sockaddr_hints hints;
+
+ if (mh)
+ memcpy (&hints, mh, sizeof (hints));
+ else
+ {
+ memset (&hints, sizeof(hints), 0);
+ hints.family = AF_UNSPEC;
+ hints.socktype = SOCK_STREAM;
+ hints.protocol = IPPROTO_TCP;
+ }
+
+ if (hints.family == AF_UNSPEC)
+ {
+ rc = mu_url_sget_scheme (url, &scheme);
+ if (rc)
+ return rc;
+
+ if (mu_kwd_xlat_name (famtab, scheme, &hints.family))
+ {
+ if (hints.flags & MU_AH_DETECT_FAMILY)
+ {
+ int flags = 0;
+
+ mu_url_get_flags (url, &flags);
+#ifdef MAILUTILS_IPV6
+ if (flags & MU_URL_IPV6)
+ hints.family = AF_INET6;
+ else
+#endif
+ if (flags & (MU_URL_HOST|MU_URL_PORT))
+ hints.family = AF_INET;
+ else if (flags & MU_URL_PATH)
+ hints.family = AF_UNIX;
+ else
+ return MU_ERR_FAMILY;
+ }
+ else
+ return MU_ERR_FAMILY;
+ }
+ }
+
+ if (hints.family == AF_UNIX)
+ {
+ rc = mu_url_sget_path (url, &node);
+ if (rc)
+ {
+ if (rc == MU_ERR_NOENT)
+ {
+ rc = mu_url_sget_host (url, &node);
+ if (rc == MU_ERR_NOENT)
+ return MU_ERR_NONAME;
+ }
+ if (rc)
+ return rc;
+ }
+ }
+ else
+ {
+#ifdef MAILUTILS_IPV6
+ if (hints.family == AF_UNSPEC)
+ hints.family = mu_url_has_flag (url, MU_URL_IPV6) ? AF_INET6 : AF_INET;
+#endif
+ rc = mu_url_sget_host (url, &node);
+ if (rc && rc != MU_ERR_NOENT)
+ return MU_ERR_NONAME;
+ rc = mu_url_sget_portstr (url, &serv);
+ if (rc && rc != MU_ERR_NOENT)
+ return MU_ERR_NONAME;
+ }
+ return mu_sockaddr_from_node (retval, node, serv, &hints);
+}
diff --git a/libmailutils/stream/tcp.c b/libmailutils/stream/tcp.c
index 40b37124d..f383f1b5a 100644
--- a/libmailutils/stream/tcp.c
+++ b/libmailutils/stream/tcp.c
@@ -39,7 +39,7 @@
#include <mailutils/errno.h>
#include <mailutils/stream.h>
#include <mailutils/util.h>
-
+#include <mailutils/sockaddr.h>
#include <mailutils/sys/stream.h>
#define TCP_STATE_INIT 1
@@ -52,18 +52,11 @@ struct _tcp_instance
{
struct _mu_stream stream;
int fd;
- char *host;
- unsigned short port;
int state;
- unsigned long address;
- unsigned long source_addr;
+ struct mu_sockaddr *remote_addr;
+ struct mu_sockaddr *source_addr;
};
-/* On solaris inet_addr() return -1. */
-#ifndef INADDR_NONE
-# define INADDR_NONE (unsigned long)-1
-#endif
-
static int
_tcp_close (mu_stream_t stream)
{
@@ -83,28 +76,12 @@ _tcp_close (mu_stream_t stream)
}
static int
-resolve_hostname (const char *host, unsigned long *ip)
-{
- unsigned long address = inet_addr (host);
- if (address == INADDR_NONE)
- {
- struct hostent *phe = gethostbyname (host);
- if (!phe)
- return MU_ERR_GETHOSTBYNAME;
- address = *(((unsigned long **) phe->h_addr_list)[0]);
- }
- *ip = address;
- return 0;
-}
-
-static int
_tcp_open (mu_stream_t stream)
{
struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
int flgs, ret;
socklen_t namelen;
struct sockaddr_in peer_addr;
- struct sockaddr_in soc_addr;
int flags;
mu_stream_get_flags (stream, &flags);
@@ -114,7 +91,8 @@ _tcp_open (mu_stream_t stream)
case TCP_STATE_INIT:
if (tcp->fd == -1)
{
- if ((tcp->fd = socket (PF_INET, SOCK_STREAM, 0)) == -1)
+ tcp->fd = socket (tcp->remote_addr->addr->sa_family, SOCK_STREAM, 0);
+ if (tcp->fd == -1)
return errno;
}
if (flags & MU_STREAM_NONBLOCK)
@@ -124,13 +102,10 @@ _tcp_open (mu_stream_t stream)
fcntl (tcp->fd, F_SETFL, flgs);
mu_stream_set_flags (stream, MU_STREAM_NONBLOCK);
}
- if (tcp->source_addr != INADDR_ANY)
+ if (tcp->source_addr)
{
- struct sockaddr_in s;
- s.sin_family = AF_INET;
- s.sin_addr.s_addr = tcp->source_addr;
- s.sin_port = 0;
- if (bind (tcp->fd, (struct sockaddr*) &s, sizeof(s)) < 0)
+ if (bind (tcp->fd, tcp->source_addr->addr,
+ tcp->source_addr->addrlen) < 0)
{
int e = errno;
close (tcp->fd);
@@ -142,27 +117,11 @@ _tcp_open (mu_stream_t stream)
tcp->state = TCP_STATE_RESOLVING;
case TCP_STATE_RESOLVING:
- if (!(tcp->host != NULL && tcp->port > 0))
- {
- _tcp_close (stream);
- return EINVAL;
- }
-
- if ((ret = resolve_hostname (tcp->host, &tcp->address)))
- {
- _tcp_close (stream);
- return ret;
- }
tcp->state = TCP_STATE_RESOLVE;
case TCP_STATE_RESOLVE:
- memset (&soc_addr, 0, sizeof (soc_addr));
- soc_addr.sin_family = AF_INET;
- soc_addr.sin_port = htons (tcp->port);
- soc_addr.sin_addr.s_addr = tcp->address;
-
- if ((connect (tcp->fd,
- (struct sockaddr *) &soc_addr, sizeof (soc_addr))) == -1)
+ if (connect (tcp->fd, tcp->remote_addr->addr,
+ tcp->remote_addr->addrlen) == -1)
{
ret = errno;
if (ret == EINPROGRESS || ret == EAGAIN)
@@ -254,10 +213,8 @@ _tcp_done (mu_stream_t stream)
{
struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
- if (tcp->host)
- free (tcp->host);
- if (tcp->fd != -1)
- close (tcp->fd);
+ mu_sockaddr_free (tcp->remote_addr);
+ mu_sockaddr_free (tcp->source_addr);
}
int
@@ -315,33 +272,21 @@ _create_tcp_stream (int flags)
}
int
-mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
- const char *host, unsigned port,
- unsigned long source_ip,
- int flags)
+mu_tcp_stream_create_from_sa (mu_stream_t *pstream,
+ struct mu_sockaddr *remote_addr,
+ struct mu_sockaddr *source_addr, int flags)
{
int rc;
mu_stream_t stream;
struct _tcp_instance *tcp;
- if (host == NULL)
- return MU_ERR_TCP_NO_HOST;
-
- if (port > USHRT_MAX)
- return MU_ERR_TCP_NO_PORT;
-
tcp = _create_tcp_stream (flags | MU_STREAM_RDWR);
if (!tcp)
return ENOMEM;
- tcp->host = strdup (host);
- if (!tcp->host)
- {
- free (tcp);
- return ENOMEM;
- }
- tcp->port = port;
- tcp->state = TCP_STATE_INIT;
- tcp->source_addr = source_ip;
+
+ tcp->remote_addr = remote_addr;
+ tcp->source_addr = source_addr;
+
stream = (mu_stream_t) tcp;
rc = mu_stream_open (stream);
if (rc == 0 || rc == EAGAIN || rc == EINPROGRESS)
@@ -351,24 +296,93 @@ mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
return rc;
}
+
+int
+mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
+ const char *host, unsigned port,
+ unsigned long source_ip,
+ int flags)
+{
+ int rc;
+ struct mu_sockaddr *remote_addr, *source_addr = NULL;
+ struct mu_sockaddr_hints hints;
+
+ memset (&hints, 0, sizeof hints);
+ hints.family = AF_INET;
+ hints.socktype = SOCK_STREAM;
+ hints.protocol = IPPROTO_TCP;
+ hints.port = port;
+ rc = mu_sockaddr_from_node (&remote_addr, host, NULL, &hints);
+ if (rc)
+ return rc;
+
+ if (source_ip)
+ {
+ struct sockaddr_in s;
+ s.sin_family = AF_INET;
+ s.sin_addr.s_addr = source_ip;
+ s.sin_port = 0;
+ rc = mu_sockaddr_create (&source_addr, (struct sockaddr*)&s,
+ sizeof (s));
+ if (rc)
+ {
+ mu_sockaddr_free (remote_addr);
+ return 0;
+ }
+ }
+
+ rc = mu_tcp_stream_create_from_sa (pstream, remote_addr, source_addr, flags);
+ if (rc)
+ {
+ mu_sockaddr_free (remote_addr);
+ mu_sockaddr_free (source_addr);
+ }
+ return rc;
+}
+
int
mu_tcp_stream_create_with_source_host (mu_stream_t *stream,
const char *host, unsigned port,
const char *source_host,
int flags)
{
- unsigned long source_addr;
- int ret = resolve_hostname (source_host, &source_addr);
- if (ret == 0)
- ret = mu_tcp_stream_create_with_source_ip (stream, host, port,
- source_addr, flags);
- return ret;
+ int rc;
+ struct mu_sockaddr *remote_addr, *source_addr = NULL;
+ struct mu_sockaddr_hints hints;
+
+ memset (&hints, 0, sizeof hints);
+ hints.family = AF_INET;
+ hints.socktype = SOCK_STREAM;
+ hints.port = port;
+ rc = mu_sockaddr_from_node (&remote_addr, host, NULL, &hints);
+ if (rc)
+ return rc;
+
+ if (source_host)
+ {
+ hints.flags = MU_AH_PASSIVE;
+ hints.port = 0;
+ rc = mu_sockaddr_from_node (&source_addr, source_host, NULL, &hints);
+ if (rc)
+ {
+ mu_sockaddr_free (remote_addr);
+ return 0;
+ }
+ }
+
+ rc = mu_tcp_stream_create_from_sa (stream, remote_addr, source_addr, flags);
+ if (rc)
+ {
+ mu_sockaddr_free (remote_addr);
+ mu_sockaddr_free (source_addr);
+ }
+ return rc;
}
int
mu_tcp_stream_create (mu_stream_t *stream, const char *host, unsigned port,
int flags)
{
- return mu_tcp_stream_create_with_source_ip (stream, host, port,
- INADDR_ANY, flags);
+ return mu_tcp_stream_create_with_source_host (stream, host, port,
+ NULL, flags);
}
diff --git a/libmailutils/tests/.gitignore b/libmailutils/tests/.gitignore
index d205efe63..d01d4ad93 100644
--- a/libmailutils/tests/.gitignore
+++ b/libmailutils/tests/.gitignore
@@ -1,5 +1,6 @@
atconfig
atlocal
+cidr
package.m4
testsuite
testsuite.dir
diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am
index 68618a1df..5c0087398 100644
--- a/libmailutils/tests/Makefile.am
+++ b/libmailutils/tests/Makefile.am
@@ -41,6 +41,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
INCLUDES = @MU_LIB_COMMON_INCLUDES@
noinst_PROGRAMS = \
addr\
+ cidr\
debugspec\
decode2047\
encode2047\
diff --git a/libmailutils/tests/cidr.c b/libmailutils/tests/cidr.c
new file mode 100644
index 000000000..797fb248e
--- /dev/null
+++ b/libmailutils/tests/cidr.c
@@ -0,0 +1,77 @@
+/* GNU Mailutils -- a suite of utilities for electronic mail
+ Copyright (C) 2011 Free Software Foundation, Inc.
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 3 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General
+ Public License along with this library. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <mailutils/mailutils.h>
+
+static void
+print_bytes (unsigned char *b, size_t l)
+{
+ for (; l; l--, b++)
+ printf (" %02x", *b);
+ printf ("\n");
+}
+
+int
+main (int argc, char **argv)
+{
+ mu_set_program_name (argv[0]);
+ if (argc < 2)
+ {
+ mu_error ("usage: %s CIDR [CIDR...]", argv[0]);
+ return 1;
+ }
+
+ while (--argc)
+ {
+ char *arg = *++argv;
+ struct mu_cidr cidr;
+ int rc;
+ char *str;
+
+ rc = mu_cidr_from_string (&cidr, arg);
+ if (rc)
+ {
+ mu_error ("%s: %s", arg, mu_strerror (rc));
+ continue;
+ }
+
+ printf ("%s:\n", arg);
+ printf ("family = %d\n", cidr.family);
+ printf ("len = %d\n", cidr.len);
+ printf ("address =");
+ print_bytes (cidr.address, cidr.len);
+ printf ("netmask =");
+ print_bytes (cidr.netmask, cidr.len);
+ rc = mu_cidr_format (&cidr, 0, &str);
+ if (rc)
+ {
+ mu_error ("cannot covert to string: %s", mu_strerror (rc));
+ return 2;
+ }
+
+ printf ("string = %s\n", str);
+ free (str);
+ }
+ return 0;
+}
+
+
diff --git a/libmailutils/tests/url-parse.c b/libmailutils/tests/url-parse.c
index 86c917315..48dd40f84 100644
--- a/libmailutils/tests/url-parse.c
+++ b/libmailutils/tests/url-parse.c
@@ -25,6 +25,7 @@
#include <mailutils/errno.h>
#include <mailutils/url.h>
#include <mailutils/secret.h>
+#include <mailutils/kwd.h>
#define CAT2(a,b) a ## b
@@ -73,12 +74,52 @@ print_query (mu_url_t url)
printf ("query[%lu] <%s>\n", (unsigned long) i, qargv[i]);
}
+struct mu_kwd parse_kwtab[] = {
+ { "hexcode", MU_URL_PARSE_HEXCODE },
+ { "hidepass", MU_URL_PARSE_HIDEPASS },
+ { "portsrv", MU_URL_PARSE_PORTSRV },
+ { "portwc", MU_URL_PARSE_PORTWC },
+ { "pipe", MU_URL_PARSE_PIPE },
+ { "slash", MU_URL_PARSE_SLASH },
+ { "dslash_optional", MU_URL_PARSE_DSLASH_OPTIONAL },
+ { "default", MU_URL_PARSE_DEFAULT },
+ { "all", MU_URL_PARSE_ALL },
+ { NULL }
+};
+
+
int
-main ()
+main (int argc, char **argv)
{
char str[1024];
unsigned port = 0;
- mu_url_t u = NULL;
+ mu_url_t u = NULL, uhint = NULL;
+ int i;
+ int parse_flags = 0;
+ int rc;
+
+ mu_set_program_name (argv[0]);
+ for (i = 1; i < argc; i++)
+ {
+ int flag;
+
+ if (strncmp (argv[i], "hint=", 5) == 0)
+ {
+ rc = mu_url_create (&uhint, argv[i] + 5);
+ if (rc)
+ {
+ mu_error ("cannot create hints: %s", mu_strerror (rc));
+ exit (1);
+ }
+ }
+ else if (mu_kwd_xlat_name_ci (parse_kwtab, argv[i], &flag) == 0)
+ parse_flags |= flag;
+ else
+ {
+ mu_error ("%s: unknown flag %s", argv[0], argv[i]);
+ exit (1);
+ }
+ }
while (fgets (str, sizeof (str), stdin) != NULL)
{
@@ -89,9 +130,9 @@ main ()
str[strlen (str) - 1] = '\0'; /* chop newline */
if (strspn (str, " \t") == strlen (str))
continue; /* skip empty lines */
- if ((rc = mu_url_create (&u, str)) != 0)
+ if ((rc = mu_url_create_hint (&u, str, parse_flags, uhint)) != 0)
{
- fprintf (stderr, "mu_url_create %s ERROR: [%d] %s",
+ fprintf (stderr, "mu_url_create %s ERROR: [%d] %s\n",
str, rc, mu_strerror (rc));
exit (1);
}
diff --git a/libmailutils/tests/url.at b/libmailutils/tests/url.at
index 8c392ea0e..c0669e2aa 100644
--- a/libmailutils/tests/url.at
+++ b/libmailutils/tests/url.at
@@ -20,10 +20,11 @@ dnl TESTURL([NAME], [KW = `'], [INPUT], [STDOUT = `'],
dnl [STDERR = `'], [RUN-IF-FAIL], [RUN-IF-PASS])
dnl
+m4_pushdef([URL_PARSE_OPTIONS])
m4_pushdef([TESTURL],[
m4_pushdef([MU_TEST_GROUP],[Url])
m4_pushdef([MU_TEST_KEYWORDS],[url])
-m4_pushdef([MU_TEST_COMMAND],[url-parse])
+m4_pushdef([MU_TEST_COMMAND],[url-parse URL_PARSE_OPTIONS])
MU_GENERIC_TEST([$1],[$2 url-m4_translit($3,[ ],[_])],[$3],[],[$4],[$5])
m4_popdef([MU_TEST_COMMAND])
m4_popdef([MU_TEST_KEYWORDS])
@@ -32,6 +33,8 @@ m4_popdef([MU_TEST_GROUP])
dnl ------------------------------------------------------------
+m4_define([URL_PARSE_OPTIONS],[default dslash_optional])
+
TESTURL([],[],
[scheme:],
[scheme <scheme>
@@ -76,6 +79,10 @@ port 0
path </absolute/path>
])
+dnl ------------------------------------------------------------
+
+m4_define([URL_PARSE_OPTIONS],[default])
+
TESTURL([],[],
[scheme://%75%73%65%72:%70%61%73%73@%68%6f%73%74],
[scheme <scheme>
@@ -198,7 +205,7 @@ path </a/path>
])
TESTURL([],[],
-[ftp:/a/path],
+[ftp:///a/path],
[scheme <ftp>
user <>
passwd <>
@@ -716,6 +723,7 @@ path <mbox/user@host>
param[0] <type=pass>
]])
+m4_pushdef([URL_PARSE_OPTIONS],[default dslash_optional])
TESTURL([],[],
[mbox:/var/spool/mail;type=index;param=2;user=gray],
[[scheme <mbox>
@@ -729,6 +737,7 @@ param[0] <type=index>
param[1] <param=2>
param[2] <user=gray>
]])
+m4_popdef([URL_PARSE_OPTIONS])
TESTURL([],[],
[mbox:///var/spool/mail;type=index;param=2;user=gray],
@@ -823,3 +832,4 @@ query[1] <list@dom>
]])
m4_popdef([TESTURL])
+m4_popdef([URL_PARSE_OPTIONS])
diff --git a/libmailutils/url/create.c b/libmailutils/url/create.c
index e58064081..130b7a2bc 100644
--- a/libmailutils/url/create.c
+++ b/libmailutils/url/create.c
@@ -59,9 +59,9 @@ getkn (struct mu_url_ctx *ctx, char *delim)
size_t n;
if (*ctx->cur == 0)
- return -1;
+ return MU_ERR_PARSE;
n = strcspn (ctx->cur, delim);
- if (n > ctx->toksize)
+ if (n + 1 > ctx->toksize)
{
char *p = realloc (ctx->tokbuf, n + 1);
if (!p)
@@ -220,11 +220,28 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host)
int rc;
mu_url_t url = ctx->url;
- rc = getkn (ctx, ":/;?");
+ rc = getkn (ctx, "[:/;?");
if (rc)
return rc;
- if (ctx->toklen)
+ if (*ctx->cur == '[')
+ {
+ /* Possibly IPv6 address */
+ rc = getkn (ctx, "]/;?");
+ if (rc)
+ return rc;
+ if (*ctx->cur == ']')
+ {
+ ctx->cur++;
+ rc = str_assign (&url->host, ctx->tokbuf + 1);
+ if (rc)
+ return rc;
+ url->flags |= MU_URL_HOST | MU_URL_IPV6;
+ has_host = 1;
+ }
+ }
+
+ if (!(url->flags & MU_URL_HOST) && ctx->toklen)
{
rc = str_assign (&url->host, ctx->tokbuf);
if (rc)
@@ -232,22 +249,20 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host)
url->flags |= MU_URL_HOST;
has_host = 1;
}
-
+
if (*ctx->cur == ':')
{
- ctx->cur++;
has_host = 1;
-
- rc = getkn (ctx, "/;?");
+ ctx->cur++;
+ rc = getkn (ctx, ":/;?");
if (rc)
return rc;
-
rc = str_assign (&url->portstr, ctx->tokbuf);
if (rc)
return rc;
url->flags |= MU_URL_PORT;
}
-
+
if (*ctx->cur == '/')
{
if (has_host)
@@ -269,7 +284,9 @@ _mu_url_ctx_parse_cred (struct mu_url_ctx *ctx)
int rc, has_cred;
mu_url_t url = ctx->url;
const char *save = ctx->cur;
-
+
+ if (*ctx->cur == 0)
+ return 0;
rc = getkn (ctx, "@");
if (rc)
return rc;
@@ -343,12 +360,18 @@ _mu_url_ctx_parse (struct mu_url_ctx *ctx)
{
int rc;
mu_url_t url = ctx->url;
+ const char *save = ctx->cur;
/* Parse the scheme part */
+ if (*ctx->cur == ':')
+ return _mu_url_ctx_parse_cred (ctx);
+
rc = getkn (ctx, ":/");
if (rc)
return rc;
- if (*ctx->cur == ':')
+ if (*ctx->cur == ':'
+ && ((ctx->flags & MU_URL_PARSE_DSLASH_OPTIONAL)
+ || (ctx->cur[1] == '/' && ctx->cur[2] == '/')))
{
rc = str_assign (&url->scheme, ctx->tokbuf);
if (rc)
@@ -356,7 +379,12 @@ _mu_url_ctx_parse (struct mu_url_ctx *ctx)
url->flags |= MU_URL_SCHEME;
ctx->cur++;
}
-
+ else
+ {
+ ctx->cur = save;
+ return _mu_url_ctx_parse_cred (ctx);
+ }
+
if (*ctx->cur == 0)
return 0;
@@ -535,5 +563,6 @@ mu_url_create (mu_url_t *purl, const char *str)
MU_URL_PARSE_HIDEPASS |
MU_URL_PARSE_PORTSRV |
MU_URL_PARSE_PIPE |
- MU_URL_PARSE_SLASH, NULL);
+ MU_URL_PARSE_SLASH |
+ MU_URL_PARSE_DSLASH_OPTIONAL, NULL);
}
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
@@ -22,6 +22,7 @@
#include "mailutils/libcfg.h"
#include "mailutils/acl.h"
#include "mailutils/argcv.h"
+#include "mailutils/cidr.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -53,53 +54,13 @@ getword (mu_config_value_t *val, int *pn)
return v->v.string;
}
-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))
return 1;
@@ -111,51 +72,19 @@ parsearg (mu_config_value_t *val, struct netdef *pnd, char **prest)
if (!w)
return 1;
}
-
- 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;
}
}
- else
- netmask = 0xfffffffful;
-
- pnd->netmask = netmask;
- if (parse_address (w, pnd))
- return 1;
-
+
if (prest)
{
if (n == val->v.arg.c)
@@ -204,15 +133,13 @@ cb_allow (void *data, mu_config_value_t *val)
{
int rc;
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;
}
@@ -221,15 +148,13 @@ cb_deny (void *data, mu_config_value_t *val)
{
int rc;
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;
}
@@ -238,16 +163,14 @@ cb_log (void *data, mu_config_value_t *val)
{
int rc;
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;
}
@@ -256,16 +179,14 @@ cb_exec (void *data, mu_config_value_t *val)
{
int rc;
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;
}
@@ -274,16 +195,14 @@ cb_ifexec (void *data, mu_config_value_t *val)
{
int rc;
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
@@ -48,6 +48,7 @@
#include <mailutils/smtp.h>
#include <mailutils/tls.h>
#include <mailutils/cstr.h>
+#include <mailutils/sockaddr.h>
#include <mailutils/sys/mailer.h>
#include <mailutils/sys/url.h>
#include <mailutils/sys/registrar.h>
@@ -114,8 +115,7 @@ smtp_mailer_add_auth_mech (struct _smtp_mailer *smtp_mailer, const char *str)
static int
smtp_open (mu_mailer_t mailer, int flags)
{
- const char *host, *auth;
- unsigned port;
+ const char *auth;
struct _smtp_mailer *smtp_mailer = mailer->data;
int rc;
size_t parmc = 0;
@@ -138,12 +138,6 @@ smtp_open (mu_mailer_t mailer, int flags)
mu_smtp_set_param (smtp_mailer->smtp, MU_SMTP_PARAM_URL,
mu_url_to_string (mailer->url));
- 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)
smtp_mailer_add_auth_mech (smtp_mailer, auth);
@@ -166,7 +160,20 @@ smtp_open (mu_mailer_t mailer, int flags)
if (mailer->stream == NULL)
{
- 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)
return rc;
mu_stream_set_buffer (mailer->stream, mu_buffer_line, 0);
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
@@ -27,6 +27,7 @@
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
+#include <netdb.h>
#include <mailutils/pop3.h>
#include <mailutils/attribute.h>
@@ -50,6 +51,7 @@
#include <mailutils/cstr.h>
#include <mailutils/cctype.h>
#include <mailutils/opool.h>
+#include <mailutils/sockaddr.h>
#include <mailutils/sys/folder.h>
#include <mailutils/sys/mailbox.h>
@@ -109,23 +111,26 @@ pop_open (mu_mailbox_t mbox, int flags)
{
struct _pop3_mailbox *mpd = mbox->data;
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. */
if (mpd == NULL)
return EINVAL;
- /* 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)
return status;
#ifdef WITH_TLS
diff --git a/mu/acl.c b/mu/acl.c
index 9e9fd8b88..4f796c582 100644
--- a/mu/acl.c
+++ b/mu/acl.c
@@ -41,36 +41,10 @@ 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;
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
acl_parse_opt (int key, char *arg, struct argp_state *state)
{
@@ -160,9 +134,17 @@ mutool_acl (int argc, char **argv)
{
const char *ap = *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)
{
mu_error ("mu_acl_check_sockaddr failed: %s", mu_strerror (rc));
diff --git a/mu/imap.c b/mu/imap.c
index 85a27a343..deea939f2 100644
--- a/mu/imap.c
+++ b/mu/imap.c
@@ -113,7 +113,6 @@ com_verbose (int argc, char **argv)
static int connect_argc;
static char **connect_argv;
#define host connect_argv[0]
-static int port = MU_IMAP_DEFAULT_PORT;
static char *username;
@@ -171,7 +170,6 @@ static int
com_connect (int argc, char **argv)
{
int status;
- int n = 0;
int tls = 0;
int i = 1;
enum mu_imap_state state;
@@ -194,16 +192,6 @@ com_connect (int argc, char **argv)
argc -= i;
argv += i;
- 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 ();
if (state != MU_IMAP_STATE_INIT)
@@ -213,13 +201,23 @@ com_connect (int argc, char **argv)
if (status == 0)
{
mu_stream_t tcp;
+ struct mu_sockaddr *sa;
+ struct mu_sockaddr_hints hints;
if (QRY_VERBOSE ())
{
imap_set_verbose ();
imap_set_verbose_mask ();
}
- 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)
{
#ifdef WITH_TLS
@@ -263,7 +261,6 @@ com_connect (int argc, char **argv)
for (i = 0; i < argc; i++)
connect_argv[i] = xstrdup (argv[i]);
connect_argv[i] = NULL;
- port = n;
imap_prompt_env ();
}
diff --git a/mu/pop.c b/mu/pop.c
index d72091cb1..de092cd5f 100644
--- a/mu/pop.c
+++ b/mu/pop.c
@@ -20,6 +20,10 @@
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netdb.h>
#include <mailutils/mailutils.h>
#include "mu.h"
#include "argp.h"
@@ -470,12 +474,28 @@ 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)
{
int status;
- int n = 0;
int tls = 0;
int i = 1;
+ int n;
for (i = 1; i < argc; i++)
{
@@ -496,16 +516,6 @@ com_connect (int argc, char **argv)
argc -= i;
argv += i;
- 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)
com_disconnect (0, NULL);
@@ -513,13 +523,26 @@ com_connect (int argc, char **argv)
if (status == 0)
{
mu_stream_t tcp;
+ struct mu_sockaddr *sa;
+ struct mu_sockaddr_hints hints;
if (QRY_VERBOSE ())
{
pop_set_verbose ();
pop_set_verbose_mask ();
}
- 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)
{
#ifdef WITH_TLS
diff --git a/testsuite/smtpsend.c b/testsuite/smtpsend.c
index e831968f5..2fe2d9f52 100644
--- a/testsuite/smtpsend.c
+++ b/testsuite/smtpsend.c
@@ -20,6 +20,7 @@
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
+#include <netdb.h>
#include <mailutils/cctype.h>
#include <mailutils/mailutils.h>
#include <mailutils/smtp.h>
@@ -85,7 +86,7 @@ main (int argc, char **argv)
int i;
char *host = NULL;
char *infile = NULL;
- int port = 25;
+ char *port = NULL;
int tls = 0;
int raw = 1;
int flags = 0;
@@ -96,6 +97,8 @@ main (int argc, char **argv)
mu_list_t rcpt_list = NULL;
mu_list_t meth_list = NULL;
mu_list_t skiphdr_list = NULL;
+ struct mu_sockaddr *sa;
+ struct mu_sockaddr_hints hints;
mu_set_program_name (argv[0]);
mu_stdstream_setup ();
@@ -111,14 +114,7 @@ main (int argc, char **argv)
for (i = 1; i < argc; i++)
{
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)
{
char *arg = argv[i] + 6;
@@ -194,7 +190,16 @@ main (int argc, char **argv)
MU_ASSERT (mu_stdio_stream_create (&instr, MU_STDIN_FD, flags));
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);
mu_stream_unref (stream);

Return to:

Send suggestions and report system problems to the System administrator.