summaryrefslogtreecommitdiff
path: root/libmailutils
diff options
context:
space:
mode:
Diffstat (limited to 'libmailutils')
-rw-r--r--libmailutils/Makefile.am4
-rw-r--r--libmailutils/cidr/Makefile.am27
-rw-r--r--libmailutils/cidr/fromsa.c101
-rw-r--r--libmailutils/cidr/fromstr.c128
-rw-r--r--libmailutils/cidr/match.c38
-rw-r--r--libmailutils/cidr/tosa.c78
-rw-r--r--libmailutils/cidr/tostr.c159
-rw-r--r--libmailutils/diag/debug.c1
-rw-r--r--libmailutils/diag/errors8
-rw-r--r--libmailutils/server/acl.c366
-rw-r--r--libmailutils/server/ipsrv.c83
-rw-r--r--libmailutils/server/msrv.c348
-rw-r--r--libmailutils/sockaddr/Makefile.am31
-rw-r--r--libmailutils/sockaddr/copy.c36
-rw-r--r--libmailutils/sockaddr/create.c47
-rw-r--r--libmailutils/sockaddr/free.c50
-rw-r--r--libmailutils/sockaddr/fromnode.c253
-rw-r--r--libmailutils/sockaddr/insert.c64
-rw-r--r--libmailutils/sockaddr/ipaddr.c88
-rw-r--r--libmailutils/sockaddr/str.c109
-rw-r--r--libmailutils/sockaddr/unlink.c45
-rw-r--r--libmailutils/sockaddr/url.c130
-rw-r--r--libmailutils/stream/tcp.c178
-rw-r--r--libmailutils/tests/.gitignore1
-rw-r--r--libmailutils/tests/Makefile.am1
-rw-r--r--libmailutils/tests/cidr.c77
-rw-r--r--libmailutils/tests/url-parse.c49
-rw-r--r--libmailutils/tests/url.at14
-rw-r--r--libmailutils/url/create.c57
29 files changed, 1899 insertions, 672 deletions
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 @@
16# Public License along with this library. If not, see 16# Public License along with this library. If not, see
17# <http://www.gnu.org/licenses/>. 17# <http://www.gnu.org/licenses/>.
18 18
19SUBDIRS = auth base address cfg diag filter mailbox mailer mime\ 19SUBDIRS = auth base address sockaddr cidr cfg diag filter mailbox mailer mime\
20 server string stream stdstream property url . tests 20 server string stream stdstream property url . tests
21 21
22lib_LTLIBRARIES = libmailutils.la 22lib_LTLIBRARIES = libmailutils.la
@@ -28,6 +28,8 @@ libmailutils_la_LIBADD = \
28 auth/libauth.la\ 28 auth/libauth.la\
29 base/libbase.la\ 29 base/libbase.la\
30 address/libaddress.la\ 30 address/libaddress.la\
31 sockaddr/libsockaddr.la\
32 cidr/libcidr.la\
31 cfg/libcfg.la\ 33 cfg/libcfg.la\
32 diag/libdiag.la\ 34 diag/libdiag.la\
33 filter/libfilter.la\ 35 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 @@
1# GNU Mailutils -- a suite of utilities for electronic mail
2# Copyright (C) 2011 Free Software Foundation, Inc.
3#
4# This library is free software; you can redistribute it and/or
5# modify it under the terms of the GNU Lesser General Public
6# License as published by the Free Software Foundation; either
7# version 3 of the License, or (at your option) any later version.
8#
9# This library is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12# Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General
15# Public License along with this library. If not, see
16# <http://www.gnu.org/licenses/>.
17
18noinst_LTLIBRARIES = libcidr.la
19
20libcidr_la_SOURCES = \
21 fromsa.c\
22 fromstr.c\
23 match.c\
24 tosa.c\
25 tostr.c
26
27INCLUDES = @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 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21#include <sys/types.h>
22#include <sys/socket.h>
23#include <sys/stat.h>
24#include <netinet/in.h>
25#include <arpa/inet.h>
26#include <netdb.h>
27#include <string.h>
28#include <stdlib.h>
29#include <mailutils/cidr.h>
30#include <mailutils/errno.h>
31
32static void
33uint32_to_bytes (unsigned char *bytes, uint32_t u)
34{
35 int i;
36
37 for (i = 0; i < 4; i++)
38 {
39 bytes[i] = u & 0xff;
40 u >>= 8;
41 }
42}
43
44int
45_mu_inaddr_to_bytes (int af, void *buf, unsigned char *bytes)
46{
47 uint32_t u;
48
49 switch (af)
50 {
51 case AF_INET:
52 memcpy (&u, buf, sizeof u);
53 uint32_to_bytes (bytes, u);
54 return 4;
55
56#ifdef MAILUTILS_IPV6
57 case AF_INET6:
58 memcpy (bytes, buf, 16);
59 return 16;
60#endif
61 }
62 return 0;
63}
64
65int
66_mu_sockaddr_to_bytes (unsigned char *bytes, struct sockaddr const *sa)
67{
68 switch (sa->sa_family)
69 {
70 case AF_INET:
71 uint32_to_bytes (bytes, ((struct sockaddr_in*)sa)->sin_addr.s_addr);
72 return 4;
73
74#ifdef MAILUTILS_IPV6
75 case AF_INET6:
76 memcpy (bytes, &((struct sockaddr_in6*)sa)->sin6_addr, 16);
77 return 16;
78#endif
79 }
80 return 0;
81}
82
83int
84mu_cidr_from_sockaddr (struct mu_cidr *cidr, const struct sockaddr *sa)
85{
86 unsigned char address[MU_INADDR_BYTES];
87 int len;
88 int i;
89
90 len = _mu_sockaddr_to_bytes (address, sa);
91 if (len == 0)
92 return MU_ERR_FAMILY;
93 cidr->family = sa->sa_family;
94 cidr->len = len;
95 memcpy (cidr->address, address, sizeof (cidr->address));
96 for (i = 0; i < MU_INADDR_BYTES; i++)
97 cidr->netmask[i] = 0xff;
98 return 0;
99}
100
101
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 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21#include <string.h>
22#include <stdlib.h>
23#include <arpa/inet.h>
24#include <mailutils/cidr.h>
25#include <mailutils/errno.h>
26#include <mailutils/sockaddr.h>
27
28static void
29masklen_to_netmask (unsigned char *buf, size_t len, size_t masklen)
30{
31 int i, cnt;
32
33 cnt = masklen / 8;
34 for (i = 0; i < cnt; i++)
35 buf[i] = 0xff;
36 if (i == MU_INADDR_BYTES)
37 return;
38 cnt = 8 - masklen % 8;
39 buf[i++] = (0xff >> cnt) << cnt;
40 for (; i < MU_INADDR_BYTES; i++)
41 buf[i] = 0;
42}
43
44int
45mu_cidr_from_string (struct mu_cidr *pcidr, const char *str)
46{
47 int rc;
48 char ipbuf[41];
49 struct mu_cidr cidr;
50 char *p;
51 size_t len;
52 union
53 {
54 struct in_addr in;
55#ifdef MAILUTILS_IPV6
56 struct in6_addr in6;
57#endif
58 } inaddr;
59
60 p = strchr (str, '/');
61 if (p)
62 len = p - str;
63 else
64 len = strlen (str);
65
66 if (len > sizeof (ipbuf))
67 return MU_ERR_BUFSPACE;
68
69 memcpy (ipbuf, str, len);
70 ipbuf[len] = 0;
71
72 if (mu_str_is_ipv4 (ipbuf))
73 cidr.family = AF_INET;
74#ifdef MAILUTILS_IPV6
75 else if (mu_str_is_ipv6 (ipbuf))
76 cidr.family = AF_INET6;
77#endif
78 else
79 return MU_ERR_FAMILY;
80
81 rc = inet_pton (cidr.family, ipbuf, &inaddr);
82 if (rc == -1)
83 return MU_ERR_FAMILY;
84 else if (rc == 0)
85 return MU_ERR_NONAME;
86 else if (rc != 1)
87 return MU_ERR_FAILURE;
88
89 cidr.len = _mu_inaddr_to_bytes (cidr.family, &inaddr, cidr.address);
90 if (cidr.len == 0)
91 return MU_ERR_FAMILY;
92
93 if (p)
94 {
95 char *end;
96 unsigned long masklen;
97
98 p++;
99
100 masklen = strtoul (p, &end, 10);
101 if (*end == 0)
102 masklen_to_netmask (cidr.netmask, cidr.len, masklen);
103 else if ((cidr.family == AF_INET && mu_str_is_ipv4 (p))
104#ifdef MAILUTILS_IPV6
105 || (cidr.family == AF_INET6 && mu_str_is_ipv6 (ipbuf))
106#endif
107 )
108 {
109 rc = inet_pton (cidr.family, p, &inaddr);
110 if (rc == -1)
111 return MU_ERR_FAMILY;
112 else if (rc == 0)
113 return MU_ERR_NONAME;
114 else if (rc != 1)
115 return MU_ERR_FAILURE;
116
117 _mu_inaddr_to_bytes (cidr.family, &inaddr, cidr.netmask);
118 }
119 else
120 return MU_ERR_FAMILY;
121 }
122 else
123 masklen_to_netmask (cidr.netmask, cidr.len, cidr.len * 8);
124
125 memcpy (pcidr, &cidr, sizeof (*pcidr));
126 return 0;
127}
128
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 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21#include <mailutils/cidr.h>
22#include <mailutils/errno.h>
23
24int
25mu_cidr_match (struct mu_cidr *a, struct mu_cidr *b)
26{
27 int i;
28
29 if (a->family != b->family)
30 return 1;
31 for (i = 0; i < a->len; i++)
32 {
33 if (a->address[i] != (b->address[i] & a->netmask[i]))
34 return 1;
35 }
36 return 0;
37}
38
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 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21#include <sys/types.h>
22#include <sys/socket.h>
23#include <sys/stat.h>
24#include <netinet/in.h>
25#include <arpa/inet.h>
26#include <netdb.h>
27#include <string.h>
28#include <stdlib.h>
29#include <mailutils/cidr.h>
30#include <mailutils/errno.h>
31
32int
33mu_cidr_to_sockaddr (struct mu_cidr *cidr, struct sockaddr **psa)
34{
35 union
36 {
37 struct sockaddr sa;
38 struct sockaddr_in s_in;
39#ifdef MAILUTILS_IPV6
40 struct sockaddr_in6 s_in6;
41#endif
42 } addr;
43 struct sockaddr *sa;
44 int socklen;
45 int i;
46
47 memset (&addr, 0, sizeof (addr));
48 addr.sa.sa_family = cidr->family;
49 switch (cidr->family)
50 {
51 case AF_INET:
52 socklen = sizeof (addr.s_in);
53 for (i = 0; i < cidr->len; i++)
54 {
55 addr.s_in.sin_addr.s_addr <<= 8;
56 addr.s_in.sin_addr.s_addr |= cidr->address[i];
57 }
58 break;
59
60#ifdef MAILUTILS_IPV6
61 case AF_INET6:
62 socklen = sizeof (addr.s_in6);
63 memcpy (&addr.s_in6.sin6_addr, cidr->address, 16);
64 break;
65#endif
66
67 default:
68 return MU_ERR_FAMILY;
69 }
70
71 sa = malloc (socklen);
72 if (!sa)
73 return ENOMEM;
74 memcpy (sa, &addr, socklen);
75 *psa = sa;
76 return 0;
77}
78
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 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21#include <string.h>
22#include <stdlib.h>
23#include <mailutils/cidr.h>
24#include <mailutils/errno.h>
25
26static int
27to_xdig (unsigned char b)
28{
29 if (b >= 0xa)
30 return 'A' + b - 0xa;
31 else
32 return '0' + b;
33}
34
35static size_t
36format_ipv6_bytes (const unsigned char *bytes, int len,
37 char *buf, size_t size)
38{
39 size_t total = 0;
40 int i;
41
42 for (i = 0; i < len; i += 2)
43 {
44 if (i)
45 {
46 if (total++ < size)
47 *buf++ = ':';
48 }
49 if (total++ < size)
50 *buf++ = to_xdig (*bytes >> 4);
51 if (total++ < size)
52 *buf++ = to_xdig (*bytes & 0xf);
53 bytes++;
54 if (total++ < size)
55 *buf++ = to_xdig (*bytes >> 4);
56 if (total++ < size)
57 *buf++ = to_xdig (*bytes & 0xf);
58 bytes++;
59 }
60 return total;
61}
62
63static size_t
64format_ipv4_bytes (const unsigned char *bytes, int len,
65 char *buf, size_t size)
66{
67 int i;
68 size_t total = 0;
69
70 for (i = 0; i < len; i++)
71 {
72 unsigned char b = *bytes++;
73 char nbuf[3];
74 int j;
75
76 if (i)
77 {
78 if (total++ < size)
79 *buf++ = '.';
80 }
81
82 j = 0;
83 do
84 {
85 nbuf[j++] = b % 10 + '0';
86 b /= 10;
87 }
88 while (b);
89
90 for (; j; j--)
91 {
92 if (total++ < size)
93 *buf++ = nbuf[j - 1];
94 }
95 }
96 return total;
97}
98
99int
100mu_cidr_to_string (struct mu_cidr *cidr, int flags,
101 char *buf, size_t size, size_t *pret)
102{
103 size_t (*fmt) (const unsigned char *bytes, int len, char *buf, size_t size);
104 size_t n, total = 0;
105
106 if (size == 0)
107 return MU_ERR_BUFSPACE;
108 size--;
109 switch (cidr->family)
110 {
111 case AF_INET:
112 fmt = format_ipv4_bytes;
113 break;
114
115#ifdef MAILUTILS_IPV6
116 case AF_INET6:
117 fmt = format_ipv6_bytes;
118 break;
119#endif
120
121 default:
122 return MU_ERR_FAMILY;
123 }
124
125 n = fmt (cidr->address, cidr->len, buf, size);
126 if (buf)
127 buf += n;
128 total += n;
129
130 if (!(flags & MU_CIDR_FMT_ADDRONLY))
131 {
132 if (total++ < size)
133 *buf++ = '/';
134 n = fmt (cidr->netmask, cidr->len, buf, size - total);
135 if (buf)
136 buf += n;
137 total += n;
138 }
139
140 if (buf)
141 *buf++ = 0;
142 if (pret)
143 *pret = total;
144 return 0;
145}
146
147int
148mu_cidr_format (struct mu_cidr *cidr, int flags, char **pbuf)
149{
150 char buf[MU_CIDR_MAXBUFSIZE];
151 int rc = mu_cidr_to_string (cidr, flags, buf, sizeof (buf), NULL);
152 if (rc)
153 return rc;
154 *pbuf = strdup (buf);
155 if (!*buf)
156 return ENOMEM;
157 return 0;
158}
159
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, ...)
689 va_list ap; 689 va_list ap;
690 690
691 mu_diag_init (); 691 mu_diag_init ();
692 mu_stream_flush (mu_strerr);
692 va_start (ap, fmt); 693 va_start (ap, fmt);
693 mu_stream_printf (mu_strerr, "\033s<%d>", MU_LOG_DEBUG); 694 mu_stream_printf (mu_strerr, "\033s<%d>", MU_LOG_DEBUG);
694 mu_stream_vprintf (mu_strerr, fmt, ap); 695 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 @@
1
1# Error messages for GNU Mailutils 2# Error messages for GNU Mailutils
2# Copyright (C) 2005, 2006, 2007, 2010, 2011 Free Software Foundation, 3# Copyright (C) 2005, 2006, 2007, 2010, 2011 Free Software Foundation,
3# Inc. 4# Inc.
@@ -98,3 +99,10 @@ MU_ERR_URL_MISS_PARTS _("URL missing required parts")
98MU_ERR_URL_EXTRA_PARTS _("URL has parts not allowed by its scheme") 99MU_ERR_URL_EXTRA_PARTS _("URL has parts not allowed by its scheme")
99 100
100MU_ERR_INFO_UNAVAILABLE _("Information is not yet available") 101MU_ERR_INFO_UNAVAILABLE _("Information is not yet available")
102
103# The following are mapped to the corresponding EAI_ errors
104MU_ERR_NONAME _("Name or service not known")
105MU_ERR_BADFLAGS _("Bad value for flags")
106MU_ERR_SOCKTYPE _("Socket type not supported")
107MU_ERR_FAMILY _("Address family not supported")
108MU_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 @@
40#include <mailutils/kwd.h> 40#include <mailutils/kwd.h>
41#include <mailutils/io.h> 41#include <mailutils/io.h>
42#include <mailutils/util.h> 42#include <mailutils/util.h>
43#include <mailutils/sockaddr.h>
44#include <mailutils/cidr.h>
45#include <mailutils/stream.h>
46#include <mailutils/stdstream.h>
47
48#ifndef MU_INADDR_BYTES
49#define MU_INADDR_BYTES 16
50#endif
43 51
44struct _mu_acl_entry 52struct _mu_acl_entry
45{ 53{
46 mu_acl_action_t action; 54 mu_acl_action_t action;
47 void *arg; 55 void *arg;
48 unsigned netmask; 56 struct mu_cidr cidr;
49 int salen;
50 struct sockaddr sa[1];
51}; 57};
52 58
53struct _mu_acl 59struct _mu_acl
@@ -64,52 +70,19 @@ _destroy_acl_entry (void *item)
64 /* FIXME: free arg? */ 70 /* FIXME: free arg? */
65} 71}
66 72
67static size_t
68mu_acl_entry_size (int salen)
69{
70 return sizeof (struct _mu_acl_entry) + salen - sizeof (struct sockaddr);
71}
72
73static int
74prepare_sa (struct sockaddr *sa)
75{
76 switch (sa->sa_family)
77 {
78 case AF_INET:
79 {
80 struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
81 s_in->sin_addr.s_addr = ntohl (s_in->sin_addr.s_addr);
82 break;
83 }
84
85 case AF_UNIX:
86 break;
87
88 default:
89 return 1;
90 }
91 return 0;
92}
93
94int 73int
95mu_acl_entry_create (struct _mu_acl_entry **pent, 74mu_acl_entry_create (struct _mu_acl_entry **pent,
96 mu_acl_action_t action, void *data, 75 mu_acl_action_t action, void *data,
97 struct sockaddr *sa, int salen, unsigned long netmask) 76 struct mu_cidr *cidr)
98{ 77{
99 struct _mu_acl_entry *p = malloc (mu_acl_entry_size (salen)); 78 struct _mu_acl_entry *p = malloc (sizeof (*p));
100 if (!p) 79 if (!p)
101 return EINVAL; 80 return EINVAL;
102 81
103 p->action = action; 82 p->action = action;
104 p->arg = data; 83 p->arg = data;
105 p->netmask = ntohl (netmask); 84 memcpy (&p->cidr, cidr, sizeof (p->cidr));
106 p->salen = salen; 85
107 memcpy (p->sa, sa, salen);
108 if (prepare_sa (p->sa))
109 {
110 free (p);
111 return EINVAL;
112 }
113 *pent = p; 86 *pent = p;
114 return 0; 87 return 0;
115} 88}
@@ -165,15 +138,14 @@ mu_acl_get_iterator (mu_acl_t acl, mu_iterator_t *pitr)
165 138
166int 139int
167mu_acl_append (mu_acl_t acl, mu_acl_action_t act, 140mu_acl_append (mu_acl_t acl, mu_acl_action_t act,
168 void *data, struct sockaddr *sa, int salen, 141 void *data, struct mu_cidr *cidr)
169 unsigned long netmask)
170{ 142{
171 int rc; 143 int rc;
172 struct _mu_acl_entry *ent; 144 struct _mu_acl_entry *ent;
173 145
174 if (!acl) 146 if (!acl)
175 return EINVAL; 147 return EINVAL;
176 rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask); 148 rc = mu_acl_entry_create (&ent, act, data, cidr);
177 if (rc) 149 if (rc)
178 { 150 {
179 mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, 151 mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
@@ -193,14 +165,14 @@ mu_acl_append (mu_acl_t acl, mu_acl_action_t act,
193 165
194int 166int
195mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data, 167mu_acl_prepend (mu_acl_t acl, mu_acl_action_t act, void *data,
196 struct sockaddr *sa, int salen, unsigned long netmask) 168 struct mu_cidr *cidr)
197{ 169{
198 int rc; 170 int rc;
199 struct _mu_acl_entry *ent; 171 struct _mu_acl_entry *ent;
200 172
201 if (!acl) 173 if (!acl)
202 return EINVAL; 174 return EINVAL;
203 rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask); 175 rc = mu_acl_entry_create (&ent, act, data, cidr);
204 if (rc) 176 if (rc)
205 { 177 {
206 mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, 178 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,
219 191
220int 192int
221mu_acl_insert (mu_acl_t acl, size_t pos, int before, 193mu_acl_insert (mu_acl_t acl, size_t pos, int before,
222 mu_acl_action_t act, void *data, 194 mu_acl_action_t act, void *data, struct mu_cidr *cidr)
223 struct sockaddr *sa, int salen, unsigned long netmask)
224{ 195{
225 int rc; 196 int rc;
226 void *ptr; 197 void *ptr;
@@ -236,7 +207,7 @@ mu_acl_insert (mu_acl_t acl, size_t pos, int before,
236 ("No such entry %lu", (unsigned long) pos)); 207 ("No such entry %lu", (unsigned long) pos));
237 return rc; 208 return rc;
238 } 209 }
239 rc = mu_acl_entry_create (&ent, act, data, sa, salen, netmask); 210 rc = mu_acl_entry_create (&ent, act, data, cidr);
240 if (!ent) 211 if (!ent)
241 { 212 {
242 mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, 213 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)
279 return rc; 250 return rc;
280} 251}
281 252
282#define MU_S_UN_NAME(sa, salen) \ 253struct run_closure
283 ((salen < mu_offsetof (struct sockaddr_un,sun_path)) ? "" : (sa)->sun_path)
284
285static void
286debug_sockaddr (struct sockaddr *sa, int salen)
287{
288 switch (sa->sa_family)
289 {
290 case AF_INET:
291 {
292 struct sockaddr_in s_in = *(struct sockaddr_in *)sa;
293 s_in.sin_addr.s_addr = htonl (s_in.sin_addr.s_addr);
294 mu_debug_log_cont ("{AF_INET %s:%d}",
295 inet_ntoa (s_in.sin_addr), ntohs (s_in.sin_port));
296 break;
297 }
298
299 case AF_UNIX:
300 {
301 struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
302 if (MU_S_UN_NAME(s_un, salen)[0] == 0)
303 mu_debug_log_cont ("{AF_UNIX}");
304 else
305 mu_debug_log_cont ("{AF_UNIX %s}", s_un->sun_path);
306 break;
307 }
308
309 default:
310 mu_debug_log_cont ("{Unsupported family: %d}", sa->sa_family);
311 }
312}
313
314size_t
315mu_stpcpy (char **pbuf, size_t *psize, const char *src)
316{
317 size_t slen = strlen (src);
318 if (pbuf == NULL || *pbuf == NULL)
319 return slen;
320 else
321 {
322 char *buf = *pbuf;
323 size_t size = *psize;
324 if (size > slen)
325 size = slen;
326 memcpy (buf, src, size);
327 *psize -= size;
328 *pbuf += size;
329 if (*psize)
330 **pbuf = 0;
331 else
332 (*pbuf)[-1] = 0;
333 return size;
334 }
335}
336
337void
338mu_sockaddr_to_str (const struct sockaddr *sa, int salen,
339 char *bufptr, size_t buflen,
340 size_t *plen)
341{ 254{
342 char *nbuf; 255 unsigned idx;
343 size_t len = 0; 256 struct mu_cidr addr;
344 switch (sa->sa_family)
345 {
346 case AF_INET:
347 {
348 struct sockaddr_in s_in = *(struct sockaddr_in *)sa;
349 len += mu_stpcpy (&bufptr, &buflen, inet_ntoa (s_in.sin_addr));
350 len += mu_stpcpy (&bufptr, &buflen, ":");
351 if (mu_asprintf (&nbuf, "%hu", ntohs (s_in.sin_port)) == 0)
352 {
353 len += mu_stpcpy (&bufptr, &buflen, nbuf);
354 free (nbuf);
355 }
356 break;
357 }
358
359 case AF_UNIX:
360 {
361 struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
362 if (MU_S_UN_NAME(s_un, salen)[0] == 0)
363 len += mu_stpcpy (&bufptr, &buflen, "anonymous socket");
364 else
365 {
366 len += mu_stpcpy (&bufptr, &buflen, "socket ");
367 len += mu_stpcpy (&bufptr, &buflen, s_un->sun_path);
368 }
369 break;
370 }
371
372 default:
373 len += mu_stpcpy (&bufptr, &buflen, "{Unsupported family");
374 if (mu_asprintf (&nbuf, ": %d", sa->sa_family) == 0)
375 {
376 len += mu_stpcpy (&bufptr, &buflen, nbuf);
377 free (nbuf);
378 }
379 len += mu_stpcpy (&bufptr, &buflen, "}");
380 }
381 if (plen)
382 *plen = len + 1;
383}
384 257
385char * 258 char ipstr[40];
386mu_sockaddr_to_astr (const struct sockaddr *sa, int salen) 259 char *addrstr;
387{ 260 char *numbuf;
388 size_t size; 261 mu_acl_result_t *result;
389 char *p; 262};
390
391 mu_sockaddr_to_str (sa, salen, NULL, 0, &size);
392 p = malloc (size);
393 if (p)
394 mu_sockaddr_to_str (sa, salen, p, size, NULL);
395 return p;
396}
397 263
398int 264int
399_acl_match (struct _mu_acl_entry *ent, struct sockaddr *sa, int salen) 265_acl_match (struct _mu_acl_entry *ent, struct run_closure *rp)
400{ 266{
401#define RESMATCH(word) \ 267#define RESMATCH(word) \
402 if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) \ 268 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)
404 270
405 if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) 271 if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
406 { 272 {
407 struct in_addr a; 273 char *s;
408 274
409 mu_debug_log_begin ("Does "); 275 if (ent->cidr.len == 0)
410 debug_sockaddr (sa, salen); 276 s = strdup ("any");
411 mu_debug_log_cont (" match "); 277 mu_cidr_format (&ent->cidr, 0, &s);
412 debug_sockaddr (ent->sa, salen); 278 if (!rp->addrstr)
413 a.s_addr = ent->netmask; 279 mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr);
414 a.s_addr = htonl (a.s_addr); 280 mu_debug_log_begin ("Does %s match %s? ", s, rp->addrstr);
415 mu_debug_log_cont (" netmask %s? ", inet_ntoa (a)); 281 free (s);
416 } 282 }
417 283
418 if (ent->sa->sa_family != sa->sa_family) 284 if (ent->cidr.len > 0 && mu_cidr_match (&ent->cidr, &rp->addr))
419 { 285 {
420 RESMATCH ("no"); 286 RESMATCH ("no");
421 return 1; 287 return 1;
422 } 288 }
423
424 switch (ent->sa->sa_family)
425 {
426 case AF_INET:
427 {
428 struct sockaddr_in *sin_ent = (struct sockaddr_in *)ent->sa;
429 struct sockaddr_in *sin_item = (struct sockaddr_in *)sa;
430
431 if (sin_ent->sin_addr.s_addr !=
432 (sin_item->sin_addr.s_addr & ent->netmask))
433 {
434 RESMATCH ("no (address differs)");
435 return 1;
436 }
437
438 if (sin_ent->sin_port && sin_item->sin_port
439 && sin_ent->sin_port != sin_item->sin_port)
440 {
441 RESMATCH ("no (port differs)");
442 return 1;
443 }
444 break;
445 }
446
447 case AF_UNIX:
448 {
449 struct sockaddr_un *sun_ent = (struct sockaddr_un *)ent->sa;
450 struct sockaddr_un *sun_item = (struct sockaddr_un *)sa;
451
452 if (MU_S_UN_NAME (sun_ent, ent->salen)[0]
453 && MU_S_UN_NAME (sun_item, salen)[0]
454 && strcmp (sun_ent->sun_path, sun_item->sun_path))
455 {
456 RESMATCH ("no");
457 return 1;
458 }
459 break;
460 }
461 }
462
463 RESMATCH ("yes"); 289 RESMATCH ("yes");
464 return 0; 290 return 0;
465} 291}
466 292
467struct run_closure
468{
469 unsigned idx;
470 struct sockaddr *sa;
471 char *numbuf;
472 char *portbuf;
473 int salen;
474 mu_acl_result_t *result;
475};
476
477#define SEQ(s, n, l) \ 293#define SEQ(s, n, l) \
478 (((l) == (sizeof(s) - 1)) && memcmp (s, n, l) == 0) 294 (((l) == (sizeof(s) - 1)) && memcmp (s, n, l) == 0)
479 295
@@ -489,40 +305,24 @@ acl_getvar (const char *name, size_t nlen, void *data)
489 return rp->numbuf; 305 return rp->numbuf;
490 } 306 }
491 307
492 switch (rp->sa->sa_family) 308 if (SEQ ("address", name, nlen))
493 { 309 {
494 case AF_INET: 310 if (!rp->addrstr)
495 { 311 mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY, &rp->addrstr);
496 struct sockaddr_in *s_in = (struct sockaddr_in *)rp->sa; 312 return rp->addrstr;
497 313 }
498 if (SEQ ("address", name, nlen))
499 {
500 struct in_addr addr = s_in->sin_addr;
501 addr.s_addr = htonl (addr.s_addr);
502 return inet_ntoa (addr);
503 }
504 314
505 if (SEQ ("port", name, nlen)) 315#if 0
506 { 316 /* FIXME?: */
507 if (!rp->portbuf && 317 if (SEQ ("port", name, nlen))
508 mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port))) 318 {
509 return NULL; 319 if (!rp->portbuf &&
510 return rp->portbuf; 320 mu_asprintf (&rp->portbuf, "%hu", ntohs (s_in->sin_port)))
511 } 321 return NULL;
512 break; 322 return rp->portbuf;
513
514 case AF_UNIX:
515 if (SEQ ("address", name, nlen))
516 {
517 struct sockaddr_un *s_un = (struct sockaddr_un *)rp->sa;
518 if (rp->salen == sizeof (s_un->sun_family))
519 return NULL;
520 else
521 return s_un->sun_path;
522 }
523 }
524 break;
525 } 323 }
324#endif
325
526 return NULL; 326 return NULL;
527} 327}
528 328
@@ -535,12 +335,18 @@ expand_arg (const char *cmdline, struct run_closure *rp, char **s)
535 335
536 mu_debug (MU_DEBCAT_ACL, MU_DEBUG_TRACE, ("Expanding \"%s\"", cmdline)); 336 mu_debug (MU_DEBCAT_ACL, MU_DEBUG_TRACE, ("Expanding \"%s\"", cmdline));
537 env[0] = "family"; 337 env[0] = "family";
538 switch (rp->sa->sa_family) 338 switch (rp->addr.family)
539 { 339 {
540 case AF_INET: 340 case AF_INET:
541 env[1] = "AF_INET"; 341 env[1] = "AF_INET";
542 break; 342 break;
543 343
344#ifdef MAILUTILS_IPV6
345 case AF_INET6:
346 env[1] = "AF_INET6";
347 break;
348#endif
349
544 case AF_UNIX: 350 case AF_UNIX:
545 env[1] = "AF_UNIX"; 351 env[1] = "AF_UNIX";
546 break; 352 break;
@@ -654,7 +460,7 @@ _run_entry (void *item, void *data)
654 mu_debug_log_begin ("%d:%s: ", rp->idx, s); 460 mu_debug_log_begin ("%d:%s: ", rp->idx, s);
655 } 461 }
656 462
657 if (_acl_match (ent, rp->sa, rp->salen) == 0) 463 if (_acl_match (ent, rp) == 0)
658 { 464 {
659 switch (ent->action) 465 switch (ent->action)
660 { 466 {
@@ -678,8 +484,10 @@ _run_entry (void *item, void *data)
678 } 484 }
679 else 485 else
680 { 486 {
681 debug_sockaddr (rp->sa, rp->salen); 487 if (!rp->addrstr)
682 mu_debug_log_nl (); 488 mu_cidr_format (&rp->addr, MU_CIDR_FMT_ADDRONLY,
489 &rp->addrstr);
490 mu_diag_output (MU_DIAG_INFO, "%s", rp->addrstr);
683 } 491 }
684 } 492 }
685 break; 493 break;
@@ -712,7 +520,7 @@ _run_entry (void *item, void *data)
712 } 520 }
713 521
714 if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) 522 if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
715 mu_debug_log_nl (); 523 mu_stream_flush (mu_strerr);
716 524
717 return status; 525 return status;
718} 526}
@@ -721,40 +529,39 @@ int
721mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen, 529mu_acl_check_sockaddr (mu_acl_t acl, const struct sockaddr *sa, int salen,
722 mu_acl_result_t *pres) 530 mu_acl_result_t *pres)
723{ 531{
532 int rc;
724 struct run_closure r; 533 struct run_closure r;
725 534
726 if (!acl) 535 if (!acl)
727 return EINVAL; 536 return EINVAL;
728 537
729 r.sa = malloc (salen); 538 memset (&r, 0, sizeof (r));
730 if (!r.sa) 539 if (sa->sa_family == AF_UNIX)
731 return ENOMEM;
732 memcpy (r.sa, sa, salen);
733 if (prepare_sa (r.sa))
734 { 540 {
735 free (r.sa); 541 *pres = mu_acl_result_accept;
736 return EINVAL; 542 return 0;
737 } 543 }
738 r.salen = salen; 544 rc = mu_cidr_from_sockaddr (&r.addr, sa);
545 if (rc)
546 return rc;
739 547
740 if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9)) 548 if (mu_debug_level_p (MU_DEBCAT_ACL, MU_DEBUG_TRACE9))
741 { 549 {
742 mu_debug_log_begin ("Checking sockaddr "); 550 mu_cidr_format (&r.addr, MU_CIDR_FMT_ADDRONLY, &r.addrstr);
743 debug_sockaddr (r.sa, r.salen); 551 mu_debug_log_begin ("Checking sockaddr %s", r.addrstr);
744 mu_debug_log_nl (); 552 mu_debug_log_nl ();
745 } 553 }
746 554
747 r.idx = 0; 555 r.idx = 0;
748 r.result = pres; 556 r.result = pres;
749 *r.result = mu_acl_result_undefined; 557 *r.result = mu_acl_result_undefined;
750 r.numbuf = r.portbuf = NULL; 558 r.numbuf = NULL;
751 mu_list_do (acl->aclist, _run_entry, &r); 559 mu_list_do (acl->aclist, _run_entry, &r);
752 free (r.numbuf); 560 free (r.numbuf);
753 free (r.portbuf); 561 free (r.addrstr);
754 free (r.sa);
755 return 0; 562 return 0;
756} 563}
757 564
758int 565int
759mu_acl_check_inaddr (mu_acl_t acl, const struct in_addr *inp, 566mu_acl_check_inaddr (mu_acl_t acl, const struct in_addr *inp,
760 mu_acl_result_t *pres) 567 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)
780int 587int
781mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres) 588mu_acl_check_fd (mu_acl_t acl, int fd, mu_acl_result_t *pres)
782{ 589{
783 struct sockaddr_in cs; 590 union
784 socklen_t len = sizeof cs; 591 {
592 struct sockaddr sa;
593 struct sockaddr_in in;
594#ifdef MAILUTILS_IPV6
595 struct sockaddr_in6 in6;
596#endif
597 } addr;
598 socklen_t len = sizeof addr;
785 599
786 if (getpeername (fd, (struct sockaddr *) &cs, &len) < 0) 600 if (getpeername (fd, &addr.sa, &len) < 0)
787 { 601 {
788 mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR, 602 mu_debug (MU_DEBCAT_ACL, MU_DEBUG_ERROR,
789 ("Cannot obtain IP address of client: %s", 603 ("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)
791 return MU_ERR_FAILURE; 605 return MU_ERR_FAILURE;
792 } 606 }
793 607
794 return mu_acl_check_sockaddr (acl, (struct sockaddr *) &cs, len, pres); 608 return mu_acl_check_sockaddr (acl, &addr.sa, len, pres);
795} 609}
796 610
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 @@
34#include <mailutils/diag.h> 34#include <mailutils/diag.h>
35#include <mailutils/errno.h> 35#include <mailutils/errno.h>
36#include <mailutils/nls.h> 36#include <mailutils/nls.h>
37#include <mailutils/sockaddr.h>
37 38
38 39
39struct _mu_ip_server 40struct _mu_ip_server
40{ 41{
41 char *ident; 42 char *ident;
42 struct sockaddr *addr; 43 struct mu_sockaddr *addr;
43 int addrlen;
44 int fd; 44 int fd;
45 int type; 45 int type;
46 mu_acl_t acl; 46 mu_acl_t acl;
@@ -66,8 +66,7 @@ struct _mu_ip_server
66#define IDENTSTR(s) ((s)->ident ? (s)->ident : "default") 66#define IDENTSTR(s) ((s)->ident ? (s)->ident : "default")
67 67
68int 68int
69mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr, 69mu_ip_server_create (mu_ip_server_t *psrv, struct mu_sockaddr *addr, int type)
70 int addrlen, int type)
71{ 70{
72 struct _mu_ip_server *srv; 71 struct _mu_ip_server *srv;
73 72
@@ -84,14 +83,7 @@ mu_ip_server_create (mu_ip_server_t *psrv, struct sockaddr *addr,
84 srv = calloc (1, sizeof *srv); 83 srv = calloc (1, sizeof *srv);
85 if (!srv) 84 if (!srv)
86 return ENOMEM; 85 return ENOMEM;
87 srv->addr = calloc (1, addrlen); 86 srv->addr = addr;
88 if (!srv->addr)
89 {
90 free (srv);
91 return ENOMEM;
92 }
93 memcpy (srv->addr, addr, addrlen);
94 srv->addrlen = addrlen;
95 srv->type = type; 87 srv->type = type;
96 srv->fd = -1; 88 srv->fd = -1;
97 switch (type) 89 switch (type)
@@ -120,7 +112,7 @@ mu_ip_server_destroy (mu_ip_server_t *psrv)
120 if (srv->f_free) 112 if (srv->f_free)
121 srv->f_free (srv->data); 113 srv->f_free (srv->data);
122 close (srv->fd); 114 close (srv->fd);
123 free (srv->addr); 115 mu_sockaddr_free (srv->addr);
124 free (srv->ident); 116 free (srv->ident);
125 if (srv->type == MU_IP_UDP && srv->v.udp_data.buf) 117 if (srv->type == MU_IP_UDP && srv->v.udp_data.buf)
126 free (srv->v.udp_data.buf); 118 free (srv->v.udp_data.buf);
@@ -234,6 +226,11 @@ mu_address_family_to_domain (int family)
234 case AF_INET: 226 case AF_INET:
235 return PF_INET; 227 return PF_INET;
236 228
229#ifdef MAILUTILS_IPV6
230 case AF_INET6:
231 return PF_INET6;
232#endif
233
237 default: 234 default:
238 abort (); 235 abort ();
239 } 236 }
@@ -247,14 +244,11 @@ mu_ip_server_open (mu_ip_server_t srv)
247 if (!srv || srv->fd != -1) 244 if (!srv || srv->fd != -1)
248 return EINVAL; 245 return EINVAL;
249 246
250 if (mu_debug_level_p (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0)) 247 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0,
251 { 248 ("opening server \"%s\" %s", IDENTSTR (srv),
252 char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen); 249 mu_sockaddr_str (srv->addr)));
253 mu_debug_log ("opening server \"%s\" %s", IDENTSTR (srv), p);
254 free (p);
255 }
256 250
257 fd = socket (mu_address_family_to_domain (srv->addr->sa_family), 251 fd = socket (mu_address_family_to_domain (srv->addr->addr->sa_family),
258 ((srv->type == MU_IP_UDP) ? SOCK_DGRAM : SOCK_STREAM), 0); 252 ((srv->type == MU_IP_UDP) ? SOCK_DGRAM : SOCK_STREAM), 0);
259 if (fd == -1) 253 if (fd == -1)
260 { 254 {
@@ -263,7 +257,7 @@ mu_ip_server_open (mu_ip_server_t srv)
263 return errno; 257 return errno;
264 } 258 }
265 259
266 switch (srv->addr->sa_family) 260 switch (srv->addr->addr->sa_family)
267 { 261 {
268 case AF_UNIX: 262 case AF_UNIX:
269 { 263 {
@@ -299,7 +293,7 @@ mu_ip_server_open (mu_ip_server_t srv)
299 } 293 }
300 break; 294 break;
301 295
302 case AF_INET: 296 default:
303 { 297 {
304 int t; 298 int t;
305 299
@@ -308,7 +302,7 @@ mu_ip_server_open (mu_ip_server_t srv)
308 } 302 }
309 } 303 }
310 304
311 if (bind (fd, srv->addr, srv->addrlen) == -1) 305 if (bind (fd, srv->addr->addr, srv->addr->addrlen) == -1)
312 { 306 {
313 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR, 307 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_ERROR,
314 ("%s: bind: %s", IDENTSTR (srv), mu_strerror (errno))); 308 ("%s: bind: %s", IDENTSTR (srv), mu_strerror (errno)));
@@ -336,12 +330,9 @@ mu_ip_server_shutdown (mu_ip_server_t srv)
336{ 330{
337 if (!srv || srv->fd != -1) 331 if (!srv || srv->fd != -1)
338 return EINVAL; 332 return EINVAL;
339 if (mu_debug_level_p (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0)) 333 mu_debug (MU_DEBCAT_SERVER, MU_DEBUG_TRACE0,
340 { 334 ("closing server \"%s\" %s", IDENTSTR (srv),
341 char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen); 335 mu_sockaddr_str (srv->addr)));
342 mu_debug_log ("closing server \"%s\" %s", IDENTSTR (srv), p);
343 free (p);
344 }
345 close (srv->fd); 336 close (srv->fd);
346 return 0; 337 return 0;
347} 338}
@@ -356,6 +347,9 @@ mu_ip_tcp_accept (mu_ip_server_t srv, void *call_data)
356 struct sockaddr sa; 347 struct sockaddr sa;
357 struct sockaddr_in s_in; 348 struct sockaddr_in s_in;
358 struct sockaddr_un s_un; 349 struct sockaddr_un s_un;
350#ifdef MAILUTILS_IPV6
351 struct sockaddr_in6 s_in6;
352#endif
359 } client; 353 } client;
360 354
361 socklen_t size = sizeof (client); 355 socklen_t size = sizeof (client);
@@ -407,6 +401,9 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
407 struct sockaddr sa; 401 struct sockaddr sa;
408 struct sockaddr_in s_in; 402 struct sockaddr_in s_in;
409 struct sockaddr_un s_un; 403 struct sockaddr_un s_un;
404#ifdef MAILUTILS_IPV6
405 struct sockaddr_in6 s_in6;
406#endif
410 } client; 407 } client;
411 fd_set rdset; 408 fd_set rdset;
412 409
@@ -463,7 +460,7 @@ mu_ip_udp_accept (mu_ip_server_t srv, void *call_data)
463 IDENTSTR (srv), strerror (rc))); 460 IDENTSTR (srv), strerror (rc)));
464 if (res == mu_acl_result_deny) 461 if (res == mu_acl_result_deny)
465 { 462 {
466 char *p = mu_sockaddr_to_astr (srv->addr, srv->addrlen); 463 char *p = mu_sockaddr_to_astr (&client.sa, salen);
467 mu_diag_output (MU_DIAG_INFO, "Denying connection from %s", p); 464 mu_diag_output (MU_DIAG_INFO, "Denying connection from %s", p);
468 free (p); 465 free (p);
469 return 0; 466 return 0;
@@ -528,22 +525,16 @@ mu_udp_server_get_rdata (mu_ip_server_t srv, char **pbuf, size_t *pbufsize)
528} 525}
529 526
530int 527int
531mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct sockaddr *s, int *size) 528mu_ip_server_get_sockaddr (mu_ip_server_t srv, struct mu_sockaddr **psa)
532{ 529{
533 int len; 530 if (!srv || !psa)
534
535 if (!srv || !s)
536 return EINVAL; 531 return EINVAL;
537 if (s == 0) 532 return mu_sockaddr_copy (psa, srv->addr);
538 len = srv->addrlen;
539 else
540 {
541 len = srv->addrlen;
542 if (*size < len)
543 return MU_ERR_BUFSPACE;
544 memcpy (s, srv->addr, len);
545 }
546 *size = len;
547 return 0;
548} 533}
549 534
535const char *
536mu_ip_server_addrstr (mu_ip_server_t srv)
537{
538 return mu_sockaddr_str (srv->addr);
539}
540
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 @@
41#include <mailutils/nls.h> 41#include <mailutils/nls.h>
42#include <mailutils/daemon.h> 42#include <mailutils/daemon.h>
43#include <mailutils/acl.h> 43#include <mailutils/acl.h>
44#include <mailutils/sockaddr.h>
45#include <mailutils/url.h>
44 46
45typedef RETSIGTYPE (*mu_sig_handler_t) (int); 47typedef RETSIGTYPE (*mu_sig_handler_t) (int);
46 48
@@ -65,19 +67,6 @@ set_signal (int sig, mu_sig_handler_t handler)
65# define NSIG 64 67# define NSIG 64
66#endif 68#endif
67 69
68union m_sockaddr
69{
70 struct sockaddr s_sa;
71 struct sockaddr_in s_in;
72 struct sockaddr_un s_un;
73};
74
75struct m_default_address
76{
77 union m_sockaddr s;
78 int len;
79};
80
81struct _mu_m_server 70struct _mu_m_server
82{ 71{
83 char *ident; /* Server identifier, for logging purposes.*/ 72 char *ident; /* Server identifier, for logging purposes.*/
@@ -98,7 +87,7 @@ struct _mu_m_server
98 size_t num_children; /* Current number of running sub-processes. */ 87 size_t num_children; /* Current number of running sub-processes. */
99 pid_t *child_pid; 88 pid_t *child_pid;
100 char *pidfile; /* Name of a PID-file. */ 89 char *pidfile; /* Name of a PID-file. */
101 struct m_default_address defaddr; /* Default address. */ 90 struct mu_sockaddr_hints hints; /* Default address hints. */
102 time_t timeout; /* Default idle timeout. */ 91 time_t timeout; /* Default idle timeout. */
103 mu_acl_t acl; /* Global access control list. */ 92 mu_acl_t acl; /* Global access control list. */
104 93
@@ -112,7 +101,7 @@ struct _mu_m_server
112struct m_srv_config /* Configuration data for a single TCP server. */ 101struct m_srv_config /* Configuration data for a single TCP server. */
113{ 102{
114 mu_m_server_t msrv; /* Parent m-server. */ 103 mu_m_server_t msrv; /* Parent m-server. */
115 mu_ip_server_t tcpsrv; /* TCP server these data are for. */ 104 mu_ip_server_t tcpsrv; /* TCP server these data are for. */
116 mu_acl_t acl; /* Access control list for this server. */ 105 mu_acl_t acl; /* Access control list for this server. */
117 int single_process; /* Should it run as a single process? */ 106 int single_process; /* Should it run as a single process? */
118 int transcript; /* Enable session transcript. */ 107 int transcript; /* Enable session transcript. */
@@ -395,33 +384,20 @@ mu_m_server_pidfile (mu_m_server_t srv)
395} 384}
396 385
397void 386void
398mu_m_server_set_default_address (mu_m_server_t srv, struct sockaddr *sa, 387mu_m_server_set_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints)
399 int salen)
400{ 388{
401 if (salen > sizeof srv->defaddr.s) 389 if (!hints)
402 { 390 memset (&srv->hints, 0, sizeof (srv->hints));
403 mu_error (_("unhandled sockaddr size")); 391 else
404 abort (); 392 memcpy (&srv->hints, hints, sizeof (srv->hints));
405 }
406 memcpy (&srv->defaddr.s.s_sa, sa, salen);
407 srv->defaddr.len = salen;
408} 393}
409 394
410int 395int
411mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa, 396mu_m_server_get_hints (mu_m_server_t srv, struct mu_sockaddr_hints *hints)
412 int *salen)
413{ 397{
414 int len; 398 if (!hints)
415
416 if (!sa)
417 return EINVAL; 399 return EINVAL;
418 len = srv->defaddr.len; 400 memcpy (hints, &srv->hints, sizeof (hints));
419 if (sa)
420 {
421 if (*salen < len)
422 return MU_ERR_BUFSPACE;
423 memcpy (sa, &srv->defaddr.s.s_sa, len);
424 }
425 return 0; 401 return 0;
426} 402}
427 403
@@ -429,11 +405,7 @@ mu_m_server_get_default_address (mu_m_server_t srv, struct sockaddr *sa,
429void 405void
430mu_m_server_set_default_port (mu_m_server_t srv, int num) 406mu_m_server_set_default_port (mu_m_server_t srv, int num)
431{ 407{
432 struct sockaddr_in s_in; 408 srv->hints.port = num;
433 s_in.sin_family = AF_INET;
434 s_in.sin_addr.s_addr = htonl (INADDR_ANY);
435 s_in.sin_port = htons (num);
436 mu_m_server_set_default_address (srv, (struct sockaddr*) &s_in, sizeof s_in);
437} 409}
438 410
439void 411void
@@ -473,12 +445,12 @@ static int m_srv_conn (int fd, struct sockaddr *sa, int salen,
473 mu_ip_server_t srv); 445 mu_ip_server_t srv);
474 446
475static struct m_srv_config * 447static struct m_srv_config *
476add_server (mu_m_server_t msrv, struct sockaddr *s, int slen, int type) 448add_server (mu_m_server_t msrv, struct mu_sockaddr *s, int type)
477{ 449{
478 mu_ip_server_t tcpsrv; 450 mu_ip_server_t tcpsrv;
479 struct m_srv_config *pconf; 451 struct m_srv_config *pconf;
480 452
481 MU_ASSERT (mu_ip_server_create (&tcpsrv, s, slen, type)); /* FIXME: type */ 453 MU_ASSERT (mu_ip_server_create (&tcpsrv, s, type)); /* FIXME: type */
482 MU_ASSERT (mu_ip_server_set_conn (tcpsrv, m_srv_conn)); 454 MU_ASSERT (mu_ip_server_set_conn (tcpsrv, m_srv_conn));
483 pconf = calloc (1, sizeof (*pconf)); 455 pconf = calloc (1, sizeof (*pconf));
484 if (!pconf) 456 if (!pconf)
@@ -513,8 +485,21 @@ mu_m_server_begin (mu_m_server_t msrv)
513 alloc_children (msrv); 485 alloc_children (msrv);
514 486
515 mu_list_count (msrv->srvlist, &count); 487 mu_list_count (msrv->srvlist, &count);
516 if (count == 0 && msrv->defaddr.len) 488 if (count == 0)
517 add_server (msrv, &msrv->defaddr.s.s_sa, msrv->defaddr.len, msrv->deftype); 489 {
490 struct mu_sockaddr *ta;
491
492 msrv->hints.flags = MU_AH_PASSIVE;
493 rc = mu_sockaddr_from_node (&ta, NULL, NULL, &msrv->hints);
494 if (rc == 0)
495 while (ta)
496 {
497 struct mu_sockaddr *next = ta->next;
498 ta->next = ta->prev = NULL;
499 add_server (msrv, ta, msrv->deftype);
500 ta = next;
501 }
502 }
518 503
519 if (!msrv->foreground) 504 if (!msrv->foreground)
520 { 505 {
@@ -599,23 +584,13 @@ tcp_conn_free (void *conn_data, void *server_data)
599static int 584static int
600_open_conn (void *item, void *data) 585_open_conn (void *item, void *data)
601{ 586{
602 union
603 {
604 struct sockaddr sa;
605 char pad[512];
606 }
607 addr;
608 int addrlen = sizeof addr;
609 char *p;
610 mu_ip_server_t tcpsrv = item; 587 mu_ip_server_t tcpsrv = item;
611 mu_m_server_t msrv = data; 588 mu_m_server_t msrv = data;
612 int rc = mu_ip_server_open (tcpsrv); 589 int rc = mu_ip_server_open (tcpsrv);
613 if (rc) 590 if (rc)
614 { 591 {
615 mu_ip_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen); 592 mu_error (_("cannot open connection on %s: %s"),
616 p = mu_sockaddr_to_astr (&addr.sa, addrlen); 593 mu_ip_server_addrstr (tcpsrv), mu_strerror (rc));
617 mu_error (_("cannot open connection on %s: %s"), p, mu_strerror (rc));
618 free (p);
619 return 0; 594 return 0;
620 } 595 }
621 rc = mu_server_add_connection (msrv->server, 596 rc = mu_server_add_connection (msrv->server,
@@ -624,10 +599,8 @@ _open_conn (void *item, void *data)
624 tcp_conn_handler, tcp_conn_free); 599 tcp_conn_handler, tcp_conn_free);
625 if (rc) 600 if (rc)
626 { 601 {
627 mu_ip_server_get_sockaddr (tcpsrv, &addr.sa, &addrlen); 602 mu_error (_("cannot add connection %s: %s"),
628 p = mu_sockaddr_to_astr (&addr.sa, addrlen); 603 mu_ip_server_addrstr (tcpsrv), mu_strerror (rc));
629 mu_error (_("cannot add connection %s: %s"), p, mu_strerror (rc));
630 free (p);
631 mu_ip_server_shutdown (tcpsrv); 604 mu_ip_server_shutdown (tcpsrv);
632 mu_ip_server_destroy (&tcpsrv); 605 mu_ip_server_destroy (&tcpsrv);
633 } 606 }
@@ -756,199 +729,55 @@ m_srv_conn (int fd, struct sockaddr *sa, int salen,
756} 729}
757 730
758 731
759
760unsigned short
761get_port (const char *p)
762{
763 if (p)
764 {
765 char *q;
766 unsigned long n = strtoul (p, &q, 0);
767 if (*q == 0)
768 {
769 if (n > USHRT_MAX)
770 {
771 mu_error (_("invalid port number: %s"), p);
772 return 1;
773 }
774
775 return htons (n);
776 }
777 else
778 {
779 struct servent *sp = getservbyname (p, "tcp");
780 if (!sp)
781 return 0;
782 return sp->s_port;
783 }
784 }
785 return 0;
786}
787
788static int
789get_family (const char **pstr, sa_family_t *pfamily)
790{
791 static struct family_tab
792 {
793 int len;
794 char *pfx;
795 int family;
796 } ftab[] = {
797#define S(s,f) { sizeof (#s":") - 1, #s":", f }
798 S (file, AF_UNIX),
799 S (unix, AF_UNIX),
800 S (local, AF_UNIX),
801 S (socket, AF_UNIX),
802 S (inet, AF_INET),
803 S (tcp, AF_INET),
804#undef S
805 { 0 }
806 };
807 struct family_tab *fp;
808
809 const char *str = *pstr;
810 int len = strlen (str);
811 for (fp = ftab; fp->len; fp++)
812 {
813 if (len > fp->len && memcmp (str, fp->pfx, fp->len) == 0)
814 {
815 str += fp->len;
816 if (str[0] == '/' && str[1] == '/')
817 str += 2;
818 *pstr = str;
819 *pfamily = fp->family;
820 return 0;
821 }
822 }
823 return 1;
824}
825
826static int
827is_ip_addr (const char *arg)
828{
829 int dot_count;
830 int digit_count;
831
832 dot_count = 0;
833 digit_count = 0;
834 for (; *arg != 0 && *arg != ':'; arg++)
835 {
836 if (*arg == '.')
837 {
838 if (++dot_count > 3)
839 break;
840 digit_count = 0;
841 }
842 else if (!(mu_isdigit (*arg) && ++digit_count <= 3))
843 return 0;
844 }
845 return dot_count == 3;
846}
847
848int 732int
849_mu_m_server_parse_url (const char *arg, union m_sockaddr *s, 733mu_m_server_parse_url (mu_m_server_t msrv, const char *arg,
850 int *psalen, struct sockaddr *defsa) 734 struct mu_sockaddr **psa)
851{ 735{
852 char *p; 736 int rc;
853 unsigned short n; 737 mu_url_t url, url_hint;
854 int len; 738
855 739 if (arg[0] == '/')
856 if (is_ip_addr (arg)) 740 url_hint = NULL;
857 s->s_sa.sa_family = AF_INET; 741 else
858 else if (get_family (&arg, &s->s_sa.sa_family))
859 { 742 {
860 mu_error (_("invalid family")); 743 rc = mu_url_create (&url_hint, "inet://");
861 return EINVAL; 744 if (rc)
745 return rc;
862 } 746 }
863 747 rc = mu_url_create_hint (&url, arg, MU_URL_PARSE_DEFAULT, url_hint);
864 switch (s->s_sa.sa_family) 748 mu_url_destroy (&url_hint);
749 if (rc)
865 { 750 {
866 case AF_INET: 751 mu_error (_("cannot parse URL `%s': %s"), arg, mu_strerror (rc));
867 *psalen = sizeof (s->s_in); 752 return rc;
868 if ((n = get_port (arg)))
869 {
870 s->s_in.sin_addr.s_addr = htonl (INADDR_ANY);
871 s->s_in.sin_port = htons (n);
872 }
873 else
874 {
875 p = strchr (arg, ':');
876 if (p)
877 *p++ = 0;
878 if (inet_aton (arg, &s->s_in.sin_addr) == 0)
879 {
880 struct hostent *hp = gethostbyname (arg);
881 if (hp)
882 s->s_in.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
883 else
884 {
885 mu_error (_("invalid IP address: %s"), arg);
886 return EINVAL;
887 }
888 }
889 if (p)
890 {
891 n = get_port (p);
892 if (!n)
893 {
894 mu_error (_("invalid port number: %s"), p);
895 return EINVAL;
896 }
897 s->s_in.sin_port = n;
898 }
899 else if (defsa && defsa->sa_family == AF_INET)
900 s->s_in.sin_port = ((struct sockaddr_in*)defsa)->sin_port;
901 else
902 {
903 mu_error (_("missing port number"));
904 return EINVAL;
905 }
906 }
907 break;
908
909 case AF_UNIX:
910 *psalen = sizeof (s->s_un);
911 len = strlen (arg);
912 if (len > sizeof s->s_un.sun_path - 1)
913 {
914 mu_error (_("%s: file name too long"), arg);
915 return EINVAL;
916 }
917 strcpy (s->s_un.sun_path, arg);
918 break;
919 } 753 }
920 return 0;
921}
922
923int
924mu_m_server_parse_url (mu_m_server_t msrv, char *arg,
925 struct sockaddr *sa, int *psalen)
926{
927 int rc;
928 union m_sockaddr s;
929 int salen;
930 754
931 rc = _mu_m_server_parse_url (arg, &s, &salen, &msrv->defaddr.s.s_sa); 755 msrv->hints.flags = MU_AH_PASSIVE;
756 rc = mu_sockaddr_from_url (psa, url, &msrv->hints);
932 if (rc) 757 if (rc)
933 return rc; 758 mu_error (_("cannot create sockaddr for URL `%s': %s"), arg,
934 if (sa) 759 mu_strerror (rc));
935 { 760 mu_url_destroy (&url);
936 if (*psalen < salen) 761 return rc;
937 return MU_ERR_BUFSPACE;
938 memcpy (sa, &s.s_sa, salen);
939 }
940 *psalen = salen;
941 return 0;
942} 762}
943 763
944static int 764static int
945server_block_begin (const char *arg, mu_m_server_t msrv, void **pdata) 765server_block_begin (const char *arg, mu_m_server_t msrv, void **pdata)
946{ 766{
947 union m_sockaddr s; 767 struct mu_sockaddr *s;
948 int salen; 768 if (mu_m_server_parse_url (msrv, arg, &s))
949 if (_mu_m_server_parse_url (arg, &s, &salen, &msrv->defaddr.s.s_sa))
950 return 1; 769 return 1;
951 *pdata = add_server (msrv, &s.s_sa, salen, msrv->deftype); 770 if (s->next)
771 {
772 /* FIXME: (1) Find a way to handle all addresses.
773 (2) Print which address is being used.
774 */
775 mu_diag_output (MU_DIAG_WARNING,
776 _("%s resolves to several addresses, "
777 "only the first is used"), arg);
778 mu_sockaddr_free (s->next);
779 }
780 *pdata = add_server (msrv, s, msrv->deftype);
952 return 0; 781 return 0;
953} 782}
954 783
@@ -1002,21 +831,46 @@ _cb_daemon_mode (void *data, mu_config_value_t *val)
1002 return 0; 831 return 0;
1003} 832}
1004 833
834unsigned short
835get_port (const char *p)
836{
837 if (p)
838 {
839 char *q;
840 unsigned long n = strtoul (p, &q, 0);
841 if (*q == 0)
842 {
843 if (n > USHRT_MAX)
844 {
845 mu_error (_("invalid port number: %s"), p);
846 return 1;
847 }
848
849 return htons (n);
850 }
851 else
852 {
853 struct servent *sp = getservbyname (p, "tcp");
854 if (!sp)
855 return 0;
856 return sp->s_port;
857 }
858 }
859 return 0;
860}
861
1005static int 862static int
1006_cb_port (void *data, mu_config_value_t *val) 863_cb_port (void *data, mu_config_value_t *val)
1007{ 864{
1008 struct m_default_address *ap = data; 865 struct mu_sockaddr_hints *hp = data;
1009 unsigned short num; 866 unsigned short num;
1010 867
1011 if (mu_cfg_assert_value_type (val, MU_CFG_STRING)) 868 if (mu_cfg_assert_value_type (val, MU_CFG_STRING))
1012 return 1; 869 return 1;
1013 num = get_port (val->v.string); 870 num = get_port (val->v.string);
1014 if (!num) 871 if (!num)
1015 return 1; 872 return 1;
1016 ap->s.s_in.sin_family = AF_INET; 873 hp->port = num;
1017 ap->s.s_in.sin_addr.s_addr = htonl (INADDR_ANY);
1018 ap->s.s_in.sin_port = num;
1019 ap->len = sizeof ap->s.s_in;
1020 return 0; 874 return 0;
1021} 875}
1022 876
@@ -1036,7 +890,7 @@ static struct mu_cfg_param dot_server_cfg_param[] = {
1036 N_("Store PID of the master process in this file."), 890 N_("Store PID of the master process in this file."),
1037 N_("file") }, 891 N_("file") },
1038 { "port", mu_cfg_callback, 892 { "port", mu_cfg_callback,
1039 NULL, mu_offsetof (struct _mu_m_server,defaddr), _cb_port, 893 NULL, mu_offsetof (struct _mu_m_server, hints), _cb_port,
1040 N_("Default port number.") }, 894 N_("Default port number.") },
1041 { "timeout", mu_cfg_time, 895 { "timeout", mu_cfg_time,
1042 NULL, mu_offsetof (struct _mu_m_server,timeout), NULL, 896 NULL, mu_offsetof (struct _mu_m_server,timeout), NULL,
diff --git a/libmailutils/sockaddr/Makefile.am b/libmailutils/sockaddr/Makefile.am
new file mode 100644
index 000000000..dcfb18446
--- /dev/null
+++ b/libmailutils/sockaddr/Makefile.am
@@ -0,0 +1,31 @@
1# GNU Mailutils -- a suite of utilities for electronic mail
2# Copyright (C) 2011 Free Software Foundation, Inc.
3#
4# This library is free software; you can redistribute it and/or
5# modify it under the terms of the GNU Lesser General Public
6# License as published by the Free Software Foundation; either
7# version 3 of the License, or (at your option) any later version.
8#
9# This library is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12# Lesser General Public License for more details.
13#
14# You should have received a copy of the GNU Lesser General
15# Public License along with this library. If not, see
16# <http://www.gnu.org/licenses/>.
17
18noinst_LTLIBRARIES = libsockaddr.la
19
20libsockaddr_la_SOURCES = \
21 copy.c\
22 create.c\
23 free.c\
24 fromnode.c\
25 insert.c\
26 ipaddr.c\
27 str.c\
28 unlink.c\
29 url.c
30
31INCLUDES = @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
diff --git a/libmailutils/sockaddr/copy.c b/libmailutils/sockaddr/copy.c
new file mode 100644
index 000000000..5e28e7857
--- /dev/null
+++ b/libmailutils/sockaddr/copy.c
@@ -0,0 +1,36 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <stdlib.h>
23#include <mailutils/sockaddr.h>
24
25int
26mu_sockaddr_copy (struct mu_sockaddr **pnew, struct mu_sockaddr *old)
27{
28 if (!old)
29 {
30 *pnew = NULL;
31 return 0;
32 }
33 return mu_sockaddr_create (pnew, old->addr, old->addrlen);
34}
35
36
diff --git a/libmailutils/sockaddr/create.c b/libmailutils/sockaddr/create.c
new file mode 100644
index 000000000..5b49471e6
--- /dev/null
+++ b/libmailutils/sockaddr/create.c
@@ -0,0 +1,47 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <stdlib.h>
23#include <errno.h>
24#include <string.h>
25#include <mailutils/sockaddr.h>
26
27int
28mu_sockaddr_create (struct mu_sockaddr **res,
29 struct sockaddr *addr, socklen_t len)
30{
31 struct mu_sockaddr *sa;
32
33 sa = calloc (1, sizeof (*sa));
34 if (!sa)
35 return ENOMEM;
36 sa->addr = malloc (len);
37 if (!sa->addr)
38 {
39 free (sa);
40 return ENOMEM;
41 }
42 memcpy (sa->addr, addr, len);
43 sa->addrlen = len;
44 *res = sa;
45 return 0;
46}
47
diff --git a/libmailutils/sockaddr/free.c b/libmailutils/sockaddr/free.c
new file mode 100644
index 000000000..2a31ec36d
--- /dev/null
+++ b/libmailutils/sockaddr/free.c
@@ -0,0 +1,50 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <stdlib.h>
23#include <mailutils/sockaddr.h>
24
25void
26mu_sockaddr_free (struct mu_sockaddr *addr)
27{
28 if (!addr)
29 return;
30 free (addr->addr);
31 free (addr->str);
32}
33
34void
35mu_sockaddr_free_list (struct mu_sockaddr *addr)
36{
37 if (!addr)
38 return;
39 if (addr->prev)
40 addr->prev->next = NULL;
41 while (addr)
42 {
43 struct mu_sockaddr *next = addr->next;
44 mu_sockaddr_free (addr);
45 addr = next;
46 }
47}
48
49
50
diff --git a/libmailutils/sockaddr/fromnode.c b/libmailutils/sockaddr/fromnode.c
new file mode 100644
index 000000000..d79b9523a
--- /dev/null
+++ b/libmailutils/sockaddr/fromnode.c
@@ -0,0 +1,253 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <sys/un.h>
25#include <sys/stat.h>
26#include <netinet/in.h>
27#include <arpa/inet.h>
28#include <netdb.h>
29#include <stdlib.h>
30#include <stdio.h>
31#include <errno.h>
32#include <string.h>
33#include <mailutils/sockaddr.h>
34#include <mailutils/url.h>
35#include <mailutils/io.h>
36#include <mailutils/errno.h>
37#include <mailutils/error.h>
38#include <mailutils/nls.h>
39
40static struct mu_sockaddr *
41match_sa (struct mu_sockaddr *list, struct sockaddr *sa, socklen_t len)
42{
43 for (; list; list = list->next)
44 if (len == list->addrlen && memcmp (list->addr, sa, len) == 0)
45 break;
46 return list;
47}
48
49int
50mu_sockaddr_from_node (struct mu_sockaddr **retval, const char *node,
51 const char *serv, struct mu_sockaddr_hints *mh)
52{
53 int rc;
54
55 if (!mh)
56 {
57 static struct mu_sockaddr_hints nullhints = { 0, AF_UNSPEC };
58 mh = &nullhints;
59 }
60
61 if (mh->family == AF_UNIX)
62 {
63 size_t slen;
64 struct sockaddr_un s_un;
65
66 if (!node)
67 return MU_ERR_NONAME;
68 slen = strlen (node);
69 if (slen >= sizeof s_un.sun_path)
70 return MU_ERR_BUFSPACE;
71
72 s_un.sun_family = AF_UNIX;
73 strcpy(s_un.sun_path, node);
74 return mu_sockaddr_create (retval, (struct sockaddr*) &s_un,
75 sizeof (s_un));
76 }
77 else
78#ifdef MAILUTILS_IPV6
79 {
80 struct addrinfo hints;
81 struct addrinfo *res, *ap;
82 char portbuf[64];
83 struct mu_sockaddr *tail = NULL;
84
85 memset (&hints, 0, sizeof (hints));
86 hints.ai_family = mh->family;
87 hints.ai_socktype = mh->socktype;
88 hints.ai_protocol = mh->protocol;
89
90 if (!node)
91 {
92 if (mh->flags & MU_AH_PASSIVE)
93 hints.ai_flags |= AI_PASSIVE;
94 else
95 return MU_ERR_NONAME;
96 }
97 if (!serv && mh->port)
98 {
99 snprintf (portbuf, sizeof portbuf, "%hu", mh->port);
100 serv = portbuf;
101 }
102
103 rc = getaddrinfo (node, serv, &hints, &res);
104
105 switch (rc)
106 {
107 case 0:
108 break;
109
110 case EAI_FAIL:
111 return MU_ERR_GETHOSTBYNAME;
112
113 case EAI_FAMILY:
114 return MU_ERR_FAMILY;
115
116 case EAI_NONAME:
117 return MU_ERR_NONAME;
118
119 case EAI_SERVICE:
120 return MU_ERR_SERVICE;
121
122 case EAI_SYSTEM:
123 mu_error (_("%s:%s: cannot parse address: %s"),
124 node, serv, mu_strerror (errno));
125 return errno;
126
127 case EAI_BADFLAGS:
128 return MU_ERR_BADFLAGS;
129
130 case EAI_SOCKTYPE:
131 return MU_ERR_SOCKTYPE;
132
133 case EAI_MEMORY:
134 return ENOMEM;
135
136 default:
137 mu_error ("%s:%s: %s", node, serv, gai_strerror (rc));
138 return MU_ERR_FAILURE;
139 }
140
141 *retval = NULL;
142 for (ap = res; ap; ap = ap->ai_next)
143 if (mh->family == AF_UNSPEC || ap->ai_addr->sa_family == mh->family)
144 {
145 struct mu_sockaddr *sa;
146
147 if (match_sa (*retval, ap->ai_addr, ap->ai_addrlen))
148 continue;
149 rc = mu_sockaddr_create (&sa, ap->ai_addr, ap->ai_addrlen);
150 if (rc)
151 {
152 mu_sockaddr_free_list (*retval);
153 freeaddrinfo (res);
154 return rc;
155 }
156 if (tail)
157 mu_sockaddr_insert (tail, sa, 0);
158 else
159 *retval = sa;
160 tail = sa;
161 }
162 freeaddrinfo (res);
163 }
164#else
165 if (mh->family == AF_INET)
166 {
167 short port;
168 struct hostent *hp;
169 struct mu_sockaddr *tail = NULL;
170 char **p;
171
172 if (serv)
173 {
174 char *end;
175 unsigned long n = strtoul (serv, &end, 10);
176
177 if (*end)
178 {
179 struct servent *sp;
180 const char *proto;
181
182 if (mh->protocol)
183 {
184 struct protoent *pp = getprotobynumber (mh->protocol);
185 if (!pp)
186 return EINVAL;
187 proto = pp->p_name;
188 }
189 else
190 proto = NULL;
191
192 sp = getservbyname (serv, proto);
193 if (!sp)
194 return MU_ERR_SERVICE;
195 port = sp->s_port;
196 }
197 else if (n == 0 || (port = n) != n)
198 return MU_ERR_PARSE; /* FIXME: need MU_ERR_RANGE? */
199 }
200 else if (mh->port)
201 port = htons (mh->port);
202 else
203 return MU_ERR_NONAME;
204
205 if (!node)
206 {
207 struct sockaddr_in s_in;
208
209 if (!(mh->flags & MU_AH_PASSIVE))
210 return MU_ERR_NONAME;
211
212 s_in.sin_family = AF_INET;
213 s_in.sin_addr.s_addr = INADDR_ANY;
214 s_in.sin_port = port;
215 return mu_sockaddr_create (retval, (struct sockaddr*)&s_in,
216 sizeof (s_in));
217 }
218
219 hp = gethostbyname (node);
220 if (!hp)
221 return MU_ERR_GETHOSTBYNAME;
222
223 if (hp->h_addrtype != AF_INET || hp->h_length != 4)
224 return MU_ERR_FAMILY;
225
226 for (p = hp->h_addr_list; *p; p++)
227 {
228 struct mu_sockaddr *sa;
229 struct sockaddr_in s_in;
230
231 s_in.sin_family = AF_INET;
232 memcpy(&s_in.sin_addr, *p, 4);
233 s_in.sin_port = port;
234
235 rc = mu_sockaddr_create (&sa, (struct sockaddr*)&s_in,
236 sizeof (s_in));
237 if (rc)
238 {
239 mu_sockaddr_free_list (*retval);
240 return rc;
241 }
242 if (tail)
243 mu_sockaddr_insert (tail, sa, 0);
244 else
245 *retval = sa;
246 tail = sa;
247 }
248 }
249 else
250 return MU_ERR_FAMILY;
251#endif
252 return 0;
253}
diff --git a/libmailutils/sockaddr/insert.c b/libmailutils/sockaddr/insert.c
new file mode 100644
index 000000000..dbac151c1
--- /dev/null
+++ b/libmailutils/sockaddr/insert.c
@@ -0,0 +1,64 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <stdlib.h>
23#include <mailutils/sockaddr.h>
24
25static void
26set_next (struct mu_sockaddr *sp, struct mu_sockaddr *tgt)
27{
28 for (; sp->next; sp = sp->next)
29 ;
30 sp->next = tgt;
31 if (tgt)
32 tgt->prev = sp;
33}
34
35struct mu_sockaddr *
36mu_sockaddr_insert (struct mu_sockaddr *anchor, struct mu_sockaddr *addr,
37 int before)
38{
39 struct mu_sockaddr *ret = anchor;
40
41 if (!anchor)
42 {
43 addr->prev = NULL;
44 set_next (addr, NULL);
45 return addr;
46 }
47
48 if (before)
49 {
50 if (anchor->prev)
51 anchor = anchor->prev;
52 else
53 {
54 addr->prev = NULL;
55 set_next (addr, anchor);
56 return addr;
57 }
58 }
59
60 set_next (addr, anchor->next);
61 anchor->next = addr;
62 addr->prev = anchor;
63 return ret;
64}
diff --git a/libmailutils/sockaddr/ipaddr.c b/libmailutils/sockaddr/ipaddr.c
new file mode 100644
index 000000000..6b14b4c29
--- /dev/null
+++ b/libmailutils/sockaddr/ipaddr.c
@@ -0,0 +1,88 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <string.h>
23#include <mailutils/sockaddr.h>
24#include <mailutils/cctype.h>
25
26int
27mu_str_is_ipv4 (const char *addr)
28{
29 int dot_count = 0;
30 int digit_count = 0;
31
32 for (; *addr; addr++)
33 {
34 if (!mu_isascii (*addr))
35 return 0;
36 if (*addr == '.')
37 {
38 if (++dot_count > 3)
39 break;
40 digit_count = 0;
41 }
42 else if (!(mu_isdigit (*addr) && ++digit_count <= 3))
43 return 0;
44 }
45
46 return (dot_count == 3);
47}
48
49int
50mu_str_is_ipv6 (const char *addr)
51{
52 int col_count = 0; /* Number of colons */
53 int dcol = 0; /* Did we encounter a double-colon? */
54 int dig_count = 0; /* Number of digits in the last group */
55
56 for (; *addr; addr++)
57 {
58 if (!mu_isascii (*addr))
59 return 0;
60 else if (mu_isxdigit (*addr))
61 {
62 if (++dig_count > 4)
63 return 0;
64 }
65 else if (*addr == ':')
66 {
67 if (col_count && dig_count == 0 && ++dcol > 1)
68 return 0;
69 if (++col_count > 7)
70 return 0;
71 dig_count = 0;
72 }
73 else
74 return 0;
75 }
76
77 return (col_count == 7 || dcol);
78}
79
80int
81mu_str_is_ipaddr (const char *addr)
82{
83 if (strchr (addr, '.'))
84 return mu_str_is_ipv4(addr);
85 else if (strchr (addr, ':'))
86 return mu_str_is_ipv6(addr);
87 return 0;
88}
diff --git a/libmailutils/sockaddr/str.c b/libmailutils/sockaddr/str.c
new file mode 100644
index 000000000..949f21ef9
--- /dev/null
+++ b/libmailutils/sockaddr/str.c
@@ -0,0 +1,109 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21#include <sys/types.h>
22#include <sys/socket.h>
23#include <sys/un.h>
24#include <sys/stat.h>
25#include <netinet/in.h>
26#include <arpa/inet.h>
27#include <netdb.h>
28
29#include <mailutils/sockaddr.h>
30#include <mailutils/errno.h>
31#include <mailutils/io.h>
32
33static char *default_sockaddr_text = "[not enogh memory]";
34
35#define S_UN_NAME(sa, salen) \
36 ((salen < mu_offsetof(struct sockaddr_un,sun_path)) ? \
37 "" : (sa)->sun_path)
38
39int
40mu_sockaddr_format (char **pbuf, const struct sockaddr *sa, socklen_t salen)
41{
42 int rc = MU_ERR_FAILURE;
43
44 switch (sa->sa_family)
45 {
46#ifdef MAILUTILS_IPV6
47 case AF_INET:
48 case AF_INET6:
49 {
50 char host[NI_MAXHOST];
51 char srv[NI_MAXSERV];
52 if (getnameinfo (sa, salen,
53 host, sizeof (host), srv, sizeof (srv),
54 NI_NUMERICHOST|NI_NUMERICSERV) == 0)
55 {
56 if (sa->sa_family == AF_INET6)
57 rc = mu_asprintf (pbuf, "inet6://[%s]:%s", host, srv);
58 else
59 rc = mu_asprintf (pbuf, "inet://%s:%s", host, srv);
60 }
61 else
62 rc = mu_asprintf (pbuf, "%s://[getnameinfo failed]",
63 sa->sa_family == AF_INET ?
64 "inet" : "inet6");
65 break;
66 }
67#else
68 case AF_INET:
69 {
70 struct sockaddr_in *s_in = (struct sockaddr_in *)sa;
71 rc = mu_asprintf (pbuf, "inet://%s:%hu",
72 inet_ntoa (s_in->sin_addr), s_in->sin_port);
73 break;
74 }
75#endif
76
77 case AF_UNIX:
78 {
79 struct sockaddr_un *s_un = (struct sockaddr_un *)sa;
80 if (S_UN_NAME (s_un, salen)[0] == 0)
81 rc = mu_asprintf (pbuf, "unix://[anonymous socket]");
82 else
83 rc = mu_asprintf (pbuf, "unix://%s", s_un->sun_path);
84 break;
85 }
86
87 default:
88 rc = mu_asprintf (pbuf, "family:%d", sa->sa_family);
89 }
90 return rc;
91}
92
93char *
94mu_sockaddr_to_astr (const struct sockaddr *sa, int salen)
95{
96 char *buf = NULL;
97 mu_sockaddr_format (&buf, sa, salen);
98 return buf;
99}
100
101const char *
102mu_sockaddr_str (struct mu_sockaddr *sa)
103{
104 if (!sa->str && mu_sockaddr_format (&sa->str, sa->addr, sa->addrlen))
105 return default_sockaddr_text;
106 return sa->str;
107}
108
109
diff --git a/libmailutils/sockaddr/unlink.c b/libmailutils/sockaddr/unlink.c
new file mode 100644
index 000000000..65808f568
--- /dev/null
+++ b/libmailutils/sockaddr/unlink.c
@@ -0,0 +1,45 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <stdlib.h>
23#include <mailutils/sockaddr.h>
24
25struct mu_sockaddr *
26mu_sockaddr_unlink (struct mu_sockaddr *addr)
27{
28 struct mu_sockaddr *p;
29
30 if (!addr)
31 return NULL;
32
33 p = addr->prev;
34 if (p)
35 p->next = addr->next;
36
37 p = addr->next;
38 if (p)
39 p->prev = addr->prev;
40
41 addr->prev = addr->next = NULL;
42
43 return p;
44}
45
diff --git a/libmailutils/sockaddr/url.c b/libmailutils/sockaddr/url.c
new file mode 100644
index 000000000..0eaf870be
--- /dev/null
+++ b/libmailutils/sockaddr/url.c
@@ -0,0 +1,130 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <sys/un.h>
25#include <sys/stat.h>
26#include <netinet/in.h>
27#include <arpa/inet.h>
28#include <netdb.h>
29#include <stdlib.h>
30#include <errno.h>
31#include <string.h>
32#include <mailutils/sockaddr.h>
33#include <mailutils/url.h>
34#include <mailutils/io.h>
35#include <mailutils/errno.h>
36#include <mailutils/nls.h>
37#include <mailutils/kwd.h>
38
39static struct mu_kwd famtab[] = {
40 { "unix", AF_UNIX },
41 { "local", AF_UNIX },
42 { "inet4", AF_INET },
43#ifdef MAILUTILS_IPV6
44 { "inet6", AF_INET6 },
45 { "inet", AF_UNSPEC },
46#else
47 { "inet", AF_INET },
48#endif
49 { NULL }
50};
51
52int
53mu_sockaddr_from_url (struct mu_sockaddr **retval, mu_url_t url,
54 struct mu_sockaddr_hints *mh)
55{
56 int rc;
57 const char *scheme;
58 const char *node = NULL, *serv = NULL;
59 struct mu_sockaddr_hints hints;
60
61 if (mh)
62 memcpy (&hints, mh, sizeof (hints));
63 else
64 {
65 memset (&hints, sizeof(hints), 0);
66 hints.family = AF_UNSPEC;
67 hints.socktype = SOCK_STREAM;
68 hints.protocol = IPPROTO_TCP;
69 }
70
71 if (hints.family == AF_UNSPEC)
72 {
73 rc = mu_url_sget_scheme (url, &scheme);
74 if (rc)
75 return rc;
76
77 if (mu_kwd_xlat_name (famtab, scheme, &hints.family))
78 {
79 if (hints.flags & MU_AH_DETECT_FAMILY)
80 {
81 int flags = 0;
82
83 mu_url_get_flags (url, &flags);
84#ifdef MAILUTILS_IPV6
85 if (flags & MU_URL_IPV6)
86 hints.family = AF_INET6;
87 else
88#endif
89 if (flags & (MU_URL_HOST|MU_URL_PORT))
90 hints.family = AF_INET;
91 else if (flags & MU_URL_PATH)
92 hints.family = AF_UNIX;
93 else
94 return MU_ERR_FAMILY;
95 }
96 else
97 return MU_ERR_FAMILY;
98 }
99 }
100
101 if (hints.family == AF_UNIX)
102 {
103 rc = mu_url_sget_path (url, &node);
104 if (rc)
105 {
106 if (rc == MU_ERR_NOENT)
107 {
108 rc = mu_url_sget_host (url, &node);
109 if (rc == MU_ERR_NOENT)
110 return MU_ERR_NONAME;
111 }
112 if (rc)
113 return rc;
114 }
115 }
116 else
117 {
118#ifdef MAILUTILS_IPV6
119 if (hints.family == AF_UNSPEC)
120 hints.family = mu_url_has_flag (url, MU_URL_IPV6) ? AF_INET6 : AF_INET;
121#endif
122 rc = mu_url_sget_host (url, &node);
123 if (rc && rc != MU_ERR_NOENT)
124 return MU_ERR_NONAME;
125 rc = mu_url_sget_portstr (url, &serv);
126 if (rc && rc != MU_ERR_NOENT)
127 return MU_ERR_NONAME;
128 }
129 return mu_sockaddr_from_node (retval, node, serv, &hints);
130}
diff --git a/libmailutils/stream/tcp.c b/libmailutils/stream/tcp.c
index 40b37124d..f383f1b5a 100644
--- a/libmailutils/stream/tcp.c
+++ b/libmailutils/stream/tcp.c
@@ -39,7 +39,7 @@
39#include <mailutils/errno.h> 39#include <mailutils/errno.h>
40#include <mailutils/stream.h> 40#include <mailutils/stream.h>
41#include <mailutils/util.h> 41#include <mailutils/util.h>
42 42#include <mailutils/sockaddr.h>
43#include <mailutils/sys/stream.h> 43#include <mailutils/sys/stream.h>
44 44
45#define TCP_STATE_INIT 1 45#define TCP_STATE_INIT 1
@@ -52,18 +52,11 @@ struct _tcp_instance
52{ 52{
53 struct _mu_stream stream; 53 struct _mu_stream stream;
54 int fd; 54 int fd;
55 char *host;
56 unsigned short port;
57 int state; 55 int state;
58 unsigned long address; 56 struct mu_sockaddr *remote_addr;
59 unsigned long source_addr; 57 struct mu_sockaddr *source_addr;
60}; 58};
61 59
62/* On solaris inet_addr() return -1. */
63#ifndef INADDR_NONE
64# define INADDR_NONE (unsigned long)-1
65#endif
66
67static int 60static int
68_tcp_close (mu_stream_t stream) 61_tcp_close (mu_stream_t stream)
69{ 62{
@@ -83,28 +76,12 @@ _tcp_close (mu_stream_t stream)
83} 76}
84 77
85static int 78static int
86resolve_hostname (const char *host, unsigned long *ip)
87{
88 unsigned long address = inet_addr (host);
89 if (address == INADDR_NONE)
90 {
91 struct hostent *phe = gethostbyname (host);
92 if (!phe)
93 return MU_ERR_GETHOSTBYNAME;
94 address = *(((unsigned long **) phe->h_addr_list)[0]);
95 }
96 *ip = address;
97 return 0;
98}
99
100static int
101_tcp_open (mu_stream_t stream) 79_tcp_open (mu_stream_t stream)
102{ 80{
103 struct _tcp_instance *tcp = (struct _tcp_instance *)stream; 81 struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
104 int flgs, ret; 82 int flgs, ret;
105 socklen_t namelen; 83 socklen_t namelen;
106 struct sockaddr_in peer_addr; 84 struct sockaddr_in peer_addr;
107 struct sockaddr_in soc_addr;
108 int flags; 85 int flags;
109 86
110 mu_stream_get_flags (stream, &flags); 87 mu_stream_get_flags (stream, &flags);
@@ -114,7 +91,8 @@ _tcp_open (mu_stream_t stream)
114 case TCP_STATE_INIT: 91 case TCP_STATE_INIT:
115 if (tcp->fd == -1) 92 if (tcp->fd == -1)
116 { 93 {
117 if ((tcp->fd = socket (PF_INET, SOCK_STREAM, 0)) == -1) 94 tcp->fd = socket (tcp->remote_addr->addr->sa_family, SOCK_STREAM, 0);
95 if (tcp->fd == -1)
118 return errno; 96 return errno;
119 } 97 }
120 if (flags & MU_STREAM_NONBLOCK) 98 if (flags & MU_STREAM_NONBLOCK)
@@ -124,13 +102,10 @@ _tcp_open (mu_stream_t stream)
124 fcntl (tcp->fd, F_SETFL, flgs); 102 fcntl (tcp->fd, F_SETFL, flgs);
125 mu_stream_set_flags (stream, MU_STREAM_NONBLOCK); 103 mu_stream_set_flags (stream, MU_STREAM_NONBLOCK);
126 } 104 }
127 if (tcp->source_addr != INADDR_ANY) 105 if (tcp->source_addr)
128 { 106 {
129 struct sockaddr_in s; 107 if (bind (tcp->fd, tcp->source_addr->addr,
130 s.sin_family = AF_INET; 108 tcp->source_addr->addrlen) < 0)
131 s.sin_addr.s_addr = tcp->source_addr;
132 s.sin_port = 0;
133 if (bind (tcp->fd, (struct sockaddr*) &s, sizeof(s)) < 0)
134 { 109 {
135 int e = errno; 110 int e = errno;
136 close (tcp->fd); 111 close (tcp->fd);
@@ -142,27 +117,11 @@ _tcp_open (mu_stream_t stream)
142 tcp->state = TCP_STATE_RESOLVING; 117 tcp->state = TCP_STATE_RESOLVING;
143 118
144 case TCP_STATE_RESOLVING: 119 case TCP_STATE_RESOLVING:
145 if (!(tcp->host != NULL && tcp->port > 0))
146 {
147 _tcp_close (stream);
148 return EINVAL;
149 }
150
151 if ((ret = resolve_hostname (tcp->host, &tcp->address)))
152 {
153 _tcp_close (stream);
154 return ret;
155 }
156 tcp->state = TCP_STATE_RESOLVE; 120 tcp->state = TCP_STATE_RESOLVE;
157 121
158 case TCP_STATE_RESOLVE: 122 case TCP_STATE_RESOLVE:
159 memset (&soc_addr, 0, sizeof (soc_addr)); 123 if (connect (tcp->fd, tcp->remote_addr->addr,
160 soc_addr.sin_family = AF_INET; 124 tcp->remote_addr->addrlen) == -1)
161 soc_addr.sin_port = htons (tcp->port);
162 soc_addr.sin_addr.s_addr = tcp->address;
163
164 if ((connect (tcp->fd,
165 (struct sockaddr *) &soc_addr, sizeof (soc_addr))) == -1)
166 { 125 {
167 ret = errno; 126 ret = errno;
168 if (ret == EINPROGRESS || ret == EAGAIN) 127 if (ret == EINPROGRESS || ret == EAGAIN)
@@ -254,10 +213,8 @@ _tcp_done (mu_stream_t stream)
254{ 213{
255 struct _tcp_instance *tcp = (struct _tcp_instance *)stream; 214 struct _tcp_instance *tcp = (struct _tcp_instance *)stream;
256 215
257 if (tcp->host) 216 mu_sockaddr_free (tcp->remote_addr);
258 free (tcp->host); 217 mu_sockaddr_free (tcp->source_addr);
259 if (tcp->fd != -1)
260 close (tcp->fd);
261} 218}
262 219
263int 220int
@@ -315,33 +272,21 @@ _create_tcp_stream (int flags)
315} 272}
316 273
317int 274int
318mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream, 275mu_tcp_stream_create_from_sa (mu_stream_t *pstream,
319 const char *host, unsigned port, 276 struct mu_sockaddr *remote_addr,
320 unsigned long source_ip, 277 struct mu_sockaddr *source_addr, int flags)
321 int flags)
322{ 278{
323 int rc; 279 int rc;
324 mu_stream_t stream; 280 mu_stream_t stream;
325 struct _tcp_instance *tcp; 281 struct _tcp_instance *tcp;
326 282
327 if (host == NULL)
328 return MU_ERR_TCP_NO_HOST;
329
330 if (port > USHRT_MAX)
331 return MU_ERR_TCP_NO_PORT;
332
333 tcp = _create_tcp_stream (flags | MU_STREAM_RDWR); 283 tcp = _create_tcp_stream (flags | MU_STREAM_RDWR);
334 if (!tcp) 284 if (!tcp)
335 return ENOMEM; 285 return ENOMEM;
336 tcp->host = strdup (host); 286
337 if (!tcp->host) 287 tcp->remote_addr = remote_addr;
338 { 288 tcp->source_addr = source_addr;
339 free (tcp); 289
340 return ENOMEM;
341 }
342 tcp->port = port;
343 tcp->state = TCP_STATE_INIT;
344 tcp->source_addr = source_ip;
345 stream = (mu_stream_t) tcp; 290 stream = (mu_stream_t) tcp;
346 rc = mu_stream_open (stream); 291 rc = mu_stream_open (stream);
347 if (rc == 0 || rc == EAGAIN || rc == EINPROGRESS) 292 if (rc == 0 || rc == EAGAIN || rc == EINPROGRESS)
@@ -351,24 +296,93 @@ mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
351 return rc; 296 return rc;
352} 297}
353 298
299
300int
301mu_tcp_stream_create_with_source_ip (mu_stream_t *pstream,
302 const char *host, unsigned port,
303 unsigned long source_ip,
304 int flags)
305{
306 int rc;
307 struct mu_sockaddr *remote_addr, *source_addr = NULL;
308 struct mu_sockaddr_hints hints;
309
310 memset (&hints, 0, sizeof hints);
311 hints.family = AF_INET;
312 hints.socktype = SOCK_STREAM;
313 hints.protocol = IPPROTO_TCP;
314 hints.port = port;
315 rc = mu_sockaddr_from_node (&remote_addr, host, NULL, &hints);
316 if (rc)
317 return rc;
318
319 if (source_ip)
320 {
321 struct sockaddr_in s;
322 s.sin_family = AF_INET;
323 s.sin_addr.s_addr = source_ip;
324 s.sin_port = 0;
325 rc = mu_sockaddr_create (&source_addr, (struct sockaddr*)&s,
326 sizeof (s));
327 if (rc)
328 {
329 mu_sockaddr_free (remote_addr);
330 return 0;
331 }
332 }
333
334 rc = mu_tcp_stream_create_from_sa (pstream, remote_addr, source_addr, flags);
335 if (rc)
336 {
337 mu_sockaddr_free (remote_addr);
338 mu_sockaddr_free (source_addr);
339 }
340 return rc;
341}
342
354int 343int
355mu_tcp_stream_create_with_source_host (mu_stream_t *stream, 344mu_tcp_stream_create_with_source_host (mu_stream_t *stream,
356 const char *host, unsigned port, 345 const char *host, unsigned port,
357 const char *source_host, 346 const char *source_host,
358 int flags) 347 int flags)
359{ 348{
360 unsigned long source_addr; 349 int rc;
361 int ret = resolve_hostname (source_host, &source_addr); 350 struct mu_sockaddr *remote_addr, *source_addr = NULL;
362 if (ret == 0) 351 struct mu_sockaddr_hints hints;
363 ret = mu_tcp_stream_create_with_source_ip (stream, host, port, 352
364 source_addr, flags); 353 memset (&hints, 0, sizeof hints);
365 return ret; 354 hints.family = AF_INET;
355 hints.socktype = SOCK_STREAM;
356 hints.port = port;
357 rc = mu_sockaddr_from_node (&remote_addr, host, NULL, &hints);
358 if (rc)
359 return rc;
360
361 if (source_host)
362 {
363 hints.flags = MU_AH_PASSIVE;
364 hints.port = 0;
365 rc = mu_sockaddr_from_node (&source_addr, source_host, NULL, &hints);
366 if (rc)
367 {
368 mu_sockaddr_free (remote_addr);
369 return 0;
370 }
371 }
372
373 rc = mu_tcp_stream_create_from_sa (stream, remote_addr, source_addr, flags);
374 if (rc)
375 {
376 mu_sockaddr_free (remote_addr);
377 mu_sockaddr_free (source_addr);
378 }
379 return rc;
366} 380}
367 381
368int 382int
369mu_tcp_stream_create (mu_stream_t *stream, const char *host, unsigned port, 383mu_tcp_stream_create (mu_stream_t *stream, const char *host, unsigned port,
370 int flags) 384 int flags)
371{ 385{
372 return mu_tcp_stream_create_with_source_ip (stream, host, port, 386 return mu_tcp_stream_create_with_source_host (stream, host, port,
373 INADDR_ANY, flags); 387 NULL, flags);
374} 388}
diff --git a/libmailutils/tests/.gitignore b/libmailutils/tests/.gitignore
index d205efe63..d01d4ad93 100644
--- a/libmailutils/tests/.gitignore
+++ b/libmailutils/tests/.gitignore
@@ -1,5 +1,6 @@
1atconfig 1atconfig
2atlocal 2atlocal
3cidr
3package.m4 4package.m4
4testsuite 5testsuite
5testsuite.dir 6testsuite.dir
diff --git a/libmailutils/tests/Makefile.am b/libmailutils/tests/Makefile.am
index 68618a1df..5c0087398 100644
--- a/libmailutils/tests/Makefile.am
+++ b/libmailutils/tests/Makefile.am
@@ -41,6 +41,7 @@ $(srcdir)/package.m4: $(top_srcdir)/configure.ac
41INCLUDES = @MU_LIB_COMMON_INCLUDES@ 41INCLUDES = @MU_LIB_COMMON_INCLUDES@
42noinst_PROGRAMS = \ 42noinst_PROGRAMS = \
43 addr\ 43 addr\
44 cidr\
44 debugspec\ 45 debugspec\
45 decode2047\ 46 decode2047\
46 encode2047\ 47 encode2047\
diff --git a/libmailutils/tests/cidr.c b/libmailutils/tests/cidr.c
new file mode 100644
index 000000000..797fb248e
--- /dev/null
+++ b/libmailutils/tests/cidr.c
@@ -0,0 +1,77 @@
1/* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21#include <stdlib.h>
22#include <stdio.h>
23#include <mailutils/mailutils.h>
24
25static void
26print_bytes (unsigned char *b, size_t l)
27{
28 for (; l; l--, b++)
29 printf (" %02x", *b);
30 printf ("\n");
31}
32
33int
34main (int argc, char **argv)
35{
36 mu_set_program_name (argv[0]);
37 if (argc < 2)
38 {
39 mu_error ("usage: %s CIDR [CIDR...]", argv[0]);
40 return 1;
41 }
42
43 while (--argc)
44 {
45 char *arg = *++argv;
46 struct mu_cidr cidr;
47 int rc;
48 char *str;
49
50 rc = mu_cidr_from_string (&cidr, arg);
51 if (rc)
52 {
53 mu_error ("%s: %s", arg, mu_strerror (rc));
54 continue;
55 }
56
57 printf ("%s:\n", arg);
58 printf ("family = %d\n", cidr.family);
59 printf ("len = %d\n", cidr.len);
60 printf ("address =");
61 print_bytes (cidr.address, cidr.len);
62 printf ("netmask =");
63 print_bytes (cidr.netmask, cidr.len);
64 rc = mu_cidr_format (&cidr, 0, &str);
65 if (rc)
66 {
67 mu_error ("cannot covert to string: %s", mu_strerror (rc));
68 return 2;
69 }
70
71 printf ("string = %s\n", str);
72 free (str);
73 }
74 return 0;
75}
76
77
diff --git a/libmailutils/tests/url-parse.c b/libmailutils/tests/url-parse.c
index 86c917315..48dd40f84 100644
--- a/libmailutils/tests/url-parse.c
+++ b/libmailutils/tests/url-parse.c
@@ -25,6 +25,7 @@
25#include <mailutils/errno.h> 25#include <mailutils/errno.h>
26#include <mailutils/url.h> 26#include <mailutils/url.h>
27#include <mailutils/secret.h> 27#include <mailutils/secret.h>
28#include <mailutils/kwd.h>
28 29
29#define CAT2(a,b) a ## b 30#define CAT2(a,b) a ## b
30 31
@@ -73,12 +74,52 @@ print_query (mu_url_t url)
73 printf ("query[%lu] <%s>\n", (unsigned long) i, qargv[i]); 74 printf ("query[%lu] <%s>\n", (unsigned long) i, qargv[i]);
74} 75}
75 76
77struct mu_kwd parse_kwtab[] = {
78 { "hexcode", MU_URL_PARSE_HEXCODE },
79 { "hidepass", MU_URL_PARSE_HIDEPASS },
80 { "portsrv", MU_URL_PARSE_PORTSRV },
81 { "portwc", MU_URL_PARSE_PORTWC },
82 { "pipe", MU_URL_PARSE_PIPE },
83 { "slash", MU_URL_PARSE_SLASH },
84 { "dslash_optional", MU_URL_PARSE_DSLASH_OPTIONAL },
85 { "default", MU_URL_PARSE_DEFAULT },
86 { "all", MU_URL_PARSE_ALL },
87 { NULL }
88};
89
90
76int 91int
77main () 92main (int argc, char **argv)
78{ 93{
79 char str[1024]; 94 char str[1024];
80 unsigned port = 0; 95 unsigned port = 0;
81 mu_url_t u = NULL; 96 mu_url_t u = NULL, uhint = NULL;
97 int i;
98 int parse_flags = 0;
99 int rc;
100
101 mu_set_program_name (argv[0]);
102 for (i = 1; i < argc; i++)
103 {
104 int flag;
105
106 if (strncmp (argv[i], "hint=", 5) == 0)
107 {
108 rc = mu_url_create (&uhint, argv[i] + 5);
109 if (rc)
110 {
111 mu_error ("cannot create hints: %s", mu_strerror (rc));
112 exit (1);
113 }
114 }
115 else if (mu_kwd_xlat_name_ci (parse_kwtab, argv[i], &flag) == 0)
116 parse_flags |= flag;
117 else
118 {
119 mu_error ("%s: unknown flag %s", argv[0], argv[i]);
120 exit (1);
121 }
122 }
82 123
83 while (fgets (str, sizeof (str), stdin) != NULL) 124 while (fgets (str, sizeof (str), stdin) != NULL)
84 { 125 {
@@ -89,9 +130,9 @@ main ()
89 str[strlen (str) - 1] = '\0'; /* chop newline */ 130 str[strlen (str) - 1] = '\0'; /* chop newline */
90 if (strspn (str, " \t") == strlen (str)) 131 if (strspn (str, " \t") == strlen (str))
91 continue; /* skip empty lines */ 132 continue; /* skip empty lines */
92 if ((rc = mu_url_create (&u, str)) != 0) 133 if ((rc = mu_url_create_hint (&u, str, parse_flags, uhint)) != 0)
93 { 134 {
94 fprintf (stderr, "mu_url_create %s ERROR: [%d] %s", 135 fprintf (stderr, "mu_url_create %s ERROR: [%d] %s\n",
95 str, rc, mu_strerror (rc)); 136 str, rc, mu_strerror (rc));
96 exit (1); 137 exit (1);
97 } 138 }
diff --git a/libmailutils/tests/url.at b/libmailutils/tests/url.at
index 8c392ea0e..c0669e2aa 100644
--- a/libmailutils/tests/url.at
+++ b/libmailutils/tests/url.at
@@ -20,10 +20,11 @@ dnl TESTURL([NAME], [KW = `'], [INPUT], [STDOUT = `'],
20dnl [STDERR = `'], [RUN-IF-FAIL], [RUN-IF-PASS]) 20dnl [STDERR = `'], [RUN-IF-FAIL], [RUN-IF-PASS])
21dnl 21dnl
22 22
23m4_pushdef([URL_PARSE_OPTIONS])
23m4_pushdef([TESTURL],[ 24m4_pushdef([TESTURL],[
24m4_pushdef([MU_TEST_GROUP],[Url]) 25m4_pushdef([MU_TEST_GROUP],[Url])
25m4_pushdef([MU_TEST_KEYWORDS],[url]) 26m4_pushdef([MU_TEST_KEYWORDS],[url])
26m4_pushdef([MU_TEST_COMMAND],[url-parse]) 27m4_pushdef([MU_TEST_COMMAND],[url-parse URL_PARSE_OPTIONS])
27MU_GENERIC_TEST([$1],[$2 url-m4_translit($3,[ ],[_])],[$3],[],[$4],[$5]) 28MU_GENERIC_TEST([$1],[$2 url-m4_translit($3,[ ],[_])],[$3],[],[$4],[$5])
28m4_popdef([MU_TEST_COMMAND]) 29m4_popdef([MU_TEST_COMMAND])
29m4_popdef([MU_TEST_KEYWORDS]) 30m4_popdef([MU_TEST_KEYWORDS])
@@ -32,6 +33,8 @@ m4_popdef([MU_TEST_GROUP])
32 33
33dnl ------------------------------------------------------------ 34dnl ------------------------------------------------------------
34 35
36m4_define([URL_PARSE_OPTIONS],[default dslash_optional])
37
35TESTURL([],[], 38TESTURL([],[],
36[scheme:], 39[scheme:],
37[scheme <scheme> 40[scheme <scheme>
@@ -76,6 +79,10 @@ port 0
76path </absolute/path> 79path </absolute/path>
77]) 80])
78 81
82dnl ------------------------------------------------------------
83
84m4_define([URL_PARSE_OPTIONS],[default])
85
79TESTURL([],[], 86TESTURL([],[],
80[scheme://%75%73%65%72:%70%61%73%73@%68%6f%73%74], 87[scheme://%75%73%65%72:%70%61%73%73@%68%6f%73%74],
81[scheme <scheme> 88[scheme <scheme>
@@ -198,7 +205,7 @@ path </a/path>
198]) 205])
199 206
200TESTURL([],[], 207TESTURL([],[],
201[ftp:/a/path], 208[ftp:///a/path],
202[scheme <ftp> 209[scheme <ftp>
203user <> 210user <>
204passwd <> 211passwd <>
@@ -716,6 +723,7 @@ path <mbox/user@host>
716param[0] <type=pass> 723param[0] <type=pass>
717]]) 724]])
718 725
726m4_pushdef([URL_PARSE_OPTIONS],[default dslash_optional])
719TESTURL([],[], 727TESTURL([],[],
720[mbox:/var/spool/mail;type=index;param=2;user=gray], 728[mbox:/var/spool/mail;type=index;param=2;user=gray],
721[[scheme <mbox> 729[[scheme <mbox>
@@ -729,6 +737,7 @@ param[0] <type=index>
729param[1] <param=2> 737param[1] <param=2>
730param[2] <user=gray> 738param[2] <user=gray>
731]]) 739]])
740m4_popdef([URL_PARSE_OPTIONS])
732 741
733TESTURL([],[], 742TESTURL([],[],
734[mbox:///var/spool/mail;type=index;param=2;user=gray], 743[mbox:///var/spool/mail;type=index;param=2;user=gray],
@@ -823,3 +832,4 @@ query[1] <list@dom>
823]]) 832]])
824 833
825m4_popdef([TESTURL]) 834m4_popdef([TESTURL])
835m4_popdef([URL_PARSE_OPTIONS])
diff --git a/libmailutils/url/create.c b/libmailutils/url/create.c
index e58064081..130b7a2bc 100644
--- a/libmailutils/url/create.c
+++ b/libmailutils/url/create.c
@@ -59,9 +59,9 @@ getkn (struct mu_url_ctx *ctx, char *delim)
59 size_t n; 59 size_t n;
60 60
61 if (*ctx->cur == 0) 61 if (*ctx->cur == 0)
62 return -1; 62 return MU_ERR_PARSE;
63 n = strcspn (ctx->cur, delim); 63 n = strcspn (ctx->cur, delim);
64 if (n > ctx->toksize) 64 if (n + 1 > ctx->toksize)
65 { 65 {
66 char *p = realloc (ctx->tokbuf, n + 1); 66 char *p = realloc (ctx->tokbuf, n + 1);
67 if (!p) 67 if (!p)
@@ -220,11 +220,28 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host)
220 int rc; 220 int rc;
221 mu_url_t url = ctx->url; 221 mu_url_t url = ctx->url;
222 222
223 rc = getkn (ctx, ":/;?"); 223 rc = getkn (ctx, "[:/;?");
224 if (rc) 224 if (rc)
225 return rc; 225 return rc;
226 226
227 if (ctx->toklen) 227 if (*ctx->cur == '[')
228 {
229 /* Possibly IPv6 address */
230 rc = getkn (ctx, "]/;?");
231 if (rc)
232 return rc;
233 if (*ctx->cur == ']')
234 {
235 ctx->cur++;
236 rc = str_assign (&url->host, ctx->tokbuf + 1);
237 if (rc)
238 return rc;
239 url->flags |= MU_URL_HOST | MU_URL_IPV6;
240 has_host = 1;
241 }
242 }
243
244 if (!(url->flags & MU_URL_HOST) && ctx->toklen)
228 { 245 {
229 rc = str_assign (&url->host, ctx->tokbuf); 246 rc = str_assign (&url->host, ctx->tokbuf);
230 if (rc) 247 if (rc)
@@ -232,22 +249,20 @@ _mu_url_ctx_parse_host (struct mu_url_ctx *ctx, int has_host)
232 url->flags |= MU_URL_HOST; 249 url->flags |= MU_URL_HOST;
233 has_host = 1; 250 has_host = 1;
234 } 251 }
235 252
236 if (*ctx->cur == ':') 253 if (*ctx->cur == ':')
237 { 254 {
238 ctx->cur++;
239 has_host = 1; 255 has_host = 1;
240 256 ctx->cur++;
241 rc = getkn (ctx, "/;?"); 257 rc = getkn (ctx, ":/;?");
242 if (rc) 258 if (rc)
243 return rc; 259 return rc;
244
245 rc = str_assign (&url->portstr, ctx->tokbuf); 260 rc = str_assign (&url->portstr, ctx->tokbuf);
246 if (rc) 261 if (rc)
247 return rc; 262 return rc;
248 url->flags |= MU_URL_PORT; 263 url->flags |= MU_URL_PORT;
249 } 264 }
250 265
251 if (*ctx->cur == '/') 266 if (*ctx->cur == '/')
252 { 267 {
253 if (has_host) 268 if (has_host)
@@ -269,7 +284,9 @@ _mu_url_ctx_parse_cred (struct mu_url_ctx *ctx)
269 int rc, has_cred; 284 int rc, has_cred;
270 mu_url_t url = ctx->url; 285 mu_url_t url = ctx->url;
271 const char *save = ctx->cur; 286 const char *save = ctx->cur;
272 287
288 if (*ctx->cur == 0)
289 return 0;
273 rc = getkn (ctx, "@"); 290 rc = getkn (ctx, "@");
274 if (rc) 291 if (rc)
275 return rc; 292 return rc;
@@ -343,12 +360,18 @@ _mu_url_ctx_parse (struct mu_url_ctx *ctx)
343{ 360{
344 int rc; 361 int rc;
345 mu_url_t url = ctx->url; 362 mu_url_t url = ctx->url;
363 const char *save = ctx->cur;
346 364
347 /* Parse the scheme part */ 365 /* Parse the scheme part */
366 if (*ctx->cur == ':')
367 return _mu_url_ctx_parse_cred (ctx);
368
348 rc = getkn (ctx, ":/"); 369 rc = getkn (ctx, ":/");
349 if (rc) 370 if (rc)
350 return rc; 371 return rc;
351 if (*ctx->cur == ':') 372 if (*ctx->cur == ':'
373 && ((ctx->flags & MU_URL_PARSE_DSLASH_OPTIONAL)
374 || (ctx->cur[1] == '/' && ctx->cur[2] == '/')))
352 { 375 {
353 rc = str_assign (&url->scheme, ctx->tokbuf); 376 rc = str_assign (&url->scheme, ctx->tokbuf);
354 if (rc) 377 if (rc)
@@ -356,7 +379,12 @@ _mu_url_ctx_parse (struct mu_url_ctx *ctx)
356 url->flags |= MU_URL_SCHEME; 379 url->flags |= MU_URL_SCHEME;
357 ctx->cur++; 380 ctx->cur++;
358 } 381 }
359 382 else
383 {
384 ctx->cur = save;
385 return _mu_url_ctx_parse_cred (ctx);
386 }
387
360 if (*ctx->cur == 0) 388 if (*ctx->cur == 0)
361 return 0; 389 return 0;
362 390
@@ -535,5 +563,6 @@ mu_url_create (mu_url_t *purl, const char *str)
535 MU_URL_PARSE_HIDEPASS | 563 MU_URL_PARSE_HIDEPASS |
536 MU_URL_PARSE_PORTSRV | 564 MU_URL_PARSE_PORTSRV |
537 MU_URL_PARSE_PIPE | 565 MU_URL_PARSE_PIPE |
538 MU_URL_PARSE_SLASH, NULL); 566 MU_URL_PARSE_SLASH |
567 MU_URL_PARSE_DSLASH_OPTIONAL, NULL);
539} 568}

Return to:

Send suggestions and report system problems to the System administrator.