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