xref: /netbsd-src/external/ibm-public/postfix/dist/src/util/find_inet.c (revision 67b9b338a7386232ac596b5fd0cd5a9cc8a03c71)
1 /*	$NetBSD: find_inet.c,v 1.3 2022/10/08 16:12:50 christos Exp $	*/
2 
3 /*++
4 /* NAME
5 /*	find_inet 3
6 /* SUMMARY
7 /*	inet-domain name services
8 /* SYNOPSIS
9 /*	#include <find_inet.h>
10 /*
11 /*	unsigned find_inet_addr(host)
12 /*	const char *host;
13 /*
14 /*	int	find_inet_port(port, proto)
15 /*	const char *port;
16 /*	const char *proto;
17 /* DESCRIPTION
18 /*	These functions translate network address information from
19 /*	between printable form to the internal the form used by the
20 /*	BSD TCP/IP network software.
21 /*
22 /*	find_inet_addr() translates a symbolic or numerical hostname.
23 /*	This function is deprecated. Use hostname_to_hostaddr() instead.
24 /*
25 /*	find_inet_port() translates a symbolic or numerical port name.
26 /* BUGS
27 /*	find_inet_addr() ignores all but the first address listed for
28 /*	a symbolic hostname.
29 /* DIAGNOSTICS
30 /*	Lookup and conversion errors are fatal.
31 /* LICENSE
32 /* .ad
33 /* .fi
34 /*	The Secure Mailer license must be distributed with this software.
35 /* AUTHOR(S)
36 /*	Wietse Venema
37 /*	IBM T.J. Watson Research
38 /*	P.O. Box 704
39 /*	Yorktown Heights, NY 10598, USA
40 /*
41 /*	Wietse Venema
42 /*	Google, Inc.
43 /*	111 8th Avenue
44 /*	New York, NY 10011, USA
45 /*--*/
46 
47 /* System libraries. */
48 
49 #include <sys_defs.h>
50 #include <sys/socket.h>
51 #include <netinet/in.h>
52 #include <arpa/inet.h>
53 #include <netdb.h>
54 #include <stdlib.h>
55 #include <string.h>
56 
57 /* Application-specific. */
58 
59 #include "msg.h"
60 #include "stringops.h"
61 #include "find_inet.h"
62 #include "known_tcp_ports.h"
63 
64 #ifndef INADDR_NONE
65 #define INADDR_NONE 0xffffffff
66 #endif
67 
68 #ifdef TEST
69 extern NORETURN PRINTFLIKE(1, 2) test_msg_fatal(const char *,...);
70 
71 #define msg_fatal test_msg_fatal
72 #endif
73 
74 /* find_inet_addr - translate numerical or symbolic host name */
75 
find_inet_addr(const char * host)76 unsigned find_inet_addr(const char *host)
77 {
78     struct in_addr addr;
79     struct hostent *hp;
80 
81     addr.s_addr = inet_addr(host);
82     if ((addr.s_addr == INADDR_NONE) || (addr.s_addr == 0)) {
83 	if ((hp = gethostbyname(host)) == 0)
84 	    msg_fatal("host not found: %s", host);
85 	if (hp->h_addrtype != AF_INET)
86 	    msg_fatal("unexpected address family: %d", hp->h_addrtype);
87 	if (hp->h_length != sizeof(addr))
88 	    msg_fatal("unexpected address length %d", hp->h_length);
89 	memcpy((void *) &addr, hp->h_addr, hp->h_length);
90     }
91     return (addr.s_addr);
92 }
93 
94 /* find_inet_port - translate numerical or symbolic service name */
95 
find_inet_port(const char * service,const char * protocol)96 int     find_inet_port(const char *service, const char *protocol)
97 {
98     struct servent *sp;
99     int     port;
100 
101     service = filter_known_tcp_port(service);
102     if (alldig(service) && (port = atoi(service)) != 0) {
103 	if (port < 0 || port > 65535)
104 	    msg_fatal("bad port number: %s", service);
105 	return (htons(port));
106     } else {
107 	if ((sp = getservbyname(service, protocol)) == 0)
108 	    msg_fatal("unknown service: %s/%s", service, protocol);
109 	return (sp->s_port);
110     }
111 }
112 
113 #ifdef TEST
114 
115 #include <stdlib.h>
116 #include <setjmp.h>
117 #include <string.h>
118 
119 #include <vstream.h>
120 #include <vstring.h>
121 #include <msg_vstream.h>
122 
123 #define STR(x) vstring_str(x)
124 
125  /* TODO(wietse) make this a proper VSTREAM interface */
126 
127 /* vstream_swap - kludge to capture output for testing */
128 
vstream_swap(VSTREAM * one,VSTREAM * two)129 static void vstream_swap(VSTREAM *one, VSTREAM *two)
130 {
131     VSTREAM save;
132 
133     save = *one;
134     *one = *two;
135     *two = save;
136 }
137 
138 jmp_buf test_fatal_jbuf;
139 
140 #undef msg_fatal
141 
142 /* test_msg_fatal - does not return, and does not terminate */
143 
test_msg_fatal(const char * fmt,...)144 void    test_msg_fatal(const char *fmt,...)
145 {
146     va_list ap;
147 
148     va_start(ap, fmt);
149     vmsg_warn(fmt, ap);
150     va_end(ap);
151     longjmp(test_fatal_jbuf, 1);
152 }
153 
154 struct association {
155     const char *lhs;			/* service name */
156     const char *rhs;			/* service port */
157 };
158 
159 struct test_case {
160     const char *label;			/* identifies test case */
161     struct association associations[10];
162     const char *service;
163     const char *proto;
164     const char *exp_warning;		/* expected error */
165     int     exp_hport;			/* expected port, host byte order */
166 };
167 
168 struct test_case test_cases[] = {
169     {"good-symbolic",
170 	 /* association */ {{"foobar", "25252"}, 0},
171 	 /* service */ "foobar",
172 	 /* proto */ "tcp",
173 	 /* exp_warning */ "",
174 	 /* exp_hport */ 25252,
175     },
176     {"good-numeric",
177 	 /* association */ {{"foobar", "25252"}, 0},
178 	 /* service */ "25252",
179 	 /* proto */ "tcp",
180 	 /* exp_warning */ "",
181 	 /* exp_hport */ 25252,
182     },
183     {"bad-symbolic",
184 	 /* association */ {{"foobar", "25252"}, 0},
185 	 /* service */ "an-impossible-name",
186 	 /* proto */ "tcp",
187 	 /* exp_warning */ "find_inet: warning: unknown service: an-impossible-name/tcp\n",
188     },
189     {"bad-numeric",
190 	 /* association */ {{"foobar", "25252"}, 0},
191 	 /* service */ "123456",
192 	 /* proto */ "tcp",
193 	 /* exp_warning */ "find_inet: warning: bad port number: 123456\n",
194     },
195 };
196 
main(int argc,char ** argv)197 int main(int argc, char **argv) {
198     struct test_case *tp;
199     struct association *ap;
200     int     pass = 0;
201     int     fail = 0;
202     const char *err;
203     int     test_failed;
204     int     nport;
205     VSTRING *msg_buf;
206     VSTREAM *memory_stream;
207 
208     msg_vstream_init("find_inet", VSTREAM_ERR);
209     msg_buf = vstring_alloc(100);
210 
211     for (tp = test_cases; tp->label != 0; tp++) {
212 	test_failed = 0;
213 	VSTRING_RESET(msg_buf);
214 	VSTRING_TERMINATE(msg_buf);
215 	clear_known_tcp_ports();
216 	for (err = 0, ap = tp->associations; err == 0 && ap->lhs != 0; ap++)
217 	    err = add_known_tcp_port(ap->lhs, ap->rhs);
218 	if (err != 0) {
219 	    msg_warn("test case %s: got err: \"%s\"", tp->label, err);
220 	    test_failed = 1;
221 	} else {
222 	    if ((memory_stream = vstream_memopen(msg_buf, O_WRONLY)) == 0)
223 		msg_fatal("open memory stream: %m");
224 	    vstream_swap(VSTREAM_ERR, memory_stream);
225 	    if (setjmp(test_fatal_jbuf) == 0)
226 		nport = find_inet_port(tp->service, tp->proto);
227 	    vstream_swap(memory_stream, VSTREAM_ERR);
228 	    if (vstream_fclose(memory_stream))
229 		msg_fatal("close memory stream: %m");
230 	    if (strcmp(STR(msg_buf), tp->exp_warning) != 0) {
231 		msg_warn("test case %s: got error: \"%s\", want: \"%s\"",
232 			 tp->label, STR(msg_buf), tp->exp_warning);
233 		test_failed = 1;
234 	    } else if (tp->exp_warning[0] == 0) {
235 		if (ntohs(nport) != tp->exp_hport) {
236 		    msg_warn("test case %s: got port \"%d\", want: \"%d\"",
237 			     tp->label, ntohs(nport), tp->exp_hport);
238 		    test_failed = 1;
239 		}
240 	    }
241 	}
242 	if (test_failed) {
243 	    msg_info("%s: FAIL", tp->label);
244 	    fail++;
245 	} else {
246 	    msg_info("%s: PASS", tp->label);
247 	    pass++;
248 	}
249     }
250     msg_info("PASS=%d FAIL=%d", pass, fail);
251     vstring_free(msg_buf);
252     exit(fail != 0);
253 }
254 
255 #endif
256