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