Commit adca074d adca074d616ac562095a92e01f2b181e6d3593c8 by Sergey Poznyakoff

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.
1 parent 827cb66a
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
......@@ -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
......
......@@ -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
......
......@@ -43,6 +43,7 @@ noinst_PROGRAMS = \
murun\
musocio\
$(NNTPCLIENT)\
sa\
sfrom
EXTRA_PROGRAMS = nntpclient
......
......@@ -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,46 +80,18 @@ read_rules (FILE *fp)
continue;
}
p = strchr (ws.ws_wordv[1], '/');
if (p)
{
char *q;
unsigned netlen;
*p++ = 0;
netlen = strtoul (p, &q, 10);
if (*q == 0)
{
if (netlen == 0)
netmask = 0;
if (strcmp (ws.ws_wordv[1], "any") == 0)
memset (&cidr, 0, sizeof (cidr));
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 ("%d: invalid netmask", line);
continue;
}
netmask = addr.s_addr;
}
else
rc = mu_cidr_from_string (&cidr, ws.ws_wordv[1]);
if (rc)
{
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
......@@ -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));
......
......@@ -39,14 +39,10 @@ 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;
int rc;
mu_url_t url, url_hint;
struct mu_sockaddr_hints hints;
p = strchr (arg, ':');
if (!*p)
if (arg[0] == '/')
url_hint = NULL;
else
{
rc = mu_url_create (&url_hint, "inet://");
if (rc)
{
mu_error ("invalid specification: %s\n", arg);
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,
......
/* 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);
}
......@@ -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\
......
......@@ -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,
......
/* 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 */
......@@ -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);
......
......@@ -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 */
......
......@@ -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);
......
/* 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 */
......@@ -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,
......
......@@ -76,6 +76,9 @@ 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;
typedef struct mu_address *mu_address_t;
......
......@@ -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 */
......@@ -58,6 +59,8 @@ extern "C" {
"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|\
......
......@@ -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\
......
# 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
/* 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;
}
/* 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;
}
/* 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;
}
/* 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;
}
/* 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;
}
......@@ -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);
......
# 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")
......
......@@ -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));
}
if (ent->sa->sa_family != sa->sa_family)
{
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;
}
char *s;
if (sin_ent->sin_port && sin_item->sin_port
&& sin_ent->sin_port != sin_item->sin_port)
{
RESMATCH ("no (port differs)");
return 1;
}
break;
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);
}
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))
if (ent->cidr.len > 0 && mu_cidr_match (&ent->cidr, &rp->addr))
{
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,19 +305,15 @@ acl_getvar (const char *name, size_t nlen, void *data)
return rp->numbuf;
}
switch (rp->sa->sa_family)
{
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 0
/* FIXME?: */
if (SEQ ("port", name, nlen))
{
if (!rp->portbuf &&
......@@ -509,20 +321,8 @@ acl_getvar (const char *name, size_t nlen, void *data)
return NULL;
return rp->portbuf;
}
break;
#endif
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;
}
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,37 +529,36 @@ 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;
}
......@@ -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);
}
......
......@@ -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);
}
......
......@@ -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. */
......@@ -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))
{
mu_error (_("invalid family"));
return EINVAL;
}
int rc;
mu_url_t url, url_hint;
switch (s->s_sa.sa_family)
{
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);
}
if (arg[0] == '/')
url_hint = NULL;
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;
}
rc = mu_url_create (&url_hint, "inet://");
if (rc)
return rc;
}
break;
case AF_UNIX:
*psalen = sizeof (s->s_un);
len = strlen (arg);
if (len > sizeof s->s_un.sun_path - 1)
rc = mu_url_create_hint (&url, arg, MU_URL_PARSE_DEFAULT, url_hint);
mu_url_destroy (&url_hint);
if (rc)
{
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)
mu_error (_("cannot create sockaddr for URL `%s': %s"), arg,
mu_strerror (rc));
mu_url_destroy (&url);
return rc;
if (sa)
{
if (*psalen < salen)
return MU_ERR_BUFSPACE;
memcpy (sa, &s.s_sa, salen);
}
*psalen = salen;
return 0;
}
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,10 +831,38 @@ _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))
......@@ -1013,10 +870,7 @@ _cb_port (void *data, mu_config_value_t *val)
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,
......
# 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
/* 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);
}
/* 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;
}
/* 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;
}
}
/* 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;
}
/* 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;
}
/* 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;
}
/* 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;
}
/* 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;
}
/* 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);
}
......@@ -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);
}
......
atconfig
atlocal
cidr
package.m4
testsuite
testsuite.dir
......
......@@ -41,6 +41,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
INCLUDES = @MU_LIB_COMMON_INCLUDES@
noinst_PROGRAMS = \
addr\
cidr\
debugspec\
decode2047\
encode2047\
......
/* 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;
}
......@@ -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);
}
......
......@@ -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])
......
......@@ -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)
......@@ -235,13 +252,11 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host)
if (*ctx->cur == ':')
{
ctx->cur++;
has_host = 1;
rc = getkn (ctx, "/;?");
ctx->cur++;
rc = getkn (ctx, ":/;?");
if (rc)
return rc;
rc = str_assign (&url->portstr, ctx->tokbuf);
if (rc)
return rc;
......@@ -270,6 +285,8 @@ _mu_url_ctx_parse_cred (struct mu_url_ctx *ctx)
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,6 +379,11 @@ _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);
}
......
......@@ -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,52 +54,12 @@ 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;
......@@ -112,49 +73,17 @@ parsearg (mu_config_value_t *val, struct netdef *pnd, char **prest)
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;
if (strcmp (w, "any") == 0)
cidr->len = 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
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)
{
......@@ -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;
}
......
......@@ -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);
......
......@@ -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
......
......@@ -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));
......
......@@ -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 ();
}
......
......@@ -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
......
......@@ -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);
......