Postfix3.3.1
host_port.c
[詳解]
1 /*++
2 /* NAME
3 /* host_port 3
4 /* SUMMARY
5 /* split string into host and port, destroy string
6 /* SYNOPSIS
7 /* #include <host_port.h>
8 /*
9 /* const char *host_port(string, host, def_host, port, def_service)
10 /* char *string;
11 /* char **host;
12 /* char *def_host;
13 /* char **port;
14 /* char *def_service;
15 /* DESCRIPTION
16 /* host_port() splits a string into substrings with the host
17 /* name or address, and the service name or port number.
18 /* The input string is modified.
19 /*
20 /* Host/domain names are validated with valid_utf8_hostname(),
21 /* and host addresses are validated with valid_hostaddr().
22 /*
23 /* The following input formats are understood (null means
24 /* a null pointer argument):
25 /*
26 /* When def_service is not null, and def_host is null:
27 /*
28 /* [host]:port, [host]:, [host]
29 /*
30 /* host:port, host:, host
31 /*
32 /* When def_host is not null, and def_service is null:
33 /*
34 /* :port, port
35 /*
36 /* Other combinations of def_service and def_host are
37 /* not supported and produce undefined results.
38 /* DIAGNOSTICS
39 /* The result is a null pointer in case of success.
40 /* In case of problems the result is a string pointer with
41 /* the problem type.
42 /* CLIENT EXAMPLE
43 /* .ad
44 /* .fi
45 /* Typical client usage allows the user to omit the service port,
46 /* in which case the client connects to a pre-determined default
47 /* port:
48 /* .nf
49 /* .na
50 /*
51 /* buf = mystrdup(endpoint);
52 /* if ((parse_error = host_port(buf, &host, NULL, &port, defport)) != 0)
53 /* msg_fatal("%s in \"%s\"", parse_error, endpoint);
54 /* if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res)) != 0)
55 /* msg_fatal("%s: %s", endpoint, MAI_STRERROR(aierr));
56 /* myfree(buf);
57 /* SERVER EXAMPLE
58 /* .ad
59 /* .fi
60 /* Typical server usage allows the user to omit the host, meaning
61 /* listen on all available network addresses:
62 /* .nf
63 /* .na
64 /*
65 /* buf = mystrdup(endpoint);
66 /* if ((parse_error = host_port(buf, &host, "", &port, NULL)) != 0)
67 /* msg_fatal("%s in \"%s\"", parse_error, endpoint);
68 /* if (*host == 0)
69 /* host = 0;
70 /* if ((aierr = hostname_to_sockaddr(host, port, SOCK_STREAM, &res)) != 0)
71 /* msg_fatal("%s: %s", endpoint, MAI_STRERROR(aierr));
72 /* myfree(buf);
73 /* LICENSE
74 /* .ad
75 /* .fi
76 /* The Secure Mailer license must be distributed with this software.
77 /* AUTHOR(S)
78 /* Wietse Venema
79 /* IBM T.J. Watson Research
80 /* P.O. Box 704
81 /* Yorktown Heights, NY 10598, USA
82 /*--*/
83 
84 /* System library. */
85 
86 #include <sys_defs.h>
87 #include <string.h>
88 #include <ctype.h>
89 
90 /* Utility library. */
91 
92 #include <msg.h>
93 #include <split_at.h>
94 #include <stringops.h> /* XXX util_utf8_enable */
95 #include <valid_utf8_hostname.h>
96 
97 /* Global library. */
98 
99 #include <host_port.h>
100 
101  /*
102  * Point-fix workaround. The libutil library should be email agnostic, but
103  * we can't rip up the library APIs in the stable releases.
104  */
105 #include <string.h>
106 #ifdef STRCASECMP_IN_STRINGS_H
107 #include <strings.h>
108 #endif
109 #define IPV6_COL "IPv6:" /* RFC 2821 */
110 #define IPV6_COL_LEN (sizeof(IPV6_COL) - 1)
111 #define HAS_IPV6_COL(str) (strncasecmp((str), IPV6_COL, IPV6_COL_LEN) == 0)
112 
113 /* host_port - parse string into host and port, destroy string */
114 
115 const char *host_port(char *buf, char **host, char *def_host,
116  char **port, char *def_service)
117 {
118  char *cp = buf;
119  int ipv6 = 0;
120 
121  /*-
122  * [host]:port, [host]:, [host].
123  * [ipv6:ipv6addr]:port, [ipv6:ipv6addr]:, [ipv6:ipv6addr].
124  */
125  if (*cp == '[') {
126  ++cp;
127  if ((ipv6 = HAS_IPV6_COL(cp)) != 0)
128  cp += IPV6_COL_LEN;
129  *host = cp;
130  if ((cp = split_at(cp, ']')) == 0)
131  return ("missing \"]\"");
132  if (*cp && *cp++ != ':')
133  return ("garbage after \"]\"");
134  if (ipv6 && !valid_ipv6_hostaddr(*host, DONT_GRIPE))
135  return ("malformed IPv6 address");
136  *port = *cp ? cp : def_service;
137  }
138 
139  /*
140  * host:port, host:, host, :port, port.
141  */
142  else {
143  if ((cp = split_at_right(buf, ':')) != 0) {
144  *host = *buf ? buf : def_host;
145  *port = *cp ? cp : def_service;
146  } else {
147  *host = def_host ? def_host : (*buf ? buf : 0);
148  *port = def_service ? def_service : (*buf ? buf : 0);
149  }
150  }
151  if (*host == 0)
152  return ("missing host information");
153  if (*port == 0)
154  return ("missing service information");
155 
156  /*
157  * Final sanity checks. We're still sloppy, allowing bare numerical
158  * network addresses instead of requiring proper [ipaddress] forms.
159  */
160  if (*host != def_host
162  && !valid_hostaddr(*host, DONT_GRIPE))
163  return ("valid hostname or network address required");
164  if (*port != def_service && ISDIGIT(**port) && !alldig(*port))
165  return ("garbage after numerical service");
166  return (0);
167 }
168 
169 #ifdef TEST
170 
171 #include <vstream.h>
172 #include <vstring.h>
173 #include <vstring_vstream.h>
174 
175 #define STR(x) vstring_str(x)
176 
177 int main(int unused_argc, char **unused_argv)
178 {
179  VSTRING *in_buf = vstring_alloc(10);
180  VSTRING *parse_buf = vstring_alloc(10);
181  char *host;
182  char *port;
183  const char *err;
184 
185  while (vstring_fgets_nonl(in_buf, VSTREAM_IN)) {
186  vstream_printf(">> %s\n", STR(in_buf));
188  if (*STR(in_buf) == '#')
189  continue;
190  vstring_strcpy(parse_buf, STR(in_buf));
191  if ((err = host_port(STR(parse_buf), &host, (char *) 0, &port, "default-service")) != 0) {
192  msg_warn("%s in %s", err, STR(in_buf));
193  } else {
194  vstream_printf("host %s port %s\n", host, port);
196  }
197  }
198  vstring_free(in_buf);
199  vstring_free(parse_buf);
200  return (0);
201 }
202 
203 #endif
int valid_hostaddr(const char *addr, int gripe)
#define vstring_fgets_nonl(s, p)
int valid_ipv6_hostaddr(const char *addr, int gripe)
#define VSTREAM_OUT
Definition: vstream.h:67
int main(int argc, char **argv)
Definition: anvil.c:1010
#define VSTREAM_IN
Definition: vstream.h:66
int alldig(const char *string)
Definition: alldig.c:38
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
Definition: vstring.c:431
int valid_utf8_hostname(int enable_utf8, const char *name, int gripe)
#define ISDIGIT(c)
Definition: sys_defs.h:1748
#define HAS_IPV6_COL(str)
Definition: host_port.c:111
VSTREAM * vstream_printf(const char *fmt,...)
Definition: vstream.c:1335
#define STR(x)
Definition: anvil.c:518
void msg_warn(const char *fmt,...)
Definition: msg.c:215
VSTRING * vstring_alloc(ssize_t len)
Definition: vstring.c:353
int vstream_fflush(VSTREAM *stream)
Definition: vstream.c:1257
const char * host_port(char *buf, char **host, char *def_host, char **port, char *def_service)
Definition: host_port.c:115
VSTRING * vstring_free(VSTRING *vp)
Definition: vstring.c:380
char * split_at(char *string, int delimiter)
Definition: split_at.c:53
#define IPV6_COL_LEN
Definition: host_port.c:110
int util_utf8_enable
Definition: printable.c:47
char * split_at_right(char *string, int delimiter)
Definition: split_at.c:64
#define DONT_GRIPE
Definition: haproxy_srvr.h:31