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