diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-03-30 00:49:43 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2011-03-30 15:51:47 +0300 |
commit | adca074d616ac562095a92e01f2b181e6d3593c8 (patch) | |
tree | f4c11a1c11fcb137cfada7643e6f284465a75c16 /libmailutils/server | |
parent | 827cb66a4c639139c3f11c7af26aa5149f25a7e0 (diff) | |
download | mailutils-adca074d616ac562095a92e01f2b181e6d3593c8.tar.gz mailutils-adca074d616ac562095a92e01f2b181e6d3593c8.tar.bz2 |
Implement IPv6 support.
* am/ipv6.m4: New file.
* examples/sa.c: New file.
* include/mailutils/cidr.h: New file.
* include/mailutils/sockaddr.h: New file.
* libmailutils/cidr/Makefile.am: New file.
* libmailutils/cidr/fromsa.c: New file.
* libmailutils/cidr/fromstr.c: New file.
* libmailutils/cidr/match.c: New file.
* libmailutils/cidr/tosa.c: New file.
* libmailutils/cidr/tostr.c: New file.
* libmailutils/sockaddr/Makefile.am: New file.
* libmailutils/sockaddr/copy.c: New file.
* libmailutils/sockaddr/create.c: New file.
* libmailutils/sockaddr/free.c: New file.
* libmailutils/sockaddr/fromnode.c: New file.
* libmailutils/sockaddr/insert.c: New file.
* libmailutils/sockaddr/ipaddr.c: New file.
* libmailutils/sockaddr/str.c: New file.
* libmailutils/sockaddr/unlink.c: New file.
* libmailutils/sockaddr/url.c: New file.
* libmailutils/tests/cidr.c: New file.
* configure.ac: Call MU_ENABLE_IPV6.
Build libmailutils/sockaddr and libmailutils/cidr.
* examples/.gitignore: Add mblconv and sa
* examples/Makefile.am: (noinst_PROGRAMS): Add sa.
* examples/aclck.c: Use new ACL API.
* examples/echosrv.c: Use new mserv API.
* include/mailutils/Makefile.am (pkginclude_HEADERS): Add cidr.h
and sockaddr.h
* include/mailutils/acl.h (mu_acl_append, mu_acl_prepend)
(mu_acl_insert): Change signatures.
* include/mailutils/debug.h (mu_sockaddr_to_str): Remove proto.
* include/mailutils/mailutils.h: Include cidr.h and sockaddr.h
* include/mailutils/server.h (mu_ip_server_create): Change signature.
(mu_ip_server_get_sockaddr): Likewise.
(mu_m_server_set_default_address)
(mu_m_server_get_default_address): Remove.
* include/mailutils/stream.h (mu_tcp_stream_create_from_sa): New proto.
* include/mailutils/types.hin (mu_cidr, mu_sockaddr): New structs.
* include/mailutils/url.h (MU_URL_IPV6): New flag.
(MU_URL_PARSE_DSLASH_OPTIONAL): New parse flag.
* libmailutils/Makefile.am: Descend into cidr and sockaddr. Link in
libcidr and libsockaddr.
* libmailutils/diag/debug.c (mu_debug_log_begin): Flush mu_strerr.
* libmailutils/diag/errors (MU_ERR_NONAME)
(MU_ERR_BADFLAGS,MU_ERR_SOCKTYPE)
(MU_ERR_FAMILY,MU_ERR_SERVICE): New errors.
* libmailutils/server/acl.c: Rewrite API using mu_cidr.
* libmailutils/server/ipsrv.c: Rewrite AI using mu_sockaddr.
* libmailutils/server/msrv.c: Likewise.
* libmailutils/stream/tcp.c: Likewise.
* libmailutils/tests/.gitignore: Add cidr.
* libmailutils/tests/Makefile.am (noinst_PROGRAMS): Add cidr.
* libmailutils/tests/url-parse.c: Support command line options
to tune the parsing.
* libmailutils/tests/url.at: Pass options to url-parse.
* libmailutils/url/create.c (getkn): Return meaningful error code.
(_mu_url_ctx_parse_host): Accept IPv6 addresses. Set the MU_URL_IPV6
flag if one is given.
(_mu_url_ctx_parse): Unless MU_URL_PARSE_DSLASH_OPTIONAL flag is
given, request :// after scheme part.
(mu_url_create): Add MU_URL_PARSE_DSLASH_OPTIONAL flag.
* libmu_cfg/acl.c: Use new ACL API.
* mu/acl.c: Likewise.
* libproto/mailer/smtp.c (smtp_open): Use mu_tcp_stream_create_from_sa
* libproto/pop/mbox.c (pop_open): Likewise.
* mu/imap.c (com_connect): Likewise.
* mu/pop.c (com_connect): Likewise.
* testsuite/smtpsend.c (main): Likewise.
Diffstat (limited to 'libmailutils/server')
-rw-r--r-- | libmailutils/server/acl.c | 366 | ||||
-rw-r--r-- | libmailutils/server/ipsrv.c | 83 | ||||
-rw-r--r-- | libmailutils/server/msrv.c | 348 |
3 files changed, 228 insertions, 569 deletions
diff --git a/libmailutils/server/acl.c b/libmailutils/server/acl.c index 0b7a507e0..ba1a4b86b 100644 --- a/libmailutils/server/acl.c +++ b/libmailutils/server/acl.c @@ -40,14 +40,20 @@ #include <mailutils/kwd.h> #include <mailutils/io.h> #include <mailutils/util.h> +#include <mailutils/sockaddr.h> +#include <mailutils/cidr.h> +#include <mailutils/stream.h> +#include <mailutils/stdstream.h> + +#ifndef MU_INADDR_BYTES +#define MU_INADDR_BYTES 16 +#endif struct _mu_acl_entry { mu_acl_action_t action; void *arg; - unsigned netmask; - int salen; - struct sockaddr sa[1]; + struct mu_cidr cidr; }; struct _mu_acl @@ -64,52 +70,19 @@ _destroy_acl_entry (void *item) /* FIXME: free arg? */ } -static size_t -mu_acl_entry_size (int salen) -{ - return sizeof (struct _mu_acl_entry) + salen - sizeof (struct sockaddr); -} - -static int -prepare_sa (struct sockaddr *sa) -{ - switch (sa->sa_family) - { - case AF_INET: - { - struct sockaddr_in *s_in = (struct sockaddr_in *)sa; - s_in->sin_addr.s_addr = ntohl (s_in->sin_addr.s_addr); - break; - } - - case AF_UNIX: - break; - - default: - return 1; - } - return 0; -} - int mu_acl_entry_create (struct _mu_acl_entry **pent, mu_acl_action_t action, void *data, - struct sockaddr *sa, int salen, unsigned long netmask) + struct mu_cidr *cidr) { - struct _mu_acl_entry *p = malloc (mu_acl_entry_size (salen)); + struct _mu_acl_entry *p = malloc (sizeof (*p)); if (!p) return EINVAL; p->action = action; p->arg = data; - p->netmask = ntohl (netmask); - p->salen = salen; - memcpy (p->sa, sa, salen); - if (prepare_sa (p->sa)) - { - free (p); - return EINVAL; - } + memcpy (&p->cidr, cidr, sizeof (p->cidr)); + *pent = p; return 0; } @@ -165,15 +138,14 @@ mu_acl_get_iterator (mu_acl_t acl, mu_iterator_t *pitr) int mu_acl_append (mu_acl_t acl, mu_acl_action_t act, - void *data, struct sockaddr *sa, int salen, - unsigned long netmask) + void *data, struct mu_cidr *cidr) { int rc; struct _mu_acl_entry *ent; if (!acl) return EINVAL; - rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask); + rc = mu_acl_entry_create (&ent, act, data, cidr); if (rc) { mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, @@ -193,14 +165,14 @@ mu_acl_append (mu_acl_t acl, mu_acl_action_t act, int mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data, - struct sockaddr *sa, int salen, unsigned long netmask) + struct mu_cidr *cidr) { int rc; struct _mu_acl_entry *ent; if (!acl) return EINVAL; - rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask); + rc = mu_acl_entry_create (&ent, act, data, cidr); if (rc) { mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, @@ -219,8 +191,7 @@ mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data, int mu_acl_insert (mu_acl_t acl, size_t pos, int before, - mu_acl_action_t act, void *data, - struct sockaddr *sa, int salen, unsigned long netmask) + mu_acl_action_t act, void *data, struct mu_cidr *cidr) { int rc; void *ptr; @@ -236,7 +207,7 @@ mu_acl_insert (mu_acl_t acl, size_t pos, int before, ("No such entry %lu", (unsigned long) pos)); return rc; } - rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask); + rc = mu_acl_entry_create (&ent, act, data, cidr); if (!ent) { mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, @@ -279,124 +250,19 @@ mu_acl_string_to_action (const char *str, mu_acl_action_t *pres) return rc; } -#define MU_S_UN_NAME(sa, salen) \ - ((salen < mu_offsetof (struct sockaddr_un,sun_path)) ? "" : (sa)->sun_path) - -static void -debug_sockaddr (struct sockaddr *sa, int salen) -{ - switch (sa->sa_family) - { - case AF_INET: - { - struct sockaddr_in s_in = *(struct sockaddr_in *)sa; - s_in.sin_addr.s_addr = htonl (s_in.sin_addr.s_addr); - mu_debug_log_cont ("{AF_INET %s:%d}", - inet_ntoa (s_in.sin_addr), ntohs (s_in.sin_port)); - break; - } - - case AF_UNIX: - { - struct sockaddr_un *s_un = (struct sockaddr_un *)sa; - if (MU_S_UN_NAME(s_un, salen)[0] == 0) - mu_debug_log_cont ("{AF_UNIX}"); - else - mu_debug_log_cont ("{AF_UNIX %s}", s_un->sun_path); - break; - } - - default: - mu_debug_log_cont ("{Unsupported family: %d}", sa->sa_family); - } -} - -size_t -mu_stpcpy (char **pbuf, size_t *psize, const char *src) -{ - size_t slen = strlen (src); - if (pbuf == NULL || *pbuf == NULL) - return slen; - else - { - char *buf = *pbuf; - size_t size = *psize; - if (size > slen) - size = slen; - memcpy (buf, src, size); - *psize -= size; - *pbuf += size; - if (*psize) - **pbuf = 0; - else - (*pbuf)[-1] = 0; - return size; - } -} - -void -mu_sockaddr_to_str (const struct sockaddr *sa, int salen, - char *bufptr, size_t buflen, - size_t *plen) +struct run_closure { - char *nbuf; - size_t len = 0; - switch (sa->sa_family) - { - case AF_INET: - { - struct sockaddr_in s_in = *(struct sockaddr_in *)sa; - len += mu_stpcpy (&bufptr, &buflen, inet_ntoa (s_in.sin_addr)); - len += mu_stpcpy (&bufptr, &buflen, ":"); - if (mu_asprintf (&nbuf, "%hu", ntohs (s_in.sin_port)) == 0) - { - len += mu_stpcpy (&bufptr, &buflen, nbuf); - free (nbuf); - } - break; - } - - case AF_UNIX: - { - struct sockaddr_un *s_un = (struct sockaddr_un *)sa; - if (MU_S_UN_NAME(s_un, salen)[0] == 0) - len += mu_stpcpy (&bufptr, &buflen, "anonymous socket"); - else - { - len += mu_stpcpy (&bufptr, &buflen, "socket "); - len += mu_stpcpy (&bufptr, &buflen, s_un->sun_path); - } - break; - } - - default: - len += mu_stpcpy (&bufptr, &buflen, "{Unsupported family"); - if (mu_asprintf (&nbuf, ": %d", sa->sa_family) == 0) - { - len += mu_stpcpy (&bufptr, &buflen, nbuf); - free (nbuf); - } - len += mu_stpcpy (&bufptr, &buflen, "}"); - } - if (plen) - *plen = len + 1; -} + unsigned idx; + struct mu_cidr addr; -char * -mu_sockaddr_to_astr (const struct sockaddr *sa, int salen) -{ - size_t size; - char *p; - - mu_sockaddr_to_str (sa, salen, NULL, 0, &size); - p = malloc (size); - if (p) - mu_sockaddr_to_str (sa, salen, p, size, NULL); - return p; -} + char ipstr[40]; + char *addrstr; + char *numbuf; + mu_acl_result_t *result; +}; int -_acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen) +_acl_match (struct _mu_acl_entry *ent, struct run_closure *rp) { #define RESMATCH(word) \ if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) \ @@ -404,76 +270,26 @@ _acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen) if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) { - struct in_addr a; - - mu_debug_log_begin ("Does "); - debug_sockaddr (sa, salen); - mu_debug_log_cont (" match "); - debug_sockaddr (ent->sa, salen); - a.s_addr = ent->netmask; - a.s_addr = htonl (a.s_addr); - mu_debug_log_cont (" netmask %s? ", inet_ntoa (a)); + char *s; + + if (ent->cidr.len == 0) + s = strdup ("any"); + mu_cidr_format (&ent->cidr, 0, &s); + if (!rp->addrstr) + mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr); + mu_debug_log_begin ("Does %s match %s? ", s, rp->addrstr); + free (s); } - if (ent->sa->sa_family != sa->sa_family) + if (ent->cidr.len > 0 && mu_cidr_match (&ent->cidr, &rp->addr)) { RESMATCH ("no"); return 1; } - - switch (ent->sa->sa_family) - { - case AF_INET: - { - struct sockaddr_in *sin_ent = (struct sockaddr_in *)ent->sa; - struct sockaddr_in *sin_item = (struct sockaddr_in *)sa; - - if (sin_ent->sin_addr.s_addr != - (sin_item->sin_addr.s_addr & ent->netmask)) - { - RESMATCH ("no (address differs)"); - return 1; - } - - if (sin_ent->sin_port && sin_item->sin_port - && sin_ent->sin_port != sin_item->sin_port) - { - RESMATCH ("no (port differs)"); - return 1; - } - break; - } - - case AF_UNIX: - { - struct sockaddr_un *sun_ent = (struct sockaddr_un *)ent->sa; - struct sockaddr_un *sun_item = (struct sockaddr_un *)sa; - - if (MU_S_UN_NAME (sun_ent, ent->salen)[0] - && MU_S_UN_NAME (sun_item, salen)[0] - && strcmp (sun_ent->sun_path, sun_item->sun_path)) - { - RESMATCH ("no"); - return 1; - } - break; - } - } - RESMATCH ("yes"); return 0; } -struct run_closure -{ - unsigned idx; - struct sockaddr *sa; - char *numbuf; - char *portbuf; - int salen; - mu_acl_result_t *result; -}; - #define SEQ(s, n, l) \ (((l) == (sizeof(s) - 1)) && memcmp (s, n, l) == 0) @@ -489,40 +305,24 @@ acl_getvar (const char *name, size_t nlen, void *data) return rp->numbuf; } - switch (rp->sa->sa_family) + if (SEQ ("address", name, nlen)) { - case AF_INET: - { - struct sockaddr_in *s_in = (struct sockaddr_in *)rp->sa; - - if (SEQ ("address", name, nlen)) - { - struct in_addr addr = s_in->sin_addr; - addr.s_addr = htonl (addr.s_addr); - return inet_ntoa (addr); - } + if (!rp->addrstr) + mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr); + return rp->addrstr; + } - if (SEQ ("port", name, nlen)) - { - if (!rp->portbuf && - mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port))) - return NULL; - return rp->portbuf; - } - break; - - case AF_UNIX: - if (SEQ ("address", name, nlen)) - { - struct sockaddr_un *s_un = (struct sockaddr_un *)rp->sa; - if (rp->salen == sizeof (s_un->sun_family)) - return NULL; - else - return s_un->sun_path; - } - } - break; +#if 0 + /* FIXME?: */ + if (SEQ ("port", name, nlen)) + { + if (!rp->portbuf && + mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port))) + return NULL; + return rp->portbuf; } +#endif + return NULL; } @@ -535,12 +335,18 @@ expand_arg (const char *cmdline, struct run_closure *rp, char **s) mu_debug (MU_DEBCAT_ACL, MU_DEBUG_TRACE, ("Expanding \"%s\"", cmdline)); env[0] = "family"; - switch (rp->sa->sa_family) + switch (rp->addr.family) { case AF_INET: env[1] = "AF_INET"; break; +#ifdef MAILUTILS_IPV6 + case AF_INET6: + env[1] = "AF_INET6"; + break; +#endif + case AF_UNIX: env[1] = "AF_UNIX"; break; @@ -654,7 +460,7 @@ _run_entry (void *item, void *data) mu_debug_log_begin ("%d:%s: ", rp->idx, s); } - if (_acl_match (ent, rp->sa, rp->salen) == 0) + if (_acl_match (ent, rp) == 0) { switch (ent->action) { @@ -678,8 +484,10 @@ _run_entry (void *item, void *data) } else { - debug_sockaddr (rp->sa, rp->salen); - mu_debug_log_nl (); + if (!rp->addrstr) + mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, + &rp->addrstr); + mu_diag_output (MU_DIAG_INFO, "%s", rp->addrstr); } } break; @@ -712,7 +520,7 @@ _run_entry (void *item, void *data) } if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) - mu_debug_log_nl (); + mu_stream_flush (mu_strerr); return status; } @@ -721,40 +529,39 @@ int mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen, mu_acl_result_t *pres) { + int rc; struct run_closure r; if (!acl) return EINVAL; - r.sa = malloc (salen); - if (!r.sa) - return ENOMEM; - memcpy (r.sa, sa, salen); - if (prepare_sa (r.sa)) + memset (&r, 0, sizeof (r)); + if (sa->sa_family == AF_UNIX) { - free (r.sa); - return EINVAL; + *pres = mu_acl_result_accept; + return 0; } - r.salen = salen; + rc = mu_cidr_from_sockaddr (&r.addr, sa); + if (rc) + return rc; if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) { - mu_debug_log_begin ("Checking sockaddr "); - debug_sockaddr (r.sa, r.salen); + mu_cidr_format (&r.addr, MU_CIDR_FMT_ADDRONLY, &r.addrstr); + mu_debug_log_begin ("Checking sockaddr %s", r.addrstr); mu_debug_log_nl (); } r.idx = 0; r.result = pres; *r.result = mu_acl_result_undefined; - r.numbuf = r.portbuf = NULL; + r.numbuf = NULL; mu_list_do (acl->aclist, _run_entry, &r); free (r.numbuf); - free (r.portbuf); - free (r.sa); + free (r.addrstr); return 0; } - + int mu_acl_check_inaddr (mu_acl_t acl, const struct in_addr *inp, mu_acl_result_t *pres) @@ -780,10 +587,17 @@ mu_acl_check_ipv4 (mu_acl_t acl, unsigned int addr, mu_acl_result_t *pres) int mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres) { - struct sockaddr_in cs; - socklen_t len = sizeof cs; + union + { + struct sockaddr sa; + struct sockaddr_in in; +#ifdef MAILUTILS_IPV6 + struct sockaddr_in6 in6; +#endif + } addr; + socklen_t len = sizeof addr; - if (getpeername (fd, (struct sockaddr *) &cs, &len) < 0) + if (getpeername (fd, &addr.sa, &len) < 0) { mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, ("Cannot obtain IP address of client: %s", @@ -791,6 +605,6 @@ mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres) return MU_ERR_FAILURE; } - return mu_acl_check_sockaddr (acl, (struct sockaddr *) &cs, len, pres); + return mu_acl_check_sockaddr (acl, &addr.sa, len, pres); } diff --git a/libmailutils/server/ipsrv.c b/libmailutils/server/ipsrv.c index a80290834..73b2e361e 100644 --- a/libmailutils/server/ipsrv.c +++ b/libmailutils/server/ipsrv.c @@ -34,13 +34,13 @@ #include <mailutils/diag.h> #include <mailutils/errno.h> #include <mailutils/nls.h> +#include <mailutils/sockaddr.h> struct _mu_ip_server { char *ident; - struct sockaddr *addr; - int addrlen; + struct mu_sockaddr *addr; int fd; int type; mu_acl_t acl; @@ -66,8 +66,7 @@ struct _mu_ip_server #define IDENTSTR(s) ((s)->ident ? (s)->ident : "default") int -mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr, - int addrlen, int type) +mu_ip_server_create (mu_ip_server_t *psrv, struct mu_sockaddr *addr, int type) { struct _mu_ip_server *srv; @@ -84,14 +83,7 @@ mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr, srv = calloc (1, sizeof *srv); if (!srv) return ENOMEM; - srv->addr = calloc (1, addrlen); - if (!srv->addr) - { - free (srv); - return ENOMEM; - } - memcpy (srv->addr, addr, addrlen); - srv->addrlen = addrlen; + srv->addr = addr; srv->type = type; srv->fd = -1; switch (type) @@ -120,7 +112,7 @@ mu_ip_server_destroy (mu_ip_server_t *psrv) if (srv->f_free) srv->f_free (srv->data); close (srv->fd); - free (srv->addr); + mu_sockaddr_free (srv->addr); free (srv->ident); if (srv->type == MU_IP_UDP && srv->v.udp_data.buf) free (srv->v.udp_data.buf); @@ -234,6 +226,11 @@ mu_address_family_to_domain (int family) case AF_INET: return PF_INET; +#ifdef MAILUTILS_IPV6 + case AF_INET6: + return PF_INET6; +#endif + default: abort (); } @@ -247,14 +244,11 @@ mu_ip_server_open (mu_ip_server_t srv) if (!srv || srv->fd != -1) return EINVAL; - if (mu_debug_level_p (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0)) - { - char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen); - mu_debug_log ("opening server \"%s\" %s", IDENTSTR (srv), p); - free (p); - } + mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0, + ("opening server \"%s\" %s", IDENTSTR (srv), + mu_sockaddr_str (srv->addr))); - fd = socket (mu_address_family_to_domain (srv->addr->sa_family), + fd = socket (mu_address_family_to_domain (srv->addr->addr->sa_family), ((srv->type == MU_IP_UDP) ? SOCK_DGRAM : SOCK_STREAM), 0); if (fd == -1) { @@ -263,7 +257,7 @@ mu_ip_server_open (mu_ip_server_t srv) return errno; } - switch (srv->addr->sa_family) + switch (srv->addr->addr->sa_family) { case AF_UNIX: { @@ -299,7 +293,7 @@ mu_ip_server_open (mu_ip_server_t srv) } break; - case AF_INET: + default: { int t; @@ -308,7 +302,7 @@ mu_ip_server_open (mu_ip_server_t srv) } } - if (bind (fd, srv->addr, srv->addrlen) == -1) + if (bind (fd, srv->addr->addr, srv->addr->addrlen) == -1) { mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR, ("%s: bind: %s", IDENTSTR (srv), mu_strerror (errno))); @@ -336,12 +330,9 @@ mu_ip_server_shutdown (mu_ip_server_t srv) { if (!srv || srv->fd != -1) return EINVAL; - if (mu_debug_level_p (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0)) - { - char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen); - mu_debug_log ("closing server \"%s\" %s", IDENTSTR (srv), p); - free (p); - } + mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0, + ("closing server \"%s\" %s", IDENTSTR (srv), + mu_sockaddr_str (srv->addr))); close (srv->fd); return 0; } @@ -356,6 +347,9 @@ mu_ip_tcp_accept (mu_ip_server_t srv, void *call_data) struct sockaddr sa; struct sockaddr_in s_in; struct sockaddr_un s_un; +#ifdef MAILUTILS_IPV6 + struct sockaddr_in6 s_in6; +#endif } client; socklen_t size = sizeof (client); @@ -407,6 +401,9 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data) struct sockaddr sa; struct sockaddr_in s_in; struct sockaddr_un s_un; +#ifdef MAILUTILS_IPV6 + struct sockaddr_in6 s_in6; +#endif } client; fd_set rdset; @@ -463,7 +460,7 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data) IDENTSTR (srv), strerror (rc))); if (res == mu_acl_result_deny) { - char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen); + char *p = mu_sockaddr_to_astr (&client.sa, salen); mu_diag_output (MU_DIAG_INFO, "Denying connection from %s", p); free (p); return 0; @@ -528,22 +525,16 @@ mu_udp_server_get_rdata (mu_ip_server_t srv, char **pbuf, size_t *pbufsize) } int -mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct sockaddr *s, int *size) +mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct mu_sockaddr **psa) { - int len; - - if (!srv || !s) + if (!srv || !psa) return EINVAL; - if (s == 0) - len = srv->addrlen; - else - { - len = srv->addrlen; - if (*size < len) - return MU_ERR_BUFSPACE; - memcpy (s, srv->addr, len); - } - *size = len; - return 0; + return mu_sockaddr_copy (psa, srv->addr); } - + +const char * +mu_ip_server_addrstr (mu_ip_server_t srv) +{ + return mu_sockaddr_str (srv->addr); +} + diff --git a/libmailutils/server/msrv.c b/libmailutils/server/msrv.c index 5c46e9d70..d5ceb8a39 100644 --- a/libmailutils/server/msrv.c +++ b/libmailutils/server/msrv.c @@ -41,6 +41,8 @@ #include <mailutils/nls.h> #include <mailutils/daemon.h> #include <mailutils/acl.h> +#include <mailutils/sockaddr.h> +#include <mailutils/url.h> typedef RETSIGTYPE (*mu_sig_handler_t) (int); @@ -65,19 +67,6 @@ set_signal (int sig, mu_sig_handler_t handler) # define NSIG 64 #endif -union m_sockaddr -{ - struct sockaddr s_sa; - struct sockaddr_in s_in; - struct sockaddr_un s_un; -}; - -struct m_default_address -{ - union m_sockaddr s; - int len; -}; - struct _mu_m_server { char *ident; /* Server identifier, for logging purposes.*/ @@ -98,7 +87,7 @@ struct _mu_m_server size_t num_children; /* Current number of running sub-processes. */ pid_t *child_pid; char *pidfile; /* Name of a PID-file. */ - struct m_default_address defaddr; /* Default address. */ + struct mu_sockaddr_hints hints; /* Default address hints. */ time_t timeout; /* Default idle timeout. */ mu_acl_t acl; /* Global access control list. */ @@ -112,7 +101,7 @@ struct _mu_m_server struct m_srv_config /* Configuration data for a single TCP server. */ { mu_m_server_t msrv; /* Parent m-server. */ - mu_ip_server_t tcpsrv; /* TCP server these data are for. */ + mu_ip_server_t tcpsrv; /* TCP server these data are for. */ mu_acl_t acl; /* Access control list for this server. */ int single_process; /* Should it run as a single process? */ int transcript; /* Enable session transcript. */ @@ -395,33 +384,20 @@ mu_m_server_pidfile (mu_m_server_t srv) } void -mu_m_server_set_default_address (mu_m_server_t srv, struct sockaddr *sa, - int salen) +mu_m_server_set_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints) { - if (salen > sizeof srv->defaddr.s) - { - mu_error (_("unhandled sockaddr size")); - abort (); - } - memcpy (&srv->defaddr.s.s_sa, sa, salen); - srv->defaddr.len = salen; + if (!hints) + memset (&srv->hints, 0, sizeof (srv->hints)); + else + memcpy (&srv->hints, hints, sizeof (srv->hints)); } int -mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa, - int *salen) +mu_m_server_get_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints) { - int len; - - if (!sa) + if (!hints) return EINVAL; - len = srv->defaddr.len; - if (sa) - { - if (*salen < len) - return MU_ERR_BUFSPACE; - memcpy (sa, &srv->defaddr.s.s_sa, len); - } + memcpy (hints, &srv->hints, sizeof (hints)); return 0; } @@ -429,11 +405,7 @@ mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa, void mu_m_server_set_default_port (mu_m_server_t srv, int num) { - struct sockaddr_in s_in; - s_in.sin_family = AF_INET; - s_in.sin_addr.s_addr = htonl (INADDR_ANY); - s_in.sin_port = htons (num); - mu_m_server_set_default_address (srv, (struct sockaddr*) &s_in, sizeof s_in); + srv->hints.port = num; } void @@ -473,12 +445,12 @@ static int m_srv_conn (int fd, struct sockaddr *sa, int salen, mu_ip_server_t srv); static struct m_srv_config * -add_server (mu_m_server_t msrv, struct sockaddr *s, int slen, int type) +add_server (mu_m_server_t msrv, struct mu_sockaddr *s, int type) { mu_ip_server_t tcpsrv; struct m_srv_config *pconf; - MU_ASSERT (mu_ip_server_create (&tcpsrv, s, slen, type)); /* FIXME: type */ + MU_ASSERT (mu_ip_server_create (&tcpsrv, s, type)); /* FIXME: type */ MU_ASSERT (mu_ip_server_set_conn (tcpsrv, m_srv_conn)); pconf = calloc (1, sizeof (*pconf)); if (!pconf) @@ -513,8 +485,21 @@ mu_m_server_begin (mu_m_server_t msrv) alloc_children (msrv); mu_list_count (msrv->srvlist, &count); - if (count == 0 && msrv->defaddr.len) - add_server (msrv, &msrv->defaddr.s.s_sa, msrv->defaddr.len, msrv->deftype); + if (count == 0) + { + struct mu_sockaddr *ta; + + msrv->hints.flags = MU_AH_PASSIVE; + rc = mu_sockaddr_from_node (&ta, NULL, NULL, &msrv->hints); + if (rc == 0) + while (ta) + { + struct mu_sockaddr *next = ta->next; + ta->next = ta->prev = NULL; + add_server (msrv, ta, msrv->deftype); + ta = next; + } + } if (!msrv->foreground) { @@ -599,23 +584,13 @@ tcp_conn_free (void *conn_data, void *server_data) static int _open_conn (void *item, void *data) { - union - { - struct sockaddr sa; - char pad[512]; - } - addr; - int addrlen = sizeof addr; - char *p; mu_ip_server_t tcpsrv = item; mu_m_server_t msrv = data; int rc = mu_ip_server_open (tcpsrv); if (rc) { - mu_ip_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen); - p = mu_sockaddr_to_astr (&addr.sa, addrlen); - mu_error (_("cannot open connection on %s: %s"), p, mu_strerror (rc)); - free (p); + mu_error (_("cannot open connection on %s: %s"), + mu_ip_server_addrstr (tcpsrv), mu_strerror (rc)); return 0; } rc = mu_server_add_connection (msrv->server, @@ -624,10 +599,8 @@ _open_conn (void *item, void *data) tcp_conn_handler, tcp_conn_free); if (rc) { - mu_ip_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen); - p = mu_sockaddr_to_astr (&addr.sa, addrlen); - mu_error (_("cannot add connection %s: %s"), p, mu_strerror (rc)); - free (p); + mu_error (_("cannot add connection %s: %s"), + mu_ip_server_addrstr (tcpsrv), mu_strerror (rc)); mu_ip_server_shutdown (tcpsrv); mu_ip_server_destroy (&tcpsrv); } @@ -756,199 +729,55 @@ m_srv_conn (int fd, struct sockaddr *sa, int salen, } - -unsigned short -get_port (const char *p) -{ - if (p) - { - char *q; - unsigned long n = strtoul (p, &q, 0); - if (*q == 0) - { - if (n > USHRT_MAX) - { - mu_error (_("invalid port number: %s"), p); - return 1; - } - - return htons (n); - } - else - { - struct servent *sp = getservbyname (p, "tcp"); - if (!sp) - return 0; - return sp->s_port; - } - } - return 0; -} - -static int -get_family (const char **pstr, sa_family_t *pfamily) -{ - static struct family_tab - { - int len; - char *pfx; - int family; - } ftab[] = { -#define S(s,f) { sizeof (#s":") - 1, #s":", f } - S (file, AF_UNIX), - S (unix, AF_UNIX), - S (local, AF_UNIX), - S (socket, AF_UNIX), - S (inet, AF_INET), - S (tcp, AF_INET), -#undef S - { 0 } - }; - struct family_tab *fp; - - const char *str = *pstr; - int len = strlen (str); - for (fp = ftab; fp->len; fp++) - { - if (len > fp->len && memcmp (str, fp->pfx, fp->len) == 0) - { - str += fp->len; - if (str[0] == '/' && str[1] == '/') - str += 2; - *pstr = str; - *pfamily = fp->family; - return 0; - } - } - return 1; -} - -static int -is_ip_addr (const char *arg) -{ - int dot_count; - int digit_count; - - dot_count = 0; - digit_count = 0; - for (; *arg != 0 && *arg != ':'; arg++) - { - if (*arg == '.') - { - if (++dot_count > 3) - break; - digit_count = 0; - } - else if (!(mu_isdigit (*arg) && ++digit_count <= 3)) - return 0; - } - return dot_count == 3; -} - int -_mu_m_server_parse_url (const char *arg, union m_sockaddr *s, - int *psalen, struct sockaddr *defsa) +mu_m_server_parse_url (mu_m_server_t msrv, const char *arg, + struct mu_sockaddr **psa) { - char *p; - unsigned short n; - int len; - - if (is_ip_addr (arg)) - s->s_sa.sa_family = AF_INET; - else if (get_family (&arg, &s->s_sa.sa_family)) + int rc; + mu_url_t url, url_hint; + + if (arg[0] == '/') + url_hint = NULL; + else { - mu_error (_("invalid family")); - return EINVAL; + rc = mu_url_create (&url_hint, "inet://"); + if (rc) + return rc; } - - switch (s->s_sa.sa_family) + rc = mu_url_create_hint (&url, arg, MU_URL_PARSE_DEFAULT, url_hint); + mu_url_destroy (&url_hint); + if (rc) { - case AF_INET: - *psalen = sizeof (s->s_in); - if ((n = get_port (arg))) - { - s->s_in.sin_addr.s_addr = htonl (INADDR_ANY); - s->s_in.sin_port = htons (n); - } - else - { - p = strchr (arg, ':'); - if (p) - *p++ = 0; - if (inet_aton (arg, &s->s_in.sin_addr) == 0) - { - struct hostent *hp = gethostbyname (arg); - if (hp) - s->s_in.sin_addr.s_addr = *(unsigned long *)hp->h_addr; - else - { - mu_error (_("invalid IP address: %s"), arg); - return EINVAL; - } - } - if (p) - { - n = get_port (p); - if (!n) - { - mu_error (_("invalid port number: %s"), p); - return EINVAL; - } - s->s_in.sin_port = n; - } - else if (defsa && defsa->sa_family == AF_INET) - s->s_in.sin_port = ((struct sockaddr_in*)defsa)->sin_port; - else - { - mu_error (_("missing port number")); - return EINVAL; - } - } - break; - - case AF_UNIX: - *psalen = sizeof (s->s_un); - len = strlen (arg); - if (len > sizeof s->s_un.sun_path - 1) - { - mu_error (_("%s: file name too long"), arg); - return EINVAL; - } - strcpy (s->s_un.sun_path, arg); - break; + mu_error (_("cannot parse URL `%s': %s"), arg, mu_strerror (rc)); + return rc; } - return 0; -} - -int |