From adca074d616ac562095a92e01f2b181e6d3593c8 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Wed, 30 Mar 2011 00:49:43 +0300 Subject: 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. --- am/ipv6.m4 | 56 ++++++ configure.ac | 9 + examples/.gitignore | 2 + examples/Makefile.am | 1 + examples/aclck.c | 89 ++------- examples/echosrv.c | 69 ++++--- examples/sa.c | 93 ++++++++++ include/mailutils/Makefile.am | 2 + include/mailutils/acl.h | 8 +- include/mailutils/cidr.h | 61 +++++++ include/mailutils/debug.h | 3 - include/mailutils/mailutils.h | 2 + include/mailutils/server.h | 12 +- include/mailutils/sockaddr.h | 78 ++++++++ include/mailutils/stream.h | 4 + include/mailutils/types.hin | 3 + include/mailutils/url.h | 9 +- libmailutils/Makefile.am | 4 +- libmailutils/cidr/Makefile.am | 27 +++ libmailutils/cidr/fromsa.c | 101 +++++++++++ libmailutils/cidr/fromstr.c | 128 +++++++++++++ libmailutils/cidr/match.c | 38 ++++ libmailutils/cidr/tosa.c | 78 ++++++++ libmailutils/cidr/tostr.c | 159 +++++++++++++++++ libmailutils/diag/debug.c | 1 + libmailutils/diag/errors | 8 + libmailutils/server/acl.c | 366 ++++++++++---------------------------- libmailutils/server/ipsrv.c | 83 ++++----- libmailutils/server/msrv.c | 348 +++++++++++------------------------- libmailutils/sockaddr/Makefile.am | 31 ++++ libmailutils/sockaddr/copy.c | 36 ++++ libmailutils/sockaddr/create.c | 47 +++++ libmailutils/sockaddr/free.c | 50 ++++++ libmailutils/sockaddr/fromnode.c | 253 ++++++++++++++++++++++++++ libmailutils/sockaddr/insert.c | 64 +++++++ libmailutils/sockaddr/ipaddr.c | 88 +++++++++ libmailutils/sockaddr/str.c | 109 ++++++++++++ libmailutils/sockaddr/unlink.c | 45 +++++ libmailutils/sockaddr/url.c | 130 ++++++++++++++ libmailutils/stream/tcp.c | 178 +++++++++--------- libmailutils/tests/.gitignore | 1 + libmailutils/tests/Makefile.am | 1 + libmailutils/tests/cidr.c | 77 ++++++++ libmailutils/tests/url-parse.c | 49 ++++- libmailutils/tests/url.at | 14 +- libmailutils/url/create.c | 57 ++++-- libmu_cfg/acl.c | 135 +++----------- libproto/mailer/smtp.c | 25 ++- libproto/pop/mbox.c | 27 +-- mu/acl.c | 40 ++--- mu/imap.c | 25 ++- mu/pop.c | 47 +++-- testsuite/smtpsend.c | 25 +-- 53 files changed, 2416 insertions(+), 980 deletions(-) create mode 100644 am/ipv6.m4 create mode 100644 examples/sa.c create mode 100644 include/mailutils/cidr.h create mode 100644 include/mailutils/sockaddr.h create mode 100644 libmailutils/cidr/Makefile.am create mode 100644 libmailutils/cidr/fromsa.c create mode 100644 libmailutils/cidr/fromstr.c create mode 100644 libmailutils/cidr/match.c create mode 100644 libmailutils/cidr/tosa.c create mode 100644 libmailutils/cidr/tostr.c create mode 100644 libmailutils/sockaddr/Makefile.am create mode 100644 libmailutils/sockaddr/copy.c create mode 100644 libmailutils/sockaddr/create.c create mode 100644 libmailutils/sockaddr/free.c create mode 100644 libmailutils/sockaddr/fromnode.c create mode 100644 libmailutils/sockaddr/insert.c create mode 100644 libmailutils/sockaddr/ipaddr.c create mode 100644 libmailutils/sockaddr/str.c create mode 100644 libmailutils/sockaddr/unlink.c create mode 100644 libmailutils/sockaddr/url.c create mode 100644 libmailutils/tests/cidr.c diff --git a/am/ipv6.m4 b/am/ipv6.m4 new file mode 100644 index 000000000..2357314b9 --- /dev/null +++ b/am/ipv6.m4 @@ -0,0 +1,56 @@ +dnl This file is part of GNU Mailutils. -*- autoconf -*- +dnl Copyright (C) 2011 Free Software Foundation, Inc. +dnl +dnl GNU Mailutils is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3 of the License, or +dnl (at your option) any later version. +dnl +dnl GNU Mailutils is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with GNU Mailutils. If not, see . + +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 +#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 ]) + AC_CHECK_TYPE([struct sockaddr_in6], + [working_ipv6=yes], [working_ipv6=no], + [#include + #include ]) + AC_CHECK_TYPE([struct addrinfo], + [working_ipv6=yes], [working_ipv6=no], + [#include ]) + AC_CHECK_FUNC([getnameinfo], + [working_ipv6=yes], [working_ipv6=no], + [#include ]) + + if test $working_ipv6 = no; then + if test $status_ipv6 = yes; then + AC_MSG_ERROR([IPv6 support is required but not available]) + fi + fi + status_ipv6=$working_ipv6 + if test $status_ipv6 = yes; then + AC_DEFINE_UNQUOTED([MAILUTILS_IPV6],1, + [Define to 1 if IPv6 support is enabled]) + fi + fi]) \ No newline at end of file diff --git a/configure.ac b/configure.ac index e03a4c3b3..2edb49459 100644 --- a/configure.ac +++ b/configure.ac @@ -541,6 +541,10 @@ AH_BOTTOM([ ]) +# IPv6 support +MU_ENABLE_IPV6 + + ## FriBidi support AC_CHECK_FUNCS(wcwidth) @@ -1285,6 +1289,8 @@ LDAP support .................. $status_ldap Radius support ................ $status_radius Support for virtual domains ... $status_virtual_domains +IPv6 support .................. $status_ipv6 + Interfaces: Guile ......................... $status_guile @@ -1332,6 +1338,7 @@ status_mh=$mu_cv_enable_mh status_maildir=$mu_cv_enable_maildir status_smtp=$mu_cv_enable_smtp status_sendmail=$mu_cv_enable_sendmail +status_ipv6=$status_ipv6 ]) dnl Output Makefiles @@ -1382,6 +1389,8 @@ AC_CONFIG_FILES([ libmailutils/auth/Makefile libmailutils/base/Makefile libmailutils/address/Makefile + libmailutils/sockaddr/Makefile + libmailutils/cidr/Makefile libmailutils/cfg/Makefile libmailutils/diag/Makefile libmailutils/filter/Makefile diff --git a/examples/.gitignore b/examples/.gitignore index af4156be3..890812aae 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -11,6 +11,7 @@ iconv listop lsf mailcap +mblconv mimetest msg-send mta @@ -20,5 +21,6 @@ muemail murun musocio nntpclient +sa sfrom url-parse diff --git a/examples/Makefile.am b/examples/Makefile.am index e22a8d355..9df91ea62 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -43,6 +43,7 @@ noinst_PROGRAMS = \ murun\ musocio\ $(NNTPCLIENT)\ + sa\ sfrom EXTRA_PROGRAMS = nntpclient diff --git a/examples/aclck.c b/examples/aclck.c index 57f5c0388..033c444b1 100644 --- a/examples/aclck.c +++ b/examples/aclck.c @@ -28,35 +28,9 @@ #include #include -struct sockaddr *target_sa; -int target_salen; +struct mu_sockaddr *target_sa; mu_acl_t acl; -struct sockaddr * -parse_address (int *psalen, char *str) -{ - struct sockaddr_in in; - struct sockaddr *sa; - - in.sin_family = AF_INET; - if (inet_aton (str, &in.sin_addr) == 0) - { - mu_error ("Invalid IPv4: %s", str); - exit (1); - } - in.sin_port = 0; - *psalen = sizeof (in); - sa = malloc (*psalen); - if (!sa) - { - mu_error ("%s", mu_strerror (errno)); - exit (1); - } - - memcpy (sa, &in, sizeof (in)); - return sa; -} - void read_rules (FILE *fp) { @@ -76,12 +50,9 @@ read_rules (FILE *fp) ws.ws_comment = "#"; while (fgets (buf, sizeof buf, fp)) { - unsigned long netmask; - int salen; - struct sockaddr *sa; + struct mu_cidr cidr; mu_acl_action_t action; void *data = NULL; - char *p; int len = strlen (buf); if (len == 0) @@ -109,47 +80,19 @@ read_rules (FILE *fp) continue; } - p = strchr (ws.ws_wordv[1], '/'); - if (p) + if (strcmp (ws.ws_wordv[1], "any") == 0) + memset (&cidr, 0, sizeof (cidr)); + else { - char *q; - unsigned netlen; - - *p++ = 0; - netlen = strtoul (p, &q, 10); - if (*q == 0) - { - if (netlen == 0) - netmask = 0; - else - { - netmask = 0xfffffffful >> (32 - netlen); - netmask <<= (32 - netlen); - netmask = htonl (netmask); - } - } - else if (*q == '.') + rc = mu_cidr_from_string (&cidr, ws.ws_wordv[1]); + if (rc) { - struct in_addr addr; - - if (inet_aton (p, &addr) == 0) - { - mu_error ("%d: invalid netmask", line); - continue; - } - netmask = addr.s_addr; - } - else - { - mu_error ("%d: invalid netmask", line); + mu_error ("%d: invalid source CIDR: %s", + line, mu_strerror (rc)); continue; } } - else - netmask = 0xfffffffful; - - sa = parse_address (&salen, ws.ws_wordv[1]); - + /* accept addr deny addr log addr [rest ...] @@ -174,7 +117,7 @@ read_rules (FILE *fp) data = strdup (ws.ws_wordv[2]); } - rc = mu_acl_append (acl, action, data, sa, salen, netmask); + rc = mu_acl_append (acl, action, data, &cidr); if (rc) mu_error ("%d: cannot append acl entry: %s", line, mu_strerror (rc)); @@ -203,7 +146,12 @@ main (int argc, char **argv) break; case 'a': - target_sa = parse_address (&target_salen, optarg); + rc = mu_sockaddr_from_node (&target_sa, optarg, NULL, NULL); + if (rc) + { + mu_error ("mu_sockaddr_from_node: %s", mu_strerror (rc)); + exit (1); + } break; case 'f': @@ -225,7 +173,8 @@ main (int argc, char **argv) argc -= optind; read_rules (file ? file : stdin); - rc = mu_acl_check_sockaddr (acl, target_sa, target_salen, &result); + rc = mu_acl_check_sockaddr (acl, target_sa->addr, target_sa->addrlen, + &result); if (rc) { mu_error ("mu_acl_check_sockaddr failed: %s", mu_strerror (rc)); diff --git a/examples/echosrv.c b/examples/echosrv.c index fb68e7aee..fffde7343 100644 --- a/examples/echosrv.c +++ b/examples/echosrv.c @@ -39,13 +39,9 @@ echo_conn (int fd, struct sockaddr *s, int len, void *server_data, void *call_data, mu_ip_server_t srv) { - struct sockaddr_in srv_addr, *s_in = (struct sockaddr_in *)s; - int addrlen = sizeof srv_addr; pid_t pid; char buf[512]; FILE *in, *out; - - mu_ip_server_get_sockaddr (srv, (struct sockaddr *)&srv_addr, &addrlen); pid = fork (); if (pid == -1) @@ -56,10 +52,20 @@ echo_conn (int fd, struct sockaddr *s, int len, if (pid) { - mu_diag_output (MU_DIAG_INFO, "%lu: opened connection %s:%d => %s:%d", + struct mu_sockaddr *clt_addr; + int rc = mu_sockaddr_create (&clt_addr, s, len); + if (rc) + { + mu_error ("mu_sockaddr_create failed: %s", mu_strerror (rc)); + return 0; + } + + mu_diag_output (MU_DIAG_INFO, "%lu: opened connection %s => %s", (unsigned long) pid, - inet_ntoa (srv_addr.sin_addr), ntohs (srv_addr.sin_port), - inet_ntoa (s_in->sin_addr), ntohs (s_in->sin_port)); + mu_ip_server_addrstr (srv), + mu_sockaddr_str (clt_addr)); + + mu_sockaddr_free (clt_addr); return 0; } @@ -108,34 +114,45 @@ tcp_conn_free (void *conn_data, void *server_data) void create_server (char *arg) { - char *p, *q; - struct sockaddr_in s; + struct mu_sockaddr *s; mu_ip_server_t tcpsrv; - unsigned n; - - p = strchr (arg, ':'); - if (!*p) + int rc; + mu_url_t url, url_hint; + struct mu_sockaddr_hints hints; + + if (arg[0] == '/') + url_hint = NULL; + else { - mu_error ("invalid specification: %s\n", arg); - exit (1); + rc = mu_url_create (&url_hint, "inet://"); + if (rc) + { + mu_error ("cannot create URL hints: %s", mu_strerror (rc)); + exit (1); + } } - *p++ = 0; - s.sin_family = AF_INET; - if (inet_aton (arg, &s.sin_addr) == 0) + rc = mu_url_create_hint (&url, arg, MU_URL_PARSE_DEFAULT, url_hint); + mu_url_destroy (&url_hint); + if (rc) { - mu_error ("invalid IP address: %s\n", arg); + mu_error ("cannot parse URL `%s': %s", arg, mu_strerror (rc)); exit (1); } - n = strtoul (p, &q, 0); - if (*q) + + memset (&hints, sizeof(hints), 0); + hints.flags = MU_AH_PASSIVE; + hints.socktype = SOCK_STREAM; + hints.protocol = IPPROTO_TCP; + rc = mu_sockaddr_from_url (&s, url, &hints); + mu_url_destroy (&url); + + if (rc) { - mu_error ("invalid port number: %s\n", p); + mu_error ("cannot create sockaddr: %s", mu_strerror (rc)); exit (1); - } - s.sin_port = htons (n); + } - MU_ASSERT (mu_ip_server_create (&tcpsrv, (struct sockaddr*) &s, sizeof s, - MU_IP_TCP)); + MU_ASSERT (mu_ip_server_create (&tcpsrv, s, MU_IP_TCP)); MU_ASSERT (mu_ip_server_open (tcpsrv)); MU_ASSERT (mu_ip_server_set_conn (tcpsrv, echo_conn)); MU_ASSERT (mu_server_add_connection (server, diff --git a/examples/sa.c b/examples/sa.c new file mode 100644 index 000000000..7cc7e93b5 --- /dev/null +++ b/examples/sa.c @@ -0,0 +1,93 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 1999, 2000, 2001, 2002, 2005, 2007, 2010, 2011 Free + Software Foundation, Inc. + + GNU Mailutils is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3, or (at your option) + any later version. + + GNU Mailutils is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Mailutils. If not, see . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include + +int +main (int argc, char **argv) +{ + struct mu_sockaddr_hints hints; + struct mu_sockaddr *sa, *ap; + int rc, i; + char *node = NULL, *serv = NULL; + char *urlstr; + + mu_set_program_name (argv[0]); + + memset (&hints, 0, sizeof (hints)); + hints.family = AF_UNSPEC; + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "passive") == 0) + hints.flags |= MU_AH_PASSIVE; + else if (strcmp (argv[i], "detect") == 0) + hints.flags |= MU_AH_DETECT_FAMILY; + else if (strncmp (argv[i], "node=", 5) == 0) + node = argv[i] + 5; + else if (strncmp (argv[i], "serv=", 5) == 0) + serv = argv[i] + 5; + else if (strncmp (argv[i], "url=", 4) == 0) + urlstr = argv[i] + 4; + else if (strncmp (argv[i], "proto=", 6) == 0) + hints.protocol = atoi(argv[i] + 6); + else if (strncmp (argv[i], "family=", 7) == 0) + hints.family = atoi (argv[i] + 7); + else if (strncmp (argv[i], "socktype=", 9) == 0) + hints.socktype = atoi (argv[i] + 9); + else + { + mu_error ("unknown argument: %s", argv[i]); + exit (1); + } + } + + if (urlstr) + { + mu_url_t url; + + if (node || serv) + { + mu_error ("both url and host/serv are given"); + exit (1); + } + + rc = mu_url_create (&url, urlstr); + if (rc) + { + mu_error ("cannot create url: %s", mu_strerror (rc)); + exit (2); + } + rc = mu_sockaddr_from_url (&sa, url, &hints); + } + else + rc = mu_sockaddr_from_node (&sa, node, serv, &hints); + if (rc) + { + mu_error ("cannot create sockaddr: %s", mu_strerror (rc)); + exit (2); + } + + for (ap = sa; ap; ap = ap->next) + printf ("%s\n", mu_sockaddr_str (ap)); + + mu_sockaddr_free (sa); + exit (0); +} + diff --git a/include/mailutils/Makefile.am b/include/mailutils/Makefile.am index daa46e9fe..1e2189437 100644 --- a/include/mailutils/Makefile.am +++ b/include/mailutils/Makefile.am @@ -36,6 +36,7 @@ pkginclude_HEADERS = \ body.h\ cctype.h\ cfg.h\ + cidr.h\ cstr.h\ daemon.h\ debug.h\ @@ -89,6 +90,7 @@ pkginclude_HEADERS = \ server.h\ sieve.h\ smtp.h\ + sockaddr.h\ stdstream.h\ stream.h\ syslog.h\ diff --git a/include/mailutils/acl.h b/include/mailutils/acl.h index b898463eb..167acc82c 100644 --- a/include/mailutils/acl.h +++ b/include/mailutils/acl.h @@ -47,13 +47,11 @@ int mu_acl_destroy (mu_acl_t *acl); int mu_acl_count (mu_acl_t acl, size_t *pcount); int mu_acl_get_iterator (mu_acl_t acl, mu_iterator_t *pitr); int mu_acl_append (mu_acl_t acl, mu_acl_action_t act, void *data, - struct sockaddr *sa, int salen, - unsigned long netmask); + struct mu_cidr *); int mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data, - struct sockaddr *sa, int salen, unsigned long netmask); + struct mu_cidr *); int mu_acl_insert (mu_acl_t acl, size_t pos, int before, - mu_acl_action_t act, void *data, - struct sockaddr *sa, int salen, unsigned long netmask); + mu_acl_action_t act, void *data, struct mu_cidr *); int mu_acl_check_ipv4 (mu_acl_t acl, unsigned int addr, mu_acl_result_t *pres); int mu_acl_check_inaddr (mu_acl_t acl, const struct in_addr *inp, diff --git a/include/mailutils/cidr.h b/include/mailutils/cidr.h new file mode 100644 index 000000000..c54bf6224 --- /dev/null +++ b/include/mailutils/cidr.h @@ -0,0 +1,61 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + . */ + +#ifndef _MAILUTILS_CIDR_H +#define _MAILUTILS_CIDR_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define MU_INADDR_BYTES 16 + +struct mu_cidr +{ + int family; + int len; + unsigned char address[MU_INADDR_BYTES]; + unsigned char netmask[MU_INADDR_BYTES]; +}; + +#define MU_CIDR_MAXBUFSIZE 81 + +int mu_cidr_from_sockaddr (struct mu_cidr *cp, const struct sockaddr *sa); +int mu_cidr_from_string (struct mu_cidr *cp, const char *str); + +#define MU_CIDR_FMT_ADDRONLY 0x01 + +int mu_cidr_to_string (struct mu_cidr *cidr, int flags, char *buf, size_t size, + size_t *pret); +int mu_cidr_format (struct mu_cidr *, int flags, char **pbuf); +int mu_cidr_to_sockaddr (struct mu_cidr *, struct sockaddr **sa); + +int mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b); + +int _mu_inaddr_to_bytes (int af, void *buf, unsigned char *bytes); + +#ifdef __cplusplus +} +#endif + +#endif /* _MAILUTILS_CIDR_H */ + + diff --git a/include/mailutils/debug.h b/include/mailutils/debug.h index 5072d51d2..a619661d7 100644 --- a/include/mailutils/debug.h +++ b/include/mailutils/debug.h @@ -54,9 +54,6 @@ extern int mu_debug_line_info; struct sockaddr; -void mu_sockaddr_to_str (const struct sockaddr *sa, int salen, - char *bufptr, size_t buflen, - size_t *plen); char *mu_sockaddr_to_astr (const struct sockaddr *sa, int salen); diff --git a/include/mailutils/mailutils.h b/include/mailutils/mailutils.h index 8d9e04b77..08a2fc0bc 100644 --- a/include/mailutils/mailutils.h +++ b/include/mailutils/mailutils.h @@ -67,5 +67,7 @@ #include #include #include +#include +#include /* EOF */ diff --git a/include/mailutils/server.h b/include/mailutils/server.h index bf8d10e6f..c5da97e43 100644 --- a/include/mailutils/server.h +++ b/include/mailutils/server.h @@ -54,8 +54,8 @@ typedef void (*mu_ip_server_free_fp) (void *data); #define MU_IP_TCP 0 #define MU_IP_UDP 1 -int mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr, - int len, int type); +int mu_ip_server_create (mu_ip_server_t *psrv, struct mu_sockaddr *addr, + int type); int mu_ip_server_destroy (mu_ip_server_t *psrv); int mu_ip_server_get_type (mu_ip_server_t srv, int *ptype); int mu_ip_server_set_ident (mu_ip_server_t srv, const char *ident); @@ -69,8 +69,8 @@ int mu_ip_server_shutdown (mu_ip_server_t srv); int mu_ip_server_accept (mu_ip_server_t srv, void *call_data); int mu_ip_server_loop (mu_ip_server_t srv, void *call_data); int mu_ip_server_get_fd (mu_ip_server_t srv); -int mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct sockaddr *s, - int *size); +int mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct mu_sockaddr **psa); +const char *mu_ip_server_addrstr (mu_ip_server_t srv); int mu_tcp_server_set_backlog (mu_ip_server_t srv, int backlog); int mu_udp_server_set_bufsize (mu_ip_server_t srv, size_t size); @@ -99,8 +99,6 @@ void mu_m_server_set_max_children (mu_m_server_t srv, size_t num); int mu_m_server_set_pidfile (mu_m_server_t srv, const char *pidfile); int mu_m_server_set_foreground (mu_m_server_t srv, int enable); void mu_m_server_set_default_port (mu_m_server_t srv, int port); -void mu_m_server_set_default_address (mu_m_server_t srv, struct sockaddr *sa, - int salen); void mu_m_server_set_timeout (mu_m_server_t srv, time_t t); void mu_m_server_set_mode (mu_m_server_t srv, int mode); void mu_m_server_set_sigset (mu_m_server_t srv, sigset_t *sigset); @@ -112,8 +110,6 @@ time_t mu_m_server_timeout (mu_m_server_t srv); const char * mu_m_server_pidfile (mu_m_server_t srv); void mu_m_server_get_sigset (mu_m_server_t srv, sigset_t *sigset); int mu_m_server_get_srvlist (mu_m_server_t srv, mu_list_t *plist); -int mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa, - int *salen); void mu_m_server_configured_count (mu_m_server_t msrv, size_t count); diff --git a/include/mailutils/sockaddr.h b/include/mailutils/sockaddr.h new file mode 100644 index 000000000..5a98f7a5a --- /dev/null +++ b/include/mailutils/sockaddr.h @@ -0,0 +1,78 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + . */ + +#ifndef _MAILUTILS_SOCKADDR_H +#define _MAILUTILS_SOCKADDR_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct mu_sockaddr +{ + struct mu_sockaddr *prev, *next; + struct sockaddr *addr; /* Address */ + socklen_t addrlen; /* Size of addr */ + char *str; /* string representation of addr, + filled up by mu_sockaddr_str */ +}; + +#define MU_AH_PASSIVE 0x01 +#define MU_AH_DETECT_FAMILY 0x02 + +struct mu_sockaddr_hints +{ + int flags; + int family; + int socktype; + int protocol; + unsigned short port; +}; + +int mu_sockaddr_create (struct mu_sockaddr **res, + struct sockaddr *addr, socklen_t len); +int mu_sockaddr_copy (struct mu_sockaddr **pnew, struct mu_sockaddr *old); +void mu_sockaddr_free (struct mu_sockaddr *addr); +struct mu_sockaddr *mu_sockaddr_unlink (struct mu_sockaddr *addr); +void mu_sockaddr_free_list (struct mu_sockaddr *addr); +struct mu_sockaddr *mu_sockaddr_insert (struct mu_sockaddr *anchor, + struct mu_sockaddr *addr, + int before); +const char *mu_sockaddr_str (struct mu_sockaddr *addr); + +int mu_sockaddr_format (char **pbuf, const struct sockaddr *sa, + socklen_t salen); + +int mu_sockaddr_from_node (struct mu_sockaddr **retval, const char *node, + const char *serv, struct mu_sockaddr_hints *hints); +int mu_sockaddr_from_url (struct mu_sockaddr **retval, mu_url_t url, + struct mu_sockaddr_hints *hints); + +int mu_str_is_ipv4 (const char *addr); +int mu_str_is_ipv6 (const char *addr); +int mu_str_is_ipaddr (const char *addr); + +#ifdef __cplusplus +} +#endif + +#endif /* _MAILUTILS_SOCKADDR_H */ + diff --git a/include/mailutils/stream.h b/include/mailutils/stream.h index b253f4ef2..8bea9074d 100644 --- a/include/mailutils/stream.h +++ b/include/mailutils/stream.h @@ -315,6 +315,10 @@ int mu_streamref_create_abridged (mu_stream_t *pref, mu_stream_t str, mu_off_t start, mu_off_t end); int mu_streamref_create (mu_stream_t *pref, mu_stream_t str); +int mu_tcp_stream_create_from_sa (mu_stream_t *pstream, + struct mu_sockaddr *remote_addr, + struct mu_sockaddr *source_addr, int flags); + int mu_tcp_stream_create_with_source_ip (mu_stream_t *stream, const char *host, unsigned port, unsigned long source_ip, diff --git a/include/mailutils/types.hin b/include/mailutils/types.hin index e89b799c5..bf81756bb 100644 --- a/include/mailutils/types.hin +++ b/include/mailutils/types.hin @@ -75,6 +75,9 @@ struct _mu_assoc; struct _mu_acl; struct _mu_server; struct _mu_tcp_server; + +struct mu_sockaddr; /* defined in mailutils/sockaddr.h */ +struct mu_cidr; /* defined in mailutils/cidr.h */ typedef _MU_OFF_TYPE_ mu_off_t; diff --git a/include/mailutils/url.h b/include/mailutils/url.h index 031e568c6..c33dadc45 100644 --- a/include/mailutils/url.h +++ b/include/mailutils/url.h @@ -34,6 +34,7 @@ extern "C" { #define MU_URL_PATH 0x0040 /* Has path */ #define MU_URL_PARAM 0x0080 /* Has parameters */ #define MU_URL_QUERY 0x0100 /* Has query */ +#define MU_URL_IPV6 0x0200 /* Host part is bracketed (IPv6) */ #define MU_URL_CRED (MU_URL_USER | MU_URL_SECRET | MU_URL_AUTH) /* Has some of authentication credentials */ @@ -53,12 +54,14 @@ extern "C" { #define MU_URL_PARSE_PORTSRV 0x0004 /* Use getservbyname to determine port number */ #define MU_URL_PARSE_PORTWC 0x0008 /* Allow wildcard (*) as a port - number (for tickets) */ + number (for tickets) */ #define MU_URL_PARSE_PIPE 0x0010 /* Translate "| ..." to - "prog://..." */ + "prog://..." */ #define MU_URL_PARSE_SLASH 0x0020 /* Translate "/..." to "file:///..." */ - +#define MU_URL_PARSE_DSLASH_OPTIONAL 0x0040 /* Double-slash after scheme: + part is optional */ + #define MU_URL_PARSE_DEFAULT \ (MU_URL_PARSE_HEXCODE|MU_URL_PARSE_HIDEPASS|MU_URL_PARSE_PORTSRV|\ MU_URL_PARSE_PIPE|MU_URL_PARSE_SLASH) diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am index ed1aeb019..5aef3382d 100644 --- a/libmailutils/Makefile.am +++ b/libmailutils/Makefile.am @@ -16,7 +16,7 @@ # Public License along with this library. If not, see # . -SUBDIRS = auth base address cfg diag filter mailbox mailer mime\ +SUBDIRS = auth base address sockaddr cidr cfg diag filter mailbox mailer mime\ server string stream stdstream property url . tests lib_LTLIBRARIES = libmailutils.la @@ -28,6 +28,8 @@ libmailutils_la_LIBADD = \ auth/libauth.la\ base/libbase.la\ address/libaddress.la\ + sockaddr/libsockaddr.la\ + cidr/libcidr.la\ cfg/libcfg.la\ diag/libdiag.la\ filter/libfilter.la\ diff --git a/libmailutils/cidr/Makefile.am b/libmailutils/cidr/Makefile.am new file mode 100644 index 000000000..408806f79 --- /dev/null +++ b/libmailutils/cidr/Makefile.am @@ -0,0 +1,27 @@ +# GNU Mailutils -- a suite of utilities for electronic mail +# Copyright (C) 2011 Free Software Foundation, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 3 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General +# Public License along with this library. If not, see +# . + +noinst_LTLIBRARIES = libcidr.la + +libcidr_la_SOURCES = \ + fromsa.c\ + fromstr.c\ + match.c\ + tosa.c\ + tostr.c + +INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils diff --git a/libmailutils/cidr/fromsa.c b/libmailutils/cidr/fromsa.c new file mode 100644 index 000000000..a2fda6680 --- /dev/null +++ b/libmailutils/cidr/fromsa.c @@ -0,0 +1,101 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void +uint32_to_bytes (unsigned char *bytes, uint32_t u) +{ + int i; + + for (i = 0; i < 4; i++) + { + bytes[i] = u & 0xff; + u >>= 8; + } +} + +int +_mu_inaddr_to_bytes (int af, void *buf, unsigned char *bytes) +{ + uint32_t u; + + switch (af) + { + case AF_INET: + memcpy (&u, buf, sizeof u); + uint32_to_bytes (bytes, u); + return 4; + +#ifdef MAILUTILS_IPV6 + case AF_INET6: + memcpy (bytes, buf, 16); + return 16; +#endif + } + return 0; +} + +int +_mu_sockaddr_to_bytes (unsigned char *bytes, struct sockaddr const *sa) +{ + switch (sa->sa_family) + { + case AF_INET: + uint32_to_bytes (bytes, ((struct sockaddr_in*)sa)->sin_addr.s_addr); + return 4; + +#ifdef MAILUTILS_IPV6 + case AF_INET6: + memcpy (bytes, &((struct sockaddr_in6*)sa)->sin6_addr, 16); + return 16; +#endif + } + return 0; +} + +int +mu_cidr_from_sockaddr (struct mu_cidr *cidr, const struct sockaddr *sa) +{ + unsigned char address[MU_INADDR_BYTES]; + int len; + int i; + + len = _mu_sockaddr_to_bytes (address, sa); + if (len == 0) + return MU_ERR_FAMILY; + cidr->family = sa->sa_family; + cidr->len = len; + memcpy (cidr->address, address, sizeof (cidr->address)); + for (i = 0; i < MU_INADDR_BYTES; i++) + cidr->netmask[i] = 0xff; + return 0; +} + + diff --git a/libmailutils/cidr/fromstr.c b/libmailutils/cidr/fromstr.c new file mode 100644 index 000000000..4e7a56f80 --- /dev/null +++ b/libmailutils/cidr/fromstr.c @@ -0,0 +1,128 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include +#include +#include +#include + +static void +masklen_to_netmask (unsigned char *buf, size_t len, size_t masklen) +{ + int i, cnt; + + cnt = masklen / 8; + for (i = 0; i < cnt; i++) + buf[i] = 0xff; + if (i == MU_INADDR_BYTES) + return; + cnt = 8 - masklen % 8; + buf[i++] = (0xff >> cnt) << cnt; + for (; i < MU_INADDR_BYTES; i++) + buf[i] = 0; +} + +int +mu_cidr_from_string (struct mu_cidr *pcidr, const char *str) +{ + int rc; + char ipbuf[41]; + struct mu_cidr cidr; + char *p; + size_t len; + union + { + struct in_addr in; +#ifdef MAILUTILS_IPV6 + struct in6_addr in6; +#endif + } inaddr; + + p = strchr (str, '/'); + if (p) + len = p - str; + else + len = strlen (str); + + if (len > sizeof (ipbuf)) + return MU_ERR_BUFSPACE; + + memcpy (ipbuf, str, len); + ipbuf[len] = 0; + + if (mu_str_is_ipv4 (ipbuf)) + cidr.family = AF_INET; +#ifdef MAILUTILS_IPV6 + else if (mu_str_is_ipv6 (ipbuf)) + cidr.family = AF_INET6; +#endif + else + return MU_ERR_FAMILY; + + rc = inet_pton (cidr.family, ipbuf, &inaddr); + if (rc == -1) + return MU_ERR_FAMILY; + else if (rc == 0) + return MU_ERR_NONAME; + else if (rc != 1) + return MU_ERR_FAILURE; + + cidr.len = _mu_inaddr_to_bytes (cidr.family, &inaddr, cidr.address); + if (cidr.len == 0) + return MU_ERR_FAMILY; + + if (p) + { + char *end; + unsigned long masklen; + + p++; + + masklen = strtoul (p, &end, 10); + if (*end == 0) + masklen_to_netmask (cidr.netmask, cidr.len, masklen); + else if ((cidr.family == AF_INET && mu_str_is_ipv4 (p)) +#ifdef MAILUTILS_IPV6 + || (cidr.family == AF_INET6 && mu_str_is_ipv6 (ipbuf)) +#endif + ) + { + rc = inet_pton (cidr.family, p, &inaddr); + if (rc == -1) + return MU_ERR_FAMILY; + else if (rc == 0) + return MU_ERR_NONAME; + else if (rc != 1) + return MU_ERR_FAILURE; + + _mu_inaddr_to_bytes (cidr.family, &inaddr, cidr.netmask); + } + else + return MU_ERR_FAMILY; + } + else + masklen_to_netmask (cidr.netmask, cidr.len, cidr.len * 8); + + memcpy (pcidr, &cidr, sizeof (*pcidr)); + return 0; +} + diff --git a/libmailutils/cidr/match.c b/libmailutils/cidr/match.c new file mode 100644 index 000000000..dff9194ee --- /dev/null +++ b/libmailutils/cidr/match.c @@ -0,0 +1,38 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include + +int +mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b) +{ + int i; + + if (a->family != b->family) + return 1; + for (i = 0; i < a->len; i++) + { + if (a->address[i] != (b->address[i] & a->netmask[i])) + return 1; + } + return 0; +} + diff --git a/libmailutils/cidr/tosa.c b/libmailutils/cidr/tosa.c new file mode 100644 index 000000000..c14a995da --- /dev/null +++ b/libmailutils/cidr/tosa.c @@ -0,0 +1,78 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int +mu_cidr_to_sockaddr (struct mu_cidr *cidr, struct sockaddr **psa) +{ + union + { + struct sockaddr sa; + struct sockaddr_in s_in; +#ifdef MAILUTILS_IPV6 + struct sockaddr_in6 s_in6; +#endif + } addr; + struct sockaddr *sa; + int socklen; + int i; + + memset (&addr, 0, sizeof (addr)); + addr.sa.sa_family = cidr->family; + switch (cidr->family) + { + case AF_INET: + socklen = sizeof (addr.s_in); + for (i = 0; i < cidr->len; i++) + { + addr.s_in.sin_addr.s_addr <<= 8; + addr.s_in.sin_addr.s_addr |= cidr->address[i]; + } + break; + +#ifdef MAILUTILS_IPV6 + case AF_INET6: + socklen = sizeof (addr.s_in6); + memcpy (&addr.s_in6.sin6_addr, cidr->address, 16); + break; +#endif + + default: + return MU_ERR_FAMILY; + } + + sa = malloc (socklen); + if (!sa) + return ENOMEM; + memcpy (sa, &addr, socklen); + *psa = sa; + return 0; +} + diff --git a/libmailutils/cidr/tostr.c b/libmailutils/cidr/tostr.c new file mode 100644 index 000000000..3d1ee5f49 --- /dev/null +++ b/libmailutils/cidr/tostr.c @@ -0,0 +1,159 @@ +/* GNU Mailutils -- a suite of utilities for electronic mail + Copyright (C) 2011 Free Software Foundation, Inc. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library. If not, see + . */ + +#ifdef HAVE_CONFIG_H +# include +#endif +#include +#include +#include +#include + +static int +to_xdig (unsigned char b) +{ + if (b >= 0xa) + return 'A' + b - 0xa; + else + return '0' + b; +} + +static size_t +format_ipv6_bytes (const unsigned char *bytes, int len, + char *buf, size_t size) +{ + size_t total = 0; + int i; + + for (i = 0; i < len; i += 2) + { + if (i) + { + if (total++ < size) + *buf++ = ':'; + } + if (total++ < size) + *buf++ = to_xdig (*bytes >> 4); + if (total++ < size) + *buf++ = to_xdig (*bytes & 0xf); + bytes++; + if (total++ < size) + *buf++ = to_xdig (*bytes >> 4); + if (total++ < size) + *buf++ = to_xdig (*bytes & 0xf); + bytes++; + } + return total; +} + +static size_t +format_ipv4_bytes (const unsigned char *bytes, int len, + char *buf, size_t size) +{ + int i; + size_t total = 0; + + for (i = 0; i < len; i++) + { + unsigned char b = *bytes++; + char nbuf[3]; + int j; + + if (i) + { + if (total++ < size) + *buf++ = '.'; + } + + j = 0; + do + { + nbuf[j++] = b % 10 + '0'; + b /= 10; + } + while (b); + + for (; j; j--) + { + if (total++ < size) + *buf++ = nbuf[j - 1]; + } + } + return total; +} + +int +mu_cidr_to_string (struct mu_cidr *cidr, int flags, + char *buf, size_t size, size_t *pret) +{ + size_t (*fmt) (const unsigned char *bytes, int len, char *buf, size_t size); + size_t n, total = 0; + + if (size == 0) + return MU_ERR_BUFSPACE; + size--; + switch (cidr->family) + { + case AF_INET: + fmt = format_ipv4_bytes; + break; + +#ifdef MAILUTILS_IPV6 + case AF_INET6: + fmt = format_ipv6_bytes; + break; +#endif + + default: + return MU_ERR_FAMILY; + } + + n = fmt (cidr->address, cidr->len, buf, size); + if (buf) + buf += n; + total += n; + + if (!(flags & MU_CIDR_FMT_ADDRONLY)) + { + if (total++ < size) + *buf++ = '/'; + n = fmt (cidr->netmask, cidr->len, buf, size - total); + if (buf) + buf += n; + total += n; + } + + if (buf) + *buf++ = 0; + if (pret) + *pret = total; + return 0; +} + +int +mu_cidr_format (struct mu_cidr *cidr, int flags, char **pbuf) +{ + char buf[MU_CIDR_MAXBUFSIZE]; + int rc = mu_cidr_to_string (cidr, flags, buf, sizeof (buf), NULL); + if (rc) + return rc; + *pbuf = strdup (buf); + if (!*buf) + return ENOMEM; + return 0; +} + diff --git a/libmailutils/diag/debug.c b/libmailutils/diag/debug.c index 124311bd8..aa10e41ba 100644 --- a/libmailutils/diag/debug.c +++ b/libmailutils/diag/debug.c @@ -689,6 +689,7 @@ mu_debug_log_begin (const char *fmt, ...) va_list ap; mu_diag_init (); + mu_stream_flush (mu_strerr); va_start (ap, fmt); mu_stream_printf (mu_strerr, "\033s<%d>", MU_LOG_DEBUG); mu_stream_vprintf (mu_strerr, fmt, ap); diff --git a/libmailutils/diag/errors b/libmailutils/diag/errors index 869e4146f..03f71b715 100644 --- a/libmailutils/diag/errors +++ b/libmailutils/diag/errors @@ -1,3 +1,4 @@ + # Error messages for GNU Mailutils # Copyright (C) 2005, 2006, 2007, 2010, 2011 Free Software Foundation, # Inc. @@ -98,3 +99,10 @@ MU_ERR_URL_MISS_PARTS _("URL missing required parts") MU_ERR_URL_EXTRA_PARTS _("URL has parts not allowed by its scheme") MU_ERR_INFO_UNAVAILABLE _("Information is not yet available") + +# The following are mapped to the corresponding EAI_ errors +MU_ERR_NONAME _("Name or service not known") +MU_ERR_BADFLAGS _("Bad value for flags") +MU_ERR_SOCKTYPE _("Socket type not supported") +MU_ERR_FAMILY _("Address family not supported") +MU_ERR_SERVICE _("Requested service not supported") diff --git a/libmailutils/server/acl.c b/libmailutils/server/acl.c index 0b7a507e0..ba1a4b86b 100644 --- a/libmailutils/server/acl.c +++ b/libmailutils/server/acl.c @@ -40,14 +40,20 @@ #include #include #include +#include +#include +#include +#include + +#ifndef MU_INADDR_BYTES +#define MU_INADDR_BYTES 16 +#endif struct _mu_acl_entry { mu_acl_action_t action; void *arg; - unsigned netmask; - int salen; - struct sockaddr sa[1]; + struct mu_cidr cidr; }; struct _mu_acl @@ -64,52 +70,19 @@ _destroy_acl_entry (void *item) /* FIXME: free arg? */ } -static size_t -mu_acl_entry_size (int salen) -{ - return sizeof (struct _mu_acl_entry) + salen - sizeof (struct sockaddr); -} - -static int -prepare_sa (struct sockaddr *sa) -{ - switch (sa->sa_family) - { - case AF_INET: - { - struct sockaddr_in *s_in = (struct sockaddr_in *)sa; - s_in->sin_addr.s_addr = ntohl (s_in->sin_addr.s_addr); - break; - } - - case AF_UNIX: - break; - - default: - return 1; - } - return 0; -} - int mu_acl_entry_create (struct _mu_acl_entry **pent, mu_acl_action_t action, void *data, - struct sockaddr *sa, int salen, unsigned long netmask) + struct mu_cidr *cidr) { - struct _mu_acl_entry *p = malloc (mu_acl_entry_size (salen)); + struct _mu_acl_entry *p = malloc (sizeof (*p)); if (!p) return EINVAL; p->action = action; p->arg = data; - p->netmask = ntohl (netmask); - p->salen = salen; - memcpy (p->sa, sa, salen); - if (prepare_sa (p->sa)) - { - free (p); - return EINVAL; - } + memcpy (&p->cidr, cidr, sizeof (p->cidr)); + *pent = p; return 0; } @@ -165,15 +138,14 @@ mu_acl_get_iterator (mu_acl_t acl, mu_iterator_t *pitr) int mu_acl_append (mu_acl_t acl, mu_acl_action_t act, - void *data, struct sockaddr *sa, int salen, - unsigned long netmask) + void *data, struct mu_cidr *cidr) { int rc; struct _mu_acl_entry *ent; if (!acl) return EINVAL; - rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask); + rc = mu_acl_entry_create (&ent, act, data, cidr); if (rc) { mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, @@ -193,14 +165,14 @@ mu_acl_append (mu_acl_t acl, mu_acl_action_t act, int mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data, - struct sockaddr *sa, int salen, unsigned long netmask) + struct mu_cidr *cidr) { int rc; struct _mu_acl_entry *ent; if (!acl) return EINVAL; - rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask); + rc = mu_acl_entry_create (&ent, act, data, cidr); if (rc) { mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, @@ -219,8 +191,7 @@ mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data, int mu_acl_insert (mu_acl_t acl, size_t pos, int before, - mu_acl_action_t act, void *data, - struct sockaddr *sa, int salen, unsigned long netmask) + mu_acl_action_t act, void *data, struct mu_cidr *cidr) { int rc; void *ptr; @@ -236,7 +207,7 @@ mu_acl_insert (mu_acl_t acl, size_t pos, int before, ("No such entry %lu", (unsigned long) pos)); return rc; } - rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask); + rc = mu_acl_entry_create (&ent, act, data, cidr); if (!ent) { mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, @@ -279,124 +250,19 @@ mu_acl_string_to_action (const char *str, mu_acl_action_t *pres) return rc; } -#define MU_S_UN_NAME(sa, salen) \ - ((salen < mu_offsetof (struct sockaddr_un,sun_path)) ? "" : (sa)->sun_path) - -static void -debug_sockaddr (struct sockaddr *sa, int salen) -{ - switch (sa->sa_family) - { - case AF_INET: - { - struct sockaddr_in s_in = *(struct sockaddr_in *)sa; - s_in.sin_addr.s_addr = htonl (s_in.sin_addr.s_addr); - mu_debug_log_cont ("{AF_INET %s:%d}", - inet_ntoa (s_in.sin_addr), ntohs (s_in.sin_port)); - break; - } - - case AF_UNIX: - { - struct sockaddr_un *s_un = (struct sockaddr_un *)sa; - if (MU_S_UN_NAME(s_un, salen)[0] == 0) - mu_debug_log_cont ("{AF_UNIX}"); - else - mu_debug_log_cont ("{AF_UNIX %s}", s_un->sun_path); - break; - } - - default: - mu_debug_log_cont ("{Unsupported family: %d}", sa->sa_family); - } -} - -size_t -mu_stpcpy (char **pbuf, size_t *psize, const char *src) -{ - size_t slen = strlen (src); - if (pbuf == NULL || *pbuf == NULL) - return slen; - else - { - char *buf = *pbuf; - size_t size = *psize; - if (size > slen) - size = slen; - memcpy (buf, src, size); - *psize -= size; - *pbuf += size; - if (*psize) - **pbuf = 0; - else - (*pbuf)[-1] = 0; - return size; - } -} - -void -mu_sockaddr_to_str (const struct sockaddr *sa, int salen, - char *bufptr, size_t buflen, - size_t *plen) +struct run_closure { - char *nbuf; - size_t len = 0; - switch (sa->sa_family) - { - case AF_INET: - { - struct sockaddr_in s_in = *(struct sockaddr_in *)sa; - len += mu_stpcpy (&bufptr, &buflen, inet_ntoa (s_in.sin_addr)); - len += mu_stpcpy (&bufptr, &buflen, ":"); - if (mu_asprintf (&nbuf, "%hu", ntohs (s_in.sin_port)) == 0) - { - len += mu_stpcpy (&bufptr, &buflen, nbuf); - free (nbuf); - } - break; - } - - case AF_UNIX: - { - struct sockaddr_un *s_un = (struct sockaddr_un *)sa; - if (MU_S_UN_NAME(s_un, salen)[0] == 0) - len += mu_stpcpy (&bufptr, &buflen, "anonymous socket"); - else - { - len += mu_stpcpy (&bufptr, &buflen, "socket "); - len += mu_stpcpy (&bufptr, &buflen, s_un->sun_path); - } - break; - } - - default: - len += mu_stpcpy (&bufptr, &buflen, "{Unsupported family"); - if (mu_asprintf (&nbuf, ": %d", sa->sa_family) == 0) - { - len += mu_stpcpy (&bufptr, &buflen, nbuf); - free (nbuf); - } - len += mu_stpcpy (&bufptr, &buflen, "}"); - } - if (plen) - *plen = len + 1; -} + unsigned idx; + struct mu_cidr addr; -char * -mu_sockaddr_to_astr (const struct sockaddr *sa, int salen) -{ - size_t size; - char *p; - - mu_sockaddr_to_str (sa, salen, NULL, 0, &size); - p = malloc (size); - if (p) - mu_sockaddr_to_str (sa, salen, p, size, NULL); - return p; -} + char ipstr[40]; + char *addrstr; + char *numbuf; + mu_acl_result_t *result; +}; int -_acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen) +_acl_match (struct _mu_acl_entry *ent, struct run_closure *rp) { #define RESMATCH(word) \ if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) \ @@ -404,76 +270,26 @@ _acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen) if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) { - struct in_addr a; - - mu_debug_log_begin ("Does "); - debug_sockaddr (sa, salen); - mu_debug_log_cont (" match "); - debug_sockaddr (ent->sa, salen); - a.s_addr = ent->netmask; - a.s_addr = htonl (a.s_addr); - mu_debug_log_cont (" netmask %s? ", inet_ntoa (a)); + char *s; + + if (ent->cidr.len == 0) + s = strdup ("any"); + mu_cidr_format (&ent->cidr, 0, &s); + if (!rp->addrstr) + mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr); + mu_debug_log_begin ("Does %s match %s? ", s, rp->addrstr); + free (s); } - if (ent->sa->sa_family != sa->sa_family) + if (ent->cidr.len > 0 && mu_cidr_match (&ent->cidr, &rp->addr)) { RESMATCH ("no"); return 1; } - - switch (ent->sa->sa_family) - { - case AF_INET: - { - struct sockaddr_in *sin_ent = (struct sockaddr_in *)ent->sa; - struct sockaddr_in *sin_item = (struct sockaddr_in *)sa; - - if (sin_ent->sin_addr.s_addr != - (sin_item->sin_addr.s_addr & ent->netmask)) - { - RESMATCH ("no (address differs)"); - return 1; - } - - if (sin_ent->sin_port && sin_item->sin_port - && sin_ent->sin_port != sin_item->sin_port) - { - RESMATCH ("no (port differs)"); - return 1; - } - break; - } - - case AF_UNIX: - { - struct sockaddr_un *sun_ent = (struct sockaddr_un *)ent->sa; - struct sockaddr_un *sun_item = (struct sockaddr_un *)sa; - - if (MU_S_UN_NAME (sun_ent, ent->salen)[0] - && MU_S_UN_NAME (sun_item, salen)[0] - && strcmp (sun_ent->sun_path, sun_item->sun_path)) - { - RESMATCH ("no"); - return 1; - } - break; - } - } - RESMATCH ("yes"); return 0; } -struct run_closure -{ - unsigned idx; - struct sockaddr *sa; - char *numbuf; - char *portbuf; - int salen; - mu_acl_result_t *result; -}; - #define SEQ(s, n, l) \ (((l) == (sizeof(s) - 1)) && memcmp (s, n, l) == 0) @@ -489,40 +305,24 @@ acl_getvar (const char *name, size_t nlen, void *data) return rp->numbuf; } - switch (rp->sa->sa_family) + if (SEQ ("address", name, nlen)) { - case AF_INET: - { - struct sockaddr_in *s_in = (struct sockaddr_in *)rp->sa; - - if (SEQ ("address", name, nlen)) - { - struct in_addr addr = s_in->sin_addr; - addr.s_addr = htonl (addr.s_addr); - return inet_ntoa (addr); - } + if (!rp->addrstr) + mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr); + return rp->addrstr; + } - if (SEQ ("port", name, nlen)) - { - if (!rp->portbuf && - mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port))) - return NULL; - return rp->portbuf; - } - break; - - case AF_UNIX: - if (SEQ ("address", name, nlen)) - { - struct sockaddr_un *s_un = (struct sockaddr_un *)rp->sa; - if (rp->salen == sizeof (s_un->sun_family)) - return NULL; - else - return s_un->sun_path; - } - } - break; +#if 0 + /* FIXME?: */ + if (SEQ ("port", name, nlen)) + { + if (!rp->portbuf && + mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port))) + return NULL; + return rp->portbuf; } +#endif + return NULL; } @@ -535,12 +335,18 @@ expand_arg (const char *cmdline, struct run_closure *rp, char **s) mu_debug (MU_DEBCAT_ACL, MU_DEBUG_TRACE, ("Expanding \"%s\"", cmdline)); env[0] = "family"; - switch (rp->sa->sa_family) + switch (rp->addr.family) { case AF_INET: env[1] = "AF_INET"; break; +#ifdef MAILUTILS_IPV6 + case AF_INET6: + env[1] = "AF_INET6"; + break; +#endif + case AF_UNIX: env[1] = "AF_UNIX"; break; @@ -654,7 +460,7 @@ _run_entry (void *item, void *data) mu_debug_log_begin ("%d:%s: ", rp->idx, s); } - if (_acl_match (ent, rp->sa, rp->salen) == 0) + if (_acl_match (ent, rp) == 0) { switch (ent->action) { @@ -678,8 +484,10 @@ _run_entry (void *item, void *data) } else { - debug_sockaddr (rp->sa, rp->salen); - mu_debug_log_nl (); + if (!rp->addrstr) + mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, + &rp->addrstr); + mu_diag_output (MU_DIAG_INFO, "%s", rp->addrstr); } } break; @@ -712,7 +520,7 @@ _run_entry (void *item, void *data) } if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) - mu_debug_log_nl (); + mu_stream_flush (mu_strerr); return status; } @@ -721,40 +529,39 @@ int mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen, mu_acl_result_t *pres) { + int rc; struct run_closure r; if (!acl) return EINVAL; - r.sa = malloc (salen); - if (!r.sa) - return ENOMEM; - memcpy (r.sa, sa, salen); - if (prepare_sa (r.sa)) + memset (&r, 0, sizeof (r)); + if (sa->sa_family == AF_UNIX) { - free (r.sa); - return EINVAL; + *pres = mu_acl_result_accept; + return 0; } - r.salen = salen; + rc = mu_cidr_from_sockaddr (&r.addr, sa); + if (rc) + return rc; if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) { - mu_debug_log_begin ("Checking sockaddr "); - debug_sockaddr (r.sa, r.salen); + mu_cidr_format (&r.addr, MU_CIDR_FMT_ADDRONLY, &r.addrstr); + mu_debug_log_begin ("Checking sockaddr %s", r.addrstr); mu_debug_log_nl (); } r.idx = 0; r.result = pres; *r.result = mu_acl_result_undefined; - r.numbuf = r.portbuf = NULL; + r.numbuf = NULL; mu_list_do (acl->aclist, _run_entry, &r); free (r.numbuf); - free (r.portbuf); - free (r.sa); + free (r.addrstr); return 0; } - + int mu_acl_check_inaddr (mu_acl_t acl, const struct in_addr *inp, mu_acl_result_t *pres) @@ -780,10 +587,17 @@ mu_acl_check_ipv4 (mu_acl_t acl, unsigned int addr, mu_acl_result_t *pres) int mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres) { - struct sockaddr_in cs; - socklen_t len = sizeof cs; + union + { + struct sockaddr sa; + struct sockaddr_in in; +#ifdef MAILUTILS_IPV6 + struct sockaddr_in6 in6; +#endif + } addr; + socklen_t len = sizeof addr; - if (getpeername (fd, (struct sockaddr *) &cs, &len) < 0) + if (getpeername (fd, &addr.sa, &len) < 0) { mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, ("Cannot obtain IP address of client: %s", @@ -791,6 +605,6 @@ mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres) return MU_ERR_FAILURE; } - return mu_acl_check_sockaddr (acl, (struct sockaddr *) &cs, len, pres); + return mu_acl_check_sockaddr (acl, &addr.sa, len, pres); } diff --git a/libmailutils/server/ipsrv.c b/libmailutils/server/ipsrv.c index a80290834..73b2e361e 100644 --- a/libmailutils/server/ipsrv.c +++ b/libmailutils/server/ipsrv.c @@ -34,13 +34,13 @@ #include #include #include +#include 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