1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2011-2021 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
39 static 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
52 int
mu_sockaddr_from_url(struct mu_sockaddr ** retval,mu_url_t url,struct mu_sockaddr_hints * mh)53 mu_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, 0, sizeof(hints));
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 }
131