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